From 8aa5344ecba04f7cbdb46d78333c977148e662c2 Mon Sep 17 00:00:00 2001 From: prashanth26 Date: Fri, 30 Nov 2018 15:07:14 +0530 Subject: [PATCH] Prune unwanted vendor files --- vendor/cloud.google.com/go/.travis.yml | 21 + vendor/cloud.google.com/go/CONTRIBUTING.md | 152 + vendor/cloud.google.com/go/MIGRATION.md | 54 + vendor/cloud.google.com/go/README.md | 546 + vendor/cloud.google.com/go/appveyor.yml | 32 + .../cloud.google.com/go/authexample_test.go | 49 + vendor/cloud.google.com/go/cloud.go | 20 + .../go/compute/metadata/metadata_test.go | 48 + vendor/cloud.google.com/go/import_test.go | 61 + vendor/cloud.google.com/go/keys.tar.enc | Bin 0 -> 10256 bytes vendor/cloud.google.com/go/license_test.go | 71 + vendor/cloud.google.com/go/old-news.md | 557 + vendor/cloud.google.com/go/regen-gapic.sh | 63 + vendor/cloud.google.com/go/run-tests.sh | 88 + .../Azure/azure-sdk-for-go/.gitignore | 32 + .../Azure/azure-sdk-for-go/.travis.yml | 48 + .../Azure/azure-sdk-for-go/CHANGELOG.md | 735 + .../Azure/azure-sdk-for-go/CONTRIBUTING.md | 16 + .../Azure/azure-sdk-for-go/Gopkg.lock | 86 + .../Azure/azure-sdk-for-go/Gopkg.toml | 66 + .../Azure/azure-sdk-for-go/README.md | 200 + .../Azure/azure-sdk-for-go/arm/README.md | 341 + .../Azure/azure-sdk-for-go/rungas.sh | 15 + vendor/github.com/Azure/go-ansiterm/README.md | 12 + .../Azure/go-ansiterm/parser_test.go | 141 + .../go-ansiterm/parser_test_helpers_test.go | 114 + .../go-ansiterm/parser_test_utilities_test.go | 66 + .../go-ansiterm/test_event_handler_test.go | 173 + .../github.com/Azure/go-autorest/.gitignore | 31 + .../github.com/Azure/go-autorest/.travis.yml | 24 + .../github.com/Azure/go-autorest/CHANGELOG.md | 345 + .../github.com/Azure/go-autorest/GNUmakefile | 23 + vendor/github.com/Azure/go-autorest/README.md | 132 + .../Azure/go-autorest/autorest/adal/README.md | 287 + .../go-autorest/autorest/adal/config_test.go | 44 + .../autorest/adal/devicetoken_test.go | 330 + .../go-autorest/autorest/adal/persist_test.go | 171 + .../go-autorest/autorest/adal/token_test.go | 725 + .../autorest/authorization_test.go | 230 + .../go-autorest/autorest/autorest_test.go | 140 + .../go-autorest/autorest/azure/async_test.go | 1327 + .../go-autorest/autorest/azure/azure_test.go | 513 + .../autorest/azure/environments_test.go | 292 + .../go-autorest/autorest/azure/rp_test.go | 126 + .../Azure/go-autorest/autorest/client_test.go | 402 + .../go-autorest/autorest/date/date_test.go | 237 + .../go-autorest/autorest/date/time_test.go | 277 + .../autorest/date/timerfc1123_test.go | 226 + .../autorest/date/unixtime_test.go | 283 + .../Azure/go-autorest/autorest/error_test.go | 202 + .../go-autorest/autorest/preparer_test.go | 802 + .../go-autorest/autorest/responder_test.go | 665 + .../Azure/go-autorest/autorest/sender_test.go | 829 + .../go-autorest/autorest/to/convert_test.go | 234 + .../go-autorest/autorest/utility_test.go | 422 + .../autorest/validation/validation_test.go | 2433 ++ .../github.com/Azure/go-autorest/glide.lock | 44 + .../github.com/Azure/go-autorest/glide.yaml | 22 + .../github.com/PuerkitoBio/purell/.gitignore | 5 + .../github.com/PuerkitoBio/purell/.travis.yml | 7 + .../github.com/PuerkitoBio/purell/README.md | 187 + .../PuerkitoBio/purell/bench_test.go | 57 + .../PuerkitoBio/purell/example_test.go | 35 + .../PuerkitoBio/purell/purell_test.go | 768 + .../PuerkitoBio/purell/urlnorm_test.go | 53 + .../github.com/PuerkitoBio/urlesc/.travis.yml | 15 + .../github.com/PuerkitoBio/urlesc/README.md | 16 + .../PuerkitoBio/urlesc/urlesc_test.go | 641 + vendor/github.com/Sirupsen/logrus/.gitignore | 2 + vendor/github.com/Sirupsen/logrus/.travis.yml | 51 + .../github.com/Sirupsen/logrus/CHANGELOG.md | 165 + vendor/github.com/Sirupsen/logrus/README.md | 493 + .../Sirupsen/logrus/alt_exit_test.go | 99 + .../github.com/Sirupsen/logrus/appveyor.yml | 14 + .../github.com/Sirupsen/logrus/entry_test.go | 115 + .../Sirupsen/logrus/example_basic_test.go | 77 + .../logrus/example_global_hook_test.go | 36 + .../Sirupsen/logrus/example_hook_test.go | 43 + .../Sirupsen/logrus/formatter_bench_test.go | 101 + vendor/github.com/Sirupsen/logrus/go.mod | 11 + vendor/github.com/Sirupsen/logrus/go.sum | 15 + .../github.com/Sirupsen/logrus/hook_test.go | 192 + .../Sirupsen/logrus/json_formatter_test.go | 346 + .../Sirupsen/logrus/logger_bench_test.go | 85 + .../github.com/Sirupsen/logrus/logger_test.go | 42 + .../github.com/Sirupsen/logrus/logrus_test.go | 716 + .../Sirupsen/logrus/text_formatter_test.go | 480 + .../aliyun/alibaba-cloud-sdk-go/.travis.yml | 31 + .../aliyun/alibaba-cloud-sdk-go/ChangeLog.txt | 673 + .../aliyun/alibaba-cloud-sdk-go/Gopkg.lock | 77 + .../aliyun/alibaba-cloud-sdk-go/Gopkg.toml | 56 + .../aliyun/alibaba-cloud-sdk-go/README.md | 72 + .../aliyun/alibaba-cloud-sdk-go/README_zh.md | 181 + .../alibaba-cloud-sdk-go/sdk/client_test.go | 573 + .../sdk/endpoints/mapping_resolver_test.go | 19 + .../sdk/requests/types_test.go | 50 + .../sdk/responses/json_parser_test.go | 145 + .../services/push/push_notice_to_android.go | 110 - .../services/push/push_notice_toi_os.go | 111 - vendor/github.com/aws/aws-sdk-go/.gitignore | 11 + .../github.com/aws/aws-sdk-go/.godoc_config | 14 + vendor/github.com/aws/aws-sdk-go/.travis.yml | 51 + vendor/github.com/aws/aws-sdk-go/CHANGELOG.md | 3371 ++ .../aws/aws-sdk-go/CHANGELOG_PENDING.md | 5 + .../aws/aws-sdk-go/CODE_OF_CONDUCT.md | 4 + .../github.com/aws/aws-sdk-go/CONTRIBUTING.md | 127 + vendor/github.com/aws/aws-sdk-go/Gopkg.lock | 20 + vendor/github.com/aws/aws-sdk-go/Gopkg.toml | 48 + vendor/github.com/aws/aws-sdk-go/Makefile | 187 + vendor/github.com/aws/aws-sdk-go/README.md | 451 + .../aws/aws-sdk-go/aws/awsutil/copy_test.go | 353 + .../aws/aws-sdk-go/aws/awsutil/equal_test.go | 30 + .../aws-sdk-go/aws/awsutil/path_value_test.go | 182 + .../aws/aws-sdk-go/aws/client/client_test.go | 78 + .../aws/client/default_retryer_test.go | 189 + .../aws/aws-sdk-go/aws/client/logger_test.go | 144 + .../aws/aws-sdk-go/aws/config_test.go | 86 + .../aws/aws-sdk-go/aws/context_test.go | 37 + .../aws/aws-sdk-go/aws/convert_types_test.go | 641 + .../aws/corehandlers/handlers_1_8_test.go | 64 + .../aws/corehandlers/handlers_test.go | 398 + .../aws/corehandlers/param_validator_test.go | 286 + .../aws/corehandlers/user_agent_test.go | 40 + .../aws/credentials/chain_provider_test.go | 154 + .../aws/credentials/credentials_test.go | 73 + .../ec2rolecreds/ec2_role_provider_test.go | 159 + .../endpointcreds/provider_test.go | 111 + .../aws/credentials/env_provider_test.go | 70 + .../aws-sdk-go/aws/credentials/example.ini | 12 + .../shared_credentials_provider_test.go | 136 + .../aws/credentials/static_provider_test.go | 34 + .../stscreds/assume_role_provider_test.go | 150 + .../aws-sdk-go/aws/defaults/defaults_test.go | 116 + .../aws-sdk-go/aws/ec2metadata/api_test.go | 289 + .../aws/ec2metadata/service_test.go | 120 + .../aws-sdk-go/aws/endpoints/decode_test.go | 117 + .../aws/endpoints/endpoints_test.go | 342 + .../aws-sdk-go/aws/endpoints/example_test.go | 66 + .../aws-sdk-go/aws/endpoints/v3model_test.go | 541 + .../connection_reset_error_other_test.go | 9 + .../request/connection_reset_error_test.go | 11 + .../aws-sdk-go/aws/request/handlers_test.go | 266 + .../aws/request/http_request_copy_test.go | 34 + .../aws/request/http_request_retry_test.go | 37 + .../aws/request/offset_reader_test.go | 140 + .../aws/request/request_1_5_test.go | 11 + .../aws/request/request_1_6_test.go | 51 + .../aws/request/request_1_7_test.go | 24 + .../aws/request/request_1_8_test.go | 85 + .../aws/request/request_context_test.go | 46 + .../aws/request/request_internal_test.go | 27 + .../aws/request/request_pagination_test.go | 619 + .../aws/request/request_resetbody_test.go | 107 + .../aws-sdk-go/aws/request/request_test.go | 1121 + .../aws-sdk-go/aws/request/retryer_test.go | 62 + .../timeout_read_closer_benchmark_test.go | 76 + .../aws/request/timeout_read_closer_test.go | 118 + .../aws/aws-sdk-go/aws/request/waiter_test.go | 654 + .../aws/session/custom_ca_bundle_test.go | 243 + .../aws-sdk-go/aws/session/env_config_test.go | 306 + .../aws-sdk-go/aws/session/session_test.go | 446 + .../aws/session/shared_config_test.go | 274 + .../aws/signer/v4/functional_1_5_test.go | 86 + .../aws/signer/v4/functional_test.go | 254 + .../aws/signer/v4/header_rules_test.go | 77 + .../aws/aws-sdk-go/aws/signer/v4/v4_test.go | 717 + .../aws/aws-sdk-go/aws/types_test.go | 92 + .../github.com/aws/aws-sdk-go/buildspec.yml | 21 + vendor/github.com/aws/aws-sdk-go/doc.go | 405 + .../shared_config_other_test.go | 40 + .../shared_config_windows_test.go | 40 + .../aws/aws-sdk-go/private/README.md | 4 + .../protocol/ec2query/build_bench_test.go | 85 + .../private/protocol/ec2query/build_test.go | 2092 + .../protocol/ec2query/unmarshal_test.go | 1869 + .../private/protocol/idempotency_test.go | 106 + .../private/protocol/jsonvalue_test.go | 93 + .../private/protocol/protocol_test.go | 203 + .../private/protocol/query/build_test.go | 4056 ++ .../private/protocol/query/unmarshal_test.go | 2991 ++ .../private/protocol/rest/build_test.go | 63 + .../private/protocol/rest/rest_test.go | 63 + .../private/protocol/unmarshal_test.go | 40 + .../protocol/xml/xmlutil/unmarshal_test.go | 142 + .../service/ec2/customizations_test.go | 48 + .../aws-sdk-go/service/ec2/examples_test.go | 4213 +++ .../aws-sdk-go/service/ec2/retryer_test.go | 37 + .../aws/aws-sdk-go/service/generate.go | 5 + .../service/sts/customizations_test.go | 45 + .../aws-sdk-go/service/sts/examples_test.go | 282 + vendor/github.com/beorn7/perks/.gitignore | 2 + vendor/github.com/beorn7/perks/README.md | 31 + .../beorn7/perks/quantile/bench_test.go | 63 + .../beorn7/perks/quantile/example_test.go | 121 + .../beorn7/perks/quantile/exampledata.txt | 2388 ++ .../beorn7/perks/quantile/stream_test.go | 215 + vendor/github.com/davecgh/go-spew/.gitignore | 22 + vendor/github.com/davecgh/go-spew/.travis.yml | 14 + vendor/github.com/davecgh/go-spew/README.md | 205 + .../github.com/davecgh/go-spew/cov_report.sh | 22 + .../davecgh/go-spew/spew/common_test.go | 298 + .../davecgh/go-spew/spew/dump_test.go | 1042 + .../davecgh/go-spew/spew/dumpcgo_test.go | 99 + .../davecgh/go-spew/spew/dumpnocgo_test.go | 26 + .../davecgh/go-spew/spew/example_test.go | 226 + .../davecgh/go-spew/spew/format_test.go | 1558 + .../davecgh/go-spew/spew/internal_test.go | 87 + .../go-spew/spew/internalunsafe_test.go | 102 + .../davecgh/go-spew/spew/spew_test.go | 320 + .../davecgh/go-spew/test_coverage.txt | 61 + vendor/github.com/dgrijalva/jwt-go/.gitignore | 4 + .../github.com/dgrijalva/jwt-go/.travis.yml | 13 + .../dgrijalva/jwt-go/MIGRATION_GUIDE.md | 97 + vendor/github.com/dgrijalva/jwt-go/README.md | 100 + .../dgrijalva/jwt-go/VERSION_HISTORY.md | 118 + .../github.com/dgrijalva/jwt-go/ecdsa_test.go | 100 + .../dgrijalva/jwt-go/example_test.go | 114 + .../dgrijalva/jwt-go/hmac_example_test.go | 66 + .../github.com/dgrijalva/jwt-go/hmac_test.go | 91 + .../dgrijalva/jwt-go/http_example_test.go | 216 + .../github.com/dgrijalva/jwt-go/none_test.go | 72 + .../dgrijalva/jwt-go/parser_test.go | 301 + .../dgrijalva/jwt-go/rsa_pss_test.go | 96 + .../github.com/dgrijalva/jwt-go/rsa_test.go | 185 + vendor/github.com/docker/docker/.dockerignore | 4 + vendor/github.com/docker/docker/.gitignore | 33 + vendor/github.com/docker/docker/.mailmap | 275 + vendor/github.com/docker/docker/CHANGELOG.md | 3337 ++ .../github.com/docker/docker/CONTRIBUTING.md | 401 + vendor/github.com/docker/docker/Dockerfile | 246 + .../docker/docker/Dockerfile.aarch64 | 175 + .../github.com/docker/docker/Dockerfile.armhf | 182 + .../docker/docker/Dockerfile.ppc64le | 188 + .../github.com/docker/docker/Dockerfile.s390x | 190 + .../docker/docker/Dockerfile.simple | 73 + .../docker/docker/Dockerfile.solaris | 20 + .../docker/docker/Dockerfile.windows | 267 + vendor/github.com/docker/docker/MAINTAINERS | 376 + vendor/github.com/docker/docker/Makefile | 147 + vendor/github.com/docker/docker/README.md | 304 + vendor/github.com/docker/docker/ROADMAP.md | 118 + vendor/github.com/docker/docker/VENDORING.md | 45 + vendor/github.com/docker/docker/VERSION | 1 + .../docker-engine-selinux/LICENSE | 339 - .../docker-engine-selinux/LICENSE | 339 - .../selinux/docker-engine-selinux/LICENSE | 340 - .../docker/docker/contrib/syntax/vim/LICENSE | 22 - .../docker/docs/static_files/contributors.png | Bin 23100 -> 0 bytes .../docker/docker/hack/generate-authors.sh | 15 - .../.build-deb/docker-engine.docker.default | 1 - .../make/.build-deb/docker-engine.docker.init | 1 - .../.build-deb/docker-engine.docker.upstart | 1 - .../hack/make/.build-deb/docker-engine.udev | 1 - vendor/github.com/docker/docker/pkg/README.md | 11 + .../docker/docker/pkg/symlink/LICENSE.APACHE | 191 - .../docker/docker/pkg/symlink/LICENSE.BSD | 27 - .../docker/docker/pkg/term/ascii_test.go | 43 + .../docker/pkg/term/windows/windows_test.go | 3 + vendor/github.com/docker/docker/poule.yml | 88 + .../docker/docker/project/CONTRIBUTORS.md | 1 - vendor/github.com/docker/docker/vendor.conf | 140 + .../github.com/emicklei/go-restful/.gitignore | 70 + .../emicklei/go-restful/.travis.yml | 6 + .../github.com/emicklei/go-restful/CHANGES.md | 234 + .../github.com/emicklei/go-restful/Makefile | 7 + .../github.com/emicklei/go-restful/README.md | 87 + vendor/github.com/emicklei/go-restful/Srcfile | 1 + .../emicklei/go-restful/bench_curly_test.go | 51 + .../emicklei/go-restful/bench_test.go | 43 + .../emicklei/go-restful/bench_test.sh | 10 + .../emicklei/go-restful/compress_test.go | 125 + .../emicklei/go-restful/container_test.go | 83 + .../emicklei/go-restful/cors_filter_test.go | 129 + .../emicklei/go-restful/coverage.sh | 2 + .../emicklei/go-restful/curly_test.go | 238 + .../emicklei/go-restful/doc_examples_test.go | 41 + .../go-restful/entity_accessors_test.go | 69 + .../emicklei/go-restful/filter_test.go | 141 + .../emicklei/go-restful/jsr311_test.go | 332 + .../emicklei/go-restful/mime_test.go | 17 + .../go-restful/options_filter_test.go | 34 + .../go-restful/path_expression_test.go | 45 + .../go-restful/path_processor_test.go | 55 + .../emicklei/go-restful/request_test.go | 141 + .../emicklei/go-restful/response_test.go | 213 + .../emicklei/go-restful/route_builder_test.go | 76 + .../emicklei/go-restful/route_test.go | 76 + .../emicklei/go-restful/tracer_test.go | 18 + .../emicklei/go-restful/web_service_test.go | 343 + vendor/github.com/ghodss/yaml/.gitignore | 20 + vendor/github.com/ghodss/yaml/.travis.yml | 7 + vendor/github.com/ghodss/yaml/README.md | 121 + vendor/github.com/ghodss/yaml/yaml_test.go | 287 + vendor/github.com/go-ini/ini/.gitignore | 6 + vendor/github.com/go-ini/ini/.travis.yml | 16 + vendor/github.com/go-ini/ini/Makefile | 15 + vendor/github.com/go-ini/ini/README.md | 44 + vendor/github.com/go-ini/ini/bench_test.go | 118 + vendor/github.com/go-ini/ini/file_test.go | 294 + .../go-ini/ini/ini_internal_test.go | 35 + vendor/github.com/go-ini/ini/ini_test.go | 1114 + vendor/github.com/go-ini/ini/key_test.go | 523 + vendor/github.com/go-ini/ini/parser_test.go | 77 + vendor/github.com/go-ini/ini/section_test.go | 313 + vendor/github.com/go-ini/ini/struct_test.go | 387 + .../go-openapi/jsonpointer/.editorconfig | 26 + .../go-openapi/jsonpointer/.gitignore | 1 + .../go-openapi/jsonpointer/.travis.yml | 15 + .../go-openapi/jsonpointer/CODE_OF_CONDUCT.md | 74 + .../go-openapi/jsonpointer/README.md | 15 + .../go-openapi/jsonpointer/pointer_test.go | 573 + .../go-openapi/jsonreference/.gitignore | 1 + .../go-openapi/jsonreference/.travis.yml | 16 + .../jsonreference/CODE_OF_CONDUCT.md | 74 + .../go-openapi/jsonreference/README.md | 15 + .../jsonreference/reference_test.go | 420 + vendor/github.com/go-openapi/spec/.drone.sec | 1 + vendor/github.com/go-openapi/spec/.drone.yml | 35 + vendor/github.com/go-openapi/spec/.gitignore | 2 + .../go-openapi/spec/.pullapprove.yml | 13 + .../go-openapi/spec/CODE_OF_CONDUCT.md | 74 + vendor/github.com/go-openapi/spec/README.md | 5 + .../github.com/go-openapi/spec/auth_test.go | 128 + .../go-openapi/spec/contact_info_test.go | 37 + .../go-openapi/spec/expander_test.go | 1098 + .../go-openapi/spec/external_docs_test.go | 29 + .../github.com/go-openapi/spec/header_test.go | 86 + .../github.com/go-openapi/spec/info_test.go | 65 + .../github.com/go-openapi/spec/items_test.go | 81 + .../go-openapi/spec/license_test.go | 28 + .../go-openapi/spec/operation_test.go | 85 + .../go-openapi/spec/parameters_test.go | 156 + .../go-openapi/spec/path_item_test.go | 81 + .../github.com/go-openapi/spec/paths_test.go | 43 + .../go-openapi/spec/properties_test.go | 58 + .../github.com/go-openapi/spec/schema_test.go | 205 + .../go-openapi/spec/structs_test.go | 110 + .../go-openapi/spec/swagger_test.go | 321 + .../go-openapi/spec/xml_object_test.go | 65 + .../github.com/go-openapi/swag/.editorconfig | 26 + vendor/github.com/go-openapi/swag/.gitignore | 3 + vendor/github.com/go-openapi/swag/.travis.yml | 14 + .../go-openapi/swag/CODE_OF_CONDUCT.md | 74 + vendor/github.com/go-openapi/swag/README.md | 12 + .../go-openapi/swag/convert_test.go | 215 + .../go-openapi/swag/convert_types_test.go | 579 + .../github.com/go-openapi/swag/json_test.go | 169 + .../go-openapi/swag/loading_test.go | 47 + vendor/github.com/go-openapi/swag/net_test.go | 30 + .../github.com/go-openapi/swag/path_test.go | 118 + .../github.com/go-openapi/swag/util_test.go | 293 + .../github.com/go-openapi/swag/yaml_test.go | 444 + vendor/github.com/gogo/protobuf/.gitignore | 3 + vendor/github.com/gogo/protobuf/.mailmap | 8 + vendor/github.com/gogo/protobuf/.travis.yml | 20 + vendor/github.com/gogo/protobuf/Makefile | 162 + vendor/github.com/gogo/protobuf/README | 258 + vendor/github.com/gogo/protobuf/Readme.md | 139 + vendor/github.com/gogo/protobuf/bench.md | 190 + .../github.com/gogo/protobuf/custom_types.md | 68 + vendor/github.com/gogo/protobuf/extensions.md | 162 + .../gogo/protobuf/install-protobuf.sh | 28 + .../github.com/gogo/protobuf/proto/Makefile | 43 + .../gogo/protobuf/proto/all_test.go | 2278 ++ .../gogo/protobuf/proto/any_test.go | 300 + .../gogo/protobuf/proto/clone_test.go | 300 + .../gogo/protobuf/proto/decode_test.go | 262 + .../gogo/protobuf/proto/encode_test.go | 84 + .../gogo/protobuf/proto/equal_test.go | 224 + .../gogo/protobuf/proto/extensions_test.go | 538 + .../gogo/protobuf/proto/map_test.go | 46 + .../gogo/protobuf/proto/message_set_test.go | 66 + .../gogo/protobuf/proto/proto3_test.go | 135 + .../gogo/protobuf/proto/size2_test.go | 63 + .../gogo/protobuf/proto/size_test.go | 164 + .../gogo/protobuf/proto/text_parser_test.go | 673 + .../gogo/protobuf/proto/text_test.go | 474 + vendor/github.com/golang/glog/README | 44 + vendor/github.com/golang/glog/glog_test.go | 415 + .../github.com/golang/groupcache/.gitignore | 1 + .../github.com/golang/groupcache/.travis.yml | 18 + vendor/github.com/golang/groupcache/README.md | 73 + .../github.com/golang/groupcache/byteview.go | 175 + .../golang/groupcache/byteview_test.go | 147 + .../golang/groupcache/groupcache.go | 491 + .../golang/groupcache/groupcache_test.go | 456 + vendor/github.com/golang/groupcache/http.go | 227 + .../github.com/golang/groupcache/http_test.go | 166 + .../golang/groupcache/lru/lru_test.go | 97 + vendor/github.com/golang/groupcache/peers.go | 85 + vendor/github.com/golang/groupcache/sinks.go | 322 + vendor/github.com/golang/protobuf/.gitignore | 17 + vendor/github.com/golang/protobuf/.travis.yml | 30 + vendor/github.com/golang/protobuf/Makefile | 48 + vendor/github.com/golang/protobuf/README.md | 283 + .../golang/protobuf/proto/all_test.go | 2410 ++ .../golang/protobuf/proto/any_test.go | 300 + .../golang/protobuf/proto/clone_test.go | 390 + .../golang/protobuf/proto/decode_test.go | 255 + .../golang/protobuf/proto/discard_test.go | 170 + .../golang/protobuf/proto/encode_test.go | 85 + .../golang/protobuf/proto/equal_test.go | 244 + .../golang/protobuf/proto/extensions_test.go | 688 + .../golang/protobuf/proto/map_test.go | 70 + .../golang/protobuf/proto/message_set_test.go | 77 + .../golang/protobuf/proto/proto3_test.go | 151 + .../golang/protobuf/proto/size2_test.go | 63 + .../golang/protobuf/proto/size_test.go | 191 + .../golang/protobuf/proto/text_parser_test.go | 706 + .../golang/protobuf/proto/text_test.go | 518 + .../golang/protobuf/ptypes/any/any.proto | 149 + .../golang/protobuf/ptypes/any_test.go | 113 + .../protobuf/ptypes/duration/duration.proto | 117 + .../golang/protobuf/ptypes/duration_test.go | 121 + .../protobuf/ptypes/timestamp/timestamp.proto | 133 + .../golang/protobuf/ptypes/timestamp_test.go | 153 + .../github.com/golang/protobuf/regenerate.sh | 53 + vendor/github.com/google/btree/.travis.yml | 1 + vendor/github.com/google/btree/README.md | 12 + vendor/github.com/google/btree/btree_test.go | 785 + vendor/github.com/google/gofuzz/.travis.yml | 13 + .../github.com/google/gofuzz/CONTRIBUTING.md | 67 + vendor/github.com/google/gofuzz/README.md | 71 + .../github.com/google/gofuzz/example_test.go | 225 + vendor/github.com/google/gofuzz/fuzz_test.go | 472 + .../github.com/googleapis/gnostic/.gitignore | 21 + .../googleapis/gnostic/.travis-install.sh | 29 + .../github.com/googleapis/gnostic/.travis.yml | 49 + .../googleapis/gnostic/COMPILE-PROTOS.sh | 35 + .../googleapis/gnostic/CONTRIBUTING.md | 35 + vendor/github.com/googleapis/gnostic/Makefile | 16 + .../gnostic/OpenAPIv2/OpenAPIv2.proto | 663 + .../googleapis/gnostic/OpenAPIv2/README.md | 16 + .../gnostic/OpenAPIv2/openapi-2.0.json | 1610 + .../github.com/googleapis/gnostic/README.md | 109 + .../googleapis/gnostic/compiler/README.md | 3 + .../gnostic/extensions/COMPILE-EXTENSION.sh | 5 + .../googleapis/gnostic/extensions/README.md | 5 + .../gnostic/extensions/extension.proto | 93 + .../github.com/googleapis/gnostic/gnostic.go | 610 + .../googleapis/gnostic/gnostic_test.go | 453 + .../gophercloud/gophercloud/.gitignore | 2 + .../gophercloud/gophercloud/.travis.yml | 21 + .../gophercloud/gophercloud/.zuul.yaml | 12 + .../gophercloud/gophercloud/CHANGELOG.md | 0 .../github.com/gophercloud/gophercloud/FAQ.md | 148 + .../gophercloud/gophercloud/MIGRATING.md | 32 + .../gophercloud/gophercloud/README.md | 159 + .../gophercloud/gophercloud/STYLEGUIDE.md | 79 + .../compute/v2/extensions/delegate.go | 23 + .../openstack/compute/v2/extensions/doc.go | 3 + .../gregjones/httpcache/.travis.yml | 19 + .../github.com/gregjones/httpcache/README.md | 25 + .../httpcache/diskcache/diskcache_test.go | 42 + .../gregjones/httpcache/httpcache_test.go | 1475 + .../hashicorp/golang-lru/.gitignore | 23 + .../hashicorp/golang-lru/2q_test.go | 306 + .../github.com/hashicorp/golang-lru/README.md | 25 + .../hashicorp/golang-lru/arc_test.go | 377 + .../hashicorp/golang-lru/lru_test.go | 221 + .../golang-lru/simplelru/lru_test.go | 167 + vendor/github.com/imdario/mergo/.gitignore | 33 + vendor/github.com/imdario/mergo/.travis.yml | 7 + .../imdario/mergo/CODE_OF_CONDUCT.md | 46 + vendor/github.com/imdario/mergo/README.md | 222 + .../github.com/imdario/mergo/issue17_test.go | 25 + .../github.com/imdario/mergo/issue23_test.go | 27 + .../github.com/imdario/mergo/issue33_test.go | 33 + .../github.com/imdario/mergo/issue38_test.go | 59 + .../github.com/imdario/mergo/issue50_test.go | 18 + .../github.com/imdario/mergo/issue52_test.go | 99 + .../github.com/imdario/mergo/issue61_test.go | 20 + .../github.com/imdario/mergo/issue64_test.go | 38 + .../github.com/imdario/mergo/issue66_test.go | 29 + .../imdario/mergo/merge_appendslice_test.go | 33 + vendor/github.com/imdario/mergo/merge_test.go | 50 + vendor/github.com/imdario/mergo/mergo_test.go | 727 + .../imdario/mergo/testdata/license.yml | 4 - .../jmespath/go-jmespath/.gitignore | 4 + .../jmespath/go-jmespath/.travis.yml | 9 + .../github.com/jmespath/go-jmespath/Makefile | 44 + .../github.com/jmespath/go-jmespath/README.md | 7 + .../jmespath/go-jmespath/api_test.go | 32 + .../jmespath/go-jmespath/compliance_test.go | 123 + .../jmespath/go-jmespath/interpreter_test.go | 221 + .../jmespath/go-jmespath/lexer_test.go | 161 + .../jmespath/go-jmespath/parser_test.go | 136 + .../jmespath/go-jmespath/util_test.go | 73 + .../github.com/json-iterator/go/.codecov.yml | 3 + vendor/github.com/json-iterator/go/.gitignore | 4 + .../github.com/json-iterator/go/.travis.yml | 14 + vendor/github.com/json-iterator/go/Gopkg.lock | 21 + vendor/github.com/json-iterator/go/Gopkg.toml | 26 + vendor/github.com/json-iterator/go/README.md | 91 + vendor/github.com/json-iterator/go/build.sh | 12 + .../json-iterator/go/example_test.go | 121 + .../go/fuzzy_mode_convert_table.md | 7 + .../json-iterator/go/iter_skip_sloppy_test.go | 162 + .../json-iterator/go/stream_test.go | 69 + vendor/github.com/json-iterator/go/test.sh | 12 + .../go-windows-terminal-sequences/README.md | 40 + .../go-windows-terminal-sequences/go.mod | 1 + .../sequences_test.go | 48 + vendor/github.com/mailru/easyjson/.gitignore | 4 + vendor/github.com/mailru/easyjson/.travis.yml | 9 + vendor/github.com/mailru/easyjson/Makefile | 60 + vendor/github.com/mailru/easyjson/README.md | 331 + .../mailru/easyjson/buffer/pool_test.go | 107 + vendor/github.com/mailru/easyjson/helpers.go | 78 + .../mailru/easyjson/jlexer/lexer_test.go | 314 + vendor/github.com/mailru/easyjson/raw.go | 45 + .../golang_protobuf_extensions/.travis.yml | 2 + .../golang_protobuf_extensions/README.md | 20 + .../pbutil/all_test.go | 177 + .../pbutil/decode_test.go | 99 + .../pbutil/encode_test.go | 67 + .../pbutil/fixtures_test.go | 103 + .../modern-go/concurrent/.gitignore | 1 + .../modern-go/concurrent/.travis.yml | 14 + .../github.com/modern-go/concurrent/README.md | 49 + .../modern-go/concurrent/map_test.go | 18 + .../github.com/modern-go/concurrent/test.sh | 12 + .../concurrent/unbounded_executor_test.go | 54 + .../github.com/modern-go/reflect2/.gitignore | 2 + .../github.com/modern-go/reflect2/.travis.yml | 15 + .../github.com/modern-go/reflect2/Gopkg.lock | 15 + .../github.com/modern-go/reflect2/Gopkg.toml | 35 + .../github.com/modern-go/reflect2/README.md | 71 + vendor/github.com/modern-go/reflect2/test.sh | 12 + vendor/github.com/onsi/ginkgo/.gitignore | 6 + vendor/github.com/onsi/ginkgo/.travis.yml | 16 + vendor/github.com/onsi/ginkgo/CHANGELOG.md | 183 + vendor/github.com/onsi/ginkgo/CONTRIBUTING.md | 13 + vendor/github.com/onsi/ginkgo/README.md | 123 + vendor/github.com/onsi/ginkgo/RELEASING.md | 14 + vendor/github.com/onsi/ginkgo/before_pr.sh | 13 + .../extensions/table/table_suite_test.go | 13 + .../ginkgo/extensions/table/table_test.go | 64 + .../codelocation/code_location_suite_test.go | 13 + .../codelocation/code_location_test.go | 80 + .../container_node_suite_test.go | 13 + .../containernode/container_node_test.go | 213 + .../internal/failer/failer_suite_test.go | 13 + .../ginkgo/internal/failer/failer_test.go | 141 + .../ginkgo/internal/leafnodes/it_node_test.go | 22 + .../leafnodes/leaf_node_suite_test.go | 13 + .../internal/leafnodes/measure_node_test.go | 155 + .../internal/leafnodes/setup_nodes_test.go | 40 + .../internal/leafnodes/shared_runner_test.go | 356 + .../internal/leafnodes/suite_nodes_test.go | 230 + .../synchronized_after_suite_node_test.go | 199 + .../synchronized_before_suite_node_test.go | 446 + .../ginkgo/internal/remote/aggregator_test.go | 315 + .../remote/fake_output_interceptor_test.go | 17 + .../internal/remote/fake_poster_test.go | 33 + .../remote/forwarding_reporter_test.go | 181 + .../internal/remote/remote_suite_test.go | 13 + .../ginkgo/internal/remote/server_test.go | 269 + .../ginkgo/internal/spec/spec_suite_test.go | 13 + .../onsi/ginkgo/internal/spec/spec_test.go | 664 + .../onsi/ginkgo/internal/spec/specs_test.go | 287 + .../spec_iterator/index_computer_test.go | 149 + .../parallel_spec_iterator_test.go | 112 + .../serial_spec_iterator_test.go | 64 + .../sharded_parallel_spec_iterator_test.go | 62 + .../spec_iterator/spec_iterator_suite_test.go | 13 + .../specrunner/spec_runner_suite_test.go | 13 + .../internal/specrunner/spec_runner_test.go | 785 + .../ginkgo/internal/suite/suite_suite_test.go | 35 + .../onsi/ginkgo/internal/suite/suite_test.go | 385 + .../internal/writer/writer_suite_test.go | 13 + .../ginkgo/internal/writer/writer_test.go | 75 + .../ginkgo/reporters/default_reporter_test.go | 433 + .../ginkgo/reporters/junit_reporter_test.go | 251 + .../ginkgo/reporters/reporters_suite_test.go | 13 + .../reporters/stenographer/support/README.md | 6 + .../support/go-colorable/README.md | 43 + .../stenographer/support/go-isatty/README.md | 37 + .../reporters/teamcity_reporter_test.go | 214 + .../onsi/ginkgo/types/types_suite_test.go | 13 + .../onsi/ginkgo/types/types_test.go | 99 + vendor/github.com/onsi/gomega/.gitignore | 5 + vendor/github.com/onsi/gomega/.travis.yml | 14 + vendor/github.com/onsi/gomega/CHANGELOG.md | 99 + vendor/github.com/onsi/gomega/CONTRIBUTING.md | 14 + vendor/github.com/onsi/gomega/README.md | 21 + vendor/github.com/onsi/gomega/RELEASING.md | 12 + .../onsi/gomega/format/format_suite_test.go | 13 + .../onsi/gomega/format/format_test.go | 627 + .../assertion/assertion_suite_test.go | 13 + .../internal/assertion/assertion_test.go | 252 + .../async_assertion_suite_test.go | 13 + .../asyncassertion/async_assertion_test.go | 345 + .../testingtsupport/testing_t_support_test.go | 34 + .../onsi/gomega/matchers/and_test.go | 103 + .../assignable_to_type_of_matcher_test.go | 46 + .../gomega/matchers/be_a_directory_test.go | 40 + .../gomega/matchers/be_a_regular_file_test.go | 40 + .../matchers/be_an_existing_file_test.go | 40 + .../gomega/matchers/be_closed_matcher_test.go | 70 + .../gomega/matchers/be_empty_matcher_test.go | 52 + .../matchers/be_equivalent_to_matcher_test.go | 50 + .../gomega/matchers/be_false_matcher_test.go | 20 + .../gomega/matchers/be_identical_to_test.go | 61 + .../gomega/matchers/be_nil_matcher_test.go | 28 + .../matchers/be_numerically_matcher_test.go | 148 + .../gomega/matchers/be_sent_matcher_test.go | 107 + .../matchers/be_temporally_matcher_test.go | 99 + .../gomega/matchers/be_true_matcher_test.go | 20 + .../gomega/matchers/be_zero_matcher_test.go | 30 + .../onsi/gomega/matchers/consist_of_test.go | 75 + .../matchers/contain_element_matcher_test.go | 76 + .../contain_substring_matcher_test.go | 36 + .../gomega/matchers/equal_matcher_test.go | 80 + .../gomega/matchers/have_cap_matcher_test.go | 50 + .../gomega/matchers/have_key_matcher_test.go | 73 + .../have_key_with_value_matcher_test.go | 82 + .../gomega/matchers/have_len_matcher_test.go | 53 + .../matchers/have_occurred_matcher_test.go | 59 + .../matchers/have_prefix_matcher_test.go | 36 + .../matchers/have_suffix_matcher_test.go | 36 + .../matchers/match_error_matcher_test.go | 107 + .../matchers/match_json_matcher_test.go | 97 + .../matchers/match_regexp_matcher_test.go | 44 + .../gomega/matchers/match_xml_matcher_test.go | 97 + .../matchers/match_yaml_matcher_test.go | 94 + .../matchers/matcher_tests_suite_test.go | 50 + .../onsi/gomega/matchers/not_test.go | 57 + .../onsi/gomega/matchers/or_test.go | 85 + .../gomega/matchers/panic_matcher_test.go | 45 + .../gomega/matchers/receive_matcher_test.go | 280 + .../gomega/matchers/succeed_matcher_test.go | 62 + .../matchers/support/goraph/MIT.LICENSE | 20 + .../gomega/matchers/with_transform_test.go | 102 + vendor/github.com/petar/GoLLRB/.gitignore | 23 + vendor/github.com/petar/GoLLRB/README.md | 66 + .../petar/GoLLRB/llrb/iterator_test.go | 76 + .../github.com/petar/GoLLRB/llrb/llrb_test.go | 239 + .../github.com/peterbourgon/diskv/README.md | 141 + .../peterbourgon/diskv/basic_test.go | 336 + .../peterbourgon/diskv/compression_test.go | 72 + .../peterbourgon/diskv/import_test.go | 76 + .../peterbourgon/diskv/index_test.go | 148 + .../peterbourgon/diskv/issues_test.go | 121 + .../peterbourgon/diskv/keys_test.go | 231 + .../peterbourgon/diskv/speed_test.go | 153 + .../peterbourgon/diskv/stream_test.go | 117 + .../prometheus/client_golang/.gitignore | 26 + .../prometheus/client_golang/.travis.yml | 10 + .../prometheus/client_golang/CHANGELOG.md | 109 + .../prometheus/client_golang/CONTRIBUTING.md | 18 + .../prometheus/client_golang/MAINTAINERS.md | 1 + .../prometheus/client_golang/README.md | 47 + .../prometheus/client_golang/VERSION | 1 + .../client_golang/prometheus/.gitignore | 1 + .../client_golang/prometheus/README.md | 1 + .../prometheus/benchmark_test.go | 185 + .../client_golang/prometheus/counter_test.go | 58 + .../prometheus/example_clustermanager_test.go | 118 + .../prometheus/example_timer_complex_test.go | 71 + .../prometheus/example_timer_gauge_test.go | 48 + .../prometheus/example_timer_test.go | 40 + .../client_golang/prometheus/examples_test.go | 754 + .../prometheus/expvar_collector_test.go | 97 + .../client_golang/prometheus/gauge_test.go | 202 + .../prometheus/go_collector_test.go | 126 + .../prometheus/histogram_test.go | 348 + .../client_golang/prometheus/http_test.go | 154 + .../client_golang/prometheus/metric_test.go | 35 + .../prometheus/process_collector_test.go | 58 + .../client_golang/prometheus/registry_test.go | 546 + .../client_golang/prometheus/summary_test.go | 388 + .../client_golang/prometheus/timer_test.go | 152 + .../client_golang/prometheus/vec_test.go | 312 + .../prometheus/client_model/.gitignore | 1 + .../prometheus/client_model/CONTRIBUTING.md | 18 + .../prometheus/client_model/MAINTAINERS.md | 1 + .../prometheus/client_model/Makefile | 62 + .../prometheus/client_model/README.md | 26 + .../prometheus/client_model/metrics.proto | 81 + .../prometheus/client_model/pom.xml | 130 + .../prometheus/client_model/ruby/LICENSE | 201 - .../prometheus/client_model/setup.py | 23 + .../github.com/prometheus/common/.travis.yml | 6 + .../prometheus/common/CONTRIBUTING.md | 18 + .../prometheus/common/MAINTAINERS.md | 1 + vendor/github.com/prometheus/common/README.md | 12 + .../prometheus/common/expfmt/bench_test.go | 167 + .../prometheus/common/expfmt/decode_test.go | 435 + .../common/expfmt/text_create_test.go | 443 + .../common/expfmt/text_parse_test.go | 593 + .../bitbucket.org/ww/goautoneg/README.txt | 67 + .../ww/goautoneg/autoneg_test.go | 33 + .../prometheus/common/model/alert_test.go | 118 + .../prometheus/common/model/labels_test.go | 140 + .../prometheus/common/model/metric_test.go | 132 + .../prometheus/common/model/signature_test.go | 314 + .../prometheus/common/model/silence_test.go | 228 + .../prometheus/common/model/time_test.go | 132 + .../prometheus/common/model/value_test.go | 468 + .../github.com/prometheus/procfs/.gitignore | 1 + .../github.com/prometheus/procfs/.travis.yml | 15 + .../prometheus/procfs/CONTRIBUTING.md | 18 + .../prometheus/procfs/MAINTAINERS.md | 1 + vendor/github.com/prometheus/procfs/Makefile | 71 + vendor/github.com/prometheus/procfs/README.md | 11 + .../prometheus/procfs/buddyinfo_test.go | 64 + .../prometheus/procfs/fixtures.ttar | 446 + .../github.com/prometheus/procfs/fs_test.go | 39 + .../github.com/prometheus/procfs/ipvs_test.go | 250 + .../prometheus/procfs/mdstat_test.go | 44 + .../prometheus/procfs/mountstats_test.go | 286 + .../prometheus/procfs/net_dev_test.go | 86 + .../prometheus/procfs/nfs/parse_nfs_test.go | 305 + .../prometheus/procfs/nfs/parse_nfsd_test.go | 196 + .../prometheus/procfs/proc_io_test.go | 46 + .../prometheus/procfs/proc_limits_test.go | 44 + .../prometheus/procfs/proc_ns_test.go | 44 + .../prometheus/procfs/proc_stat_test.go | 123 + .../github.com/prometheus/procfs/proc_test.go | 174 + .../github.com/prometheus/procfs/stat_test.go | 74 + vendor/github.com/prometheus/procfs/ttar | 389 + .../github.com/prometheus/procfs/xfrm_test.go | 66 + .../prometheus/procfs/xfs/parse_test.go | 442 + vendor/github.com/satori/go.uuid/.travis.yml | 23 + vendor/github.com/satori/go.uuid/README.md | 65 + .../github.com/satori/go.uuid/codec_test.go | 248 + .../satori/go.uuid/generator_test.go | 134 + vendor/github.com/satori/go.uuid/sql_test.go | 136 + vendor/github.com/satori/go.uuid/uuid_test.go | 90 + vendor/github.com/spf13/pflag/.gitignore | 2 + vendor/github.com/spf13/pflag/.travis.yml | 21 + vendor/github.com/spf13/pflag/README.md | 296 + .../github.com/spf13/pflag/bool_slice_test.go | 215 + vendor/github.com/spf13/pflag/bool_test.go | 179 + vendor/github.com/spf13/pflag/bytes_test.go | 72 + vendor/github.com/spf13/pflag/count_test.go | 56 + .../spf13/pflag/duration_slice_test.go | 165 + vendor/github.com/spf13/pflag/example_test.go | 36 + vendor/github.com/spf13/pflag/export_test.go | 29 + vendor/github.com/spf13/pflag/flag_test.go | 1259 + .../github.com/spf13/pflag/golangflag_test.go | 47 + .../github.com/spf13/pflag/int_slice_test.go | 165 + .../github.com/spf13/pflag/ip_slice_test.go | 222 + vendor/github.com/spf13/pflag/ip_test.go | 63 + vendor/github.com/spf13/pflag/ipnet_test.go | 70 + .../github.com/spf13/pflag/printusage_test.go | 74 + .../spf13/pflag/string_array_test.go | 233 + .../spf13/pflag/string_slice_test.go | 253 + .../github.com/spf13/pflag/uint_slice_test.go | 161 + vendor/golang.org/x/crypto/.gitattributes | 10 + vendor/golang.org/x/crypto/.gitignore | 2 + vendor/golang.org/x/crypto/CONTRIBUTING.md | 26 + vendor/golang.org/x/crypto/README.md | 21 + vendor/golang.org/x/crypto/codereview.cfg | 1 + .../golang.org/x/crypto/ssh/benchmark_test.go | 123 + vendor/golang.org/x/crypto/ssh/buffer.go | 97 + vendor/golang.org/x/crypto/ssh/buffer_test.go | 87 + vendor/golang.org/x/crypto/ssh/certs.go | 521 + vendor/golang.org/x/crypto/ssh/certs_test.go | 335 + vendor/golang.org/x/crypto/ssh/channel.go | 633 + vendor/golang.org/x/crypto/ssh/cipher.go | 770 + vendor/golang.org/x/crypto/ssh/cipher_test.go | 131 + vendor/golang.org/x/crypto/ssh/client.go | 278 + vendor/golang.org/x/crypto/ssh/client_auth.go | 525 + .../x/crypto/ssh/client_auth_test.go | 628 + vendor/golang.org/x/crypto/ssh/client_test.go | 166 + vendor/golang.org/x/crypto/ssh/common.go | 383 + vendor/golang.org/x/crypto/ssh/connection.go | 143 + vendor/golang.org/x/crypto/ssh/doc.go | 21 + .../golang.org/x/crypto/ssh/example_test.go | 320 + vendor/golang.org/x/crypto/ssh/handshake.go | 646 + .../golang.org/x/crypto/ssh/handshake_test.go | 559 + vendor/golang.org/x/crypto/ssh/kex.go | 540 + vendor/golang.org/x/crypto/ssh/kex_test.go | 50 + vendor/golang.org/x/crypto/ssh/keys.go | 1032 + vendor/golang.org/x/crypto/ssh/keys_test.go | 500 + vendor/golang.org/x/crypto/ssh/mac.go | 61 + .../golang.org/x/crypto/ssh/mempipe_test.go | 110 + vendor/golang.org/x/crypto/ssh/messages.go | 766 + .../golang.org/x/crypto/ssh/messages_test.go | 288 + vendor/golang.org/x/crypto/ssh/mux.go | 330 + vendor/golang.org/x/crypto/ssh/mux_test.go | 501 + vendor/golang.org/x/crypto/ssh/server.go | 593 + vendor/golang.org/x/crypto/ssh/session.go | 647 + .../golang.org/x/crypto/ssh/session_test.go | 774 + vendor/golang.org/x/crypto/ssh/streamlocal.go | 116 + vendor/golang.org/x/crypto/ssh/tcpip.go | 474 + vendor/golang.org/x/crypto/ssh/tcpip_test.go | 20 + .../x/crypto/ssh/terminal/terminal_test.go | 358 + .../golang.org/x/crypto/ssh/testdata_test.go | 63 + vendor/golang.org/x/crypto/ssh/transport.go | 353 + .../golang.org/x/crypto/ssh/transport_test.go | 113 + vendor/golang.org/x/net/.gitattributes | 10 + vendor/golang.org/x/net/.gitignore | 2 + vendor/golang.org/x/net/CONTRIBUTING.md | 26 + vendor/golang.org/x/net/README.md | 16 + vendor/golang.org/x/net/codereview.cfg | 1 + .../golang.org/x/net/context/context_test.go | 583 + .../x/net/context/ctxhttp/ctxhttp_17_test.go | 29 + .../net/context/ctxhttp/ctxhttp_pre17_test.go | 79 + .../x/net/context/ctxhttp/ctxhttp_test.go | 105 + .../x/net/context/withtimeout_test.go | 31 + .../golang.org/x/net/html/atom/atom_test.go | 109 + .../golang.org/x/net/html/atom/table_test.go | 376 + .../x/net/html/charset/charset_test.go | 237 + vendor/golang.org/x/net/html/entity_test.go | 29 + vendor/golang.org/x/net/html/escape_test.go | 97 + vendor/golang.org/x/net/html/example_test.go | 40 + vendor/golang.org/x/net/html/node_test.go | 146 + vendor/golang.org/x/net/html/parse_test.go | 400 + vendor/golang.org/x/net/html/render_test.go | 156 + vendor/golang.org/x/net/html/token_test.go | 748 + .../x/net/http/httpguts/httplex_test.go | 119 + vendor/golang.org/x/net/http2/.gitignore | 2 + vendor/golang.org/x/net/http2/Dockerfile | 51 + vendor/golang.org/x/net/http2/Makefile | 3 + vendor/golang.org/x/net/http2/README | 20 + vendor/golang.org/x/net/http2/ciphers_test.go | 309 + .../golang.org/x/net/http2/databuffer_test.go | 157 + vendor/golang.org/x/net/http2/errors_test.go | 24 + vendor/golang.org/x/net/http2/flow_test.go | 53 + vendor/golang.org/x/net/http2/frame_test.go | 1191 + vendor/golang.org/x/net/http2/go18_test.go | 79 + vendor/golang.org/x/net/http2/go19_test.go | 59 + vendor/golang.org/x/net/http2/gotrack_test.go | 33 + .../x/net/http2/hpack/encode_test.go | 386 + .../x/net/http2/hpack/hpack_test.go | 741 + .../x/net/http2/hpack/tables_test.go | 214 + vendor/golang.org/x/net/http2/http2_test.go | 199 + vendor/golang.org/x/net/http2/pipe_test.go | 130 + .../x/net/http2/server_push_test.go | 521 + vendor/golang.org/x/net/http2/server_test.go | 3785 ++ .../golang.org/x/net/http2/transport_test.go | 3848 ++ .../x/net/http2/writesched_priority_test.go | 541 + .../x/net/http2/writesched_random_test.go | 44 + .../golang.org/x/net/http2/writesched_test.go | 125 + vendor/golang.org/x/net/http2/z_spec_test.go | 356 + vendor/golang.org/x/net/idna/example_test.go | 70 + vendor/golang.org/x/net/idna/idna_test.go | 108 + vendor/golang.org/x/net/idna/punycode_test.go | 198 + vendor/golang.org/x/oauth2/.travis.yml | 13 + vendor/golang.org/x/oauth2/CONTRIBUTING.md | 26 + vendor/golang.org/x/oauth2/README.md | 77 + vendor/golang.org/x/oauth2/example_test.go | 89 + .../x/oauth2/google/example_test.go | 162 + .../golang.org/x/oauth2/google/google_test.go | 116 + vendor/golang.org/x/oauth2/google/jwt_test.go | 91 + vendor/golang.org/x/oauth2/google/sdk_test.go | 107 + .../x/oauth2/internal/token_test.go | 112 + vendor/golang.org/x/oauth2/jws/jws_test.go | 46 + .../golang.org/x/oauth2/jwt/example_test.go | 33 + vendor/golang.org/x/oauth2/jwt/jwt_test.go | 221 + vendor/golang.org/x/oauth2/oauth2_test.go | 505 + vendor/golang.org/x/oauth2/token_test.go | 72 + vendor/golang.org/x/oauth2/transport_test.go | 108 + vendor/golang.org/x/sys/.gitattributes | 10 + vendor/golang.org/x/sys/.gitignore | 2 + vendor/golang.org/x/sys/CONTRIBUTING.md | 26 + vendor/golang.org/x/sys/README.md | 18 + vendor/golang.org/x/sys/codereview.cfg | 1 + vendor/golang.org/x/sys/unix/.gitignore | 2 + vendor/golang.org/x/sys/unix/README.md | 173 + vendor/golang.org/x/sys/unix/creds_test.go | 134 + .../golang.org/x/sys/unix/dev_linux_test.go | 53 + vendor/golang.org/x/sys/unix/example_test.go | 19 + vendor/golang.org/x/sys/unix/export_test.go | 9 + vendor/golang.org/x/sys/unix/mkall.sh | 188 + vendor/golang.org/x/sys/unix/mkerrors.sh | 601 + vendor/golang.org/x/sys/unix/mksyscall.pl | 341 + .../x/sys/unix/mksyscall_solaris.pl | 289 + .../golang.org/x/sys/unix/mksysctl_openbsd.pl | 264 + .../golang.org/x/sys/unix/mksysnum_darwin.pl | 39 + .../x/sys/unix/mksysnum_dragonfly.pl | 50 + .../golang.org/x/sys/unix/mksysnum_freebsd.pl | 50 + .../golang.org/x/sys/unix/mksysnum_netbsd.pl | 58 + .../golang.org/x/sys/unix/mksysnum_openbsd.pl | 50 + .../golang.org/x/sys/unix/mmap_unix_test.go | 35 + vendor/golang.org/x/sys/unix/openbsd_test.go | 113 + .../golang.org/x/sys/unix/syscall_bsd_test.go | 93 + .../x/sys/unix/syscall_darwin_test.go | 19 + .../x/sys/unix/syscall_freebsd_test.go | 312 + .../x/sys/unix/syscall_linux_test.go | 387 + .../x/sys/unix/syscall_solaris_test.go | 55 + vendor/golang.org/x/sys/unix/syscall_test.go | 60 + .../x/sys/unix/syscall_unix_test.go | 627 + .../golang.org/x/sys/unix/timestruct_test.go | 54 + vendor/golang.org/x/sys/unix/xattr_test.go | 118 + .../golang.org/x/sys/windows/syscall_test.go | 53 + .../x/sys/windows/syscall_windows_test.go | 107 + vendor/golang.org/x/text/.gitattributes | 10 + vendor/golang.org/x/text/.gitignore | 6 + vendor/golang.org/x/text/CONTRIBUTING.md | 31 + vendor/golang.org/x/text/README.md | 93 + vendor/golang.org/x/text/codereview.cfg | 1 + .../x/text/collate/build/builder_test.go | 290 + .../x/text/collate/build/colelem_test.go | 215 + .../x/text/collate/build/contract_test.go | 266 + .../x/text/collate/build/order_test.go | 229 + .../x/text/collate/build/trie_test.go | 107 + .../golang.org/x/text/collate/collate_test.go | 482 + .../golang.org/x/text/collate/export_test.go | 51 + .../golang.org/x/text/collate/option_test.go | 209 + vendor/golang.org/x/text/collate/reg_test.go | 230 + vendor/golang.org/x/text/collate/sort_test.go | 55 + .../golang.org/x/text/collate/table_test.go | 291 + vendor/golang.org/x/text/doc.go | 13 + .../x/text/encoding/charmap/charmap_test.go | 258 + .../x/text/encoding/encoding_test.go | 290 + .../x/text/encoding/example_test.go | 42 + .../text/encoding/htmlindex/htmlindex_test.go | 144 + .../x/text/encoding/japanese/all_test.go | 248 + .../x/text/encoding/korean/all_test.go | 94 + .../encoding/simplifiedchinese/all_test.go | 143 + .../encoding/traditionalchinese/all_test.go | 114 + .../x/text/encoding/unicode/unicode_test.go | 499 + vendor/golang.org/x/text/gen.go | 319 + .../x/text/internal/colltab/collate_test.go | 121 + .../x/text/internal/colltab/collelem_test.go | 183 + .../x/text/internal/colltab/colltab_test.go | 64 + .../x/text/internal/colltab/contract_test.go | 131 + .../x/text/internal/colltab/iter_test.go | 63 + .../x/text/internal/colltab/numeric_test.go | 159 + .../x/text/internal/colltab/trie_test.go | 106 + .../x/text/internal/colltab/weighter_test.go | 42 + vendor/golang.org/x/text/internal/gen.go | 52 + vendor/golang.org/x/text/internal/gen_test.go | 38 + vendor/golang.org/x/text/internal/internal.go | 51 + .../x/text/internal/internal_test.go | 38 + vendor/golang.org/x/text/internal/match.go | 67 + .../golang.org/x/text/internal/match_test.go | 56 + vendor/golang.org/x/text/internal/tables.go | 118 + .../x/text/internal/tag/tag_test.go | 67 + .../x/text/internal/triegen/data_test.go | 875 + .../internal/triegen/example_compact_test.go | 71 + .../x/text/internal/triegen/example_test.go | 148 + .../x/text/internal/triegen/gen_test.go | 68 + .../x/text/internal/ucd/example_test.go | 81 + .../x/text/internal/ucd/ucd_test.go | 105 + vendor/golang.org/x/text/language/Makefile | 16 + .../x/text/language/coverage_test.go | 154 + .../x/text/language/examples_test.go | 413 + .../x/text/language/httpexample_test.go | 48 + .../x/text/language/language_test.go | 911 + .../golang.org/x/text/language/lookup_test.go | 457 + .../golang.org/x/text/language/match_test.go | 505 + .../golang.org/x/text/language/parse_test.go | 517 + vendor/golang.org/x/text/runes/cond_test.go | 282 + .../golang.org/x/text/runes/example_test.go | 60 + vendor/golang.org/x/text/runes/runes_test.go | 664 + .../x/text/secure/bidirule/bench_test.go | 54 + .../secure/bidirule/bidirule10.0.0_test.go | 694 + .../secure/bidirule/bidirule9.0.0_test.go | 668 + .../x/text/secure/bidirule/bidirule_test.go | 168 + vendor/golang.org/x/text/secure/doc.go | 6 + .../x/text/transform/examples_test.go | 37 + .../x/text/transform/transform_test.go | 1317 + .../x/text/unicode/bidi/core_test.go | 224 + .../x/text/unicode/bidi/ranges_test.go | 53 + .../x/text/unicode/bidi/tables_test.go | 82 + .../x/text/unicode/cldr/cldr_test.go | 27 + .../x/text/unicode/cldr/collate_test.go | 275 + .../x/text/unicode/cldr/data_test.go | 186 + .../x/text/unicode/cldr/examples_test.go | 21 + .../x/text/unicode/cldr/resolve_test.go | 368 + .../x/text/unicode/cldr/slice_test.go | 175 + vendor/golang.org/x/text/unicode/doc.go | 8 + .../x/text/unicode/norm/composition_test.go | 130 + .../x/text/unicode/norm/data10.0.0_test.go | 7424 ++++ .../x/text/unicode/norm/data9.0.0_test.go | 7409 ++++ .../x/text/unicode/norm/example_iter_test.go | 82 + .../x/text/unicode/norm/example_test.go | 27 + .../x/text/unicode/norm/forminfo_test.go | 54 + .../x/text/unicode/norm/iter_test.go | 98 + .../x/text/unicode/norm/normalize_test.go | 1287 + .../x/text/unicode/norm/readwriter_test.go | 56 + .../x/text/unicode/norm/transform_test.go | 101 + .../x/text/unicode/norm/ucd_test.go | 275 + .../x/text/unicode/rangetable/merge_test.go | 184 + .../unicode/rangetable/rangetable_test.go | 55 + vendor/golang.org/x/text/width/common_test.go | 92 + .../golang.org/x/text/width/example_test.go | 52 + vendor/golang.org/x/text/width/runes_test.go | 461 + vendor/golang.org/x/text/width/tables_test.go | 59 + .../golang.org/x/text/width/transform_test.go | 701 + vendor/golang.org/x/time/CONTRIBUTING.md | 26 + vendor/golang.org/x/time/README.md | 17 + vendor/golang.org/x/time/rate/rate_test.go | 459 + vendor/golang.org/x/tools/.gitattributes | 10 + vendor/golang.org/x/tools/.gitignore | 2 + vendor/golang.org/x/tools/CONTRIBUTING.md | 26 + vendor/golang.org/x/tools/README.md | 27 + vendor/golang.org/x/tools/cmd/getgo/LICENSE | 27 - vendor/golang.org/x/tools/codereview.cfg | 1 + .../x/tools/go/ast/astutil/enclosing_test.go | 195 + .../x/tools/go/ast/astutil/imports_test.go | 1818 + .../x/tools/go/ast/astutil/rewrite_test.go | 248 + vendor/golang.org/x/tools/imports/fix_test.go | 2175 ++ .../tools/internal/fastwalk/fastwalk_test.go | 190 + .../x/tools/third_party/moduleloader/LICENSE | 22 - .../x/tools/third_party/typescript/LICENSE | 55 - .../x/tools/third_party/webcomponents/LICENSE | 27 - vendor/google.golang.org/api/.gitignore | 12 + vendor/google.golang.org/api/.hgtags | 1 + vendor/google.golang.org/api/.travis.yml | 18 + vendor/google.golang.org/api/CONTRIBUTING.md | 484 + .../google.golang.org/api/GettingStarted.md | 130 + vendor/google.golang.org/api/NOTES | 13 + vendor/google.golang.org/api/README.md | 104 + vendor/google.golang.org/api/TODO | 2 + vendor/google.golang.org/api/api-list.json | 3140 ++ .../api/compute/v1/compute-api.json | 31438 ++++++++++++++++ .../api/gensupport/backoff_test.go | 46 + .../api/gensupport/buffer_test.go | 296 + .../api/gensupport/header_test.go | 28 + .../api/gensupport/json_test.go | 516 + .../api/gensupport/jsonfloat_test.go | 53 + .../api/gensupport/media_test.go | 407 + .../api/gensupport/resumable_test.go | 281 + .../api/gensupport/retry_test.go | 176 + .../api/gensupport/send_test.go | 20 + .../api/gensupport/util_test.go | 57 + .../api/googleapi/googleapi_test.go | 291 + .../uritemplates/uritemplates_test.go | 280 + .../api/googleapi/types_test.go | 68 + vendor/google.golang.org/api/key.json.enc | Bin 0 -> 2432 bytes .../google.golang.org/appengine/.travis.yml | 18 + vendor/google.golang.org/appengine/README.md | 73 + .../appengine/appengine_test.go | 49 + .../appengine/internal/api_race_test.go | 9 + .../appengine/internal/api_test.go | 467 + .../appengine/internal/app_id_test.go | 34 + .../app_identity/app_identity_service.proto | 64 + .../appengine/internal/base/api_base.proto | 33 + .../internal/datastore/datastore_v3.proto | 541 + .../appengine/internal/internal_vm_test.go | 60 + .../appengine/internal/log/log_service.proto | 150 + .../internal/modules/modules_service.proto | 80 + .../appengine/internal/net_test.go | 58 + .../appengine/internal/regen.sh | 40 + .../internal/remote_api/remote_api.proto | 44 + .../internal/urlfetch/urlfetch_service.proto | 64 + .../appengine/namespace_test.go | 39 + vendor/gopkg.in/inf.v0/benchmark_test.go | 210 + vendor/gopkg.in/inf.v0/dec_go1_2_test.go | 33 + vendor/gopkg.in/inf.v0/dec_internal_test.go | 40 + vendor/gopkg.in/inf.v0/dec_test.go | 379 + vendor/gopkg.in/inf.v0/example_test.go | 62 + .../gopkg.in/inf.v0/rounder_example_test.go | 73 + vendor/gopkg.in/inf.v0/rounder_test.go | 109 + vendor/gopkg.in/yaml.v2/.travis.yml | 12 + vendor/gopkg.in/yaml.v2/README.md | 133 + vendor/gopkg.in/yaml.v2/decode_test.go | 1326 + vendor/gopkg.in/yaml.v2/encode_test.go | 595 + .../gopkg.in/yaml.v2/example_embedded_test.go | 41 + vendor/gopkg.in/yaml.v2/go.mod | 5 + vendor/gopkg.in/yaml.v2/suite_test.go | 12 + vendor/k8s.io/api/CONTRIBUTING.md | 7 + vendor/k8s.io/api/OWNERS | 52 + vendor/k8s.io/api/README.md | 1 + vendor/k8s.io/api/SECURITY_CONTACTS | 17 + .../v1alpha1/generated.proto | 107 + .../v1beta1/generated.proto | 269 + vendor/k8s.io/api/apps/OWNERS | 19 + vendor/k8s.io/api/apps/v1/generated.proto | 700 + .../k8s.io/api/apps/v1beta1/generated.proto | 483 + .../k8s.io/api/apps/v1beta2/generated.proto | 751 + vendor/k8s.io/api/authentication/OWNERS | 9 + .../api/authentication/v1/generated.proto | 159 + .../authentication/v1beta1/generated.proto | 98 + vendor/k8s.io/api/authorization/OWNERS | 17 + .../api/authorization/v1/generated.proto | 272 + .../api/authorization/v1beta1/generated.proto | 272 + vendor/k8s.io/api/autoscaling/OWNERS | 19 + .../k8s.io/api/autoscaling/v1/generated.proto | 415 + .../api/autoscaling/v2beta1/generated.proto | 397 + .../api/autoscaling/v2beta2/generated.proto | 369 + vendor/k8s.io/api/batch/OWNERS | 18 + vendor/k8s.io/api/batch/v1/generated.proto | 184 + .../k8s.io/api/batch/v1beta1/generated.proto | 137 + .../k8s.io/api/batch/v2alpha1/generated.proto | 135 + vendor/k8s.io/api/certificates/OWNERS | 14 + .../api/certificates/v1beta1/generated.proto | 121 + vendor/k8s.io/api/code-of-conduct.md | 3 + .../api/coordination/v1beta1/generated.proto | 80 + vendor/k8s.io/api/core/v1/generated.proto | 4757 +++ vendor/k8s.io/api/core/v1/taint_test.go | 122 + vendor/k8s.io/api/core/v1/toleration_test.go | 123 + vendor/k8s.io/api/events/OWNERS | 8 + .../k8s.io/api/events/v1beta1/generated.proto | 121 + vendor/k8s.io/api/extensions/OWNERS | 38 + .../api/extensions/v1beta1/generated.proto | 1166 + vendor/k8s.io/api/networking/OWNERS | 5 + .../k8s.io/api/networking/v1/generated.proto | 195 + vendor/k8s.io/api/policy/OWNERS | 8 + .../k8s.io/api/policy/v1beta1/generated.proto | 341 + vendor/k8s.io/api/rbac/OWNERS | 17 + vendor/k8s.io/api/rbac/v1/generated.proto | 197 + .../k8s.io/api/rbac/v1alpha1/generated.proto | 199 + .../k8s.io/api/rbac/v1beta1/generated.proto | 198 + vendor/k8s.io/api/roundtrip_test.go | 151 + .../api/scheduling/v1alpha1/generated.proto | 67 + .../api/scheduling/v1beta1/generated.proto | 67 + .../api/settings/v1alpha1/generated.proto | 75 + vendor/k8s.io/api/storage/OWNERS | 3 + vendor/k8s.io/api/storage/v1/generated.proto | 90 + .../api/storage/v1alpha1/generated.proto | 126 + .../api/storage/v1beta1/generated.proto | 186 + vendor/k8s.io/apimachinery/CONTRIBUTING.md | 7 + vendor/k8s.io/apimachinery/OWNERS | 23 + vendor/k8s.io/apimachinery/README.md | 29 + vendor/k8s.io/apimachinery/SECURITY_CONTACTS | 17 + vendor/k8s.io/apimachinery/code-of-conduct.md | 3 + vendor/k8s.io/apimachinery/pkg/OWNERS | 6 + .../k8s.io/apimachinery/pkg/api/errors/OWNERS | 24 + .../pkg/api/errors/errors_test.go | 222 + .../k8s.io/apimachinery/pkg/api/meta/OWNERS | 25 + .../apimachinery/pkg/api/meta/meta_test.go | 51 + .../pkg/api/meta/multirestmapper_test.go | 391 + .../pkg/api/meta/priority_test.go | 409 + .../pkg/api/meta/restmapper_test.go | 724 + .../apimachinery/pkg/api/resource/OWNERS | 16 + .../pkg/api/resource/amount_test.go | 162 + .../pkg/api/resource/generated.proto | 88 + .../pkg/api/resource/math_test.go | 211 + .../pkg/api/resource/quantity_example_test.go | 59 + .../pkg/api/resource/quantity_proto_test.go | 103 + .../pkg/api/resource/quantity_test.go | 1352 + .../pkg/api/resource/scale_int_test.go | 85 + .../pkg/api/validation/objectmeta_test.go | 500 + .../meta/internalversion/register_test.go | 89 + .../meta/internalversion/roundtrip_test.go} | 15 +- .../apimachinery/pkg/apis/meta/v1/OWNERS | 31 + .../pkg/apis/meta/v1/controller_ref_test.go | 133 + .../pkg/apis/meta/v1/conversion_test.go | 84 + .../pkg/apis/meta/v1/duration_test.go | 153 + .../pkg/apis/meta/v1/generated.proto | 879 + .../pkg/apis/meta/v1/group_version_test.go | 79 + .../pkg/apis/meta/v1/helpers_test.go | 161 + .../pkg/apis/meta/v1/labels_test.go | 123 + .../pkg/apis/meta/v1/micro_time_test.go | 139 + .../pkg/apis/meta/v1/time_test.go | 197 + .../pkg/apis/meta/v1/types_test.go | 135 + .../apis/meta/v1/unstructured/helpers_test.go | 136 + .../v1/unstructured/unstructured_list_test.go | 86 + .../meta/v1/unstructured/unstructured_test.go | 162 + .../meta/v1/validation/validation_test.go | 127 + .../pkg/apis/meta/v1beta1/generated.proto | 57 + .../pkg/conversion/converter_test.go | 734 + .../pkg/conversion/helper_test.go} | 32 +- .../conversion/queryparams/convert_test.go | 219 + .../apimachinery/pkg/fields/fields_test.go | 57 + .../apimachinery/pkg/fields/selector_test.go | 397 + .../apimachinery/pkg/labels/labels_test.go | 231 + .../apimachinery/pkg/labels/selector_test.go | 619 + .../pkg/runtime/conversion_test.go | 115 + .../pkg/runtime/converter_test.go | 597 + .../apimachinery/pkg/runtime/embedded_test.go | 256 + .../pkg/runtime/extension_test.go | 113 + .../apimachinery/pkg/runtime/generated.proto | 127 + .../pkg/runtime/local_scheme_test.go | 150 + .../pkg/runtime/schema/generated.proto} | 11 +- .../pkg/runtime/schema/group_version_test.go | 180 + .../apimachinery/pkg/runtime/scheme_test.go | 1021 + .../pkg/runtime/serializer/codec_test.go | 339 + .../pkg/runtime/serializer/json/json_test.go | 346 + .../pkg/runtime/serializer/json/meta_test.go | 45 + .../pkg/runtime/serializer/sparse_test.go | 91 + .../serializer/streaming/streaming_test.go | 84 + .../serializer/versioning/versioning_test.go | 382 + .../runtime/swagger_doc_generator_test.go} | 40 +- .../apimachinery/pkg/util/cache/cache_test.go | 90 + .../pkg/util/cache/lruexpirecache_test.go | 68 + .../apimachinery/pkg/util/clock/clock_test.go | 196 + .../apimachinery/pkg/util/diff/diff_test.go | 148 + .../pkg/util/errors/errors_test.go | 368 + .../pkg/util/framer/framer_test.go | 176 + .../pkg/util/intstr/generated.proto | 43 + .../pkg/util/intstr/intstr_test.go | 183 + .../apimachinery/pkg/util/json/json_test.go | 319 + .../apimachinery/pkg/util/mergepatch/OWNERS | 5 + .../pkg/util/mergepatch/util_test.go | 136 + .../pkg/util/naming/from_stack_test.go | 56 + .../apimachinery/pkg/util/net/http_test.go | 282 + .../pkg/util/net/interface_test.go | 725 + .../pkg/util/net/port_range_test.go | 77 + .../pkg/util/net/port_split_test.go | 121 + .../apimachinery/pkg/util/net/util_test.go | 68 + .../apimachinery/pkg/util/rand/rand_test.go | 114 + .../pkg/util/runtime/runtime_test.go | 71 + .../apimachinery/pkg/util/sets/set_test.go | 270 + .../pkg/util/strategicpatch/OWNERS | 6 + .../pkg/util/strategicpatch/patch_test.go | 6763 ++++ .../pkg/util/validation/field/errors_test.go | 175 + .../pkg/util/validation/field/path_test.go | 123 + .../pkg/util/validation/validation_test.go | 541 + .../apimachinery/pkg/util/wait/wait_test.go | 501 + .../pkg/util/yaml/decoder_test.go | 405 + .../apimachinery/pkg/version/helpers_test.go | 52 + .../apimachinery/pkg/watch/filter_test.go | 84 + .../k8s.io/apimachinery/pkg/watch/mux_test.go | 176 + .../pkg/watch/streamwatcher_test.go | 68 + .../apimachinery/pkg/watch/watch_test.go | 175 + .../third_party/forked/golang/json/OWNERS | 5 + .../forked/golang/json/fields_test.go | 30 + .../forked/golang/reflect/deep_equal_test.go | 137 + vendor/k8s.io/apiserver/.import-restrictions | 10 + vendor/k8s.io/apiserver/CONTRIBUTING.md | 7 + vendor/k8s.io/apiserver/OWNERS | 22 + vendor/k8s.io/apiserver/README.md | 30 + vendor/k8s.io/apiserver/SECURITY_CONTACTS | 17 + vendor/k8s.io/apiserver/code-of-conduct.md | 3 + .../pkg/util/feature/feature_gate_test.go | 347 + .../pkg/util/flag/ciphersuites_flag_test.go | 114 + ...n_separated_multimap_string_string_test.go | 242 + ...langle_separated_map_string_string_test.go | 159 + .../pkg/util/flag/map_string_bool_test.go | 163 + .../pkg/util/flag/map_string_string_test.go | 181 + .../pkg/util/flag/namedcertkey_flag_test.go | 138 + vendor/k8s.io/client-go/.travis.yml | 8 + vendor/k8s.io/client-go/CHANGELOG.md | 590 + vendor/k8s.io/client-go/CONTRIBUTING.md | 9 + vendor/k8s.io/client-go/INSTALL.md | 162 + vendor/k8s.io/client-go/OWNERS | 17 + vendor/k8s.io/client-go/README.md | 193 + vendor/k8s.io/client-go/SECURITY_CONTACTS | 17 + vendor/k8s.io/client-go/code-of-conduct.md | 3 + .../discovery/cached_discovery_test.go | 169 + .../discovery/discovery_client_test.go | 882 + .../discovery/fake/discovery_test.go | 46 + .../discovery/helper_blackbox_test.go | 184 + .../client-go/discovery/round_tripper_test.go | 95 + .../v1beta1/daemonset_expansion_test.go | 152 + .../client-go/pkg/version/.gitattributes | 1 + vendor/k8s.io/client-go/pkg/version/def.bzl | 38 + .../plugin/pkg/client/auth/exec/exec_test.go | 748 + .../plugin/pkg/client/auth/plugins.go} | 15 +- vendor/k8s.io/client-go/rest/OWNERS | 24 + vendor/k8s.io/client-go/rest/client_test.go | 343 + vendor/k8s.io/client-go/rest/config_test.go | 375 + vendor/k8s.io/client-go/rest/plugin_test.go | 311 + vendor/k8s.io/client-go/rest/request_test.go | 1937 + .../client-go/rest/token_source_test.go | 156 + .../k8s.io/client-go/rest/url_utils_test.go | 61 + .../k8s.io/client-go/rest/urlbackoff_test.go | 79 + .../client-go/rest/watch/decoder_test.go | 123 + .../client-go/rest/watch/encoder_test.go | 84 + .../k8s.io/client-go/testing/fixture_test.go | 235 + .../client-go/tools/auth/clientauth_test.go | 69 + vendor/k8s.io/client-go/tools/cache/OWNERS | 50 + .../client-go/tools/cache/controller_test.go | 405 + .../client-go/tools/cache/delta_fifo_test.go | 492 + .../tools/cache/expiration_cache_test.go | 189 + .../k8s.io/client-go/tools/cache/fifo_test.go | 280 + .../k8s.io/client-go/tools/cache/heap_test.go | 382 + .../client-go/tools/cache/index_test.go | 163 + .../tools/cache/mutation_detector_test.go | 81 + .../tools/cache/processor_listener_test.go | 58 + .../client-go/tools/cache/reflector_test.go | 389 + .../tools/cache/shared_informer_test.go | 265 + .../client-go/tools/cache/store_test.go | 156 + .../tools/cache/undelta_store_test.go | 131 + .../tools/clientcmd/api/helpers_test.go | 302 + .../tools/clientcmd/api/types_test.go | 135 + .../tools/clientcmd/client_config_test.go | 681 + .../client-go/tools/clientcmd/loader_test.go | 789 + .../clientcmd/merged_client_builder_test.go | 328 + .../tools/clientcmd/overrides_test.go | 50 + .../tools/clientcmd/validation_test.go | 574 + .../client-go/tools/leaderelection/OWNERS | 13 + .../leaderelection/leaderelection_test.go | 292 + vendor/k8s.io/client-go/tools/metrics/OWNERS | 7 + .../client-go/tools/pager/pager_test.go | 206 + vendor/k8s.io/client-go/tools/record/OWNERS | 27 + .../client-go/tools/record/event_test.go | 924 + .../tools/record/events_cache_test.go | 279 + .../client-go/tools/reference/ref_test.go | 72 + vendor/k8s.io/client-go/transport/OWNERS | 7 + .../k8s.io/client-go/transport/cache_test.go | 157 + .../transport/round_trippers_test.go | 329 + .../client-go/transport/transport_test.go | 288 + .../util/buffer/ring_growing_test.go | 50 + vendor/k8s.io/client-go/util/cert/csr_test.go | 75 + vendor/k8s.io/client-go/util/cert/pem_test.go | 197 + .../util/connrotation/connrotation_test.go | 61 + .../util/flowcontrol/backoff_test.go | 195 + .../util/flowcontrol/throttle_test.go | 153 + .../client-go/util/integer/integer_test.go | 244 + vendor/k8s.io/client-go/util/retry/OWNERS | 2 + .../k8s.io/client-go/util/retry/util_test.go | 71 + .../workqueue/default_rate_limiters_test.go | 184 + .../util/workqueue/delaying_queue_test.go | 255 + .../client-go/util/workqueue/queue_test.go | 161 + .../workqueue/rate_limitting_queue_test.go | 75 + .../.github/PULL_REQUEST_TEMPLATE.md | 2 - .../k8s.io/code-generator/Godeps/Godeps.json | 282 - vendor/k8s.io/code-generator/Godeps/OWNERS | 2 - vendor/k8s.io/code-generator/Godeps/Readme | 5 - .../apiserver/apis/example/install/install.go | 33 - .../apiserver/apis/example/register.go | 45 - .../_examples/apiserver/apis/example/types.go | 44 - .../apiserver/apis/example/v1/doc.go | 21 - .../apiserver/apis/example/v1/register.go | 59 - .../apiserver/apis/example/v1/types.go | 47 - .../example/v1/zz_generated.conversion.go | 137 - .../apis/example/v1/zz_generated.deepcopy.go | 101 - .../apis/example/zz_generated.deepcopy.go | 101 - .../_examples/apiserver/apis/example2/doc.go | 20 - .../apis/example2/install/install.go | 33 - .../apiserver/apis/example2/register.go | 45 - .../apiserver/apis/example2/types.go | 44 - .../apiserver/apis/example2/v1/register.go | 59 - .../apiserver/apis/example2/v1/types.go | 47 - .../example2/v1/zz_generated.conversion.go | 137 - .../apis/example2/v1/zz_generated.deepcopy.go | 101 - .../apis/example2/v1/zz_generated.defaults.go | 32 - .../apis/example2/zz_generated.deepcopy.go | 101 - .../clientset/internalversion/clientset.go | 104 - .../clientset/internalversion/doc.go | 20 - .../fake/clientset_generated.go | 84 - .../clientset/internalversion/fake/doc.go | 20 - .../internalversion/fake/register.go | 58 - .../clientset/internalversion/scheme/doc.go | 20 - .../internalversion/scheme/register.go | 43 - .../typed/example/internalversion/doc.go | 20 - .../example/internalversion/example_client.go | 96 - .../typed/example/internalversion/fake/doc.go | 20 - .../fake/fake_example_client.go | 40 - .../internalversion/fake/fake_testtype.go | 140 - .../internalversion/generated_expansion.go | 21 - .../typed/example/internalversion/testtype.go | 174 - .../typed/example2/internalversion/doc.go | 20 - .../internalversion/example2_client.go | 96 - .../example2/internalversion/fake/doc.go | 20 - .../fake/fake_example2_client.go | 40 - .../internalversion/fake/fake_testtype.go | 140 - .../example2/internalversion/testtype.go | 174 - .../clientset/versioned/clientset.go | 120 - .../apiserver/clientset/versioned/doc.go | 20 - .../versioned/fake/clientset_generated.go | 94 - .../apiserver/clientset/versioned/fake/doc.go | 20 - .../clientset/versioned/fake/register.go | 58 - .../clientset/versioned/scheme/doc.go | 20 - .../clientset/versioned/scheme/register.go | 58 - .../versioned/typed/example/v1/doc.go | 20 - .../typed/example/v1/example_client.go | 90 - .../versioned/typed/example/v1/fake/doc.go | 20 - .../example/v1/fake/fake_example_client.go | 40 - .../typed/example/v1/fake/fake_testtype.go | 140 - .../typed/example/v1/generated_expansion.go | 21 - .../versioned/typed/example/v1/testtype.go | 174 - .../versioned/typed/example2/v1/doc.go | 20 - .../typed/example2/v1/example2_client.go | 90 - .../versioned/typed/example2/v1/fake/doc.go | 20 - .../example2/v1/fake/fake_example2_client.go | 40 - .../typed/example2/v1/fake/fake_testtype.go | 140 - .../typed/example2/v1/generated_expansion.go | 21 - .../versioned/typed/example2/v1/testtype.go | 174 - .../externalversions/example/interface.go | 46 - .../externalversions/example/v1/interface.go | 45 - .../externalversions/example/v1/testtype.go | 89 - .../externalversions/example2/interface.go | 46 - .../externalversions/example2/v1/interface.go | 45 - .../externalversions/example2/v1/testtype.go | 89 - .../informers/externalversions/factory.go | 186 - .../informers/externalversions/generic.go | 67 - .../internalinterfaces/factory_interfaces.go | 38 - .../internalversion/example/interface.go | 46 - .../example/internalversion/interface.go | 45 - .../example/internalversion/testtype.go | 89 - .../internalversion/example2/interface.go | 46 - .../example2/internalversion/interface.go | 45 - .../example2/internalversion/testtype.go | 89 - .../informers/internalversion/factory.go | 186 - .../informers/internalversion/generic.go | 67 - .../internalinterfaces/factory_interfaces.go | 38 - .../internalversion/expansion_generated.go | 27 - .../example/internalversion/testtype.go | 94 - .../listers/example/v1/expansion_generated.go | 27 - .../apiserver/listers/example/v1/testtype.go | 94 - .../internalversion/expansion_generated.go | 27 - .../example2/internalversion/testtype.go | 94 - .../example2/v1/expansion_generated.go | 27 - .../apiserver/listers/example2/v1/testtype.go | 94 - .../_examples/crd/apis/example/v1/doc.go | 20 - .../_examples/crd/apis/example/v1/register.go | 59 - .../_examples/crd/apis/example/v1/types.go | 74 - .../apis/example/v1/zz_generated.deepcopy.go | 177 - .../apis/example/v1/zz_generated.defaults.go | 32 - .../_examples/crd/apis/example2/v1/doc.go | 21 - .../crd/apis/example2/v1/register.go | 59 - .../_examples/crd/apis/example2/v1/types.go | 47 - .../apis/example2/v1/zz_generated.deepcopy.go | 101 - .../apis/example2/v1/zz_generated.defaults.go | 32 - .../crd/clientset/versioned/clientset.go | 120 - .../_examples/crd/clientset/versioned/doc.go | 20 - .../versioned/fake/clientset_generated.go | 94 - .../crd/clientset/versioned/fake/doc.go | 20 - .../crd/clientset/versioned/fake/register.go | 58 - .../crd/clientset/versioned/scheme/doc.go | 20 - .../clientset/versioned/scheme/register.go | 58 - .../typed/example/v1/clustertesttype.go | 193 - .../versioned/typed/example/v1/doc.go | 20 - .../typed/example/v1/example_client.go | 95 - .../versioned/typed/example/v1/fake/doc.go | 20 - .../example/v1/fake/fake_clustertesttype.go | 152 - .../example/v1/fake/fake_example_client.go | 44 - .../typed/example/v1/fake/fake_testtype.go | 140 - .../versioned/typed/example/v1/testtype.go | 174 - .../versioned/typed/example2/v1/doc.go | 20 - .../typed/example2/v1/example2_client.go | 90 - .../versioned/typed/example2/v1/fake/doc.go | 20 - .../example2/v1/fake/fake_example2_client.go | 40 - .../typed/example2/v1/fake/fake_testtype.go | 140 - .../typed/example2/v1/generated_expansion.go | 21 - .../versioned/typed/example2/v1/testtype.go | 174 - .../externalversions/example/interface.go | 46 - .../example/v1/clustertesttype.go | 88 - .../externalversions/example/v1/interface.go | 52 - .../externalversions/example/v1/testtype.go | 89 - .../externalversions/example2/interface.go | 46 - .../externalversions/example2/v1/interface.go | 45 - .../externalversions/example2/v1/testtype.go | 89 - .../crd/informers/externalversions/factory.go | 186 - .../crd/informers/externalversions/generic.go | 69 - .../internalinterfaces/factory_interfaces.go | 38 - .../crd/listers/example/v1/clustertesttype.go | 65 - .../listers/example/v1/expansion_generated.go | 31 - .../crd/listers/example/v1/testtype.go | 94 - .../example2/v1/expansion_generated.go | 27 - .../crd/listers/example2/v1/testtype.go | 94 - .../cmd/client-gen/args/gvpackages_test.go | 116 + .../client-gen/generators/util/tags_test.go | 148 + .../types/helpers_test.go} | 21 +- .../cmd/go-to-protobuf/.gitignore | 1 - .../code-generator/cmd/go-to-protobuf/OWNERS | 4 - .../cmd/go-to-protobuf/protobuf/cmd.go | 349 - .../cmd/go-to-protobuf/protobuf/generator.go | 769 - .../go-to-protobuf/protobuf/import_tracker.go | 50 - .../cmd/go-to-protobuf/protobuf/namer.go | 208 - .../cmd/go-to-protobuf/protobuf/package.go | 215 - .../cmd/go-to-protobuf/protobuf/parser.go | 452 - .../go-to-protobuf/protoc-gen-gogo/main.go | 32 - .../code-generator/cmd/import-boss/.gitignore | 1 - .../code-generator/cmd/import-boss/main.go | 89 - .../cmd/register-gen/args/args.go | 39 - .../cmd/register-gen/generators/packages.go | 137 - .../generators/register_external.go | 117 - .../code-generator/cmd/register-gen/main.go | 52 - .../code-generator/hack/boilerplate.go.txt | 16 - .../code-generator/hack/update-codegen.sh | 32 - .../code-generator/hack/verify-codegen.sh | 53 - .../third_party/forked/golang/reflect/type.go | 91 - vendor/k8s.io/gengo/.import-restrictions | 10 + vendor/k8s.io/gengo/.travis.yml | 16 + vendor/k8s.io/gengo/OWNERS | 4 + vendor/k8s.io/gengo/README.md | 53 + .../doc.go => gengo/args/args_test.go} | 22 +- vendor/k8s.io/gengo/code-of-conduct.md | 3 + .../gengo/examples/deepcopy-gen/.gitignore | 1 + .../gengo/examples/deepcopy-gen/Makefile | 16 + .../deepcopy-gen/generators/deepcopy_test.go | 713 + .../gengo/examples/deepcopy-gen/main.go | 88 + .../gengo/examples/defaulter-gen/.gitignore | 1 + .../defaulter-gen/.import-restrictions | 12 + .../gengo/examples/defaulter-gen/Makefile | 15 + .../gengo/examples/defaulter-gen/OWNERS | 2 + .../gengo/examples/defaulter-gen/main.go | 75 + .../cmd => gengo/examples}/set-gen/.gitignore | 0 vendor/k8s.io/gengo/examples/set-gen/Makefile | 15 + .../cmd => gengo/examples}/set-gen/main.go | 10 +- .../gengo/examples/set-gen/sets/set_test.go | 270 + .../gengo/generator/snippet_writer_test.go | 88 + vendor/k8s.io/gengo/namer/namer_test.go | 100 + .../k8s.io/gengo/namer/plural_namer_test.go | 118 + .../k8s.io/gengo/parser/local_parse_test.go | 68 + vendor/k8s.io/gengo/parser/parse_test.go | 458 + vendor/k8s.io/gengo/types/comments_test.go | 86 + vendor/k8s.io/gengo/types/flatten_test.go | 68 + vendor/k8s.io/gengo/types/types_test.go | 210 + vendor/k8s.io/kube-openapi/.gitignore | 20 + vendor/k8s.io/kube-openapi/.travis.yml | 4 + vendor/k8s.io/kube-openapi/OWNERS | 7 + vendor/k8s.io/kube-openapi/README.md | 14 + vendor/k8s.io/kube-openapi/code-of-conduct.md | 3 + .../k8s.io/kube-openapi/pkg/generators/README | 46 + .../pkg/generators/openapi_test.go | 482 + .../pkg/util/proto/openapi_suite_test.go | 49 + .../pkg/util/proto/openapi_test.go | 207 + vendor/k8s.io/kube-openapi/pkg/util/trie.go | 79 + vendor/k8s.io/kube-openapi/pkg/util/util.go | 39 + 1491 files changed, 321358 insertions(+), 14058 deletions(-) create mode 100644 vendor/cloud.google.com/go/.travis.yml create mode 100644 vendor/cloud.google.com/go/CONTRIBUTING.md create mode 100644 vendor/cloud.google.com/go/MIGRATION.md create mode 100644 vendor/cloud.google.com/go/README.md create mode 100644 vendor/cloud.google.com/go/appveyor.yml create mode 100644 vendor/cloud.google.com/go/authexample_test.go create mode 100644 vendor/cloud.google.com/go/cloud.go create mode 100644 vendor/cloud.google.com/go/compute/metadata/metadata_test.go create mode 100644 vendor/cloud.google.com/go/import_test.go create mode 100644 vendor/cloud.google.com/go/keys.tar.enc create mode 100644 vendor/cloud.google.com/go/license_test.go create mode 100644 vendor/cloud.google.com/go/old-news.md create mode 100755 vendor/cloud.google.com/go/regen-gapic.sh create mode 100755 vendor/cloud.google.com/go/run-tests.sh create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/.gitignore create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/.travis.yml create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/CONTRIBUTING.md create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/Gopkg.lock create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/Gopkg.toml create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/README.md create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/arm/README.md create mode 100644 vendor/github.com/Azure/azure-sdk-for-go/rungas.sh create mode 100644 vendor/github.com/Azure/go-ansiterm/README.md create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_test.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_test_helpers_test.go create mode 100644 vendor/github.com/Azure/go-ansiterm/parser_test_utilities_test.go create mode 100644 vendor/github.com/Azure/go-ansiterm/test_event_handler_test.go create mode 100644 vendor/github.com/Azure/go-autorest/.gitignore create mode 100644 vendor/github.com/Azure/go-autorest/.travis.yml create mode 100644 vendor/github.com/Azure/go-autorest/CHANGELOG.md create mode 100644 vendor/github.com/Azure/go-autorest/GNUmakefile create mode 100644 vendor/github.com/Azure/go-autorest/README.md create mode 100644 vendor/github.com/Azure/go-autorest/autorest/adal/README.md create mode 100644 vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/authorization_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/autorest_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/azure/async_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/azure/azure_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/azure/environments_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/azure/rp_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/client_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/date/date_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/date/time_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/date/unixtime_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/error_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/preparer_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/responder_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/sender_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/to/convert_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/utility_test.go create mode 100644 vendor/github.com/Azure/go-autorest/autorest/validation/validation_test.go create mode 100644 vendor/github.com/Azure/go-autorest/glide.lock create mode 100644 vendor/github.com/Azure/go-autorest/glide.yaml create mode 100644 vendor/github.com/PuerkitoBio/purell/.gitignore create mode 100644 vendor/github.com/PuerkitoBio/purell/.travis.yml create mode 100644 vendor/github.com/PuerkitoBio/purell/README.md create mode 100644 vendor/github.com/PuerkitoBio/purell/bench_test.go create mode 100644 vendor/github.com/PuerkitoBio/purell/example_test.go create mode 100644 vendor/github.com/PuerkitoBio/purell/purell_test.go create mode 100644 vendor/github.com/PuerkitoBio/purell/urlnorm_test.go create mode 100644 vendor/github.com/PuerkitoBio/urlesc/.travis.yml create mode 100644 vendor/github.com/PuerkitoBio/urlesc/README.md create mode 100644 vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/.gitignore create mode 100644 vendor/github.com/Sirupsen/logrus/.travis.yml create mode 100644 vendor/github.com/Sirupsen/logrus/CHANGELOG.md create mode 100644 vendor/github.com/Sirupsen/logrus/README.md create mode 100644 vendor/github.com/Sirupsen/logrus/alt_exit_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/appveyor.yml create mode 100644 vendor/github.com/Sirupsen/logrus/entry_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/example_basic_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/example_global_hook_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/example_hook_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/formatter_bench_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/go.mod create mode 100644 vendor/github.com/Sirupsen/logrus/go.sum create mode 100644 vendor/github.com/Sirupsen/logrus/hook_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/json_formatter_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/logger_bench_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/logger_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/logrus_test.go create mode 100644 vendor/github.com/Sirupsen/logrus/text_formatter_test.go create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/.travis.yml create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/ChangeLog.txt create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.lock create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.toml create mode 100755 vendor/github.com/aliyun/alibaba-cloud-sdk-go/README.md create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/README_zh.md create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/client_test.go create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints/mapping_resolver_test.go create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests/types_test.go create mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses/json_parser_test.go delete mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go delete mode 100644 vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go create mode 100644 vendor/github.com/aws/aws-sdk-go/.gitignore create mode 100644 vendor/github.com/aws/aws-sdk-go/.godoc_config create mode 100644 vendor/github.com/aws/aws-sdk-go/.travis.yml create mode 100644 vendor/github.com/aws/aws-sdk-go/CHANGELOG.md create mode 100644 vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md create mode 100644 vendor/github.com/aws/aws-sdk-go/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md create mode 100644 vendor/github.com/aws/aws-sdk-go/Gopkg.lock create mode 100644 vendor/github.com/aws/aws-sdk-go/Gopkg.toml create mode 100644 vendor/github.com/aws/aws-sdk-go/Makefile create mode 100644 vendor/github.com/aws/aws-sdk-go/README.md create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/config_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/context_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/endpoints/example_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/handlers_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/http_request_copy_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/http_request_retry_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_1_5_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_1_6_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_context_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_internal_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_resetbody_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/request_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/retryer_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_benchmark_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/request/waiter_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/session/custom_ca_bundle_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/session/env_config_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/session/session_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/session/shared_config_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_5_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/aws/types_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/buildspec.yml create mode 100644 vendor/github.com/aws/aws-sdk-go/doc.go create mode 100644 vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_other_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_windows_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/README.md create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_bench_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/protocol_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/query/build_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/rest/rest_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/ec2/customizations_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/ec2/examples_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/ec2/retryer_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/generate.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/sts/customizations_test.go create mode 100644 vendor/github.com/aws/aws-sdk-go/service/sts/examples_test.go create mode 100644 vendor/github.com/beorn7/perks/.gitignore create mode 100644 vendor/github.com/beorn7/perks/README.md create mode 100644 vendor/github.com/beorn7/perks/quantile/bench_test.go create mode 100644 vendor/github.com/beorn7/perks/quantile/example_test.go create mode 100644 vendor/github.com/beorn7/perks/quantile/exampledata.txt create mode 100644 vendor/github.com/beorn7/perks/quantile/stream_test.go create mode 100644 vendor/github.com/davecgh/go-spew/.gitignore create mode 100644 vendor/github.com/davecgh/go-spew/.travis.yml create mode 100644 vendor/github.com/davecgh/go-spew/README.md create mode 100644 vendor/github.com/davecgh/go-spew/cov_report.sh create mode 100644 vendor/github.com/davecgh/go-spew/spew/common_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/dump_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/example_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/format_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/internal_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/spew_test.go create mode 100644 vendor/github.com/davecgh/go-spew/test_coverage.txt create mode 100644 vendor/github.com/dgrijalva/jwt-go/.gitignore create mode 100644 vendor/github.com/dgrijalva/jwt-go/.travis.yml create mode 100644 vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md create mode 100644 vendor/github.com/dgrijalva/jwt-go/README.md create mode 100644 vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md create mode 100644 vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/example_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/hmac_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/http_example_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/none_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/parser_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go create mode 100644 vendor/github.com/dgrijalva/jwt-go/rsa_test.go create mode 100644 vendor/github.com/docker/docker/.dockerignore create mode 100644 vendor/github.com/docker/docker/.gitignore create mode 100644 vendor/github.com/docker/docker/.mailmap create mode 100644 vendor/github.com/docker/docker/CHANGELOG.md create mode 100644 vendor/github.com/docker/docker/CONTRIBUTING.md create mode 100644 vendor/github.com/docker/docker/Dockerfile create mode 100644 vendor/github.com/docker/docker/Dockerfile.aarch64 create mode 100644 vendor/github.com/docker/docker/Dockerfile.armhf create mode 100644 vendor/github.com/docker/docker/Dockerfile.ppc64le create mode 100644 vendor/github.com/docker/docker/Dockerfile.s390x create mode 100644 vendor/github.com/docker/docker/Dockerfile.simple create mode 100644 vendor/github.com/docker/docker/Dockerfile.solaris create mode 100644 vendor/github.com/docker/docker/Dockerfile.windows create mode 100644 vendor/github.com/docker/docker/MAINTAINERS create mode 100644 vendor/github.com/docker/docker/Makefile create mode 100644 vendor/github.com/docker/docker/README.md create mode 100644 vendor/github.com/docker/docker/ROADMAP.md create mode 100644 vendor/github.com/docker/docker/VENDORING.md create mode 100644 vendor/github.com/docker/docker/VERSION delete mode 100644 vendor/github.com/docker/docker/contrib/selinux-fedora-24/docker-engine-selinux/LICENSE delete mode 100644 vendor/github.com/docker/docker/contrib/selinux-oraclelinux-7/docker-engine-selinux/LICENSE delete mode 100644 vendor/github.com/docker/docker/contrib/selinux/docker-engine-selinux/LICENSE delete mode 100644 vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE delete mode 100644 vendor/github.com/docker/docker/docs/static_files/contributors.png delete mode 100755 vendor/github.com/docker/docker/hack/generate-authors.sh delete mode 120000 vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default delete mode 120000 vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.init delete mode 120000 vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.upstart delete mode 120000 vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.udev create mode 100644 vendor/github.com/docker/docker/pkg/README.md delete mode 100644 vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE delete mode 100644 vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD create mode 100644 vendor/github.com/docker/docker/pkg/term/ascii_test.go create mode 100644 vendor/github.com/docker/docker/pkg/term/windows/windows_test.go create mode 100644 vendor/github.com/docker/docker/poule.yml delete mode 120000 vendor/github.com/docker/docker/project/CONTRIBUTORS.md create mode 100644 vendor/github.com/docker/docker/vendor.conf create mode 100644 vendor/github.com/emicklei/go-restful/.gitignore create mode 100644 vendor/github.com/emicklei/go-restful/.travis.yml create mode 100644 vendor/github.com/emicklei/go-restful/CHANGES.md create mode 100644 vendor/github.com/emicklei/go-restful/Makefile create mode 100644 vendor/github.com/emicklei/go-restful/README.md create mode 100644 vendor/github.com/emicklei/go-restful/Srcfile create mode 100644 vendor/github.com/emicklei/go-restful/bench_curly_test.go create mode 100644 vendor/github.com/emicklei/go-restful/bench_test.go create mode 100644 vendor/github.com/emicklei/go-restful/bench_test.sh create mode 100644 vendor/github.com/emicklei/go-restful/compress_test.go create mode 100644 vendor/github.com/emicklei/go-restful/container_test.go create mode 100644 vendor/github.com/emicklei/go-restful/cors_filter_test.go create mode 100644 vendor/github.com/emicklei/go-restful/coverage.sh create mode 100644 vendor/github.com/emicklei/go-restful/curly_test.go create mode 100644 vendor/github.com/emicklei/go-restful/doc_examples_test.go create mode 100644 vendor/github.com/emicklei/go-restful/entity_accessors_test.go create mode 100644 vendor/github.com/emicklei/go-restful/filter_test.go create mode 100644 vendor/github.com/emicklei/go-restful/jsr311_test.go create mode 100644 vendor/github.com/emicklei/go-restful/mime_test.go create mode 100644 vendor/github.com/emicklei/go-restful/options_filter_test.go create mode 100644 vendor/github.com/emicklei/go-restful/path_expression_test.go create mode 100644 vendor/github.com/emicklei/go-restful/path_processor_test.go create mode 100644 vendor/github.com/emicklei/go-restful/request_test.go create mode 100644 vendor/github.com/emicklei/go-restful/response_test.go create mode 100644 vendor/github.com/emicklei/go-restful/route_builder_test.go create mode 100644 vendor/github.com/emicklei/go-restful/route_test.go create mode 100644 vendor/github.com/emicklei/go-restful/tracer_test.go create mode 100644 vendor/github.com/emicklei/go-restful/web_service_test.go create mode 100644 vendor/github.com/ghodss/yaml/.gitignore create mode 100644 vendor/github.com/ghodss/yaml/.travis.yml create mode 100644 vendor/github.com/ghodss/yaml/README.md create mode 100644 vendor/github.com/ghodss/yaml/yaml_test.go create mode 100644 vendor/github.com/go-ini/ini/.gitignore create mode 100644 vendor/github.com/go-ini/ini/.travis.yml create mode 100644 vendor/github.com/go-ini/ini/Makefile create mode 100644 vendor/github.com/go-ini/ini/README.md create mode 100644 vendor/github.com/go-ini/ini/bench_test.go create mode 100644 vendor/github.com/go-ini/ini/file_test.go create mode 100644 vendor/github.com/go-ini/ini/ini_internal_test.go create mode 100644 vendor/github.com/go-ini/ini/ini_test.go create mode 100644 vendor/github.com/go-ini/ini/key_test.go create mode 100644 vendor/github.com/go-ini/ini/parser_test.go create mode 100644 vendor/github.com/go-ini/ini/section_test.go create mode 100644 vendor/github.com/go-ini/ini/struct_test.go create mode 100644 vendor/github.com/go-openapi/jsonpointer/.editorconfig create mode 100644 vendor/github.com/go-openapi/jsonpointer/.gitignore create mode 100644 vendor/github.com/go-openapi/jsonpointer/.travis.yml create mode 100644 vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/jsonpointer/README.md create mode 100644 vendor/github.com/go-openapi/jsonpointer/pointer_test.go create mode 100644 vendor/github.com/go-openapi/jsonreference/.gitignore create mode 100644 vendor/github.com/go-openapi/jsonreference/.travis.yml create mode 100644 vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/jsonreference/README.md create mode 100644 vendor/github.com/go-openapi/jsonreference/reference_test.go create mode 100644 vendor/github.com/go-openapi/spec/.drone.sec create mode 100644 vendor/github.com/go-openapi/spec/.drone.yml create mode 100644 vendor/github.com/go-openapi/spec/.gitignore create mode 100644 vendor/github.com/go-openapi/spec/.pullapprove.yml create mode 100644 vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/spec/README.md create mode 100644 vendor/github.com/go-openapi/spec/auth_test.go create mode 100644 vendor/github.com/go-openapi/spec/contact_info_test.go create mode 100644 vendor/github.com/go-openapi/spec/expander_test.go create mode 100644 vendor/github.com/go-openapi/spec/external_docs_test.go create mode 100644 vendor/github.com/go-openapi/spec/header_test.go create mode 100644 vendor/github.com/go-openapi/spec/info_test.go create mode 100644 vendor/github.com/go-openapi/spec/items_test.go create mode 100644 vendor/github.com/go-openapi/spec/license_test.go create mode 100644 vendor/github.com/go-openapi/spec/operation_test.go create mode 100644 vendor/github.com/go-openapi/spec/parameters_test.go create mode 100644 vendor/github.com/go-openapi/spec/path_item_test.go create mode 100644 vendor/github.com/go-openapi/spec/paths_test.go create mode 100644 vendor/github.com/go-openapi/spec/properties_test.go create mode 100644 vendor/github.com/go-openapi/spec/schema_test.go create mode 100644 vendor/github.com/go-openapi/spec/structs_test.go create mode 100644 vendor/github.com/go-openapi/spec/swagger_test.go create mode 100644 vendor/github.com/go-openapi/spec/xml_object_test.go create mode 100644 vendor/github.com/go-openapi/swag/.editorconfig create mode 100644 vendor/github.com/go-openapi/swag/.gitignore create mode 100644 vendor/github.com/go-openapi/swag/.travis.yml create mode 100644 vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/go-openapi/swag/README.md create mode 100644 vendor/github.com/go-openapi/swag/convert_test.go create mode 100644 vendor/github.com/go-openapi/swag/convert_types_test.go create mode 100644 vendor/github.com/go-openapi/swag/json_test.go create mode 100644 vendor/github.com/go-openapi/swag/loading_test.go create mode 100644 vendor/github.com/go-openapi/swag/net_test.go create mode 100644 vendor/github.com/go-openapi/swag/path_test.go create mode 100644 vendor/github.com/go-openapi/swag/util_test.go create mode 100644 vendor/github.com/go-openapi/swag/yaml_test.go create mode 100644 vendor/github.com/gogo/protobuf/.gitignore create mode 100644 vendor/github.com/gogo/protobuf/.mailmap create mode 100644 vendor/github.com/gogo/protobuf/.travis.yml create mode 100644 vendor/github.com/gogo/protobuf/Makefile create mode 100644 vendor/github.com/gogo/protobuf/README create mode 100644 vendor/github.com/gogo/protobuf/Readme.md create mode 100644 vendor/github.com/gogo/protobuf/bench.md create mode 100644 vendor/github.com/gogo/protobuf/custom_types.md create mode 100644 vendor/github.com/gogo/protobuf/extensions.md create mode 100755 vendor/github.com/gogo/protobuf/install-protobuf.sh create mode 100644 vendor/github.com/gogo/protobuf/proto/Makefile create mode 100644 vendor/github.com/gogo/protobuf/proto/all_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/any_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/clone_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/decode_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/encode_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/equal_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/extensions_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/map_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/message_set_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/proto3_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/size2_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/size_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text_parser_test.go create mode 100644 vendor/github.com/gogo/protobuf/proto/text_test.go create mode 100644 vendor/github.com/golang/glog/README create mode 100644 vendor/github.com/golang/glog/glog_test.go create mode 100644 vendor/github.com/golang/groupcache/.gitignore create mode 100644 vendor/github.com/golang/groupcache/.travis.yml create mode 100644 vendor/github.com/golang/groupcache/README.md create mode 100644 vendor/github.com/golang/groupcache/byteview.go create mode 100644 vendor/github.com/golang/groupcache/byteview_test.go create mode 100644 vendor/github.com/golang/groupcache/groupcache.go create mode 100644 vendor/github.com/golang/groupcache/groupcache_test.go create mode 100644 vendor/github.com/golang/groupcache/http.go create mode 100644 vendor/github.com/golang/groupcache/http_test.go create mode 100644 vendor/github.com/golang/groupcache/lru/lru_test.go create mode 100644 vendor/github.com/golang/groupcache/peers.go create mode 100644 vendor/github.com/golang/groupcache/sinks.go create mode 100644 vendor/github.com/golang/protobuf/.gitignore create mode 100644 vendor/github.com/golang/protobuf/.travis.yml create mode 100644 vendor/github.com/golang/protobuf/Makefile create mode 100644 vendor/github.com/golang/protobuf/README.md create mode 100644 vendor/github.com/golang/protobuf/proto/all_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/any_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/clone_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/decode_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/discard_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/encode_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/equal_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/extensions_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/map_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/message_set_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/proto3_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/size2_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/size_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/text_parser_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/text_test.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/any/any.proto create mode 100644 vendor/github.com/golang/protobuf/ptypes/any_test.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/duration/duration.proto create mode 100644 vendor/github.com/golang/protobuf/ptypes/duration_test.go create mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto create mode 100644 vendor/github.com/golang/protobuf/ptypes/timestamp_test.go create mode 100755 vendor/github.com/golang/protobuf/regenerate.sh create mode 100644 vendor/github.com/google/btree/.travis.yml create mode 100644 vendor/github.com/google/btree/README.md create mode 100644 vendor/github.com/google/btree/btree_test.go create mode 100644 vendor/github.com/google/gofuzz/.travis.yml create mode 100644 vendor/github.com/google/gofuzz/CONTRIBUTING.md create mode 100644 vendor/github.com/google/gofuzz/README.md create mode 100644 vendor/github.com/google/gofuzz/example_test.go create mode 100644 vendor/github.com/google/gofuzz/fuzz_test.go create mode 100644 vendor/github.com/googleapis/gnostic/.gitignore create mode 100755 vendor/github.com/googleapis/gnostic/.travis-install.sh create mode 100644 vendor/github.com/googleapis/gnostic/.travis.yml create mode 100755 vendor/github.com/googleapis/gnostic/COMPILE-PROTOS.sh create mode 100644 vendor/github.com/googleapis/gnostic/CONTRIBUTING.md create mode 100644 vendor/github.com/googleapis/gnostic/Makefile create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md create mode 100644 vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json create mode 100644 vendor/github.com/googleapis/gnostic/README.md create mode 100644 vendor/github.com/googleapis/gnostic/compiler/README.md create mode 100755 vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh create mode 100644 vendor/github.com/googleapis/gnostic/extensions/README.md create mode 100644 vendor/github.com/googleapis/gnostic/extensions/extension.proto create mode 100644 vendor/github.com/googleapis/gnostic/gnostic.go create mode 100644 vendor/github.com/googleapis/gnostic/gnostic_test.go create mode 100644 vendor/github.com/gophercloud/gophercloud/.gitignore create mode 100644 vendor/github.com/gophercloud/gophercloud/.travis.yml create mode 100644 vendor/github.com/gophercloud/gophercloud/.zuul.yaml create mode 100644 vendor/github.com/gophercloud/gophercloud/CHANGELOG.md create mode 100644 vendor/github.com/gophercloud/gophercloud/FAQ.md create mode 100644 vendor/github.com/gophercloud/gophercloud/MIGRATING.md create mode 100644 vendor/github.com/gophercloud/gophercloud/README.md create mode 100644 vendor/github.com/gophercloud/gophercloud/STYLEGUIDE.md create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/delegate.go create mode 100644 vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/doc.go create mode 100644 vendor/github.com/gregjones/httpcache/.travis.yml create mode 100644 vendor/github.com/gregjones/httpcache/README.md create mode 100644 vendor/github.com/gregjones/httpcache/diskcache/diskcache_test.go create mode 100644 vendor/github.com/gregjones/httpcache/httpcache_test.go create mode 100644 vendor/github.com/hashicorp/golang-lru/.gitignore create mode 100644 vendor/github.com/hashicorp/golang-lru/2q_test.go create mode 100644 vendor/github.com/hashicorp/golang-lru/README.md create mode 100644 vendor/github.com/hashicorp/golang-lru/arc_test.go create mode 100644 vendor/github.com/hashicorp/golang-lru/lru_test.go create mode 100644 vendor/github.com/hashicorp/golang-lru/simplelru/lru_test.go create mode 100644 vendor/github.com/imdario/mergo/.gitignore create mode 100644 vendor/github.com/imdario/mergo/.travis.yml create mode 100644 vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/imdario/mergo/README.md create mode 100644 vendor/github.com/imdario/mergo/issue17_test.go create mode 100644 vendor/github.com/imdario/mergo/issue23_test.go create mode 100644 vendor/github.com/imdario/mergo/issue33_test.go create mode 100644 vendor/github.com/imdario/mergo/issue38_test.go create mode 100644 vendor/github.com/imdario/mergo/issue50_test.go create mode 100644 vendor/github.com/imdario/mergo/issue52_test.go create mode 100644 vendor/github.com/imdario/mergo/issue61_test.go create mode 100644 vendor/github.com/imdario/mergo/issue64_test.go create mode 100644 vendor/github.com/imdario/mergo/issue66_test.go create mode 100644 vendor/github.com/imdario/mergo/merge_appendslice_test.go create mode 100644 vendor/github.com/imdario/mergo/merge_test.go create mode 100644 vendor/github.com/imdario/mergo/mergo_test.go delete mode 100644 vendor/github.com/imdario/mergo/testdata/license.yml create mode 100644 vendor/github.com/jmespath/go-jmespath/.gitignore create mode 100644 vendor/github.com/jmespath/go-jmespath/.travis.yml create mode 100644 vendor/github.com/jmespath/go-jmespath/Makefile create mode 100644 vendor/github.com/jmespath/go-jmespath/README.md create mode 100644 vendor/github.com/jmespath/go-jmespath/api_test.go create mode 100644 vendor/github.com/jmespath/go-jmespath/compliance_test.go create mode 100644 vendor/github.com/jmespath/go-jmespath/interpreter_test.go create mode 100644 vendor/github.com/jmespath/go-jmespath/lexer_test.go create mode 100644 vendor/github.com/jmespath/go-jmespath/parser_test.go create mode 100644 vendor/github.com/jmespath/go-jmespath/util_test.go create mode 100644 vendor/github.com/json-iterator/go/.codecov.yml create mode 100644 vendor/github.com/json-iterator/go/.gitignore create mode 100644 vendor/github.com/json-iterator/go/.travis.yml create mode 100644 vendor/github.com/json-iterator/go/Gopkg.lock create mode 100644 vendor/github.com/json-iterator/go/Gopkg.toml create mode 100644 vendor/github.com/json-iterator/go/README.md create mode 100755 vendor/github.com/json-iterator/go/build.sh create mode 100644 vendor/github.com/json-iterator/go/example_test.go create mode 100644 vendor/github.com/json-iterator/go/fuzzy_mode_convert_table.md create mode 100644 vendor/github.com/json-iterator/go/iter_skip_sloppy_test.go create mode 100644 vendor/github.com/json-iterator/go/stream_test.go create mode 100755 vendor/github.com/json-iterator/go/test.sh create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/README.md create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod create mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go create mode 100644 vendor/github.com/mailru/easyjson/.gitignore create mode 100644 vendor/github.com/mailru/easyjson/.travis.yml create mode 100644 vendor/github.com/mailru/easyjson/Makefile create mode 100644 vendor/github.com/mailru/easyjson/README.md create mode 100644 vendor/github.com/mailru/easyjson/buffer/pool_test.go create mode 100644 vendor/github.com/mailru/easyjson/helpers.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/lexer_test.go create mode 100644 vendor/github.com/mailru/easyjson/raw.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/.travis.yml create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/README.md create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/all_test.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode_test.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode_test.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/fixtures_test.go create mode 100644 vendor/github.com/modern-go/concurrent/.gitignore create mode 100644 vendor/github.com/modern-go/concurrent/.travis.yml create mode 100644 vendor/github.com/modern-go/concurrent/README.md create mode 100644 vendor/github.com/modern-go/concurrent/map_test.go create mode 100755 vendor/github.com/modern-go/concurrent/test.sh create mode 100644 vendor/github.com/modern-go/concurrent/unbounded_executor_test.go create mode 100644 vendor/github.com/modern-go/reflect2/.gitignore create mode 100644 vendor/github.com/modern-go/reflect2/.travis.yml create mode 100644 vendor/github.com/modern-go/reflect2/Gopkg.lock create mode 100644 vendor/github.com/modern-go/reflect2/Gopkg.toml create mode 100644 vendor/github.com/modern-go/reflect2/README.md create mode 100755 vendor/github.com/modern-go/reflect2/test.sh create mode 100644 vendor/github.com/onsi/ginkgo/.gitignore create mode 100644 vendor/github.com/onsi/ginkgo/.travis.yml create mode 100644 vendor/github.com/onsi/ginkgo/CHANGELOG.md create mode 100644 vendor/github.com/onsi/ginkgo/CONTRIBUTING.md create mode 100644 vendor/github.com/onsi/ginkgo/README.md create mode 100644 vendor/github.com/onsi/ginkgo/RELEASING.md create mode 100755 vendor/github.com/onsi/ginkgo/before_pr.sh create mode 100644 vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/extensions/table/table_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/containernode/container_node_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/failer/failer_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/failer/failer_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/remote/aggregator_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/remote/fake_poster_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/remote/remote_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/remote/server_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec/spec_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec/specs_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec_iterator/index_computer_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec_iterator/serial_spec_iterator_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec_iterator/sharded_parallel_spec_iterator_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/spec_iterator/spec_iterator_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/suite/suite_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/writer/writer_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/internal/writer/writer_test.go create mode 100644 vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go create mode 100644 vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go create mode 100644 vendor/github.com/onsi/ginkgo/reporters/reporters_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/reporters/stenographer/support/README.md create mode 100644 vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable/README.md create mode 100644 vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty/README.md create mode 100644 vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go create mode 100644 vendor/github.com/onsi/ginkgo/types/types_suite_test.go create mode 100644 vendor/github.com/onsi/ginkgo/types/types_test.go create mode 100644 vendor/github.com/onsi/gomega/.gitignore create mode 100644 vendor/github.com/onsi/gomega/.travis.yml create mode 100644 vendor/github.com/onsi/gomega/CHANGELOG.md create mode 100644 vendor/github.com/onsi/gomega/CONTRIBUTING.md create mode 100644 vendor/github.com/onsi/gomega/README.md create mode 100644 vendor/github.com/onsi/gomega/RELEASING.md create mode 100644 vendor/github.com/onsi/gomega/format/format_suite_test.go create mode 100644 vendor/github.com/onsi/gomega/format/format_test.go create mode 100644 vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go create mode 100644 vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go create mode 100644 vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go create mode 100644 vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go create mode 100644 vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/and_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/consist_of_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/not_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/or_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go create mode 100644 vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE create mode 100644 vendor/github.com/onsi/gomega/matchers/with_transform_test.go create mode 100644 vendor/github.com/petar/GoLLRB/.gitignore create mode 100644 vendor/github.com/petar/GoLLRB/README.md create mode 100644 vendor/github.com/petar/GoLLRB/llrb/iterator_test.go create mode 100644 vendor/github.com/petar/GoLLRB/llrb/llrb_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/README.md create mode 100644 vendor/github.com/peterbourgon/diskv/basic_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/compression_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/import_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/index_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/issues_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/keys_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/speed_test.go create mode 100644 vendor/github.com/peterbourgon/diskv/stream_test.go create mode 100644 vendor/github.com/prometheus/client_golang/.gitignore create mode 100644 vendor/github.com/prometheus/client_golang/.travis.yml create mode 100644 vendor/github.com/prometheus/client_golang/CHANGELOG.md create mode 100644 vendor/github.com/prometheus/client_golang/CONTRIBUTING.md create mode 100644 vendor/github.com/prometheus/client_golang/MAINTAINERS.md create mode 100644 vendor/github.com/prometheus/client_golang/README.md create mode 100644 vendor/github.com/prometheus/client_golang/VERSION create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/.gitignore create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/README.md create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/counter_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_clustermanager_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/examples_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/expvar_collector_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/http_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/metric_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/registry_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/summary_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/timer_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/vec_test.go create mode 100644 vendor/github.com/prometheus/client_model/.gitignore create mode 100644 vendor/github.com/prometheus/client_model/CONTRIBUTING.md create mode 100644 vendor/github.com/prometheus/client_model/MAINTAINERS.md create mode 100644 vendor/github.com/prometheus/client_model/Makefile create mode 100644 vendor/github.com/prometheus/client_model/README.md create mode 100644 vendor/github.com/prometheus/client_model/metrics.proto create mode 100644 vendor/github.com/prometheus/client_model/pom.xml delete mode 100644 vendor/github.com/prometheus/client_model/ruby/LICENSE create mode 100644 vendor/github.com/prometheus/client_model/setup.py create mode 100644 vendor/github.com/prometheus/common/.travis.yml create mode 100644 vendor/github.com/prometheus/common/CONTRIBUTING.md create mode 100644 vendor/github.com/prometheus/common/MAINTAINERS.md create mode 100644 vendor/github.com/prometheus/common/README.md create mode 100644 vendor/github.com/prometheus/common/expfmt/bench_test.go create mode 100644 vendor/github.com/prometheus/common/expfmt/decode_test.go create mode 100644 vendor/github.com/prometheus/common/expfmt/text_create_test.go create mode 100644 vendor/github.com/prometheus/common/expfmt/text_parse_test.go create mode 100644 vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt create mode 100644 vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg_test.go create mode 100644 vendor/github.com/prometheus/common/model/alert_test.go create mode 100644 vendor/github.com/prometheus/common/model/labels_test.go create mode 100644 vendor/github.com/prometheus/common/model/metric_test.go create mode 100644 vendor/github.com/prometheus/common/model/signature_test.go create mode 100644 vendor/github.com/prometheus/common/model/silence_test.go create mode 100644 vendor/github.com/prometheus/common/model/time_test.go create mode 100644 vendor/github.com/prometheus/common/model/value_test.go create mode 100644 vendor/github.com/prometheus/procfs/.gitignore create mode 100644 vendor/github.com/prometheus/procfs/.travis.yml create mode 100644 vendor/github.com/prometheus/procfs/CONTRIBUTING.md create mode 100644 vendor/github.com/prometheus/procfs/MAINTAINERS.md create mode 100644 vendor/github.com/prometheus/procfs/Makefile create mode 100644 vendor/github.com/prometheus/procfs/README.md create mode 100644 vendor/github.com/prometheus/procfs/buddyinfo_test.go create mode 100644 vendor/github.com/prometheus/procfs/fixtures.ttar create mode 100644 vendor/github.com/prometheus/procfs/fs_test.go create mode 100644 vendor/github.com/prometheus/procfs/ipvs_test.go create mode 100644 vendor/github.com/prometheus/procfs/mdstat_test.go create mode 100644 vendor/github.com/prometheus/procfs/mountstats_test.go create mode 100644 vendor/github.com/prometheus/procfs/net_dev_test.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfs_test.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfsd_test.go create mode 100644 vendor/github.com/prometheus/procfs/proc_io_test.go create mode 100644 vendor/github.com/prometheus/procfs/proc_limits_test.go create mode 100644 vendor/github.com/prometheus/procfs/proc_ns_test.go create mode 100644 vendor/github.com/prometheus/procfs/proc_stat_test.go create mode 100644 vendor/github.com/prometheus/procfs/proc_test.go create mode 100644 vendor/github.com/prometheus/procfs/stat_test.go create mode 100755 vendor/github.com/prometheus/procfs/ttar create mode 100644 vendor/github.com/prometheus/procfs/xfrm_test.go create mode 100644 vendor/github.com/prometheus/procfs/xfs/parse_test.go create mode 100644 vendor/github.com/satori/go.uuid/.travis.yml create mode 100644 vendor/github.com/satori/go.uuid/README.md create mode 100644 vendor/github.com/satori/go.uuid/codec_test.go create mode 100644 vendor/github.com/satori/go.uuid/generator_test.go create mode 100644 vendor/github.com/satori/go.uuid/sql_test.go create mode 100644 vendor/github.com/satori/go.uuid/uuid_test.go create mode 100644 vendor/github.com/spf13/pflag/.gitignore create mode 100644 vendor/github.com/spf13/pflag/.travis.yml create mode 100644 vendor/github.com/spf13/pflag/README.md create mode 100644 vendor/github.com/spf13/pflag/bool_slice_test.go create mode 100644 vendor/github.com/spf13/pflag/bool_test.go create mode 100644 vendor/github.com/spf13/pflag/bytes_test.go create mode 100644 vendor/github.com/spf13/pflag/count_test.go create mode 100644 vendor/github.com/spf13/pflag/duration_slice_test.go create mode 100644 vendor/github.com/spf13/pflag/example_test.go create mode 100644 vendor/github.com/spf13/pflag/export_test.go create mode 100644 vendor/github.com/spf13/pflag/flag_test.go create mode 100644 vendor/github.com/spf13/pflag/golangflag_test.go create mode 100644 vendor/github.com/spf13/pflag/int_slice_test.go create mode 100644 vendor/github.com/spf13/pflag/ip_slice_test.go create mode 100644 vendor/github.com/spf13/pflag/ip_test.go create mode 100644 vendor/github.com/spf13/pflag/ipnet_test.go create mode 100644 vendor/github.com/spf13/pflag/printusage_test.go create mode 100644 vendor/github.com/spf13/pflag/string_array_test.go create mode 100644 vendor/github.com/spf13/pflag/string_slice_test.go create mode 100644 vendor/github.com/spf13/pflag/uint_slice_test.go create mode 100644 vendor/golang.org/x/crypto/.gitattributes create mode 100644 vendor/golang.org/x/crypto/.gitignore create mode 100644 vendor/golang.org/x/crypto/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/crypto/README.md create mode 100644 vendor/golang.org/x/crypto/codereview.cfg create mode 100644 vendor/golang.org/x/crypto/ssh/benchmark_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/buffer.go create mode 100644 vendor/golang.org/x/crypto/ssh/buffer_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/certs.go create mode 100644 vendor/golang.org/x/crypto/ssh/certs_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/channel.go create mode 100644 vendor/golang.org/x/crypto/ssh/cipher.go create mode 100644 vendor/golang.org/x/crypto/ssh/cipher_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/client.go create mode 100644 vendor/golang.org/x/crypto/ssh/client_auth.go create mode 100644 vendor/golang.org/x/crypto/ssh/client_auth_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/client_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/common.go create mode 100644 vendor/golang.org/x/crypto/ssh/connection.go create mode 100644 vendor/golang.org/x/crypto/ssh/doc.go create mode 100644 vendor/golang.org/x/crypto/ssh/example_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/handshake.go create mode 100644 vendor/golang.org/x/crypto/ssh/handshake_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/kex.go create mode 100644 vendor/golang.org/x/crypto/ssh/kex_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/keys.go create mode 100644 vendor/golang.org/x/crypto/ssh/keys_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/mac.go create mode 100644 vendor/golang.org/x/crypto/ssh/mempipe_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/messages.go create mode 100644 vendor/golang.org/x/crypto/ssh/messages_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/mux.go create mode 100644 vendor/golang.org/x/crypto/ssh/mux_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/server.go create mode 100644 vendor/golang.org/x/crypto/ssh/session.go create mode 100644 vendor/golang.org/x/crypto/ssh/session_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/streamlocal.go create mode 100644 vendor/golang.org/x/crypto/ssh/tcpip.go create mode 100644 vendor/golang.org/x/crypto/ssh/tcpip_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/testdata_test.go create mode 100644 vendor/golang.org/x/crypto/ssh/transport.go create mode 100644 vendor/golang.org/x/crypto/ssh/transport_test.go create mode 100644 vendor/golang.org/x/net/.gitattributes create mode 100644 vendor/golang.org/x/net/.gitignore create mode 100644 vendor/golang.org/x/net/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/net/README.md create mode 100644 vendor/golang.org/x/net/codereview.cfg create mode 100644 vendor/golang.org/x/net/context/context_test.go create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go create mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go create mode 100644 vendor/golang.org/x/net/context/withtimeout_test.go create mode 100644 vendor/golang.org/x/net/html/atom/atom_test.go create mode 100644 vendor/golang.org/x/net/html/atom/table_test.go create mode 100644 vendor/golang.org/x/net/html/charset/charset_test.go create mode 100644 vendor/golang.org/x/net/html/entity_test.go create mode 100644 vendor/golang.org/x/net/html/escape_test.go create mode 100644 vendor/golang.org/x/net/html/example_test.go create mode 100644 vendor/golang.org/x/net/html/node_test.go create mode 100644 vendor/golang.org/x/net/html/parse_test.go create mode 100644 vendor/golang.org/x/net/html/render_test.go create mode 100644 vendor/golang.org/x/net/html/token_test.go create mode 100644 vendor/golang.org/x/net/http/httpguts/httplex_test.go create mode 100644 vendor/golang.org/x/net/http2/.gitignore create mode 100644 vendor/golang.org/x/net/http2/Dockerfile create mode 100644 vendor/golang.org/x/net/http2/Makefile create mode 100644 vendor/golang.org/x/net/http2/README create mode 100644 vendor/golang.org/x/net/http2/ciphers_test.go create mode 100644 vendor/golang.org/x/net/http2/databuffer_test.go create mode 100644 vendor/golang.org/x/net/http2/errors_test.go create mode 100644 vendor/golang.org/x/net/http2/flow_test.go create mode 100644 vendor/golang.org/x/net/http2/frame_test.go create mode 100644 vendor/golang.org/x/net/http2/go18_test.go create mode 100644 vendor/golang.org/x/net/http2/go19_test.go create mode 100644 vendor/golang.org/x/net/http2/gotrack_test.go create mode 100644 vendor/golang.org/x/net/http2/hpack/encode_test.go create mode 100644 vendor/golang.org/x/net/http2/hpack/hpack_test.go create mode 100644 vendor/golang.org/x/net/http2/hpack/tables_test.go create mode 100644 vendor/golang.org/x/net/http2/http2_test.go create mode 100644 vendor/golang.org/x/net/http2/pipe_test.go create mode 100644 vendor/golang.org/x/net/http2/server_push_test.go create mode 100644 vendor/golang.org/x/net/http2/server_test.go create mode 100644 vendor/golang.org/x/net/http2/transport_test.go create mode 100644 vendor/golang.org/x/net/http2/writesched_priority_test.go create mode 100644 vendor/golang.org/x/net/http2/writesched_random_test.go create mode 100644 vendor/golang.org/x/net/http2/writesched_test.go create mode 100644 vendor/golang.org/x/net/http2/z_spec_test.go create mode 100644 vendor/golang.org/x/net/idna/example_test.go create mode 100644 vendor/golang.org/x/net/idna/idna_test.go create mode 100644 vendor/golang.org/x/net/idna/punycode_test.go create mode 100644 vendor/golang.org/x/oauth2/.travis.yml create mode 100644 vendor/golang.org/x/oauth2/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/oauth2/README.md create mode 100644 vendor/golang.org/x/oauth2/example_test.go create mode 100644 vendor/golang.org/x/oauth2/google/example_test.go create mode 100644 vendor/golang.org/x/oauth2/google/google_test.go create mode 100644 vendor/golang.org/x/oauth2/google/jwt_test.go create mode 100644 vendor/golang.org/x/oauth2/google/sdk_test.go create mode 100644 vendor/golang.org/x/oauth2/internal/token_test.go create mode 100644 vendor/golang.org/x/oauth2/jws/jws_test.go create mode 100644 vendor/golang.org/x/oauth2/jwt/example_test.go create mode 100644 vendor/golang.org/x/oauth2/jwt/jwt_test.go create mode 100644 vendor/golang.org/x/oauth2/oauth2_test.go create mode 100644 vendor/golang.org/x/oauth2/token_test.go create mode 100644 vendor/golang.org/x/oauth2/transport_test.go create mode 100644 vendor/golang.org/x/sys/.gitattributes create mode 100644 vendor/golang.org/x/sys/.gitignore create mode 100644 vendor/golang.org/x/sys/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/sys/README.md create mode 100644 vendor/golang.org/x/sys/codereview.cfg create mode 100644 vendor/golang.org/x/sys/unix/.gitignore create mode 100644 vendor/golang.org/x/sys/unix/README.md create mode 100644 vendor/golang.org/x/sys/unix/creds_test.go create mode 100644 vendor/golang.org/x/sys/unix/dev_linux_test.go create mode 100644 vendor/golang.org/x/sys/unix/example_test.go create mode 100644 vendor/golang.org/x/sys/unix/export_test.go create mode 100755 vendor/golang.org/x/sys/unix/mkall.sh create mode 100755 vendor/golang.org/x/sys/unix/mkerrors.sh create mode 100755 vendor/golang.org/x/sys/unix/mksyscall.pl create mode 100755 vendor/golang.org/x/sys/unix/mksyscall_solaris.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_darwin.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl create mode 100755 vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl create mode 100644 vendor/golang.org/x/sys/unix/mmap_unix_test.go create mode 100644 vendor/golang.org/x/sys/unix/openbsd_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_bsd_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_test.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_test.go create mode 100644 vendor/golang.org/x/sys/unix/timestruct_test.go create mode 100644 vendor/golang.org/x/sys/unix/xattr_test.go create mode 100644 vendor/golang.org/x/sys/windows/syscall_test.go create mode 100644 vendor/golang.org/x/sys/windows/syscall_windows_test.go create mode 100644 vendor/golang.org/x/text/.gitattributes create mode 100644 vendor/golang.org/x/text/.gitignore create mode 100644 vendor/golang.org/x/text/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/text/README.md create mode 100644 vendor/golang.org/x/text/codereview.cfg create mode 100644 vendor/golang.org/x/text/collate/build/builder_test.go create mode 100644 vendor/golang.org/x/text/collate/build/colelem_test.go create mode 100644 vendor/golang.org/x/text/collate/build/contract_test.go create mode 100644 vendor/golang.org/x/text/collate/build/order_test.go create mode 100644 vendor/golang.org/x/text/collate/build/trie_test.go create mode 100644 vendor/golang.org/x/text/collate/collate_test.go create mode 100644 vendor/golang.org/x/text/collate/export_test.go create mode 100644 vendor/golang.org/x/text/collate/option_test.go create mode 100644 vendor/golang.org/x/text/collate/reg_test.go create mode 100644 vendor/golang.org/x/text/collate/sort_test.go create mode 100644 vendor/golang.org/x/text/collate/table_test.go create mode 100644 vendor/golang.org/x/text/doc.go create mode 100644 vendor/golang.org/x/text/encoding/charmap/charmap_test.go create mode 100644 vendor/golang.org/x/text/encoding/encoding_test.go create mode 100644 vendor/golang.org/x/text/encoding/example_test.go create mode 100644 vendor/golang.org/x/text/encoding/htmlindex/htmlindex_test.go create mode 100644 vendor/golang.org/x/text/encoding/japanese/all_test.go create mode 100644 vendor/golang.org/x/text/encoding/korean/all_test.go create mode 100644 vendor/golang.org/x/text/encoding/simplifiedchinese/all_test.go create mode 100644 vendor/golang.org/x/text/encoding/traditionalchinese/all_test.go create mode 100644 vendor/golang.org/x/text/encoding/unicode/unicode_test.go create mode 100644 vendor/golang.org/x/text/gen.go create mode 100644 vendor/golang.org/x/text/internal/colltab/collate_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/collelem_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/colltab_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/contract_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/iter_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/numeric_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/trie_test.go create mode 100644 vendor/golang.org/x/text/internal/colltab/weighter_test.go create mode 100644 vendor/golang.org/x/text/internal/gen.go create mode 100644 vendor/golang.org/x/text/internal/gen_test.go create mode 100644 vendor/golang.org/x/text/internal/internal.go create mode 100644 vendor/golang.org/x/text/internal/internal_test.go create mode 100644 vendor/golang.org/x/text/internal/match.go create mode 100644 vendor/golang.org/x/text/internal/match_test.go create mode 100644 vendor/golang.org/x/text/internal/tables.go create mode 100644 vendor/golang.org/x/text/internal/tag/tag_test.go create mode 100644 vendor/golang.org/x/text/internal/triegen/data_test.go create mode 100644 vendor/golang.org/x/text/internal/triegen/example_compact_test.go create mode 100644 vendor/golang.org/x/text/internal/triegen/example_test.go create mode 100644 vendor/golang.org/x/text/internal/triegen/gen_test.go create mode 100644 vendor/golang.org/x/text/internal/ucd/example_test.go create mode 100644 vendor/golang.org/x/text/internal/ucd/ucd_test.go create mode 100644 vendor/golang.org/x/text/language/Makefile create mode 100644 vendor/golang.org/x/text/language/coverage_test.go create mode 100644 vendor/golang.org/x/text/language/examples_test.go create mode 100644 vendor/golang.org/x/text/language/httpexample_test.go create mode 100644 vendor/golang.org/x/text/language/language_test.go create mode 100644 vendor/golang.org/x/text/language/lookup_test.go create mode 100644 vendor/golang.org/x/text/language/match_test.go create mode 100644 vendor/golang.org/x/text/language/parse_test.go create mode 100644 vendor/golang.org/x/text/runes/cond_test.go create mode 100644 vendor/golang.org/x/text/runes/example_test.go create mode 100644 vendor/golang.org/x/text/runes/runes_test.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bench_test.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0_test.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0_test.go create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule_test.go create mode 100644 vendor/golang.org/x/text/secure/doc.go create mode 100644 vendor/golang.org/x/text/transform/examples_test.go create mode 100644 vendor/golang.org/x/text/transform/transform_test.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/core_test.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/ranges_test.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables_test.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/cldr_test.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/collate_test.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/data_test.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/examples_test.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/resolve_test.go create mode 100644 vendor/golang.org/x/text/unicode/cldr/slice_test.go create mode 100644 vendor/golang.org/x/text/unicode/doc.go create mode 100644 vendor/golang.org/x/text/unicode/norm/composition_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/data10.0.0_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/data9.0.0_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/example_iter_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/example_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/forminfo_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/iter_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/normalize_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/readwriter_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/transform_test.go create mode 100644 vendor/golang.org/x/text/unicode/norm/ucd_test.go create mode 100644 vendor/golang.org/x/text/unicode/rangetable/merge_test.go create mode 100644 vendor/golang.org/x/text/unicode/rangetable/rangetable_test.go create mode 100644 vendor/golang.org/x/text/width/common_test.go create mode 100644 vendor/golang.org/x/text/width/example_test.go create mode 100644 vendor/golang.org/x/text/width/runes_test.go create mode 100644 vendor/golang.org/x/text/width/tables_test.go create mode 100644 vendor/golang.org/x/text/width/transform_test.go create mode 100644 vendor/golang.org/x/time/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/time/README.md create mode 100644 vendor/golang.org/x/time/rate/rate_test.go create mode 100644 vendor/golang.org/x/tools/.gitattributes create mode 100644 vendor/golang.org/x/tools/.gitignore create mode 100644 vendor/golang.org/x/tools/CONTRIBUTING.md create mode 100644 vendor/golang.org/x/tools/README.md delete mode 100644 vendor/golang.org/x/tools/cmd/getgo/LICENSE create mode 100644 vendor/golang.org/x/tools/codereview.cfg create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/enclosing_test.go create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/imports_test.go create mode 100644 vendor/golang.org/x/tools/go/ast/astutil/rewrite_test.go create mode 100644 vendor/golang.org/x/tools/imports/fix_test.go create mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_test.go delete mode 100644 vendor/golang.org/x/tools/third_party/moduleloader/LICENSE delete mode 100644 vendor/golang.org/x/tools/third_party/typescript/LICENSE delete mode 100644 vendor/golang.org/x/tools/third_party/webcomponents/LICENSE create mode 100644 vendor/google.golang.org/api/.gitignore create mode 100644 vendor/google.golang.org/api/.hgtags create mode 100644 vendor/google.golang.org/api/.travis.yml create mode 100644 vendor/google.golang.org/api/CONTRIBUTING.md create mode 100644 vendor/google.golang.org/api/GettingStarted.md create mode 100644 vendor/google.golang.org/api/NOTES create mode 100644 vendor/google.golang.org/api/README.md create mode 100644 vendor/google.golang.org/api/TODO create mode 100644 vendor/google.golang.org/api/api-list.json create mode 100644 vendor/google.golang.org/api/compute/v1/compute-api.json create mode 100644 vendor/google.golang.org/api/gensupport/backoff_test.go create mode 100644 vendor/google.golang.org/api/gensupport/buffer_test.go create mode 100644 vendor/google.golang.org/api/gensupport/header_test.go create mode 100644 vendor/google.golang.org/api/gensupport/json_test.go create mode 100644 vendor/google.golang.org/api/gensupport/jsonfloat_test.go create mode 100644 vendor/google.golang.org/api/gensupport/media_test.go create mode 100644 vendor/google.golang.org/api/gensupport/resumable_test.go create mode 100644 vendor/google.golang.org/api/gensupport/retry_test.go create mode 100644 vendor/google.golang.org/api/gensupport/send_test.go create mode 100644 vendor/google.golang.org/api/gensupport/util_test.go create mode 100644 vendor/google.golang.org/api/googleapi/googleapi_test.go create mode 100644 vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates_test.go create mode 100644 vendor/google.golang.org/api/googleapi/types_test.go create mode 100644 vendor/google.golang.org/api/key.json.enc create mode 100644 vendor/google.golang.org/appengine/.travis.yml create mode 100644 vendor/google.golang.org/appengine/README.md create mode 100644 vendor/google.golang.org/appengine/appengine_test.go create mode 100644 vendor/google.golang.org/appengine/internal/api_race_test.go create mode 100644 vendor/google.golang.org/appengine/internal/api_test.go create mode 100644 vendor/google.golang.org/appengine/internal/app_id_test.go create mode 100644 vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.proto create mode 100755 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto create mode 100644 vendor/google.golang.org/appengine/internal/internal_vm_test.go create mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/modules/modules_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/net_test.go create mode 100755 vendor/google.golang.org/appengine/internal/regen.sh create mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto create mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto create mode 100644 vendor/google.golang.org/appengine/namespace_test.go create mode 100644 vendor/gopkg.in/inf.v0/benchmark_test.go create mode 100644 vendor/gopkg.in/inf.v0/dec_go1_2_test.go create mode 100644 vendor/gopkg.in/inf.v0/dec_internal_test.go create mode 100644 vendor/gopkg.in/inf.v0/dec_test.go create mode 100644 vendor/gopkg.in/inf.v0/example_test.go create mode 100644 vendor/gopkg.in/inf.v0/rounder_example_test.go create mode 100644 vendor/gopkg.in/inf.v0/rounder_test.go create mode 100644 vendor/gopkg.in/yaml.v2/.travis.yml create mode 100644 vendor/gopkg.in/yaml.v2/README.md create mode 100644 vendor/gopkg.in/yaml.v2/decode_test.go create mode 100644 vendor/gopkg.in/yaml.v2/encode_test.go create mode 100644 vendor/gopkg.in/yaml.v2/example_embedded_test.go create mode 100644 vendor/gopkg.in/yaml.v2/go.mod create mode 100644 vendor/gopkg.in/yaml.v2/suite_test.go create mode 100644 vendor/k8s.io/api/CONTRIBUTING.md create mode 100644 vendor/k8s.io/api/OWNERS create mode 100644 vendor/k8s.io/api/README.md create mode 100644 vendor/k8s.io/api/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/api/admissionregistration/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/admissionregistration/v1beta1/generated.proto create mode 100755 vendor/k8s.io/api/apps/OWNERS create mode 100644 vendor/k8s.io/api/apps/v1/generated.proto create mode 100644 vendor/k8s.io/api/apps/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/apps/v1beta2/generated.proto create mode 100755 vendor/k8s.io/api/authentication/OWNERS create mode 100644 vendor/k8s.io/api/authentication/v1/generated.proto create mode 100644 vendor/k8s.io/api/authentication/v1beta1/generated.proto create mode 100755 vendor/k8s.io/api/authorization/OWNERS create mode 100644 vendor/k8s.io/api/authorization/v1/generated.proto create mode 100644 vendor/k8s.io/api/authorization/v1beta1/generated.proto create mode 100755 vendor/k8s.io/api/autoscaling/OWNERS create mode 100644 vendor/k8s.io/api/autoscaling/v1/generated.proto create mode 100644 vendor/k8s.io/api/autoscaling/v2beta1/generated.proto create mode 100644 vendor/k8s.io/api/autoscaling/v2beta2/generated.proto create mode 100755 vendor/k8s.io/api/batch/OWNERS create mode 100644 vendor/k8s.io/api/batch/v1/generated.proto create mode 100644 vendor/k8s.io/api/batch/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/batch/v2alpha1/generated.proto create mode 100755 vendor/k8s.io/api/certificates/OWNERS create mode 100644 vendor/k8s.io/api/certificates/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/code-of-conduct.md create mode 100644 vendor/k8s.io/api/coordination/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/core/v1/generated.proto create mode 100644 vendor/k8s.io/api/core/v1/taint_test.go create mode 100644 vendor/k8s.io/api/core/v1/toleration_test.go create mode 100644 vendor/k8s.io/api/events/OWNERS create mode 100644 vendor/k8s.io/api/events/v1beta1/generated.proto create mode 100755 vendor/k8s.io/api/extensions/OWNERS create mode 100644 vendor/k8s.io/api/extensions/v1beta1/generated.proto create mode 100755 vendor/k8s.io/api/networking/OWNERS create mode 100644 vendor/k8s.io/api/networking/v1/generated.proto create mode 100755 vendor/k8s.io/api/policy/OWNERS create mode 100644 vendor/k8s.io/api/policy/v1beta1/generated.proto create mode 100755 vendor/k8s.io/api/rbac/OWNERS create mode 100644 vendor/k8s.io/api/rbac/v1/generated.proto create mode 100644 vendor/k8s.io/api/rbac/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/rbac/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/roundtrip_test.go create mode 100644 vendor/k8s.io/api/scheduling/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/scheduling/v1beta1/generated.proto create mode 100644 vendor/k8s.io/api/settings/v1alpha1/generated.proto create mode 100755 vendor/k8s.io/api/storage/OWNERS create mode 100644 vendor/k8s.io/api/storage/v1/generated.proto create mode 100644 vendor/k8s.io/api/storage/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/storage/v1beta1/generated.proto create mode 100644 vendor/k8s.io/apimachinery/CONTRIBUTING.md create mode 100644 vendor/k8s.io/apimachinery/OWNERS create mode 100644 vendor/k8s.io/apimachinery/README.md create mode 100644 vendor/k8s.io/apimachinery/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/apimachinery/code-of-conduct.md create mode 100644 vendor/k8s.io/apimachinery/pkg/OWNERS create mode 100755 vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go create mode 100755 vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go create mode 100755 vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go rename vendor/k8s.io/{code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go => apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go} (68%) create mode 100755 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation/validation_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/converter_test.go rename vendor/k8s.io/{code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go => apimachinery/pkg/conversion/helper_test.go} (54%) create mode 100644 vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/fields_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/fields/selector_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/labels_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/labels/selector_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/conversion_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/converter_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/embedded_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/extension_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/local_scheme_test.go rename vendor/k8s.io/{code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go => apimachinery/pkg/runtime/schema/generated.proto} (71%) create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/scheme_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/sparse_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming/streaming_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning_test.go rename vendor/k8s.io/{code-generator/cmd/go-to-protobuf/main.go => apimachinery/pkg/runtime/swagger_doc_generator_test.go} (50%) create mode 100644 vendor/k8s.io/apimachinery/pkg/util/cache/cache_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/cache/lruexpirecache_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/clock/clock_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/diff/diff_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/errors/errors_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/framer/framer_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto create mode 100644 vendor/k8s.io/apimachinery/pkg/util/intstr/intstr_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/json/json_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/mergepatch/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/util/mergepatch/util_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/naming/from_stack_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/http_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/interface_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/port_range_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/port_split_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/net/util_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/rand/rand_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/runtime/runtime_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/set_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/strategicpatch/OWNERS create mode 100644 vendor/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/field/errors_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/field/path_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/validation_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/wait_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/yaml/decoder_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/version/helpers_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/filter_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/mux_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/streamwatcher_test.go create mode 100644 vendor/k8s.io/apimachinery/pkg/watch/watch_test.go create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/json/OWNERS create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/json/fields_test.go create mode 100644 vendor/k8s.io/apimachinery/third_party/forked/golang/reflect/deep_equal_test.go create mode 100644 vendor/k8s.io/apiserver/.import-restrictions create mode 100644 vendor/k8s.io/apiserver/CONTRIBUTING.md create mode 100644 vendor/k8s.io/apiserver/OWNERS create mode 100644 vendor/k8s.io/apiserver/README.md create mode 100644 vendor/k8s.io/apiserver/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/apiserver/code-of-conduct.md create mode 100644 vendor/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/flag/ciphersuites_flag_test.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/flag/colon_separated_multimap_string_string_test.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/flag/langle_separated_map_string_string_test.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/flag/map_string_bool_test.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/flag/map_string_string_test.go create mode 100644 vendor/k8s.io/apiserver/pkg/util/flag/namedcertkey_flag_test.go create mode 100644 vendor/k8s.io/client-go/.travis.yml create mode 100644 vendor/k8s.io/client-go/CHANGELOG.md create mode 100644 vendor/k8s.io/client-go/CONTRIBUTING.md create mode 100644 vendor/k8s.io/client-go/INSTALL.md create mode 100644 vendor/k8s.io/client-go/OWNERS create mode 100644 vendor/k8s.io/client-go/README.md create mode 100644 vendor/k8s.io/client-go/SECURITY_CONTACTS create mode 100644 vendor/k8s.io/client-go/code-of-conduct.md create mode 100644 vendor/k8s.io/client-go/discovery/cached_discovery_test.go create mode 100644 vendor/k8s.io/client-go/discovery/discovery_client_test.go create mode 100644 vendor/k8s.io/client-go/discovery/fake/discovery_test.go create mode 100644 vendor/k8s.io/client-go/discovery/helper_blackbox_test.go create mode 100644 vendor/k8s.io/client-go/discovery/round_tripper_test.go create mode 100644 vendor/k8s.io/client-go/listers/extensions/v1beta1/daemonset_expansion_test.go create mode 100644 vendor/k8s.io/client-go/pkg/version/.gitattributes create mode 100644 vendor/k8s.io/client-go/pkg/version/def.bzl create mode 100644 vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go rename vendor/k8s.io/{code-generator/_examples/apiserver/apis/example2/v1/doc.go => client-go/plugin/pkg/client/auth/plugins.go} (67%) create mode 100755 vendor/k8s.io/client-go/rest/OWNERS create mode 100644 vendor/k8s.io/client-go/rest/client_test.go create mode 100644 vendor/k8s.io/client-go/rest/config_test.go create mode 100644 vendor/k8s.io/client-go/rest/plugin_test.go create mode 100755 vendor/k8s.io/client-go/rest/request_test.go create mode 100644 vendor/k8s.io/client-go/rest/token_source_test.go create mode 100644 vendor/k8s.io/client-go/rest/url_utils_test.go create mode 100644 vendor/k8s.io/client-go/rest/urlbackoff_test.go create mode 100644 vendor/k8s.io/client-go/rest/watch/decoder_test.go create mode 100644 vendor/k8s.io/client-go/rest/watch/encoder_test.go create mode 100644 vendor/k8s.io/client-go/testing/fixture_test.go create mode 100644 vendor/k8s.io/client-go/tools/auth/clientauth_test.go create mode 100755 vendor/k8s.io/client-go/tools/cache/OWNERS create mode 100644 vendor/k8s.io/client-go/tools/cache/controller_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/delta_fifo_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/expiration_cache_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/fifo_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/heap_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/index_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/mutation_detector_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/processor_listener_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/reflector_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/shared_informer_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/store_test.go create mode 100644 vendor/k8s.io/client-go/tools/cache/undelta_store_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/helpers_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/api/types_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/client_config_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/loader_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/overrides_test.go create mode 100644 vendor/k8s.io/client-go/tools/clientcmd/validation_test.go create mode 100644 vendor/k8s.io/client-go/tools/leaderelection/OWNERS create mode 100644 vendor/k8s.io/client-go/tools/leaderelection/leaderelection_test.go create mode 100755 vendor/k8s.io/client-go/tools/metrics/OWNERS create mode 100644 vendor/k8s.io/client-go/tools/pager/pager_test.go create mode 100755 vendor/k8s.io/client-go/tools/record/OWNERS create mode 100644 vendor/k8s.io/client-go/tools/record/event_test.go create mode 100644 vendor/k8s.io/client-go/tools/record/events_cache_test.go create mode 100644 vendor/k8s.io/client-go/tools/reference/ref_test.go create mode 100755 vendor/k8s.io/client-go/transport/OWNERS create mode 100644 vendor/k8s.io/client-go/transport/cache_test.go create mode 100644 vendor/k8s.io/client-go/transport/round_trippers_test.go create mode 100644 vendor/k8s.io/client-go/transport/transport_test.go create mode 100644 vendor/k8s.io/client-go/util/buffer/ring_growing_test.go create mode 100644 vendor/k8s.io/client-go/util/cert/csr_test.go create mode 100644 vendor/k8s.io/client-go/util/cert/pem_test.go create mode 100644 vendor/k8s.io/client-go/util/connrotation/connrotation_test.go create mode 100644 vendor/k8s.io/client-go/util/flowcontrol/backoff_test.go create mode 100644 vendor/k8s.io/client-go/util/flowcontrol/throttle_test.go create mode 100644 vendor/k8s.io/client-go/util/integer/integer_test.go create mode 100755 vendor/k8s.io/client-go/util/retry/OWNERS create mode 100644 vendor/k8s.io/client-go/util/retry/util_test.go create mode 100644 vendor/k8s.io/client-go/util/workqueue/default_rate_limiters_test.go create mode 100644 vendor/k8s.io/client-go/util/workqueue/delaying_queue_test.go create mode 100644 vendor/k8s.io/client-go/util/workqueue/queue_test.go create mode 100644 vendor/k8s.io/client-go/util/workqueue/rate_limitting_queue_test.go delete mode 100644 vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 vendor/k8s.io/code-generator/Godeps/Godeps.json delete mode 100644 vendor/k8s.io/code-generator/Godeps/OWNERS delete mode 100644 vendor/k8s.io/code-generator/Godeps/Readme delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go delete mode 100644 vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go create mode 100644 vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages_test.go create mode 100644 vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags_test.go rename vendor/k8s.io/code-generator/cmd/{go-to-protobuf/protobuf/tags.go => client-gen/types/helpers_test.go} (59%) delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go delete mode 100644 vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go delete mode 100644 vendor/k8s.io/code-generator/cmd/import-boss/.gitignore delete mode 100644 vendor/k8s.io/code-generator/cmd/import-boss/main.go delete mode 100644 vendor/k8s.io/code-generator/cmd/register-gen/args/args.go delete mode 100644 vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go delete mode 100644 vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go delete mode 100644 vendor/k8s.io/code-generator/cmd/register-gen/main.go delete mode 100644 vendor/k8s.io/code-generator/hack/boilerplate.go.txt delete mode 100755 vendor/k8s.io/code-generator/hack/update-codegen.sh delete mode 100755 vendor/k8s.io/code-generator/hack/verify-codegen.sh delete mode 100644 vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go create mode 100644 vendor/k8s.io/gengo/.import-restrictions create mode 100644 vendor/k8s.io/gengo/.travis.yml create mode 100644 vendor/k8s.io/gengo/OWNERS create mode 100644 vendor/k8s.io/gengo/README.md rename vendor/k8s.io/{code-generator/_examples/apiserver/apis/example/doc.go => gengo/args/args_test.go} (61%) create mode 100644 vendor/k8s.io/gengo/code-of-conduct.md create mode 100644 vendor/k8s.io/gengo/examples/deepcopy-gen/.gitignore create mode 100644 vendor/k8s.io/gengo/examples/deepcopy-gen/Makefile create mode 100644 vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy_test.go create mode 100644 vendor/k8s.io/gengo/examples/deepcopy-gen/main.go create mode 100644 vendor/k8s.io/gengo/examples/defaulter-gen/.gitignore create mode 100644 vendor/k8s.io/gengo/examples/defaulter-gen/.import-restrictions create mode 100644 vendor/k8s.io/gengo/examples/defaulter-gen/Makefile create mode 100644 vendor/k8s.io/gengo/examples/defaulter-gen/OWNERS create mode 100644 vendor/k8s.io/gengo/examples/defaulter-gen/main.go rename vendor/k8s.io/{code-generator/cmd => gengo/examples}/set-gen/.gitignore (100%) create mode 100644 vendor/k8s.io/gengo/examples/set-gen/Makefile rename vendor/k8s.io/{code-generator/cmd => gengo/examples}/set-gen/main.go (77%) create mode 100644 vendor/k8s.io/gengo/examples/set-gen/sets/set_test.go create mode 100644 vendor/k8s.io/gengo/generator/snippet_writer_test.go create mode 100644 vendor/k8s.io/gengo/namer/namer_test.go create mode 100644 vendor/k8s.io/gengo/namer/plural_namer_test.go create mode 100644 vendor/k8s.io/gengo/parser/local_parse_test.go create mode 100644 vendor/k8s.io/gengo/parser/parse_test.go create mode 100644 vendor/k8s.io/gengo/types/comments_test.go create mode 100644 vendor/k8s.io/gengo/types/flatten_test.go create mode 100644 vendor/k8s.io/gengo/types/types_test.go create mode 100644 vendor/k8s.io/kube-openapi/.gitignore create mode 100644 vendor/k8s.io/kube-openapi/.travis.yml create mode 100755 vendor/k8s.io/kube-openapi/OWNERS create mode 100644 vendor/k8s.io/kube-openapi/README.md create mode 100644 vendor/k8s.io/kube-openapi/code-of-conduct.md create mode 100644 vendor/k8s.io/kube-openapi/pkg/generators/README create mode 100644 vendor/k8s.io/kube-openapi/pkg/generators/openapi_test.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_suite_test.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_test.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/util/trie.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/util/util.go diff --git a/vendor/cloud.google.com/go/.travis.yml b/vendor/cloud.google.com/go/.travis.yml new file mode 100644 index 000000000..59594d41c --- /dev/null +++ b/vendor/cloud.google.com/go/.travis.yml @@ -0,0 +1,21 @@ +sudo: false +language: go +go: +- 1.6.x +- 1.7.x +- 1.8.x +- 1.9.x +install: +- go get -v cloud.google.com/go/... +script: +- openssl aes-256-cbc -K $encrypted_a8b3f4fc85f4_key -iv $encrypted_a8b3f4fc85f4_iv -in keys.tar.enc -out keys.tar -d +- tar xvf keys.tar +- GCLOUD_TESTS_GOLANG_PROJECT_ID="dulcet-port-762" + GCLOUD_TESTS_GOLANG_KEY="$(pwd)/dulcet-port-762-key.json" + GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID="gcloud-golang-firestore-tests" + GCLOUD_TESTS_GOLANG_FIRESTORE_KEY="$(pwd)/gcloud-golang-firestore-tests-key.json" + ./run-tests.sh $TRAVIS_COMMIT +env: + matrix: + # The GCLOUD_TESTS_API_KEY environment variable. + secure: VdldogUOoubQ60LhuHJ+g/aJoBiujkSkWEWl79Zb8cvQorcQbxISS+JsOOp4QkUOU4WwaHAm8/3pIH1QMWOR6O78DaLmDKi5Q4RpkVdCpUXy+OAfQaZIcBsispMrjxLXnqFjo9ELnrArfjoeCTzaX0QTCfwQwVmigC8rR30JBKI= diff --git a/vendor/cloud.google.com/go/CONTRIBUTING.md b/vendor/cloud.google.com/go/CONTRIBUTING.md new file mode 100644 index 000000000..95c94a48b --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTING.md @@ -0,0 +1,152 @@ +# Contributing + +1. Sign one of the contributor license agreements below. +1. `go get golang.org/x/review/git-codereview` to install the code reviewing tool. + 1. You will need to ensure that your `GOBIN` directory (by default + `$GOPATH/bin`) is in your `PATH` so that git can find the command. + 1. If you would like, you may want to set up aliases for git-codereview, + such that `git codereview change` becomes `git change`. See the + [godoc](https://godoc.org/golang.org/x/review/git-codereview) for details. + 1. Should you run into issues with the git-codereview tool, please note + that all error messages will assume that you have set up these + aliases. +1. Get the cloud package by running `go get -d cloud.google.com/go`. + 1. If you have already checked out the source, make sure that the remote git + origin is https://code.googlesource.com/gocloud: + + git remote set-url origin https://code.googlesource.com/gocloud +1. Make sure your auth is configured correctly by visiting + https://code.googlesource.com, clicking "Generate Password", and following + the directions. +1. Make changes and create a change by running `git codereview change `, +provide a commit message, and use `git codereview mail` to create a Gerrit CL. +1. Keep amending to the change with `git codereview change` and mail as your receive +feedback. Each new mailed amendment will create a new patch set for your change in Gerrit. + +## Integration Tests + +In addition to the unit tests, you may run the integration test suite. + +To run the integrations tests, creating and configuration of a project in the +Google Developers Console is required. + +After creating a project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount). +Ensure the project-level **Owner** +[IAM role](console.cloud.google.com/iam-admin/iam/project) role is added to the +service account. Alternatively, the account can be granted all of the following roles: +- **Editor** +- **Logs Configuration Writer** +- **PubSub Admin** + +Once you create a project, set the following environment variables to be able to +run the against the actual APIs. + +- **GCLOUD_TESTS_GOLANG_PROJECT_ID**: Developers Console project's ID (e.g. bamboo-shift-455) +- **GCLOUD_TESTS_GOLANG_KEY**: The path to the JSON key file. +- **GCLOUD_TESTS_API_KEY**: Your API key. + +Firestore requires a different project and key: + +- **GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID**: Developers Console project's ID + supporting Firestore +- **GCLOUD_TESTS_GOLANG_FIRESTORE_KEY**: The path to the JSON key file. + +Install the [gcloud command-line tool][gcloudcli] to your machine and use it +to create some resources used in integration tests. + +From the project's root directory: + +``` sh +# Set the default project in your env. +$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID + +# Authenticate the gcloud tool with your account. +$ gcloud auth login + +# Create the indexes used in the datastore integration tests. +$ gcloud preview datastore create-indexes datastore/testdata/index.yaml + +# Create a Google Cloud storage bucket with the same name as your test project, +# and with the Stackdriver Logging service account as owner, for the sink +# integration tests in logging. +$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID +$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID + +# Create a PubSub topic for integration tests of storage notifications. +$ gcloud beta pubsub topics create go-storage-notification-test + +# Create a Spanner instance for the spanner integration tests. +$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 1 --description 'Instance for go client test' +# NOTE: Spanner instances are priced by the node-hour, so you may want to delete +# the instance after testing with 'gcloud beta spanner instances delete'. + + +``` + +Once you've set the environment variables, you can run the integration tests by +running: + +``` sh +$ go test -v cloud.google.com/go/... +``` + +## Contributor License Agreements + +Before we can accept your pull requests you'll need to sign a Contributor +License Agreement (CLA): + +- **If you are an individual writing original source code** and **you own the +intellectual property**, then you'll need to sign an [individual CLA][indvcla]. +- **If you work for a company that wants to allow you to contribute your +work**, then you'll need to sign a [corporate CLA][corpcla]. + +You can sign these electronically (just scroll to the bottom). After that, +we'll be able to accept your pull requests. + +## Contributor Code of Conduct + +As contributors and maintainers of this project, +and in the interest of fostering an open and welcoming community, +we pledge to respect all people who contribute through reporting issues, +posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project +a harassment-free experience for everyone, +regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, +such as physical or electronic +addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct. +By adopting this Code of Conduct, +project maintainers commit themselves to fairly and consistently +applying these principles to every aspect of managing this project. +Project maintainers who do not follow or enforce the Code of Conduct +may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior +may be reported by opening an issue +or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) + +[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ +[indvcla]: https://developers.google.com/open-source/cla/individual +[corpcla]: https://developers.google.com/open-source/cla/corporate diff --git a/vendor/cloud.google.com/go/MIGRATION.md b/vendor/cloud.google.com/go/MIGRATION.md new file mode 100644 index 000000000..791210de1 --- /dev/null +++ b/vendor/cloud.google.com/go/MIGRATION.md @@ -0,0 +1,54 @@ +# Code Changes + +## v0.10.0 + +- pubsub: Replace + + ``` + sub.ModifyPushConfig(ctx, pubsub.PushConfig{Endpoint: "https://example.com/push"}) + ``` + + with + + ``` + sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{ + PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"}, + }) + ``` + +- trace: traceGRPCServerInterceptor will be provided from *trace.Client. +Given an initialized `*trace.Client` named `tc`, instead of + + ``` + s := grpc.NewServer(grpc.UnaryInterceptor(trace.GRPCServerInterceptor(tc))) + ``` + + write + + ``` + s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor())) + ``` + +- trace trace.GRPCClientInterceptor will also provided from *trace.Client. +Instead of + + ``` + conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor())) + ``` + + write + + ``` + conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) + ``` + +- trace: We removed the deprecated `trace.EnableGRPCTracing`. Use the gRPC +interceptor as a dial option as shown below when initializing Cloud package +clients: + + ``` + c, err := pubsub.NewClient(ctx, "project-id", option.WithGRPCDialOption(grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor()))) + if err != nil { + ... + } + ``` diff --git a/vendor/cloud.google.com/go/README.md b/vendor/cloud.google.com/go/README.md new file mode 100644 index 000000000..ada5f57a4 --- /dev/null +++ b/vendor/cloud.google.com/go/README.md @@ -0,0 +1,546 @@ +# Google Cloud Client Libraries for Go + +[![GoDoc](https://godoc.org/cloud.google.com/go?status.svg)](https://godoc.org/cloud.google.com/go) + +Go packages for [Google Cloud Platform](https://cloud.google.com) services. + +``` go +import "cloud.google.com/go" +``` + +To install the packages on your system, + +``` +$ go get -u cloud.google.com/go/... +``` + +**NOTE:** Some of these packages are under development, and may occasionally +make backwards-incompatible changes. + +**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud). + + * [News](#news) + * [Supported APIs](#supported-apis) + * [Go Versions Supported](#go-versions-supported) + * [Authorization](#authorization) + * [Cloud Datastore](#cloud-datastore-) + * [Cloud Storage](#cloud-storage-) + * [Cloud Pub/Sub](#cloud-pub-sub-) + * [Cloud BigQuery](#cloud-bigquery-) + * [Stackdriver Logging](#stackdriver-logging-) + * [Cloud Spanner](#cloud-spanner-) + + +## News + +_January 18, 2018_ + +*v0.18.0* + +- bigquery: + - Marked stable. + - Schema inference of nullable fields supported. + - Added TimePartitioning to QueryConfig. + +- firestore: Data provided to DocumentRef.Set with a Merge option can contain + Delete sentinels. + +- logging: Clients can accept parent resources other than projects. + +- pubsub: + - pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome. + - Support updating more subscription metadata: AckDeadline, + RetainAckedMessages and RetentionDuration. + +- oslogin/apiv1beta: New client for the Cloud OS Login API. + +- rpcreplay: A package for recording and replaying gRPC traffic. + +- spanner: + - Add a ReadWithOptions that supports a row limit, as well as an index. + - Support query plan and execution statistics. + - Added [OpenCensus](http://opencensus.io) support. + +- storage: Clarify checksum validation for gzipped files (it is not validated + when the file is served uncompressed). + + +_December 11, 2017_ + +*v0.17.0* + +- firestore BREAKING CHANGES: + - Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update. + Change + `docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})` + to + `docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})` + + Change + `docref.UpdateStruct(ctx, []string{"Field"}, aStruct)` + to + `docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})` + - Rename MergePaths to Merge; require args to be FieldPaths + - A value stored as an integer can be read into a floating-point field, and vice versa. +- bigtable/cmd/cbt: + - Support deleting a column. + - Add regex option for row read. +- spanner: Mark stable. +- storage: + - Add Reader.ContentEncoding method. + - Fix handling of SignedURL headers. +- bigquery: + - If Uploader.Put is called with no rows, it returns nil without making a + call. + - Schema inference supports the "nullable" option in struct tags for + non-required fields. + - TimePartitioning supports "Field". + + +_October 30, 2017_ + +*v0.16.0* + +- Other bigquery changes: + - `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE). + - UseStandardSQL is deprecated; set UseLegacySQL to true if you need + Legacy SQL. + - Uploader.Put will generate a random insert ID if you do not provide one. + - Support time partitioning for load jobs. + - Support dry-run queries. + - A `Job` remembers its last retrieved status. + - Support retrieving job configuration. + - Support labels for jobs and tables. + - Support dataset access lists. + - Improve support for external data sources, including data from Bigtable and + Google Sheets, and tables with external data. + - Support updating a table's view configuration. + - Fix uploading civil times with nanoseconds. + +- storage: + - Support PubSub notifications. + - Support Requester Pays buckets. + +- profiler: Support goroutine and mutex profile types. + + +_October 3, 2017_ + +*v0.15.0* + +- firestore: beta release. See the + [announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html). + +- errorreporting: The existing package has been redesigned. + +- errors: This package has been removed. Use errorreporting. + + +[Older news](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/old-news.md) + +## Supported APIs + +Google API | Status | Package +---------------------------------|--------------|----------------------------------------------------------- +[BigQuery][cloud-bigquery] | stable | [`cloud.google.com/go/bigquery`][cloud-bigquery-ref] +[Bigtable][cloud-bigtable] | beta | [`cloud.google.com/go/bigtable`][cloud-bigtable-ref] +[Container][cloud-container] | alpha | [`cloud.google.com/go/container/apiv1`][cloud-container-ref] +[Data Loss Prevention][cloud-dlp]| alpha | [`cloud.google.com/go/dlp/apiv2beta1`][cloud-dlp-ref] +[Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`][cloud-datastore-ref] +[Debugger][cloud-debugger] | alpha | [`cloud.google.com/go/debugger/apiv2`][cloud-debugger-ref] +[ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`][cloud-errors-ref] +[Firestore][cloud-firestore] | beta | [`cloud.google.com/go/firestore`][cloud-firestore-ref] +[Language][cloud-language] | stable | [`cloud.google.com/go/language/apiv1`][cloud-language-ref] +[Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`][cloud-logging-ref] +[Monitoring][cloud-monitoring] | beta | [`cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref] +[OS Login][cloud-oslogin] | alpha | [`cloud.google.com/compute/docs/oslogin/rest`][cloud-oslogin-ref] +[Pub/Sub][cloud-pubsub] | beta | [`cloud.google.com/go/pubsub`][cloud-pubsub-ref] +[Spanner][cloud-spanner] | stable | [`cloud.google.com/go/spanner`][cloud-spanner-ref] +[Speech][cloud-speech] | stable | [`cloud.google.com/go/speech/apiv1`][cloud-speech-ref] +[Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`][cloud-storage-ref] +[Translation][cloud-translation] | stable | [`cloud.google.com/go/translate`][cloud-translation-ref] +[Video Intelligence][cloud-video]| beta | [`cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref] +[Vision][cloud-vision] | stable | [`cloud.google.com/go/vision/apiv1`][cloud-vision-ref] + + +> **Alpha status**: the API is still being actively developed. As a +> result, it might change in backward-incompatible ways and is not recommended +> for production use. +> +> **Beta status**: the API is largely complete, but still has outstanding +> features and bugs to be addressed. There may be minor backwards-incompatible +> changes where necessary. +> +> **Stable status**: the API is mature and ready for production use. We will +> continue addressing bugs and feature requests. + +Documentation and examples are available at +https://godoc.org/cloud.google.com/go + +Visit or join the +[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce) +for updates on these packages. + +## Go Versions Supported + +We support the two most recent major versions of Go. If Google App Engine uses +an older version, we support that as well. You can see which versions are +currently supported by looking at the lines following `go:` in +[`.travis.yml`](.travis.yml). + +## Authorization + +By default, each API will use [Google Application Default Credentials][default-creds] +for authorization credentials used in calling the API endpoints. This will allow your +application to run in many environments without requiring explicit configuration. + +[snip]:# (auth) +```go +client, err := storage.NewClient(ctx) +``` + +To authorize using a +[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys), +pass +[`option.WithServiceAccountFile`](https://godoc.org/google.golang.org/api/option#WithServiceAccountFile) +to the `NewClient` function of the desired package. For example: + +[snip]:# (auth-JSON) +```go +client, err := storage.NewClient(ctx, option.WithServiceAccountFile("path/to/keyfile.json")) +``` + +You can exert more control over authorization by using the +[`golang.org/x/oauth2`](https://godoc.org/golang.org/x/oauth2) package to +create an `oauth2.TokenSource`. Then pass +[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource) +to the `NewClient` function: +[snip]:# (auth-ts) +```go +tokenSource := ... +client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource)) +``` + +## Cloud Datastore [![GoDoc](https://godoc.org/cloud.google.com/go/datastore?status.svg)](https://godoc.org/cloud.google.com/go/datastore) + +- [About Cloud Datastore][cloud-datastore] +- [Activating the API for your project][cloud-datastore-activation] +- [API documentation][cloud-datastore-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore) +- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks) + +### Example Usage + +First create a `datastore.Client` to use throughout your application: + +[snip]:# (datastore-1) +```go +client, err := datastore.NewClient(ctx, "my-project-id") +if err != nil { + log.Fatal(err) +} +``` + +Then use that client to interact with the API: + +[snip]:# (datastore-2) +```go +type Post struct { + Title string + Body string `datastore:",noindex"` + PublishedAt time.Time +} +keys := []*datastore.Key{ + datastore.NameKey("Post", "post1", nil), + datastore.NameKey("Post", "post2", nil), +} +posts := []*Post{ + {Title: "Post 1", Body: "...", PublishedAt: time.Now()}, + {Title: "Post 2", Body: "...", PublishedAt: time.Now()}, +} +if _, err := client.PutMulti(ctx, keys, posts); err != nil { + log.Fatal(err) +} +``` + +## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage) + +- [About Cloud Storage][cloud-storage] +- [API documentation][cloud-storage-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/storage) +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage) + +### Example Usage + +First create a `storage.Client` to use throughout your application: + +[snip]:# (storage-1) +```go +client, err := storage.NewClient(ctx) +if err != nil { + log.Fatal(err) +} +``` + +[snip]:# (storage-2) +```go +// Read the object1 from bucket. +rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx) +if err != nil { + log.Fatal(err) +} +defer rc.Close() +body, err := ioutil.ReadAll(rc) +if err != nil { + log.Fatal(err) +} +``` + +## Cloud Pub/Sub [![GoDoc](https://godoc.org/cloud.google.com/go/pubsub?status.svg)](https://godoc.org/cloud.google.com/go/pubsub) + +- [About Cloud Pubsub][cloud-pubsub] +- [API documentation][cloud-pubsub-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub) +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub) + +### Example Usage + +First create a `pubsub.Client` to use throughout your application: + +[snip]:# (pubsub-1) +```go +client, err := pubsub.NewClient(ctx, "project-id") +if err != nil { + log.Fatal(err) +} +``` + +Then use the client to publish and subscribe: + +[snip]:# (pubsub-2) +```go +// Publish "hello world" on topic1. +topic := client.Topic("topic1") +res := topic.Publish(ctx, &pubsub.Message{ + Data: []byte("hello world"), +}) +// The publish happens asynchronously. +// Later, you can get the result from res: +... +msgID, err := res.Get(ctx) +if err != nil { + log.Fatal(err) +} + +// Use a callback to receive messages via subscription1. +sub := client.Subscription("subscription1") +err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { + fmt.Println(m.Data) + m.Ack() // Acknowledge that we've consumed the message. +}) +if err != nil { + log.Println(err) +} +``` + +## Cloud BigQuery [![GoDoc](https://godoc.org/cloud.google.com/go/bigquery?status.svg)](https://godoc.org/cloud.google.com/go/bigquery) + +- [About Cloud BigQuery][cloud-bigquery] +- [API documentation][cloud-bigquery-docs] +- [Go client documentation][cloud-bigquery-ref] +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery) + +### Example Usage + +First create a `bigquery.Client` to use throughout your application: +[snip]:# (bq-1) +```go +c, err := bigquery.NewClient(ctx, "my-project-ID") +if err != nil { + // TODO: Handle error. +} +``` + +Then use that client to interact with the API: +[snip]:# (bq-2) +```go +// Construct a query. +q := c.Query(` + SELECT year, SUM(number) + FROM [bigquery-public-data:usa_names.usa_1910_2013] + WHERE name = "William" + GROUP BY year + ORDER BY year +`) +// Execute the query. +it, err := q.Read(ctx) +if err != nil { + // TODO: Handle error. +} +// Iterate through the results. +for { + var values []bigquery.Value + err := it.Next(&values) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(values) +} +``` + + +## Stackdriver Logging [![GoDoc](https://godoc.org/cloud.google.com/go/logging?status.svg)](https://godoc.org/cloud.google.com/go/logging) + +- [About Stackdriver Logging][cloud-logging] +- [API documentation][cloud-logging-docs] +- [Go client documentation][cloud-logging-ref] +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging) + +### Example Usage + +First create a `logging.Client` to use throughout your application: +[snip]:# (logging-1) +```go +ctx := context.Background() +client, err := logging.NewClient(ctx, "my-project") +if err != nil { + // TODO: Handle error. +} +``` + +Usually, you'll want to add log entries to a buffer to be periodically flushed +(automatically and asynchronously) to the Stackdriver Logging service. +[snip]:# (logging-2) +```go +logger := client.Logger("my-log") +logger.Log(logging.Entry{Payload: "something happened!"}) +``` + +Close your client before your program exits, to flush any buffered log entries. +[snip]:# (logging-3) +```go +err = client.Close() +if err != nil { + // TODO: Handle error. +} +``` + +## Cloud Spanner [![GoDoc](https://godoc.org/cloud.google.com/go/spanner?status.svg)](https://godoc.org/cloud.google.com/go/spanner) + +- [About Cloud Spanner][cloud-spanner] +- [API documentation][cloud-spanner-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner) + +### Example Usage + +First create a `spanner.Client` to use throughout your application: + +[snip]:# (spanner-1) +```go +client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D") +if err != nil { + log.Fatal(err) +} +``` + +[snip]:# (spanner-2) +```go +// Simple Reads And Writes +_, err = client.Apply(ctx, []*spanner.Mutation{ + spanner.Insert("Users", + []string{"name", "email"}, + []interface{}{"alice", "a@example.com"})}) +if err != nil { + log.Fatal(err) +} +row, err := client.Single().ReadRow(ctx, "Users", + spanner.Key{"alice"}, []string{"email"}) +if err != nil { + log.Fatal(err) +} +``` + + +## Contributing + +Contributions are welcome. Please, see the +[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md) +document for details. We're using Gerrit for our code reviews. Please don't open pull +requests against this repo, new pull requests will be automatically closed. + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. +See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct) +for more information. + +[cloud-datastore]: https://cloud.google.com/datastore/ +[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore +[cloud-datastore-docs]: https://cloud.google.com/datastore/docs +[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate + +[cloud-firestore]: https://cloud.google.com/firestore/ +[cloud-firestore-ref]: https://godoc.org/cloud.google.com/go/firestore +[cloud-firestore-docs]: https://cloud.google.com/firestore/docs +[cloud-firestore-activation]: https://cloud.google.com/firestore/docs/activate + +[cloud-pubsub]: https://cloud.google.com/pubsub/ +[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub +[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs + +[cloud-storage]: https://cloud.google.com/storage/ +[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage +[cloud-storage-docs]: https://cloud.google.com/storage/docs +[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets + +[cloud-bigtable]: https://cloud.google.com/bigtable/ +[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable + +[cloud-bigquery]: https://cloud.google.com/bigquery/ +[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs +[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery + +[cloud-logging]: https://cloud.google.com/logging/ +[cloud-logging-docs]: https://cloud.google.com/logging/docs +[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging + +[cloud-monitoring]: https://cloud.google.com/monitoring/ +[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3 + +[cloud-vision]: https://cloud.google.com/vision +[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1 + +[cloud-language]: https://cloud.google.com/natural-language +[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1 + +[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest +[cloud-oslogin-ref]: https://cloud.google.com/compute/docs/oslogin/rest + +[cloud-speech]: https://cloud.google.com/speech +[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1 + +[cloud-spanner]: https://cloud.google.com/spanner/ +[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner +[cloud-spanner-docs]: https://cloud.google.com/spanner/docs + +[cloud-translation]: https://cloud.google.com/translation +[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation + +[cloud-video]: https://cloud.google.com/video-intelligence/ +[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1 + +[cloud-errors]: https://cloud.google.com/error-reporting/ +[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting + +[cloud-container]: https://cloud.google.com/containers/ +[cloud-container-ref]: https://godoc.org/cloud.google.com/go/container/apiv1 + +[cloud-debugger]: https://cloud.google.com/debugger/ +[cloud-debugger-ref]: https://godoc.org/cloud.google.com/go/debugger/apiv2 + +[cloud-dlp]: https://cloud.google.com/dlp/ +[cloud-dlp-ref]: https://godoc.org/cloud.google.com/go/dlp/apiv2beta1 + +[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials diff --git a/vendor/cloud.google.com/go/appveyor.yml b/vendor/cloud.google.com/go/appveyor.yml new file mode 100644 index 000000000..e66cd00af --- /dev/null +++ b/vendor/cloud.google.com/go/appveyor.yml @@ -0,0 +1,32 @@ +# This file configures AppVeyor (http://www.appveyor.com), +# a Windows-based CI service similar to Travis. + +# Identifier for this run +version: "{build}" + +# Clone the repo into this path, which conforms to the standard +# Go workspace structure. +clone_folder: c:\gopath\src\cloud.google.com\go + +environment: + GOPATH: c:\gopath + GCLOUD_TESTS_GOLANG_PROJECT_ID: dulcet-port-762 + GCLOUD_TESTS_GOLANG_KEY: c:\gopath\src\cloud.google.com\go\key.json + KEYFILE_CONTENTS: + secure: IvRbDAhM2PIQqzVkjzJ4FjizUvoQ+c3vG/qhJQG+HlZ/L5KEkqLu+x6WjLrExrNMyGku4znB2jmbTrUW3Ob4sGG+R5vvqeQ3YMHCVIkw5CxY+/bUDkW5RZWsVbuCnNa/vKsWmCP+/sZW6ICe29yKJ2ZOb6QaauI4s9R6j+cqBbU9pumMGYFRb0Rw3uUU7DKmVFCy+NjTENZIlDP9rmjANgAzigowJJEb2Tg9sLlQKmQeKiBSRN8lKc5Nq60a+fIzHGKvql4eIitDDDpOpyHv15/Xr1BzFw2yDoiR4X1lng0u7q0X9RgX4VIYa6gT16NXBEmQgbuX8gh7SfPMp9RhiZD9sVUaV+yogEabYpyPnmUURo0hXwkctKaBkQlEmKvjHwF5dvbg8+yqGhwtjAgFNimXG3INrwQsfQsZskkQWanutbJf9xy50GyWWFZZdi0uT4oXP/b5P7aklPXKXsvrJKBh7RjEaqBrhi86IJwOjBspvoR4l2WmcQyxb2xzQS1pjbBJFQfYJJ8+JgsstTL8PBO9d4ybJC0li1Om1qnWxkaewvPxxuoHJ9LpRKof19yRYWBmhTXb2tTASKG/zslvl4fgG4DmQBS93WC7dsiGOhAraGw2eCTgd0lYZOhk1FjWl9TS80aktXxzH/7nTvem5ohm+eDl6O0wnTL4KXjQVNSQ1PyLn4lGRJ5MNGzBTRFWIr2API2rca4Fysyfh/UdmazPGlNbY9JPGqb9+F04QzLfqm+Zz/cHy59E7lOSMBlUI4KD6d6ZNNKNRH+/g9i+fSiyiXKugTfda8KBnWGyPwprxuWGYaiQUGUYOwJY5R6x5c4mjImAB310V+Wo33UbWFJiwxEDsiCNqW1meVkBzt2er26vh4qbgCUIQ3iM3gFPfHgy+QxkmIhic7Q1HYacQElt8AAP41M7cCKWCuZidegP37MBB//mjjiNt047ZSQEvB4tqsX/OvfbByVef+cbtVw9T0yjHvmCdPW1XrhyrCCgclu6oYYdbmc5D7BBDRbjjMWGv6YvceAbfGf6ukdB5PuV+TGEN/FoQ1QTRA6Aqf+3fLMg4mS4oyTfw5xyYNbv3qoyLPrp+BnxI53WB9p0hfMg4n9FD6NntBxjDq+Q3Lk/bjC/Y4MaRWdzbMzF9a0lgGfcw9DURlK5p7uGJC9vg34feNoQprxVEZRQ01cHLeob6eGkYm4HxSRx8JY39Mh+9wzJo+k/aIvFleNC3e35NOrkXr6wb5e42n2DwBdPqdNolTLtLFRglAL1LTpp27UjvjieWJAKfoDTR5CKl01sZqt0wPdLLcvsMj6CiPFmccUIOYeZMe86kLBD61Qa5F1EwkgO3Om2qSjW96FzL4skRc+BmU5RrHlAFSldR1wpUgtkUMv9vH5Cy+UJdcvpZ8KbmhZ2PsjF7ddJ1ve9RAw3cP325AyIMwZ77Ef1mgTM0NJze6eSW1qKlEsgt1FADPyeUu1NQTA2H2dueMPGlArWTSUgyWR9AdfpqouT7eg0JWI5w+yUZZC+/rPglYbt84oLmYpwuli0z8FyEQRPIc3EtkfWIv/yYgDr2TZ0N2KvGfpi/MAUWgxI1gleC2uKgEOEtuJthd3XZjF2NoE7IBqjQOINybcJOjyeB5vRLDY1FLuxYzdg1y1etkV4XQig/vje + +install: + # Info for debugging. + - echo %PATH% + - go version + - go env + - go get -v -d -t ./... + + +# Provide a build script, or AppVeyor will call msbuild. +build_script: + - go install -v ./... + - echo %KEYFILE_CONTENTS% > %GCLOUD_TESTS_GOLANG_KEY% + +test_script: + - go test -v ./... diff --git a/vendor/cloud.google.com/go/authexample_test.go b/vendor/cloud.google.com/go/authexample_test.go new file mode 100644 index 000000000..fe75467f9 --- /dev/null +++ b/vendor/cloud.google.com/go/authexample_test.go @@ -0,0 +1,49 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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 cloud_test + +import ( + "cloud.google.com/go/datastore" + "golang.org/x/net/context" + "google.golang.org/api/option" +) + +func Example_applicationDefaultCredentials() { + // Google Application Default Credentials is the recommended way to authorize + // and authenticate clients. + // + // See the following link on how to create and obtain Application Default Credentials: + // https://developers.google.com/identity/protocols/application-default-credentials. + client, err := datastore.NewClient(context.Background(), "project-id") + if err != nil { + // TODO: handle error. + } + _ = client // Use the client. +} + +func Example_serviceAccountFile() { + // Use a JSON key file associated with a Google service account to + // authenticate and authorize. Service Account keys can be created and + // downloaded from https://console.developers.google.com/permissions/serviceaccounts. + // + // Note: This example uses the datastore client, but the same steps apply to + // the other client libraries underneath this package. + client, err := datastore.NewClient(context.Background(), + "project-id", option.WithServiceAccountFile("/path/to/service-account-key.json")) + if err != nil { + // TODO: handle error. + } + _ = client // Use the client. +} diff --git a/vendor/cloud.google.com/go/cloud.go b/vendor/cloud.google.com/go/cloud.go new file mode 100644 index 000000000..6ba428dc6 --- /dev/null +++ b/vendor/cloud.google.com/go/cloud.go @@ -0,0 +1,20 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// 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 cloud is the root of the packages used to access Google Cloud +// Services. See https://godoc.org/cloud.google.com/go for a full list +// of sub-packages. +// +// This package documents how to authorize and authenticate the sub packages. +package cloud // import "cloud.google.com/go" diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go new file mode 100644 index 000000000..9ac592691 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go @@ -0,0 +1,48 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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 metadata + +import ( + "os" + "sync" + "testing" +) + +func TestOnGCE_Stress(t *testing.T) { + if testing.Short() { + t.Skip("skipping in -short mode") + } + var last bool + for i := 0; i < 100; i++ { + onGCEOnce = sync.Once{} + + now := OnGCE() + if i > 0 && now != last { + t.Errorf("%d. changed from %v to %v", i, last, now) + } + last = now + } + t.Logf("OnGCE() = %v", last) +} + +func TestOnGCE_Force(t *testing.T) { + onGCEOnce = sync.Once{} + old := os.Getenv(metadataHostEnv) + defer os.Setenv(metadataHostEnv, old) + os.Setenv(metadataHostEnv, "127.0.0.1") + if !OnGCE() { + t.Error("OnGCE() = false; want true") + } +} diff --git a/vendor/cloud.google.com/go/import_test.go b/vendor/cloud.google.com/go/import_test.go new file mode 100644 index 000000000..839fae45f --- /dev/null +++ b/vendor/cloud.google.com/go/import_test.go @@ -0,0 +1,61 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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 cloud + +import ( + "go/parser" + "go/token" + "os" + "path/filepath" + "strconv" + "testing" +) + +func TestContextImport(t *testing.T) { + t.Parallel() + + whiteList := map[string]bool{ + "storage/go17.go": true, + } + + err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + if filepath.Ext(path) != ".go" || whiteList[path] { + return nil + } + + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) + if err != nil { + return err + } + + for _, imp := range file.Imports { + impPath, err := strconv.Unquote(imp.Path.Value) + if err != nil { + return err + } + if impPath == "context" { + t.Errorf(`file %q import "context", want "golang.org/x/net/context"`, path) + } + } + return nil + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/cloud.google.com/go/keys.tar.enc b/vendor/cloud.google.com/go/keys.tar.enc new file mode 100644 index 0000000000000000000000000000000000000000..c54408c93a2b7d36467ceced9e697a7e6be66db5 GIT binary patch literal 10256 zcmV+rDDT%d%4FE-XGE3p;$)uBB?9V+ouudaKhoM}hbuNiA~pZ{E8E-hBY`-Dn_Q%D z)1eTB-6xjC`t3rjAH(j)i+}xJ0#_k#k2Ei-53?7pb(EE)s?ceMM>7zAAv>$SzP9-h zHi8>*N=*@`J_+b(a1jXZ(+M=#xZ;N&knOE6gw@5_dZB+sYusIMbmvbdeU>he9Zmq3 z7IfMkHTjLY+Jn_1Zy14{?#2fgMv-vh_Qa|bOItot{b4e5?QEPEqMPX*xdx>5w zTt*8it3>fa)awDKDNh0HtzYlzJ@1<@O1)#R#Fzw2S5FB;2IhW)5i#@B)p-qFz;$z?e{Z-huragATmXz zSTOC<2gDF{%_s}F^%zNV6N~igmTwHb1mBT*^CA^@soq^ z+<#m8D%(S_$p5}UYl@NJoJBV!g zc?^JRPT@FROn^^CBj~Dy0VyPXaTviGoF$seUez{s&nn4wmvaTbrTv`zaFmIEs8-bT z-Sbw%Fj}r!&$18`7|;b`!$zoOD1QAtz>~%g{DVJRm(|bbb**QdepSwaVs#bKhm-+ zc_CBe!I}>4=DyBd6Omd71Ktp`6nhA^$3@GdbA=U3t)2S?nqpLS!Wxla?bWRJ2YHAH z@Df|>tCsw(=GxQXg1;oz`r77C(uGgsGGUaPCM^9K1nhz~>Uim_t%z;Ud3W?cZ#~g9 z)+_0w$>bCua;W+Rnj}EDfXBFn8{yz7uyDfL&2IZ9t+2Xb{@iana-TFz?ic-2KCR=a zpX;Nq#W~!?bXJdp;LRQo>I<}bs5WSJhGZ5$!zEtr;lcaph1p;f1gj{AODENdep|_6 z?#}50L@7Gw(Kg;u3%0iQ<^XAGtbDi~s8_ROq~9(eVl^5eC>F>|;Z{U`0%K$c=7n!~ zaVy7Y8gbPa)sO!@(+qeqrTAHlZntqJMFfE-_icOnY3Zt+?Ll%L3y@I#1sTi{*zdb< zFJA28ZwTxgzNZ=tK7W=1*z1XZo$mhW>u`OuFDMHpLK76y=jo}^vXUE_T_YDo)-j*v z>nHKlA2k14n}!u%<DpyyKCHc>9Dm!D3O~<^1!z&M zx^bZ|4LkR5o~AJB@y=+bpTT#q`eZP5Pzi#wNq1&F`{%j-_o+IJ39Qa7;ttdY#ekn9 zRDymxZq)uPZW2oMD`d!%9Vwy%;xB7y8Ou!=N?8Z+KjoYk%5pT)pzXGC~rMB#16J&}C&~&Li+e>{P>ZDThyl`m|SJix~w$9%GCpFkcO{PR0TBpXNdn_^2mcdJ;;^5lPA;< zdW{p!%(!4YGN1I7e5|b{k42|owjY<`?10CCRL-h;-2_JslMUN1UXpN(JgX%-d1nM%y*W=r72P~k4o z?9AmJtr7{J#GyEe=X68u__?HvbD}zd#6=N=So*5a<7yNCgtFvoZ6X@_Os9ESREtxx zY_vzNJgca!y*$ZCuJ{zSB3P^W8uQ!GdKU-0TB`|4MjOG`Qd!8O30Wf}c(B;p{P6Wp zD!7UDS(PCf3piqXn2p^t&vKK)JNVIn%R4LuHXk#6g2Va*AKLv7gW1@|EGq2(vIqzv zC3M+ilY&N-u_bdhcB_{khbo2oB1ou`wF-H_33M__b<;;4Z9o_meKvKfA+U^JZlxq1F)5c73St7fs>0@K5J?EHJP=N@ zI!-=!^J5riIY#r7kBBJ%9@svn*J;(BH~$?6Ne$SL^AJ& z|E9^+ZAD_lGJb@z{?6KK9+qrXYev>%Lwc- z#SyG5FHLKzvyzveqMmSl1``^qr@-X$6n}tn4?x5))?&@~Rx;r3<2D4;MW7T=meKuj zR5J`_zckAHW+b@5`mN(70i3DVYhty}{kaW=r&EqIj;kV=(gz6ShmX8Jb?L4pwZ~)g zg2Yp+%J-#Qd_*cF7~M_h9w}A@mZv!CI5O}kIWG*dO@QHZXUQ^_b2*~0ivGMGOnbL7 zSePL`G{Czy5&5)B@~|`FV9)=Iw6+J2#+=^Rr`8AuHK}dX{?}R>UHUR7c3b1U@{437 z&nzV=x*+N)uMH#o0J?b(K2Y@5uLoF(K8hCU18x|z)sIt3d%TineP)`_cQud;z5+rFMmr_H+e1Ze zaL;M0h-v|A)N4a0CjUC?43r88z^-JOG`oUHh82hGIM>I}cqrFFt?_Xap=lJW(=m41 zjxh>qf&p8!w_1$~TK$|VM7b&N5>a%@EM%D~wGkYdbBRb2bvQn z65?`Uh5+1cBV$Bh+)lxH$fi}m`~gNU@&rWjbbYJH z``*)UGVsbc&K9A>$xO>5QFV+btPpB&f)!;eWjhcyg&$=1OuNYGbl=1wBb&09Wz4Nu zk;3IcUq~CcS2^)LN!Q3v(h1yUhrgmY5$H)AX1wl4xB ziC12Tr9IZuDZe!$k=)}G8iBMo;URV0uI7^G5nwVf|3+6yMTDZg7ygmq0{^u{bbv64 z`$$@mZLb>_QnOZKgcYgTpy6Yz&f@B4^F1@*bBS578`^3 z{)00y3}rzArlWG)=njUp>mN^U0qj-~>c&__-}tYf??|ntj~9}LLh9>)rw7P<3{6D4fpnnf0B!5WpdcnDc?c4Mo427}3y=lT^*z19nRYh0^bu;hikJLh)un zA2)Q0A1aR5M@4cpi(*sscB)7RarN*=ppr!JH^D)S~d`99;&g-j4h;pj-I_2s?~T0^0*U7}&j7YS znQ6ebPqs6C?GELt+(0d~djDz*)kU7F|_OK0WvjBczgOJAVl*VY~ zew1ENHvN6L*$Rq&EIWxYRG^qwTvXEUraD03#YQdE1a9;v%CrqpB?6(YuJ@v)abLRN z4RaZAd+c4T82CN9)5dsmGsDJ^?!r(X2~EqFeWUEDEz+7TOe1$Y&>O0Mtc_ZW1bTf5 z_GwJ(S?o*6%`|U4E^}%XsKe#qy?NND3{NE4Cj~1YNfJ%$*0<35lxsaTHtKJa`)aih z{gk%2w#chF_vMbi=kh;bROmspkG7cCLeKZL-p?xo0T^&!J1zJk37IC15%zfhKr*?O zB{(g?z$}&=u>w0jZ!nF<{H08V%Ljc7K0RA@fvLrf$_K)mzY-)JoIUQQmt8$}`&#Gw zS`=d~Zm^W~+pK>%1u(pdoPWT*UjmD=g}?T`x7=w#^%C5h=I?~n67kd6{UmAcMeGsD z-2t(#2b=83S^Gguxg~*xt^5m$^7ap%YJRbDbj)jzz9kc_=wyG%`B~_YUk2Rt&m+YZ zQp4Sns)1a_Pr^F|syj^4meXW_ce)LW0969-dm}|#-zDwtOBZM#WgHFB*Mmugft&m% zkM6A0f{{+xbP5900`p(?q+nC7L^L|D<{S@ar#$~LX~Qez{!>CYKJtBY zdZV6=ah-z$oH3+F66iZMDlMg9U+azmU%c}65tPVuh{eh^RW<7C>8-8LK^`4trY)=| z&dZYzpQwT9K3nk+D~mW2S2<|M3vc%+UIyOf4&|b63<=SJ4!sxQ0)QOdP}Xbkh(#A5 zp!bI3*&z^p`U(2@^^Re)OzW&0hchNFAhQ?>7rqDE7VE{n(>Ke%F1v7z)DK}j>hyT* zSCDi*CxWm(d^J^`_8G+m<~Q(!b!Ir+UGxD-nEp?Qbj9M`sHnnnSF|C|>0FIp!m(|$A^4xe3?E;E_ZJB8eXvVCny>l%B1hfPNK`dMV3Sf{i>vy^MMGzr@pRY$G!aYTxW5ytW^CjMkw`}7jgQ&K#?Dz;3 z@uoo4!Y1eMUun$2vxdbY-Ku z(e?Y73Xc7$9>WBz1lZIjPmSuq_q;-Klcp2kV3V7EqU)Mn=9lDK~XgBUQ&amv52 zx;0w8mYJV={o!&f4rc}5Do5@fM}Nmew>9m}K+ zkmuez$a%1$?&?jQ~|rD-iejJaHYQd|HcOmo3IJ) zaE+2%n}N5Ec*Tq|+XimH{d4;WuNH$|8PIKlG;99&z6ZLzZ`3nE+&j0}U0D{bs_L-W z0wd0O4*h&!@WOG{jRbx+o==YMlQ}V#kp%m|!LQ%(P!`V{>NxsOVBtjEb%%=_y_9$v za7(VfVGVPPV{1al(HnPLz18*HU~SgoQmc}=xUM2fv0j86u>4&vD$qMc+;R-^QDy{@ za)E=gaZ;6Mh6p!N>5!^mI85}_^cEJ>m{6g?%A4bzKkcXTz?yyNB1|b#cPL%u&2I?b z`JfD*B_RqRiKxJphax@mQ(+XhnQgUzo90RZ_T^;VXng`Wrp+w_b<`kwQYAJ%3@*pT z)9J@h_ocUk+-r&p3vHe##RdP4O>NIv8wO?10Y?bGt}OInrZ8`HrE23maFr!~>nMVm z+5p!YWsS8K7%Q_%*TSkKW zZ|u4$D{zG52B8i6$2}gN*WhL=!oL6kP$b|dpujKGoVWYY51>g(yFz=oXQ`dqhbs(` zLLcl>+Rw<>-zo=K&ip{9-bTAyY9+T7&9j%KH1U54jyhvJ*ZS(0 zGXF?vTsAye2K^6DSU?(Rc%Z%T6%JPuHE~BJZE2k?m=3h60%{jyaij|6*YKJEf2fi84{XKF57(aA{pX0&URv2kKdekL<@ zsdD@wA?0~6_q^mRN zJ-ON!F>A&yBATCVNY&R@!Qd=?DD}qORWp}x`-5K95}8sxa^P03?hqM9x9PTcnFD|U zF)Q5VWa{}#Y81o79t7!dY4iekBNS5k3}{#NGJ@ZRFaXcf@5dY5*C92&SXSfqH{Klp z#15kl21f`$$t;6T%ac5c^D8j&)gPQ$Np8*0p28@xs;oVkq9P6Z0mIQ|H2=Oz8)b9L zFnP{$Wv9>zG(pll*G_vcu@9F1&lCL!_Y#!0Zgx84_)cSY9;=>Sy&Wdflx=Qg^6I%z z+K`Pyyo6pXYaMQmqM{Y)k(<*7`}3!`6_1^wl+i4!KX`}5qVyW#k~ZWnlGUH`rl{z|#og&2ZZrhd z@>nz$D@K;f{+@`ecgbJDk8n7+@XeqW%93HBGD-p4>K~EflaXSDIcjCte&{29?fZS> zjQDB%f@A24i_Pkh{M)|niy})S@umuj)fYDq(2g}fTqSw4Fv%yLoj%KNkabdQ3I@RQ z#`glL(>t%eAS2vwZeuEnA!r7~Q4t62PY75RFA%>_6l5lHD6g2>4ztj$?mG2fr;#kJ9ltNHAEHf1Hc_&I+4?Jf*2!m<4`WRmdVO{c6Lci8nfhIurItki0q z2uqvlHY^UhEx)A5;uFOK1zVbHIRORe2s(fJi@(0`A!6a@n-69oBTVCdVAcl_DJV1| z%q)}O~01yRqlo60#D?r>c; zw+LDyQ`G(7F=QFmH*!4LTt-j1WopoQU(x8L0A)S=#>c--+k z^udb{OAvnC$hP?qA?|;DVuM-?>5Z76yH^H5F(Ct5>GQx@gt=sNm`AXW{vPHo1iV5; z#ok__P;nbv@k`UtUKpFwzxEV2S7j#S`hq5#$nphU#7%U`^q=TCCy|BsQ-4FWtBt;5 z5lg1xr(5kyc?cHPh}yK|%6IGmt7b}`hwegg#Asf33g1ie(%{k+weflY)$~f^?alCW z3Gb~c@R~cF7(=6Nq48~_B$G3cse9(DMDYpE@GkPlg0VFI1kWqJ^g=cJ62&PRLhIb+ zm9>n?^rv2cmb9T?m(9)KPY}> zV4amq=dG7byHc&iu^pn6qT-Y;VH`K2!>?EByg}S+q;)QTExZ73a8CFdAZ= zJDXGG@@Iw=tw1dIp%(1h;qUcMoBBk!GcA2$Bi+X9Ktf1@liH=D_2+3}^B!;oU;3y` z=}ws9(;*@fhX$ad859=^%+iyXGPg5&*T@I3f1_5{`XqxL5b=#lJSd2pHV;2^H_PuN-b1#X@v zOalvs?7N1WkriZlHBCXYF1Tr?a#o(`b_lv+E1(*n->RG95fP&2W4f`bY91$coOo`HUymltOKZ<&U~l7h5Gx^l_0;EuM9dv$dUd zK~xZLFR84Cacx*Ek8$Zksq8$;4IL=KR16!op&U&=gpqup${L3ys$GY-Qs=uZ>W2=t z_1kvZfrUYeCl2OfN8n2>-7Bik8cHh4#_VnJ=f;IA#K;_m*y8k9;>O`-@~)iox5GQv zNkrMGH67FuX&IV%?@cb^|E~vZ4$kfv+OgvYsm_jtZq3UE6D?dE>H+1gpI1IDK@esM zl1r3dIVRALnR0w5Nm5O9F0u(gf6%>j{B#&9-GPPm;fY7TM_HCB22GSXj$m zIkO=TG>?IKTN% z?c5tk4D78k46*mQlO2wC@{)hJm;bQv9VT@=z z52g=a90@rXmXpz#?Z{25(jQB~|EVZ3Y~n*&;6Oq+ROAg2xx;SrIVN^-OBviXSHSB| zv5#ug&T8x1ywY0FW4q<8!nIy%<#?C;3CiLMT*#49ASeKxP1_N{=!O0A%p_lzh6l$y ze!EwGvsK#qM%MKRul!?BrY99K<{Tm4{}q+Df<>4fBszF0YKoMst2ro|#k5W^8UWbG zIWVC1jj{Babn;2P1?sQt6=H8A=rqY=xAmqZ8~HkNm<4ASTvX?aL zJp+Dt`u&BjUQY|nz5v4gv-89i4`OfK1;7>0X8%qVH0{0@lN@26Y{PIlLt- zylUx##ov|6-<=}cEN)?w^JNZD9MogG!z=3De$lR(1Pwr7?+&*83cSRU`=5xfH@4gJS2!c?+l*BK97R?^pnANZD!J_tNc>Xs8?G6}~NF?V)3)^~O~!P}S1jwV$iV&PrqN z19JV{h(0sF+8B&j1suhG7Hr9xgr3T}0*K%m6YBXuB_s-czIp?o##_7*xDREqzN%Kl zNV~KYHb;%_QaBn$#MmE-5ydy0RzFp<&N2z7W6l};d&jcLWiu3{2FzI$wUN$=Pmbn1 zt@UR-n9lI58SNOkyiiEwk3A`wK%0Bq(Qj{&;i7n$g3QS&xkqs1-Os=tsfxs_fDZ3k z%OF3R$~XVaGpc<|xP@|S9^rlClUXgbtoDimos*dZCa#%~)hmQyw`AhQel4D89Ttd8 zWE(M3K_JLO`6yN@E!l4tbOw*w3)Bo-KelG7!Qf8A1e&^1o^Vh7Kg#hI4hJ~T+lZ5$ z>>{^w9IE&>1MSK*rT526L2}x+VSX#FpP2s?KaVjN;%*R;Uh&zxhJzk^Wdjo~<@glj zsPoY!vVF`RU-!9}go-G%Hg-D-GlDs4CK0^q*bw-Eg0l=BYB<6}F0fd1Iw zB1tF27B$%!k8B!w06En(S&jG9p)tgw^RK^{{?KY#GDt-e-r2iG^QusFbA|gAmpFj( zz1?ajcKCvf?=rs=(L75&ubCZyluky9Zq%~J3IOmA#BV>2anKf%kD0_dxA~g`YMC}H zzWFYK31-LFX}uTf2NzcsLzOjQq3}F$->x8uzYq{cpxex}8k&AjBKbD0*LHoC;d=Kt zeLV?otF=HCNYQWjph}pR+-9S>{MD)-MpvZiri%9AoKj8Ewd3wq`k^qcpgS816j{9S zAFmtRD;^$JwD`Sy4fgJ2-SP%g*LrgNgtXAT_xyf!J%L`ZD}?#jI3+5y0*qW3nBDfG zuid}anyzn$dw#Fkr{lbSPK(oAPYXj>faM7o&?0fP;2?Labw>2HtSqW%u^6pX+n&o( zskce>)_;SWUHi@*mKtvv@ z;LaGT)#$z^4A-ETCcp$7{>fjh#+y(`YsB+xs7@yR1Pp$h7gSXP_%~OWw`d>*+|H5R z+ahN;BqWl??#FnMwAS&rPA(6%_Cr zf#xf>)S62xWGvUC+1#iXJwap&WlQ{vx93Q%$FrTIRfEv>QNVa(RhNhH=_%|w-2Z;j zg>-WT2OWJ(n#q_B%?4{}cyaHHAYejfy1>75=6G918Z?uIS3P%&b*V^IPcq2RX14O6 z6%67B^|GtUeCt$4`MgLsR&L;yUZh92+o#!Z`>-V4fa(J4ejdWqL6Uh3R!x~|1qA~k zC?{j@0aPoHP#el+L>b~bL;NTCuo>6#(jM$^qx+GxuIiq;Z}vR2kF9Ap$mWQ;L~ueZjbYUtRN z_Mn)W%w^WIvCQ#eCN82;?SS`r!_hrZb7dgFvb`@Aa!8T(l-r zMey26L9@dxr@EgpBfm$4aL)pn<>}zMo-JH#8g3J4%C_cRSlX`Z2J~PgiLwi5oXXrH zZ@rm{UUp$+{}3@m7j&dAV0eYbIf;A)Y6wpyDMnB6HSY}G^TS)%Bxi+y*4VYuJ*6Zuv{ zzCpNgC%HyRX!s@|DpK}y+gN9#%HwmG!eodpS4t|$x0P7{iA3*%Q18Ussq-}u0bghs zLY(c)DTR5a9`%|+;IIHK>?S23MMzX;-BWU%IBomnM12~=oS!!&rEv;Uj8D86G9XK literal 0 HcmV?d00001 diff --git a/vendor/cloud.google.com/go/license_test.go b/vendor/cloud.google.com/go/license_test.go new file mode 100644 index 000000000..f93e9e005 --- /dev/null +++ b/vendor/cloud.google.com/go/license_test.go @@ -0,0 +1,71 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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 cloud + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +var sentinels = []string{ + "Copyright", + "Google", + `Licensed under the Apache License, Version 2.0 (the "License");`, +} + +func TestLicense(t *testing.T) { + t.Parallel() + err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + + if ext := filepath.Ext(path); ext != ".go" && ext != ".proto" { + return nil + } + if strings.HasSuffix(path, ".pb.go") { + // .pb.go files are generated from the proto files. + // .proto files must have license headers. + return nil + } + if path == "bigtable/cmd/cbt/cbtdoc.go" { + // Automatically generated. + return nil + } + + src, err := ioutil.ReadFile(path) + if err != nil { + return nil + } + src = src[:140] // Ensure all of the sentinel values are at the top of the file. + + // Find license + for _, sentinel := range sentinels { + if !bytes.Contains(src, []byte(sentinel)) { + t.Errorf("%v: license header not present. want %q", path, sentinel) + return nil + } + } + + return nil + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/cloud.google.com/go/old-news.md b/vendor/cloud.google.com/go/old-news.md new file mode 100644 index 000000000..0c8a224d0 --- /dev/null +++ b/vendor/cloud.google.com/go/old-news.md @@ -0,0 +1,557 @@ +_September 28, 2017_ + +*v0.14.0* + +- bigquery BREAKING CHANGES: + - Standard SQL is the default for queries and views. + - `Table.Create` takes `TableMetadata` as a second argument, instead of + options. + - `Dataset.Create` takes `DatasetMetadata` as a second argument. + - `DatasetMetadata` field `ID` renamed to `FullID` + - `TableMetadata` field `ID` renamed to `FullID` + +- Other bigquery changes: + - The client will append a random suffix to a provided job ID if you set + `AddJobIDSuffix` to true in a job config. + - Listing jobs is supported. + - Better retry logic. + +- vision, language, speech: clients are now stable + +- monitoring: client is now beta + +- profiler: + - Rename InstanceName to Instance, ZoneName to Zone + - Auto-detect service name and version on AppEngine. + +_September 8, 2017_ + +*v0.13.0* + +- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these + options to continue using Legacy SQL after the client switches its default + to Standard SQL. + +- bigquery: Support for updating dataset labels. + +- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other + than the client's. DatasetsInProject is no longer needed and is deprecated. + +- bigtable: Fail ListInstances when any zones fail. + +- spanner: support decoding of slices of basic types (e.g. []string, []int64, + etc.) + +- logging/logadmin: UpdateSink no longer creates a sink if it is missing + (actually a change to the underlying service, not the client) + +- profiler: Service and ServiceVersion replace Target in Config. + +_August 22, 2017_ + +*v0.12.0* + +- pubsub: Subscription.Receive now uses streaming pull. + +- pubsub: add Client.TopicInProject to access topics in a different project + than the client. + +- errors: renamed errorreporting. The errors package will be removed shortly. + +- datastore: improved retry behavior. + +- bigquery: support updates to dataset metadata, with etags. + +- bigquery: add etag support to Table.Update (BREAKING: etag argument added). + +- bigquery: generate all job IDs on the client. + +- storage: support bucket lifecycle configurations. + + +_July 31, 2017_ + +*v0.11.0* + +- Clients for spanner, pubsub and video are now in beta. + +- New client for DLP. + +- spanner: performance and testing improvements. + +- storage: requester-pays buckets are supported. + +- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements. + +- pubsub: bug fixes and other minor improvements + +_June 17, 2017_ + + +*v0.10.0* + +- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update. + +- pubsub: Subscription.Receive now runs concurrently for higher throughput. + +- vision: cloud.google.com/go/vision is deprecated. Use +cloud.google.com/go/vision/apiv1 instead. + +- translation: now stable. + +- trace: several changes to the surface. See the link below. + +[Code changes required from v0.9.0.](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/MIGRATION.md) + + +_March 17, 2017_ + +Breaking Pubsub changes. +* Publish is now asynchronous +([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)). +* Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)). +* Message.Done replaced with Message.Ack and Message.Nack. + +_February 14, 2017_ + +Release of a client library for Spanner. See +the +[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html). + +Note that although the Spanner service is beta, the Go client library is alpha. + +_December 12, 2016_ + +Beta release of BigQuery, DataStore, Logging and Storage. See the +[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html). + +Also, BigQuery now supports structs. Read a row directly into a struct with +`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`. +You can also use field tags. See the [package documentation][cloud-bigquery-ref] +for details. + +_December 5, 2016_ + +More changes to BigQuery: + +* The `ValueList` type was removed. It is no longer necessary. Instead of + ```go + var v ValueList + ... it.Next(&v) .. + ``` + use + + ```go + var v []Value + ... it.Next(&v) ... + ``` + +* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or + `ValueList` would append to the slice. Now each call resets the size to zero first. + +* Schema inference will infer the SQL type BYTES for a struct field of + type []byte. Previously it inferred STRING. + +* The types `uint`, `uint64` and `uintptr` are no longer supported in schema + inference. BigQuery's integer type is INT64, and those types may hold values + that are not correctly represented in a 64-bit signed integer. + +* The SQL types DATE, TIME and DATETIME are now supported. They correspond to + the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil` + package. + +_November 17, 2016_ + +Change to BigQuery: values from INTEGER columns will now be returned as int64, +not int. This will avoid errors arising from large values on 32-bit systems. + +_November 8, 2016_ + +New datastore feature: datastore now encodes your nested Go structs as Entity values, +instead of a flattened list of the embedded struct's fields. +This means that you may now have twice-nested slices, eg. +```go +type State struct { + Cities []struct{ + Populations []int + } +} +``` + +See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for +more details. + +_November 8, 2016_ + +Breaking changes to datastore: contexts no longer hold namespaces; instead you +must set a key's namespace explicitly. Also, key functions have been changed +and renamed. + +* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method: + ```go + q := datastore.NewQuery("Kind").Namespace("ns") + ``` + +* All the fields of Key are exported. That means you can construct any Key with a struct literal: + ```go + k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"} + ``` + +* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed. + +* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace + ```go + NewIncompleteKey(ctx, kind, parent) + ``` + with + ```go + IncompleteKey(kind, parent) + ``` + and if you do use namespaces, make sure you set the namespace on the returned key. + +* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace + ```go + NewKey(ctx, kind, name, 0, parent) + NewKey(ctx, kind, "", id, parent) + ``` + with + ```go + NameKey(kind, name, parent) + IDKey(kind, id, parent) + ``` + and if you do use namespaces, make sure you set the namespace on the returned key. + +* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`. + +* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection. + +See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for +more details. + +_October 27, 2016_ + +Breaking change to bigquery: `NewGCSReference` is now a function, +not a method on `Client`. + +New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling +loading data into a table from a file or any `io.Reader`. + +_October 21, 2016_ + +Breaking change to pubsub: removed `pubsub.Done`. + +Use `iterator.Done` instead, where `iterator` is the package +`google.golang.org/api/iterator`. + +_October 19, 2016_ + +Breaking changes to cloud.google.com/go/bigquery: + +* Client.Table and Client.OpenTable have been removed. + Replace + ```go + client.OpenTable("project", "dataset", "table") + ``` + with + ```go + client.DatasetInProject("project", "dataset").Table("table") + ``` + +* Client.CreateTable has been removed. + Replace + ```go + client.CreateTable(ctx, "project", "dataset", "table") + ``` + with + ```go + client.DatasetInProject("project", "dataset").Table("table").Create(ctx) + ``` + +* Dataset.ListTables have been replaced with Dataset.Tables. + Replace + ```go + tables, err := ds.ListTables(ctx) + ``` + with + ```go + it := ds.Tables(ctx) + for { + table, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use table. + } + ``` + +* Client.Read has been replaced with Job.Read, Table.Read and Query.Read. + Replace + ```go + it, err := client.Read(ctx, job) + ``` + with + ```go + it, err := job.Read(ctx) + ``` + and similarly for reading from tables or queries. + +* The iterator returned from the Read methods is now named RowIterator. Its + behavior is closer to the other iterators in these libraries. It no longer + supports the Schema method; see the next item. + Replace + ```go + for it.Next(ctx) { + var vals ValueList + if err := it.Get(&vals); err != nil { + // TODO: Handle error. + } + // TODO: use vals. + } + if err := it.Err(); err != nil { + // TODO: Handle error. + } + ``` + with + ``` + for { + var vals ValueList + err := it.Next(&vals) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use vals. + } + ``` + Instead of the `RecordsPerRequest(n)` option, write + ```go + it.PageInfo().MaxSize = n + ``` + Instead of the `StartIndex(i)` option, write + ```go + it.StartIndex = i + ``` + +* ValueLoader.Load now takes a Schema in addition to a slice of Values. + Replace + ```go + func (vl *myValueLoader) Load(v []bigquery.Value) + ``` + with + ```go + func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema) + ``` + + +* Table.Patch is replace by Table.Update. + Replace + ```go + p := table.Patch() + p.Description("new description") + metadata, err := p.Apply(ctx) + ``` + with + ```go + metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{ + Description: "new description", + }) + ``` + +* Client.Copy is replaced by separate methods for each of its four functions. + All options have been replaced by struct fields. + + * To load data from Google Cloud Storage into a table, use Table.LoaderFrom. + + Replace + ```go + client.Copy(ctx, table, gcsRef) + ``` + with + ```go + table.LoaderFrom(gcsRef).Run(ctx) + ``` + Instead of passing options to Copy, set fields on the Loader: + ```go + loader := table.LoaderFrom(gcsRef) + loader.WriteDisposition = bigquery.WriteTruncate + ``` + + * To extract data from a table into Google Cloud Storage, use + Table.ExtractorTo. Set fields on the returned Extractor instead of + passing options. + + Replace + ```go + client.Copy(ctx, gcsRef, table) + ``` + with + ```go + table.ExtractorTo(gcsRef).Run(ctx) + ``` + + * To copy data into a table from one or more other tables, use + Table.CopierFrom. Set fields on the returned Copier instead of passing options. + + Replace + ```go + client.Copy(ctx, dstTable, srcTable) + ``` + with + ```go + dst.Table.CopierFrom(srcTable).Run(ctx) + ``` + + * To start a query job, create a Query and call its Run method. Set fields + on the query instead of passing options. + + Replace + ```go + client.Copy(ctx, table, query) + ``` + with + ```go + query.Run(ctx) + ``` + +* Table.NewUploader has been renamed to Table.Uploader. Instead of options, + configure an Uploader by setting its fields. + Replace + ```go + u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) + ``` + with + ```go + u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) + u.IgnoreUnknownValues = true + ``` + +_October 10, 2016_ + +Breaking changes to cloud.google.com/go/storage: + +* AdminClient replaced by methods on Client. + Replace + ```go + adminClient.CreateBucket(ctx, bucketName, attrs) + ``` + with + ```go + client.Bucket(bucketName).Create(ctx, projectID, attrs) + ``` + +* BucketHandle.List replaced by BucketHandle.Objects. + Replace + ```go + for query != nil { + objs, err := bucket.List(d.ctx, query) + if err != nil { ... } + query = objs.Next + for _, obj := range objs.Results { + fmt.Println(obj) + } + } + ``` + with + ```go + iter := bucket.Objects(d.ctx, query) + for { + obj, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { ... } + fmt.Println(obj) + } + ``` + (The `iterator` package is at `google.golang.org/api/iterator`.) + + Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`. + + Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`. + + +* ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom. + Replace + ```go + attrs, err := src.CopyTo(ctx, dst, nil) + ``` + with + ```go + attrs, err := dst.CopierFrom(src).Run(ctx) + ``` + + Replace + ```go + attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"}) + ``` + with + ```go + c := dst.CopierFrom(src) + c.ContextType = "text/html" + attrs, err := c.Run(ctx) + ``` + +* ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom. + Replace + ```go + attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil) + ``` + with + ```go + attrs, err := dst.ComposerFrom(src1, src2).Run(ctx) + ``` + +* ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate. + Replace + ```go + attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"}) + ``` + with + ```go + attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"}) + ``` + +* ObjectHandle.WithConditions replaced by ObjectHandle.If. + Replace + ```go + obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen)) + ``` + with + ```go + obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen}) + ``` + + Replace + ```go + obj.WithConditions(storage.IfGenerationMatch(0)) + ``` + with + ```go + obj.If(storage.Conditions{DoesNotExist: true}) + ``` + +* `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`). + +_October 6, 2016_ + +Package preview/logging deleted. Use logging instead. + +_September 27, 2016_ + +Logging client replaced with preview version (see below). + +_September 8, 2016_ + +* New clients for some of Google's Machine Learning APIs: Vision, Speech, and +Natural Language. + +* Preview version of a new [Stackdriver Logging][cloud-logging] client in +[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging). +This client uses gRPC as its transport layer, and supports log reading, sinks +and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly. + diff --git a/vendor/cloud.google.com/go/regen-gapic.sh b/vendor/cloud.google.com/go/regen-gapic.sh new file mode 100755 index 000000000..158b1b0db --- /dev/null +++ b/vendor/cloud.google.com/go/regen-gapic.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# This script generates all GAPIC clients in this repo. +# One-time setup: +# cd path/to/googleapis # https://github.com/googleapis/googleapis +# virtualenv env +# . env/bin/activate +# pip install googleapis-artman +# deactivate +# +# Regenerate: +# cd path/to/googleapis +# . env/bin/activate +# $GOPATH/src/cloud.google.com/go/regen-gapic.sh +# deactivate +# +# Being in googleapis directory is important; +# that's where we find YAML files and where artman puts the "artman-genfiles" directory. +# +# NOTE: This script does not generate the "raw" gRPC client found in google.golang.org/genproto. +# To do that, use the regen.sh script in the genproto repo instead. + +set -ex + +APIS=( +google/cloud/bigquery/datatransfer/artman_bigquerydatatransfer.yaml +google/cloud/dataproc/artman_dataproc_v1.yaml +google/cloud/language/artman_language_v1.yaml +google/cloud/language/artman_language_v1beta2.yaml +google/cloud/oslogin/artman_oslogin_v1beta.yaml +google/cloud/speech/artman_speech_v1.yaml +google/cloud/speech/artman_speech_v1beta1.yaml +google/cloud/videointelligence/artman_videointelligence_v1beta1.yaml +google/cloud/videointelligence/artman_videointelligence_v1beta2.yaml +google/cloud/vision/artman_vision_v1.yaml +google/cloud/vision/artman_vision_v1p1beta1.yaml +google/container/artman_container.yaml +google/devtools/artman_clouddebugger.yaml +google/devtools/clouderrorreporting/artman_errorreporting.yaml +google/devtools/cloudtrace/artman_cloudtrace_v1.yaml +google/devtools/cloudtrace/artman_cloudtrace_v2.yaml +google/firestore/artman_firestore.yaml +google/logging/artman_logging.yaml +google/longrunning/artman_longrunning.yaml +google/monitoring/artman_monitoring.yaml +google/privacy/dlp/artman_dlp.yaml +google/pubsub/artman_pubsub.yaml +google/spanner/admin/database/artman_spanner_admin_database.yaml +google/spanner/admin/instance/artman_spanner_admin_instance.yaml +google/spanner/artman_spanner.yaml +) + +for api in "${APIS[@]}"; do + rm -rf artman-genfiles/* + artman2 --config "$api" generate go_gapic + cp -r artman-genfiles/gapi-*/cloud.google.com/go/* $GOPATH/src/cloud.google.com/go/ +done + +go list cloud.google.com/go/... | grep apiv | xargs go test + +go test -short cloud.google.com/go/... + +echo "googleapis version: $(git rev-parse HEAD)" diff --git a/vendor/cloud.google.com/go/run-tests.sh b/vendor/cloud.google.com/go/run-tests.sh new file mode 100755 index 000000000..f47ff50a5 --- /dev/null +++ b/vendor/cloud.google.com/go/run-tests.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# Selectively run tests for this repo, based on what has changed +# in a commit. Runs short tests for the whole repo, and full tests +# for changed directories. + +set -e + +prefix=cloud.google.com/go + +dryrun=false +if [[ $1 == "-n" ]]; then + dryrun=true + shift +fi + +if [[ $1 == "" ]]; then + echo >&2 "usage: $0 [-n] COMMIT" + exit 1 +fi + +# Files or directories that cause all tests to run if modified. +declare -A run_all +run_all=([.travis.yml]=1 [run-tests.sh]=1) + +function run { + if $dryrun; then + echo $* + else + (set -x; $*) + fi +} + + +# Find all the packages that have changed in this commit. +declare -A changed_packages + +for f in $(git diff-tree --no-commit-id --name-only -r $1); do + if [[ ${run_all[$f]} == 1 ]]; then + # This change requires a full test. Do it and exit. + run go test -race -v $prefix/... + exit + fi + # Map, e.g., "spanner/client.go" to "$prefix/spanner". + d=$(dirname $f) + if [[ $d == "." ]]; then + pkg=$prefix + else + pkg=$prefix/$d + fi + changed_packages[$pkg]=1 +done + +echo "changed packages: ${!changed_packages[*]}" + + +# Reports whether its argument, a package name, depends (recursively) +# on a changed package. +function depends_on_changed_package { + # According to go list, a package does not depend on itself, so + # we test that separately. + if [[ ${changed_packages[$1]} == 1 ]]; then + return 0 + fi + for dep in $(go list -f '{{range .Deps}}{{.}} {{end}}' $1); do + if [[ ${changed_packages[$dep]} == 1 ]]; then + return 0 + fi + done + return 1 +} + +# Collect the packages into two separate lists. (It is faster go test a list of +# packages than to individually go test each one.) + +shorts= +fulls= +for pkg in $(go list $prefix/...); do # for each package in the repo + if depends_on_changed_package $pkg; then # if it depends on a changed package + fulls="$fulls $pkg" # run the full test + else # otherwise + shorts="$shorts $pkg" # run the short test + fi +done +run go test -race -v -short $shorts +if [[ $fulls != "" ]]; then + run go test -race -v $fulls +fi diff --git a/vendor/github.com/Azure/azure-sdk-for-go/.gitignore b/vendor/github.com/Azure/azure-sdk-for-go/.gitignore new file mode 100644 index 000000000..ff0345c3c --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/.gitignore @@ -0,0 +1,32 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +# *.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# Editor swap files +*.swp +*~ +.DS_Store + +# ignore vendor/ +vendor/ diff --git a/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml b/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml new file mode 100644 index 000000000..b6de91791 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/.travis.yml @@ -0,0 +1,48 @@ +sudo: false + +language: go +go: + - 1.8.x + - 1.9.x + +install: + - go get -u github.com/golang/lint/golint + - go get -u github.com/golang/dep/cmd/dep + - export GO15VENDOREXPERIMENT=1 + - dep ensure + +script: + - bash rungas.sh + - grep -L -r --include *.go --exclude-dir vendor -P "Copyright (\d{4}|\(c\)) Microsoft" ./ | tee /dev/stderr | test -z "$(< /dev/stdin)" + - test -z "$(gofmt -s -l $(find ./arm/* -type d -print) | tee /dev/stderr)" + - test -z "$(gofmt -s -l -w management | tee /dev/stderr)" + - test -z "$(gofmt -s -l -w storage | tee /dev/stderr)" + - test -z "$(gofmt -s -l -w Gododir | tee /dev/stderr)" + - test -z "$(gofmt -s -l -w $(find ./datalake-store/* -type d -print) | tee /dev/stderr)" + - test -z "$(gofmt -s -l -w $(find ./services/* -type d -print) | tee /dev/stderr)" + - test -z "$(go build $(find ./* -type d -print | grep -v '^./vendor$' | grep -v '^./storage$') | tee /dev/stderr)" + - test -z "$(go vet $(find ./arm/* -type d -print) | tee /dev/stderr)" + - test -z "$(golint ./arm/... | tee /dev/stderr)" + - go build ./arm/examples/... + - go build ./profiles/... + - test -z "$(go fmt ./profiles/... | tee /dev/stderr)" + - test -z "$(go vet ./profiles/... | tee /dev/stderr)" + # - test -z "$(golint ./profiles/... | tee /dev/stderr)" # This line should be uncommented once Aliases include comments. + - go build ./services/... + - test -z "$(go fmt ./services/... | tee /dev/stderr)" + - test -z "$(go vet ./services/... | tee /dev/stderr)" + # - test -z "$(golint ./services/... | tee /dev/stderr)" + - go test -v ./management/... + - go test -v ./arm/... + - go test -v ./storage/... + - bash ./tools/profileBuilder/test.sh + - go test -v ./datalake-store/... + - go test -v ./dataplane/... + - test -z "$(golint ./management/... | grep -v 'should have comment' | grep -v 'stutters' | tee /dev/stderr)" + - test -z "$(golint ./storage/... | tee /dev/stderr)" + - go vet ./management/... + - go vet ./storage/... + - go vet ./datalake-store/... + - go vet ./dataplane/... + - test -z "$(golint ./Gododir/... | tee /dev/stderr)" + - go vet ./Gododir/... diff --git a/vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md new file mode 100644 index 000000000..c03948dc8 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/CHANGELOG.md @@ -0,0 +1,735 @@ +# CHANGELOG + +## `v12.5.0-beta` + +### Changes + +- Added Container Instance API Versions 2017-10-01-preview, 2017-12-01-preview, and 2018-02-01-preview. + +## `v12.4.0-beta` + +### Changes + +- Added API version 2017-12-01 for the compute package. + +## `v12.3.0-beta` + +### Changes + +- Updated event grid dataplane with latest swagger changes. +- Added latest event grid management plane API version. + +## `v12.2.0-beta` + +### Changes + +#### Storage + +- Add support for creating a SAS client from an endpoint and SAS token. +- Fixed bug that wasn't appending SAS token to URI query parameters in all cases. + +## `v12.1.1-beta` + +### Changes + +- Removing (at least temporarily) calls to `uuid.NewV1()` due to breaking changes (see https://github.com/Azure/azure-sdk-for-go/issues/947 for more info). +- Deleted glide files as we are now using dep. + +## `v12.1.0-beta` + +### New Services + +#### Data plane +- Cognitive Services Computer Vision +- Cognitive Services Content Moderator +- Cognitive Services LUIS + +## `v12.0.0-beta` + +### Changes +- Long Running Operations now return a `Future` type. Go routines and return via channel features have been removed. +- Added support for services that make use of polymorphic types. +- Operations now make use of the [Context Pattern](https://blog.golang.org/context). +- Container Services has been moved out of Compute folder in its own folder. +- Azure Go SDK is now using [dep](https://github.com/golang/dep) for vendoring. +- The *arm* and *dataplane* folders have been deprecated. Use the *profiles* and the *services* folders instead. +- Group clients have been renamed to a a service specific name. + +### New Services + +#### Management Plane +- Azure Container Service for Kubernetes (AKS) +- Azure MSI Service + +#### Data plane +- Cognitive Services Custom Search +- Cognitive Services Entity Search +- Cognitive Services Image Search +- Cognitive Services News Search +- Cognitive Services Video Search +- Cognitive Services Web Search +- Cognitive Services Spell Check +- MongoDb for CosmosDb + + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 515f358fe1e521441aec5d63d62b5f0affcc8ea9 +- [AutoRest Go Generator](https://github.com/Azure/autorest.go) commit: c759908a0d8726eb755afd93353c58e072c345af + +## `v11.3.0-beta` + +### ARM + +- Added storage API version 2017-10-01. + +## `v11.2.2-beta` + +### Bug Fixes + - Regenerating `latest` and `preview` profiles after deleting falsely included apimanagement. + +## `v11.2.1-beta` + +### Bug Fixes + - Commenting out ignore rule that false-positived on the graphrbac package. + +## `v11.2.0-beta` + +### Repository Structure + - Adding support for Multi-API Version paradigm in `services` directory. + - Adding support for Azure Profile in `profiles` directory. + +### Storage + - Added operations for getting and setting container metadata. + - Fixed unmarshaling bug on list containers operation.' + +### Generated code notes + +- Services directory generated from [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 274c99f7bd93d8b98048e31b74a34333cecded74 +- [AutoRest Go Generator](https://github.com/Azure/autorest.go) version: 2.0.41 + +## `v11.1.1-beta` + +### ARM + +- Registers resource providers if necessary. +- Requires go-autorest v9.1.0 + +### Generated code notes + +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commits: + - All services except trafficmanager and containerregistry: 0c2a12b50d8598f68d6715b507f7dd53e163407e + - trafficmanager and containerregistry: c97a18ed775029207715b09c80761334724740b9 +- [AutoRest Go Generator](https://github.com/Azure/autorest.go) version: 2.0.36 + +### Storage + +- Fixed bug in which blob types were unmarshaed incorrectly. + +## `v11.1.0-beta` + +### ARM + +- trafficmanager and containerregistry SDKs now reflect the services faithfully +- trafficmanager also has a new operation group: user metrics. + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: c97a18ed775029207715b09c80761334724740b9 +- [AutoRest Go Generator](https://github.com/Azure/autorest.go) commit: 5d984152f2e9cff6878ea5060bed7e8d8a2ae1cc + +## `v11.0.0-beta` + +### ARM + +| api | version | note | +|:------------------------------------|:-------------------|:------------------------------------| +| arm/analysisservices | 2017-08-01-beta | update | +| arm/batch | 2017-05-01 | update | +| arm/cdn | 2017-04-02 | update | +| arm/cognitiveservices | 2017-04-18 | update | +| arm/compute | multiple | update | +| arm/containerregistry | 2017-10-01 | update | +| arm/customerinsights | 2017-04-26 | update | +| arm/eventgrid | 2017-09-15-preview | update | +| arm/eventhub | 2017-04-01 | update | +| arm/graphrbac | 1.6 | update | +| arm/iothub | 2017-07-01 | update | +| arm/keyvault | 2016-10-01 | update | +| arm/marketplaceordering | 2015-06-01 | new | +| arm/opertionalinsights | multiple | update | +| arm/operationsmanagement | 2015-11-01-preview | new | +| arm/recoveryservices | multiple | update | +| arm/recoveryservicesbackup | multiple | update | +| arm/redis | 2017-02-01 | update | +| arm/relay | 2017-04-01 | update | +| arm/resourcehealth | 017-07-01 | update | +| arm/resources/resources | 2017-05-10 | update | +| arm/servicebus | 2017-04-01 | update | +| arm/storage | 2017-06-01 | update | +| arm/streamanalytics | 2016-03-01 | update | +| arm/trafficmanager | 2017-09-01-preview | update | +| arm/visualstudio | 2014-04-01-preview | update | + +### Data plane + +| api | version | note | +|:------------------------------------|:-------------------|:------------------------------------| +| dataplane/cognitiveservices/face | 1.0 | new | +| dataplane/cognitiveservices/textanalytics | v2.0 | new | + +### Storage + +- Support for queue SAS. +- Refactored GetSASURI blob operation to be more complete. +- Added a SAS client for some operations (`container.Exists()`, and `container.ListBlobs()`) + +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 0c2a12b50d8598f68d6715b507f7dd53e163407e +- [AutoRest Go Generator](https://github.com/Azure/autorest.go) commit: 678110f012c7cde6528a1e61d125bdc7ea636b7f + +## `v10.3.1-beta` +- Added Apache notice file. + +### ARM +- Fixed package name on some `version.go` files. + +### Storage +- Fixed bug related to SAS URI generation and storage emulator support. + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: ad55af74f3f0e2b390a4306532528168ba742fef +- [AutoRest Go extension](https://github.com/Azure/autorest.go) commit: 28a531c59c82cf67bc90c87095c1d34a936461b4 + +## `v10.3.0-beta` +### ARM + +| api | version | note | +|:------------------------------------|:-------------------|:------------------------------------| +| arm/containerinstance | 2017-08-01-preview | new | +| arm/eventgrid | 2017-06-15-preview | new | + +### ASM +- Marked as in mainteinance mode. +- Added Go 1.7 build tags. + +### Storage +- Support for Go 1.7 and Go 1.6 (except table batch operation tests). + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: ad55af74f3f0e2b390a4306532528168ba742fef +- [AutoRest](https://github.com/Azure/autorest) commit: cfb296f153f948f85afab637f7212fcfdc4a8bbb + +## `v10.2.1-beta` +- Fixes polymorphic structs in `mysql` and `postgresql` packages. + +## `v10.2.0-beta` +### ARM + +| api | version | note | +|:------------------------------------|:-------------------|:------------------------------------| +| arm/cosmos-db | 2015-04-08 | new | +| arm/mysql | 2017-04-30-preview | new | +| arm/postgresql | 2017-04-30-preview | new | + +### Storage +- Bug fixes. + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 485ded7560c6309efb2f795ec6e46b7436dc6fdb +- [AutoRest](https://github.com/Azure/autorest) commit: c180952b850e677a8624655abeaded307d95cae3 + +## `v10.1.0-beta` +### ARM + +| arm/recoveryservicessiterecovery | 2016-08-10 | new | +| arm/managedapplications | 2016-09-01-preview | new | +| arm/storsimple8000series | 2017-06-01 | new | +| arm/streamanalytics | multiple | new | + +### Storage +- Bug fixes. + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: a2cdf005407b81edb161c1f7b5c49b5ce8e7f041 +- [AutoRest](https://github.com/Azure/autorest) commit: 8e9c2d3704a04913a175ab76972b7d9597c77687 + +----- +## `v10.0.0-beta` +### ARM +In addition to the tabulated changes below, each package had the following updates: +- Long running operations now run inside a goroutine and return channels for the response and the errors. +- Some functions changed from returning `autorest.Response` to return the already unmarshaled struct. +- Uses go-autorest v8.0.0. + +| api | version | note | +|:------------------------------------|:-------------------|:------------------------------------| +| arm/advisor | 2017-04-19 | new | +| arm/analysisservices | 2016-05-16 | refactor | +| arm/apimanagement | 2016-10-10 | update to latest swagger & refactor | +| arm/appinsights | 2015-05-01 | new | +| arm/automation | 2015-10-31 | new | +| arm/billing | 2017-04-24-preview | update to latest swagger & refactor | +| arm/cdn | 2016-10-02 | refactor | +| arm/commerce | 2015-06-01-preview | refactor | +| arm/compute | 2016-04-30-preview | refactor | +| arm/consumption | 2017-04-24-preview | new | +| arm/containerregistry | 2017-03-01 | update to latest swagger & refactor | +| arm/containerservice | 2017-01-31 | update to latest swagger & refactor | +| arm/customer-insights | 2017-01-01 | refactor | +| arm/datalake-analytics/account | 2016-11-01 | refactor | +| arm/datalake-store/account | 2016-11-01 | refactor | +| arm/devtestlabs | 2016-05-15 | refactor | +| arm/disk | 2016-04-30-preview | refactor | +| arm/dns | 2016-04-01 | refactor | +| arm/documentdb | 2015-04-08 | refactor | +| arm/eventhub | 2015-08-01 | refactor | +| arm/graphrbac | 1.6 | refactor | +| arm/hdinsight | 2015-03-01-preview | new | +| arm/insights | multiple | new | +| arm/intune | 2015-01-14-preview | refactor | +| arm/iothub | 2016-02-03 | refactor | +| arm/machinelearning/commitmentplans | 2016-05-01-preview | refactor | +| arm/machinelearning/webservices | 2017-01-01 | update to latest swagger & refactor | +| arm/monitor | multiple | new | +| arm/network | 2017-03-01 | update to latest swagger & refactor | +| arm/notificationhubs | 2017-04-01 | update to latest swagger & refactor | +| arm/operationalinsights | 2015-11-01-preview | update to latest swagger & refactor | +| arm/powerbiembedded | 2016-01-29 | refactor | +| arm/recoveryservices | 2016-12-01 | refactor | +| arm/recoveryservicesbackup | 2016-12-01 | new | +| arm/redis | 2016-04-01 | refactor | +| arm/relay | 2016-07-01 | new | +| arm/resourcehealth | 2015-01-01 | new | +| arm/resources/features | 2015-12-01 | refactor | +| arm/resources/links | 2016-09-01 | refactor | +| arm/resources/resources | 2016-09-01 | refactor | +| arm/resources/subscriptions | 2016-06-01 | refactor | +| arm/scheduler | 2016-03-01 | refactor | +| arm/servermanagement | 2016-07-01-preview | refactor | +| arm/servicebus | 2015-08-01 | refactor | +| arm/servicefabric | 2016-09-01 | new | +| arm/service-map | 2015-11-01-preview | refactor | +| arm/sql | multiple | update to latest swagger & refactor | +| arm/storage | 2016-12-01 | update to latest swagger & refactor | +| arm/storageimportexport | 2016-11-01 | refactor | +| arm/web | multiple | refactor | + +### Data plane +| api | version | note | +|:------------------------------------|:-------------------|:------------------------------------| +| dataplane/keyvault | 2016-10-01 | refactor | + +### Storage +Storage has returned to this repo. +It has also been refactored: +- Blobs, containers, tables, etc are now method receivers. These structs are the ones being + updated with each operation. +- When creating a client, the SDK checks if the storage account provided is valid. +- Added retry logic. It provides the flexibility for user to provide their own retry logic. +- Added operations: + - Get table + - Get entity + - Get and set queue ACL + - Table batch + - Page blob incremental copy +- All operations that previously had `extraHeaders` as parameter now recieve a struct with well + defined possible headers and other options. Some functions are easier to use. +- Storage tests now use HTTP recordings. + +### Generated code notes +- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 519980465d9c195622d466dc4601b1999a448ed5 +- [AutoRest](https://github.com/Azure/autorest) commit: ced950d64e39735b84d41876a56b54b27c227dc7 + +## `v9.0.0-beta` +### ARM +In addition to the tabulated changes below, each package had the following updates: + - API Version is now associated with individual methods, instead of the client. This was done to + support composite swaggers, which logically may contain more than one API Version. + - Version numbers are now calculated in the generator instead of at runtime. This keeps us from + adding new allocations, while removing the race-conditions that were added. + +| api | version | note | +|:------------------------------------|:-------------------|:-----------------------------------| +| arm/analysisservices | 2016-05-16 | update to latest swagger | +| arm/authorization | 2015-07-01 | refactoring | +| arm/batch | 2017-01-01 | update to latest swagger &refactor | +| arm/cdn | 2016-10-02 | update to latest swagger | +| arm/compute | 2016-04-30-preview | update to latest swagger | +| arm/dns | 2016-04-01 | update to latest swagger &refactor | +| arm/eventhub | 2015-08-01 | refactoring | +| arm/logic | 2016-06-01 | update to latest swagger &refactor | +| arm/notificationshub | 2016-03-01 | update to latest swagger &refactor | +| arm/redis | 2016-04-01 | update to latest swagger &refactor | +| arm/resources/resources | 2016-09-01 | update to latest swagger | +| arm/servicebus | 2015-08-01 | update to latest swagger | +| arm/sql | 2014-04-01 | update to latest swagger | +| arm/web | multiple | generating from composite | +| datalake-analytics/account | 2016-11-01 | update to latest swagger | +| datalake-store/filesystem | 2016-11-01 | update to latest swagger | + +### Storage +Storage has been moved to its own repository which can be found here: +https://github.com/Azure/azure-storage-go + +For backwards compatibility, a submodule has been added to this repo. However, consuming storage +via this repository is deprecated and may be deleted in future versions. + +## `v8.1.0-beta` +### ARM +| api | version | note | +|:------------------------------------|:-------------------|:-----------------------------------| +| arm/apimanagement | 2016-07-07 | new | +| arm/apideployment | 2016-07-07 | new | +| arm/billing | 2017-02-27-preview | new | +| arm/compute | 2016-04-30-preview | update to latest swagger | +| arm/containerservice | 2017-01-31 | update to latest swagger | +| arm/customer-insights | 2017-01-01 | new | +| arm/graphrbac | 1.6 | new | +| arm/networkwatcher | 2016-12-01 | new | +| arm/operationalinsights | 2015-11-01-preview | new | +| arm/service-map | 2015-11-01-preview | new | +| arm/storageimportexport | 2016-11-01 | new | + +### Data plane +| api | version | note | +|:------------------------------------|:-------------------|:-----------------------------------| +| dataplane/keyvault | 2016-10-01 | new | + +- Uses go-autorest v7.3.0 + + +## `v8.0.0-beta` +### ARM +- In addition to the tablulated changes below, all updated packages received performance + improvements to their Version() method. +- Some validation that was taking place in the runtime was erroneously blocking calls. + all packages have been updated to take that bug fix. + +| api | version | note | +|:------------------------------------|:-------------------|:-----------------------------------| +| arm/analysisservices | 2016-05-16 | update to latest swagger | +| arm/cdn | 2016-10-02 | update to latest swagger | +| arm/cognitiveservices | 2016-02-01-preview | update to latest swagger | +| arm/compute | 2016-03-30 | update to latest swagger, refactor | +| arm/containerregistry | 2016-06-27-preview | update to latest swagger | +| arm/containerservice | 2016-09-30 | update to latest swagger | +| arm/datalake-analytics | 2016-11-01 | update to latest swagger | +| arm/datalake-store | 2016-11-01 | update to latest swagger | +| arm/disk | 2016-04-30-preview | new | +| arm/documentdb | 2015-04-08 | update to latest swagger | +| arm/iothub | 2016-02-03 | update to latest swagger | +| arm/keyvault | 2015-06-01 | update to latest swagger | +| arm/logic | 2016-06-01 | update to latest swagger | +| arm/machinelearning | 2016-05-01-preview | update to latest swagger | +| arm/mobileengagement | 2014-12-01 | update to latest swagger, refactor | +| arm/redis | 2016-04-01 | update to latest swagger | +| arm/resources/locks | 2016-09-01 | refactor | +| arm/resources/policy | 2016-12-01 | previous version was deleted | +| arm/resources/resources | 2016-09-01 | update to latest swagger, refactor | +| arm/scheduler | 2016-03-01 | refactor | +| arm/search | 2015-08-19 | refactor | +| arm/web | 2015-08-01 | refactor | + +## `v7.0.0-beta` + +| api | version | note | +|:------------------------------------|:-------------------|:-----------------------------------| +| arm/analysisservices | 2016-05-16 | new | +| arm/cdn | 2016-10-02 | update to latest swagger | +| arm/commerce | 2015-06-01-preview | new | +| arm/containerservice | 2016-09-30 | update to latest swagger | +| arm/containerregistry | 2016-06-27-preview | new | +| arm/datalake-analytics/account | 2016-11-01 | update to latest swagger | +| arm/datalake-store/account | 2016-11-01 | update to latest swagger | +| arm/datalake-store/filesystem | 2016-11-01 | update to latest swagger | +| arm/documentdb | 2015-04-08 | new | +| arm/machinelearning/commitmentplans | 2016-05-01-preview | new | +| arm/recoveryservices | 2016-06-01 | new | +| arm/resources/subscriptions | 2016-06-01 | new | +| arm/search | 2015-08-19 | update to latest swagger | +| arm/sql | 2014-04-01 | previous version was deleted | + +### Storage +- Can now update messages in storage queues. +- Added support for blob snapshots and aborting blob copy operations. +- Added support for getting and setting ACLs on containers. +- Added various APIs for file and directory manipulation. + +### Support for the following swagger extensions was added to the Go generator which affected codegen. +- x-ms-client-flatten +- x-ms-paramater-location + +## `v6.0.0-beta` + +| api | version | note | +|:-------------------------------|:-------------------|:-----------------------------------| +| arm/authorization | no change | code refactoring | +| arm/batch | no change | code refactoring | +| arm/compute | no change | code refactoring | +| arm/containerservice | 2016-03-30 | return | +| arm/datalake-analytics/account | 2015-10-01-preview | new | +| arm/datalake-store/filesystem | no change | moved to datalake-store/filesystem | +| arm/eventhub | no change | code refactoring | +| arm/intune | no change | code refactoring | +| arm/iothub | no change | code refactoring | +| arm/keyvault | no change | code refactoring | +| arm/mediaservices | no change | code refactoring | +| arm/network | no change | code refactoring | +| arm/notificationhubs | no change | code refactoring | +| arm/redis | no change | code refactoring | +| arm/resources/resources | no change | code refactoring | +| arm/resources/links | 2016-09-01 | new | +| arm/resources/locks | 2016-09-01 | updated | +| arm/resources/policy | no change | code refactoring | +| arm/resources/resources | 2016-09-01 | updated | +| arm/servermanagement | 2016-07-01-preview | updated | +| arm/web | no change | code refactoring | + +- storage: Added blob lease functionality and tests + +## `v5.0.0-beta` + +| api | version | note | +|:------------------------------|:--------------------|:-----------------| +| arm/network | 2016-09-01 | updated | +| arm/servermanagement | 2015-07-01-preview | new | +| arm/eventhub | 2015-08-01 | new | +| arm/containerservice | -- | removed | +| arm/resources/subscriptions | no change | code refactoring | +| arm/resources/features | no change | code refactoring | +| arm/resources/resources | no change | code refactoring | +| arm/datalake-store/accounts | no change | code refactoring | +| arm/datalake-store/filesystem | no change | code refactoring | +| arm/notificationhubs | no change | code refactoring | +| arm/redis | no change | code refactoring | + +- storage: Add more file storage share operations. +- azure-rest-api-specs/commit/b8cdc2c50a0872fc0039f20c2b6b33aa0c2af4bf +- Uses go-autorest v7.2.1 + +## `v4.0.0-beta` + +- arm/logic: breaking change in package logic. +- arm: parameter validation code added in all arm packages. +- Uses go-autorest v7.2.0. + + +## `v3.2.0-beta` + +| api | version | note | +|:----------------------------|:--------------------|:----------| +| arm/mediaservices | 2015-10-01 | new | +| arm/keyvault | 2015-06-01 | new | +| arm/iothub | 2016-02-03 | new | +| arm/datalake-store | 2015-12-01 | new | +| arm/network | 2016-06-01 | updated | +| arm/resources/resources | 2016-07-01 | updated | +| arm/resources/policy | 2016-04-01 | updated | +| arm/servicebus | 2015-08-01 | updated | + +- arm: uses go-autorest version v7.1.0. +- storage: fix for operating on blobs names containing special characters. +- storage: add SetBlobProperties(), update BlobProperties response fields. +- storage: make storage client work correctly with read-only secondary account. +- storage: add Azure Storage Emulator support. + + +## `v3.1.0-beta` + +- Added a new arm/compute/containerservice (2016-03-30) package +- Reintroduced NewxxClientWithBaseURI method. +- Uses go-autorest version - v7.0.7. + + +## `v3.0.0-beta` + +This release brings the Go SDK ARM packages up-to-date with Azure ARM Swagger files for most +services. Since the underlying [Swagger files](https://github.com/Azure/azure-rest-api-specs) +continue to change substantially, the ARM packages are still in *beta* status. + +The ARM packages now align with the following API versions (*highlighted* packages are new or +updated in this release): + +| api | version | note | +|:----------------------------|:--------------------|:----------| +| arm/authorization | 2015-07-01 | no change | +| arm/intune | 2015-01-14-preview | no change | +| arm/notificationhubs | 2014-09-01 | no change | +| arm/resources/features | 2015-12-01 | no change | +| arm/resources/subscriptions | 2015-11-01 | no change | +| arm/web | 2015-08-01 | no change | +| arm/cdn | 2016-04-02 | updated | +| arm/compute | 2016-03-30 | updated | +| arm/dns | 2016-04-01 | updated | +| arm/logic | 2015-08-01-preview | updated | +| arm/network | 2016-03-30 | updated | +| arm/redis | 2016-04-01 | updated | +| arm/resources/resources | 2016-02-01 | updated | +| arm/resources/policy | 2015-10-01-preview | updated | +| arm/resources/locks | 2015-01-01 | updated (resources/authorization earlier)| +| arm/scheduler | 2016-03-01 | updated | +| arm/storage | 2016-01-01 | updated | +| arm/search | 2015-02-28 | updated | +| arm/batch | 2015-12-01 | new | +| arm/cognitiveservices | 2016-02-01-preview | new | +| arm/devtestlabs | 2016-05-15 | new | +| arm/machinelearning | 2016-05-01-preview | new | +| arm/powerbiembedded | 2016-01-29 | new | +| arm/mobileengagement | 2014-12-01 | new | +| arm/servicebus | 2014-09-01 | new | +| arm/sql | 2015-05-01 | new | +| arm/trafficmanager | 2015-11-01 | new | + + +Below are some design changes. +- Removed Api version from method arguments. +- Removed New...ClientWithBaseURI() method in all clients. BaseURI value is set in client.go. +- Uses go-autorest version v7.0.6. + + +## `v2.2.0-beta` + +- Uses go-autorest version v7.0.5. +- Update version of pacakges "jwt-go" and "crypto" in glide.lock. + + +## `v2.1.1-beta` + +- arm: Better error messages for long running operation failures (Uses go-autorest version v7.0.4). + + +## `v2.1.0-beta` + +- arm: Uses go-autorest v7.0.3 (polling related updates). +- arm: Cancel channel argument added in long-running calls. +- storage: Allow caller to provide headers for DeleteBlob methods. +- storage: Enables connection sharing with http keepalive. +- storage: Add BlobPrefixes and Delimiter to BlobListResponse + + +## `v2.0.0-beta` + +- Uses go-autorest v6.0.0 (Polling and Asynchronous requests related changes). + + +## `v0.5.0-beta` + +Updated following packages to new API versions: +- arm/resources/features 2015-12-01 +- arm/resources/resources 2015-11-01 +- arm/resources/subscriptions 2015-11-01 + + +### Changes + + - SDK now uses go-autorest v3.0.0. + + + +## `v0.4.0-beta` + +This release brings the Go SDK ARM packages up-to-date with Azure ARM Swagger files for most +services. Since the underlying [Swagger files](https://github.com/Azure/azure-rest-api-specs) +continue to change substantially, the ARM packages are still in *beta* status. + +The ARM packages now align with the following API versions (*highlighted* packages are new or +updated in this release): + +- *arm/authorization 2015-07-01* +- *arm/cdn 2015-06-01* +- arm/compute 2015-06-15 +- arm/dns 2015-05-04-preview +- *arm/intune 2015-01-14-preview* +- arm/logic 2015-02-01-preview +- *arm/network 2015-06-15* +- *arm/notificationhubs 2014-09-01* +- arm/redis 2015-08-01 +- *arm/resources/authorization 2015-01-01* +- *arm/resources/features 2014-08-01-preview* +- *arm/resources/resources 2014-04-01-preview* +- *arm/resources/subscriptions 2014-04-01-preview* +- *arm/scheduler 2016-01-01* +- arm/storage 2015-06-15 +- arm/web 2015-08-01 + +### Changes + +- Moved the arm/authorization, arm/features, arm/resources, and arm/subscriptions packages under a new, resources, package (to reflect the corresponding Swagger structure) +- Added a new arm/authoriation (2015-07-01) package +- Added a new arm/cdn (2015-06-01) package +- Added a new arm/intune (2015-01-14-preview) package +- Udated arm/network (2015-06-01) +- Added a new arm/notificationhubs (2014-09-01) package +- Updated arm/scheduler (2016-01-01) package + + +----- + +## `v0.3.0-beta` + +- Corrected unintentional struct field renaming and client renaming in v0.2.0-beta + +----- + +## `v0.2.0-beta` + +- Added support for DNS, Redis, and Web site services +- Updated Storage service to API version 2015-06-15 +- Updated Network to include routing table support +- Address https://github.com/Azure/azure-sdk-for-go/issues/232 +- Address https://github.com/Azure/azure-sdk-for-go/issues/231 +- Address https://github.com/Azure/azure-sdk-for-go/issues/230 +- Address https://github.com/Azure/azure-sdk-for-go/issues/224 +- Address https://github.com/Azure/azure-sdk-for-go/issues/184 +- Address https://github.com/Azure/azure-sdk-for-go/issues/183 + +------ + +## `v0.1.1-beta` + +- Improves the UserAgent string to disambiguate arm packages from others in the SDK +- Improves setting the http.Response into generated results (reduces likelihood of a nil reference) +- Adds gofmt, golint, and govet to Travis CI for the arm packages + +##### Fixed Issues + +- https://github.com/Azure/azure-sdk-for-go/issues/196 +- https://github.com/Azure/azure-sdk-for-go/issues/213 + +------ + +## v0.1.0-beta + +This release addresses the issues raised against the alpha release and adds more features. Most +notably, to address the challenges of encoding JSON +(see the [comments](https://github.com/Azure/go-autorest#handling-empty-values) in the +[go-autorest](https://github.com/Azure/go-autorest) package) by using pointers for *all* structure +fields (with the exception of enumerations). The +[go-autorest/autorest/to](https://github.com/Azure/go-autorest/tree/master/autorest/to) package +provides helpers to convert to / from pointers. The examples demonstrate their usage. + +Additionally, the packages now align with Go coding standards and pass both `golint` and `govet`. +Accomplishing this required renaming various fields and parameters (such as changing Url to URL). + +##### Changes + +- Changed request / response structures to use pointer fields. +- Changed methods to return `error` instead of `autorest.Error`. +- Re-divided methods to ease asynchronous requests. +- Added paged results support. +- Added a UserAgent string. +- Added changes necessary to pass golint and govet. +- Updated README.md with details on asynchronous requests and paging. +- Saved package dependencies through Godep (for the entire SDK). + +##### Fixed Issues: + +- https://github.com/Azure/azure-sdk-for-go/issues/205 +- https://github.com/Azure/azure-sdk-for-go/issues/206 +- https://github.com/Azure/azure-sdk-for-go/issues/211 +- https://github.com/Azure/azure-sdk-for-go/issues/212 + +----- + +## v0.1.0-alpha + +This release introduces the Azure Resource Manager packages generated from the corresponding +[Swagger API](http://swagger.io) [definitions](https://github.com/Azure/azure-rest-api-specs). \ No newline at end of file diff --git a/vendor/github.com/Azure/azure-sdk-for-go/CONTRIBUTING.md b/vendor/github.com/Azure/azure-sdk-for-go/CONTRIBUTING.md new file mode 100644 index 000000000..f702746e1 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/CONTRIBUTING.md @@ -0,0 +1,16 @@ +# Contributing + +While in preview we maintain only a `master` branch for releases and `dev` branch for development. + +After release we will maintain a branch for each major version to backport important fixes. + +Please submit pull requests to `dev` to update the latest version or to a version branch for backports. + +Also see these [guidelines][] about contributing to Azure projects. + +This project follows the [Microsoft Open Source Code of Conduct][CoC]. For more information see the [Code of Conduct FAQ][CoCfaq]. Contact [opencode@microsoft.com][CoCmail] with questions and comments. + +[guidelines]: http://azure.github.io/guidelines/ +[CoC]: https://opensource.microsoft.com/codeofconduct/ +[CoCfaq]: https://opensource.microsoft.com/codeofconduct/faq/ +[CoCmail]: mailto:opencode@microsoft.com diff --git a/vendor/github.com/Azure/azure-sdk-for-go/Gopkg.lock b/vendor/github.com/Azure/azure-sdk-for-go/Gopkg.lock new file mode 100644 index 000000000..0bc046387 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/Gopkg.lock @@ -0,0 +1,86 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/Azure/go-autorest" + packages = ["autorest","autorest/adal","autorest/azure","autorest/date","autorest/to","autorest/validation"] + revision = "d4e6b95c12a08b4de2d48b45d5b4d594e5d32fab" + version = "v9.9.0" + +[[projects]] + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29" + version = "v3.1.0" + +[[projects]] + branch = "master" + name = "github.com/dnaeon/go-vcr" + packages = ["cassette","recorder"] + revision = "87d4990451a858cc210399285be976e63bc3c364" + +[[projects]] + name = "github.com/marstr/collection" + packages = ["."] + revision = "871b1cfa2ab97d3d8f54a034280907896190c346" + version = "v0.3.3" + +[[projects]] + branch = "master" + name = "github.com/marstr/goalias" + packages = ["model"] + revision = "3026ca7e18e829805b990b41e4ce28c92cb80caa" + +[[projects]] + name = "github.com/marstr/guid" + packages = ["."] + revision = "8bdf7d1a087ccc975cf37dd6507da50698fd19ca" + +[[projects]] + branch = "master" + name = "github.com/marstr/randname" + packages = ["."] + revision = "3ef1f47af99e66171417047e6f6fa334345e95e7" + +[[projects]] + name = "github.com/satori/go.uuid" + packages = ["."] + revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" + version = "v1.2.0" + +[[projects]] + branch = "master" + name = "github.com/shopspring/decimal" + packages = ["."] + revision = "e3482495ff4cba75613e4177ed79825c890058a9" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = ["pkcs12","pkcs12/internal/rc2"] + revision = "1875d0a70c90e57f11972aefd42276df65e895b9" + +[[projects]] + branch = "v1" + name = "gopkg.in/check.v1" + packages = ["."] + revision = "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec" + +[[projects]] + branch = "v2" + name = "gopkg.in/mgo.v2" + packages = [".","bson","internal/json","internal/sasl","internal/scram"] + revision = "3f83fa5005286a7fe593b055f0d7771a7dce4655" + +[[projects]] + branch = "v2" + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "25b644f9483e9a97a5bc10479513a83eb0d865915323f8c7cfc06caa15c947bb" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/Azure/azure-sdk-for-go/Gopkg.toml b/vendor/github.com/Azure/azure-sdk-for-go/Gopkg.toml new file mode 100644 index 000000000..4d84c44cf --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/Gopkg.toml @@ -0,0 +1,66 @@ + +# 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" + + +[[constraint]] + name = "github.com/Azure/go-autorest" + version = "9.9.0" + +[[constraint]] + branch = "master" + name = "github.com/dnaeon/go-vcr" + +[[constraint]] + name = "github.com/marstr/collection" + version = "0.3.3" + +[[constraint]] + branch = "master" + name = "github.com/marstr/goalias" + +[[constraint]] + revision = "8bdf7d1a087ccc975cf37dd6507da50698fd19ca" + name = "github.com/marstr/guid" + +[[constraint]] + branch = "master" + name = "github.com/marstr/randname" + +[[constraint]] + name = "github.com/satori/go.uuid" + version = "1.1.0" + +[[constraint]] + branch = "master" + name = "github.com/shopspring/decimal" + +[[constraint]] + branch = "master" + name = "golang.org/x/crypto" + +[[constraint]] + branch = "v1" + name = "gopkg.in/check.v1" + +[[constraint]] + branch = "v2" + name = "gopkg.in/mgo.v2" diff --git a/vendor/github.com/Azure/azure-sdk-for-go/README.md b/vendor/github.com/Azure/azure-sdk-for-go/README.md new file mode 100644 index 000000000..de8b38492 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/README.md @@ -0,0 +1,200 @@ +# Azure SDK for Go + +[![godoc](https://godoc.org/github.com/Azure/azure-sdk-for-go?status.svg)](https://godoc.org/github.com/Azure/azure-sdk-for-go) +[![Build Status](https://travis-ci.org/Azure/azure-sdk-for-go.svg?branch=master)](https://travis-ci.org/Azure/azure-sdk-for-go) +[![Go Report Card](https://goreportcard.com/badge/github.com/Azure/azure-sdk-for-go)](https://goreportcard.com/report/github.com/Azure/azure-sdk-for-go) + +azure-sdk-for-go provides Go packages for using Azure services. It has been +tested with Go 1.8 and 1.9. To be notified about updates and changes, subscribe +to the [Azure update feed][]. + +:exclamation: **NOTE:** This project is in preview and breaking changes are +introduced frequently. Therefore, vendoring dependencies is even more +important than usual. We use [dep](https://github.com/golang/dep). + +### Install: + +```sh +$ go get -u github.com/Azure/azure-sdk-for-go/... +``` + +or if you use dep (recommended), within your project run: + +```sh +$ dep ensure -add github.com/Azure/azure-sdk-for-go +``` + +If you need to install Go, follow [the official instructions][]. + +[the official instructions]: https://golang.org/dl/ + +### Use: + +For complete examples see [Azure-Samples/azure-sdk-for-go-samples][samples_repo]. + +1. Import a package from the [services][services_dir] directory. +1. Create and authenticate a client with a `New*Client` func, e.g. + `c := compute.NewVirtualMachinesClient(...)`. +1. Invoke API methods using the client, e.g. `c.CreateOrUpdate(...)`. +1. Handle responses. + +For example, to create a new virtual network (substitute your own values for +strings in angle brackets): + +```go +import ( + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" +) + +vnetClient := network.NewVirtualNetworksClient("") +vnetClient.Authorizer = autorest.NewBearerAuthorizer("") + +vnetClient.CreateOrUpdate( + "", + "", + network.VirtualNetwork{ + Location: to.StringPtr(""), + VirtualNetworkPropertiesFormat: &network.VirtualNetworkPropertiesFormat{ + AddressSpace: &network.AddressSpace{ + AddressPrefixes: &[]string{"10.0.0.0/8"}, + }, + Subnets: &[]network.Subnet{ + { + Name: to.StringPtr(""), + SubnetPropertiesFormat: &network.SubnetPropertiesFormat{ + AddressPrefix: to.StringPtr("10.0.0.0/16"), + }, + }, + { + Name: to.StringPtr(""), + SubnetPropertiesFormat: &network.SubnetPropertiesFormat{ + AddressPrefix: to.StringPtr("10.1.0.0/16"), + }, + }, + }, + }, + }, + nil) +``` + +## Authentication + +Most operations require an OAuth token for authentication and authorization. +You can get one from Azure AD using the +[adal](https://github.com/Azure/go-autorest/tree/master/autorest/adal) +package and a service principal as shown in the following example. + +If you need to create a service principal (aka Client, App), run +`az ad sp create-for-rbac -n ""` +in the [azure-cli](https://github.com/Azure/azure-cli), see these +[docs](https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest) +for more info. + +Copy the new principal's ID, secret, and tenant ID for use in your app, e.g. as follows: + +```go +import ( + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/azure" +) + +var ( + clientID = "" + subscriptionID = "" + tenantID = "" + clientSecret = "" +) + +func getServicePrincipalToken() (adal.OAuthTokenProvider, error) { + config, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, tenantID) + return adal.NewServicePrincipalToken( + *oauthConfig, + clientID, + clientSecret, + azure.PublicCloud.ResourceManagerEndpoint) +} +``` + +## Background + +Most packages in the SDK are generated from [Azure API specs][] with +[Azure/autorest][] and [Azure/autorest.go][]. + +[Azure API Specs]: https://github.com/Azure/azure-rest-api-specs +[Azure/autorest]: https://github.com/Azure/autorest +[Azure/autorest.go]: https://github.com/Azure/autorest.go + +A list of available services and package import paths is in [SERVICES.md][]. + +## Versioning + +*More info in [the wiki](https://github.com/Azure/azure-sdk-for-go/wiki/Versioning)* + +You'll need to consider both SDK and API versions when selecting your +targets. The following will describe them one by one. + +**SDK versions** are set with repository-wide [tags][]. We try to adhere to +[semver][], so although we've long moved past version zero, we continue to +add `-beta` to versions because **this package is still in preview.** + +[tags]: https://github.com/Azure/azure-sdk-for-go/tags +[semver]: https://semver.org + +Azure **API versions** are typically a date string of form +`yyyy-mm-dd[-preview|-beta]`. Whatever SDK version you use, you must also +specify an API version in your import path, for example: + +```go +import "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2016-03-01/compute" +import "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network" +``` + +For a list of all available services and versions see [godoc][services_godoc] +or start with `find ./services -type d -mindepth 3` within this repo. + +Azure **API profiles** specify a subset of APIs and versions offered in +specific Azure regions and Azure Stack. The 2017-03-09 profile is intended for +use with Azure Stack and includes compatible Compute, Network, Storage and +Group management APIs. You can use it as follows: + +```go +import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/compute/mgmt/compute" +import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/network/mgmt/network" +import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/..." +import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage" +``` + +We also provide two special profiles: `latest` and `preview`. These will always +refer to the most recent stable or preview API versions for each service. For +example, to automatically use the most recent Compute APIs, use one of the following +imports: + +```go +import "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute" +import "github.com/Azure/azure-sdk-for-go/profiles/preview/compute/mgmt/compute" +``` + +## Resources + +- SDK docs are at [godoc.org](https://godoc.org/github.com/Azure/azure-sdk-for-go/). +- SDK samples are at [Azure-Samples/azure-sdk-for-go-samples](https://github.com/Azure-Samples/azure-sdk-for-go-samples). +- SDK notifications are published via the [Azure update feed][]. +- Azure API docs are at [docs.microsoft.com/rest/api](https://docs.microsoft.com/rest/api/). +- General Azure docs are at [docs.microsoft.com/azure](https://docs.microsoft.com/azure). + +## License + +Apache 2.0, see [LICENSE][]. + +## Contribute + +See [CONTRIBUTING.md][]. + +[services_dir]: https://github.com/Azure/azure-sdk-for-go/tree/master/services +[samples_repo]: https://github.com/Azure-Samples/azure-sdk-for-go-samples +[Azure update feed]: https://azure.microsoft.com/updates/ +[LICENSE]: ./LICENSE +[CONTRIBUTING.md]: ./CONTRIBUTING.md +[services_godoc]: https://godoc.org/github.com/Azure/azure-sdk-for-go/services diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/README.md b/vendor/github.com/Azure/azure-sdk-for-go/arm/README.md new file mode 100644 index 000000000..54feec999 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/arm/README.md @@ -0,0 +1,341 @@ +# Introducing the Azure Resource Manager packages for Go + +The `github.com/Azure/azure-sdk-for-go/arm` packages are used to perform operations using the Azure Resource Manager (ARM). Read more about [Azure Resource Manager vs. classic deployment](https://azure.microsoft.com/documentation/articles/resource-manager-deployment-model/). Packages for Azure Service Manager or classic deployment are in the [management](https://github.com/Azure/azure-sdk-for-go/tree/master/management) folder. + + +## How Did We Get Here? + +Azure is growing rapidly, regularly adding new services and features. While rapid growth +is good for users, it is hard on SDKs. Each new service and each new feature requires someone to +learn the details and add the needed code to the SDK. As a result, the +[Azure SDK for Go](https://github.com/Azure/azure-sdk-for-go) +has lagged behind Azure. It is missing +entire services and has not kept current with features. There is simply too much change to maintain +a hand-written SDK. + +For this reason, the +[Azure SDK for Go](https://github.com/Azure/azure-sdk-for-go), +with the release of the Azure Resource Manager (ARM) +packages, is transitioning to a generated-code model. Other Azure SDKs, notably the +[Azure SDK for .NET](https://github.com/Azure/azure-sdk-for-net), have successfully adopted a +generated-code strategy. Recently, Microsoft published the +[AutoRest](https://github.com/Azure/autorest) tool used to create these SDKs and we have been adding support for Go. The ARM packages are +the first set generated using this new toolchain. The input for AutoRest are the [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs), files in Swagger JSON format. + +There are a couple of items to note. First, since both the tooling and the underlying support +packages are new, the code is not yet "production ready". Treat these packages as of +***beta*** quality. +That's not to say we don't believe in the code, but we want to see what others think and how well +they work in a variety of environments before settling down into an official, first release. If you +find problems or have suggestions, please submit a pull request to document what you find. However, +since the code is generated, we'll use your pull request to guide changes we make to the underlying +generator versus merging the pull request itself. + +The second item of note is that, to keep the generated code clean and reliable, it depends on +another new package [go-autorest](https://github.com/Azure/go-autorest). +Though part of the SDK, we separated the code to better control versioning and maintain agility. +Since +[go-autorest](https://github.com/Azure/go-autorest) +is hand-crafted, we will take pull requests in the same manner as for our other repositories. + +We intend to rapidly improve these packages until they are "production ready". +So, try them out and give us your thoughts. + +## What Have We Done? + +Creating new frameworks is hard and often leads to "cliffs": The code is easy to use until some +special case or tweak arises and then, well, then you're stuck. Often times small differences in +requirements can lead to forking the code and investing a lot of time. Cliffs occur even more +frequently in generated code. We wanted to avoid them and believe the new model does. Our initial +goals were: + +* Easy-to-use out of the box. It should be "clone and go" for straight-forward use. +* Easy composition to handle the majority of complex cases. +* Easy to integrate with existing frameworks, fit nicely with channels, supporting fan-out / +fan-in set ups. + +These are best shown in a series of examples, all of which are included in the +[examples](/arm/examples) sub-folder. + +## How is the SDK tested? + +Testing the SDK is currently a work in progress. It includes three different points: + +* Test the [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) against the APIs themselves. This way we can find if the specs are reflecting correctly the API behavior. All Azure SDKs can benefit from this tests. +* Add [acceptance tests](https://github.com/Azure/autorest/blob/master/docs/developer/guide/writing-tests.md) to AutoRest. +* Test the generated SDK with code samples. This would catch bugs that escaped the previous tests, and provide some documentation. + + +## First a Sidenote: Authentication and the Azure Resource Manager + +Before using the Azure Resource Manager packages, you need to understand how it authenticates and +authorizes requests. +Azure Resource Manager requests can be authorized through [OAuth2](http://oauth.net). While OAuth2 provides many advantages over +certificates, programmatic use, such as for scripts on headless servers, requires understanding and +creating one or more *Service Principals.* + +The Azure-SDK-for-Node has an excellent tutorial that includes instructions for how to create Service Principals in the Portal and using the Azure CLI, both of which are applicable to Go. +Find that documentation here: [Authenticaion, Azure/azure-sdk-for-node](https://github.com/Azure/azure-sdk-for-node/blob/master/Documentation/Authentication.md) + +In addition, there are several good blog posts, such as +[Automating Azure on your CI server using a Service Principal](http://blog.davidebbo.com/2014/12/azure-service-principal.html) +and +[Microsoft Azure REST API + OAuth 2.0](https://ahmetalpbalkan.com/blog/azure-rest-api-with-oauth2/), +that describe what this means. +For details on creating and authorizing Service Principals, see the MSDN articles +[Azure API Management REST API Authentication](https://msdn.microsoft.com/library/azure/5b13010a-d202-4af5-aabf-7ebc26800b3d) +and +[Create a new Azure Service Principal using the Azure portal](https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/). +Dushyant Gill, a Senior Program Manager for Azure Active Directory, has written an extensive blog +post, +[Developer's Guide to Auth with Azure Resource Manager API](http://www.dushyantgill.com/blog/2015/05/23/developers-guide-to-auth-with-azure-resource-manager-api/), +that is also quite helpful. + +### Use an authentication file + +This SDK also supports authentication with a JSON file containing credentials for the service principal. In the Azure CLI, you can create a service principal and its authentication file with this command: + +``` bash +az ad sp create-for-rbac --sdk-auth > mycredentials.json +``` + +Save this file in a secure location on your system where your code can read it. Set an environment variable with the full path to the file: + +``` bash +export AZURE_AUTH_LOCATION=/secure/location/mycredentials.json +``` + +``` powershell +$env:AZURE_AUTH_LOCATION= "/secure/location/mycredentials.json" +``` + +The file looks like this, in case you want to create it yourself: + +``` json +{ + "clientId": "", + "clientSecret": "your service principal client secret", + "subscriptionId": "", + "tenantId": "", + "activeDirectoryEndpointUrl": "https://login.microsoftonline.com", + "resourceManagerEndpointUrl": "https://management.azure.com/", + "activeDirectoryGraphResourceId": "https://graph.windows.net/", + "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/", + "galleryEndpointUrl": "https://gallery.azure.com/", + "managementEndpointUrl": "https://management.core.windows.net/" +} +``` + +Clients can be created later like this: + +``` go +package main + +import ( + "github.com/Azure/go-autorest/autorest/azure/auth" + "github.com/Azure/azure-sdk-for-go/arm/storage" +) + +func main() { + authentication, err := auth.GetClientSetup(storage.DefaultBaseURI) + if err != nil { + panic(err) + } + client := storage.NewAccountsClientWithBaseURI(authentication.BaseURI, authentication.SubscriptionID) + client.Authorizer = authentication +} + +``` + +### Complete source code + +Get code for a full example of [authenticating to Azure via certificate or device authorization](https://github.com/Azure/go-autorest/tree/master/autorest/azure/example). + +## A Simple Example: Checking availability of name within Azure Storage + +Each ARM provider, such as +[Azure Storage](http://azure.microsoft.com/documentation/services/storage/) +or +[Azure Compute](https://azure.microsoft.com/documentation/services/virtual-machines/), +has its own package. Start by importing +the packages for the providers you need. Next, most packages divide their APIs across multiple +clients to avoid name collision and improve usability. For example, the +[Azure Storage](http://azure.microsoft.com/documentation/services/storage/) +package has +two clients: +[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient) +and +[storage.UsageOperationsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#UsageOperationsClient). +To check if a name is available, use the +[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient). + +Each ARM client composes with [autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client). +[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client) +enables altering the behavior of the API calls by leveraging the decorator pattern of +[go-autorest](https://github.com/Azure/go-autorest). For example, in the code above, the +[azure.ServicePrincipalToken](https://godoc.org/github.com/Azure/go-autorest/autorest/azure#ServicePrincipalToken) +includes a +[WithAuthorization](https://godoc.org/github.com/Azure/go-autorest/autorest#Client.WithAuthorization) +[autorest.PrepareDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#PrepareDecorator) +that applies the OAuth2 authorization token to the request. It will, as needed, refresh the token +using the supplied credentials. + +Providing a decorated +[autorest.Sender](https://godoc.org/github.com/Azure/go-autorest/autorest#Sender) or populating +the [autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client) +with a custom +[autorest.PrepareDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#PrepareDecorator) +or +[autorest.RespondDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#RespondDecorator) +enables more control. See the included example file +[check.go](/arm/examples/check/check.go) +for more details. Through these you can modify the outgoing request, inspect the incoming response, +or even go so far as to provide a +[circuit breaker](https://msdn.microsoft.com/library/dn589784.aspx) +to protect your service from unexpected latencies. + +Lastly, all Azure ARM API calls return an instance of +[autorest.DetailedError](https://godoc.org/github.com/Azure/go-autorest/autorest#DetailedError). +Not only DetailedError gives anonymous access to the original +[error](http://golang.org/ref/spec#Errors), +but provides the package type (e.g., +[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient)), +the failing method (e.g., +[CheckNameAvailability](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient.CheckNameAvailability)), +and a detailed error message. + +### Complete source code + +Complete source code for this example can be found in [check.go](/arm/examples/check/check.go). + +1. Create a [service principal](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/). You will need the Tenant ID, Client ID and Client Secret for [authentication](#first-a-sidenote-authentication-and-the-azure-resource-manager), so keep them as soon as you get them. +2. Get your Azure Subscription ID using either of the methods mentioned below: + - Get it through the [portal](portal.azure.com) in the subscriptions section. + - Get it using the [Azure CLI](https://azure.microsoft.com/documentation/articles/xplat-cli-install/) with command `azure account show`. + - Get it using [Azure Powershell](https://azure.microsoft.com/documentation/articles/powershell-install-configure/) with cmdlet `Get-AzureRmSubscription`. +3. Set environment variables `AZURE_TENANT_ID = `, `AZURE_CLIENT_ID = `, `AZURE_CLIENT_SECRET = ` and `AZURE_SUBSCRIPTION_ID = `. +4. Run the sample with commands: + +``` +$ cd arm/examples/check +$ go run check.go +``` + +## Something a Bit More Complex: Creating a new Azure Storage account + +Redundancy, both local and across regions, and service load affect service responsiveness. Some +API calls will return before having completed the request. An Azure ARM API call indicates the +request is incomplete (versus the request failed for some reason) by returning HTTP status code +'202 Accepted.' The +[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client) +composed into +all of the Azure ARM clients, provides support for basic request polling. The default is to +poll until a specified duration has passed (with polling frequency determined by the +HTTP [Retry-After](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37) +header in the response). By changing the +[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client) +settings, you can poll for a fixed number of attempts or elect to not poll at all. + +Whether you elect to poll or not, all Azure ARM client responses compose with an instance of +[autorest.Response](https://godoc.org/github.com/Azure/go-autorest/autorest#Response). +At present, +[autorest.Response](https://godoc.org/github.com/Azure/go-autorest/autorest#Response) +only composes over the standard +[http.Response](https://golang.org/pkg/net/http/#Response) +object (that may change as we implement more features). When your code receives an error from an +Azure ARM API call, you may find it useful to inspect the HTTP status code contained in the returned +[autorest.Response](https://godoc.org/github.com/Azure/go-autorest/autorest#Response). +If, for example, it is an HTTP 202, then you can use the +[GetPollingLocation](https://godoc.org/github.com/Azure/go-autorest/autorest#Response.GetPollingLocation) +response method to extract the URL at which to continue polling. Similarly, the +[GetPollingDelay](https://godoc.org/github.com/Azure/go-autorest/autorest#Response.GetPollingDelay) +response method returns, as a +[time.Duration](http://golang.org/pkg/time/#Duration), +the service suggested minimum polling delay. + +Creating a new Azure storage account is a straight-forward way to see these concepts. + +[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client) +portion of the +[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient) +to poll for a fixed number of attempts versus polling for a set duration (which is the default). +If an error occurs creating the storage account, the code inspects the HTTP status code and +prints the URL the +[Azure Storage](http://azure.microsoft.com/documentation/services/storage/) +service returned for polling. + +### Complete source for the example +More details, including deleting the created account, are in the example code file [create.go](/arm/examples/create/create.go) + +1. Create a [service principal](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/). You will need the Tenant ID, Client ID and Client Secret for [authentication](#first-a-sidenote-authentication-and-the-azure-resource-manager), so keep them as soon as you get them. +2. Get your Azure Subscription ID using either of the methods mentioned below: + - Get it through the [portal](portal.azure.com) in the subscriptions section. + - Get it using the [Azure CLI](https://azure.microsoft.com/documentation/articles/xplat-cli-install/) with command `azure account show`. + - Get it using [Azure Powershell](https://azure.microsoft.com/documentation/articles/powershell-install-configure/) with cmdlet `Get-AzureRmSubscription`. +3. Set environment variables `AZURE_TENANT_ID = `, `AZURE_CLIENT_ID = `, `AZURE_CLIENT_SECRET = ` and `AZURE_SUBSCRIPTION_ID = `. +4. Create a resource group and add its name in the first line of the main function. +5. Run the example with commands: + +``` +$ cd arm/examples/create +$ go run create.go +``` + + +## Making Asynchronous Requests + +One of Go's many strong points is how natural it makes sending and managing asynchronous requests +by means of goroutines. We wanted the ARM packages to fit naturally in the variety of asynchronous +patterns used in Go code, but also be straight-forward for simple use cases. We accomplished both +by adopting a pattern for all APIs. Each package API includes (at least) four methods +(more if the API returns a paged result set). For example, for an API call named `Foo` the package +defines: + +- `FooPreparer`: This method accepts the arguments for the API and returns a prepared +`http.Request`. +- `FooSender`: This method sends the prepared `http.Request`. It handles the possible status codes +and will, unless the disabled in the [autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client), handling polling. +- `FooResponder`: This method accepts and handles the `http.Response` returned by the sender +and unmarshals the JSON, if any, into the result. +- `Foo`: This method accepts the arguments for the API and returns the result. It is a wrapper +around the `FooPreparer`, `FooSender`, and `FooResponder`. + +By using the preparer, sender, and responder methods, package users can spread request and +response handling across goroutines as needed. Further, adding a cancel channel to the +`http.Response` (most easily through a +[PrepareDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#PrepareDecorator)), +enables canceling sent requests (see the documentation on +[http.Request](https://golang.org/pkg/net/http/#Request)) for details. + +## Paged Result Sets + +Some API calls return partial results. Typically, when they do, the result structure will include +a `Value` array and a `NextLink` URL. The `NextLink` URL is used to retrieve the next page or +block of results. + +The packages add two methods to make working with and retrieving paged results natural. First, +on paged result structures, the packages include a preparer method that returns an `http.Request` +for the next set of results. For a result set returned in a structure named `FooResults`, the +package will include a method named `FooResultsPreparer`. If the `NextLink` is `nil` or empty, the +method returns `nil`. + +The corresponding API (which typically includes "List" in the name) has a method to ease retrieving +the next result set given a result set. For example, for an API named `FooList`, the package will +include `FooListNextResults` that accepts the results of the last call and returns the next set. + +## Summing Up + +The new Azure Resource Manager packages for the Azure SDK for Go are a big step toward keeping the +SDK current with Azure's rapid growth. +As mentioned, we intend to rapidly stabilize these packages for production use. +We'll also add more examples, including some highlighting the +[Azure Resource Manager Templates](https://msdn.microsoft.com/library/azure/dn790568.aspx) +and the other providers. + +So, give the packages a try, explore the various ARM providers, and let us know what you think. + +We look forward to hearing from you! + +## License + +See the Azure SDK for Go LICENSE file. diff --git a/vendor/github.com/Azure/azure-sdk-for-go/rungas.sh b/vendor/github.com/Azure/azure-sdk-for-go/rungas.sh new file mode 100644 index 000000000..92e3d4df8 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/rungas.sh @@ -0,0 +1,15 @@ +#!/bin/bash +GITBRANCH=`git rev-parse --abbrev-ref HEAD` +#We intend to only run gas on release branches. +if [ "master" != $GITBRANCH ]; then + exit 0 +fi +REALEXITSTATUS=0 +go get -u github.com/HewlettPackard/gas +gas -skip=*/arm/*/models.go -skip=*/management/examples/*.go -skip=*vendor* -skip=*/Gododir/* ./... | tee /dev/stderr +REALEXITSTATUS=$(($REALEXITSTATUS+$?)) +gas -exclude=G101 ./arm/... ./management/examples/... | tee /dev/stderr +REALEXITSTATUS=$(($REALEXITSTATUS+$?)) +gas -exclude=G204 ./Gododir/... | tee /dev/stderr +REALEXITSTATUS=$(($REALEXITSTATUS+$?)) +exit $REALEXITSTATUS \ No newline at end of file diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md new file mode 100644 index 000000000..261c041e7 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/README.md @@ -0,0 +1,12 @@ +# go-ansiterm + +This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent. + +For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position. + +The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). + +See parser_test.go for examples exercising the state machine and generating appropriate function calls. + +----- +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-ansiterm/parser_test.go b/vendor/github.com/Azure/go-ansiterm/parser_test.go new file mode 100644 index 000000000..cd4888ff4 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_test.go @@ -0,0 +1,141 @@ +package ansiterm + +import ( + "fmt" + "testing" +) + +func TestStateTransitions(t *testing.T) { + stateTransitionHelper(t, "CsiEntry", "Ground", alphabetics) + stateTransitionHelper(t, "CsiEntry", "CsiParam", csiCollectables) + stateTransitionHelper(t, "Escape", "CsiEntry", []byte{ANSI_ESCAPE_SECONDARY}) + stateTransitionHelper(t, "Escape", "OscString", []byte{0x5D}) + stateTransitionHelper(t, "Escape", "Ground", escapeToGroundBytes) + stateTransitionHelper(t, "Escape", "EscapeIntermediate", intermeds) + stateTransitionHelper(t, "EscapeIntermediate", "EscapeIntermediate", intermeds) + stateTransitionHelper(t, "EscapeIntermediate", "EscapeIntermediate", executors) + stateTransitionHelper(t, "EscapeIntermediate", "Ground", escapeIntermediateToGroundBytes) + stateTransitionHelper(t, "OscString", "Ground", []byte{ANSI_BEL}) + stateTransitionHelper(t, "OscString", "Ground", []byte{0x5C}) + stateTransitionHelper(t, "Ground", "Ground", executors) +} + +func TestAnyToX(t *testing.T) { + anyToXHelper(t, []byte{ANSI_ESCAPE_PRIMARY}, "Escape") + anyToXHelper(t, []byte{DCS_ENTRY}, "DcsEntry") + anyToXHelper(t, []byte{OSC_STRING}, "OscString") + anyToXHelper(t, []byte{CSI_ENTRY}, "CsiEntry") + anyToXHelper(t, toGroundBytes, "Ground") +} + +func TestCollectCsiParams(t *testing.T) { + parser, _ := createTestParser("CsiEntry") + parser.Parse(csiCollectables) + + buffer := parser.context.paramBuffer + bufferCount := len(buffer) + + if bufferCount != len(csiCollectables) { + t.Errorf("Buffer: %v", buffer) + t.Errorf("CsiParams: %v", csiCollectables) + t.Errorf("Buffer count failure: %d != %d", bufferCount, len(csiParams)) + return + } + + for i, v := range csiCollectables { + if v != buffer[i] { + t.Errorf("Buffer: %v", buffer) + t.Errorf("CsiParams: %v", csiParams) + t.Errorf("Mismatch at buffer[%d] = %d", i, buffer[i]) + } + } +} + +func TestParseParams(t *testing.T) { + parseParamsHelper(t, []byte{}, []string{}) + parseParamsHelper(t, []byte{';'}, []string{}) + parseParamsHelper(t, []byte{';', ';'}, []string{}) + parseParamsHelper(t, []byte{'7'}, []string{"7"}) + parseParamsHelper(t, []byte{'7', ';'}, []string{"7"}) + parseParamsHelper(t, []byte{'7', ';', ';'}, []string{"7"}) + parseParamsHelper(t, []byte{'7', ';', ';', '8'}, []string{"7", "8"}) + parseParamsHelper(t, []byte{'7', ';', '8', ';'}, []string{"7", "8"}) + parseParamsHelper(t, []byte{'7', ';', ';', '8', ';', ';'}, []string{"7", "8"}) + parseParamsHelper(t, []byte{'7', '8'}, []string{"78"}) + parseParamsHelper(t, []byte{'7', '8', ';'}, []string{"78"}) + parseParamsHelper(t, []byte{'7', '8', ';', '9', '0'}, []string{"78", "90"}) + parseParamsHelper(t, []byte{'7', '8', ';', ';', '9', '0'}, []string{"78", "90"}) + parseParamsHelper(t, []byte{'7', '8', ';', '9', '0', ';'}, []string{"78", "90"}) + parseParamsHelper(t, []byte{'7', '8', ';', '9', '0', ';', ';'}, []string{"78", "90"}) +} + +func TestCursor(t *testing.T) { + cursorSingleParamHelper(t, 'A', "CUU") + cursorSingleParamHelper(t, 'B', "CUD") + cursorSingleParamHelper(t, 'C', "CUF") + cursorSingleParamHelper(t, 'D', "CUB") + cursorSingleParamHelper(t, 'E', "CNL") + cursorSingleParamHelper(t, 'F', "CPL") + cursorSingleParamHelper(t, 'G', "CHA") + cursorTwoParamHelper(t, 'H', "CUP") + cursorTwoParamHelper(t, 'f', "HVP") + funcCallParamHelper(t, []byte{'?', '2', '5', 'h'}, "CsiEntry", "Ground", []string{"DECTCEM([true])"}) + funcCallParamHelper(t, []byte{'?', '2', '5', 'l'}, "CsiEntry", "Ground", []string{"DECTCEM([false])"}) +} + +func TestErase(t *testing.T) { + // Erase in Display + eraseHelper(t, 'J', "ED") + + // Erase in Line + eraseHelper(t, 'K', "EL") +} + +func TestSelectGraphicRendition(t *testing.T) { + funcCallParamHelper(t, []byte{'m'}, "CsiEntry", "Ground", []string{"SGR([0])"}) + funcCallParamHelper(t, []byte{'0', 'm'}, "CsiEntry", "Ground", []string{"SGR([0])"}) + funcCallParamHelper(t, []byte{'0', ';', '1', 'm'}, "CsiEntry", "Ground", []string{"SGR([0 1])"}) + funcCallParamHelper(t, []byte{'0', ';', '1', ';', '2', 'm'}, "CsiEntry", "Ground", []string{"SGR([0 1 2])"}) +} + +func TestScroll(t *testing.T) { + scrollHelper(t, 'S', "SU") + scrollHelper(t, 'T', "SD") +} + +func TestPrint(t *testing.T) { + parser, evtHandler := createTestParser("Ground") + parser.Parse(printables) + validateState(t, parser.currState, "Ground") + + for i, v := range printables { + expectedCall := fmt.Sprintf("Print([%s])", string(v)) + actualCall := evtHandler.FunctionCalls[i] + if actualCall != expectedCall { + t.Errorf("Actual != Expected: %v != %v at %d", actualCall, expectedCall, i) + } + } +} + +func TestClear(t *testing.T) { + p, _ := createTestParser("Ground") + fillContext(p.context) + p.clear() + validateEmptyContext(t, p.context) +} + +func TestClearOnStateChange(t *testing.T) { + clearOnStateChangeHelper(t, "Ground", "Escape", []byte{ANSI_ESCAPE_PRIMARY}) + clearOnStateChangeHelper(t, "Ground", "CsiEntry", []byte{CSI_ENTRY}) +} + +func TestC0(t *testing.T) { + expectedCall := "Execute([" + string(ANSI_LINE_FEED) + "])" + c0Helper(t, []byte{ANSI_LINE_FEED}, "Ground", []string{expectedCall}) + expectedCall = "Execute([" + string(ANSI_CARRIAGE_RETURN) + "])" + c0Helper(t, []byte{ANSI_CARRIAGE_RETURN}, "Ground", []string{expectedCall}) +} + +func TestEscDispatch(t *testing.T) { + funcCallParamHelper(t, []byte{'M'}, "Escape", "Ground", []string{"RI([])"}) +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_test_helpers_test.go b/vendor/github.com/Azure/go-ansiterm/parser_test_helpers_test.go new file mode 100644 index 000000000..562f215d3 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_test_helpers_test.go @@ -0,0 +1,114 @@ +package ansiterm + +import ( + "fmt" + "testing" +) + +func getStateNames() []string { + parser, _ := createTestParser("Ground") + + stateNames := []string{} + for _, state := range parser.stateMap { + stateNames = append(stateNames, state.Name()) + } + + return stateNames +} + +func stateTransitionHelper(t *testing.T, start string, end string, bytes []byte) { + for _, b := range bytes { + bytes := []byte{byte(b)} + parser, _ := createTestParser(start) + parser.Parse(bytes) + validateState(t, parser.currState, end) + } +} + +func anyToXHelper(t *testing.T, bytes []byte, expectedState string) { + for _, s := range getStateNames() { + stateTransitionHelper(t, s, expectedState, bytes) + } +} + +func funcCallParamHelper(t *testing.T, bytes []byte, start string, expected string, expectedCalls []string) { + parser, evtHandler := createTestParser(start) + parser.Parse(bytes) + validateState(t, parser.currState, expected) + validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls) +} + +func parseParamsHelper(t *testing.T, bytes []byte, expectedParams []string) { + params, err := parseParams(bytes) + + if err != nil { + t.Errorf("Parameter parse error: %v", err) + return + } + + if len(params) != len(expectedParams) { + t.Errorf("Parsed parameters: %v", params) + t.Errorf("Expected parameters: %v", expectedParams) + t.Errorf("Parameter length failure: %d != %d", len(params), len(expectedParams)) + return + } + + for i, v := range expectedParams { + if v != params[i] { + t.Errorf("Parsed parameters: %v", params) + t.Errorf("Expected parameters: %v", expectedParams) + t.Errorf("Parameter parse failure: %s != %s at position %d", v, params[i], i) + } + } +} + +func cursorSingleParamHelper(t *testing.T, command byte, funcName string) { + funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) + funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) + funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) + funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23])", funcName)}) + funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) + funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) +} + +func cursorTwoParamHelper(t *testing.T, command byte, funcName string) { + funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)}) + funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)}) + funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 1])", funcName)}) + funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23 1])", funcName)}) + funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)}) + funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)}) +} + +func eraseHelper(t *testing.T, command byte, funcName string) { + funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)}) + funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)}) + funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) + funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)}) + funcCallParamHelper(t, []byte{'3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([3])", funcName)}) + funcCallParamHelper(t, []byte{'4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)}) + funcCallParamHelper(t, []byte{'1', ';', '2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) +} + +func scrollHelper(t *testing.T, command byte, funcName string) { + funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) + funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) + funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)}) + funcCallParamHelper(t, []byte{'5', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([5])", funcName)}) + funcCallParamHelper(t, []byte{'4', ';', '6', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([4])", funcName)}) +} + +func clearOnStateChangeHelper(t *testing.T, start string, end string, bytes []byte) { + p, _ := createTestParser(start) + fillContext(p.context) + p.Parse(bytes) + validateState(t, p.currState, end) + validateEmptyContext(t, p.context) +} + +func c0Helper(t *testing.T, bytes []byte, expectedState string, expectedCalls []string) { + parser, evtHandler := createTestParser("Ground") + parser.Parse(bytes) + validateState(t, parser.currState, expectedState) + validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls) +} diff --git a/vendor/github.com/Azure/go-ansiterm/parser_test_utilities_test.go b/vendor/github.com/Azure/go-ansiterm/parser_test_utilities_test.go new file mode 100644 index 000000000..78b885ca1 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/parser_test_utilities_test.go @@ -0,0 +1,66 @@ +package ansiterm + +import ( + "testing" +) + +func createTestParser(s string) (*AnsiParser, *TestAnsiEventHandler) { + evtHandler := CreateTestAnsiEventHandler() + parser := CreateParser(s, evtHandler) + + return parser, evtHandler +} + +func validateState(t *testing.T, actualState state, expectedStateName string) { + actualName := "Nil" + + if actualState != nil { + actualName = actualState.Name() + } + + if actualName != expectedStateName { + t.Errorf("Invalid state: '%s' != '%s'", actualName, expectedStateName) + } +} + +func validateFuncCalls(t *testing.T, actualCalls []string, expectedCalls []string) { + actualCount := len(actualCalls) + expectedCount := len(expectedCalls) + + if actualCount != expectedCount { + t.Errorf("Actual calls: %v", actualCalls) + t.Errorf("Expected calls: %v", expectedCalls) + t.Errorf("Call count error: %d != %d", actualCount, expectedCount) + return + } + + for i, v := range actualCalls { + if v != expectedCalls[i] { + t.Errorf("Actual calls: %v", actualCalls) + t.Errorf("Expected calls: %v", expectedCalls) + t.Errorf("Mismatched calls: %s != %s with lengths %d and %d", v, expectedCalls[i], len(v), len(expectedCalls[i])) + } + } +} + +func fillContext(context *ansiContext) { + context.currentChar = 'A' + context.paramBuffer = []byte{'C', 'D', 'E'} + context.interBuffer = []byte{'F', 'G', 'H'} +} + +func validateEmptyContext(t *testing.T, context *ansiContext) { + var expectedCurrChar byte = 0x0 + if context.currentChar != expectedCurrChar { + t.Errorf("Currentchar mismatch '%#x' != '%#x'", context.currentChar, expectedCurrChar) + } + + if len(context.paramBuffer) != 0 { + t.Errorf("Non-empty parameter buffer: %v", context.paramBuffer) + } + + if len(context.paramBuffer) != 0 { + t.Errorf("Non-empty intermediate buffer: %v", context.interBuffer) + } + +} diff --git a/vendor/github.com/Azure/go-ansiterm/test_event_handler_test.go b/vendor/github.com/Azure/go-ansiterm/test_event_handler_test.go new file mode 100644 index 000000000..60f9f30b9 --- /dev/null +++ b/vendor/github.com/Azure/go-ansiterm/test_event_handler_test.go @@ -0,0 +1,173 @@ +package ansiterm + +import ( + "fmt" + "strconv" +) + +type TestAnsiEventHandler struct { + FunctionCalls []string +} + +func CreateTestAnsiEventHandler() *TestAnsiEventHandler { + evtHandler := TestAnsiEventHandler{} + evtHandler.FunctionCalls = make([]string, 0) + return &evtHandler +} + +func (h *TestAnsiEventHandler) recordCall(call string, params []string) { + s := fmt.Sprintf("%s(%v)", call, params) + h.FunctionCalls = append(h.FunctionCalls, s) +} + +func (h *TestAnsiEventHandler) Print(b byte) error { + h.recordCall("Print", []string{string(b)}) + return nil +} + +func (h *TestAnsiEventHandler) Execute(b byte) error { + h.recordCall("Execute", []string{string(b)}) + return nil +} + +func (h *TestAnsiEventHandler) CUU(param int) error { + h.recordCall("CUU", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CUD(param int) error { + h.recordCall("CUD", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CUF(param int) error { + h.recordCall("CUF", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CUB(param int) error { + h.recordCall("CUB", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CNL(param int) error { + h.recordCall("CNL", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CPL(param int) error { + h.recordCall("CPL", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CHA(param int) error { + h.recordCall("CHA", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) VPA(param int) error { + h.recordCall("VPA", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) CUP(x int, y int) error { + xS, yS := strconv.Itoa(x), strconv.Itoa(y) + h.recordCall("CUP", []string{xS, yS}) + return nil +} + +func (h *TestAnsiEventHandler) HVP(x int, y int) error { + xS, yS := strconv.Itoa(x), strconv.Itoa(y) + h.recordCall("HVP", []string{xS, yS}) + return nil +} + +func (h *TestAnsiEventHandler) DECTCEM(visible bool) error { + h.recordCall("DECTCEM", []string{strconv.FormatBool(visible)}) + return nil +} + +func (h *TestAnsiEventHandler) DECOM(visible bool) error { + h.recordCall("DECOM", []string{strconv.FormatBool(visible)}) + return nil +} + +func (h *TestAnsiEventHandler) DECCOLM(use132 bool) error { + h.recordCall("DECOLM", []string{strconv.FormatBool(use132)}) + return nil +} + +func (h *TestAnsiEventHandler) ED(param int) error { + h.recordCall("ED", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) EL(param int) error { + h.recordCall("EL", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) IL(param int) error { + h.recordCall("IL", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) DL(param int) error { + h.recordCall("DL", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) ICH(param int) error { + h.recordCall("ICH", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) DCH(param int) error { + h.recordCall("DCH", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) SGR(params []int) error { + strings := []string{} + for _, v := range params { + strings = append(strings, strconv.Itoa(v)) + } + + h.recordCall("SGR", strings) + return nil +} + +func (h *TestAnsiEventHandler) SU(param int) error { + h.recordCall("SU", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) SD(param int) error { + h.recordCall("SD", []string{strconv.Itoa(param)}) + return nil +} + +func (h *TestAnsiEventHandler) DA(params []string) error { + h.recordCall("DA", params) + return nil +} + +func (h *TestAnsiEventHandler) DECSTBM(top int, bottom int) error { + topS, bottomS := strconv.Itoa(top), strconv.Itoa(bottom) + h.recordCall("DECSTBM", []string{topS, bottomS}) + return nil +} + +func (h *TestAnsiEventHandler) RI() error { + h.recordCall("RI", nil) + return nil +} + +func (h *TestAnsiEventHandler) IND() error { + h.recordCall("IND", nil) + return nil +} + +func (h *TestAnsiEventHandler) Flush() error { + return nil +} diff --git a/vendor/github.com/Azure/go-autorest/.gitignore b/vendor/github.com/Azure/go-autorest/.gitignore new file mode 100644 index 000000000..ab262cbe5 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/.gitignore @@ -0,0 +1,31 @@ +# The standard Go .gitignore file follows. (Sourced from: github.com/github/gitignore/master/Go.gitignore) +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test +.DS_Store +.idea/ + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# go-autorest specific +vendor/ +autorest/azure/example/example diff --git a/vendor/github.com/Azure/go-autorest/.travis.yml b/vendor/github.com/Azure/go-autorest/.travis.yml new file mode 100644 index 000000000..14315d754 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/.travis.yml @@ -0,0 +1,24 @@ +sudo: false + +language: go + +go: + - 1.9 + - 1.8 + - 1.7 + +install: + - go get -u github.com/golang/lint/golint + - go get -u github.com/Masterminds/glide + - go get -u github.com/stretchr/testify + - go get -u github.com/GoASTScanner/gas + - glide install + +script: + - grep -L -r --include *.go --exclude-dir vendor -P "Copyright (\d{4}|\(c\)) Microsoft" ./ | tee /dev/stderr | test -z "$(< /dev/stdin)" + - test -z "$(gofmt -s -l -w ./autorest/. | tee /dev/stderr)" + - test -z "$(golint ./autorest/... | tee /dev/stderr)" + - go vet ./autorest/... + - test -z "$(gas ./autorest/... | tee /dev/stderr | grep Error)" + - go build -v ./autorest/... + - go test -v ./autorest/... diff --git a/vendor/github.com/Azure/go-autorest/CHANGELOG.md b/vendor/github.com/Azure/go-autorest/CHANGELOG.md new file mode 100644 index 000000000..10f1de8e6 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/CHANGELOG.md @@ -0,0 +1,345 @@ +# CHANGELOG + +## v9.10.0 +- Fix the Service Bus suffix in Azure public env +- Add Service Bus Endpoint (AAD ResourceURI) for use in [Azure Service Bus RBAC Preview](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-role-based-access-control) + +## v9.9.0 + +### New Features + +- Added EventGridKeyAuthorizer for key authorization with event grid topics. + +### Bug Fixes + +- Fixed race condition when auto-refreshing service principal tokens. + +## v9.8.1 + +### Bug Fixes + +- Added http.StatusNoContent (204) to the list of expected status codes for long-running operations. +- Updated runtime version info so it's current. + +## v9.8.0 + +### New Features + +- Added type azure.AsyncOpIncompleteError to be returned from a future's Result() method when the operation has not completed. + +## v9.7.1 + +### Bug Fixes + +- Use correct AAD and Graph endpoints for US Gov environment. + +## v9.7.0 + +### New Features + +- Added support for application/octet-stream MIME types. + +## v9.6.1 + +### Bug Fixes + +- Ensure Authorization header is added to request when polling for registration status. + +## v9.6.0 + +### New Features + +- Added support for acquiring tokens via MSI with a user assigned identity. + +## v9.5.3 + +### Bug Fixes +- Don't remove encoding of existing URL Query parameters when calling autorest.WithQueryParameters. +- Set correct Content Type when using autorest.WithFormData. + +## v9.5.2 + +### Bug Fixes + +- Check for nil *http.Response before dereferencing it. + +## v9.5.1 + +### Bug Fixes + +- Don't count http.StatusTooManyRequests (429) against the retry cap. +- Use retry logic when SkipResourceProviderRegistration is set to true. + +## v9.5.0 + +### New Features + +- Added support for username + password, API key, authoriazation code and cognitive services authentication. +- Added field SkipResourceProviderRegistration to clients to provide a way to skip auto-registration of RPs. +- Added utility function AsStringSlice() to convert its parameters to a string slice. + +### Bug Fixes + +- When checking for authentication failures look at the error type not the status code as it could vary. + +## v9.4.2 + +### Bug Fixes + +- Validate parameters when creating credentials. +- Don't retry requests if the returned status is a 401 (http.StatusUnauthorized) as it will never succeed. + +## v9.4.1 + +### Bug Fixes + +- Update the AccessTokensPath() to read access tokens path through AZURE_ACCESS_TOKEN_FILE. If this + environment variable is not set, it will fall back to use default path set by Azure CLI. +- Use case-insensitive string comparison for polling states. + +## v9.4.0 + +### New Features + +- Added WaitForCompletion() to Future as a default polling implementation. + +### Bug Fixes + +- Method Future.Done() shouldn't update polling status for unexpected HTTP status codes. + +## v9.3.1 + +### Bug Fixes + +- DoRetryForStatusCodes will retry if sender.Do returns a non-nil error. + +## v9.3.0 + +### New Features + +- Added PollingMethod() to Future so callers know what kind of polling mechanism is used. +- Added azure.ChangeToGet() which transforms an http.Request into a GET (to be used with LROs). + +## v9.2.0 + +### New Features + +- Added support for custom Azure Stack endpoints. +- Added type azure.Future used to track the status of long-running operations. + +### Bug Fixes + +- Preserve the original error in DoRetryWithRegistration when registration fails. + +## v9.1.1 + +- Fixes a bug regarding the cookie jar on `autorest.Client.Sender`. + +## v9.1.0 + +### New Features + +- In cases where there is a non-empty error from the service, attempt to unmarshal it instead of uniformly calling it an "Unknown" error. +- Support for loading Azure CLI Authentication files. +- Automatically register your subscription with the Azure Resource Provider if it hadn't been previously. + +### Bug Fixes + + - RetriableRequest can now tolerate a ReadSeekable body being read but not reset. + - Adding missing Apache Headers + +## v9.0.0 + +> **IMPORTANT:** This release was intially labeled incorrectly as `v8.4.0`. From the time it was released, it should have been marked `v9.0.0` because it contains breaking changes to the MSI packages. We appologize for any inconvenience this causes. + +Adding MSI Endpoint Support and CLI token rehydration. + +## v8.3.1 + +Pick up bug fix in adal for MSI support. + +## v8.3.0 + +Updates to Error string formats for clarity. Also, adding a copy of the http.Response to errors for an improved debugging experience. + +## v8.2.0 + +### New Features + +- Add support for bearer authentication callbacks +- Support 429 response codes that include "Retry-After" header +- Support validation constraint "Pattern" for map keys + +### Bug Fixes + +- Make RetriableRequest work with multiple versions of Go + +## v8.1.1 +Updates the RetriableRequest to take advantage of GetBody() added in Go 1.8. + +## v8.1.0 +Adds RetriableRequest type for more efficient handling of retrying HTTP requests. + +## v8.0.0 + +ADAL refactored into its own package. +Support for UNIX time. + +## v7.3.1 +- Version Testing now removed from production bits that are shipped with the library. + +## v7.3.0 +- Exposing new `RespondDecorator`, `ByDiscardingBody`. This allows operations + to acknowledge that they do not need either the entire or a trailing portion + of accepts response body. In doing so, Go's http library can reuse HTTP + connections more readily. +- Adding `PrepareDecorator` to target custom BaseURLs. +- Adding ACR suffix to public cloud environment. +- Updating Glide dependencies. + +## v7.2.5 +- Fixed the Active Directory endpoint for the China cloud. +- Removes UTF-8 BOM if present in response payload. +- Added telemetry. + +## v7.2.3 +- Fixing bug in calls to `DelayForBackoff` that caused doubling of delay + duration. + +## v7.2.2 +- autorest/azure: added ASM and ARM VM DNS suffixes. + +## v7.2.1 +- fixed parsing of UTC times that are not RFC3339 conformant. + +## v7.2.0 +- autorest/validation: Reformat validation error for better error message. + +## v7.1.0 +- preparer: Added support for multipart formdata - WithMultiPartFormdata() +- preparer: Added support for sending file in request body - WithFile +- client: Added RetryDuration parameter. +- autorest/validation: new package for validation code for Azure Go SDK. + +## v7.0.7 +- Add trailing / to endpoint +- azure: add EnvironmentFromName + +## v7.0.6 +- Add retry logic for 408, 500, 502, 503 and 504 status codes. +- Change url path and query encoding logic. +- Fix DelayForBackoff for proper exponential delay. +- Add CookieJar in Client. + +## v7.0.5 +- Add check to start polling only when status is in [200,201,202]. +- Refactoring for unchecked errors. +- azure/persist changes. +- Fix 'file in use' issue in renewing token in deviceflow. +- Store header RetryAfter for subsequent requests in polling. +- Add attribute details in service error. + +## v7.0.4 +- Better error messages for long running operation failures + +## v7.0.3 +- Corrected DoPollForAsynchronous to properly handle the initial response + +## v7.0.2 +- Corrected DoPollForAsynchronous to continue using the polling method first discovered + +## v7.0.1 +- Fixed empty JSON input error in ByUnmarshallingJSON +- Fixed polling support for GET calls +- Changed format name from TimeRfc1123 to TimeRFC1123 + +## v7.0.0 +- Added ByCopying responder with supporting TeeReadCloser +- Rewrote Azure asynchronous handling +- Reverted to only unmarshalling JSON +- Corrected handling of RFC3339 time strings and added support for Rfc1123 time format + +The `json.Decoder` does not catch bad data as thoroughly as `json.Unmarshal`. Since +`encoding/json` successfully deserializes all core types, and extended types normally provide +their custom JSON serialization handlers, the code has been reverted back to using +`json.Unmarshal`. The original change to use `json.Decode` was made to reduce duplicate +code; there is no loss of function, and there is a gain in accuracy, by reverting. + +Additionally, Azure services indicate requests to be polled by multiple means. The existing code +only checked for one of those (that is, the presence of the `Azure-AsyncOperation` header). +The new code correctly covers all cases and aligns with the other Azure SDKs. + +## v6.1.0 +- Introduced `date.ByUnmarshallingJSONDate` and `date.ByUnmarshallingJSONTime` to enable JSON encoded values. + +## v6.0.0 +- Completely reworked the handling of polled and asynchronous requests +- Removed unnecessary routines +- Reworked `mocks.Sender` to replay a series of `http.Response` objects +- Added `PrepareDecorators` for primitive types (e.g., bool, int32) + +Handling polled and asynchronous requests is no longer part of `Client#Send`. Instead new +`SendDecorators` implement different styles of polled behavior. See`autorest.DoPollForStatusCodes` +and `azure.DoPollForAsynchronous` for examples. + +## v5.0.0 +- Added new RespondDecorators unmarshalling primitive types +- Corrected application of inspection and authorization PrependDecorators + +## v4.0.0 +- Added support for Azure long-running operations. +- Added cancelation support to all decorators and functions that may delay. +- Breaking: `DelayForBackoff` now accepts a channel, which may be nil. + +## v3.1.0 +- Add support for OAuth Device Flow authorization. +- Add support for ServicePrincipalTokens that are backed by an existing token, rather than other secret material. +- Add helpers for persisting and restoring Tokens. +- Increased code coverage in the github.com/Azure/autorest/azure package + +## v3.0.0 +- Breaking: `NewErrorWithError` no longer takes `statusCode int`. +- Breaking: `NewErrorWithStatusCode` is replaced with `NewErrorWithResponse`. +- Breaking: `Client#Send()` no longer takes `codes ...int` argument. +- Add: XML unmarshaling support with `ByUnmarshallingXML()` +- Stopped vending dependencies locally and switched to [Glide](https://github.com/Masterminds/glide). + Applications using this library should either use Glide or vendor dependencies locally some other way. +- Add: `azure.WithErrorUnlessStatusCode()` decorator to handle Azure errors. +- Fix: use `net/http.DefaultClient` as base client. +- Fix: Missing inspection for polling responses added. +- Add: CopyAndDecode helpers. +- Improved `./autorest/to` with `[]string` helpers. +- Removed golint suppressions in .travis.yml. + +## v2.1.0 + +- Added `StatusCode` to `Error` for more easily obtaining the HTTP Reponse StatusCode (if any) + +## v2.0.0 + +- Changed `to.StringMapPtr` method signature to return a pointer +- Changed `ServicePrincipalCertificateSecret` and `NewServicePrincipalTokenFromCertificate` to support generic certificate and private keys + +## v1.0.0 + +- Added Logging inspectors to trace http.Request / Response +- Added support for User-Agent header +- Changed WithHeader PrepareDecorator to use set vs. add +- Added JSON to error when unmarshalling fails +- Added Client#Send method +- Corrected case of "Azure" in package paths +- Added "to" helpers, Azure helpers, and improved ease-of-use +- Corrected golint issues + +## v1.0.1 + +- Added CHANGELOG.md + +## v1.1.0 + +- Added mechanism to retrieve a ServicePrincipalToken using a certificate-signed JWT +- Added an example of creating a certificate-based ServicePrincipal and retrieving an OAuth token using the certificate + +## v1.1.1 + +- Introduce godeps and vendor dependencies introduced in v1.1.1 diff --git a/vendor/github.com/Azure/go-autorest/GNUmakefile b/vendor/github.com/Azure/go-autorest/GNUmakefile new file mode 100644 index 000000000..a434e73ac --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/GNUmakefile @@ -0,0 +1,23 @@ +DIR?=./autorest/ + +default: build + +build: fmt + go install $(DIR) + +test: + go test $(DIR) || exit 1 + +vet: + @echo "go vet ." + @go vet $(DIR)... ; if [ $$? -eq 1 ]; then \ + echo ""; \ + echo "Vet found suspicious constructs. Please check the reported constructs"; \ + echo "and fix them if necessary before submitting the code for review."; \ + exit 1; \ + fi + +fmt: + gofmt -w $(DIR) + +.PHONY: build test vet fmt diff --git a/vendor/github.com/Azure/go-autorest/README.md b/vendor/github.com/Azure/go-autorest/README.md new file mode 100644 index 000000000..f4c34d0e6 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/README.md @@ -0,0 +1,132 @@ +# go-autorest + +[![GoDoc](https://godoc.org/github.com/Azure/go-autorest/autorest?status.png)](https://godoc.org/github.com/Azure/go-autorest/autorest) [![Build Status](https://travis-ci.org/Azure/go-autorest.svg?branch=master)](https://travis-ci.org/Azure/go-autorest) [![Go Report Card](https://goreportcard.com/badge/Azure/go-autorest)](https://goreportcard.com/report/Azure/go-autorest) + +## Usage +Package autorest implements an HTTP request pipeline suitable for use across multiple go-routines +and provides the shared routines relied on by AutoRest (see https://github.com/Azure/autorest/) +generated Go code. + +The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending, +and Responding. A typical pattern is: + +```go + req, err := Prepare(&http.Request{}, + token.WithAuthorization()) + + resp, err := Send(req, + WithLogging(logger), + DoErrorIfStatusCode(http.StatusInternalServerError), + DoCloseIfError(), + DoRetryForAttempts(5, time.Second)) + + err = Respond(resp, + ByDiscardingBody(), + ByClosing()) +``` + +Each phase relies on decorators to modify and / or manage processing. Decorators may first modify +and then pass the data along, pass the data first and then modify the result, or wrap themselves +around passing the data (such as a logger might do). Decorators run in the order provided. For +example, the following: + +```go + req, err := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/"), + WithPath("a"), + WithPath("b"), + WithPath("c")) +``` + +will set the URL to: + +``` + https://microsoft.com/a/b/c +``` + +Preparers and Responders may be shared and re-used (assuming the underlying decorators support +sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders +shared among multiple go-routines, and a single Sender shared among multiple sending go-routines, +all bound together by means of input / output channels. + +Decorators hold their passed state within a closure (such as the path components in the example +above). Be careful to share Preparers and Responders only in a context where such held state +applies. For example, it may not make sense to share a Preparer that applies a query string from a +fixed set of values. Similarly, sharing a Responder that reads the response body into a passed +struct (e.g., `ByUnmarshallingJson`) is likely incorrect. + +Errors raised by autorest objects and methods will conform to the `autorest.Error` interface. + +See the included examples for more detail. For details on the suggested use of this package by +generated clients, see the Client described below. + +## Helpers + +### Handling Swagger Dates + +The Swagger specification (https://swagger.io) that drives AutoRest +(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The +github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure correct +parsing and formatting. + +### Handling Empty Values + +In JSON, missing values have different semantics than empty values. This is especially true for +services using the HTTP PATCH verb. The JSON submitted with a PATCH request generally contains +only those values to modify. Missing values are to be left unchanged. Developers, then, require a +means to both specify an empty value and to leave the value out of the submitted JSON. + +The Go JSON package (`encoding/json`) supports the `omitempty` tag. When specified, it omits +empty values from the rendered JSON. Since Go defines default values for all base types (such as "" +for string and 0 for int) and provides no means to mark a value as actually empty, the JSON package +treats default values as meaning empty, omitting them from the rendered JSON. This means that, using +the Go base types encoded through the default JSON package, it is not possible to create JSON to +clear a value at the server. + +The workaround within the Go community is to use pointers to base types in lieu of base types within +structures that map to JSON. For example, instead of a value of type `string`, the workaround uses +`*string`. While this enables distinguishing empty values from those to be unchanged, creating +pointers to a base type (notably constant, in-line values) requires additional variables. This, for +example, + +```go + s := struct { + S *string + }{ S: &"foo" } +``` +fails, while, this + +```go + v := "foo" + s := struct { + S *string + }{ S: &v } +``` +succeeds. + +To ease using pointers, the subpackage `to` contains helpers that convert to and from pointers for +Go base types which have Swagger analogs. It also provides a helper that converts between +`map[string]string` and `map[string]*string`, enabling the JSON to specify that the value +associated with a key should be cleared. With the helpers, the previous example becomes + +```go + s := struct { + S *string + }{ S: to.StringPtr("foo") } +``` + +## Install + +```bash +go get github.com/Azure/go-autorest/autorest +go get github.com/Azure/go-autorest/autorest/azure +go get github.com/Azure/go-autorest/autorest/date +go get github.com/Azure/go-autorest/autorest/to +``` + +## License + +See LICENSE file. + +----- +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/README.md b/vendor/github.com/Azure/go-autorest/autorest/adal/README.md new file mode 100644 index 000000000..08966c9cf --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/README.md @@ -0,0 +1,287 @@ +# Azure Active Directory library for Go + +This project provides a stand alone Azure Active Directory library for Go. The code was extracted +from [go-autorest](https://github.com/Azure/go-autorest/) project, which is used as a base for +[azure-sdk-for-go](https://github.com/Azure/azure-sdk-for-go). + + +## Installation + +``` +go get -u github.com/Azure/go-autorest/autorest/adal +``` + +## Usage + +An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) follow these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli). + +### Register an Azure AD Application with secret + + +1. Register a new application with a `secret` credential + + ``` + az ad app create \ + --display-name example-app \ + --homepage https://example-app/home \ + --identifier-uris https://example-app/app \ + --password secret + ``` + +2. Create a service principal using the `Application ID` from previous step + + ``` + az ad sp create --id "Application ID" + ``` + + * Replace `Application ID` with `appId` from step 1. + +### Register an Azure AD Application with certificate + +1. Create a private key + + ``` + openssl genrsa -out "example-app.key" 2048 + ``` + +2. Create the certificate + + ``` + openssl req -new -key "example-app.key" -subj "/CN=example-app" -out "example-app.csr" + openssl x509 -req -in "example-app.csr" -signkey "example-app.key" -out "example-app.crt" -days 10000 + ``` + +3. Create the PKCS12 version of the certificate containing also the private key + + ``` + openssl pkcs12 -export -out "example-app.pfx" -inkey "example-app.key" -in "example-app.crt" -passout pass: + + ``` + +4. Register a new application with the certificate content form `example-app.crt` + + ``` + certificateContents="$(tail -n+2 "example-app.crt" | head -n-1)" + + az ad app create \ + --display-name example-app \ + --homepage https://example-app/home \ + --identifier-uris https://example-app/app \ + --key-usage Verify --end-date 2018-01-01 \ + --key-value "${certificateContents}" + ``` + +5. Create a service principal using the `Application ID` from previous step + + ``` + az ad sp create --id "APPLICATION_ID" + ``` + + * Replace `APPLICATION_ID` with `appId` from step 4. + + +### Grant the necessary permissions + +Azure relies on a Role-Based Access Control (RBAC) model to manage the access to resources at a fine-grained +level. There is a set of [pre-defined roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-built-in-roles) +which can be assigned to a service principal of an Azure AD application depending of your needs. + +``` +az role assignment create --assigner "SERVICE_PRINCIPAL_ID" --role "ROLE_NAME" +``` + +* Replace the `SERVICE_PRINCIPAL_ID` with the `appId` from previous step. +* Replace the `ROLE_NAME` with a role name of your choice. + +It is also possible to define custom role definitions. + +``` +az role definition create --role-definition role-definition.json +``` + +* Check [custom roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file. + + +### Acquire Access Token + +The common configuration used by all flows: + +```Go +const activeDirectoryEndpoint = "https://login.microsoftonline.com/" +tenantID := "TENANT_ID" +oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, tenantID) + +applicationID := "APPLICATION_ID" + +callback := func(token adal.Token) error { + // This is called after the token is acquired +} + +// The resource for which the token is acquired +resource := "https://management.core.windows.net/" +``` + +* Replace the `TENANT_ID` with your tenant ID. +* Replace the `APPLICATION_ID` with the value from previous section. + +#### Client Credentials + +```Go +applicationSecret := "APPLICATION_SECRET" + +spt, err := adal.NewServicePrincipalToken( + oauthConfig, + appliationID, + applicationSecret, + resource, + callbacks...) +if err != nil { + return nil, err +} + +// Acquire a new access token +err = spt.Refresh() +if (err == nil) { + token := spt.Token +} +``` + +* Replace the `APPLICATION_SECRET` with the `password` value from previous section. + +#### Client Certificate + +```Go +certificatePath := "./example-app.pfx" + +certData, err := ioutil.ReadFile(certificatePath) +if err != nil { + return nil, fmt.Errorf("failed to read the certificate file (%s): %v", certificatePath, err) +} + +// Get the certificate and private key from pfx file +certificate, rsaPrivateKey, err := decodePkcs12(certData, "") +if err != nil { + return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err) +} + +spt, err := adal.NewServicePrincipalTokenFromCertificate( + oauthConfig, + applicationID, + certificate, + rsaPrivateKey, + resource, + callbacks...) + +// Acquire a new access token +err = spt.Refresh() +if (err == nil) { + token := spt.Token +} +``` + +* Update the certificate path to point to the example-app.pfx file which was created in previous section. + + +#### Device Code + +```Go +oauthClient := &http.Client{} + +// Acquire the device code +deviceCode, err := adal.InitiateDeviceAuth( + oauthClient, + oauthConfig, + applicationID, + resource) +if err != nil { + return nil, fmt.Errorf("Failed to start device auth flow: %s", err) +} + +// Display the authentication message +fmt.Println(*deviceCode.Message) + +// Wait here until the user is authenticated +token, err := adal.WaitForUserCompletion(oauthClient, deviceCode) +if err != nil { + return nil, fmt.Errorf("Failed to finish device auth flow: %s", err) +} + +spt, err := adal.NewServicePrincipalTokenFromManualToken( + oauthConfig, + applicationID, + resource, + *token, + callbacks...) + +if (err == nil) { + token := spt.Token +} +``` + +#### Username password authenticate + +```Go +spt, err := adal.NewServicePrincipalTokenFromUsernamePassword( + oauthConfig, + applicationID, + username, + password, + resource, + callbacks...) + +if (err == nil) { + token := spt.Token +} +``` + +#### Authorization code authenticate + +``` Go +spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode( + oauthConfig, + applicationID, + clientSecret, + authorizationCode, + redirectURI, + resource, + callbacks...) + +err = spt.Refresh() +if (err == nil) { + token := spt.Token +} +``` + +### Command Line Tool + +A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above. + +``` +adal -h + +Usage of ./adal: + -applicationId string + application id + -certificatePath string + path to pk12/PFC application certificate + -mode string + authentication mode (device, secret, cert, refresh) (default "device") + -resource string + resource for which the token is requested + -secret string + application secret + -tenantId string + tenant id + -tokenCachePath string + location of oath token cache (default "/home/cgc/.adal/accessToken.json") +``` + +Example acquire a token for `https://management.core.windows.net/` using device code flow: + +``` +adal -mode device \ + -applicationId "APPLICATION_ID" \ + -tenantId "TENANT_ID" \ + -resource https://management.core.windows.net/ + +``` diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go b/vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go new file mode 100644 index 000000000..304280f66 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/config_test.go @@ -0,0 +1,44 @@ +package adal + +// Copyright 2017 Microsoft 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. + +import ( + "testing" +) + +func TestNewOAuthConfig(t *testing.T) { + const testActiveDirectoryEndpoint = "https://login.test.com" + const testTenantID = "tenant-id-test" + + config, err := NewOAuthConfig(testActiveDirectoryEndpoint, testTenantID) + if err != nil { + t.Fatalf("autorest/adal: Unexpected error while creating oauth configuration for tenant: %v.", err) + } + + expected := "https://login.test.com/tenant-id-test/oauth2/authorize?api-version=1.0" + if config.AuthorizeEndpoint.String() != expected { + t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.AuthorizeEndpoint) + } + + expected = "https://login.test.com/tenant-id-test/oauth2/token?api-version=1.0" + if config.TokenEndpoint.String() != expected { + t.Fatalf("autorest/adal: Incorrect authorize url for Tenant from Environment. expected(%s). actual(%v).", expected, config.TokenEndpoint) + } + + expected = "https://login.test.com/tenant-id-test/oauth2/devicecode?api-version=1.0" + if config.DeviceCodeEndpoint.String() != expected { + t.Fatalf("autorest/adal Incorrect devicecode url for Tenant from Environment. expected(%s). actual(%v).", expected, config.DeviceCodeEndpoint) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go b/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go new file mode 100644 index 000000000..6beee161f --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken_test.go @@ -0,0 +1,330 @@ +package adal + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "testing" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +const ( + TestResource = "SomeResource" + TestClientID = "SomeClientID" + TestTenantID = "SomeTenantID" + TestActiveDirectoryEndpoint = "https://login.test.com/" +) + +var ( + testOAuthConfig, _ = NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID) + TestOAuthConfig = *testOAuthConfig +) + +const MockDeviceCodeResponse = ` +{ + "device_code": "10000-40-1234567890", + "user_code": "ABCDEF", + "verification_url": "http://aka.ms/deviceauth", + "expires_in": "900", + "interval": "0" +} +` + +const MockDeviceTokenResponse = `{ + "access_token": "accessToken", + "refresh_token": "refreshToken", + "expires_in": "1000", + "expires_on": "2000", + "not_before": "3000", + "resource": "resource", + "token_type": "type" +} +` + +func TestDeviceCodeIncludesResource(t *testing.T) { + sender := mocks.NewSender() + sender.AppendResponse(mocks.NewResponseWithContent(MockDeviceCodeResponse)) + + code, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource) + if err != nil { + t.Fatalf("adal: unexpected error initiating device auth") + } + + if code.Resource != TestResource { + t.Fatalf("adal: InitiateDeviceAuth failed to stash the resource in the DeviceCode struct") + } +} + +func TestDeviceCodeReturnsErrorIfSendingFails(t *testing.T) { + sender := mocks.NewSender() + sender.SetError(fmt.Errorf("this is an error")) + + _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource) + if err == nil || !strings.Contains(err.Error(), errCodeSendingFails) { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeSendingFails, err.Error()) + } +} + +func TestDeviceCodeReturnsErrorIfBadRequest(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody("doesn't matter") + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request")) + + _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource) + if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceCodeReturnsErrorIfCannotDeserializeDeviceCode(t *testing.T) { + gibberishJSON := strings.Replace(MockDeviceCodeResponse, "expires_in", "\":, :gibberish", -1) + sender := mocks.NewSender() + body := mocks.NewBody(gibberishJSON) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")) + + _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource) + if err == nil || !strings.Contains(err.Error(), errCodeHandlingFails) { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errCodeHandlingFails, err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceCodeReturnsErrorIfEmptyDeviceCode(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody("") + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")) + + _, err := InitiateDeviceAuth(sender, TestOAuthConfig, TestClientID, TestResource) + if err != ErrDeviceCodeEmpty { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", ErrDeviceCodeEmpty, err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func deviceCode() *DeviceCode { + var deviceCode DeviceCode + _ = json.Unmarshal([]byte(MockDeviceCodeResponse), &deviceCode) + deviceCode.Resource = TestResource + deviceCode.ClientID = TestClientID + return &deviceCode +} + +func TestDeviceTokenReturns(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody(MockDeviceTokenResponse) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err != nil { + t.Fatalf("adal: got error unexpectedly") + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceTokenReturnsErrorIfSendingFails(t *testing.T) { + sender := mocks.NewSender() + sender.SetError(fmt.Errorf("this is an error")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err == nil || !strings.Contains(err.Error(), errTokenSendingFails) { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenSendingFails, err.Error()) + } +} + +func TestDeviceTokenReturnsErrorIfServerError(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody("") + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusInternalServerError, "Internal Server Error")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceTokenReturnsErrorIfCannotDeserializeDeviceToken(t *testing.T) { + gibberishJSON := strings.Replace(MockDeviceTokenResponse, "expires_in", ";:\"gibberish", -1) + sender := mocks.NewSender() + body := mocks.NewBody(gibberishJSON) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err == nil || !strings.Contains(err.Error(), errTokenHandlingFails) { + t.Fatalf("adal: failed to get correct error expected(%s) actual(%s)", errTokenHandlingFails, err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func errorDeviceTokenResponse(message string) string { + return `{ "error": "` + message + `" }` +} + +func TestDeviceTokenReturnsErrorIfAuthorizationPending(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody(errorDeviceTokenResponse("authorization_pending")) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request")) + + _, err := CheckForUserCompletion(sender, deviceCode()) + if err != ErrDeviceAuthorizationPending { + t.Fatalf("!!!") + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceTokenReturnsErrorIfSlowDown(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody(errorDeviceTokenResponse("slow_down")) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request")) + + _, err := CheckForUserCompletion(sender, deviceCode()) + if err != ErrDeviceSlowDown { + t.Fatalf("!!!") + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +type deviceTokenSender struct { + errorString string + attempts int +} + +func newDeviceTokenSender(deviceErrorString string) *deviceTokenSender { + return &deviceTokenSender{errorString: deviceErrorString, attempts: 0} +} + +func (s *deviceTokenSender) Do(req *http.Request) (*http.Response, error) { + var resp *http.Response + if s.attempts < 1 { + s.attempts++ + resp = mocks.NewResponseWithContent(errorDeviceTokenResponse(s.errorString)) + } else { + resp = mocks.NewResponseWithContent(MockDeviceTokenResponse) + } + return resp, nil +} + +// since the above only exercise CheckForUserCompletion, we repeat the test here, +// but with the intent of showing that WaitForUserCompletion loops properly. +func TestDeviceTokenSucceedsWithIntermediateAuthPending(t *testing.T) { + sender := newDeviceTokenSender("authorization_pending") + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err != nil { + t.Fatalf("unexpected error occurred") + } +} + +// same as above but with SlowDown now +func TestDeviceTokenSucceedsWithIntermediateSlowDown(t *testing.T) { + sender := newDeviceTokenSender("slow_down") + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err != nil { + t.Fatalf("unexpected error occurred") + } +} + +func TestDeviceTokenReturnsErrorIfAccessDenied(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody(errorDeviceTokenResponse("access_denied")) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err != ErrDeviceAccessDenied { + t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceAccessDenied.Error(), err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceTokenReturnsErrorIfCodeExpired(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody(errorDeviceTokenResponse("code_expired")) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err != ErrDeviceCodeExpired { + t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceCodeExpired.Error(), err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceTokenReturnsErrorForUnknownError(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody(errorDeviceTokenResponse("unknown_error")) + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusBadRequest, "Bad Request")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err == nil { + t.Fatalf("failed to get error") + } + if err != ErrDeviceGeneric { + t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrDeviceGeneric.Error(), err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} + +func TestDeviceTokenReturnsErrorIfTokenEmptyAndStatusOK(t *testing.T) { + sender := mocks.NewSender() + body := mocks.NewBody("") + sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK")) + + _, err := WaitForUserCompletion(sender, deviceCode()) + if err != ErrOAuthTokenEmpty { + t.Fatalf("adal: got wrong error expected(%s) actual(%s)", ErrOAuthTokenEmpty.Error(), err.Error()) + } + + if body.IsOpen() { + t.Fatalf("response body was left open!") + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go b/vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go new file mode 100644 index 000000000..a9c287c6d --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/persist_test.go @@ -0,0 +1,171 @@ +package adal + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "io/ioutil" + "os" + "path" + "reflect" + "runtime" + "strings" + "testing" +) + +const MockTokenJSON string = `{ + "access_token": "accessToken", + "refresh_token": "refreshToken", + "expires_in": "1000", + "expires_on": "2000", + "not_before": "3000", + "resource": "resource", + "token_type": "type" +}` + +var TestToken = Token{ + AccessToken: "accessToken", + RefreshToken: "refreshToken", + ExpiresIn: "1000", + ExpiresOn: "2000", + NotBefore: "3000", + Resource: "resource", + Type: "type", +} + +func writeTestTokenFile(t *testing.T, suffix string, contents string) *os.File { + f, err := ioutil.TempFile(os.TempDir(), suffix) + if err != nil { + t.Fatalf("azure: unexpected error when creating temp file: %v", err) + } + defer f.Close() + + _, err = f.Write([]byte(contents)) + if err != nil { + t.Fatalf("azure: unexpected error when writing temp test file: %v", err) + } + + return f +} + +func TestLoadToken(t *testing.T) { + f := writeTestTokenFile(t, "testloadtoken", MockTokenJSON) + defer os.Remove(f.Name()) + + expectedToken := TestToken + actualToken, err := LoadToken(f.Name()) + if err != nil { + t.Fatalf("azure: unexpected error loading token from file: %v", err) + } + + if *actualToken != expectedToken { + t.Fatalf("azure: failed to decode properly expected(%v) actual(%v)", expectedToken, *actualToken) + } + + // test that LoadToken closes the file properly + err = SaveToken(f.Name(), 0600, *actualToken) + if err != nil { + t.Fatalf("azure: could not save token after LoadToken: %v", err) + } +} + +func TestLoadTokenFailsBadPath(t *testing.T) { + _, err := LoadToken("/tmp/this_file_should_never_exist_really") + expectedSubstring := "failed to open file" + if err == nil || !strings.Contains(err.Error(), expectedSubstring) { + t.Fatalf("azure: failed to get correct error expected(%s) actual(%s)", expectedSubstring, err.Error()) + } +} + +func TestLoadTokenFailsBadJson(t *testing.T) { + gibberishJSON := strings.Replace(MockTokenJSON, "expires_on", ";:\"gibberish", -1) + f := writeTestTokenFile(t, "testloadtokenfailsbadjson", gibberishJSON) + defer os.Remove(f.Name()) + + _, err := LoadToken(f.Name()) + expectedSubstring := "failed to decode contents of file" + if err == nil || !strings.Contains(err.Error(), expectedSubstring) { + t.Fatalf("azure: failed to get correct error expected(%s) actual(%s)", expectedSubstring, err.Error()) + } +} + +func token() *Token { + var token Token + json.Unmarshal([]byte(MockTokenJSON), &token) + return &token +} + +func TestSaveToken(t *testing.T) { + f, err := ioutil.TempFile("", "testloadtoken") + if err != nil { + t.Fatalf("azure: unexpected error when creating temp file: %v", err) + } + defer os.Remove(f.Name()) + f.Close() + + mode := os.ModePerm & 0642 + err = SaveToken(f.Name(), mode, *token()) + if err != nil { + t.Fatalf("azure: unexpected error saving token to file: %v", err) + } + fi, err := os.Stat(f.Name()) // open a new stat as held ones are not fresh + if err != nil { + t.Fatalf("azure: stat failed: %v", err) + } + if runtime.GOOS != "windows" { // permissions don't work on Windows + if perm := fi.Mode().Perm(); perm != mode { + t.Fatalf("azure: wrong file perm. got:%s; expected:%s file :%s", perm, mode, f.Name()) + } + } + + var actualToken Token + var expectedToken Token + + json.Unmarshal([]byte(MockTokenJSON), expectedToken) + + contents, err := ioutil.ReadFile(f.Name()) + if err != nil { + t.Fatal("!!") + } + json.Unmarshal(contents, actualToken) + + if !reflect.DeepEqual(actualToken, expectedToken) { + t.Fatal("azure: token was not serialized correctly") + } +} + +func TestSaveTokenFailsNoPermission(t *testing.T) { + pathWhereWeShouldntHavePermission := "/usr/thiswontwork/atall" + if runtime.GOOS == "windows" { + pathWhereWeShouldntHavePermission = path.Join(os.Getenv("windir"), "system32\\mytokendir\\mytoken") + } + err := SaveToken(pathWhereWeShouldntHavePermission, 0644, *token()) + expectedSubstring := "failed to create directory" + if err == nil || !strings.Contains(err.Error(), expectedSubstring) { + t.Fatalf("azure: failed to get correct error expected(%s) actual(%v)", expectedSubstring, err) + } +} + +func TestSaveTokenFailsCantCreate(t *testing.T) { + tokenPath := "/thiswontwork" + if runtime.GOOS == "windows" { + tokenPath = path.Join(os.Getenv("windir"), "system32") + } + err := SaveToken(tokenPath, 0644, *token()) + expectedSubstring := "failed to create the temp file to write the token" + if err == nil || !strings.Contains(err.Error(), expectedSubstring) { + t.Fatalf("azure: failed to get correct error expected(%s) actual(%v)", expectedSubstring, err) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go b/vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go new file mode 100644 index 000000000..56a3c3b5b --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/token_test.go @@ -0,0 +1,725 @@ +package adal + +// Copyright 2017 Microsoft 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. + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "fmt" + "io/ioutil" + "math/big" + "net/http" + "net/url" + "os" + "reflect" + "strconv" + "strings" + "testing" + "time" + + "github.com/Azure/go-autorest/autorest/date" + "github.com/Azure/go-autorest/autorest/mocks" +) + +const ( + defaultFormData = "client_id=id&client_secret=secret&grant_type=client_credentials&resource=resource" + defaultManualFormData = "client_id=id&grant_type=refresh_token&refresh_token=refreshtoken&resource=resource" +) + +func TestTokenExpires(t *testing.T) { + tt := time.Now().Add(5 * time.Second) + tk := newTokenExpiresAt(tt) + + if tk.Expires().Equal(tt) { + t.Fatalf("adal: Token#Expires miscalculated expiration time -- received %v, expected %v", tk.Expires(), tt) + } +} + +func TestTokenIsExpired(t *testing.T) { + tk := newTokenExpiresAt(time.Now().Add(-5 * time.Second)) + + if !tk.IsExpired() { + t.Fatalf("adal: Token#IsExpired failed to mark a stale token as expired -- now %v, token expires at %v", + time.Now().UTC(), tk.Expires()) + } +} + +func TestTokenIsExpiredUninitialized(t *testing.T) { + tk := &Token{} + + if !tk.IsExpired() { + t.Fatalf("adal: An uninitialized Token failed to mark itself as expired (expiration time %v)", tk.Expires()) + } +} + +func TestTokenIsNoExpired(t *testing.T) { + tk := newTokenExpiresAt(time.Now().Add(1000 * time.Second)) + + if tk.IsExpired() { + t.Fatalf("adal: Token marked a fresh token as expired -- now %v, token expires at %v", time.Now().UTC(), tk.Expires()) + } +} + +func TestTokenWillExpireIn(t *testing.T) { + d := 5 * time.Second + tk := newTokenExpiresIn(d) + + if !tk.WillExpireIn(d) { + t.Fatal("adal: Token#WillExpireIn mismeasured expiration time") + } +} + +func TestServicePrincipalTokenSetAutoRefresh(t *testing.T) { + spt := newServicePrincipalToken() + + if !spt.autoRefresh { + t.Fatal("adal: ServicePrincipalToken did not default to automatic token refreshing") + } + + spt.SetAutoRefresh(false) + if spt.autoRefresh { + t.Fatal("adal: ServicePrincipalToken#SetAutoRefresh did not disable automatic token refreshing") + } +} + +func TestServicePrincipalTokenSetRefreshWithin(t *testing.T) { + spt := newServicePrincipalToken() + + if spt.refreshWithin != defaultRefresh { + t.Fatal("adal: ServicePrincipalToken did not correctly set the default refresh interval") + } + + spt.SetRefreshWithin(2 * defaultRefresh) + if spt.refreshWithin != 2*defaultRefresh { + t.Fatal("adal: ServicePrincipalToken#SetRefreshWithin did not set the refresh interval") + } +} + +func TestServicePrincipalTokenSetSender(t *testing.T) { + spt := newServicePrincipalToken() + + c := &http.Client{} + spt.SetSender(c) + if !reflect.DeepEqual(c, spt.sender) { + t.Fatal("adal: ServicePrincipalToken#SetSender did not set the sender") + } +} + +func TestServicePrincipalTokenRefreshUsesPOST(t *testing.T) { + spt := newServicePrincipalToken() + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + if r.Method != "POST" { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "POST", r.Method) + } + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } + + if body.IsOpen() { + t.Fatalf("the response was not closed!") + } +} + +func TestServicePrincipalTokenFromMSIRefreshUsesPOST(t *testing.T) { + resource := "https://resource" + cb := func(token Token) error { return nil } + + spt, err := NewServicePrincipalTokenFromMSI("http://msiendpoint/", resource, cb) + if err != nil { + t.Fatalf("Failed to get MSI SPT: %v", err) + } + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + if r.Method != "POST" { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set HTTP method -- expected %v, received %v", "POST", r.Method) + } + if h := r.Header.Get("Metadata"); h != "true" { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Metadata header for MSI") + } + return resp, nil + }) + } + })()) + spt.SetSender(s) + err = spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } + + if body.IsOpen() { + t.Fatalf("the response was not closed!") + } +} + +func TestServicePrincipalTokenRefreshSetsMimeType(t *testing.T) { + spt := newServicePrincipalToken() + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + if r.Header.Get(http.CanonicalHeaderKey("Content-Type")) != "application/x-www-form-urlencoded" { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set Content-Type -- expected %v, received %v", + "application/x-form-urlencoded", + r.Header.Get(http.CanonicalHeaderKey("Content-Type"))) + } + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } +} + +func TestServicePrincipalTokenRefreshSetsURL(t *testing.T) { + spt := newServicePrincipalToken() + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + if r.URL.String() != TestOAuthConfig.TokenEndpoint.String() { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the URL -- expected %v, received %v", + TestOAuthConfig.TokenEndpoint, r.URL) + } + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } +} + +func testServicePrincipalTokenRefreshSetsBody(t *testing.T, spt *ServicePrincipalToken, f func(*testing.T, []byte)) { + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("adal: Failed to read body of Service Principal token request (%v)", err) + } + f(t, b) + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } +} + +func TestServicePrincipalTokenManualRefreshSetsBody(t *testing.T) { + sptManual := newServicePrincipalTokenManual() + testServicePrincipalTokenRefreshSetsBody(t, sptManual, func(t *testing.T, b []byte) { + if string(b) != defaultManualFormData { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the HTTP Request Body -- expected %v, received %v", + defaultManualFormData, string(b)) + } + }) +} + +func TestServicePrincipalTokenCertficateRefreshSetsBody(t *testing.T) { + sptCert := newServicePrincipalTokenCertificate(t) + testServicePrincipalTokenRefreshSetsBody(t, sptCert, func(t *testing.T, b []byte) { + body := string(b) + + values, _ := url.ParseQuery(body) + if values["client_assertion_type"][0] != "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" || + values["client_id"][0] != "id" || + values["grant_type"][0] != "client_credentials" || + values["resource"][0] != "resource" { + t.Fatalf("adal: ServicePrincipalTokenCertificate#Refresh did not correctly set the HTTP Request Body.") + } + }) +} + +func TestServicePrincipalTokenUsernamePasswordRefreshSetsBody(t *testing.T) { + spt := newServicePrincipalTokenUsernamePassword(t) + testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) { + body := string(b) + + values, _ := url.ParseQuery(body) + if values["client_id"][0] != "id" || + values["grant_type"][0] != "password" || + values["username"][0] != "username" || + values["password"][0] != "password" || + values["resource"][0] != "resource" { + t.Fatalf("adal: ServicePrincipalTokenUsernamePassword#Refresh did not correctly set the HTTP Request Body.") + } + }) +} + +func TestServicePrincipalTokenAuthorizationCodeRefreshSetsBody(t *testing.T) { + spt := newServicePrincipalTokenAuthorizationCode(t) + testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) { + body := string(b) + + values, _ := url.ParseQuery(body) + if values["client_id"][0] != "id" || + values["grant_type"][0] != OAuthGrantTypeAuthorizationCode || + values["code"][0] != "code" || + values["client_secret"][0] != "clientSecret" || + values["redirect_uri"][0] != "http://redirectUri/getToken" || + values["resource"][0] != "resource" { + t.Fatalf("adal: ServicePrincipalTokenAuthorizationCode#Refresh did not correctly set the HTTP Request Body.") + } + }) +} + +func TestServicePrincipalTokenSecretRefreshSetsBody(t *testing.T) { + spt := newServicePrincipalToken() + testServicePrincipalTokenRefreshSetsBody(t, spt, func(t *testing.T, b []byte) { + if string(b) != defaultFormData { + t.Fatalf("adal: ServicePrincipalToken#Refresh did not correctly set the HTTP Request Body -- expected %v, received %v", + defaultFormData, string(b)) + } + + }) +} + +func TestServicePrincipalTokenRefreshClosesRequestBody(t *testing.T) { + spt := newServicePrincipalToken() + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } + if resp.Body.(*mocks.Body).IsOpen() { + t.Fatal("adal: ServicePrincipalToken#Refresh failed to close the HTTP Response Body") + } +} + +func TestServicePrincipalTokenRefreshRejectsResponsesWithStatusNotOK(t *testing.T) { + spt := newServicePrincipalToken() + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusUnauthorized, "Unauthorized") + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err == nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh should reject a response with status != %d", http.StatusOK) + } +} + +func TestServicePrincipalTokenRefreshRejectsEmptyBody(t *testing.T) { + spt := newServicePrincipalToken() + + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + return mocks.NewResponse(), nil + }) + } + })()) + spt.SetSender(s) + err := spt.Refresh() + if err == nil { + t.Fatal("adal: ServicePrincipalToken#Refresh should reject an empty token") + } +} + +func TestServicePrincipalTokenRefreshPropagatesErrors(t *testing.T) { + spt := newServicePrincipalToken() + + c := mocks.NewSender() + c.SetError(fmt.Errorf("Faux Error")) + spt.SetSender(c) + + err := spt.Refresh() + if err == nil { + t.Fatal("adal: Failed to propagate the request error") + } +} + +func TestServicePrincipalTokenRefreshReturnsErrorIfNotOk(t *testing.T) { + spt := newServicePrincipalToken() + + c := mocks.NewSender() + c.AppendResponse(mocks.NewResponseWithStatus("401 NotAuthorized", http.StatusUnauthorized)) + spt.SetSender(c) + + err := spt.Refresh() + if err == nil { + t.Fatalf("adal: Failed to return an when receiving a status code other than HTTP %d", http.StatusOK) + } +} + +func TestServicePrincipalTokenRefreshUnmarshals(t *testing.T) { + spt := newServicePrincipalToken() + + expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds())) + j := newTokenJSON(expiresOn, "resource") + resp := mocks.NewResponseWithContent(j) + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + return resp, nil + }) + } + })()) + spt.SetSender(s) + + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } else if spt.AccessToken != "accessToken" || + spt.ExpiresIn != "3600" || + spt.ExpiresOn != expiresOn || + spt.NotBefore != expiresOn || + spt.Resource != "resource" || + spt.Type != "Bearer" { + t.Fatalf("adal: ServicePrincipalToken#Refresh failed correctly unmarshal the JSON -- expected %v, received %v", + j, *spt) + } +} + +func TestServicePrincipalTokenEnsureFreshRefreshes(t *testing.T) { + spt := newServicePrincipalToken() + expireToken(&spt.Token) + + body := mocks.NewBody(newTokenJSON("test", "test")) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + + f := false + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + f = true + return resp, nil + }) + } + })()) + spt.SetSender(s) + err := spt.EnsureFresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err) + } + if !f { + t.Fatal("adal: ServicePrincipalToken#EnsureFresh failed to call Refresh for stale token") + } +} + +func TestServicePrincipalTokenEnsureFreshSkipsIfFresh(t *testing.T) { + spt := newServicePrincipalToken() + setTokenToExpireIn(&spt.Token, 1000*time.Second) + + f := false + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + f = true + return mocks.NewResponse(), nil + }) + } + })()) + spt.SetSender(s) + err := spt.EnsureFresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#EnsureFresh returned an unexpected error (%v)", err) + } + if f { + t.Fatal("adal: ServicePrincipalToken#EnsureFresh invoked Refresh for fresh token") + } +} + +func TestRefreshCallback(t *testing.T) { + callbackTriggered := false + spt := newServicePrincipalToken(func(Token) error { + callbackTriggered = true + return nil + }) + + expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds())) + + sender := mocks.NewSender() + j := newTokenJSON(expiresOn, "resource") + sender.AppendResponse(mocks.NewResponseWithContent(j)) + spt.SetSender(sender) + err := spt.Refresh() + if err != nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh returned an unexpected error (%v)", err) + } + if !callbackTriggered { + t.Fatalf("adal: RefreshCallback failed to trigger call callback") + } +} + +func TestRefreshCallbackErrorPropagates(t *testing.T) { + errorText := "this is an error text" + spt := newServicePrincipalToken(func(Token) error { + return fmt.Errorf(errorText) + }) + + expiresOn := strconv.Itoa(int(time.Now().Add(3600 * time.Second).Sub(date.UnixEpoch()).Seconds())) + + sender := mocks.NewSender() + j := newTokenJSON(expiresOn, "resource") + sender.AppendResponse(mocks.NewResponseWithContent(j)) + spt.SetSender(sender) + err := spt.Refresh() + + if err == nil || !strings.Contains(err.Error(), errorText) { + t.Fatalf("adal: RefreshCallback failed to propagate error") + } +} + +// This demonstrates the danger of manual token without a refresh token +func TestServicePrincipalTokenManualRefreshFailsWithoutRefresh(t *testing.T) { + spt := newServicePrincipalTokenManual() + spt.RefreshToken = "" + err := spt.Refresh() + if err == nil { + t.Fatalf("adal: ServicePrincipalToken#Refresh should have failed with a ManualTokenSecret without a refresh token") + } +} + +func TestNewServicePrincipalTokenFromMSI(t *testing.T) { + resource := "https://resource" + cb := func(token Token) error { return nil } + + spt, err := NewServicePrincipalTokenFromMSI("http://msiendpoint/", resource, cb) + if err != nil { + t.Fatalf("Failed to get MSI SPT: %v", err) + } + + // check some of the SPT fields + if _, ok := spt.secret.(*ServicePrincipalMSISecret); !ok { + t.Fatal("SPT secret was not of MSI type") + } + + if spt.resource != resource { + t.Fatal("SPT came back with incorrect resource") + } + + if len(spt.refreshCallbacks) != 1 { + t.Fatal("SPT had incorrect refresh callbacks.") + } +} + +func TestNewServicePrincipalTokenFromMSIWithUserAssignedID(t *testing.T) { + resource := "https://resource" + userID := "abc123" + cb := func(token Token) error { return nil } + + spt, err := NewServicePrincipalTokenFromMSIWithUserAssignedID("http://msiendpoint/", resource, userID, cb) + if err != nil { + t.Fatalf("Failed to get MSI SPT: %v", err) + } + + // check some of the SPT fields + if _, ok := spt.secret.(*ServicePrincipalMSISecret); !ok { + t.Fatal("SPT secret was not of MSI type") + } + + if spt.resource != resource { + t.Fatal("SPT came back with incorrect resource") + } + + if len(spt.refreshCallbacks) != 1 { + t.Fatal("SPT had incorrect refresh callbacks.") + } + + if spt.clientID != userID { + t.Fatal("SPT had incorrect client ID") + } +} + +func TestGetVMEndpoint(t *testing.T) { + tempSettingsFile, err := ioutil.TempFile("", "ManagedIdentity-Settings") + if err != nil { + t.Fatal("Couldn't write temp settings file") + } + defer os.Remove(tempSettingsFile.Name()) + + settingsContents := []byte(`{ + "url": "http://msiendpoint/" + }`) + + if _, err := tempSettingsFile.Write(settingsContents); err != nil { + t.Fatal("Couldn't fill temp settings file") + } + + endpoint, err := getMSIVMEndpoint(tempSettingsFile.Name()) + if err != nil { + t.Fatal("Coudn't get VM endpoint") + } + + if endpoint != "http://msiendpoint/" { + t.Fatal("Didn't get correct endpoint") + } +} + +func newToken() *Token { + return &Token{ + AccessToken: "ASECRETVALUE", + Resource: "https://azure.microsoft.com/", + Type: "Bearer", + } +} + +func newTokenJSON(expiresOn string, resource string) string { + return fmt.Sprintf(`{ + "access_token" : "accessToken", + "expires_in" : "3600", + "expires_on" : "%s", + "not_before" : "%s", + "resource" : "%s", + "token_type" : "Bearer" + }`, + expiresOn, expiresOn, resource) +} + +func newTokenExpiresIn(expireIn time.Duration) *Token { + return setTokenToExpireIn(newToken(), expireIn) +} + +func newTokenExpiresAt(expireAt time.Time) *Token { + return setTokenToExpireAt(newToken(), expireAt) +} + +func expireToken(t *Token) *Token { + return setTokenToExpireIn(t, 0) +} + +func setTokenToExpireAt(t *Token, expireAt time.Time) *Token { + t.ExpiresIn = "3600" + t.ExpiresOn = strconv.Itoa(int(expireAt.Sub(date.UnixEpoch()).Seconds())) + t.NotBefore = t.ExpiresOn + return t +} + +func setTokenToExpireIn(t *Token, expireIn time.Duration) *Token { + return setTokenToExpireAt(t, time.Now().Add(expireIn)) +} + +func newServicePrincipalToken(callbacks ...TokenRefreshCallback) *ServicePrincipalToken { + spt, _ := NewServicePrincipalToken(TestOAuthConfig, "id", "secret", "resource", callbacks...) + return spt +} + +func newServicePrincipalTokenManual() *ServicePrincipalToken { + token := newToken() + token.RefreshToken = "refreshtoken" + spt, _ := NewServicePrincipalTokenFromManualToken(TestOAuthConfig, "id", "resource", *token) + return spt +} + +func newServicePrincipalTokenCertificate(t *testing.T) *ServicePrincipalToken { + template := x509.Certificate{ + SerialNumber: big.NewInt(0), + Subject: pkix.Name{CommonName: "test"}, + BasicConstraintsValid: true, + } + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + certificateBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) + if err != nil { + t.Fatal(err) + } + certificate, err := x509.ParseCertificate(certificateBytes) + if err != nil { + t.Fatal(err) + } + + spt, _ := NewServicePrincipalTokenFromCertificate(TestOAuthConfig, "id", certificate, privateKey, "resource") + return spt +} + +func newServicePrincipalTokenUsernamePassword(t *testing.T) *ServicePrincipalToken { + spt, _ := NewServicePrincipalTokenFromUsernamePassword(TestOAuthConfig, "id", "username", "password", "resource") + return spt +} + +func newServicePrincipalTokenAuthorizationCode(t *testing.T) *ServicePrincipalToken { + spt, _ := NewServicePrincipalTokenFromAuthorizationCode(TestOAuthConfig, "id", "clientSecret", "code", "http://redirectUri/getToken", "resource") + return spt +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/authorization_test.go b/vendor/github.com/Azure/go-autorest/autorest/authorization_test.go new file mode 100644 index 000000000..6fae544cd --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/authorization_test.go @@ -0,0 +1,230 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "fmt" + "net/http" + "reflect" + "testing" + + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/mocks" +) + +const ( + TestTenantID = "TestTenantID" + TestActiveDirectoryEndpoint = "https://login/test.com/" +) + +func TestWithAuthorizer(t *testing.T) { + r1 := mocks.NewRequest() + + na := &NullAuthorizer{} + r2, err := Prepare(r1, + na.WithAuthorization()) + if err != nil { + t.Fatalf("autorest: NullAuthorizer#WithAuthorization returned an unexpected error (%v)", err) + } else if !reflect.DeepEqual(r1, r2) { + t.Fatalf("autorest: NullAuthorizer#WithAuthorization modified the request -- received %v, expected %v", r2, r1) + } +} + +func TestTokenWithAuthorization(t *testing.T) { + token := &adal.Token{ + AccessToken: "TestToken", + Resource: "https://azure.microsoft.com/", + Type: "Bearer", + } + + ba := NewBearerAuthorizer(token) + req, err := Prepare(&http.Request{}, ba.WithAuthorization()) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", token.AccessToken) { + t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header") + } +} + +func TestServicePrincipalTokenWithAuthorizationNoRefresh(t *testing.T) { + oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } + spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", nil) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } + spt.SetAutoRefresh(false) + s := mocks.NewSender() + spt.SetSender(s) + + ba := NewBearerAuthorizer(spt) + req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization()) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.AccessToken) { + t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header") + } +} + +func TestServicePrincipalTokenWithAuthorizationRefresh(t *testing.T) { + + oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } + refreshed := false + spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", func(t adal.Token) error { + refreshed = true + return nil + }) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } + + jwt := `{ + "access_token" : "accessToken", + "expires_in" : "3600", + "expires_on" : "test", + "not_before" : "test", + "resource" : "test", + "token_type" : "Bearer" + }` + body := mocks.NewBody(jwt) + resp := mocks.NewResponseWithBodyAndStatus(body, http.StatusOK, "OK") + c := mocks.NewSender() + s := DecorateSender(c, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + return resp, nil + }) + } + })()) + spt.SetSender(s) + + ba := NewBearerAuthorizer(spt) + req, err := Prepare(mocks.NewRequest(), ba.WithAuthorization()) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } else if req.Header.Get(http.CanonicalHeaderKey("Authorization")) != fmt.Sprintf("Bearer %s", spt.AccessToken) { + t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to set Authorization header") + } + + if !refreshed { + t.Fatal("azure: BearerAuthorizer#WithAuthorization must refresh the token") + } +} + +func TestServicePrincipalTokenWithAuthorizationReturnsErrorIfConnotRefresh(t *testing.T) { + oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, TestTenantID) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } + spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", "resource", nil) + if err != nil { + t.Fatalf("azure: BearerAuthorizer#WithAuthorization returned an error (%v)", err) + } + + s := mocks.NewSender() + s.AppendResponse(mocks.NewResponseWithStatus("400 Bad Request", http.StatusBadRequest)) + spt.SetSender(s) + + ba := NewBearerAuthorizer(spt) + _, err = Prepare(mocks.NewRequest(), ba.WithAuthorization()) + if err == nil { + t.Fatal("azure: BearerAuthorizer#WithAuthorization failed to return an error when refresh fails") + } +} + +func TestBearerAuthorizerCallback(t *testing.T) { + tenantString := "123-tenantID-456" + resourceString := "https://fake.resource.net" + + s := mocks.NewSender() + resp := mocks.NewResponseWithStatus("401 Unauthorized", http.StatusUnauthorized) + mocks.SetResponseHeader(resp, bearerChallengeHeader, bearer+" \"authorization\"=\"https://fake.net/"+tenantString+"\",\"resource\"=\""+resourceString+"\"") + s.AppendResponse(resp) + + auth := NewBearerAuthorizerCallback(s, func(tenantID, resource string) (*BearerAuthorizer, error) { + if tenantID != tenantString { + t.Fatal("BearerAuthorizerCallback: bad tenant ID") + } + if resource != resourceString { + t.Fatal("BearerAuthorizerCallback: bad resource") + } + + oauthConfig, err := adal.NewOAuthConfig(TestActiveDirectoryEndpoint, tenantID) + if err != nil { + t.Fatalf("azure: NewOAuthConfig returned an error (%v)", err) + } + + spt, err := adal.NewServicePrincipalToken(*oauthConfig, "id", "secret", resource) + if err != nil { + t.Fatalf("azure: NewServicePrincipalToken returned an error (%v)", err) + } + + spt.SetSender(s) + return NewBearerAuthorizer(spt), nil + }) + + _, err := Prepare(mocks.NewRequest(), auth.WithAuthorization()) + if err == nil { + t.Fatal("azure: BearerAuthorizerCallback#WithAuthorization failed to return an error when refresh fails") + } +} + +func TestApiKeyAuthorization(t *testing.T) { + + headers := make(map[string]interface{}) + queryParameters := make(map[string]interface{}) + + dummyAuthHeader := "dummyAuthHeader" + dummyAuthHeaderValue := "dummyAuthHeaderValue" + + dummyAuthQueryParameter := "dummyAuthQueryParameter" + dummyAuthQueryParameterValue := "dummyAuthQueryParameterValue" + + headers[dummyAuthHeader] = dummyAuthHeaderValue + queryParameters[dummyAuthQueryParameter] = dummyAuthQueryParameterValue + + aka := NewAPIKeyAuthorizer(headers, queryParameters) + + req, err := Prepare(mocks.NewRequest(), aka.WithAuthorization()) + + if err != nil { + t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization returned an error (%v)", err) + } else if req.Header.Get(http.CanonicalHeaderKey(dummyAuthHeader)) != dummyAuthHeaderValue { + t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization failed to set %s header", dummyAuthHeader) + + } else if req.URL.Query().Get(dummyAuthQueryParameter) != dummyAuthQueryParameterValue { + t.Fatalf("azure: APIKeyAuthorizer#WithAuthorization failed to set %s query parameter", dummyAuthQueryParameterValue) + } +} + +func TestCognitivesServicesAuthorization(t *testing.T) { + subscriptionKey := "dummyKey" + csa := NewCognitiveServicesAuthorizer(subscriptionKey) + req, err := Prepare(mocks.NewRequest(), csa.WithAuthorization()) + + if err != nil { + t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization returned an error (%v)", err) + } else if req.Header.Get(http.CanonicalHeaderKey(bingAPISdkHeader)) != golangBingAPISdkHeaderValue { + t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization failed to set %s header", bingAPISdkHeader) + } else if req.Header.Get(http.CanonicalHeaderKey(apiKeyAuthorizerHeader)) != subscriptionKey { + t.Fatalf("azure: CognitiveServicesAuthorizer#WithAuthorization failed to set %s header", apiKeyAuthorizerHeader) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/autorest_test.go b/vendor/github.com/Azure/go-autorest/autorest/autorest_test.go new file mode 100644 index 000000000..467ea438b --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/autorest_test.go @@ -0,0 +1,140 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "net/http" + "testing" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +func TestResponseHasStatusCode(t *testing.T) { + codes := []int{http.StatusOK, http.StatusAccepted} + resp := &http.Response{StatusCode: http.StatusAccepted} + if !ResponseHasStatusCode(resp, codes...) { + t.Fatalf("autorest: ResponseHasStatusCode failed to find %v in %v", resp.StatusCode, codes) + } +} + +func TestResponseHasStatusCodeNotPresent(t *testing.T) { + codes := []int{http.StatusOK, http.StatusAccepted} + resp := &http.Response{StatusCode: http.StatusInternalServerError} + if ResponseHasStatusCode(resp, codes...) { + t.Fatalf("autorest: ResponseHasStatusCode unexpectedly found %v in %v", resp.StatusCode, codes) + } +} + +func TestNewPollingRequestDoesNotReturnARequestWhenLocationHeaderIsMissing(t *testing.T) { + resp := mocks.NewResponseWithStatus("500 InternalServerError", http.StatusInternalServerError) + + req, _ := NewPollingRequest(resp, nil) + if req != nil { + t.Fatal("autorest: NewPollingRequest returned an http.Request when the Location header was missing") + } +} + +func TestNewPollingRequestReturnsAnErrorWhenPrepareFails(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + resp.Header.Set(http.CanonicalHeaderKey(HeaderLocation), mocks.TestBadURL) + + _, err := NewPollingRequest(resp, nil) + if err == nil { + t.Fatal("autorest: NewPollingRequest failed to return an error when Prepare fails") + } +} + +func TestNewPollingRequestDoesNotReturnARequestWhenPrepareFails(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + resp.Header.Set(http.CanonicalHeaderKey(HeaderLocation), mocks.TestBadURL) + + req, _ := NewPollingRequest(resp, nil) + if req != nil { + t.Fatal("autorest: NewPollingRequest returned an http.Request when Prepare failed") + } +} + +func TestNewPollingRequestReturnsAGetRequest(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + + req, _ := NewPollingRequest(resp, nil) + if req.Method != "GET" { + t.Fatalf("autorest: NewPollingRequest did not create an HTTP GET request -- actual method %v", req.Method) + } +} + +func TestNewPollingRequestProvidesTheURL(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + + req, _ := NewPollingRequest(resp, nil) + if req.URL.String() != mocks.TestURL { + t.Fatalf("autorest: NewPollingRequest did not create an HTTP with the expected URL -- received %v, expected %v", req.URL, mocks.TestURL) + } +} + +func TestGetLocation(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + + l := GetLocation(resp) + if len(l) == 0 { + t.Fatalf("autorest: GetLocation failed to return Location header -- expected %v, received %v", mocks.TestURL, l) + } +} + +func TestGetLocationReturnsEmptyStringForMissingLocation(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + + l := GetLocation(resp) + if len(l) != 0 { + t.Fatalf("autorest: GetLocation return a value without a Location header -- received %v", l) + } +} + +func TestGetRetryAfter(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + + d := GetRetryAfter(resp, DefaultPollingDelay) + if d != mocks.TestDelay { + t.Fatalf("autorest: GetRetryAfter failed to returned the expected delay -- expected %v, received %v", mocks.TestDelay, d) + } +} + +func TestGetRetryAfterReturnsDefaultDelayIfRetryHeaderIsMissing(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + + d := GetRetryAfter(resp, DefaultPollingDelay) + if d != DefaultPollingDelay { + t.Fatalf("autorest: GetRetryAfter failed to returned the default delay for a missing Retry-After header -- expected %v, received %v", + DefaultPollingDelay, d) + } +} + +func TestGetRetryAfterReturnsDefaultDelayIfRetryHeaderIsMalformed(t *testing.T) { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + resp.Header.Set(http.CanonicalHeaderKey(HeaderRetryAfter), "a very bad non-integer value") + + d := GetRetryAfter(resp, DefaultPollingDelay) + if d != DefaultPollingDelay { + t.Fatalf("autorest: GetRetryAfter failed to returned the default delay for a malformed Retry-After header -- expected %v, received %v", + DefaultPollingDelay, d) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/async_test.go b/vendor/github.com/Azure/go-autorest/autorest/azure/async_test.go new file mode 100644 index 000000000..5757e25c2 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/async_test.go @@ -0,0 +1,1327 @@ +package azure + +// Copyright 2017 Microsoft 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. + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "reflect" + "strings" + "sync" + "testing" + "time" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/mocks" +) + +func TestGetAsyncOperation_ReturnsAzureAsyncOperationHeader(t *testing.T) { + r := newAsynchronousResponse() + + if getAsyncOperation(r) != mocks.TestAzureAsyncURL { + t.Fatalf("azure: getAsyncOperation failed to extract the Azure-AsyncOperation header -- expected %v, received %v", mocks.TestURL, getAsyncOperation(r)) + } +} + +func TestGetAsyncOperation_ReturnsEmptyStringIfHeaderIsAbsent(t *testing.T) { + r := mocks.NewResponse() + + if len(getAsyncOperation(r)) != 0 { + t.Fatalf("azure: getAsyncOperation failed to return empty string when the Azure-AsyncOperation header is absent -- received %v", getAsyncOperation(r)) + } +} + +func TestHasSucceeded_ReturnsTrueForSuccess(t *testing.T) { + if !hasSucceeded(operationSucceeded) { + t.Fatal("azure: hasSucceeded failed to return true for success") + } +} + +func TestHasSucceeded_ReturnsFalseOtherwise(t *testing.T) { + if hasSucceeded("not a success string") { + t.Fatal("azure: hasSucceeded returned true for a non-success") + } +} + +func TestHasTerminated_ReturnsTrueForValidTerminationStates(t *testing.T) { + for _, state := range []string{operationSucceeded, operationCanceled, operationFailed} { + if !hasTerminated(state) { + t.Fatalf("azure: hasTerminated failed to return true for the '%s' state", state) + } + } +} + +func TestHasTerminated_ReturnsFalseForUnknownStates(t *testing.T) { + if hasTerminated("not a known state") { + t.Fatal("azure: hasTerminated returned true for an unknown state") + } +} + +func TestOperationError_ErrorReturnsAString(t *testing.T) { + s := (ServiceError{Code: "server code", Message: "server error"}).Error() + if s == "" { + t.Fatalf("azure: operationError#Error failed to return an error") + } + if !strings.Contains(s, "server code") || !strings.Contains(s, "server error") { + t.Fatalf("azure: operationError#Error returned a malformed error -- error='%v'", s) + } +} + +func TestOperationResource_StateReturnsState(t *testing.T) { + if (operationResource{Status: "state"}).state() != "state" { + t.Fatalf("azure: operationResource#state failed to return the correct state") + } +} + +func TestOperationResource_HasSucceededReturnsFalseIfNotSuccess(t *testing.T) { + if (operationResource{Status: "not a success string"}).hasSucceeded() { + t.Fatalf("azure: operationResource#hasSucceeded failed to return false for a canceled operation") + } +} + +func TestOperationResource_HasSucceededReturnsTrueIfSuccessful(t *testing.T) { + if !(operationResource{Status: operationSucceeded}).hasSucceeded() { + t.Fatalf("azure: operationResource#hasSucceeded failed to return true for a successful operation") + } +} + +func TestOperationResource_HasTerminatedReturnsTrueForKnownStates(t *testing.T) { + for _, state := range []string{operationSucceeded, operationCanceled, operationFailed} { + if !(operationResource{Status: state}).hasTerminated() { + t.Fatalf("azure: operationResource#hasTerminated failed to return true for the '%s' state", state) + } + } +} + +func TestOperationResource_HasTerminatedReturnsFalseForUnknownStates(t *testing.T) { + if (operationResource{Status: "not a known state"}).hasTerminated() { + t.Fatalf("azure: operationResource#hasTerminated returned true for a non-terminal operation") + } +} + +func TestProvisioningStatus_StateReturnsState(t *testing.T) { + if (provisioningStatus{Properties: provisioningProperties{"state"}}).state() != "state" { + t.Fatalf("azure: provisioningStatus#state failed to return the correct state") + } +} + +func TestProvisioningStatus_HasSucceededReturnsFalseIfNotSuccess(t *testing.T) { + if (provisioningStatus{Properties: provisioningProperties{"not a success string"}}).hasSucceeded() { + t.Fatalf("azure: provisioningStatus#hasSucceeded failed to return false for a canceled operation") + } +} + +func TestProvisioningStatus_HasSucceededReturnsTrueIfSuccessful(t *testing.T) { + if !(provisioningStatus{Properties: provisioningProperties{operationSucceeded}}).hasSucceeded() { + t.Fatalf("azure: provisioningStatus#hasSucceeded failed to return true for a successful operation") + } +} + +func TestProvisioningStatus_HasTerminatedReturnsTrueForKnownStates(t *testing.T) { + for _, state := range []string{operationSucceeded, operationCanceled, operationFailed} { + if !(provisioningStatus{Properties: provisioningProperties{state}}).hasTerminated() { + t.Fatalf("azure: provisioningStatus#hasTerminated failed to return true for the '%s' state", state) + } + } +} + +func TestProvisioningStatus_HasTerminatedReturnsFalseForUnknownStates(t *testing.T) { + if (provisioningStatus{Properties: provisioningProperties{"not a known state"}}).hasTerminated() { + t.Fatalf("azure: provisioningStatus#hasTerminated returned true for a non-terminal operation") + } +} + +func TestPollingState_HasSucceededReturnsFalseIfNotSuccess(t *testing.T) { + if (pollingState{State: "not a success string"}).hasSucceeded() { + t.Fatalf("azure: pollingState#hasSucceeded failed to return false for a canceled operation") + } +} + +func TestPollingState_HasSucceededReturnsTrueIfSuccessful(t *testing.T) { + if !(pollingState{State: operationSucceeded}).hasSucceeded() { + t.Fatalf("azure: pollingState#hasSucceeded failed to return true for a successful operation") + } +} + +func TestPollingState_HasTerminatedReturnsTrueForKnownStates(t *testing.T) { + for _, state := range []string{operationSucceeded, operationCanceled, operationFailed} { + if !(pollingState{State: state}).hasTerminated() { + t.Fatalf("azure: pollingState#hasTerminated failed to return true for the '%s' state", state) + } + } +} + +func TestPollingState_HasTerminatedReturnsFalseForUnknownStates(t *testing.T) { + if (pollingState{State: "not a known state"}).hasTerminated() { + t.Fatalf("azure: pollingState#hasTerminated returned true for a non-terminal operation") + } +} + +func TestUpdatePollingState_ReturnsAnErrorIfOneOccurs(t *testing.T) { + resp := mocks.NewResponseWithContent(operationResourceIllegal) + err := updatePollingState(resp, &pollingState{}) + if err == nil { + t.Fatalf("azure: updatePollingState failed to return an error after a JSON parsing error") + } +} + +func TestUpdatePollingState_ReturnsTerminatedForKnownProvisioningStates(t *testing.T) { + for _, state := range []string{operationSucceeded, operationCanceled, operationFailed} { + resp := mocks.NewResponseWithContent(fmt.Sprintf(pollingStateFormat, state)) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if !ps.hasTerminated() { + t.Fatalf("azure: updatePollingState failed to return a terminating pollingState for the '%s' state", state) + } + } +} + +func TestUpdatePollingState_ReturnsSuccessForSuccessfulProvisioningState(t *testing.T) { + resp := mocks.NewResponseWithContent(fmt.Sprintf(pollingStateFormat, operationSucceeded)) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if !ps.hasSucceeded() { + t.Fatalf("azure: updatePollingState failed to return a successful pollingState for the '%s' state", operationSucceeded) + } +} + +func TestUpdatePollingState_ReturnsInProgressForAllOtherProvisioningStates(t *testing.T) { + s := "not a recognized state" + resp := mocks.NewResponseWithContent(fmt.Sprintf(pollingStateFormat, s)) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if ps.hasTerminated() { + t.Fatalf("azure: updatePollingState returned terminated for unknown state '%s'", s) + } +} + +func TestUpdatePollingState_ReturnsSuccessWhenProvisioningStateFieldIsAbsentForSuccessStatusCodes(t *testing.T) { + for _, sc := range []int{http.StatusOK, http.StatusCreated, http.StatusNoContent} { + resp := mocks.NewResponseWithContent(pollingStateEmpty) + resp.StatusCode = sc + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if !ps.hasSucceeded() { + t.Fatalf("azure: updatePollingState failed to return success when the provisionState field is absent for Status Code %d", sc) + } + } +} + +func TestUpdatePollingState_ReturnsInProgressWhenProvisioningStateFieldIsAbsentForAccepted(t *testing.T) { + resp := mocks.NewResponseWithContent(pollingStateEmpty) + resp.StatusCode = http.StatusAccepted + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if ps.hasTerminated() { + t.Fatalf("azure: updatePollingState returned terminated when the provisionState field is absent for Status Code Accepted") + } +} + +func TestUpdatePollingState_ReturnsFailedWhenProvisioningStateFieldIsAbsentForUnknownStatusCodes(t *testing.T) { + resp := mocks.NewResponseWithContent(pollingStateEmpty) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if !ps.hasTerminated() || ps.hasSucceeded() { + t.Fatalf("azure: updatePollingState did not return failed when the provisionState field is absent for an unknown Status Code") + } +} + +func TestUpdatePollingState_ReturnsTerminatedForKnownOperationResourceStates(t *testing.T) { + for _, state := range []string{operationSucceeded, operationCanceled, operationFailed} { + resp := mocks.NewResponseWithContent(fmt.Sprintf(operationResourceFormat, state)) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingAsyncOperation} + updatePollingState(resp, ps) + if !ps.hasTerminated() { + t.Fatalf("azure: updatePollingState failed to return a terminating pollingState for the '%s' state", state) + } + } +} + +func TestUpdatePollingState_ReturnsSuccessForSuccessfulOperationResourceState(t *testing.T) { + resp := mocks.NewResponseWithContent(fmt.Sprintf(operationResourceFormat, operationSucceeded)) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingAsyncOperation} + updatePollingState(resp, ps) + if !ps.hasSucceeded() { + t.Fatalf("azure: updatePollingState failed to return a successful pollingState for the '%s' state", operationSucceeded) + } +} + +func TestUpdatePollingState_ReturnsInProgressForAllOtherOperationResourceStates(t *testing.T) { + s := "not a recognized state" + resp := mocks.NewResponseWithContent(fmt.Sprintf(operationResourceFormat, s)) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingAsyncOperation} + updatePollingState(resp, ps) + if ps.hasTerminated() { + t.Fatalf("azure: updatePollingState returned terminated for unknown state '%s'", s) + } +} + +func TestUpdatePollingState_CopiesTheResponseBody(t *testing.T) { + s := fmt.Sprintf(pollingStateFormat, operationSucceeded) + resp := mocks.NewResponseWithContent(s) + resp.StatusCode = 42 + ps := &pollingState{PollingMethod: PollingAsyncOperation} + updatePollingState(resp, ps) + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatalf("azure: updatePollingState failed to replace the http.Response Body -- Error='%v'", err) + } + if string(b) != s { + t.Fatalf("azure: updatePollingState failed to copy the http.Response Body -- Expected='%s' Received='%s'", s, string(b)) + } +} + +func TestUpdatePollingState_ClosesTheOriginalResponseBody(t *testing.T) { + resp := mocks.NewResponse() + b := resp.Body.(*mocks.Body) + ps := &pollingState{PollingMethod: PollingLocation} + updatePollingState(resp, ps) + if b.IsOpen() { + t.Fatal("azure: updatePollingState failed to close the original http.Response Body") + } +} + +func TestUpdatePollingState_FailsWhenResponseLacksRequest(t *testing.T) { + resp := newAsynchronousResponse() + resp.Request = nil + + ps := pollingState{} + err := updatePollingState(resp, &ps) + if err == nil { + t.Fatal("azure: updatePollingState failed to return an error when the http.Response lacked the original http.Request") + } +} + +func TestUpdatePollingState_SetsThePollingMethodWhenUsingTheAzureAsyncOperationHeader(t *testing.T) { + ps := pollingState{} + updatePollingState(newAsynchronousResponse(), &ps) + + if ps.PollingMethod != PollingAsyncOperation { + t.Fatal("azure: updatePollingState failed to set the correct response format when using the Azure-AsyncOperation header") + } +} + +func TestUpdatePollingState_SetsThePollingMethodWhenUsingTheAzureAsyncOperationHeaderIsMissing(t *testing.T) { + resp := newAsynchronousResponse() + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + ps := pollingState{} + updatePollingState(resp, &ps) + + if ps.PollingMethod != PollingLocation { + t.Fatal("azure: updatePollingState failed to set the correct response format when the Azure-AsyncOperation header is absent") + } +} + +func TestUpdatePollingState_DoesNotChangeAnExistingReponseFormat(t *testing.T) { + resp := newAsynchronousResponse() + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + ps := pollingState{PollingMethod: PollingAsyncOperation} + updatePollingState(resp, &ps) + + if ps.PollingMethod != PollingAsyncOperation { + t.Fatal("azure: updatePollingState failed to leave an existing response format setting") + } +} + +func TestUpdatePollingState_PrefersTheAzureAsyncOperationHeader(t *testing.T) { + resp := newAsynchronousResponse() + + ps := pollingState{} + updatePollingState(resp, &ps) + + if ps.URI != mocks.TestAzureAsyncURL { + t.Fatal("azure: updatePollingState failed to prefer the Azure-AsyncOperation header") + } +} + +func TestUpdatePollingState_PrefersLocationWhenTheAzureAsyncOperationHeaderMissing(t *testing.T) { + resp := newAsynchronousResponse() + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + ps := pollingState{} + updatePollingState(resp, &ps) + + if ps.URI != mocks.TestLocationURL { + t.Fatal("azure: updatePollingState failed to prefer the Location header when the Azure-AsyncOperation header is missing") + } +} + +func TestUpdatePollingState_UsesTheObjectLocationIfAsyncHeadersAreMissing(t *testing.T) { + resp := newAsynchronousResponse() + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + resp.Header.Del(http.CanonicalHeaderKey(autorest.HeaderLocation)) + resp.Request.Method = http.MethodPatch + + ps := pollingState{} + updatePollingState(resp, &ps) + + if ps.URI != mocks.TestURL { + t.Fatal("azure: updatePollingState failed to use the Object URL when the asynchronous headers are missing") + } +} + +func TestUpdatePollingState_RecognizesLowerCaseHTTPVerbs(t *testing.T) { + for _, m := range []string{strings.ToLower(http.MethodPatch), strings.ToLower(http.MethodPut), strings.ToLower(http.MethodGet)} { + resp := newAsynchronousResponse() + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + resp.Header.Del(http.CanonicalHeaderKey(autorest.HeaderLocation)) + resp.Request.Method = m + + ps := pollingState{} + updatePollingState(resp, &ps) + + if ps.URI != mocks.TestURL { + t.Fatalf("azure: updatePollingState failed to recognize the lower-case HTTP verb '%s'", m) + } + } +} + +func TestUpdatePollingState_ReturnsAnErrorIfAsyncHeadersAreMissingForANewOrDeletedObject(t *testing.T) { + resp := newAsynchronousResponse() + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + resp.Header.Del(http.CanonicalHeaderKey(autorest.HeaderLocation)) + + for _, m := range []string{http.MethodDelete, http.MethodPost} { + resp.Request.Method = m + err := updatePollingState(resp, &pollingState{}) + if err == nil { + t.Fatalf("azure: updatePollingState failed to return an error even though it could not determine the polling URL for Method '%s'", m) + } + } +} + +func TestNewPollingRequest_ReturnsAnErrorWhenPrepareFails(t *testing.T) { + _, err := newPollingRequest(pollingState{PollingMethod: PollingAsyncOperation, URI: mocks.TestBadURL}) + if err == nil { + t.Fatal("azure: newPollingRequest failed to return an error when Prepare fails") + } +} + +func TestNewPollingRequest_DoesNotReturnARequestWhenPrepareFails(t *testing.T) { + req, _ := newPollingRequest(pollingState{PollingMethod: PollingAsyncOperation, URI: mocks.TestBadURL}) + if req != nil { + t.Fatal("azure: newPollingRequest returned an http.Request when Prepare failed") + } +} + +func TestNewPollingRequest_ReturnsAGetRequest(t *testing.T) { + req, _ := newPollingRequest(pollingState{PollingMethod: PollingAsyncOperation, URI: mocks.TestAzureAsyncURL}) + if req.Method != "GET" { + t.Fatalf("azure: newPollingRequest did not create an HTTP GET request -- actual method %v", req.Method) + } +} + +func TestDoPollForAsynchronous_IgnoresUnspecifiedStatusCodes(t *testing.T) { + client := mocks.NewSender() + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Duration(0))) + + if client.Attempts() != 1 { + t.Fatalf("azure: DoPollForAsynchronous polled for unspecified status code") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsForSpecifiedStatusCodes(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(newAsynchronousResponse()) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() != 2 { + t.Fatalf("azure: DoPollForAsynchronous failed to poll for specified status code") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_CanBeCanceled(t *testing.T) { + cancel := make(chan struct{}) + delay := 5 * time.Second + + r1 := newAsynchronousResponse() + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(newOperationResourceResponse("Busy"), -1) + + var wg sync.WaitGroup + wg.Add(1) + start := time.Now() + go func() { + req := mocks.NewRequest() + req.Cancel = cancel + + wg.Done() + + r, _ := autorest.SendWithSender(client, req, + DoPollForAsynchronous(10*time.Second)) + autorest.Respond(r, + autorest.ByClosing()) + }() + wg.Wait() + close(cancel) + time.Sleep(5 * time.Millisecond) + if time.Since(start) >= delay { + t.Fatalf("azure: DoPollForAsynchronous failed to cancel") + } +} + +func TestDoPollForAsynchronous_ClosesAllNonreturnedResponseBodiesWhenPolling(t *testing.T) { + r1 := newAsynchronousResponse() + b1 := r1.Body.(*mocks.Body) + r2 := newOperationResourceResponse("busy") + b2 := r2.Body.(*mocks.Body) + r3 := newOperationResourceResponse(operationSucceeded) + b3 := r3.Body.(*mocks.Body) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendResponse(r3) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if b1.IsOpen() || b2.IsOpen() || b3.IsOpen() { + t.Fatalf("azure: DoPollForAsynchronous did not close unreturned response bodies") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_LeavesLastResponseBodyOpen(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse(operationSucceeded) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendResponse(r3) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + b, err := ioutil.ReadAll(r.Body) + if len(b) <= 0 || err != nil { + t.Fatalf("azure: DoPollForAsynchronous did not leave open the body of the last response - Error='%v'", err) + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_DoesNotPollIfOriginalRequestReturnedAnError(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendResponse(r2) + client.SetError(fmt.Errorf("Faux Error")) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() != 1 { + t.Fatalf("azure: DoPollForAsynchronous tried to poll after receiving an error") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_DoesNotPollIfCreatingOperationRequestFails(t *testing.T) { + r1 := newAsynchronousResponse() + mocks.SetResponseHeader(r1, http.CanonicalHeaderKey(headerAsyncOperation), mocks.TestBadURL) + r2 := newOperationResourceResponse("busy") + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() > 1 { + t.Fatalf("azure: DoPollForAsynchronous polled with an invalidly formed operation request") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_StopsPollingAfterAnError(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.SetError(fmt.Errorf("Faux Error")) + client.SetEmitErrorAfter(2) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() > 3 { + t.Fatalf("azure: DoPollForAsynchronous failed to stop polling after receiving an error") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsPollingError(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(newAsynchronousResponse(), 5) + client.SetError(fmt.Errorf("Faux Error")) + client.SetEmitErrorAfter(1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if err == nil { + t.Fatalf("azure: DoPollForAsynchronous failed to return error from polling") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsForStatusAccepted(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Status = "202 Accepted" + r1.StatusCode = http.StatusAccepted + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse(operationCanceled) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: DoPollForAsynchronous stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsForStatusCreated(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Status = "201 Created" + r1.StatusCode = http.StatusCreated + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse(operationCanceled) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: DoPollForAsynchronous stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsUntilProvisioningStatusTerminates(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3 := newProvisioningStatusResponse(operationCanceled) + r3.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: DoPollForAsynchronous stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsUntilProvisioningStatusSucceeds(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3 := newProvisioningStatusResponse(operationSucceeded) + r3.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: DoPollForAsynchronous stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsUntilOperationResourceHasTerminated(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse(operationCanceled) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: DoPollForAsynchronous stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_PollsUntilOperationResourceHasSucceeded(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse(operationSucceeded) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: DoPollForAsynchronous stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_StopsPollingWhenOperationResourceHasTerminated(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse(operationCanceled) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 2) + + r, _ := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() > 4 { + t.Fatalf("azure: DoPollForAsynchronous failed to stop after receiving a terminated OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsAnErrorForCanceledOperations(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceErrorResponse(operationCanceled) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if err == nil || !strings.Contains(fmt.Sprintf("%v", err), "Canceled") { + t.Fatalf("azure: DoPollForAsynchronous failed to return an appropriate error for a canceled OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsAnErrorForFailedOperations(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceErrorResponse(operationFailed) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if err == nil || !strings.Contains(fmt.Sprintf("%v", err), "Failed") { + t.Fatalf("azure: DoPollForAsynchronous failed to return an appropriate error for a canceled OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_WithNilURI(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r1.Header.Del(http.CanonicalHeaderKey(autorest.HeaderLocation)) + + r2 := newOperationResourceResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2.Header.Del(http.CanonicalHeaderKey(autorest.HeaderLocation)) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendResponse(r2) + + req, _ := http.NewRequest("POST", "https://microsoft.com/a/b/c/", mocks.NewBody("")) + r, err := autorest.SendWithSender(client, req, + DoPollForAsynchronous(time.Millisecond)) + + if err == nil { + t.Fatalf("azure: DoPollForAsynchronous failed to return error for nil URI. got: nil; want: Azure Polling Error - Unable to obtain polling URI for POST") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsAnUnknownErrorForFailedOperations(t *testing.T) { + // Return unknown error if error not present in last response + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3 := newProvisioningStatusResponse(operationFailed) + r3.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + expected := makeLongRunningOperationErrorString("Unknown", "None") + if err.Error() != expected { + t.Fatalf("azure: DoPollForAsynchronous failed to return an appropriate error message for an unknown error. \n expected=%q \n got=%q", + expected, err.Error()) + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsErrorForLastErrorResponse(t *testing.T) { + // Return error code and message if error present in last response + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3 := newAsynchronousResponseWithError("400 Bad Request", http.StatusBadRequest) + r3.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + expected := makeLongRunningOperationErrorString("InvalidParameter", "tom-service-DISCOVERY-server-base-v1.core.local' is not a valid captured VHD blob name prefix.") + if err.Error() != expected { + t.Fatalf("azure: DoPollForAsynchronous failed to return an appropriate error message for an unknown error. \n expected=%q \n got=%q", + expected, err.Error()) + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsOperationResourceErrorForFailedOperations(t *testing.T) { + // Return Operation resource response with error code and message in last operation resource response + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceErrorResponse(operationFailed) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + expected := makeLongRunningOperationErrorString("BadArgument", "The provided database 'foo' has an invalid username.") + if err.Error() != expected { + t.Fatalf("azure: DoPollForAsynchronous failed to return an appropriate error message for a failed Operations. \n expected=%q \n got=%q", + expected, err.Error()) + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_ReturnsErrorForFirstPutRequest(t *testing.T) { + // Return 400 bad response with error code and message in first put + r1 := newAsynchronousResponseWithError("400 Bad Request", http.StatusBadRequest) + client := mocks.NewSender() + client.AppendResponse(r1) + + res, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + if err != nil { + t.Fatalf("azure: DoPollForAsynchronous failed to return an appropriate error message for a failed Operations. \n expected=%q \n got=%q", + errorResponse, err.Error()) + } + + err = autorest.Respond(res, + WithErrorUnlessStatusCode(http.StatusAccepted, http.StatusCreated, http.StatusOK), + autorest.ByClosing()) + + reqError, ok := err.(*RequestError) + if !ok { + t.Fatalf("azure: returned error is not azure.RequestError: %T", err) + } + + expected := &RequestError{ + ServiceError: &ServiceError{ + Code: "InvalidParameter", + Message: "tom-service-DISCOVERY-server-base-v1.core.local' is not a valid captured VHD blob name prefix.", + }, + DetailedError: autorest.DetailedError{ + StatusCode: 400, + }, + } + if !reflect.DeepEqual(reqError, expected) { + t.Fatalf("azure: wrong error. expected=%q\ngot=%q", expected, reqError) + } + + defer res.Body.Close() + b, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if string(b) != errorResponse { + t.Fatalf("azure: Response body is wrong. got=%q expected=%q", string(b), errorResponse) + } + +} + +func TestDoPollForAsynchronous_ReturnsNoErrorForSuccessfulOperations(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceErrorResponse(operationSucceeded) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if err != nil { + t.Fatalf("azure: DoPollForAsynchronous returned an error for a successful OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestDoPollForAsynchronous_StopsPollingIfItReceivesAnInvalidOperationResource(t *testing.T) { + r1 := newAsynchronousResponse() + r2 := newOperationResourceResponse("busy") + r3 := newOperationResourceResponse("busy") + r3.Body = mocks.NewBody(operationResourceIllegal) + r4 := newOperationResourceResponse(operationSucceeded) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendAndRepeatResponse(r3, 1) + client.AppendAndRepeatResponse(r4, 1) + + r, err := autorest.SendWithSender(client, mocks.NewRequest(), + DoPollForAsynchronous(time.Millisecond)) + + if client.Attempts() > 4 { + t.Fatalf("azure: DoPollForAsynchronous failed to stop polling after receiving an invalid OperationResource") + } + if err == nil { + t.Fatalf("azure: DoPollForAsynchronous failed to return an error after receving an invalid OperationResource") + } + + autorest.Respond(r, + autorest.ByClosing()) +} + +func TestFuture_PollsUntilProvisioningStatusSucceeds(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3 := newProvisioningStatusResponse(operationSucceeded) + r3.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + client := mocks.NewSender() + client.AppendResponse(r1) + client.AppendAndRepeatResponse(r2, 2) + client.AppendResponse(r3) + + future := NewFuture(mocks.NewRequest()) + + for done, err := future.Done(client); !done; done, err = future.Done(client) { + if future.PollingMethod() != PollingLocation { + t.Fatalf("azure: wrong future polling method") + } + if err != nil { + t.Fatalf("azure: TestFuture polling Done failed") + } + delay, ok := future.GetPollingDelay() + if !ok { + t.Fatalf("expected Retry-After value") + } + time.Sleep(delay) + } + + if client.Attempts() < client.NumResponses() { + t.Fatalf("azure: TestFuture stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(future.Response(), + autorest.ByClosing()) +} + +func TestFuture_Marshalling(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(newAsynchronousResponse()) + + future := NewFuture(mocks.NewRequest()) + done, err := future.Done(client) + if err != nil { + t.Fatalf("azure: TestFuture marshalling Done failed") + } + if done { + t.Fatalf("azure: TestFuture marshalling shouldn't be done") + } + if future.PollingMethod() != PollingAsyncOperation { + t.Fatalf("azure: wrong future polling method") + } + + data, err := json.Marshal(future) + if err != nil { + t.Fatalf("azure: TestFuture failed to marshal") + } + + var future2 Future + err = json.Unmarshal(data, &future2) + if err != nil { + t.Fatalf("azure: TestFuture failed to unmarshal") + } + + if future.ps.Code != future2.ps.Code { + t.Fatalf("azure: TestFuture marshalling codes don't match") + } + if future.ps.Message != future2.ps.Message { + t.Fatalf("azure: TestFuture marshalling messages don't match") + } + if future.ps.PollingMethod != future2.ps.PollingMethod { + t.Fatalf("azure: TestFuture marshalling response formats don't match") + } + if future.ps.State != future2.ps.State { + t.Fatalf("azure: TestFuture marshalling states don't match") + } + if future.ps.URI != future2.ps.URI { + t.Fatalf("azure: TestFuture marshalling URIs don't match") + } +} + +func TestFuture_WaitForCompletion(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3 := newAsynchronousResponseWithError("Internal server error", http.StatusInternalServerError) + r3.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r3.Header.Del(http.CanonicalHeaderKey("Retry-After")) + r4 := newProvisioningStatusResponse(operationSucceeded) + r4.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + sender := mocks.NewSender() + sender.AppendResponse(r1) + sender.AppendError(errors.New("transient network failure")) + sender.AppendAndRepeatResponse(r2, 2) + sender.AppendResponse(r3) + sender.AppendResponse(r4) + + future := NewFuture(mocks.NewRequest()) + + client := autorest.Client{ + PollingDelay: 1 * time.Second, + PollingDuration: autorest.DefaultPollingDuration, + RetryAttempts: autorest.DefaultRetryAttempts, + RetryDuration: 1 * time.Second, + Sender: sender, + } + + err := future.WaitForCompletion(context.Background(), client) + if err != nil { + t.Fatalf("azure: WaitForCompletion returned non-nil error") + } + + if sender.Attempts() < sender.NumResponses() { + t.Fatalf("azure: TestFuture stopped polling before receiving a terminated OperationResource") + } + + autorest.Respond(future.Response(), + autorest.ByClosing()) +} + +func TestFuture_WaitForCompletionTimedOut(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + sender := mocks.NewSender() + sender.AppendResponse(r1) + sender.AppendAndRepeatResponseWithDelay(r2, 1*time.Second, 5) + + future := NewFuture(mocks.NewRequest()) + + client := autorest.Client{ + PollingDelay: autorest.DefaultPollingDelay, + PollingDuration: 2 * time.Second, + RetryAttempts: autorest.DefaultRetryAttempts, + RetryDuration: 1 * time.Second, + Sender: sender, + } + + err := future.WaitForCompletion(context.Background(), client) + if err == nil { + t.Fatalf("azure: WaitForCompletion returned nil error, should have timed out") + } +} + +func TestFuture_WaitForCompletionRetriesExceeded(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + sender := mocks.NewSender() + sender.AppendResponse(r1) + sender.AppendAndRepeatError(errors.New("transient network failure"), autorest.DefaultRetryAttempts+1) + + future := NewFuture(mocks.NewRequest()) + + client := autorest.Client{ + PollingDelay: autorest.DefaultPollingDelay, + PollingDuration: autorest.DefaultPollingDuration, + RetryAttempts: autorest.DefaultRetryAttempts, + RetryDuration: 100 * time.Millisecond, + Sender: sender, + } + + err := future.WaitForCompletion(context.Background(), client) + if err == nil { + t.Fatalf("azure: WaitForCompletion returned nil error, should have errored out") + } +} + +func TestFuture_WaitForCompletionCancelled(t *testing.T) { + r1 := newAsynchronousResponse() + r1.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + r2 := newProvisioningStatusResponse("busy") + r2.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + + sender := mocks.NewSender() + sender.AppendResponse(r1) + sender.AppendAndRepeatResponseWithDelay(r2, 1*time.Second, 5) + + future := NewFuture(mocks.NewRequest()) + + client := autorest.Client{ + PollingDelay: autorest.DefaultPollingDelay, + PollingDuration: autorest.DefaultPollingDuration, + RetryAttempts: autorest.DefaultRetryAttempts, + RetryDuration: autorest.DefaultRetryDuration, + Sender: sender, + } + + ctx, cancel := context.WithCancel(context.Background()) + go func() { + time.Sleep(2 * time.Second) + cancel() + }() + + err := future.WaitForCompletion(ctx, client) + if err == nil { + t.Fatalf("azure: WaitForCompletion returned nil error, should have been cancelled") + } +} + +const ( + operationResourceIllegal = ` + This is not JSON and should fail...badly. + ` + pollingStateFormat = ` + { + "unused" : { + "somefield" : 42 + }, + "properties" : { + "provisioningState": "%s" + } + } + ` + + errorResponse = ` + { + "error" : { + "code" : "InvalidParameter", + "message" : "tom-service-DISCOVERY-server-base-v1.core.local' is not a valid captured VHD blob name prefix." + } + } + ` + + pollingStateEmpty = ` + { + "unused" : { + "somefield" : 42 + }, + "properties" : { + } + } + ` + + operationResourceFormat = ` + { + "id": "/subscriptions/id/locations/westus/operationsStatus/sameguid", + "name": "sameguid", + "status" : "%s", + "startTime" : "2006-01-02T15:04:05Z", + "endTime" : "2006-01-02T16:04:05Z", + "percentComplete" : 50.00, + + "properties" : {} + } + ` + + operationResourceErrorFormat = ` + { + "id": "/subscriptions/id/locations/westus/operationsStatus/sameguid", + "name": "sameguid", + "status" : "%s", + "startTime" : "2006-01-02T15:04:05Z", + "endTime" : "2006-01-02T16:04:05Z", + "percentComplete" : 50.00, + + "properties" : {}, + "error" : { + "code" : "BadArgument", + "message" : "The provided database 'foo' has an invalid username." + } + } + ` +) + +func newAsynchronousResponse() *http.Response { + r := mocks.NewResponseWithStatus("201 Created", http.StatusCreated) + r.Body = mocks.NewBody(fmt.Sprintf(pollingStateFormat, operationInProgress)) + mocks.SetResponseHeader(r, http.CanonicalHeaderKey(headerAsyncOperation), mocks.TestAzureAsyncURL) + mocks.SetResponseHeader(r, http.CanonicalHeaderKey(autorest.HeaderLocation), mocks.TestLocationURL) + mocks.SetRetryHeader(r, retryDelay) + r.Request = mocks.NewRequestForURL(mocks.TestURL) + return r +} + +func newAsynchronousResponseWithError(response string, status int) *http.Response { + r := mocks.NewResponseWithStatus(response, status) + mocks.SetRetryHeader(r, retryDelay) + r.Request = mocks.NewRequestForURL(mocks.TestURL) + r.Body = mocks.NewBody(errorResponse) + return r +} + +func newOperationResourceResponse(status string) *http.Response { + r := newAsynchronousResponse() + r.Body = mocks.NewBody(fmt.Sprintf(operationResourceFormat, status)) + return r +} + +func newOperationResourceErrorResponse(status string) *http.Response { + r := newAsynchronousResponse() + r.Body = mocks.NewBody(fmt.Sprintf(operationResourceErrorFormat, status)) + return r +} + +func newProvisioningStatusResponse(status string) *http.Response { + r := newAsynchronousResponse() + r.Body = mocks.NewBody(fmt.Sprintf(pollingStateFormat, status)) + return r +} + +func makeLongRunningOperationErrorString(code string, message string) string { + return fmt.Sprintf("Long running operation terminated with status 'Failed': Code=%q Message=%q", code, message) +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/azure_test.go b/vendor/github.com/Azure/go-autorest/autorest/azure/azure_test.go new file mode 100644 index 000000000..e8bddbbfd --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/azure_test.go @@ -0,0 +1,513 @@ +package azure + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "reflect" + "strconv" + "testing" + "time" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/mocks" +) + +const ( + headerAuthorization = "Authorization" + longDelay = 5 * time.Second + retryDelay = 10 * time.Millisecond + testLogPrefix = "azure:" +) + +// Use a Client Inspector to set the request identifier. +func ExampleWithClientID() { + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + req, _ := autorest.Prepare(&http.Request{}, + autorest.AsGet(), + autorest.WithBaseURL("https://microsoft.com/a/b/c/")) + + c := autorest.Client{Sender: mocks.NewSender()} + c.RequestInspector = WithReturningClientID(uuid) + + autorest.SendWithSender(c, req) + fmt.Printf("Inspector added the %s header with the value %s\n", + HeaderClientID, req.Header.Get(HeaderClientID)) + fmt.Printf("Inspector added the %s header with the value %s\n", + HeaderReturnClientID, req.Header.Get(HeaderReturnClientID)) + // Output: + // Inspector added the x-ms-client-request-id header with the value 71FDB9F4-5E49-4C12-B266-DE7B4FD999A6 + // Inspector added the x-ms-return-client-request-id header with the value true +} + +func TestWithReturningClientIDReturnsError(t *testing.T) { + var errIn error + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + _, errOut := autorest.Prepare(&http.Request{}, + withErrorPrepareDecorator(&errIn), + WithReturningClientID(uuid)) + + if errOut == nil || errIn != errOut { + t.Fatalf("azure: WithReturningClientID failed to exit early when receiving an error -- expected (%v), received (%v)", + errIn, errOut) + } +} + +func TestWithClientID(t *testing.T) { + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + req, _ := autorest.Prepare(&http.Request{}, + WithClientID(uuid)) + + if req.Header.Get(HeaderClientID) != uuid { + t.Fatalf("azure: WithClientID failed to set %s -- expected %s, received %s", + HeaderClientID, uuid, req.Header.Get(HeaderClientID)) + } +} + +func TestWithReturnClientID(t *testing.T) { + b := false + req, _ := autorest.Prepare(&http.Request{}, + WithReturnClientID(b)) + + if req.Header.Get(HeaderReturnClientID) != strconv.FormatBool(b) { + t.Fatalf("azure: WithReturnClientID failed to set %s -- expected %s, received %s", + HeaderClientID, strconv.FormatBool(b), req.Header.Get(HeaderClientID)) + } +} + +func TestExtractClientID(t *testing.T) { + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + resp := mocks.NewResponse() + mocks.SetResponseHeader(resp, HeaderClientID, uuid) + + if ExtractClientID(resp) != uuid { + t.Fatalf("azure: ExtractClientID failed to extract the %s -- expected %s, received %s", + HeaderClientID, uuid, ExtractClientID(resp)) + } +} + +func TestExtractRequestID(t *testing.T) { + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + resp := mocks.NewResponse() + mocks.SetResponseHeader(resp, HeaderRequestID, uuid) + + if ExtractRequestID(resp) != uuid { + t.Fatalf("azure: ExtractRequestID failed to extract the %s -- expected %s, received %s", + HeaderRequestID, uuid, ExtractRequestID(resp)) + } +} + +func TestIsAzureError_ReturnsTrueForAzureError(t *testing.T) { + if !IsAzureError(&RequestError{}) { + t.Fatalf("azure: IsAzureError failed to return true for an Azure Service error") + } +} + +func TestIsAzureError_ReturnsFalseForNonAzureError(t *testing.T) { + if IsAzureError(fmt.Errorf("An Error")) { + t.Fatalf("azure: IsAzureError return true for an non-Azure Service error") + } +} + +func TestNewErrorWithError_UsesReponseStatusCode(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("Error"), "packageType", "method", mocks.NewResponseWithStatus("Forbidden", http.StatusForbidden), "message") + if e.StatusCode != http.StatusForbidden { + t.Fatalf("azure: NewErrorWithError failed to use the Status Code of the passed Response -- expected %v, received %v", http.StatusForbidden, e.StatusCode) + } +} + +func TestNewErrorWithError_ReturnsUnwrappedError(t *testing.T) { + e1 := RequestError{} + e1.ServiceError = &ServiceError{Code: "42", Message: "A Message"} + e1.StatusCode = 200 + e1.RequestID = "A RequestID" + e2 := NewErrorWithError(&e1, "packageType", "method", nil, "message") + + if !reflect.DeepEqual(e1, e2) { + t.Fatalf("azure: NewErrorWithError wrapped an RequestError -- expected %T, received %T", e1, e2) + } +} + +func TestNewErrorWithError_WrapsAnError(t *testing.T) { + e1 := fmt.Errorf("Inner Error") + var e2 interface{} = NewErrorWithError(e1, "packageType", "method", nil, "message") + + if _, ok := e2.(RequestError); !ok { + t.Fatalf("azure: NewErrorWithError failed to wrap a standard error -- received %T", e2) + } +} + +func TestWithErrorUnlessStatusCode_NotAnAzureError(t *testing.T) { + body := ` + + IIS Error page + + Some non-JSON error page + ` + r := mocks.NewResponseWithContent(body) + r.Request = mocks.NewRequest() + r.StatusCode = http.StatusBadRequest + r.Status = http.StatusText(r.StatusCode) + + err := autorest.Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + ok, _ := err.(*RequestError) + if ok != nil { + t.Fatalf("azure: azure.RequestError returned from malformed response: %v", err) + } + + // the error body should still be there + defer r.Body.Close() + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + if string(b) != body { + t.Fatalf("response body is wrong. got=%q exptected=%q", string(b), body) + } +} + +func TestWithErrorUnlessStatusCode_FoundAzureErrorWithoutDetails(t *testing.T) { + j := `{ + "error": { + "code": "InternalError", + "message": "Azure is having trouble right now." + } + }` + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + r := mocks.NewResponseWithContent(j) + mocks.SetResponseHeader(r, HeaderRequestID, uuid) + r.Request = mocks.NewRequest() + r.StatusCode = http.StatusInternalServerError + r.Status = http.StatusText(r.StatusCode) + + err := autorest.Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + + if err == nil { + t.Fatalf("azure: returned nil error for proper error response") + } + azErr, ok := err.(*RequestError) + if !ok { + t.Fatalf("azure: returned error is not azure.RequestError: %T", err) + } + + expected := "autorest/azure: Service returned an error. Status=500 Code=\"InternalError\" Message=\"Azure is having trouble right now.\"" + if !reflect.DeepEqual(expected, azErr.Error()) { + t.Fatalf("azure: service error is not unmarshaled properly.\nexpected=%v\ngot=%v", expected, azErr.Error()) + } + + if expected := http.StatusInternalServerError; azErr.StatusCode != expected { + t.Fatalf("azure: got wrong StatusCode=%d Expected=%d", azErr.StatusCode, expected) + } + if expected := uuid; azErr.RequestID != expected { + t.Fatalf("azure: wrong request ID in error. expected=%q; got=%q", expected, azErr.RequestID) + } + + _ = azErr.Error() + + // the error body should still be there + defer r.Body.Close() + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + if string(b) != j { + t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j) + } + +} + +func TestWithErrorUnlessStatusCode_FoundAzureErrorWithDetails(t *testing.T) { + j := `{ + "error": { + "code": "InternalError", + "message": "Azure is having trouble right now.", + "details": [{"code": "conflict1", "message":"error message1"}, + {"code": "conflict2", "message":"error message2"}] + } + }` + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + r := mocks.NewResponseWithContent(j) + mocks.SetResponseHeader(r, HeaderRequestID, uuid) + r.Request = mocks.NewRequest() + r.StatusCode = http.StatusInternalServerError + r.Status = http.StatusText(r.StatusCode) + + err := autorest.Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + + if err == nil { + t.Fatalf("azure: returned nil error for proper error response") + } + azErr, ok := err.(*RequestError) + if !ok { + t.Fatalf("azure: returned error is not azure.RequestError: %T", err) + } + + if expected := "InternalError"; azErr.ServiceError.Code != expected { + t.Fatalf("azure: wrong error code. expected=%q; got=%q", expected, azErr.ServiceError.Code) + } + if azErr.ServiceError.Message == "" { + t.Fatalf("azure: error message is not unmarshaled properly") + } + b, _ := json.Marshal(*azErr.ServiceError.Details) + if string(b) != `[{"code":"conflict1","message":"error message1"},{"code":"conflict2","message":"error message2"}]` { + t.Fatalf("azure: error details is not unmarshaled properly") + } + + if expected := http.StatusInternalServerError; azErr.StatusCode != expected { + t.Fatalf("azure: got wrong StatusCode=%v Expected=%d", azErr.StatusCode, expected) + } + if expected := uuid; azErr.RequestID != expected { + t.Fatalf("azure: wrong request ID in error. expected=%q; got=%q", expected, azErr.RequestID) + } + + _ = azErr.Error() + + // the error body should still be there + defer r.Body.Close() + b, err = ioutil.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + if string(b) != j { + t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j) + } + +} + +func TestWithErrorUnlessStatusCode_NoAzureError(t *testing.T) { + j := `{ + "Status":"NotFound" + }` + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + r := mocks.NewResponseWithContent(j) + mocks.SetResponseHeader(r, HeaderRequestID, uuid) + r.Request = mocks.NewRequest() + r.StatusCode = http.StatusInternalServerError + r.Status = http.StatusText(r.StatusCode) + + err := autorest.Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + if err == nil { + t.Fatalf("azure: returned nil error for proper error response") + } + azErr, ok := err.(*RequestError) + if !ok { + t.Fatalf("azure: returned error is not azure.RequestError: %T", err) + } + + expected := &ServiceError{ + Code: "Unknown", + Message: "Unknown service error", + } + + if !reflect.DeepEqual(expected, azErr.ServiceError) { + t.Fatalf("azure: service error is not unmarshaled properly. expected=%q\ngot=%q", expected, azErr.ServiceError) + } + + if expected := http.StatusInternalServerError; azErr.StatusCode != expected { + t.Fatalf("azure: got wrong StatusCode=%v Expected=%d", azErr.StatusCode, expected) + } + if expected := uuid; azErr.RequestID != expected { + t.Fatalf("azure: wrong request ID in error. expected=%q; got=%q", expected, azErr.RequestID) + } + + _ = azErr.Error() + + // the error body should still be there + defer r.Body.Close() + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + if string(b) != j { + t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j) + } + +} + +func TestWithErrorUnlessStatusCode_UnwrappedError(t *testing.T) { + j := `{ + "target": null, + "code": "InternalError", + "message": "Azure is having trouble right now.", + "details": [{"code": "conflict1", "message":"error message1"}, + {"code": "conflict2", "message":"error message2"}], + "innererror": [] +}` + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + r := mocks.NewResponseWithContent(j) + mocks.SetResponseHeader(r, HeaderRequestID, uuid) + r.Request = mocks.NewRequest() + r.StatusCode = http.StatusInternalServerError + r.Status = http.StatusText(r.StatusCode) + + err := autorest.Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + + if err == nil { + t.Fatal("azure: returned nil error for proper error response") + } + + azErr, ok := err.(*RequestError) + if !ok { + t.Fatalf("returned error is not azure.RequestError: %T", err) + } + + if expected := http.StatusInternalServerError; azErr.StatusCode != expected { + t.Logf("Incorrect StatusCode got: %v want: %d", azErr.StatusCode, expected) + t.Fail() + } + + if expected := "Azure is having trouble right now."; azErr.ServiceError.Message != expected { + t.Logf("Incorrect Message\n\tgot: %q\n\twant: %q", azErr.Message, expected) + t.Fail() + } + + if expected := uuid; azErr.RequestID != expected { + t.Logf("Incorrect request ID\n\tgot: %q\n\twant: %q", azErr.RequestID, expected) + t.Fail() + } + + expectedServiceErrorDetails := `[{"code":"conflict1","message":"error message1"},{"code":"conflict2","message":"error message2"}]` + if azErr.ServiceError == nil { + t.Logf("`ServiceError` was nil when it shouldn't have been.") + t.Fail() + } else if azErr.ServiceError.Details == nil { + t.Logf("`ServiceError.Details` was nil when it should have been %q", expectedServiceErrorDetails) + t.Fail() + } else if details, _ := json.Marshal(*azErr.ServiceError.Details); expectedServiceErrorDetails != string(details) { + t.Logf("Error detaisl was not unmarshaled properly.\n\tgot: %q\n\twant: %q", string(details), expectedServiceErrorDetails) + t.Fail() + } + + // the error body should still be there + defer r.Body.Close() + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Error(err) + } + if string(b) != j { + t.Fatalf("response body is wrong. got=%q expected=%q", string(b), j) + } + +} + +func TestRequestErrorString_WithError(t *testing.T) { + j := `{ + "error": { + "code": "InternalError", + "message": "Conflict", + "details": [{"code": "conflict1", "message":"error message1"}] + } + }` + uuid := "71FDB9F4-5E49-4C12-B266-DE7B4FD999A6" + r := mocks.NewResponseWithContent(j) + mocks.SetResponseHeader(r, HeaderRequestID, uuid) + r.Request = mocks.NewRequest() + r.StatusCode = http.StatusInternalServerError + r.Status = http.StatusText(r.StatusCode) + + err := autorest.Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + + if err == nil { + t.Fatalf("azure: returned nil error for proper error response") + } + azErr, _ := err.(*RequestError) + expected := "autorest/azure: Service returned an error. Status=500 Code=\"InternalError\" Message=\"Conflict\" Details=[{\"code\":\"conflict1\",\"message\":\"error message1\"}]" + if expected != azErr.Error() { + t.Fatalf("azure: send wrong RequestError.\nexpected=%v\ngot=%v", expected, azErr.Error()) + } +} + +func withErrorPrepareDecorator(e *error) autorest.PrepareDecorator { + return func(p autorest.Preparer) autorest.Preparer { + return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { + *e = fmt.Errorf("azure: Faux Prepare Error") + return r, *e + }) + } +} + +func withAsyncResponseDecorator(n int) autorest.SendDecorator { + i := 0 + return func(s autorest.Sender) autorest.Sender { + return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + if err == nil { + if i < n { + resp.StatusCode = http.StatusCreated + resp.Header = http.Header{} + resp.Header.Add(http.CanonicalHeaderKey(headerAsyncOperation), mocks.TestURL) + i++ + } else { + resp.StatusCode = http.StatusOK + resp.Header.Del(http.CanonicalHeaderKey(headerAsyncOperation)) + } + } + return resp, err + }) + } +} + +type mockAuthorizer struct{} + +func (ma mockAuthorizer) WithAuthorization() autorest.PrepareDecorator { + return autorest.WithHeader(headerAuthorization, mocks.TestAuthorizationHeader) +} + +type mockFailingAuthorizer struct{} + +func (mfa mockFailingAuthorizer) WithAuthorization() autorest.PrepareDecorator { + return func(p autorest.Preparer) autorest.Preparer { + return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { + return r, fmt.Errorf("ERROR: mockFailingAuthorizer returned expected error") + }) + } +} + +type mockInspector struct { + wasInvoked bool +} + +func (mi *mockInspector) WithInspection() autorest.PrepareDecorator { + return func(p autorest.Preparer) autorest.Preparer { + return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { + mi.wasInvoked = true + return p.Prepare(r) + }) + } +} + +func (mi *mockInspector) ByInspecting() autorest.RespondDecorator { + return func(r autorest.Responder) autorest.Responder { + return autorest.ResponderFunc(func(resp *http.Response) error { + mi.wasInvoked = true + return r.Respond(resp) + }) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/environments_test.go b/vendor/github.com/Azure/go-autorest/autorest/azure/environments_test.go new file mode 100644 index 000000000..98162c3f1 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/environments_test.go @@ -0,0 +1,292 @@ +// test +package azure + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "os" + "path" + "path/filepath" + "runtime" + "testing" +) + +// This correlates to the expected contents of ./testdata/test_environment_1.json +var testEnvironment1 = Environment{ + Name: "--unit-test--", + ManagementPortalURL: "--management-portal-url", + PublishSettingsURL: "--publish-settings-url--", + ServiceManagementEndpoint: "--service-management-endpoint--", + ResourceManagerEndpoint: "--resource-management-endpoint--", + ActiveDirectoryEndpoint: "--active-directory-endpoint--", + GalleryEndpoint: "--gallery-endpoint--", + KeyVaultEndpoint: "--key-vault--endpoint--", + GraphEndpoint: "--graph-endpoint--", + StorageEndpointSuffix: "--storage-endpoint-suffix--", + SQLDatabaseDNSSuffix: "--sql-database-dns-suffix--", + TrafficManagerDNSSuffix: "--traffic-manager-dns-suffix--", + KeyVaultDNSSuffix: "--key-vault-dns-suffix--", + ServiceBusEndpointSuffix: "--service-bus-endpoint-suffix--", + ServiceManagementVMDNSSuffix: "--asm-vm-dns-suffix--", + ResourceManagerVMDNSSuffix: "--arm-vm-dns-suffix--", + ContainerRegistryDNSSuffix: "--container-registry-dns-suffix--", +} + +func TestEnvironment_EnvironmentFromFile(t *testing.T) { + got, err := EnvironmentFromFile(filepath.Join("testdata", "test_environment_1.json")) + if err != nil { + t.Error(err) + } + + if got != testEnvironment1 { + t.Logf("got: %v want: %v", got, testEnvironment1) + t.Fail() + } +} + +func TestEnvironment_EnvironmentFromName_Stack(t *testing.T) { + _, currentFile, _, _ := runtime.Caller(0) + prevEnvFilepathValue := os.Getenv(EnvironmentFilepathName) + os.Setenv(EnvironmentFilepathName, filepath.Join(path.Dir(currentFile), "testdata", "test_environment_1.json")) + defer os.Setenv(EnvironmentFilepathName, prevEnvFilepathValue) + + got, err := EnvironmentFromName("AZURESTACKCLOUD") + if err != nil { + t.Error(err) + } + + if got != testEnvironment1 { + t.Logf("got: %v want: %v", got, testEnvironment1) + t.Fail() + } +} + +func TestEnvironmentFromName(t *testing.T) { + name := "azurechinacloud" + if env, _ := EnvironmentFromName(name); env != ChinaCloud { + t.Errorf("Expected to get ChinaCloud for %q", name) + } + + name = "AzureChinaCloud" + if env, _ := EnvironmentFromName(name); env != ChinaCloud { + t.Errorf("Expected to get ChinaCloud for %q", name) + } + + name = "azuregermancloud" + if env, _ := EnvironmentFromName(name); env != GermanCloud { + t.Errorf("Expected to get GermanCloud for %q", name) + } + + name = "AzureGermanCloud" + if env, _ := EnvironmentFromName(name); env != GermanCloud { + t.Errorf("Expected to get GermanCloud for %q", name) + } + + name = "azurepubliccloud" + if env, _ := EnvironmentFromName(name); env != PublicCloud { + t.Errorf("Expected to get PublicCloud for %q", name) + } + + name = "AzurePublicCloud" + if env, _ := EnvironmentFromName(name); env != PublicCloud { + t.Errorf("Expected to get PublicCloud for %q", name) + } + + name = "azureusgovernmentcloud" + if env, _ := EnvironmentFromName(name); env != USGovernmentCloud { + t.Errorf("Expected to get USGovernmentCloud for %q", name) + } + + name = "AzureUSGovernmentCloud" + if env, _ := EnvironmentFromName(name); env != USGovernmentCloud { + t.Errorf("Expected to get USGovernmentCloud for %q", name) + } + + name = "thisisnotarealcloudenv" + if _, err := EnvironmentFromName(name); err == nil { + t.Errorf("Expected to get an error for %q", name) + } +} + +func TestDeserializeEnvironment(t *testing.T) { + env := `{ + "name": "--name--", + "ActiveDirectoryEndpoint": "--active-directory-endpoint--", + "galleryEndpoint": "--gallery-endpoint--", + "graphEndpoint": "--graph-endpoint--", + "serviceBusEndpoint": "--service-bus-endpoint--", + "keyVaultDNSSuffix": "--key-vault-dns-suffix--", + "keyVaultEndpoint": "--key-vault-endpoint--", + "managementPortalURL": "--management-portal-url--", + "publishSettingsURL": "--publish-settings-url--", + "resourceManagerEndpoint": "--resource-manager-endpoint--", + "serviceBusEndpointSuffix": "--service-bus-endpoint-suffix--", + "serviceManagementEndpoint": "--service-management-endpoint--", + "sqlDatabaseDNSSuffix": "--sql-database-dns-suffix--", + "storageEndpointSuffix": "--storage-endpoint-suffix--", + "trafficManagerDNSSuffix": "--traffic-manager-dns-suffix--", + "serviceManagementVMDNSSuffix": "--asm-vm-dns-suffix--", + "resourceManagerVMDNSSuffix": "--arm-vm-dns-suffix--", + "containerRegistryDNSSuffix": "--container-registry-dns-suffix--" + }` + + testSubject := Environment{} + err := json.Unmarshal([]byte(env), &testSubject) + if err != nil { + t.Fatalf("failed to unmarshal: %s", err) + } + + if "--name--" != testSubject.Name { + t.Errorf("Expected Name to be \"--name--\", but got %q", testSubject.Name) + } + if "--management-portal-url--" != testSubject.ManagementPortalURL { + t.Errorf("Expected ManagementPortalURL to be \"--management-portal-url--\", but got %q", testSubject.ManagementPortalURL) + } + if "--publish-settings-url--" != testSubject.PublishSettingsURL { + t.Errorf("Expected PublishSettingsURL to be \"--publish-settings-url--\", but got %q", testSubject.PublishSettingsURL) + } + if "--service-management-endpoint--" != testSubject.ServiceManagementEndpoint { + t.Errorf("Expected ServiceManagementEndpoint to be \"--service-management-endpoint--\", but got %q", testSubject.ServiceManagementEndpoint) + } + if "--resource-manager-endpoint--" != testSubject.ResourceManagerEndpoint { + t.Errorf("Expected ResourceManagerEndpoint to be \"--resource-manager-endpoint--\", but got %q", testSubject.ResourceManagerEndpoint) + } + if "--active-directory-endpoint--" != testSubject.ActiveDirectoryEndpoint { + t.Errorf("Expected ActiveDirectoryEndpoint to be \"--active-directory-endpoint--\", but got %q", testSubject.ActiveDirectoryEndpoint) + } + if "--gallery-endpoint--" != testSubject.GalleryEndpoint { + t.Errorf("Expected GalleryEndpoint to be \"--gallery-endpoint--\", but got %q", testSubject.GalleryEndpoint) + } + if "--key-vault-endpoint--" != testSubject.KeyVaultEndpoint { + t.Errorf("Expected KeyVaultEndpoint to be \"--key-vault-endpoint--\", but got %q", testSubject.KeyVaultEndpoint) + } + if "--service-bus-endpoint--" != testSubject.ServiceBusEndpoint { + t.Errorf("Expected ServiceBusEndpoint to be \"--service-bus-endpoint--\", but goet %q", testSubject.ServiceBusEndpoint) + } + if "--graph-endpoint--" != testSubject.GraphEndpoint { + t.Errorf("Expected GraphEndpoint to be \"--graph-endpoint--\", but got %q", testSubject.GraphEndpoint) + } + if "--storage-endpoint-suffix--" != testSubject.StorageEndpointSuffix { + t.Errorf("Expected StorageEndpointSuffix to be \"--storage-endpoint-suffix--\", but got %q", testSubject.StorageEndpointSuffix) + } + if "--sql-database-dns-suffix--" != testSubject.SQLDatabaseDNSSuffix { + t.Errorf("Expected sql-database-dns-suffix to be \"--sql-database-dns-suffix--\", but got %q", testSubject.SQLDatabaseDNSSuffix) + } + if "--key-vault-dns-suffix--" != testSubject.KeyVaultDNSSuffix { + t.Errorf("Expected StorageEndpointSuffix to be \"--key-vault-dns-suffix--\", but got %q", testSubject.KeyVaultDNSSuffix) + } + if "--service-bus-endpoint-suffix--" != testSubject.ServiceBusEndpointSuffix { + t.Errorf("Expected StorageEndpointSuffix to be \"--service-bus-endpoint-suffix--\", but got %q", testSubject.ServiceBusEndpointSuffix) + } + if "--asm-vm-dns-suffix--" != testSubject.ServiceManagementVMDNSSuffix { + t.Errorf("Expected ServiceManagementVMDNSSuffix to be \"--asm-vm-dns-suffix--\", but got %q", testSubject.ServiceManagementVMDNSSuffix) + } + if "--arm-vm-dns-suffix--" != testSubject.ResourceManagerVMDNSSuffix { + t.Errorf("Expected ResourceManagerVMDNSSuffix to be \"--arm-vm-dns-suffix--\", but got %q", testSubject.ResourceManagerVMDNSSuffix) + } + if "--container-registry-dns-suffix--" != testSubject.ContainerRegistryDNSSuffix { + t.Errorf("Expected ContainerRegistryDNSSuffix to be \"--container-registry-dns-suffix--\", but got %q", testSubject.ContainerRegistryDNSSuffix) + } +} + +func TestRoundTripSerialization(t *testing.T) { + env := Environment{ + Name: "--unit-test--", + ManagementPortalURL: "--management-portal-url", + PublishSettingsURL: "--publish-settings-url--", + ServiceManagementEndpoint: "--service-management-endpoint--", + ResourceManagerEndpoint: "--resource-management-endpoint--", + ActiveDirectoryEndpoint: "--active-directory-endpoint--", + GalleryEndpoint: "--gallery-endpoint--", + KeyVaultEndpoint: "--key-vault--endpoint--", + GraphEndpoint: "--graph-endpoint--", + ServiceBusEndpoint: "--service-bus-endpoint--", + StorageEndpointSuffix: "--storage-endpoint-suffix--", + SQLDatabaseDNSSuffix: "--sql-database-dns-suffix--", + TrafficManagerDNSSuffix: "--traffic-manager-dns-suffix--", + KeyVaultDNSSuffix: "--key-vault-dns-suffix--", + ServiceBusEndpointSuffix: "--service-bus-endpoint-suffix--", + ServiceManagementVMDNSSuffix: "--asm-vm-dns-suffix--", + ResourceManagerVMDNSSuffix: "--arm-vm-dns-suffix--", + ContainerRegistryDNSSuffix: "--container-registry-dns-suffix--", + } + + bytes, err := json.Marshal(env) + if err != nil { + t.Fatalf("failed to marshal: %s", err) + } + + testSubject := Environment{} + err = json.Unmarshal(bytes, &testSubject) + if err != nil { + t.Fatalf("failed to unmarshal: %s", err) + } + + if env.Name != testSubject.Name { + t.Errorf("Expected Name to be %q, but got %q", env.Name, testSubject.Name) + } + if env.ManagementPortalURL != testSubject.ManagementPortalURL { + t.Errorf("Expected ManagementPortalURL to be %q, but got %q", env.ManagementPortalURL, testSubject.ManagementPortalURL) + } + if env.PublishSettingsURL != testSubject.PublishSettingsURL { + t.Errorf("Expected PublishSettingsURL to be %q, but got %q", env.PublishSettingsURL, testSubject.PublishSettingsURL) + } + if env.ServiceManagementEndpoint != testSubject.ServiceManagementEndpoint { + t.Errorf("Expected ServiceManagementEndpoint to be %q, but got %q", env.ServiceManagementEndpoint, testSubject.ServiceManagementEndpoint) + } + if env.ResourceManagerEndpoint != testSubject.ResourceManagerEndpoint { + t.Errorf("Expected ResourceManagerEndpoint to be %q, but got %q", env.ResourceManagerEndpoint, testSubject.ResourceManagerEndpoint) + } + if env.ActiveDirectoryEndpoint != testSubject.ActiveDirectoryEndpoint { + t.Errorf("Expected ActiveDirectoryEndpoint to be %q, but got %q", env.ActiveDirectoryEndpoint, testSubject.ActiveDirectoryEndpoint) + } + if env.GalleryEndpoint != testSubject.GalleryEndpoint { + t.Errorf("Expected GalleryEndpoint to be %q, but got %q", env.GalleryEndpoint, testSubject.GalleryEndpoint) + } + if env.ServiceBusEndpoint != testSubject.ServiceBusEndpoint { + t.Errorf("Expected ServiceBusEnpoint to be %q, but got %q", env.ServiceBusEndpoint, testSubject.ServiceBusEndpoint) + } + if env.KeyVaultEndpoint != testSubject.KeyVaultEndpoint { + t.Errorf("Expected KeyVaultEndpoint to be %q, but got %q", env.KeyVaultEndpoint, testSubject.KeyVaultEndpoint) + } + if env.GraphEndpoint != testSubject.GraphEndpoint { + t.Errorf("Expected GraphEndpoint to be %q, but got %q", env.GraphEndpoint, testSubject.GraphEndpoint) + } + if env.StorageEndpointSuffix != testSubject.StorageEndpointSuffix { + t.Errorf("Expected StorageEndpointSuffix to be %q, but got %q", env.StorageEndpointSuffix, testSubject.StorageEndpointSuffix) + } + if env.SQLDatabaseDNSSuffix != testSubject.SQLDatabaseDNSSuffix { + t.Errorf("Expected SQLDatabaseDNSSuffix to be %q, but got %q", env.SQLDatabaseDNSSuffix, testSubject.SQLDatabaseDNSSuffix) + } + if env.TrafficManagerDNSSuffix != testSubject.TrafficManagerDNSSuffix { + t.Errorf("Expected TrafficManagerDNSSuffix to be %q, but got %q", env.TrafficManagerDNSSuffix, testSubject.TrafficManagerDNSSuffix) + } + if env.KeyVaultDNSSuffix != testSubject.KeyVaultDNSSuffix { + t.Errorf("Expected KeyVaultDNSSuffix to be %q, but got %q", env.KeyVaultDNSSuffix, testSubject.KeyVaultDNSSuffix) + } + if env.ServiceBusEndpointSuffix != testSubject.ServiceBusEndpointSuffix { + t.Errorf("Expected ServiceBusEndpointSuffix to be %q, but got %q", env.ServiceBusEndpointSuffix, testSubject.ServiceBusEndpointSuffix) + } + if env.ServiceManagementVMDNSSuffix != testSubject.ServiceManagementVMDNSSuffix { + t.Errorf("Expected ServiceManagementVMDNSSuffix to be %q, but got %q", env.ServiceManagementVMDNSSuffix, testSubject.ServiceManagementVMDNSSuffix) + } + if env.ResourceManagerVMDNSSuffix != testSubject.ResourceManagerVMDNSSuffix { + t.Errorf("Expected ResourceManagerVMDNSSuffix to be %q, but got %q", env.ResourceManagerVMDNSSuffix, testSubject.ResourceManagerVMDNSSuffix) + } + if env.ContainerRegistryDNSSuffix != testSubject.ContainerRegistryDNSSuffix { + t.Errorf("Expected ContainerRegistryDNSSuffix to be %q, but got %q", env.ContainerRegistryDNSSuffix, testSubject.ContainerRegistryDNSSuffix) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/rp_test.go b/vendor/github.com/Azure/go-autorest/autorest/azure/rp_test.go new file mode 100644 index 000000000..9bcebbb48 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/rp_test.go @@ -0,0 +1,126 @@ +// Copyright 2017 Microsoft 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 azure + +import ( + "net/http" + "testing" + "time" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/mocks" +) + +func TestDoRetryWithRegistration(t *testing.T) { + client := mocks.NewSender() + // first response, should retry because it is a transient error + client.AppendResponse(mocks.NewResponseWithStatus("Internal server error", http.StatusInternalServerError)) + // response indicates the resource provider has not been registered + client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{ + "error":{ + "code":"MissingSubscriptionRegistration", + "message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions.", + "details":[ + { + "code":"MissingSubscriptionRegistration", + "target":"Microsoft.EventGrid", + "message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions." + } + ] + } +} +`), http.StatusConflict, "MissingSubscriptionRegistration")) + // first poll response, still not ready + client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{ + "registrationState": "Registering" +} +`), http.StatusOK, "200 OK")) + // last poll response, respurce provider has been registered + client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{ + "registrationState": "Registered" +} +`), http.StatusOK, "200 OK")) + // retry original request, response is successful + client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK)) + + req := mocks.NewRequestForURL("https://lol/subscriptions/rofl") + req.Body = mocks.NewBody("lolol") + r, err := autorest.SendWithSender(client, req, + DoRetryWithRegistration(autorest.Client{ + PollingDelay: time.Second, + PollingDuration: time.Second * 10, + RetryAttempts: 5, + RetryDuration: time.Second, + Sender: client, + }), + ) + if err != nil { + t.Fatalf("got error: %v", err) + } + + autorest.Respond(r, + autorest.ByDiscardingBody(), + autorest.ByClosing(), + ) + + if r.StatusCode != http.StatusOK { + t.Fatalf("azure: Sender#DoRetryWithRegistration -- Got: StatusCode %v; Want: StatusCode 200 OK", r.StatusCode) + } +} + +func TestDoRetrySkipRegistration(t *testing.T) { + client := mocks.NewSender() + // first response, should retry because it is a transient error + client.AppendResponse(mocks.NewResponseWithStatus("Internal server error", http.StatusInternalServerError)) + // response indicates the resource provider has not been registered + client.AppendResponse(mocks.NewResponseWithBodyAndStatus(mocks.NewBody(`{ + "error":{ + "code":"MissingSubscriptionRegistration", + "message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions.", + "details":[ + { + "code":"MissingSubscriptionRegistration", + "target":"Microsoft.EventGrid", + "message":"The subscription registration is in 'Unregistered' state. The subscription must be registered to use namespace 'Microsoft.EventGrid'. See https://aka.ms/rps-not-found for how to register subscriptions." + } + ] + } +}`), http.StatusConflict, "MissingSubscriptionRegistration")) + + req := mocks.NewRequestForURL("https://lol/subscriptions/rofl") + req.Body = mocks.NewBody("lolol") + r, err := autorest.SendWithSender(client, req, + DoRetryWithRegistration(autorest.Client{ + PollingDelay: time.Second, + PollingDuration: time.Second * 10, + RetryAttempts: 5, + RetryDuration: time.Second, + Sender: client, + SkipResourceProviderRegistration: true, + }), + ) + if err != nil { + t.Fatalf("got error: %v", err) + } + + autorest.Respond(r, + autorest.ByDiscardingBody(), + autorest.ByClosing(), + ) + + if r.StatusCode != http.StatusConflict { + t.Fatalf("azure: Sender#DoRetryWithRegistration -- Got: StatusCode %v; Want: StatusCode 409 Conflict", r.StatusCode) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/client_test.go b/vendor/github.com/Azure/go-autorest/autorest/client_test.go new file mode 100644 index 000000000..151f8eedb --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/client_test.go @@ -0,0 +1,402 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "math/rand" + "net/http" + "net/http/httptest" + "reflect" + "testing" + "time" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +func TestLoggingInspectorWithInspection(t *testing.T) { + b := bytes.Buffer{} + c := Client{} + li := LoggingInspector{Logger: log.New(&b, "", 0)} + c.RequestInspector = li.WithInspection() + + Prepare(mocks.NewRequestWithContent("Content"), + c.WithInspection()) + + if len(b.String()) <= 0 { + t.Fatal("autorest: LoggingInspector#WithInspection did not record Request to the log") + } +} + +func TestLoggingInspectorWithInspectionEmitsErrors(t *testing.T) { + b := bytes.Buffer{} + c := Client{} + r := mocks.NewRequestWithContent("Content") + li := LoggingInspector{Logger: log.New(&b, "", 0)} + c.RequestInspector = li.WithInspection() + + if _, err := Prepare(r, + c.WithInspection()); err != nil { + t.Error(err) + } + + if len(b.String()) <= 0 { + t.Fatal("autorest: LoggingInspector#WithInspection did not record Request to the log") + } +} + +func TestLoggingInspectorWithInspectionRestoresBody(t *testing.T) { + b := bytes.Buffer{} + c := Client{} + r := mocks.NewRequestWithContent("Content") + li := LoggingInspector{Logger: log.New(&b, "", 0)} + c.RequestInspector = li.WithInspection() + + Prepare(r, + c.WithInspection()) + + s, _ := ioutil.ReadAll(r.Body) + if len(s) <= 0 { + t.Fatal("autorest: LoggingInspector#WithInspection did not restore the Request body") + } +} + +func TestLoggingInspectorByInspecting(t *testing.T) { + b := bytes.Buffer{} + c := Client{} + li := LoggingInspector{Logger: log.New(&b, "", 0)} + c.ResponseInspector = li.ByInspecting() + + Respond(mocks.NewResponseWithContent("Content"), + c.ByInspecting()) + + if len(b.String()) <= 0 { + t.Fatal("autorest: LoggingInspector#ByInspection did not record Response to the log") + } +} + +func TestLoggingInspectorByInspectingEmitsErrors(t *testing.T) { + b := bytes.Buffer{} + c := Client{} + r := mocks.NewResponseWithContent("Content") + li := LoggingInspector{Logger: log.New(&b, "", 0)} + c.ResponseInspector = li.ByInspecting() + + if err := Respond(r, + c.ByInspecting()); err != nil { + t.Fatal(err) + } + + if len(b.String()) <= 0 { + t.Fatal("autorest: LoggingInspector#ByInspection did not record Response to the log") + } +} + +func TestLoggingInspectorByInspectingRestoresBody(t *testing.T) { + b := bytes.Buffer{} + c := Client{} + r := mocks.NewResponseWithContent("Content") + li := LoggingInspector{Logger: log.New(&b, "", 0)} + c.ResponseInspector = li.ByInspecting() + + Respond(r, + c.ByInspecting()) + + s, _ := ioutil.ReadAll(r.Body) + if len(s) <= 0 { + t.Fatal("autorest: LoggingInspector#ByInspecting did not restore the Response body") + } +} + +func TestNewClientWithUserAgent(t *testing.T) { + ua := "UserAgent" + c := NewClientWithUserAgent(ua) + completeUA := fmt.Sprintf("%s %s", defaultUserAgent, ua) + + if c.UserAgent != completeUA { + t.Fatalf("autorest: NewClientWithUserAgent failed to set the UserAgent -- expected %s, received %s", + completeUA, c.UserAgent) + } +} + +func TestAddToUserAgent(t *testing.T) { + ua := "UserAgent" + c := NewClientWithUserAgent(ua) + ext := "extension" + err := c.AddToUserAgent(ext) + if err != nil { + t.Fatalf("autorest: AddToUserAgent returned error -- expected nil, received %s", err) + } + completeUA := fmt.Sprintf("%s %s %s", defaultUserAgent, ua, ext) + + if c.UserAgent != completeUA { + t.Fatalf("autorest: AddToUserAgent failed to add an extension to the UserAgent -- expected %s, received %s", + completeUA, c.UserAgent) + } + + err = c.AddToUserAgent("") + if err == nil { + t.Fatalf("autorest: AddToUserAgent didn't return error -- expected %s, received nil", + fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent)) + } + if c.UserAgent != completeUA { + t.Fatalf("autorest: AddToUserAgent failed to not add an empty extension to the UserAgent -- expected %s, received %s", + completeUA, c.UserAgent) + } +} + +func TestClientSenderReturnsHttpClientByDefault(t *testing.T) { + c := Client{} + + if fmt.Sprintf("%T", c.sender()) != "*http.Client" { + t.Fatal("autorest: Client#sender failed to return http.Client by default") + } +} + +func TestClientSenderReturnsSetSender(t *testing.T) { + c := Client{} + + s := mocks.NewSender() + c.Sender = s + + if c.sender() != s { + t.Fatal("autorest: Client#sender failed to return set Sender") + } +} + +func TestClientDoInvokesSender(t *testing.T) { + c := Client{} + + s := mocks.NewSender() + c.Sender = s + + c.Do(&http.Request{}) + if s.Attempts() != 1 { + t.Fatal("autorest: Client#Do failed to invoke the Sender") + } +} + +func TestClientDoSetsUserAgent(t *testing.T) { + ua := "UserAgent" + c := Client{UserAgent: ua} + r := mocks.NewRequest() + s := mocks.NewSender() + c.Sender = s + + c.Do(r) + + if r.UserAgent() != ua { + t.Fatalf("autorest: Client#Do failed to correctly set User-Agent header: %s=%s", + http.CanonicalHeaderKey(headerUserAgent), r.UserAgent()) + } +} + +func TestClientDoSetsAuthorization(t *testing.T) { + r := mocks.NewRequest() + s := mocks.NewSender() + c := Client{Authorizer: mockAuthorizer{}, Sender: s} + + c.Do(r) + if len(r.Header.Get(http.CanonicalHeaderKey(headerAuthorization))) <= 0 { + t.Fatalf("autorest: Client#Send failed to set Authorization header -- %s=%s", + http.CanonicalHeaderKey(headerAuthorization), + r.Header.Get(http.CanonicalHeaderKey(headerAuthorization))) + } +} + +func TestClientDoInvokesRequestInspector(t *testing.T) { + r := mocks.NewRequest() + s := mocks.NewSender() + i := &mockInspector{} + c := Client{RequestInspector: i.WithInspection(), Sender: s} + + c.Do(r) + if !i.wasInvoked { + t.Fatal("autorest: Client#Send failed to invoke the RequestInspector") + } +} + +func TestClientDoInvokesResponseInspector(t *testing.T) { + r := mocks.NewRequest() + s := mocks.NewSender() + i := &mockInspector{} + c := Client{ResponseInspector: i.ByInspecting(), Sender: s} + + c.Do(r) + if !i.wasInvoked { + t.Fatal("autorest: Client#Send failed to invoke the ResponseInspector") + } +} + +func TestClientDoReturnsErrorIfPrepareFails(t *testing.T) { + c := Client{} + s := mocks.NewSender() + c.Authorizer = mockFailingAuthorizer{} + c.Sender = s + + _, err := c.Do(&http.Request{}) + if err == nil { + t.Fatalf("autorest: Client#Do failed to return an error when Prepare failed") + } +} + +func TestClientDoDoesNotSendIfPrepareFails(t *testing.T) { + c := Client{} + s := mocks.NewSender() + c.Authorizer = mockFailingAuthorizer{} + c.Sender = s + + c.Do(&http.Request{}) + if s.Attempts() > 0 { + t.Fatal("autorest: Client#Do failed to invoke the Sender") + } +} + +func TestClientAuthorizerReturnsNullAuthorizerByDefault(t *testing.T) { + c := Client{} + + if fmt.Sprintf("%T", c.authorizer()) != "autorest.NullAuthorizer" { + t.Fatal("autorest: Client#authorizer failed to return the NullAuthorizer by default") + } +} + +func TestClientAuthorizerReturnsSetAuthorizer(t *testing.T) { + c := Client{} + c.Authorizer = mockAuthorizer{} + + if fmt.Sprintf("%T", c.authorizer()) != "autorest.mockAuthorizer" { + t.Fatal("autorest: Client#authorizer failed to return the set Authorizer") + } +} + +func TestClientWithAuthorizer(t *testing.T) { + c := Client{} + c.Authorizer = mockAuthorizer{} + + req, _ := Prepare(&http.Request{}, + c.WithAuthorization()) + + if req.Header.Get(headerAuthorization) == "" { + t.Fatal("autorest: Client#WithAuthorizer failed to return the WithAuthorizer from the active Authorizer") + } +} + +func TestClientWithInspection(t *testing.T) { + c := Client{} + r := &mockInspector{} + c.RequestInspector = r.WithInspection() + + Prepare(&http.Request{}, + c.WithInspection()) + + if !r.wasInvoked { + t.Fatal("autorest: Client#WithInspection failed to invoke RequestInspector") + } +} + +func TestClientWithInspectionSetsDefault(t *testing.T) { + c := Client{} + + r1 := &http.Request{} + r2, _ := Prepare(r1, + c.WithInspection()) + + if !reflect.DeepEqual(r1, r2) { + t.Fatal("autorest: Client#WithInspection failed to provide a default RequestInspector") + } +} + +func TestClientByInspecting(t *testing.T) { + c := Client{} + r := &mockInspector{} + c.ResponseInspector = r.ByInspecting() + + Respond(&http.Response{}, + c.ByInspecting()) + + if !r.wasInvoked { + t.Fatal("autorest: Client#ByInspecting failed to invoke ResponseInspector") + } +} + +func TestClientByInspectingSetsDefault(t *testing.T) { + c := Client{} + + r := &http.Response{} + Respond(r, + c.ByInspecting()) + + if !reflect.DeepEqual(r, &http.Response{}) { + t.Fatal("autorest: Client#ByInspecting failed to provide a default ResponseInspector") + } +} + +func TestCookies(t *testing.T) { + second := "second" + expected := http.Cookie{ + Name: "tastes", + Value: "delicious", + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.SetCookie(w, &expected) + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: ioutil.ReadAll failed reading request body: %s", err) + } + if string(b) == second { + cookie, err := r.Cookie(expected.Name) + if err != nil { + t.Fatalf("autorest: r.Cookie could not get request cookie: %s", err) + } + if cookie == nil { + t.Fatalf("autorest: got nil cookie, expecting %v", expected) + } + if cookie.Value != expected.Value { + t.Fatalf("autorest: got cookie value '%s', expecting '%s'", cookie.Value, expected.Name) + } + } + })) + defer server.Close() + + client := NewClientWithUserAgent("") + _, err := SendWithSender(client, mocks.NewRequestForURL(server.URL)) + if err != nil { + t.Fatalf("autorest: first request failed: %s", err) + } + + r2, err := http.NewRequest(http.MethodGet, server.URL, mocks.NewBody(second)) + if err != nil { + t.Fatalf("autorest: failed creating second request: %s", err) + } + + _, err = SendWithSender(client, r2) + if err != nil { + t.Fatalf("autorest: second request failed: %s", err) + } +} + +func randomString(n int) string { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + r := rand.New(rand.NewSource(time.Now().UTC().UnixNano())) + s := make([]byte, n) + for i := range s { + s[i] = chars[r.Intn(len(chars))] + } + return string(s) +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/date_test.go b/vendor/github.com/Azure/go-autorest/autorest/date/date_test.go new file mode 100644 index 000000000..4a40bbc3e --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/date/date_test.go @@ -0,0 +1,237 @@ +package date + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + "time" +) + +func ExampleParseDate() { + d, err := ParseDate("2001-02-03") + if err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: 2001-02-03 +} + +func ExampleDate() { + d, err := ParseDate("2001-02-03") + if err != nil { + fmt.Println(err) + } + + t, err := time.Parse(time.RFC3339, "2001-02-04T00:00:00Z") + if err != nil { + fmt.Println(err) + } + + // Date acts as time.Time when the receiver + if d.Before(t) { + fmt.Printf("Before ") + } else { + fmt.Printf("After ") + } + + // Convert Date when needing a time.Time + if t.After(d.ToTime()) { + fmt.Printf("After") + } else { + fmt.Printf("Before") + } + // Output: Before After +} + +func ExampleDate_MarshalBinary() { + d, err := ParseDate("2001-02-03") + if err != nil { + fmt.Println(err) + } + t, err := d.MarshalBinary() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(t)) + // Output: 2001-02-03 +} + +func ExampleDate_UnmarshalBinary() { + d := Date{} + t := "2001-02-03" + + if err := d.UnmarshalBinary([]byte(t)); err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: 2001-02-03 +} + +func ExampleDate_MarshalJSON() { + d, err := ParseDate("2001-02-03") + if err != nil { + fmt.Println(err) + } + j, err := json.Marshal(d) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(j)) + // Output: "2001-02-03" +} + +func ExampleDate_UnmarshalJSON() { + var d struct { + Date Date `json:"date"` + } + j := `{"date" : "2001-02-03"}` + + if err := json.Unmarshal([]byte(j), &d); err != nil { + fmt.Println(err) + } + fmt.Println(d.Date) + // Output: 2001-02-03 +} + +func ExampleDate_MarshalText() { + d, err := ParseDate("2001-02-03") + if err != nil { + fmt.Println(err) + } + t, err := d.MarshalText() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(t)) + // Output: 2001-02-03 +} + +func ExampleDate_UnmarshalText() { + d := Date{} + t := "2001-02-03" + + if err := d.UnmarshalText([]byte(t)); err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: 2001-02-03 +} + +func TestDateString(t *testing.T) { + d, err := ParseDate("2001-02-03") + if err != nil { + t.Fatalf("date: String failed (%v)", err) + } + if d.String() != "2001-02-03" { + t.Fatalf("date: String failed (%v)", d.String()) + } +} + +func TestDateBinaryRoundTrip(t *testing.T) { + d1, err := ParseDate("2001-02-03") + if err != nil { + t.Fatalf("date: ParseDate failed (%v)", err) + } + t1, err := d1.MarshalBinary() + if err != nil { + t.Fatalf("date: MarshalBinary failed (%v)", err) + } + + d2 := Date{} + if err = d2.UnmarshalBinary(t1); err != nil { + t.Fatalf("date: UnmarshalBinary failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip Binary failed (%v, %v)", d1, d2) + } +} + +func TestDateJSONRoundTrip(t *testing.T) { + type s struct { + Date Date `json:"date"` + } + var err error + d1 := s{} + d1.Date, err = ParseDate("2001-02-03") + if err != nil { + t.Fatalf("date: ParseDate failed (%v)", err) + } + + j, err := json.Marshal(d1) + if err != nil { + t.Fatalf("date: MarshalJSON failed (%v)", err) + } + + d2 := s{} + if err = json.Unmarshal(j, &d2); err != nil { + t.Fatalf("date: UnmarshalJSON failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip JSON failed (%v, %v)", d1, d2) + } +} + +func TestDateTextRoundTrip(t *testing.T) { + d1, err := ParseDate("2001-02-03") + if err != nil { + t.Fatalf("date: ParseDate failed (%v)", err) + } + t1, err := d1.MarshalText() + if err != nil { + t.Fatalf("date: MarshalText failed (%v)", err) + } + d2 := Date{} + if err = d2.UnmarshalText(t1); err != nil { + t.Fatalf("date: UnmarshalText failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip Text failed (%v, %v)", d1, d2) + } +} + +func TestDateToTime(t *testing.T) { + var d Date + d, err := ParseDate("2001-02-03") + if err != nil { + t.Fatalf("date: ParseDate failed (%v)", err) + } + var _ time.Time = d.ToTime() +} + +func TestDateUnmarshalJSONReturnsError(t *testing.T) { + var d struct { + Date Date `json:"date"` + } + j := `{"date" : "February 3, 2001"}` + + if err := json.Unmarshal([]byte(j), &d); err == nil { + t.Fatal("date: Date failed to return error for malformed JSON date") + } +} + +func TestDateUnmarshalTextReturnsError(t *testing.T) { + d := Date{} + txt := "February 3, 2001" + + if err := d.UnmarshalText([]byte(txt)); err == nil { + t.Fatal("date: Date failed to return error for malformed Text date") + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/time_test.go b/vendor/github.com/Azure/go-autorest/autorest/date/time_test.go new file mode 100644 index 000000000..d8c811707 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/date/time_test.go @@ -0,0 +1,277 @@ +package date + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + "time" +) + +func ExampleParseTime() { + d, _ := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + fmt.Println(d) + // Output: 2001-02-03 04:05:06 +0000 UTC +} + +func ExampleTime_MarshalBinary() { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + fmt.Println(err) + } + d := Time{ti} + t, err := d.MarshalBinary() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(t)) + // Output: 2001-02-03T04:05:06Z +} + +func ExampleTime_UnmarshalBinary() { + d := Time{} + t := "2001-02-03T04:05:06Z" + + if err := d.UnmarshalBinary([]byte(t)); err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: 2001-02-03T04:05:06Z +} + +func ExampleTime_MarshalJSON() { + d, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + fmt.Println(err) + } + j, err := json.Marshal(d) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(j)) + // Output: "2001-02-03T04:05:06Z" +} + +func ExampleTime_UnmarshalJSON() { + var d struct { + Time Time `json:"datetime"` + } + j := `{"datetime" : "2001-02-03T04:05:06Z"}` + + if err := json.Unmarshal([]byte(j), &d); err != nil { + fmt.Println(err) + } + fmt.Println(d.Time) + // Output: 2001-02-03T04:05:06Z +} + +func ExampleTime_MarshalText() { + d, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + fmt.Println(err) + } + t, err := d.MarshalText() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(t)) + // Output: 2001-02-03T04:05:06Z +} + +func ExampleTime_UnmarshalText() { + d := Time{} + t := "2001-02-03T04:05:06Z" + + if err := d.UnmarshalText([]byte(t)); err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: 2001-02-03T04:05:06Z +} + +func TestUnmarshalTextforInvalidDate(t *testing.T) { + d := Time{} + dt := "2001-02-03T04:05:06AAA" + + if err := d.UnmarshalText([]byte(dt)); err == nil { + t.Fatalf("date: Time#Unmarshal was expecting error for invalid date") + } +} + +func TestUnmarshalJSONforInvalidDate(t *testing.T) { + d := Time{} + dt := `"2001-02-03T04:05:06AAA"` + + if err := d.UnmarshalJSON([]byte(dt)); err == nil { + t.Fatalf("date: Time#Unmarshal was expecting error for invalid date") + } +} + +func TestTimeString(t *testing.T) { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + fmt.Println(err) + } + d := Time{ti} + if d.String() != "2001-02-03T04:05:06Z" { + t.Fatalf("date: Time#String failed (%v)", d.String()) + } +} + +func TestTimeStringReturnsEmptyStringForError(t *testing.T) { + d := Time{Time: time.Date(20000, 01, 01, 01, 01, 01, 01, time.UTC)} + if d.String() != "" { + t.Fatalf("date: Time#String failed empty string for an error") + } +} + +func TestTimeBinaryRoundTrip(t *testing.T) { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + t.Fatalf("date: Time#ParseTime failed (%v)", err) + } + d1 := Time{ti} + t1, err := d1.MarshalBinary() + if err != nil { + t.Fatalf("date: Time#MarshalBinary failed (%v)", err) + } + + d2 := Time{} + if err = d2.UnmarshalBinary(t1); err != nil { + t.Fatalf("date: Time#UnmarshalBinary failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date:Round-trip Binary failed (%v, %v)", d1, d2) + } +} + +func TestTimeJSONRoundTrip(t *testing.T) { + type s struct { + Time Time `json:"datetime"` + } + + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + t.Fatalf("date: Time#ParseTime failed (%v)", err) + } + + d1 := s{Time: Time{ti}} + j, err := json.Marshal(d1) + if err != nil { + t.Fatalf("date: Time#MarshalJSON failed (%v)", err) + } + + d2 := s{} + if err = json.Unmarshal(j, &d2); err != nil { + t.Fatalf("date: Time#UnmarshalJSON failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip JSON failed (%v, %v)", d1, d2) + } +} + +func TestTimeTextRoundTrip(t *testing.T) { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + t.Fatalf("date: Time#ParseTime failed (%v)", err) + } + d1 := Time{Time: ti} + t1, err := d1.MarshalText() + if err != nil { + t.Fatalf("date: Time#MarshalText failed (%v)", err) + } + + d2 := Time{} + if err = d2.UnmarshalText(t1); err != nil { + t.Fatalf("date: Time#UnmarshalText failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip Text failed (%v, %v)", d1, d2) + } +} + +func TestTimeToTime(t *testing.T) { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + d := Time{ti} + if err != nil { + t.Fatalf("date: Time#ParseTime failed (%v)", err) + } + var _ time.Time = d.ToTime() +} + +func TestUnmarshalJSONNoOffset(t *testing.T) { + var d struct { + Time Time `json:"datetime"` + } + j := `{"datetime" : "2001-02-03T04:05:06.789"}` + + if err := json.Unmarshal([]byte(j), &d); err != nil { + t.Fatalf("date: Time#Unmarshal failed (%v)", err) + } +} + +func TestUnmarshalJSONPosOffset(t *testing.T) { + var d struct { + Time Time `json:"datetime"` + } + j := `{"datetime" : "1980-01-02T00:11:35.01+01:00"}` + + if err := json.Unmarshal([]byte(j), &d); err != nil { + t.Fatalf("date: Time#Unmarshal failed (%v)", err) + } +} + +func TestUnmarshalJSONNegOffset(t *testing.T) { + var d struct { + Time Time `json:"datetime"` + } + j := `{"datetime" : "1492-10-12T10:15:01.789-08:00"}` + + if err := json.Unmarshal([]byte(j), &d); err != nil { + t.Fatalf("date: Time#Unmarshal failed (%v)", err) + } +} + +func TestUnmarshalTextNoOffset(t *testing.T) { + d := Time{} + t1 := "2001-02-03T04:05:06" + + if err := d.UnmarshalText([]byte(t1)); err != nil { + t.Fatalf("date: Time#UnmarshalText failed (%v)", err) + } +} + +func TestUnmarshalTextPosOffset(t *testing.T) { + d := Time{} + t1 := "2001-02-03T04:05:06+00:30" + + if err := d.UnmarshalText([]byte(t1)); err != nil { + t.Fatalf("date: Time#UnmarshalText failed (%v)", err) + } +} + +func TestUnmarshalTextNegOffset(t *testing.T) { + d := Time{} + t1 := "2001-02-03T04:05:06-11:00" + + if err := d.UnmarshalText([]byte(t1)); err != nil { + t.Fatalf("date: Time#UnmarshalText failed (%v)", err) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123_test.go b/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123_test.go new file mode 100644 index 000000000..dfd640513 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123_test.go @@ -0,0 +1,226 @@ +package date + +// Copyright 2017 Microsoft 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. + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + "time" +) + +func ExampleTimeRFC1123() { + d, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + if err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: 2006-01-02 15:04:05 +0000 MST +} + +func ExampleTimeRFC1123_MarshalBinary() { + ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + if err != nil { + fmt.Println(err) + } + d := TimeRFC1123{ti} + b, err := d.MarshalBinary() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(b)) + // Output: Mon, 02 Jan 2006 15:04:05 MST +} + +func ExampleTimeRFC1123_UnmarshalBinary() { + d := TimeRFC1123{} + t := "Mon, 02 Jan 2006 15:04:05 MST" + if err := d.UnmarshalBinary([]byte(t)); err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: Mon, 02 Jan 2006 15:04:05 MST +} + +func ExampleTimeRFC1123_MarshalJSON() { + ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + if err != nil { + fmt.Println(err) + } + d := TimeRFC1123{ti} + j, err := json.Marshal(d) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(j)) + // Output: "Mon, 02 Jan 2006 15:04:05 MST" +} + +func TestTimeRFC1123MarshalJSONInvalid(t *testing.T) { + ti := time.Date(20000, 01, 01, 00, 00, 00, 00, time.UTC) + d := TimeRFC1123{ti} + if _, err := json.Marshal(d); err == nil { + t.Fatalf("date: TimeRFC1123#Marshal failed for invalid date") + } +} + +func ExampleTimeRFC1123_UnmarshalJSON() { + var d struct { + Time TimeRFC1123 `json:"datetime"` + } + j := `{"datetime" : "Mon, 02 Jan 2006 15:04:05 MST"}` + + if err := json.Unmarshal([]byte(j), &d); err != nil { + fmt.Println(err) + } + fmt.Println(d.Time) + // Output: Mon, 02 Jan 2006 15:04:05 MST +} + +func ExampleTimeRFC1123_MarshalText() { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + fmt.Println(err) + } + d := TimeRFC1123{ti} + t, err := d.MarshalText() + if err != nil { + fmt.Println(err) + } + fmt.Println(string(t)) + // Output: Sat, 03 Feb 2001 04:05:06 UTC +} + +func ExampleTimeRFC1123_UnmarshalText() { + d := TimeRFC1123{} + t := "Sat, 03 Feb 2001 04:05:06 UTC" + + if err := d.UnmarshalText([]byte(t)); err != nil { + fmt.Println(err) + } + fmt.Println(d) + // Output: Sat, 03 Feb 2001 04:05:06 UTC +} + +func TestUnmarshalJSONforInvalidDateRfc1123(t *testing.T) { + dt := `"Mon, 02 Jan 2000000 15:05 MST"` + d := TimeRFC1123{} + if err := d.UnmarshalJSON([]byte(dt)); err == nil { + t.Fatalf("date: TimeRFC1123#Unmarshal failed for invalid date") + } +} + +func TestUnmarshalTextforInvalidDateRfc1123(t *testing.T) { + dt := "Mon, 02 Jan 2000000 15:05 MST" + d := TimeRFC1123{} + if err := d.UnmarshalText([]byte(dt)); err == nil { + t.Fatalf("date: TimeRFC1123#Unmarshal failed for invalid date") + } +} + +func TestTimeStringRfc1123(t *testing.T) { + ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + if err != nil { + fmt.Println(err) + } + d := TimeRFC1123{ti} + if d.String() != "Mon, 02 Jan 2006 15:04:05 MST" { + t.Fatalf("date: TimeRFC1123#String failed (%v)", d.String()) + } +} + +func TestTimeStringReturnsEmptyStringForErrorRfc1123(t *testing.T) { + d := TimeRFC1123{Time: time.Date(20000, 01, 01, 01, 01, 01, 01, time.UTC)} + if d.String() != "" { + t.Fatalf("date: TimeRFC1123#String failed empty string for an error") + } +} + +func TestTimeBinaryRoundTripRfc1123(t *testing.T) { + ti, err := ParseTime(rfc3339, "2001-02-03T04:05:06Z") + if err != nil { + t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err) + } + d1 := TimeRFC1123{ti} + t1, err := d1.MarshalBinary() + if err != nil { + t.Fatalf("date: TimeRFC1123#MarshalBinary failed (%v)", err) + } + + d2 := TimeRFC1123{} + if err = d2.UnmarshalBinary(t1); err != nil { + t.Fatalf("date: TimeRFC1123#UnmarshalBinary failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip Binary failed (%v, %v)", d1, d2) + } +} + +func TestTimeJSONRoundTripRfc1123(t *testing.T) { + type s struct { + Time TimeRFC1123 `json:"datetime"` + } + var err error + ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + if err != nil { + t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err) + } + d1 := s{Time: TimeRFC1123{ti}} + j, err := json.Marshal(d1) + if err != nil { + t.Fatalf("date: TimeRFC1123#MarshalJSON failed (%v)", err) + } + + d2 := s{} + if err = json.Unmarshal(j, &d2); err != nil { + t.Fatalf("date: TimeRFC1123#UnmarshalJSON failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip JSON failed (%v, %v)", d1, d2) + } +} + +func TestTimeTextRoundTripRfc1123(t *testing.T) { + ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + if err != nil { + t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err) + } + d1 := TimeRFC1123{Time: ti} + t1, err := d1.MarshalText() + if err != nil { + t.Fatalf("date: TimeRFC1123#MarshalText failed (%v)", err) + } + + d2 := TimeRFC1123{} + if err = d2.UnmarshalText(t1); err != nil { + t.Fatalf("date: TimeRFC1123#UnmarshalText failed (%v)", err) + } + + if !reflect.DeepEqual(d1, d2) { + t.Fatalf("date: Round-trip Text failed (%v, %v)", d1, d2) + } +} + +func TestTimeToTimeRFC1123(t *testing.T) { + ti, err := ParseTime(rfc1123, "Mon, 02 Jan 2006 15:04:05 MST") + d := TimeRFC1123{ti} + if err != nil { + t.Fatalf("date: TimeRFC1123#ParseTime failed (%v)", err) + } + var _ time.Time = d.ToTime() +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/unixtime_test.go b/vendor/github.com/Azure/go-autorest/autorest/date/unixtime_test.go new file mode 100644 index 000000000..3fa347c00 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/date/unixtime_test.go @@ -0,0 +1,283 @@ +// +build go1.7 + +package date + +// Copyright 2017 Microsoft 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. + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "math" + "testing" + "time" +) + +func ExampleUnixTime_MarshalJSON() { + epoch := UnixTime(UnixEpoch()) + text, _ := json.Marshal(epoch) + fmt.Print(string(text)) + // Output: 0 +} + +func ExampleUnixTime_UnmarshalJSON() { + var myTime UnixTime + json.Unmarshal([]byte("1.3e2"), &myTime) + fmt.Printf("%v", time.Time(myTime)) + // Output: 1970-01-01 00:02:10 +0000 UTC +} + +func TestUnixTime_MarshalJSON(t *testing.T) { + testCases := []time.Time{ + UnixEpoch().Add(-1 * time.Second), // One second befote the Unix Epoch + time.Date(2017, time.April, 14, 20, 27, 47, 0, time.UTC), // The time this test was written + UnixEpoch(), + time.Date(1800, 01, 01, 0, 0, 0, 0, time.UTC), + time.Date(2200, 12, 29, 00, 01, 37, 82, time.UTC), + } + + for _, tc := range testCases { + t.Run(tc.String(), func(subT *testing.T) { + var actual, expected float64 + var marshaled []byte + + target := UnixTime(tc) + expected = float64(target.Duration().Nanoseconds()) / 1e9 + + if temp, err := json.Marshal(target); err == nil { + marshaled = temp + } else { + subT.Error(err) + return + } + + dec := json.NewDecoder(bytes.NewReader(marshaled)) + if err := dec.Decode(&actual); err != nil { + subT.Error(err) + return + } + + diff := math.Abs(actual - expected) + subT.Logf("\ngot :\t%g\nwant:\t%g\ndiff:\t%g", actual, expected, diff) + if diff > 1e-9 { //Must be within 1 nanosecond of one another + subT.Fail() + } + }) + } +} + +func TestUnixTime_UnmarshalJSON(t *testing.T) { + testCases := []struct { + text string + expected time.Time + }{ + {"1", UnixEpoch().Add(time.Second)}, + {"0", UnixEpoch()}, + {"1492203742", time.Date(2017, time.April, 14, 21, 02, 22, 0, time.UTC)}, // The time this test was written + {"-1", time.Date(1969, time.December, 31, 23, 59, 59, 0, time.UTC)}, + {"1.5", UnixEpoch().Add(1500 * time.Millisecond)}, + {"0e1", UnixEpoch()}, // See http://json.org for 'number' format definition. + {"1.3e+2", UnixEpoch().Add(130 * time.Second)}, + {"1.6E-10", UnixEpoch()}, // This is so small, it should get truncated into the UnixEpoch + {"2E-6", UnixEpoch().Add(2 * time.Microsecond)}, + {"1.289345e9", UnixEpoch().Add(1289345000 * time.Second)}, + {"1e-9", UnixEpoch().Add(time.Nanosecond)}, + } + + for _, tc := range testCases { + t.Run(tc.text, func(subT *testing.T) { + var rehydrated UnixTime + if err := json.Unmarshal([]byte(tc.text), &rehydrated); err != nil { + subT.Error(err) + return + } + + if time.Time(rehydrated) != tc.expected { + subT.Logf("\ngot: \t%v\nwant:\t%v\ndiff:\t%v", time.Time(rehydrated), tc.expected, time.Time(rehydrated).Sub(tc.expected)) + subT.Fail() + } + }) + } +} + +func TestUnixTime_JSONRoundTrip(t *testing.T) { + testCases := []time.Time{ + UnixEpoch(), + time.Date(2005, time.November, 5, 0, 0, 0, 0, time.UTC), // The day V for Vendetta (film) was released. + UnixEpoch().Add(-6 * time.Second), + UnixEpoch().Add(800 * time.Hour), + UnixEpoch().Add(time.Nanosecond), + time.Date(2015, time.September, 05, 4, 30, 12, 9992, time.UTC), + } + + for _, tc := range testCases { + t.Run(tc.String(), func(subT *testing.T) { + subject := UnixTime(tc) + var marshaled []byte + if temp, err := json.Marshal(subject); err == nil { + marshaled = temp + } else { + subT.Error(err) + return + } + + var unmarshaled UnixTime + if err := json.Unmarshal(marshaled, &unmarshaled); err != nil { + subT.Error(err) + } + + actual := time.Time(unmarshaled) + diff := actual.Sub(tc) + subT.Logf("\ngot :\t%s\nwant:\t%s\ndiff:\t%s", actual.String(), tc.String(), diff.String()) + + if diff > time.Duration(100) { // We lose some precision be working in floats. We shouldn't lose more than 100 nanoseconds. + subT.Fail() + } + }) + } +} + +func TestUnixTime_MarshalBinary(t *testing.T) { + testCases := []struct { + expected int64 + subject time.Time + }{ + {0, UnixEpoch()}, + {-15 * int64(time.Second), UnixEpoch().Add(-15 * time.Second)}, + {54, UnixEpoch().Add(54 * time.Nanosecond)}, + } + + for _, tc := range testCases { + t.Run("", func(subT *testing.T) { + var marshaled []byte + + if temp, err := UnixTime(tc.subject).MarshalBinary(); err == nil { + marshaled = temp + } else { + subT.Error(err) + return + } + + var unmarshaled int64 + if err := binary.Read(bytes.NewReader(marshaled), binary.LittleEndian, &unmarshaled); err != nil { + subT.Error(err) + return + } + + if unmarshaled != tc.expected { + subT.Logf("\ngot: \t%d\nwant:\t%d", unmarshaled, tc.expected) + subT.Fail() + } + }) + } +} + +func TestUnixTime_BinaryRoundTrip(t *testing.T) { + testCases := []time.Time{ + UnixEpoch(), + UnixEpoch().Add(800 * time.Minute), + UnixEpoch().Add(7 * time.Hour), + UnixEpoch().Add(-1 * time.Nanosecond), + } + + for _, tc := range testCases { + t.Run(tc.String(), func(subT *testing.T) { + original := UnixTime(tc) + var marshaled []byte + + if temp, err := original.MarshalBinary(); err == nil { + marshaled = temp + } else { + subT.Error(err) + return + } + + var traveled UnixTime + if err := traveled.UnmarshalBinary(marshaled); err != nil { + subT.Error(err) + return + } + + if traveled != original { + subT.Logf("\ngot: \t%s\nwant:\t%s", time.Time(original).String(), time.Time(traveled).String()) + subT.Fail() + } + }) + } +} + +func TestUnixTime_MarshalText(t *testing.T) { + testCases := []time.Time{ + UnixEpoch(), + UnixEpoch().Add(45 * time.Second), + UnixEpoch().Add(time.Nanosecond), + UnixEpoch().Add(-100000 * time.Second), + } + + for _, tc := range testCases { + expected, _ := tc.MarshalText() + t.Run("", func(subT *testing.T) { + var marshaled []byte + + if temp, err := UnixTime(tc).MarshalText(); err == nil { + marshaled = temp + } else { + subT.Error(err) + return + } + + if string(marshaled) != string(expected) { + subT.Logf("\ngot: \t%s\nwant:\t%s", string(marshaled), string(expected)) + subT.Fail() + } + }) + } +} + +func TestUnixTime_TextRoundTrip(t *testing.T) { + testCases := []time.Time{ + UnixEpoch(), + UnixEpoch().Add(-1 * time.Nanosecond), + UnixEpoch().Add(1 * time.Nanosecond), + time.Date(2017, time.April, 17, 21, 00, 00, 00, time.UTC), + } + + for _, tc := range testCases { + t.Run(tc.String(), func(subT *testing.T) { + unixTC := UnixTime(tc) + + var marshaled []byte + + if temp, err := unixTC.MarshalText(); err == nil { + marshaled = temp + } else { + subT.Error(err) + return + } + + var unmarshaled UnixTime + if err := unmarshaled.UnmarshalText(marshaled); err != nil { + subT.Error(err) + return + } + + if unmarshaled != unixTC { + t.Logf("\ngot: \t%s\nwant:\t%s", time.Time(unmarshaled).String(), tc.String()) + t.Fail() + } + }) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/error_test.go b/vendor/github.com/Azure/go-autorest/autorest/error_test.go new file mode 100644 index 000000000..f4f5d75ef --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/error_test.go @@ -0,0 +1,202 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "fmt" + "net/http" + "reflect" + "regexp" + "testing" +) + +func TestNewErrorWithError_AssignsPackageType(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if e.PackageType != "packageType" { + t.Fatalf("autorest: Error failed to set package type -- expected %v, received %v", "packageType", e.PackageType) + } +} + +func TestNewErrorWithError_AssignsMethod(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if e.Method != "method" { + t.Fatalf("autorest: Error failed to set method -- expected %v, received %v", "method", e.Method) + } +} + +func TestNewErrorWithError_AssignsMessage(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if e.Message != "message" { + t.Fatalf("autorest: Error failed to set message -- expected %v, received %v", "message", e.Message) + } +} + +func TestNewErrorWithError_AssignsUndefinedStatusCodeIfRespNil(t *testing.T) { + e := NewErrorWithError(nil, "packageType", "method", nil, "message") + if e.StatusCode != UndefinedStatusCode { + t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", UndefinedStatusCode, e.StatusCode) + } +} + +func TestNewErrorWithError_AssignsStatusCode(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", &http.Response{ + StatusCode: http.StatusBadRequest, + Status: http.StatusText(http.StatusBadRequest)}, "message") + + if e.StatusCode != http.StatusBadRequest { + t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", http.StatusBadRequest, e.StatusCode) + } +} + +func TestNewErrorWithError_AcceptsArgs(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message %s", "arg") + + if matched, _ := regexp.MatchString(`.*arg.*`, e.Message); !matched { + t.Fatalf("autorest: Error failed to apply message arguments -- expected %v, received %v", + `.*arg.*`, e.Message) + } +} + +func TestNewErrorWithError_AssignsError(t *testing.T) { + err := fmt.Errorf("original") + e := NewErrorWithError(err, "packageType", "method", nil, "message") + + if e.Original != err { + t.Fatalf("autorest: Error failed to set error -- expected %v, received %v", err, e.Original) + } +} + +func TestNewErrorWithResponse_ContainsStatusCode(t *testing.T) { + e := NewErrorWithResponse("packageType", "method", &http.Response{ + StatusCode: http.StatusBadRequest, + Status: http.StatusText(http.StatusBadRequest)}, "message") + + if e.StatusCode != http.StatusBadRequest { + t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", http.StatusBadRequest, e.StatusCode) + } +} + +func TestNewErrorWithResponse_nilResponse_ReportsUndefinedStatusCode(t *testing.T) { + e := NewErrorWithResponse("packageType", "method", nil, "message") + + if e.StatusCode != UndefinedStatusCode { + t.Fatalf("autorest: Error failed to set status code -- expected %v, received %v", UndefinedStatusCode, e.StatusCode) + } +} + +func TestNewErrorWithResponse_Forwards(t *testing.T) { + e1 := NewError("packageType", "method", "message %s", "arg") + e2 := NewErrorWithResponse("packageType", "method", nil, "message %s", "arg") + + if !reflect.DeepEqual(e1, e2) { + t.Fatal("autorest: NewError did not return an error equivelent to NewErrorWithError") + } +} + +func TestNewErrorWithError_Forwards(t *testing.T) { + e1 := NewError("packageType", "method", "message %s", "arg") + e2 := NewErrorWithError(nil, "packageType", "method", nil, "message %s", "arg") + + if !reflect.DeepEqual(e1, e2) { + t.Fatal("autorest: NewError did not return an error equivelent to NewErrorWithError") + } +} + +func TestNewErrorWithError_DoesNotWrapADetailedError(t *testing.T) { + e1 := NewError("packageType1", "method1", "message1 %s", "arg1") + e2 := NewErrorWithError(e1, "packageType2", "method2", nil, "message2 %s", "arg2") + + if !reflect.DeepEqual(e1, e2) { + t.Fatalf("autorest: NewErrorWithError incorrectly wrapped a DetailedError -- expected %v, received %v", e1, e2) + } +} + +func TestNewErrorWithError_WrapsAnError(t *testing.T) { + e1 := fmt.Errorf("Inner Error") + var e2 interface{} = NewErrorWithError(e1, "packageType", "method", nil, "message") + + if _, ok := e2.(DetailedError); !ok { + t.Fatalf("autorest: NewErrorWithError failed to wrap a standard error -- received %T", e2) + } +} + +func TestDetailedError(t *testing.T) { + err := fmt.Errorf("original") + e := NewErrorWithError(err, "packageType", "method", nil, "message") + + if matched, _ := regexp.MatchString(`.*original.*`, e.Error()); !matched { + t.Fatalf("autorest: Error#Error failed to return original error message -- expected %v, received %v", + `.*original.*`, e.Error()) + } +} + +func TestDetailedErrorConstainsPackageType(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if matched, _ := regexp.MatchString(`.*packageType.*`, e.Error()); !matched { + t.Fatalf("autorest: Error#String failed to include PackageType -- expected %v, received %v", + `.*packageType.*`, e.Error()) + } +} + +func TestDetailedErrorConstainsMethod(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if matched, _ := regexp.MatchString(`.*method.*`, e.Error()); !matched { + t.Fatalf("autorest: Error#String failed to include Method -- expected %v, received %v", + `.*method.*`, e.Error()) + } +} + +func TestDetailedErrorConstainsMessage(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if matched, _ := regexp.MatchString(`.*message.*`, e.Error()); !matched { + t.Fatalf("autorest: Error#String failed to include Message -- expected %v, received %v", + `.*message.*`, e.Error()) + } +} + +func TestDetailedErrorConstainsStatusCode(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", &http.Response{ + StatusCode: http.StatusBadRequest, + Status: http.StatusText(http.StatusBadRequest)}, "message") + + if matched, _ := regexp.MatchString(`.*400.*`, e.Error()); !matched { + t.Fatalf("autorest: Error#String failed to include Status Code -- expected %v, received %v", + `.*400.*`, e.Error()) + } +} + +func TestDetailedErrorConstainsOriginal(t *testing.T) { + e := NewErrorWithError(fmt.Errorf("original"), "packageType", "method", nil, "message") + + if matched, _ := regexp.MatchString(`.*original.*`, e.Error()); !matched { + t.Fatalf("autorest: Error#String failed to include Original error -- expected %v, received %v", + `.*original.*`, e.Error()) + } +} + +func TestDetailedErrorSkipsOriginal(t *testing.T) { + e := NewError("packageType", "method", "message") + + if matched, _ := regexp.MatchString(`.*Original.*`, e.Error()); matched { + t.Fatalf("autorest: Error#String included missing Original error -- unexpected %v, received %v", + `.*Original.*`, e.Error()) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/preparer_test.go b/vendor/github.com/Azure/go-autorest/autorest/preparer_test.go new file mode 100644 index 000000000..b4d19967b --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/preparer_test.go @@ -0,0 +1,802 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "strconv" + "strings" + "testing" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +// PrepareDecorators wrap and invoke a Preparer. Most often, the decorator invokes the passed +// Preparer and decorates the response. +func ExamplePrepareDecorator() { + path := "a/b/c/" + pd := func() PrepareDecorator { + return func(p Preparer) Preparer { + return PreparerFunc(func(r *http.Request) (*http.Request, error) { + r, err := p.Prepare(r) + if err == nil { + if r.URL == nil { + return r, fmt.Errorf("ERROR: URL is not set") + } + r.URL.Path += path + } + return r, err + }) + } + } + + r, _ := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/"), + pd()) + + fmt.Printf("Path is %s\n", r.URL) + // Output: Path is https://microsoft.com/a/b/c/ +} + +// PrepareDecorators may also modify and then invoke the Preparer. +func ExamplePrepareDecorator_pre() { + pd := func() PrepareDecorator { + return func(p Preparer) Preparer { + return PreparerFunc(func(r *http.Request) (*http.Request, error) { + r.Header.Add(http.CanonicalHeaderKey("ContentType"), "application/json") + return p.Prepare(r) + }) + } + } + + r, _ := Prepare(&http.Request{Header: http.Header{}}, + pd()) + + fmt.Printf("ContentType is %s\n", r.Header.Get("ContentType")) + // Output: ContentType is application/json +} + +// Create a sequence of three Preparers that build up the URL path. +func ExampleCreatePreparer() { + p := CreatePreparer( + WithBaseURL("https://microsoft.com/"), + WithPath("a"), + WithPath("b"), + WithPath("c")) + r, err := p.Prepare(&http.Request{}) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a/b/c +} + +// Create and apply separate Preparers +func ExampleCreatePreparer_multiple() { + params := map[string]interface{}{ + "param1": "a", + "param2": "c", + } + + p1 := CreatePreparer(WithBaseURL("https://microsoft.com/")) + p2 := CreatePreparer(WithPathParameters("/{param1}/b/{param2}/", params)) + + r, err := p1.Prepare(&http.Request{}) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } + + r, err = p2.Prepare(r) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a/b/c/ +} + +// Create and chain separate Preparers +func ExampleCreatePreparer_chain() { + params := map[string]interface{}{ + "param1": "a", + "param2": "c", + } + + p := CreatePreparer(WithBaseURL("https://microsoft.com/")) + p = DecoratePreparer(p, WithPathParameters("/{param1}/b/{param2}/", params)) + + r, err := p.Prepare(&http.Request{}) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a/b/c/ +} + +// Create and prepare an http.Request in one call +func ExamplePrepare() { + r, err := Prepare(&http.Request{}, + AsGet(), + WithBaseURL("https://microsoft.com/"), + WithPath("a/b/c/")) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Printf("%s %s", r.Method, r.URL) + } + // Output: GET https://microsoft.com/a/b/c/ +} + +// Create a request for a supplied base URL and path +func ExampleWithBaseURL() { + r, err := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/a/b/c/")) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a/b/c/ +} + +func ExampleWithBaseURL_second() { + _, err := Prepare(&http.Request{}, WithBaseURL(":")) + fmt.Println(err) + // Output: parse :: missing protocol scheme +} + +func ExampleWithCustomBaseURL() { + r, err := Prepare(&http.Request{}, + WithCustomBaseURL("https://{account}.{service}.core.windows.net/", + map[string]interface{}{ + "account": "myaccount", + "service": "blob", + })) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://myaccount.blob.core.windows.net/ +} + +func ExampleWithCustomBaseURL_second() { + _, err := Prepare(&http.Request{}, + WithCustomBaseURL(":", map[string]interface{}{})) + fmt.Println(err) + // Output: parse :: missing protocol scheme +} + +// Create a request with a custom HTTP header +func ExampleWithHeader() { + r, err := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/a/b/c/"), + WithHeader("x-foo", "bar")) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Printf("Header %s=%s\n", "x-foo", r.Header.Get("x-foo")) + } + // Output: Header x-foo=bar +} + +// Create a request whose Body is the JSON encoding of a structure +func ExampleWithFormData() { + v := url.Values{} + v.Add("name", "Rob Pike") + v.Add("age", "42") + + r, err := Prepare(&http.Request{}, + WithFormData(v)) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Printf("Request Body contains %s\n", string(b)) + } + // Output: Request Body contains age=42&name=Rob+Pike +} + +// Create a request whose Body is the JSON encoding of a structure +func ExampleWithJSON() { + t := mocks.T{Name: "Rob Pike", Age: 42} + + r, err := Prepare(&http.Request{}, + WithJSON(&t)) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Printf("Request Body contains %s\n", string(b)) + } + // Output: Request Body contains {"name":"Rob Pike","age":42} +} + +// Create a request from a path with escaped parameters +func ExampleWithEscapedPathParameters() { + params := map[string]interface{}{ + "param1": "a b c", + "param2": "d e f", + } + r, err := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/"), + WithEscapedPathParameters("/{param1}/b/{param2}/", params)) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a+b+c/b/d+e+f/ +} + +// Create a request from a path with parameters +func ExampleWithPathParameters() { + params := map[string]interface{}{ + "param1": "a", + "param2": "c", + } + r, err := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/"), + WithPathParameters("/{param1}/b/{param2}/", params)) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a/b/c/ +} + +// Create a request with query parameters +func ExampleWithQueryParameters() { + params := map[string]interface{}{ + "q1": "value1", + "q2": "value2", + } + r, err := Prepare(&http.Request{}, + WithBaseURL("https://microsoft.com/"), + WithPath("/a/b/c/"), + WithQueryParameters(params)) + if err != nil { + fmt.Printf("ERROR: %v\n", err) + } else { + fmt.Println(r.URL) + } + // Output: https://microsoft.com/a/b/c/?q1=value1&q2=value2 +} + +func TestWithCustomBaseURL(t *testing.T) { + r, err := Prepare(&http.Request{}, WithCustomBaseURL("https://{account}.{service}.core.windows.net/", + map[string]interface{}{ + "account": "myaccount", + "service": "blob", + })) + if err != nil { + t.Fatalf("autorest: WithCustomBaseURL should not fail") + } + if r.URL.String() != "https://myaccount.blob.core.windows.net/" { + t.Fatalf("autorest: WithCustomBaseURL expected https://myaccount.blob.core.windows.net/, got %s", r.URL) + } +} + +func TestWithCustomBaseURLwithInvalidURL(t *testing.T) { + _, err := Prepare(&http.Request{}, WithCustomBaseURL("hello/{account}.{service}.core.windows.net/", + map[string]interface{}{ + "account": "myaccount", + "service": "blob", + })) + if err == nil { + t.Fatalf("autorest: WithCustomBaseURL should fail fo URL parse error") + } +} + +func TestWithPathWithInvalidPath(t *testing.T) { + p := "path%2*end" + if _, err := Prepare(&http.Request{}, WithBaseURL("https://microsoft.com/"), WithPath(p)); err == nil { + t.Fatalf("autorest: WithPath should fail for invalid URL escape error for path '%v' ", p) + } + +} + +func TestWithPathParametersWithInvalidPath(t *testing.T) { + p := "path%2*end" + m := map[string]interface{}{ + "path1": p, + } + if _, err := Prepare(&http.Request{}, WithBaseURL("https://microsoft.com/"), WithPathParameters("/{path1}/", m)); err == nil { + t.Fatalf("autorest: WithPath should fail for invalid URL escape for path '%v' ", p) + } + +} + +func TestCreatePreparerDoesNotModify(t *testing.T) { + r1 := &http.Request{} + p := CreatePreparer() + r2, err := p.Prepare(r1) + if err != nil { + t.Fatalf("autorest: CreatePreparer failed (%v)", err) + } + if !reflect.DeepEqual(r1, r2) { + t.Fatalf("autorest: CreatePreparer without decorators modified the request") + } +} + +func TestCreatePreparerRunsDecoratorsInOrder(t *testing.T) { + p := CreatePreparer(WithBaseURL("https://microsoft.com/"), WithPath("1"), WithPath("2"), WithPath("3")) + r, err := p.Prepare(&http.Request{}) + if err != nil { + t.Fatalf("autorest: CreatePreparer failed (%v)", err) + } + if r.URL.String() != "https:/1/2/3" && r.URL.Host != "microsoft.com" { + t.Fatalf("autorest: CreatePreparer failed to run decorators in order") + } +} + +func TestAsContentType(t *testing.T) { + r, err := Prepare(mocks.NewRequest(), AsContentType("application/text")) + if err != nil { + fmt.Printf("ERROR: %v", err) + } + if r.Header.Get(headerContentType) != "application/text" { + t.Fatalf("autorest: AsContentType failed to add header (%s=%s)", headerContentType, r.Header.Get(headerContentType)) + } +} + +func TestAsFormURLEncoded(t *testing.T) { + r, err := Prepare(mocks.NewRequest(), AsFormURLEncoded()) + if err != nil { + fmt.Printf("ERROR: %v", err) + } + if r.Header.Get(headerContentType) != mimeTypeFormPost { + t.Fatalf("autorest: AsFormURLEncoded failed to add header (%s=%s)", headerContentType, r.Header.Get(headerContentType)) + } +} + +func TestAsJSON(t *testing.T) { + r, err := Prepare(mocks.NewRequest(), AsJSON()) + if err != nil { + fmt.Printf("ERROR: %v", err) + } + if r.Header.Get(headerContentType) != mimeTypeJSON { + t.Fatalf("autorest: AsJSON failed to add header (%s=%s)", headerContentType, r.Header.Get(headerContentType)) + } +} + +func TestWithNothing(t *testing.T) { + r1 := mocks.NewRequest() + r2, err := Prepare(r1, WithNothing()) + if err != nil { + t.Fatalf("autorest: WithNothing returned an unexpected error (%v)", err) + } + + if !reflect.DeepEqual(r1, r2) { + t.Fatal("azure: WithNothing modified the passed HTTP Request") + } +} + +func TestWithBearerAuthorization(t *testing.T) { + r, err := Prepare(mocks.NewRequest(), WithBearerAuthorization("SOME-TOKEN")) + if err != nil { + fmt.Printf("ERROR: %v", err) + } + if r.Header.Get(headerAuthorization) != "Bearer SOME-TOKEN" { + t.Fatalf("autorest: WithBearerAuthorization failed to add header (%s=%s)", headerAuthorization, r.Header.Get(headerAuthorization)) + } +} + +func TestWithUserAgent(t *testing.T) { + ua := "User Agent Go" + r, err := Prepare(mocks.NewRequest(), WithUserAgent(ua)) + if err != nil { + fmt.Printf("ERROR: %v", err) + } + if r.UserAgent() != ua || r.Header.Get(headerUserAgent) != ua { + t.Fatalf("autorest: WithUserAgent failed to add header (%s=%s)", headerUserAgent, r.Header.Get(headerUserAgent)) + } +} + +func TestWithMethod(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), WithMethod("HEAD")) + if r.Method != "HEAD" { + t.Fatal("autorest: WithMethod failed to set HTTP method header") + } +} + +func TestAsDelete(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsDelete()) + if r.Method != "DELETE" { + t.Fatal("autorest: AsDelete failed to set HTTP method header to DELETE") + } +} + +func TestAsGet(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsGet()) + if r.Method != "GET" { + t.Fatal("autorest: AsGet failed to set HTTP method header to GET") + } +} + +func TestAsHead(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsHead()) + if r.Method != "HEAD" { + t.Fatal("autorest: AsHead failed to set HTTP method header to HEAD") + } +} + +func TestAsOptions(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsOptions()) + if r.Method != "OPTIONS" { + t.Fatal("autorest: AsOptions failed to set HTTP method header to OPTIONS") + } +} + +func TestAsPatch(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsPatch()) + if r.Method != "PATCH" { + t.Fatal("autorest: AsPatch failed to set HTTP method header to PATCH") + } +} + +func TestAsPost(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsPost()) + if r.Method != "POST" { + t.Fatal("autorest: AsPost failed to set HTTP method header to POST") + } +} + +func TestAsPut(t *testing.T) { + r, _ := Prepare(mocks.NewRequest(), AsPut()) + if r.Method != "PUT" { + t.Fatal("autorest: AsPut failed to set HTTP method header to PUT") + } +} + +func TestPrepareWithNullRequest(t *testing.T) { + _, err := Prepare(nil) + if err == nil { + t.Fatal("autorest: Prepare failed to return an error when given a null http.Request") + } +} + +func TestWithFormData(t *testing.T) { + v := url.Values{} + v.Add("name", "Rob Pike") + v.Add("age", "42") + + r, err := Prepare(&http.Request{}, + WithFormData(v)) + if err != nil { + t.Fatalf("autorest: WithFormData failed with error (%v)", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithFormData failed with error (%v)", err) + } + + expected := "name=Rob+Pike&age=42" + if !(string(b) == "name=Rob+Pike&age=42" || string(b) == "age=42&name=Rob+Pike") { + t.Fatalf("autorest:WithFormData failed to return correct string got (%v), expected (%v)", string(b), expected) + } + + if r.ContentLength != int64(len(b)) { + t.Fatalf("autorest:WithFormData set Content-Length to %v, expected %v", r.ContentLength, len(b)) + } + + if expected, got := r.Header.Get(http.CanonicalHeaderKey(headerContentType)), mimeTypeFormPost; expected != got { + t.Fatalf("autorest:WithFormData Content Type not set or set to wrong value. Expected %v and got %v", expected, got) + } +} + +func TestWithMultiPartFormDataSetsContentLength(t *testing.T) { + v := map[string]interface{}{ + "file": ioutil.NopCloser(strings.NewReader("Hello Gopher")), + "age": "42", + } + + r, err := Prepare(&http.Request{}, + WithMultiPartFormData(v)) + if err != nil { + t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err) + } + + if r.ContentLength != int64(len(b)) { + t.Fatalf("autorest:WithMultiPartFormData set Content-Length to %v, expected %v", r.ContentLength, len(b)) + } +} + +func TestWithMultiPartFormDataWithNoFile(t *testing.T) { + v := map[string]interface{}{ + "file": "no file", + "age": "42", + } + + r, err := Prepare(&http.Request{}, + WithMultiPartFormData(v)) + if err != nil { + t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithMultiPartFormData failed with error (%v)", err) + } + + if r.ContentLength != int64(len(b)) { + t.Fatalf("autorest:WithMultiPartFormData set Content-Length to %v, expected %v", r.ContentLength, len(b)) + } +} + +func TestWithFile(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithFile(ioutil.NopCloser(strings.NewReader("Hello Gopher")))) + if err != nil { + t.Fatalf("autorest: WithFile failed with error (%v)", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithFile failed with error (%v)", err) + } + if r.ContentLength != int64(len(b)) { + t.Fatalf("autorest:WithFile set Content-Length to %v, expected %v", r.ContentLength, len(b)) + } +} + +func TestWithBool_SetsTheBody(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithBool(false)) + if err != nil { + t.Fatalf("autorest: WithBool failed with error (%v)", err) + } + + s, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithBool failed with error (%v)", err) + } + + if r.ContentLength != int64(len(fmt.Sprintf("%v", false))) { + t.Fatalf("autorest: WithBool set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", false)))) + } + + v, err := strconv.ParseBool(string(s)) + if err != nil || v { + t.Fatalf("autorest: WithBool incorrectly encoded the boolean as %v", s) + } +} + +func TestWithFloat32_SetsTheBody(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithFloat32(42.0)) + if err != nil { + t.Fatalf("autorest: WithFloat32 failed with error (%v)", err) + } + + s, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithFloat32 failed with error (%v)", err) + } + + if r.ContentLength != int64(len(fmt.Sprintf("%v", 42.0))) { + t.Fatalf("autorest: WithFloat32 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42.0)))) + } + + v, err := strconv.ParseFloat(string(s), 32) + if err != nil || float32(v) != float32(42.0) { + t.Fatalf("autorest: WithFloat32 incorrectly encoded the boolean as %v", s) + } +} + +func TestWithFloat64_SetsTheBody(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithFloat64(42.0)) + if err != nil { + t.Fatalf("autorest: WithFloat64 failed with error (%v)", err) + } + + s, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithFloat64 failed with error (%v)", err) + } + + if r.ContentLength != int64(len(fmt.Sprintf("%v", 42.0))) { + t.Fatalf("autorest: WithFloat64 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42.0)))) + } + + v, err := strconv.ParseFloat(string(s), 64) + if err != nil || v != float64(42.0) { + t.Fatalf("autorest: WithFloat64 incorrectly encoded the boolean as %v", s) + } +} + +func TestWithInt32_SetsTheBody(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithInt32(42)) + if err != nil { + t.Fatalf("autorest: WithInt32 failed with error (%v)", err) + } + + s, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithInt32 failed with error (%v)", err) + } + + if r.ContentLength != int64(len(fmt.Sprintf("%v", 42))) { + t.Fatalf("autorest: WithInt32 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42)))) + } + + v, err := strconv.ParseInt(string(s), 10, 32) + if err != nil || int32(v) != int32(42) { + t.Fatalf("autorest: WithInt32 incorrectly encoded the boolean as %v", s) + } +} + +func TestWithInt64_SetsTheBody(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithInt64(42)) + if err != nil { + t.Fatalf("autorest: WithInt64 failed with error (%v)", err) + } + + s, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithInt64 failed with error (%v)", err) + } + + if r.ContentLength != int64(len(fmt.Sprintf("%v", 42))) { + t.Fatalf("autorest: WithInt64 set Content-Length to %v, expected %v", r.ContentLength, int64(len(fmt.Sprintf("%v", 42)))) + } + + v, err := strconv.ParseInt(string(s), 10, 64) + if err != nil || v != int64(42) { + t.Fatalf("autorest: WithInt64 incorrectly encoded the boolean as %v", s) + } +} + +func TestWithString_SetsTheBody(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithString("value")) + if err != nil { + t.Fatalf("autorest: WithString failed with error (%v)", err) + } + + s, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithString failed with error (%v)", err) + } + + if r.ContentLength != int64(len("value")) { + t.Fatalf("autorest: WithString set Content-Length to %v, expected %v", r.ContentLength, int64(len("value"))) + } + + if string(s) != "value" { + t.Fatalf("autorest: WithString incorrectly encoded the string as %v", s) + } +} + +func TestWithJSONSetsContentLength(t *testing.T) { + r, err := Prepare(&http.Request{}, + WithJSON(&mocks.T{Name: "Rob Pike", Age: 42})) + if err != nil { + t.Fatalf("autorest: WithJSON failed with error (%v)", err) + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: WithJSON failed with error (%v)", err) + } + + if r.ContentLength != int64(len(b)) { + t.Fatalf("autorest:WithJSON set Content-Length to %v, expected %v", r.ContentLength, len(b)) + } +} + +func TestWithHeaderAllocatesHeaders(t *testing.T) { + r, err := Prepare(mocks.NewRequest(), WithHeader("x-foo", "bar")) + if err != nil { + t.Fatalf("autorest: WithHeader failed (%v)", err) + } + if r.Header.Get("x-foo") != "bar" { + t.Fatalf("autorest: WithHeader failed to add header (%s=%s)", "x-foo", r.Header.Get("x-foo")) + } +} + +func TestWithPathCatchesNilURL(t *testing.T) { + _, err := Prepare(&http.Request{}, WithPath("a")) + if err == nil { + t.Fatalf("autorest: WithPath failed to catch a nil URL") + } +} + +func TestWithEscapedPathParametersCatchesNilURL(t *testing.T) { + _, err := Prepare(&http.Request{}, WithEscapedPathParameters("", map[string]interface{}{"foo": "bar"})) + if err == nil { + t.Fatalf("autorest: WithEscapedPathParameters failed to catch a nil URL") + } +} + +func TestWithPathParametersCatchesNilURL(t *testing.T) { + _, err := Prepare(&http.Request{}, WithPathParameters("", map[string]interface{}{"foo": "bar"})) + if err == nil { + t.Fatalf("autorest: WithPathParameters failed to catch a nil URL") + } +} + +func TestWithQueryParametersCatchesNilURL(t *testing.T) { + _, err := Prepare(&http.Request{}, WithQueryParameters(map[string]interface{}{"foo": "bar"})) + if err == nil { + t.Fatalf("autorest: WithQueryParameters failed to catch a nil URL") + } +} + +func TestModifyingExistingRequest(t *testing.T) { + r, err := Prepare(mocks.NewRequestForURL("https://bing.com"), WithPath("search"), WithQueryParameters(map[string]interface{}{"q": "golang"})) + if err != nil { + t.Fatalf("autorest: Preparing an existing request returned an error (%v)", err) + } + if r.URL.Host != "bing.com" { + t.Fatalf("autorest: Preparing an existing request failed when setting the host (%s)", r.URL) + } + + if r.URL.Path != "/search" { + t.Fatalf("autorest: Preparing an existing request failed when setting the path (%s)", r.URL.Path) + } + + if r.URL.RawQuery != "q=golang" { + t.Fatalf("autorest: Preparing an existing request failed when setting the query parameters (%s)", r.URL.RawQuery) + } +} + +func TestModifyingRequestWithExistingQueryParameters(t *testing.T) { + r, err := Prepare( + mocks.NewRequestForURL("https://bing.com"), + WithPath("search"), + WithQueryParameters(map[string]interface{}{"q": "golang the best"}), + WithQueryParameters(map[string]interface{}{"pq": "golang+encoded"}), + ) + if err != nil { + t.Fatalf("autorest: Preparing an existing request returned an error (%v)", err) + } + + if r.URL.Host != "bing.com" { + t.Fatalf("autorest: Preparing an existing request failed when setting the host (%s)", r.URL) + } + + if r.URL.Path != "/search" { + t.Fatalf("autorest: Preparing an existing request failed when setting the path (%s)", r.URL.Path) + } + + if r.URL.RawQuery != "pq=golang+encoded&q=golang+the+best" { + t.Fatalf("autorest: Preparing an existing request failed when setting the query parameters (%s)", r.URL.RawQuery) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/responder_test.go b/vendor/github.com/Azure/go-autorest/autorest/responder_test.go new file mode 100644 index 000000000..4a57b1e3b --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/responder_test.go @@ -0,0 +1,665 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "reflect" + "strings" + "testing" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +func ExampleWithErrorUnlessOK() { + r := mocks.NewResponse() + r.Request = mocks.NewRequest() + + // Respond and leave the response body open (for a subsequent responder to close) + err := Respond(r, + WithErrorUnlessOK(), + ByDiscardingBody(), + ByClosingIfError()) + + if err == nil { + fmt.Printf("%s of %s returned HTTP 200", r.Request.Method, r.Request.URL) + + // Complete handling the response and close the body + Respond(r, + ByDiscardingBody(), + ByClosing()) + } + // Output: GET of https://microsoft.com/a/b/c/ returned HTTP 200 +} + +func ExampleByUnmarshallingJSON() { + c := ` + { + "name" : "Rob Pike", + "age" : 42 + } + ` + + type V struct { + Name string `json:"name"` + Age int `json:"age"` + } + + v := &V{} + + Respond(mocks.NewResponseWithContent(c), + ByUnmarshallingJSON(v), + ByClosing()) + + fmt.Printf("%s is %d years old\n", v.Name, v.Age) + // Output: Rob Pike is 42 years old +} + +func ExampleByUnmarshallingXML() { + c := ` + + Rob Pike + 42 + ` + + type V struct { + Name string `xml:"Name"` + Age int `xml:"Age"` + } + + v := &V{} + + Respond(mocks.NewResponseWithContent(c), + ByUnmarshallingXML(v), + ByClosing()) + + fmt.Printf("%s is %d years old\n", v.Name, v.Age) + // Output: Rob Pike is 42 years old +} + +func TestCreateResponderDoesNotModify(t *testing.T) { + r1 := mocks.NewResponse() + r2 := mocks.NewResponse() + p := CreateResponder() + err := p.Respond(r1) + if err != nil { + t.Fatalf("autorest: CreateResponder failed (%v)", err) + } + if !reflect.DeepEqual(r1, r2) { + t.Fatalf("autorest: CreateResponder without decorators modified the response") + } +} + +func TestCreateResponderRunsDecoratorsInOrder(t *testing.T) { + s := "" + + d := func(n int) RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + err := r.Respond(resp) + if err == nil { + s += fmt.Sprintf("%d", n) + } + return err + }) + } + } + + p := CreateResponder(d(1), d(2), d(3)) + err := p.Respond(&http.Response{}) + if err != nil { + t.Fatalf("autorest: Respond failed (%v)", err) + } + + if s != "123" { + t.Fatalf("autorest: CreateResponder invoked decorators in an incorrect order; expected '123', received '%s'", s) + } +} + +func TestByIgnoring(t *testing.T) { + r := mocks.NewResponse() + + Respond(r, + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(r2 *http.Response) error { + r1 := mocks.NewResponse() + if !reflect.DeepEqual(r1, r2) { + t.Fatalf("autorest: ByIgnoring modified the HTTP Response -- received %v, expected %v", r2, r1) + } + return nil + }) + } + })(), + ByIgnoring(), + ByClosing()) +} + +func TestByCopying_Copies(t *testing.T) { + r := mocks.NewResponseWithContent(jsonT) + b := &bytes.Buffer{} + + err := Respond(r, + ByCopying(b), + ByUnmarshallingJSON(&mocks.T{}), + ByClosing()) + if err != nil { + t.Fatalf("autorest: ByCopying returned an unexpected error -- %v", err) + } + if b.String() != jsonT { + t.Fatalf("autorest: ByCopying failed to copy the bytes read") + } +} + +func TestByCopying_ReturnsNestedErrors(t *testing.T) { + r := mocks.NewResponseWithContent(jsonT) + + r.Body.Close() + err := Respond(r, + ByCopying(&bytes.Buffer{}), + ByUnmarshallingJSON(&mocks.T{}), + ByClosing()) + if err == nil { + t.Fatalf("autorest: ByCopying failed to return the expected error") + } +} + +func TestByCopying_AcceptsNilReponse(t *testing.T) { + r := mocks.NewResponse() + + Respond(r, + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + r.Respond(nil) + return nil + }) + } + })(), + ByCopying(&bytes.Buffer{})) +} + +func TestByCopying_AcceptsNilBody(t *testing.T) { + r := mocks.NewResponse() + + Respond(r, + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + resp.Body = nil + r.Respond(resp) + return nil + }) + } + })(), + ByCopying(&bytes.Buffer{})) +} + +func TestByClosing(t *testing.T) { + r := mocks.NewResponse() + err := Respond(r, ByClosing()) + if err != nil { + t.Fatalf("autorest: ByClosing failed (%v)", err) + } + if r.Body.(*mocks.Body).IsOpen() { + t.Fatalf("autorest: ByClosing did not close the response body") + } +} + +func TestByClosingAcceptsNilResponse(t *testing.T) { + r := mocks.NewResponse() + + Respond(r, + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + r.Respond(nil) + return nil + }) + } + })(), + ByClosing()) +} + +func TestByClosingAcceptsNilBody(t *testing.T) { + r := mocks.NewResponse() + + Respond(r, + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + resp.Body = nil + r.Respond(resp) + return nil + }) + } + })(), + ByClosing()) +} + +func TestByClosingClosesEvenAfterErrors(t *testing.T) { + var e error + + r := mocks.NewResponse() + Respond(r, + withErrorRespondDecorator(&e), + ByClosing()) + + if r.Body.(*mocks.Body).IsOpen() { + t.Fatalf("autorest: ByClosing did not close the response body after an error occurred") + } +} + +func TestByClosingClosesReturnsNestedErrors(t *testing.T) { + var e error + + r := mocks.NewResponse() + err := Respond(r, + withErrorRespondDecorator(&e), + ByClosing()) + + if err == nil || !reflect.DeepEqual(e, err) { + t.Fatalf("autorest: ByClosing failed to return a nested error") + } +} + +func TestByClosingIfErrorAcceptsNilResponse(t *testing.T) { + var e error + + r := mocks.NewResponse() + + Respond(r, + withErrorRespondDecorator(&e), + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + r.Respond(nil) + return nil + }) + } + })(), + ByClosingIfError()) +} + +func TestByClosingIfErrorAcceptsNilBody(t *testing.T) { + var e error + + r := mocks.NewResponse() + + Respond(r, + withErrorRespondDecorator(&e), + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + resp.Body = nil + r.Respond(resp) + return nil + }) + } + })(), + ByClosingIfError()) +} + +func TestByClosingIfErrorClosesIfAnErrorOccurs(t *testing.T) { + var e error + + r := mocks.NewResponse() + Respond(r, + withErrorRespondDecorator(&e), + ByClosingIfError()) + + if r.Body.(*mocks.Body).IsOpen() { + t.Fatalf("autorest: ByClosingIfError did not close the response body after an error occurred") + } +} + +func TestByClosingIfErrorDoesNotClosesIfNoErrorOccurs(t *testing.T) { + r := mocks.NewResponse() + Respond(r, + ByClosingIfError()) + + if !r.Body.(*mocks.Body).IsOpen() { + t.Fatalf("autorest: ByClosingIfError closed the response body even though no error occurred") + } +} + +func TestByDiscardingBody(t *testing.T) { + r := mocks.NewResponse() + err := Respond(r, + ByDiscardingBody()) + if err != nil { + t.Fatalf("autorest: ByDiscardingBody failed (%v)", err) + } + buf, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatalf("autorest: Reading result of ByDiscardingBody failed (%v)", err) + } + + if len(buf) != 0 { + t.Logf("autorest: Body was not empty after calling ByDiscardingBody.") + t.Fail() + } +} + +func TestByDiscardingBodyAcceptsNilResponse(t *testing.T) { + var e error + + r := mocks.NewResponse() + + Respond(r, + withErrorRespondDecorator(&e), + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + r.Respond(nil) + return nil + }) + } + })(), + ByDiscardingBody()) +} + +func TestByDiscardingBodyAcceptsNilBody(t *testing.T) { + var e error + + r := mocks.NewResponse() + + Respond(r, + withErrorRespondDecorator(&e), + (func() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + resp.Body.Close() + resp.Body = nil + r.Respond(resp) + return nil + }) + } + })(), + ByDiscardingBody()) +} + +func TestByUnmarshallingJSON(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err != nil { + t.Fatalf("autorest: ByUnmarshallingJSON failed (%v)", err) + } + if v.Name != "Rob Pike" || v.Age != 42 { + t.Fatalf("autorest: ByUnmarshallingJSON failed to properly unmarshal") + } +} + +func TestByUnmarshallingJSON_HandlesReadErrors(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + r.Body.(*mocks.Body).Close() + + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err == nil { + t.Fatalf("autorest: ByUnmarshallingJSON failed to receive / respond to read error") + } +} + +func TestByUnmarshallingJSONIncludesJSONInErrors(t *testing.T) { + v := &mocks.T{} + j := jsonT[0 : len(jsonT)-2] + r := mocks.NewResponseWithContent(j) + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err == nil || !strings.Contains(err.Error(), j) { + t.Fatalf("autorest: ByUnmarshallingJSON failed to return JSON in error (%v)", err) + } +} + +func TestByUnmarshallingJSONEmptyInput(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(``) + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err != nil { + t.Fatalf("autorest: ByUnmarshallingJSON failed to return nil in case of empty JSON (%v)", err) + } +} + +func TestByUnmarshallingXML(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(xmlT) + err := Respond(r, + ByUnmarshallingXML(v), + ByClosing()) + if err != nil { + t.Fatalf("autorest: ByUnmarshallingXML failed (%v)", err) + } + if v.Name != "Rob Pike" || v.Age != 42 { + t.Fatalf("autorest: ByUnmarshallingXML failed to properly unmarshal") + } +} + +func TestByUnmarshallingXML_HandlesReadErrors(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(xmlT) + r.Body.(*mocks.Body).Close() + + err := Respond(r, + ByUnmarshallingXML(v), + ByClosing()) + if err == nil { + t.Fatalf("autorest: ByUnmarshallingXML failed to receive / respond to read error") + } +} + +func TestByUnmarshallingXMLIncludesXMLInErrors(t *testing.T) { + v := &mocks.T{} + x := xmlT[0 : len(xmlT)-2] + r := mocks.NewResponseWithContent(x) + err := Respond(r, + ByUnmarshallingXML(v), + ByClosing()) + if err == nil || !strings.Contains(err.Error(), x) { + t.Fatalf("autorest: ByUnmarshallingXML failed to return XML in error (%v)", err) + } +} + +func TestRespondAcceptsNullResponse(t *testing.T) { + err := Respond(nil) + if err != nil { + t.Fatalf("autorest: Respond returned an unexpected error when given a null Response (%v)", err) + } +} + +func TestWithErrorUnlessStatusCodeOKResponse(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + err := Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + ByUnmarshallingJSON(v), + ByClosing()) + + if err != nil { + t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) failed on okay response. (%v)", err) + } + + if v.Name != "Rob Pike" || v.Age != 42 { + t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) corrupted the response body of okay response.") + } +} + +func TesWithErrorUnlessStatusCodeErrorResponse(t *testing.T) { + v := &mocks.T{} + e := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + r.Status = "400 BadRequest" + r.StatusCode = http.StatusBadRequest + + err := Respond(r, + WithErrorUnlessStatusCode(http.StatusOK), + ByUnmarshallingJSON(v), + ByClosing()) + + if err == nil { + t.Fatal("autorest: WithErrorUnlessStatusCode(http.StatusOK) did not return error, on a response to a bad request.") + } + + var errorRespBody []byte + if derr, ok := err.(DetailedError); !ok { + t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) got wrong error type : %T, expected: DetailedError, on a response to a bad request.", err) + } else { + errorRespBody = derr.ServiceError + } + + if errorRespBody == nil { + t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) ServiceError not returned in DetailedError on a response to a bad request.") + } + + err = json.Unmarshal(errorRespBody, e) + if err != nil { + t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) cannot parse error returned in ServiceError into json. %v", err) + } + + expected := &mocks.T{Name: "Rob Pike", Age: 42} + if e != expected { + t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK wrong value from parsed ServiceError: got=%#v expected=%#v", e, expected) + } +} + +func TestWithErrorUnlessStatusCode(t *testing.T) { + r := mocks.NewResponse() + r.Request = mocks.NewRequest() + r.Status = "400 BadRequest" + r.StatusCode = http.StatusBadRequest + + err := Respond(r, + WithErrorUnlessStatusCode(http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError), + ByClosingIfError()) + + if err != nil { + t.Fatalf("autorest: WithErrorUnlessStatusCode returned an error (%v) for an acceptable status code (%s)", err, r.Status) + } +} + +func TestWithErrorUnlessStatusCodeEmitsErrorForUnacceptableStatusCode(t *testing.T) { + r := mocks.NewResponse() + r.Request = mocks.NewRequest() + r.Status = "400 BadRequest" + r.StatusCode = http.StatusBadRequest + + err := Respond(r, + WithErrorUnlessStatusCode(http.StatusOK, http.StatusUnauthorized, http.StatusInternalServerError), + ByClosingIfError()) + + if err == nil { + t.Fatalf("autorest: WithErrorUnlessStatusCode failed to return an error for an unacceptable status code (%s)", r.Status) + } +} + +func TestWithErrorUnlessOK(t *testing.T) { + r := mocks.NewResponse() + r.Request = mocks.NewRequest() + + err := Respond(r, + WithErrorUnlessOK(), + ByClosingIfError()) + + if err != nil { + t.Fatalf("autorest: WithErrorUnlessOK returned an error for OK status code (%v)", err) + } +} + +func TestWithErrorUnlessOKEmitsErrorIfNotOK(t *testing.T) { + r := mocks.NewResponse() + r.Request = mocks.NewRequest() + r.Status = "400 BadRequest" + r.StatusCode = http.StatusBadRequest + + err := Respond(r, + WithErrorUnlessOK(), + ByClosingIfError()) + + if err == nil { + t.Fatalf("autorest: WithErrorUnlessOK failed to return an error for a non-OK status code (%v)", err) + } +} + +func TestExtractHeader(t *testing.T) { + r := mocks.NewResponse() + v := []string{"v1", "v2", "v3"} + mocks.SetResponseHeaderValues(r, mocks.TestHeader, v) + + if !reflect.DeepEqual(ExtractHeader(mocks.TestHeader, r), v) { + t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v", + mocks.TestHeader, v, mocks.TestHeader, ExtractHeader(mocks.TestHeader, r)) + } +} + +func TestExtractHeaderHandlesMissingHeader(t *testing.T) { + var v []string + r := mocks.NewResponse() + + if !reflect.DeepEqual(ExtractHeader(mocks.TestHeader, r), v) { + t.Fatalf("autorest: ExtractHeader failed to handle a missing header -- expected %v, received %v", + v, ExtractHeader(mocks.TestHeader, r)) + } +} + +func TestExtractHeaderValue(t *testing.T) { + r := mocks.NewResponse() + v := "v1" + mocks.SetResponseHeader(r, mocks.TestHeader, v) + + if ExtractHeaderValue(mocks.TestHeader, r) != v { + t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v", + mocks.TestHeader, v, mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r)) + } +} + +func TestExtractHeaderValueHandlesMissingHeader(t *testing.T) { + r := mocks.NewResponse() + v := "" + + if ExtractHeaderValue(mocks.TestHeader, r) != v { + t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v", + mocks.TestHeader, v, mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r)) + } +} + +func TestExtractHeaderValueRetrievesFirstValue(t *testing.T) { + r := mocks.NewResponse() + v := []string{"v1", "v2", "v3"} + mocks.SetResponseHeaderValues(r, mocks.TestHeader, v) + + if ExtractHeaderValue(mocks.TestHeader, r) != v[0] { + t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v", + mocks.TestHeader, v[0], mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r)) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/sender_test.go b/vendor/github.com/Azure/go-autorest/autorest/sender_test.go new file mode 100644 index 000000000..c30837253 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/sender_test.go @@ -0,0 +1,829 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "bytes" + "fmt" + "log" + "net/http" + "os" + "reflect" + "sync" + "testing" + "time" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +func ExampleSendWithSender() { + r := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(r) + + client := mocks.NewSender() + client.AppendAndRepeatResponse(r, 10) + + logger := log.New(os.Stdout, "autorest: ", 0) + na := NullAuthorizer{} + + req, _ := Prepare(&http.Request{}, + AsGet(), + WithBaseURL("https://microsoft.com/a/b/c/"), + na.WithAuthorization()) + + r, _ = SendWithSender(client, req, + WithLogging(logger), + DoErrorIfStatusCode(http.StatusAccepted), + DoCloseIfError(), + DoRetryForAttempts(5, time.Duration(0))) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + // Output: + // autorest: Sending GET https://microsoft.com/a/b/c/ + // autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted + // autorest: Sending GET https://microsoft.com/a/b/c/ + // autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted + // autorest: Sending GET https://microsoft.com/a/b/c/ + // autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted + // autorest: Sending GET https://microsoft.com/a/b/c/ + // autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted + // autorest: Sending GET https://microsoft.com/a/b/c/ + // autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted +} + +func ExampleDoRetryForAttempts() { + client := mocks.NewSender() + client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10) + + // Retry with backoff -- ensure returned Bodies are closed + r, _ := SendWithSender(client, mocks.NewRequest(), + DoCloseIfError(), + DoRetryForAttempts(5, time.Duration(0))) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + fmt.Printf("Retry stopped after %d attempts", client.Attempts()) + // Output: Retry stopped after 5 attempts +} + +func ExampleDoErrorIfStatusCode() { + client := mocks.NewSender() + client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 NoContent", http.StatusNoContent), 10) + + // Chain decorators to retry the request, up to five times, if the status code is 204 + r, _ := SendWithSender(client, mocks.NewRequest(), + DoErrorIfStatusCode(http.StatusNoContent), + DoCloseIfError(), + DoRetryForAttempts(5, time.Duration(0))) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + fmt.Printf("Retry stopped after %d attempts with code %s", client.Attempts(), r.Status) + // Output: Retry stopped after 5 attempts with code 204 NoContent +} + +func TestSendWithSenderRunsDecoratorsInOrder(t *testing.T) { + client := mocks.NewSender() + s := "" + + r, err := SendWithSender(client, mocks.NewRequest(), + withMessage(&s, "a"), + withMessage(&s, "b"), + withMessage(&s, "c")) + if err != nil { + t.Fatalf("autorest: SendWithSender returned an error (%v)", err) + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if s != "abc" { + t.Fatalf("autorest: SendWithSender invoke decorators out of order; expected 'abc', received '%s'", s) + } +} + +func TestCreateSender(t *testing.T) { + f := false + + s := CreateSender( + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + f = true + return nil, nil + }) + } + })()) + s.Do(&http.Request{}) + + if !f { + t.Fatal("autorest: CreateSender failed to apply supplied decorator") + } +} + +func TestSend(t *testing.T) { + f := false + + Send(&http.Request{}, + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + f = true + return nil, nil + }) + } + })()) + + if !f { + t.Fatal("autorest: Send failed to apply supplied decorator") + } +} + +func TestAfterDelayWaits(t *testing.T) { + client := mocks.NewSender() + + d := 2 * time.Second + + tt := time.Now() + r, _ := SendWithSender(client, mocks.NewRequest(), + AfterDelay(d)) + s := time.Since(tt) + if s < d { + t.Fatal("autorest: AfterDelay failed to wait for at least the specified duration") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestAfterDelay_Cancels(t *testing.T) { + client := mocks.NewSender() + cancel := make(chan struct{}) + delay := 5 * time.Second + + var wg sync.WaitGroup + wg.Add(1) + tt := time.Now() + go func() { + req := mocks.NewRequest() + req.Cancel = cancel + wg.Done() + SendWithSender(client, req, + AfterDelay(delay)) + }() + wg.Wait() + close(cancel) + time.Sleep(5 * time.Millisecond) + if time.Since(tt) >= delay { + t.Fatal("autorest: AfterDelay failed to cancel") + } +} + +func TestAfterDelayDoesNotWaitTooLong(t *testing.T) { + client := mocks.NewSender() + + d := 5 * time.Millisecond + start := time.Now() + r, _ := SendWithSender(client, mocks.NewRequest(), + AfterDelay(d)) + + if time.Since(start) > (5 * d) { + t.Fatal("autorest: AfterDelay waited too long (exceeded 5 times specified duration)") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestAsIs(t *testing.T) { + client := mocks.NewSender() + + r1 := mocks.NewResponse() + client.AppendResponse(r1) + + r2, err := SendWithSender(client, mocks.NewRequest(), + AsIs()) + if err != nil { + t.Fatalf("autorest: AsIs returned an unexpected error (%v)", err) + } else if !reflect.DeepEqual(r1, r2) { + t.Fatalf("autorest: AsIs modified the response -- received %v, expected %v", r2, r1) + } + + Respond(r1, + ByDiscardingBody(), + ByClosing()) + Respond(r2, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoCloseIfError(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest)) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoErrorIfStatusCode(http.StatusBadRequest), + DoCloseIfError()) + + if r.Body.(*mocks.Body).IsOpen() { + t.Fatal("autorest: Expected DoCloseIfError to close response body -- it was left open") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoCloseIfErrorAcceptsNilResponse(t *testing.T) { + client := mocks.NewSender() + + SendWithSender(client, mocks.NewRequest(), + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + if err != nil { + resp.Body.Close() + } + return nil, fmt.Errorf("Faux Error") + }) + } + })(), + DoCloseIfError()) +} + +func TestDoCloseIfErrorAcceptsNilBody(t *testing.T) { + client := mocks.NewSender() + + SendWithSender(client, mocks.NewRequest(), + (func() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + if err != nil { + resp.Body.Close() + } + resp.Body = nil + return resp, fmt.Errorf("Faux Error") + }) + } + })(), + DoCloseIfError()) +} + +func TestDoErrorIfStatusCode(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest)) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoErrorIfStatusCode(http.StatusBadRequest), + DoCloseIfError()) + if err == nil { + t.Fatal("autorest: DoErrorIfStatusCode failed to emit an error for passed code") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoErrorIfStatusCodeIgnoresStatusCodes(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(newAcceptedResponse()) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoErrorIfStatusCode(http.StatusBadRequest), + DoCloseIfError()) + if err != nil { + t.Fatal("autorest: DoErrorIfStatusCode failed to ignore a status code") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoErrorUnlessStatusCode(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest)) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoErrorUnlessStatusCode(http.StatusAccepted), + DoCloseIfError()) + if err == nil { + t.Fatal("autorest: DoErrorUnlessStatusCode failed to emit an error for an unknown status code") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoErrorUnlessStatusCodeIgnoresStatusCodes(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(newAcceptedResponse()) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoErrorUnlessStatusCode(http.StatusAccepted), + DoCloseIfError()) + if err != nil { + t.Fatal("autorest: DoErrorUnlessStatusCode emitted an error for a knonwn status code") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForAttemptsStopsAfterSuccess(t *testing.T) { + client := mocks.NewSender() + + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForAttempts(5, time.Duration(0))) + if client.Attempts() != 1 { + t.Fatalf("autorest: DoRetryForAttempts failed to stop after success -- expected attempts %v, actual %v", + 1, client.Attempts()) + } + if err != nil { + t.Fatalf("autorest: DoRetryForAttempts returned an unexpected error (%v)", err) + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForAttemptsStopsAfterAttempts(t *testing.T) { + client := mocks.NewSender() + client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForAttempts(5, time.Duration(0)), + DoCloseIfError()) + if err == nil { + t.Fatal("autorest: Mock client failed to emit errors") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if client.Attempts() != 5 { + t.Fatal("autorest: DoRetryForAttempts failed to stop after specified number of attempts") + } +} + +func TestDoRetryForAttemptsReturnsResponse(t *testing.T) { + client := mocks.NewSender() + client.SetError(fmt.Errorf("Faux Error")) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForAttempts(1, time.Duration(0))) + if err == nil { + t.Fatal("autorest: Mock client failed to emit errors") + } + + if r == nil { + t.Fatal("autorest: DoRetryForAttempts failed to return the underlying response") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForDurationStopsAfterSuccess(t *testing.T) { + client := mocks.NewSender() + + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForDuration(10*time.Millisecond, time.Duration(0))) + if client.Attempts() != 1 { + t.Fatalf("autorest: DoRetryForDuration failed to stop after success -- expected attempts %v, actual %v", + 1, client.Attempts()) + } + if err != nil { + t.Fatalf("autorest: DoRetryForDuration returned an unexpected error (%v)", err) + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForDurationStopsAfterDuration(t *testing.T) { + client := mocks.NewSender() + client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1) + + d := 5 * time.Millisecond + start := time.Now() + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForDuration(d, time.Duration(0)), + DoCloseIfError()) + if err == nil { + t.Fatal("autorest: Mock client failed to emit errors") + } + + if time.Since(start) < d { + t.Fatal("autorest: DoRetryForDuration failed stopped too soon") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForDurationStopsWithinReason(t *testing.T) { + client := mocks.NewSender() + client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1) + + d := 5 * time.Second + start := time.Now() + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForDuration(d, time.Duration(0)), + DoCloseIfError()) + if err == nil { + t.Fatal("autorest: Mock client failed to emit errors") + } + + if time.Since(start) > (5 * d) { + t.Fatal("autorest: DoRetryForDuration failed stopped soon enough (exceeded 5 times specified duration)") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForDurationReturnsResponse(t *testing.T) { + client := mocks.NewSender() + client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForDuration(10*time.Millisecond, time.Duration(0)), + DoCloseIfError()) + if err == nil { + t.Fatal("autorest: Mock client failed to emit errors") + } + + if r == nil { + t.Fatal("autorest: DoRetryForDuration failed to return the underlying response") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDelayForBackoff(t *testing.T) { + d := 2 * time.Second + start := time.Now() + DelayForBackoff(d, 0, nil) + if time.Since(start) < d { + t.Fatal("autorest: DelayForBackoff did not delay as long as expected") + } +} + +func TestDelayForBackoff_Cancels(t *testing.T) { + cancel := make(chan struct{}) + delay := 5 * time.Second + + var wg sync.WaitGroup + wg.Add(1) + start := time.Now() + go func() { + wg.Done() + DelayForBackoff(delay, 0, cancel) + }() + wg.Wait() + close(cancel) + time.Sleep(5 * time.Millisecond) + if time.Since(start) >= delay { + t.Fatal("autorest: DelayForBackoff failed to cancel") + } +} + +func TestDelayForBackoffWithinReason(t *testing.T) { + d := 5 * time.Second + maxCoefficient := 2 + start := time.Now() + DelayForBackoff(d, 0, nil) + if time.Since(start) > (time.Duration(maxCoefficient) * d) { + + t.Fatalf("autorest: DelayForBackoff delayed too long (exceeded %d times the specified duration)", maxCoefficient) + } +} + +func TestDoPollForStatusCodes_IgnoresUnspecifiedStatusCodes(t *testing.T) { + client := mocks.NewSender() + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Duration(0), time.Duration(0))) + + if client.Attempts() != 1 { + t.Fatalf("autorest: Sender#DoPollForStatusCodes polled for unspecified status code") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoPollForStatusCodes_PollsForSpecifiedStatusCodes(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(newAcceptedResponse()) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted)) + + if client.Attempts() != 2 { + t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to poll for specified status code") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoPollForStatusCodes_CanBeCanceled(t *testing.T) { + cancel := make(chan struct{}) + delay := 5 * time.Second + + r := mocks.NewResponse() + mocks.SetAcceptedHeaders(r) + client := mocks.NewSender() + client.AppendAndRepeatResponse(r, 100) + + var wg sync.WaitGroup + wg.Add(1) + start := time.Now() + go func() { + wg.Done() + r, _ := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted)) + Respond(r, + ByDiscardingBody(), + ByClosing()) + }() + wg.Wait() + close(cancel) + time.Sleep(5 * time.Millisecond) + if time.Since(start) >= delay { + t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to cancel") + } +} + +func TestDoPollForStatusCodes_ClosesAllNonreturnedResponseBodiesWhenPolling(t *testing.T) { + resp := newAcceptedResponse() + + client := mocks.NewSender() + client.AppendAndRepeatResponse(resp, 2) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted)) + + if resp.Body.(*mocks.Body).IsOpen() || resp.Body.(*mocks.Body).CloseAttempts() < 2 { + t.Fatalf("autorest: Sender#DoPollForStatusCodes did not close unreturned response bodies") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoPollForStatusCodes_LeavesLastResponseBodyOpen(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(newAcceptedResponse()) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted)) + + if !r.Body.(*mocks.Body).IsOpen() { + t.Fatalf("autorest: Sender#DoPollForStatusCodes did not leave open the body of the last response") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoPollForStatusCodes_StopsPollingAfterAnError(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(newAcceptedResponse(), 5) + client.SetError(fmt.Errorf("Faux Error")) + client.SetEmitErrorAfter(1) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted)) + + if client.Attempts() > 2 { + t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to stop polling after receiving an error") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoPollForStatusCodes_ReturnsPollingError(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(newAcceptedResponse(), 5) + client.SetError(fmt.Errorf("Faux Error")) + client.SetEmitErrorAfter(1) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted)) + + if err == nil { + t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to return error from polling") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestWithLogging_Logs(t *testing.T) { + buf := &bytes.Buffer{} + logger := log.New(buf, "autorest: ", 0) + client := mocks.NewSender() + + r, _ := SendWithSender(client, &http.Request{}, + WithLogging(logger)) + + if buf.String() == "" { + t.Fatal("autorest: Sender#WithLogging failed to log the request") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestWithLogging_HandlesMissingResponse(t *testing.T) { + buf := &bytes.Buffer{} + logger := log.New(buf, "autorest: ", 0) + client := mocks.NewSender() + client.AppendResponse(nil) + client.SetError(fmt.Errorf("Faux Error")) + + r, err := SendWithSender(client, &http.Request{}, + WithLogging(logger)) + + if r != nil || err == nil { + t.Fatal("autorest: Sender#WithLogging returned a valid response -- expecting nil") + } + if buf.String() == "" { + t.Fatal("autorest: Sender#WithLogging failed to log the request for a nil response") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) +} + +func TestDoRetryForStatusCodesWithSuccess(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("408 Request Timeout", http.StatusRequestTimeout), 2) + client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK)) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoRetryForStatusCodes(5, time.Duration(2*time.Second), http.StatusRequestTimeout), + ) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if client.Attempts() != 3 { + t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ", + r.Status, client.Attempts()-1) + } +} + +func TestDoRetryForStatusCodesWithNoSuccess(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("504 Gateway Timeout", http.StatusGatewayTimeout), 5) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoRetryForStatusCodes(2, time.Duration(2*time.Second), http.StatusGatewayTimeout), + ) + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if client.Attempts() != 3 { + t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: failed stop after %v retry attempts; Want: Stop after 2 retry attempts", + client.Attempts()-1) + } +} + +func TestDoRetryForStatusCodes_CodeNotInRetryList(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 No Content", http.StatusNoContent), 1) + + r, _ := SendWithSender(client, mocks.NewRequest(), + DoRetryForStatusCodes(6, time.Duration(2*time.Second), http.StatusGatewayTimeout), + ) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if client.Attempts() != 1 || r.Status != "204 No Content" { + t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: Retry attempts %v for StatusCode %v; Want: 0 attempts for StatusCode 204", + client.Attempts(), r.Status) + } +} + +func TestDoRetryForStatusCodes_RequestBodyReadError(t *testing.T) { + client := mocks.NewSender() + client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 No Content", http.StatusNoContent), 2) + + r, err := SendWithSender(client, mocks.NewRequestWithCloseBody(), + DoRetryForStatusCodes(6, time.Duration(2*time.Second), http.StatusGatewayTimeout), + ) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if err == nil || client.Attempts() != 0 { + t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: Not failed for request body read error; Want: Failed for body read error - %v", err) + } +} + +func newAcceptedResponse() *http.Response { + resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted) + mocks.SetAcceptedHeaders(resp) + return resp +} + +func TestDelayWithRetryAfterWithSuccess(t *testing.T) { + after, retries := 2, 2 + totalSecs := after * retries + + client := mocks.NewSender() + resp := mocks.NewResponseWithStatus("429 Too many requests", http.StatusTooManyRequests) + mocks.SetResponseHeader(resp, "Retry-After", fmt.Sprintf("%v", after)) + client.AppendAndRepeatResponse(resp, retries) + client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK)) + + d := time.Second * time.Duration(totalSecs) + start := time.Now() + r, _ := SendWithSender(client, mocks.NewRequest(), + DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusTooManyRequests), + ) + + if time.Since(start) < d { + t.Fatal("autorest: DelayWithRetryAfter failed stopped too soon") + } + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if client.Attempts() != 3 { + t.Fatalf("autorest: Sender#DelayWithRetryAfter -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ", + r.Status, client.Attempts()-1) + } +} + +func TestDoRetryForStatusCodes_NilResponse(t *testing.T) { + client := mocks.NewSender() + client.AppendResponse(nil) + client.SetError(fmt.Errorf("faux error")) + + r, err := SendWithSender(client, mocks.NewRequest(), + DoRetryForStatusCodes(3, time.Duration(1*time.Second), StatusCodesForRetry...), + ) + + Respond(r, + ByDiscardingBody(), + ByClosing()) + + if err != nil || client.Attempts() != 2 { + t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponse -- Got: non-nil error or wrong number of attempts - %v", err) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/to/convert_test.go b/vendor/github.com/Azure/go-autorest/autorest/to/convert_test.go new file mode 100644 index 000000000..f8177a163 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/to/convert_test.go @@ -0,0 +1,234 @@ +package to + +// Copyright 2017 Microsoft 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. + +import ( + "reflect" + "testing" +) + +func TestString(t *testing.T) { + v := "" + if String(&v) != v { + t.Fatalf("to: String failed to return the correct string -- expected %v, received %v", + v, String(&v)) + } +} + +func TestStringHandlesNil(t *testing.T) { + if String(nil) != "" { + t.Fatalf("to: String failed to correctly convert nil -- expected %v, received %v", + "", String(nil)) + } +} + +func TestStringPtr(t *testing.T) { + v := "" + if *StringPtr(v) != v { + t.Fatalf("to: StringPtr failed to return the correct string -- expected %v, received %v", + v, *StringPtr(v)) + } +} + +func TestStringSlice(t *testing.T) { + v := []string{} + if out := StringSlice(&v); !reflect.DeepEqual(out, v) { + t.Fatalf("to: StringSlice failed to return the correct slice -- expected %v, received %v", + v, out) + } +} + +func TestStringSliceHandlesNil(t *testing.T) { + if out := StringSlice(nil); out != nil { + t.Fatalf("to: StringSlice failed to correctly convert nil -- expected %v, received %v", + nil, out) + } +} + +func TestStringSlicePtr(t *testing.T) { + v := []string{"a", "b"} + if out := StringSlicePtr(v); !reflect.DeepEqual(*out, v) { + t.Fatalf("to: StringSlicePtr failed to return the correct slice -- expected %v, received %v", + v, *out) + } +} + +func TestStringMap(t *testing.T) { + msp := map[string]*string{"foo": StringPtr("foo"), "bar": StringPtr("bar"), "baz": StringPtr("baz")} + for k, v := range StringMap(msp) { + if *msp[k] != v { + t.Fatalf("to: StringMap incorrectly converted an entry -- expected [%s]%v, received[%s]%v", + k, v, k, *msp[k]) + } + } +} + +func TestStringMapHandlesNil(t *testing.T) { + msp := map[string]*string{"foo": StringPtr("foo"), "bar": nil, "baz": StringPtr("baz")} + for k, v := range StringMap(msp) { + if msp[k] == nil && v != "" { + t.Fatalf("to: StringMap incorrectly converted a nil entry -- expected [%s]%v, received[%s]%v", + k, v, k, *msp[k]) + } + } +} + +func TestStringMapPtr(t *testing.T) { + ms := map[string]string{"foo": "foo", "bar": "bar", "baz": "baz"} + for k, msp := range *StringMapPtr(ms) { + if ms[k] != *msp { + t.Fatalf("to: StringMapPtr incorrectly converted an entry -- expected [%s]%v, received[%s]%v", + k, ms[k], k, *msp) + } + } +} + +func TestBool(t *testing.T) { + v := false + if Bool(&v) != v { + t.Fatalf("to: Bool failed to return the correct string -- expected %v, received %v", + v, Bool(&v)) + } +} + +func TestBoolHandlesNil(t *testing.T) { + if Bool(nil) != false { + t.Fatalf("to: Bool failed to correctly convert nil -- expected %v, received %v", + false, Bool(nil)) + } +} + +func TestBoolPtr(t *testing.T) { + v := false + if *BoolPtr(v) != v { + t.Fatalf("to: BoolPtr failed to return the correct string -- expected %v, received %v", + v, *BoolPtr(v)) + } +} + +func TestInt(t *testing.T) { + v := 0 + if Int(&v) != v { + t.Fatalf("to: Int failed to return the correct string -- expected %v, received %v", + v, Int(&v)) + } +} + +func TestIntHandlesNil(t *testing.T) { + if Int(nil) != 0 { + t.Fatalf("to: Int failed to correctly convert nil -- expected %v, received %v", + 0, Int(nil)) + } +} + +func TestIntPtr(t *testing.T) { + v := 0 + if *IntPtr(v) != v { + t.Fatalf("to: IntPtr failed to return the correct string -- expected %v, received %v", + v, *IntPtr(v)) + } +} + +func TestInt32(t *testing.T) { + v := int32(0) + if Int32(&v) != v { + t.Fatalf("to: Int32 failed to return the correct string -- expected %v, received %v", + v, Int32(&v)) + } +} + +func TestInt32HandlesNil(t *testing.T) { + if Int32(nil) != int32(0) { + t.Fatalf("to: Int32 failed to correctly convert nil -- expected %v, received %v", + 0, Int32(nil)) + } +} + +func TestInt32Ptr(t *testing.T) { + v := int32(0) + if *Int32Ptr(v) != v { + t.Fatalf("to: Int32Ptr failed to return the correct string -- expected %v, received %v", + v, *Int32Ptr(v)) + } +} + +func TestInt64(t *testing.T) { + v := int64(0) + if Int64(&v) != v { + t.Fatalf("to: Int64 failed to return the correct string -- expected %v, received %v", + v, Int64(&v)) + } +} + +func TestInt64HandlesNil(t *testing.T) { + if Int64(nil) != int64(0) { + t.Fatalf("to: Int64 failed to correctly convert nil -- expected %v, received %v", + 0, Int64(nil)) + } +} + +func TestInt64Ptr(t *testing.T) { + v := int64(0) + if *Int64Ptr(v) != v { + t.Fatalf("to: Int64Ptr failed to return the correct string -- expected %v, received %v", + v, *Int64Ptr(v)) + } +} + +func TestFloat32(t *testing.T) { + v := float32(0) + if Float32(&v) != v { + t.Fatalf("to: Float32 failed to return the correct string -- expected %v, received %v", + v, Float32(&v)) + } +} + +func TestFloat32HandlesNil(t *testing.T) { + if Float32(nil) != float32(0) { + t.Fatalf("to: Float32 failed to correctly convert nil -- expected %v, received %v", + 0, Float32(nil)) + } +} + +func TestFloat32Ptr(t *testing.T) { + v := float32(0) + if *Float32Ptr(v) != v { + t.Fatalf("to: Float32Ptr failed to return the correct string -- expected %v, received %v", + v, *Float32Ptr(v)) + } +} + +func TestFloat64(t *testing.T) { + v := float64(0) + if Float64(&v) != v { + t.Fatalf("to: Float64 failed to return the correct string -- expected %v, received %v", + v, Float64(&v)) + } +} + +func TestFloat64HandlesNil(t *testing.T) { + if Float64(nil) != float64(0) { + t.Fatalf("to: Float64 failed to correctly convert nil -- expected %v, received %v", + 0, Float64(nil)) + } +} + +func TestFloat64Ptr(t *testing.T) { + v := float64(0) + if *Float64Ptr(v) != v { + t.Fatalf("to: Float64Ptr failed to return the correct string -- expected %v, received %v", + v, *Float64Ptr(v)) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/utility_test.go b/vendor/github.com/Azure/go-autorest/autorest/utility_test.go new file mode 100644 index 000000000..cc4919b5f --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/utility_test.go @@ -0,0 +1,422 @@ +package autorest + +// Copyright 2017 Microsoft 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. + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "net/http" + "net/url" + "reflect" + "sort" + "strings" + "testing" + + "github.com/Azure/go-autorest/autorest/mocks" +) + +const ( + jsonT = ` + { + "name":"Rob Pike", + "age":42 + }` + xmlT = ` + + Rob Pike + 42 + ` +) + +func TestNewDecoderCreatesJSONDecoder(t *testing.T) { + d := NewDecoder(EncodedAsJSON, strings.NewReader(jsonT)) + _, ok := d.(*json.Decoder) + if d == nil || !ok { + t.Fatal("autorest: NewDecoder failed to create a JSON decoder when requested") + } +} + +func TestNewDecoderCreatesXMLDecoder(t *testing.T) { + d := NewDecoder(EncodedAsXML, strings.NewReader(xmlT)) + _, ok := d.(*xml.Decoder) + if d == nil || !ok { + t.Fatal("autorest: NewDecoder failed to create an XML decoder when requested") + } +} + +func TestNewDecoderReturnsNilForUnknownEncoding(t *testing.T) { + d := NewDecoder("unknown", strings.NewReader(xmlT)) + if d != nil { + t.Fatal("autorest: NewDecoder created a decoder for an unknown encoding") + } +} + +func TestCopyAndDecodeDecodesJSON(t *testing.T) { + _, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{}) + if err != nil { + t.Fatalf("autorest: CopyAndDecode returned an error with valid JSON - %v", err) + } +} + +func TestCopyAndDecodeDecodesXML(t *testing.T) { + _, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT), &mocks.T{}) + if err != nil { + t.Fatalf("autorest: CopyAndDecode returned an error with valid XML - %v", err) + } +} + +func TestCopyAndDecodeReturnsJSONDecodingErrors(t *testing.T) { + _, err := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT[0:len(jsonT)-2]), &mocks.T{}) + if err == nil { + t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid JSON") + } +} + +func TestCopyAndDecodeReturnsXMLDecodingErrors(t *testing.T) { + _, err := CopyAndDecode(EncodedAsXML, strings.NewReader(xmlT[0:len(xmlT)-2]), &mocks.T{}) + if err == nil { + t.Fatalf("autorest: CopyAndDecode failed to return an error with invalid XML") + } +} + +func TestCopyAndDecodeAlwaysReturnsACopy(t *testing.T) { + b, _ := CopyAndDecode(EncodedAsJSON, strings.NewReader(jsonT), &mocks.T{}) + if b.String() != jsonT { + t.Fatalf("autorest: CopyAndDecode failed to return a valid copy of the data - %v", b.String()) + } +} + +func TestTeeReadCloser_Copies(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + b := &bytes.Buffer{} + + r.Body = TeeReadCloser(r.Body, b) + + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err != nil { + t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err) + } + if b.String() != jsonT { + t.Fatalf("autorest: TeeReadCloser failed to copy the bytes read") + } +} + +func TestTeeReadCloser_PassesReadErrors(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + + r.Body.(*mocks.Body).Close() + r.Body = TeeReadCloser(r.Body, &bytes.Buffer{}) + + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err == nil { + t.Fatalf("autorest: TeeReadCloser failed to return the expected error") + } +} + +func TestTeeReadCloser_ClosesWrappedReader(t *testing.T) { + v := &mocks.T{} + r := mocks.NewResponseWithContent(jsonT) + + b := r.Body.(*mocks.Body) + r.Body = TeeReadCloser(r.Body, &bytes.Buffer{}) + err := Respond(r, + ByUnmarshallingJSON(v), + ByClosing()) + if err != nil { + t.Fatalf("autorest: TeeReadCloser returned an unexpected error -- %v", err) + } + if b.IsOpen() { + t.Fatalf("autorest: TeeReadCloser failed to close the nested io.ReadCloser") + } +} + +func TestContainsIntFindsValue(t *testing.T) { + ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + v := 5 + if !containsInt(ints, v) { + t.Fatalf("autorest: containsInt failed to find %v in %v", v, ints) + } +} + +func TestContainsIntDoesNotFindValue(t *testing.T) { + ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + v := 42 + if containsInt(ints, v) { + t.Fatalf("autorest: containsInt unexpectedly found %v in %v", v, ints) + } +} + +func TestContainsIntAcceptsEmptyList(t *testing.T) { + ints := make([]int, 10) + if containsInt(ints, 42) { + t.Fatalf("autorest: containsInt failed to handle an empty list") + } +} + +func TestContainsIntAcceptsNilList(t *testing.T) { + var ints []int + if containsInt(ints, 42) { + t.Fatalf("autorest: containsInt failed to handle an nil list") + } +} + +func TestEscapeStrings(t *testing.T) { + m := map[string]string{ + "string": "a long string with = odd characters", + "int": "42", + "nil": "", + } + r := map[string]string{ + "string": "a+long+string+with+%3D+odd+characters", + "int": "42", + "nil": "", + } + v := escapeValueStrings(m) + if !reflect.DeepEqual(v, r) { + t.Fatalf("autorest: ensureValueStrings returned %v\n", v) + } +} + +func TestEnsureStrings(t *testing.T) { + m := map[string]interface{}{ + "string": "string", + "int": 42, + "nil": nil, + "bytes": []byte{255, 254, 253}, + } + r := map[string]string{ + "string": "string", + "int": "42", + "nil": "", + "bytes": string([]byte{255, 254, 253}), + } + v := ensureValueStrings(m) + if !reflect.DeepEqual(v, r) { + t.Fatalf("autorest: ensureValueStrings returned %v\n", v) + } +} + +func ExampleString() { + m := []string{ + "string1", + "string2", + "string3", + } + + fmt.Println(String(m, ",")) + // Output: string1,string2,string3 +} + +func TestStringWithValidString(t *testing.T) { + i := 123 + if got, want := String(i), "123"; got != want { + t.Logf("got: %q\nwant: %q", got, want) + t.Fail() + } +} + +func TestStringWithStringSlice(t *testing.T) { + s := []string{"string1", "string2"} + if got, want := String(s, ","), "string1,string2"; got != want { + t.Logf("got: %q\nwant: %q", got, want) + t.Fail() + } +} + +func TestStringWithEnum(t *testing.T) { + type TestEnumType string + s := TestEnumType("string1") + if got, want := String(s), "string1"; got != want { + t.Logf("got: %q\nwant: %q", got, want) + t.Fail() + } +} + +func TestStringWithEnumSlice(t *testing.T) { + type TestEnumType string + s := []TestEnumType{"string1", "string2"} + if got, want := String(s, ","), "string1,string2"; got != want { + t.Logf("got: %q\nwant: %q", got, want) + t.Fail() + } +} + +func ExampleAsStringSlice() { + type TestEnumType string + + a := []TestEnumType{"value1", "value2"} + b, _ := AsStringSlice(a) + for _, c := range b { + fmt.Println(c) + } + // Output: + // value1 + // value2 +} + +func TestEncodeWithValidPath(t *testing.T) { + s := Encode("Path", "Hello Gopher") + if s != "Hello%20Gopher" { + t.Fatalf("autorest: Encode method failed for valid path encoding. Got: %v; Want: %v", s, "Hello%20Gopher") + } +} + +func TestEncodeWithValidQuery(t *testing.T) { + s := Encode("Query", "Hello Gopher") + if s != "Hello+Gopher" { + t.Fatalf("autorest: Encode method failed for valid query encoding. Got: '%v'; Want: 'Hello+Gopher'", s) + } +} + +func TestEncodeWithValidNotPathQuery(t *testing.T) { + s := Encode("Host", "Hello Gopher") + if s != "Hello Gopher" { + t.Fatalf("autorest: Encode method failed for parameter not query or path. Got: '%v'; Want: 'Hello Gopher'", s) + } +} + +func TestMapToValues(t *testing.T) { + m := map[string]interface{}{ + "a": "a", + "b": 2, + } + v := url.Values{} + v.Add("a", "a") + v.Add("b", "2") + if !isEqual(v, MapToValues(m)) { + t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m)) + } +} + +func TestMapToValuesWithArrayValues(t *testing.T) { + m := map[string]interface{}{ + "a": []string{"a", "b"}, + "b": 2, + "c": []int{3, 4}, + } + v := url.Values{} + v.Add("a", "a") + v.Add("a", "b") + v.Add("b", "2") + v.Add("c", "3") + v.Add("c", "4") + + if !isEqual(v, MapToValues(m)) { + t.Fatalf("autorest: MapToValues method failed to return correct values - expected(%v) got(%v)", v, MapToValues(m)) + } +} + +func isEqual(v, u url.Values) bool { + for key, value := range v { + if len(u[key]) == 0 { + return false + } + sort.Strings(value) + sort.Strings(u[key]) + for i := range value { + if value[i] != u[key][i] { + return false + } + } + u.Del(key) + } + if len(u) > 0 { + return false + } + return true +} + +func doEnsureBodyClosed(t *testing.T) SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + if resp != nil && resp.Body != nil && resp.Body.(*mocks.Body).IsOpen() { + t.Fatal("autorest: Expected Body to be closed -- it was left open") + } + return resp, err + }) + } +} + +type mockAuthorizer struct{} + +func (ma mockAuthorizer) WithAuthorization() PrepareDecorator { + return WithHeader(headerAuthorization, mocks.TestAuthorizationHeader) +} + +type mockFailingAuthorizer struct{} + +func (mfa mockFailingAuthorizer) WithAuthorization() PrepareDecorator { + return func(p Preparer) Preparer { + return PreparerFunc(func(r *http.Request) (*http.Request, error) { + return r, fmt.Errorf("ERROR: mockFailingAuthorizer returned expected error") + }) + } +} + +type mockInspector struct { + wasInvoked bool +} + +func (mi *mockInspector) WithInspection() PrepareDecorator { + return func(p Preparer) Preparer { + return PreparerFunc(func(r *http.Request) (*http.Request, error) { + mi.wasInvoked = true + return p.Prepare(r) + }) + } +} + +func (mi *mockInspector) ByInspecting() RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + mi.wasInvoked = true + return r.Respond(resp) + }) + } +} + +func withMessage(output *string, msg string) SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + if err == nil { + *output += msg + } + return resp, err + }) + } +} + +func withErrorRespondDecorator(e *error) RespondDecorator { + return func(r Responder) Responder { + return ResponderFunc(func(resp *http.Response) error { + err := r.Respond(resp) + if err != nil { + return err + } + *e = fmt.Errorf("autorest: Faux Respond Error") + return *e + }) + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/validation/validation_test.go b/vendor/github.com/Azure/go-autorest/autorest/validation/validation_test.go new file mode 100644 index 000000000..c86649d8f --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/validation/validation_test.go @@ -0,0 +1,2433 @@ +package validation + +// Copyright 2017 Microsoft 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. + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCheckForUniqueInArrayTrue(t *testing.T) { + require.Equal(t, checkForUniqueInArray(reflect.ValueOf([]int{1, 2, 3})), true) +} + +func TestCheckForUniqueInArrayFalse(t *testing.T) { + require.Equal(t, checkForUniqueInArray(reflect.ValueOf([]int{1, 2, 3, 3})), false) +} + +func TestCheckForUniqueInArrayEmpty(t *testing.T) { + require.Equal(t, checkForUniqueInArray(reflect.ValueOf([]int{})), false) +} + +func TestCheckForUniqueInMapTrue(t *testing.T) { + require.Equal(t, checkForUniqueInMap(reflect.ValueOf(map[string]int{"one": 1, "two": 2})), true) +} + +func TestCheckForUniqueInMapFalse(t *testing.T) { + require.Equal(t, checkForUniqueInMap(reflect.ValueOf(map[int]string{1: "one", 2: "one"})), false) +} + +func TestCheckForUniqueInMapEmpty(t *testing.T) { + require.Equal(t, checkForUniqueInMap(reflect.ValueOf(map[int]string{})), false) +} + +func TestCheckEmpty_WithValueEmptyRuleTrue(t *testing.T) { + var x interface{} + v := Constraint{ + Target: "str", + Name: Empty, + Rule: true, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), v, "value can not be null or empty; required parameter") + require.Equal(t, checkEmpty(reflect.ValueOf(x), v).Error(), expected.Error()) +} + +func TestCheckEmpty_WithEmptyStringRuleFalse(t *testing.T) { + var x interface{} + v := Constraint{ + Target: "str", + Name: Empty, + Rule: false, + Chain: nil, + } + require.Nil(t, checkEmpty(reflect.ValueOf(x), v)) +} + +func TestCheckEmpty_IncorrectRule(t *testing.T) { + var x interface{} + v := Constraint{ + Target: "str", + Name: Empty, + Rule: 10, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), v, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", v.Name, v.Rule)) + require.Equal(t, checkEmpty(reflect.ValueOf(x), v).Error(), expected.Error()) +} + +func TestCheckEmpty_WithErrorArray(t *testing.T) { + var x interface{} = []string{} + v := Constraint{ + Target: "str", + Name: Empty, + Rule: true, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), v, "value can not be null or empty; required parameter") + require.Equal(t, checkEmpty(reflect.ValueOf(x), v).Error(), expected.Error()) +} + +func TestCheckNil_WithNilValueRuleTrue(t *testing.T) { + var x interface{} + v := Constraint{ + Target: "x", + Name: Null, + Rule: true, + Chain: []Constraint{ + {"x", MaxItems, 4, nil}, + }, + } + expected := createError(reflect.ValueOf(x), v, "value can not be null; required parameter") + require.Equal(t, checkNil(reflect.ValueOf(x), v).Error(), expected.Error()) +} + +func TestCheckNil_WithNilValueRuleFalse(t *testing.T) { + var x interface{} + v := Constraint{ + Target: "x", + Name: Null, + Rule: false, + Chain: []Constraint{ + {"x", MaxItems, 4, nil}, + }, + } + require.Nil(t, checkNil(reflect.ValueOf(x), v)) +} + +func TestCheckNil_IncorrectRule(t *testing.T) { + var x interface{} + c := Constraint{ + Target: "str", + Name: Null, + Rule: 10, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("rule must be bool value for %v constraint; got: %v", c.Name, c.Rule)) + require.Equal(t, checkNil(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_WithNilValueRuleTrue(t *testing.T) { + var a []string + var x interface{} = a + c := Constraint{ + Target: "arr", + Name: Null, + Rule: true, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, "value can not be null; required parameter") + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c), expected) +} + +func TestValidateArrayMap_WithNilValueRuleFalse(t *testing.T) { + var x interface{} = []string{} + c := Constraint{ + Target: "arr", + Name: Null, + Rule: false, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_WithValueRuleNullTrue(t *testing.T) { + var x interface{} = []string{"1", "2"} + c := Constraint{ + Target: "arr", + Name: Null, + Rule: false, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_WithEmptyValueRuleTrue(t *testing.T) { + var x interface{} = []string{} + c := Constraint{ + Target: "arr", + Name: Empty, + Rule: true, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, "value can not be null or empty; required parameter") + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c), expected) +} + +func TestValidateArrayMap_WithEmptyValueRuleFalse(t *testing.T) { + var x interface{} = []string{} + c := Constraint{ + Target: "arr", + Name: Empty, + Rule: false, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_WithEmptyRuleEmptyTrue(t *testing.T) { + var x interface{} = []string{"1", "2"} + c := Constraint{ + Target: "arr", + Name: Empty, + Rule: false, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_MaxItemsIncorrectRule(t *testing.T) { + var x interface{} = []string{"1", "2"} + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: false, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("rule must be integer for %v constraint; got: %v", c.Name, c.Rule)) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_MaxItemsNoError(t *testing.T) { + var x interface{} = []string{"1", "2"} + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_MaxItemsWithError(t *testing.T) { + var x interface{} = []string{"1", "2", "3"} + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: 2, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("maximum item limit is %v; got: 3", c.Rule)) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_MaxItemsWithEmpty(t *testing.T) { + var x interface{} = []string{} + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_MinItemsIncorrectRule(t *testing.T) { + var x interface{} = []int{1, 2} + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: false, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("rule must be integer for %v constraint; got: %v", c.Name, c.Rule)) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_MinItemsNoError1(t *testing.T) { + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf([]int{1, 2}), c)) +} + +func TestValidateArrayMap_MinItemsNoError2(t *testing.T) { + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf([]int{1, 2, 3}), c)) +} + +func TestValidateArrayMap_MinItemsWithError(t *testing.T) { + var x interface{} = []int{1} + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("minimum item limit is %v; got: 1", c.Rule)) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_MinItemsWithEmpty(t *testing.T) { + var x interface{} = []int{} + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("minimum item limit is %v; got: 0", c.Rule)) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_Map_MaxItemsIncorrectRule(t *testing.T) { + var x interface{} = map[int]string{1: "1", 2: "2"} + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: false, + Chain: nil, + } + require.Equal(t, strings.Contains(validateArrayMap(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("rule must be integer for %v constraint; got: %v", c.Name, c.Rule)), true) +} + +func TestValidateArrayMap_Map_MaxItemsNoError(t *testing.T) { + var x interface{} = map[int]string{1: "1", 2: "2"} + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_Map_MaxItemsWithError(t *testing.T) { + a := map[int]string{1: "1", 2: "2", 3: "3"} + var x interface{} = a + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: 2, + Chain: nil, + } + require.Equal(t, strings.Contains(validateArrayMap(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("maximum item limit is %v; got: %v", c.Rule, len(a))), true) +} + +func TestValidateArrayMap_Map_MaxItemsWithEmpty(t *testing.T) { + a := map[int]string{} + var x interface{} = a + c := Constraint{ + Target: "arr", + Name: MaxItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_Map_MinItemsIncorrectRule(t *testing.T) { + var x interface{} = map[int]string{1: "1", 2: "2"} + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: false, + Chain: nil, + } + require.Equal(t, strings.Contains(validateArrayMap(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("rule must be integer for %v constraint; got: %v", c.Name, c.Rule)), true) +} + +func TestValidateArrayMap_Map_MinItemsNoError1(t *testing.T) { + var x interface{} = map[int]string{1: "1", 2: "2"} + require.Nil(t, validateArrayMap(reflect.ValueOf(x), + Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + })) +} + +func TestValidateArrayMap_Map_MinItemsNoError2(t *testing.T) { + var x interface{} = map[int]string{1: "1", 2: "2", 3: "3"} + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_Map_MinItemsWithError(t *testing.T) { + a := map[int]string{1: "1"} + var x interface{} = a + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("minimum item limit is %v; got: %v", c.Rule, len(a))) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +func TestValidateArrayMap_Map_MinItemsWithEmpty(t *testing.T) { + a := map[int]string{} + var x interface{} = a + c := Constraint{ + Target: "arr", + Name: MinItems, + Rule: 2, + Chain: nil, + } + expected := createError(reflect.ValueOf(x), c, fmt.Sprintf("minimum item limit is %v; got: %v", c.Rule, len(a))) + require.Equal(t, validateArrayMap(reflect.ValueOf(x), c).Error(), expected.Error()) +} + +// func TestValidateArrayMap_Map_MinItemsNil(t *testing.T) { +// var a map[int]float64 +// var x interface{} = a +// c := Constraint{ +// Target: "str", +// Name: MinItems, +// Rule: true, +// Chain: nil, +// } +// expected := createError(reflect.Value(x), c, fmt.Sprintf("all items in parameter %v must be unique; got:%v", c.Target, x)) +// if z := validateArrayMap(reflect.ValueOf(x), c); strings.Contains(z.Error(), "all items in parameter str must be unique;") { +// t.Fatalf("autorest/validation: valiateArrayMap failed to return error \nexpect: %v;\ngot: %v", expected, z) +// } +// } + +func TestValidateArrayMap_Map_UniqueItemsTrue(t *testing.T) { + var x interface{} = map[float64]int{1.2: 1, 1.4: 2} + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_Map_UniqueItemsFalse(t *testing.T) { + var x interface{} = map[string]string{"1": "1", "2": "2", "3": "1"} + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("all items in parameter %q must be unique", c.Target)), true) +} + +func TestValidateArrayMap_Map_UniqueItemsEmpty(t *testing.T) { + // Consider Empty map as not unique returns false + var x interface{} = map[int]float64{} + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("all items in parameter %q must be unique", c.Target)), true) +} + +func TestValidateArrayMap_Map_UniqueItemsNil(t *testing.T) { + var a map[int]float64 + var x interface{} = a + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("all items in parameter %q must be unique; got:%v", c.Target, x)), true) +} + +func TestValidateArrayMap_Array_UniqueItemsTrue(t *testing.T) { + var x interface{} = []int{1, 2} + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_Array_UniqueItemsFalse(t *testing.T) { + var x interface{} = []string{"1", "2", "1"} + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("all items in parameter %q must be unique; got:%v", c.Target, x)), true) +} + +func TestValidateArrayMap_Array_UniqueItemsEmpty(t *testing.T) { + // Consider Empty array as not unique returns false + var x interface{} = []float64{} + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("all items in parameter %q must be unique; got:%v", c.Target, x)), true) +} + +func TestValidateArrayMap_Array_UniqueItemsNil(t *testing.T) { + // Consider nil array as not unique returns false + var a []float64 + var x interface{} = a + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("all items in parameter %q must be unique; got:%v", c.Target, x)), true) +} + +func TestValidateArrayMap_Array_UniqueItemsInvalidType(t *testing.T) { + var x interface{} = "hello" + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("type must be array, slice or map for constraint %v; got: %v", c.Name, reflect.ValueOf(x).Kind())), true) +} + +func TestValidateArrayMap_Array_UniqueItemsInvalidConstraint(t *testing.T) { + var x interface{} = "hello" + c := Constraint{ + Target: "str", + Name: "sdad", + Rule: true, + Chain: nil, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("constraint %v is not applicable to array, slice and map type", c.Name)), true) +} + +func TestValidateArrayMap_ValidateChainConstraint1(t *testing.T) { + a := []int{1, 2, 3, 4} + var x interface{} = a + c := Constraint{ + Target: "str", + Name: Null, + Rule: true, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("maximum item limit is %v; got: %v", (c.Chain)[0].Rule, len(a))), true) +} + +func TestValidateArrayMap_ValidateChainConstraint2(t *testing.T) { + a := []int{1, 2, 3, 4} + var x interface{} = a + c := Constraint{ + Target: "str", + Name: Empty, + Rule: true, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("maximum item limit is %v; got: %v", (c.Chain)[0].Rule, len(a))), true) +} + +func TestValidateArrayMap_ValidateChainConstraint3(t *testing.T) { + var a []string + var x interface{} = a + c := Constraint{ + Target: "str", + Name: Null, + Rule: true, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("value can not be null; required parameter")), true) +} + +func TestValidateArrayMap_ValidateChainConstraint4(t *testing.T) { + var x interface{} = []int{} + c := Constraint{ + Target: "str", + Name: Empty, + Rule: true, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("value can not be null or empty; required parameter")), true) +} + +func TestValidateArrayMap_ValidateChainConstraintNilNotRequired(t *testing.T) { + var a []int + var x interface{} = a + c := Constraint{ + Target: "str", + Name: Null, + Rule: false, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_ValidateChainConstraintEmptyNotRequired(t *testing.T) { + var x interface{} = map[string]int{} + c := Constraint{ + Target: "str", + Name: Empty, + Rule: false, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateArrayMap_ReadOnlyWithError(t *testing.T) { + var x interface{} = []int{1, 2} + c := Constraint{ + Target: "str", + Name: ReadOnly, + Rule: true, + Chain: []Constraint{ + {"str", MaxItems, 3, nil}, + }, + } + z := validateArrayMap(reflect.ValueOf(x), c) + require.Equal(t, strings.Contains(z.Error(), + fmt.Sprintf("readonly parameter; must send as nil or empty in request")), true) +} + +func TestValidateArrayMap_ReadOnlyWithoutError(t *testing.T) { + var x interface{} = []int{} + c := Constraint{ + Target: "str", + Name: ReadOnly, + Rule: true, + Chain: nil, + } + require.Nil(t, validateArrayMap(reflect.ValueOf(x), c)) +} + +func TestValidateString_ReadOnly(t *testing.T) { + var x interface{} = "Hello Gopher" + c := Constraint{ + Target: "str", + Name: ReadOnly, + Rule: true, + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("readonly parameter; must send as nil or empty in request")), true) +} + +func TestValidateString_EmptyTrue(t *testing.T) { + // Empty true means parameter is required but Empty returns error + c := Constraint{ + Target: "str", + Name: Empty, + Rule: true, + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(""), c).Error(), + fmt.Sprintf("value can not be null or empty; required parameter")), true) +} + +func TestValidateString_EmptyFalse(t *testing.T) { + // Empty false means parameter is not required and Empty return nil + var x interface{} + c := Constraint{ + Target: "str", + Name: Empty, + Rule: false, + Chain: nil, + } + require.Nil(t, validateString(reflect.ValueOf(x), c)) +} + +func TestValidateString_MaxLengthInvalid(t *testing.T) { + // Empty true means parameter is required but Empty returns error + var x interface{} = "Hello" + c := Constraint{ + Target: "str", + Name: MaxLength, + Rule: 4, + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value length must be less than or equal to %v", c.Rule)), true) +} + +func TestValidateString_MaxLengthValid(t *testing.T) { + // Empty false means parameter is not required and Empty return nil + c := Constraint{ + Target: "str", + Name: MaxLength, + Rule: 7, + Chain: nil, + } + require.Nil(t, validateString(reflect.ValueOf("Hello"), c)) +} + +func TestValidateString_MaxLengthRuleInvalid(t *testing.T) { + var x interface{} = "Hello" + c := Constraint{ + Target: "str", + Name: MaxLength, + Rule: true, // must be int for maxLength + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("rule must be integer value for %v constraint; got: %v", c.Name, c.Rule)), true) +} + +func TestValidateString_MinLengthInvalid(t *testing.T) { + var x interface{} = "Hello" + c := Constraint{ + Target: "str", + Name: MinLength, + Rule: 10, + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value length must be greater than or equal to %v", c.Rule)), true) +} + +func TestValidateString_MinLengthValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: MinLength, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateString(reflect.ValueOf("Hello"), c)) +} + +func TestValidateString_MinLengthRuleInvalid(t *testing.T) { + var x interface{} = "Hello" + c := Constraint{ + Target: "str", + Name: MinLength, + Rule: true, // must be int for minLength + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("rule must be integer value for %v constraint; got: %v", c.Name, c.Rule)), true) +} + +func TestValidateString_PatternInvalidPattern(t *testing.T) { + var x interface{} = "Hello" + c := Constraint{ + Target: "str", + Name: Pattern, + Rule: `^[[:alnum:$`, + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + "error parsing regexp: missing closing ]"), true) +} + +func TestValidateString_PatternMatch1(t *testing.T) { + c := Constraint{ + Target: "str", + Name: Pattern, + Rule: `^http://\w+$`, + Chain: nil, + } + require.Nil(t, validateString(reflect.ValueOf("http://masd"), c)) +} + +func TestValidateString_PatternMatch2(t *testing.T) { + c := Constraint{ + Target: "str", + Name: Pattern, + Rule: `^[a-zA-Z0-9]+$`, + Chain: nil, + } + require.Nil(t, validateString(reflect.ValueOf("asdadad2323sad"), c)) +} + +func TestValidateString_PatternNotMatch(t *testing.T) { + var x interface{} = "asdad@@ad2323sad" + c := Constraint{ + Target: "str", + Name: Pattern, + Rule: `^[a-zA-Z0-9]+$`, + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value doesn't match pattern %v", c.Rule)), true) +} + +func TestValidateString_InvalidConstraint(t *testing.T) { + var x interface{} = "asdad@@ad2323sad" + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: "^[a-zA-Z0-9]+$", + Chain: nil, + } + require.Equal(t, strings.Contains(validateString(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("constraint %s is not applicable to string type", c.Name)), true) +} + +func TestValidateFloat_InvalidConstraint(t *testing.T) { + var x interface{} = 1.4 + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: 3.0, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("constraint %v is not applicable for type float", c.Name)), true) +} + +func TestValidateFloat_InvalidRuleValue(t *testing.T) { + var x interface{} = 1.4 + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 3, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("rule must be float value for %v constraint; got: %v", c.Name, c.Rule)), true) +} + +func TestValidateFloat_ExclusiveMinimumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 1.0, + Chain: nil, + } + require.Nil(t, validateFloat(reflect.ValueOf(1.42), c)) +} + +func TestValidateFloat_ExclusiveMinimumConstraintInvalid(t *testing.T) { + var x interface{} = 1.4 + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 1.5, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value must be greater than %v", c.Rule)), true) +} + +func TestValidateFloat_ExclusiveMinimumConstraintBoundary(t *testing.T) { + var x interface{} = 1.42 + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 1.42, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value must be greater than %v", c.Rule)), true) +} + +func TestValidateFloat_exclusiveMaximumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: ExclusiveMaximum, + Rule: 2.0, + Chain: nil, + } + require.Nil(t, validateFloat(reflect.ValueOf(1.42), c)) +} + +func TestValidateFloat_exclusiveMaximumConstraintInvalid(t *testing.T) { + var x interface{} = 1.42 + c := Constraint{ + Target: "str", + Name: ExclusiveMaximum, + Rule: 1.2, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value must be less than %v", c.Rule)), true) +} + +func TestValidateFloat_exclusiveMaximumConstraintBoundary(t *testing.T) { + var x interface{} = 1.42 + c := Constraint{ + Target: "str", + Name: ExclusiveMaximum, + Rule: 1.42, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value must be less than %v", c.Rule)), true) +} + +func TestValidateFloat_inclusiveMaximumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMaximum, + Rule: 2.0, + Chain: nil, + } + require.Nil(t, validateFloat(reflect.ValueOf(1.42), c)) +} + +func TestValidateFloat_inclusiveMaximumConstraintInvalid(t *testing.T) { + var x interface{} = 1.42 + c := Constraint{ + Target: "str", + Name: InclusiveMaximum, + Rule: 1.2, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value must be less than or equal to %v", c.Rule)), true) + +} + +func TestValidateFloat_inclusiveMaximumConstraintBoundary(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMaximum, + Rule: 1.42, + Chain: nil, + } + require.Nil(t, validateFloat(reflect.ValueOf(1.42), c)) +} + +func TestValidateFloat_InclusiveMinimumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMinimum, + Rule: 1.0, + Chain: nil, + } + require.Nil(t, validateFloat(reflect.ValueOf(1.42), c)) +} + +func TestValidateFloat_InclusiveMinimumConstraintInvalid(t *testing.T) { + var x interface{} = 1.42 + c := Constraint{ + Target: "str", + Name: InclusiveMinimum, + Rule: 1.5, + Chain: nil, + } + require.Equal(t, strings.Contains(validateFloat(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("value must be greater than or equal to %v", c.Rule)), true) + +} + +func TestValidateFloat_InclusiveMinimumConstraintBoundary(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMinimum, + Rule: 1.42, + Chain: nil, + } + require.Nil(t, validateFloat(reflect.ValueOf(1.42), c)) +} + +func TestValidateInt_InvalidConstraint(t *testing.T) { + var x interface{} = 1 + c := Constraint{ + Target: "str", + Name: UniqueItems, + Rule: 3, + Chain: nil, + } + require.Equal(t, strings.Contains(validateInt(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("constraint %s is not applicable for type integer", c.Name)), true) +} + +func TestValidateInt_InvalidRuleValue(t *testing.T) { + var x interface{} = 1 + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 3.4, + Chain: nil, + } + require.Equal(t, strings.Contains(validateInt(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("rule must be integer value for %v constraint; got: %v", c.Name, c.Rule)), true) +} + +func TestValidateInt_ExclusiveMinimumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 1, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(3), c)) +} + +func TestValidateInt_ExclusiveMinimumConstraintInvalid(t *testing.T) { + var x interface{} = 1 + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 3, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, fmt.Sprintf("value must be greater than %v", c.Rule)).Error()) +} + +func TestValidateInt_ExclusiveMinimumConstraintBoundary(t *testing.T) { + var x interface{} = 1 + c := Constraint{ + Target: "str", + Name: ExclusiveMinimum, + Rule: 1, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, fmt.Sprintf("value must be greater than %v", c.Rule)).Error()) +} + +func TestValidateInt_exclusiveMaximumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: ExclusiveMaximum, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(1), c)) +} + +func TestValidateInt_exclusiveMaximumConstraintInvalid(t *testing.T) { + var x interface{} = 2 + c := Constraint{ + Target: "str", + Name: ExclusiveMaximum, + Rule: 1, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, fmt.Sprintf("value must be less than %v", c.Rule)).Error()) +} + +func TestValidateInt_exclusiveMaximumConstraintBoundary(t *testing.T) { + var x interface{} = 1 + c := Constraint{ + Target: "str", + Name: ExclusiveMaximum, + Rule: 1, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, fmt.Sprintf("value must be less than %v", c.Rule)).Error()) +} + +func TestValidateInt_inclusiveMaximumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMaximum, + Rule: 2, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(1), c)) +} + +func TestValidateInt_inclusiveMaximumConstraintInvalid(t *testing.T) { + var x interface{} = 2 + c := Constraint{ + Target: "str", + Name: InclusiveMaximum, + Rule: 1, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, fmt.Sprintf("value must be less than or equal to %v", c.Rule)).Error()) +} + +func TestValidateInt_inclusiveMaximumConstraintBoundary(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMaximum, + Rule: 1, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(1), c)) +} + +func TestValidateInt_InclusiveMinimumConstraintValid(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMinimum, + Rule: 1, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(1), c)) +} + +func TestValidateInt_InclusiveMinimumConstraintInvalid(t *testing.T) { + var x interface{} = 1 + c := Constraint{ + Target: "str", + Name: InclusiveMinimum, + Rule: 2, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, fmt.Sprintf("value must be greater than or equal to %v", c.Rule)).Error()) +} + +func TestValidateInt_InclusiveMinimumConstraintBoundary(t *testing.T) { + c := Constraint{ + Target: "str", + Name: InclusiveMinimum, + Rule: 1, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(1), c)) +} + +func TestValidateInt_MultipleOfWithoutError(t *testing.T) { + c := Constraint{ + Target: "str", + Name: MultipleOf, + Rule: 10, + Chain: nil, + } + require.Nil(t, validateInt(reflect.ValueOf(2300), c)) +} + +func TestValidateInt_MultipleOfWithError(t *testing.T) { + c := Constraint{ + Target: "str", + Name: MultipleOf, + Rule: 11, + Chain: nil, + } + require.Equal(t, validateInt(reflect.ValueOf(2300), c).Error(), + createError(reflect.ValueOf(2300), c, fmt.Sprintf("value must be a multiple of %v", c.Rule)).Error()) +} + +func TestValidatePointer_NilTrue(t *testing.T) { + var z *int + var x interface{} = z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, // Required property + Chain: nil, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, "value can not be null; required parameter").Error()) +} + +func TestValidatePointer_NilFalse(t *testing.T) { + var z *int + var x interface{} = z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: false, // not required property + Chain: nil, + } + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidatePointer_NilReadonlyValid(t *testing.T) { + var z *int + var x interface{} = z + c := Constraint{ + Target: "ptr", + Name: ReadOnly, + Rule: true, + Chain: nil, + } + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidatePointer_NilReadonlyInvalid(t *testing.T) { + z := 10 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: ReadOnly, + Rule: true, + Chain: nil, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(z), c, "readonly parameter; must send as nil or empty in request").Error()) +} + +func TestValidatePointer_IntValid(t *testing.T) { + z := 10 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: InclusiveMinimum, + Rule: 3, + Chain: nil, + } + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidatePointer_IntInvalid(t *testing.T) { + z := 10 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: InclusiveMinimum, + Rule: 11, + Chain: nil, + }, + }, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(10), c.Chain[0], "value must be greater than or equal to 11").Error()) +} + +func TestValidatePointer_IntInvalidConstraint(t *testing.T) { + z := 10 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: MaxItems, + Rule: 3, + Chain: nil, + }, + }, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(10), c.Chain[0], + fmt.Sprintf("constraint %v is not applicable for type integer", MaxItems)).Error()) +} + +func TestValidatePointer_ValidInt64(t *testing.T) { + z := int64(10) + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: InclusiveMinimum, + Rule: 3, + Chain: nil, + }, + }} + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidatePointer_InvalidConstraintInt64(t *testing.T) { + z := int64(10) + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: MaxItems, + Rule: 3, + Chain: nil, + }, + }, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(10), c.Chain[0], + fmt.Sprintf("constraint %v is not applicable for type integer", MaxItems)).Error()) +} + +func TestValidatePointer_ValidFloat(t *testing.T) { + z := 10.1 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: InclusiveMinimum, + Rule: 3.0, + Chain: nil, + }}} + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidatePointer_InvalidFloat(t *testing.T) { + z := 10.1 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: InclusiveMinimum, + Rule: 12.0, + Chain: nil, + }}, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(10.1), c.Chain[0], + "value must be greater than or equal to 12").Error()) +} + +func TestValidatePointer_InvalidConstraintFloat(t *testing.T) { + z := 10.1 + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: MaxItems, + Rule: 3.0, + Chain: nil, + }}, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(10.1), c.Chain[0], + fmt.Sprintf("constraint %v is not applicable for type float", MaxItems)).Error()) +} + +func TestValidatePointer_StringValid(t *testing.T) { + z := "hello" + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: Pattern, + Rule: "^[a-z]+$", + Chain: nil, + }}} + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidatePointer_StringInvalid(t *testing.T) { + z := "hello" + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: MaxLength, + Rule: 2, + Chain: nil, + }}} + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf("hello"), c.Chain[0], + "value length must be less than or equal to 2").Error()) +} + +func TestValidatePointer_ArrayValid(t *testing.T) { + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: UniqueItems, + Rule: "true", + Chain: nil, + }}} + require.Nil(t, validatePtr(reflect.ValueOf(&[]string{"1", "2"}), c)) +} + +func TestValidatePointer_ArrayInvalid(t *testing.T) { + z := []string{"1", "2", "2"} + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{{ + Target: "ptr", + Name: UniqueItems, + Rule: true, + Chain: nil, + }}, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(z), c.Chain[0], + fmt.Sprintf("all items in parameter %q must be unique; got:%v", c.Target, z)).Error()) +} + +func TestValidatePointer_MapValid(t *testing.T) { + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{ + { + Target: "ptr", + Name: UniqueItems, + Rule: true, + Chain: nil, + }}} + require.Nil(t, validatePtr(reflect.ValueOf(&map[interface{}]string{1: "1", "1": "2"}), c)) +} + +func TestValidatePointer_MapInvalid(t *testing.T) { + z := map[interface{}]string{1: "1", "1": "2", 1.3: "2"} + var x interface{} = &z + c := Constraint{ + Target: "ptr", + Name: Null, + Rule: true, + Chain: []Constraint{{ + Target: "ptr", + Name: UniqueItems, + Rule: true, + Chain: nil, + }}, + } + require.Equal(t, strings.Contains(validatePtr(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("all items in parameter %q must be unique;", c.Target)), true) +} + +type Child struct { + I string +} +type Product struct { + C *Child + Str *string + Name string + Arr *[]string + M *map[string]string + Num *int32 +} + +type Sample struct { + M *map[string]*string + Name string +} + +func TestValidatePointer_StructWithError(t *testing.T) { + s := "hello" + var x interface{} = &Product{ + C: &Child{"100"}, + Str: &s, + Name: "Gopher", + } + c := Constraint{ + "p", Null, "True", + []Constraint{ + {"C", Null, true, + []Constraint{ + {"I", MaxLength, 2, nil}, + }}, + {"Str", MaxLength, 2, nil}, + {"Name", MaxLength, 5, nil}, + }, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf("100"), c.Chain[0].Chain[0], + "value length must be less than or equal to 2").Error()) +} + +func TestValidatePointer_WithNilStruct(t *testing.T) { + var p *Product + var x interface{} = p + c := Constraint{ + "p", Null, true, + []Constraint{ + {"C", Null, true, + []Constraint{ + {"I", Empty, true, + []Constraint{ + {"I", MaxLength, 5, nil}, + }}, + }}, + {"Str", MaxLength, 2, nil}, + {"Name", MaxLength, 5, nil}, + }, + } + require.Equal(t, validatePtr(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x), c, + fmt.Sprintf("value can not be null; required parameter")).Error()) +} + +func TestValidatePointer_StructWithNoError(t *testing.T) { + s := "hello" + var x interface{} = &Product{ + C: &Child{"100"}, + Str: &s, + Name: "Gopher", + } + c := Constraint{ + "p", Null, true, + []Constraint{ + {"C", Null, true, + []Constraint{ + {"I", Empty, true, + []Constraint{ + {"I", MaxLength, 5, nil}, + }}, + }}, + }, + } + require.Nil(t, validatePtr(reflect.ValueOf(x), c)) +} + +func TestValidateStruct_FieldNotExist(t *testing.T) { + s := "hello" + var x interface{} = Product{ + C: &Child{"100"}, + Str: &s, + Name: "Gopher", + } + c := Constraint{ + "C", Null, true, + []Constraint{ + {"Name", Empty, true, nil}, + }, + } + s = "Name" + require.Equal(t, validateStruct(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(Child{"100"}), c.Chain[0], + fmt.Sprintf("field %q doesn't exist", s)).Error()) +} + +func TestValidateStruct_WithChainConstraint(t *testing.T) { + s := "hello" + var x interface{} = Product{ + C: &Child{"100"}, + Str: &s, + Name: "Gopher", + } + c := Constraint{ + "C", Null, true, + []Constraint{ + {"I", Empty, true, + []Constraint{ + {"I", MaxLength, 2, nil}, + }}, + }, + } + require.Equal(t, validateStruct(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf("100"), c.Chain[0].Chain[0], "value length must be less than or equal to 2").Error()) +} + +func TestValidateStruct_WithoutChainConstraint(t *testing.T) { + s := "hello" + var x interface{} = Product{ + C: &Child{""}, + Str: &s, + Name: "Gopher", + } + c := Constraint{"C", Null, true, + []Constraint{ + {"I", Empty, true, nil}, // throw error for Empty + }} + require.Equal(t, validateStruct(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(""), c.Chain[0], "value can not be null or empty; required parameter").Error()) +} + +func TestValidateStruct_WithArrayNull(t *testing.T) { + s := "hello" + var x interface{} = Product{ + C: &Child{""}, + Str: &s, + Name: "Gopher", + Arr: nil, + } + c := Constraint{"Arr", Null, true, + []Constraint{ + {"Arr", MaxItems, 4, nil}, + {"Arr", MinItems, 2, nil}, + }, + } + require.Equal(t, validateStruct(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(x.(Product).Arr), c, "value can not be null; required parameter").Error()) +} + +func TestValidateStruct_WithArrayEmptyError(t *testing.T) { + // arr := []string{} + var x interface{} = Product{ + Arr: &[]string{}, + } + c := Constraint{ + "Arr", Null, true, + []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MaxItems, 4, nil}, + {"Arr", MinItems, 2, nil}, + }} + + require.Equal(t, validateStruct(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(*(x.(Product).Arr)), c.Chain[0], + fmt.Sprintf("value can not be null or empty; required parameter")).Error()) +} + +func TestValidateStruct_WithArrayEmptyWithoutError(t *testing.T) { + var x interface{} = Product{ + Arr: &[]string{}, + } + c := Constraint{ + "Arr", Null, true, + []Constraint{ + {"Arr", Empty, false, nil}, + {"Arr", MaxItems, 4, nil}, + }, + } + require.Nil(t, validateStruct(reflect.ValueOf(x), c)) +} + +func TestValidateStruct_ArrayWithError(t *testing.T) { + arr := []string{"1", "1"} + var x interface{} = Product{ + Arr: &arr, + } + c := Constraint{ + "Arr", Null, true, + []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MaxItems, 4, nil}, + {"Arr", UniqueItems, true, nil}, + }, + } + s := "Arr" + require.Equal(t, validateStruct(reflect.ValueOf(x), c).Error(), + createError(reflect.ValueOf(*(x.(Product).Arr)), c.Chain[2], + fmt.Sprintf("all items in parameter %q must be unique; got:%v", s, *(x.(Product).Arr))).Error()) +} + +func TestValidateStruct_MapWithError(t *testing.T) { + m := map[string]string{ + "a": "hello", + "b": "hello", + } + var x interface{} = Product{ + M: &m, + } + c := Constraint{ + "M", Null, true, + []Constraint{ + {"M", Empty, true, nil}, + {"M", MaxItems, 4, nil}, + {"M", UniqueItems, true, nil}, + }, + } + + s := "M" + require.Equal(t, strings.Contains(validateStruct(reflect.ValueOf(x), c).Error(), + fmt.Sprintf("all items in parameter %q must be unique;", s)), true) +} + +func TestValidateStruct_MapWithNoError(t *testing.T) { + m := map[string]string{} + var x interface{} = Product{ + M: &m, + } + c := Constraint{ + "M", Null, true, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MaxItems, 4, nil}, + }, + } + require.Nil(t, validateStruct(reflect.ValueOf(x), c)) +} + +func TestValidateStruct_MapNilNoError(t *testing.T) { + var m map[string]string + var x interface{} = Product{ + M: &m, + } + c := Constraint{ + "M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MaxItems, 4, nil}, + }, + } + require.Nil(t, validateStruct(reflect.ValueOf(x), c)) +} + +func TestValidate_MapValidationWithError(t *testing.T) { + var x1 interface{} = &Product{ + Arr: &[]string{"1", "2"}, + M: &map[string]string{"a": "hello"}, + } + s := "hello" + var x2 interface{} = &Sample{ + M: &map[string]*string{"a": &s}, + } + v := []Validation{ + {x1, + []Constraint{{"x1", Null, true, + []Constraint{ + {"Arr", Null, true, + []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MaxItems, 4, nil}, + {"Arr", UniqueItems, true, nil}, + }, + }, + {"M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MinItems, 1, nil}, + {"M", UniqueItems, true, nil}, + }, + }, + }, + }}}, + {x2, + []Constraint{ + {"x2", Null, true, + []Constraint{ + {"M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MinItems, 2, nil}, + {"M", UniqueItems, true, nil}, + }, + }, + }, + }, + {"Name", Empty, true, nil}, + }}, + } + + z := Validate(v).Error() + require.Equal(t, strings.Contains(z, "minimum item limit is 2; got: 1"), true) + require.Equal(t, strings.Contains(z, "MinItems"), true) +} + +func TestValidate_MapValidationWithoutError(t *testing.T) { + var x1 interface{} = &Product{ + Arr: &[]string{"1", "2"}, + M: &map[string]string{"a": "hello"}, + } + s := "hello" + var x2 interface{} = &Sample{ + M: &map[string]*string{"a": &s}, + } + v := []Validation{ + {x1, + []Constraint{{"x1", Null, true, + []Constraint{ + {"Arr", Null, true, + []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MaxItems, 4, nil}, + {"Arr", UniqueItems, true, nil}, + }, + }, + {"M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MinItems, 1, nil}, + {"M", UniqueItems, true, nil}, + {"M", Pattern, "^[a-z]+$", nil}, + }, + }, + }, + }}}, + {x2, + []Constraint{ + {"x2", Null, true, + []Constraint{ + {"M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MinItems, 1, nil}, + {"M", UniqueItems, true, nil}, + {"M", Pattern, "^[a-z]+$", nil}, + }, + }, + }, + }, + {"Name", Empty, true, nil}, + }}, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_UnknownType(t *testing.T) { + var c chan int + v := []Validation{ + {c, + []Constraint{{"c", Null, true, nil}}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(c), v[0].Constraints[0], + fmt.Sprintf("unknown type %v", reflect.ValueOf(c).Kind())).Error()) +} + +func TestValidate_example1(t *testing.T) { + var x1 interface{} = Product{ + Arr: &[]string{"1", "1"}, + M: &map[string]string{"a": "hello"}, + } + s := "hello" + var x2 interface{} = Sample{ + M: &map[string]*string{"a": &s}, + } + v := []Validation{ + {x1, + []Constraint{{"Arr", Null, true, + []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MaxItems, 4, nil}, + {"Arr", UniqueItems, true, nil}, + }}, + {"M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MinItems, 1, nil}, + {"M", UniqueItems, true, nil}, + }, + }, + }}, + {x2, + []Constraint{ + {"M", Null, false, + []Constraint{ + {"M", Empty, false, nil}, + {"M", MinItems, 1, nil}, + {"M", UniqueItems, true, nil}, + }, + }, + {"Name", Empty, true, nil}, + }}, + } + s = "Arr" + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf([]string{"1", "1"}), v[0].Constraints[0].Chain[2], + fmt.Sprintf("all items in parameter %q must be unique; got:%v", s, []string{"1", "1"})).Error()) +} + +func TestValidate_Int(t *testing.T) { + n := int32(100) + v := []Validation{ + {n, + []Constraint{ + {"n", MultipleOf, 10, nil}, + {"n", ExclusiveMinimum, 100, nil}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(n), v[0].Constraints[1], + "value must be greater than 100").Error()) +} + +func TestValidate_IntPointer(t *testing.T) { + n := int32(100) + p := &n + v := []Validation{ + {p, + []Constraint{ + {"p", Null, true, []Constraint{ + {"p", ExclusiveMinimum, 100, nil}, + }}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(n), v[0].Constraints[0].Chain[0], + "value must be greater than 100").Error()) + + // required paramter + p = nil + v = []Validation{ + {p, + []Constraint{ + {"p", Null, true, []Constraint{ + {"p", ExclusiveMinimum, 100, nil}, + }}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(v[0].TargetValue), v[0].Constraints[0], + "value can not be null; required parameter").Error()) + + // Not required + p = nil + v = []Validation{ + {p, + []Constraint{ + {"p", Null, false, []Constraint{ + {"p", ExclusiveMinimum, 100, nil}, + }}, + }, + }, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_IntStruct(t *testing.T) { + n := int32(100) + p := &Product{ + Num: &n, + } + + v := []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"Num", Null, true, []Constraint{ + {"Num", ExclusiveMinimum, 100, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(n), v[0].Constraints[0].Chain[0].Chain[0], + "value must be greater than 100").Error()) + + // required paramter + p = &Product{} + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"p.Num", Null, true, []Constraint{ + {"p.Num", ExclusiveMinimum, 100, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(p.Num), v[0].Constraints[0].Chain[0], + "value can not be null; required parameter").Error()) + + // Not required + p = &Product{} + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"Num", Null, false, []Constraint{ + {"Num", ExclusiveMinimum, 100, nil}, + }}, + }, + }}}, + } + require.Nil(t, Validate(v)) + + // Parent not required + p = nil + v = []Validation{ + {p, []Constraint{{"p", Null, false, + []Constraint{ + {"Num", Null, false, []Constraint{ + {"Num", ExclusiveMinimum, 100, nil}, + }}, + }, + }}}, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_String(t *testing.T) { + s := "hello" + v := []Validation{ + {s, + []Constraint{ + {"s", Empty, true, nil}, + {"s", Empty, true, + []Constraint{{"s", MaxLength, 3, nil}}}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[1].Chain[0], + "value length must be less than or equal to 3").Error()) + + // required paramter + s = "" + v = []Validation{ + {s, + []Constraint{ + {"s", Empty, true, nil}, + {"s", Empty, true, + []Constraint{{"s", MaxLength, 3, nil}}}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[1], + "value can not be null or empty; required parameter").Error()) + + // not required paramter + s = "" + v = []Validation{ + {s, + []Constraint{ + {"s", Empty, false, nil}, + {"s", Empty, false, + []Constraint{{"s", MaxLength, 3, nil}}}, + }, + }, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_StringStruct(t *testing.T) { + s := "hello" + p := &Product{ + Str: &s, + } + + v := []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"p.Str", Null, true, []Constraint{ + {"p.Str", Empty, true, nil}, + {"p.Str", MaxLength, 3, nil}, + }}, + }, + }}}, + } + // e := ValidationError{ + // Constraint: MaxLength, + // Target: "Str", + // TargetValue: s, + // Details: fmt.Sprintf("value length must be less than 3", s), + // } + // if z := Validate(v); !reflect.DeepEqual(e, z) { + // t.Fatalf("autorest/validation: Validate failed to return error \nexpect: %v\ngot: %v", e, z) + // } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[0].Chain[0].Chain[1], + "value length must be less than or equal to 3").Error()) + + // required paramter - can't be Empty + s = "" + p = &Product{ + Str: &s, + } + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"Str", Null, true, []Constraint{ + {"Str", Empty, true, nil}, + {"Str", MaxLength, 3, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[0].Chain[0].Chain[0], + "value can not be null or empty; required parameter").Error()) + + // required paramter - can't be null + p = &Product{} + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"p.Str", Null, true, []Constraint{ + {"p.Str", Empty, true, nil}, + {"p.Str", MaxLength, 3, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(p.Str), v[0].Constraints[0].Chain[0], + "value can not be null; required parameter").Error()) + + // Not required + p = &Product{} + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"Str", Null, false, []Constraint{ + {"Str", Empty, true, nil}, + {"Str", MaxLength, 3, nil}, + }}, + }, + }}}, + } + require.Nil(t, Validate(v)) + + // Parent not required + p = nil + v = []Validation{ + {p, []Constraint{{"p", Null, false, + []Constraint{ + {"Str", Null, true, []Constraint{ + {"Str", Empty, true, nil}, + {"Str", MaxLength, 3, nil}, + }}, + }, + }}}, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_Array(t *testing.T) { + s := []string{"hello"} + v := []Validation{ + {s, + []Constraint{ + {"s", Null, true, + []Constraint{ + {"s", Empty, true, nil}, + {"s", MinItems, 2, nil}, + }}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[0].Chain[1], + fmt.Sprintf("minimum item limit is 2; got: %v", len(s))).Error()) + + // Empty array + v = []Validation{ + {[]string{}, + []Constraint{ + {"s", Null, true, + []Constraint{ + {"s", Empty, true, nil}, + {"s", MinItems, 2, nil}}}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf([]string{}), v[0].Constraints[0].Chain[0], + "value can not be null or empty; required parameter").Error()) + + // null array + var s1 []string + v = []Validation{ + {s1, + []Constraint{ + {"s1", Null, true, + []Constraint{ + {"s1", Empty, true, nil}, + {"s1", MinItems, 2, nil}}}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s1), v[0].Constraints[0], + "value can not be null; required parameter").Error()) + + // not required paramter + v = []Validation{ + {s1, + []Constraint{ + {"s1", Null, false, + []Constraint{ + {"s1", Empty, true, nil}, + {"s1", MinItems, 2, nil}}}, + }, + }, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_ArrayPointer(t *testing.T) { + s := []string{"hello"} + v := []Validation{ + {&s, + []Constraint{ + {"s", Null, true, + []Constraint{ + {"s", Empty, true, nil}, + {"s", MinItems, 2, nil}, + }}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[0].Chain[1], + fmt.Sprintf("minimum item limit is 2; got: %v", len(s))).Error()) + + // Empty array + v = []Validation{ + {&[]string{}, + []Constraint{ + {"s", Null, true, + []Constraint{ + {"s", Empty, true, nil}, + {"s", MinItems, 2, nil}}}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf([]string{}), v[0].Constraints[0].Chain[0], + "value can not be null or empty; required parameter").Error()) + + // null array + var s1 *[]string + v = []Validation{ + {s1, + []Constraint{ + {"s1", Null, true, + []Constraint{ + {"s1", Empty, true, nil}, + {"s1", MinItems, 2, nil}}}, + }, + }, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s1), v[0].Constraints[0], + "value can not be null; required parameter").Error()) + + // not required paramter + v = []Validation{ + {s1, + []Constraint{ + {"s1", Null, false, + []Constraint{ + {"s1", Empty, true, nil}, + {"s1", MinItems, 2, nil}}}, + }, + }, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_ArrayInStruct(t *testing.T) { + s := []string{"hello"} + p := &Product{ + Arr: &s, + } + + v := []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"p.Arr", Null, true, []Constraint{ + {"p.Arr", Empty, true, nil}, + {"p.Arr", MinItems, 2, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(s), v[0].Constraints[0].Chain[0].Chain[1], + fmt.Sprintf("minimum item limit is 2; got: %v", len(s))).Error()) + + // required paramter - can't be Empty + p = &Product{ + Arr: &[]string{}, + } + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"p.Arr", Null, true, []Constraint{ + {"p.Arr", Empty, true, nil}, + {"p.Arr", MinItems, 2, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf([]string{}), v[0].Constraints[0].Chain[0].Chain[0], + "value can not be null or empty; required parameter").Error()) + + // required paramter - can't be null + p = &Product{} + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{ + {"p.Arr", Null, true, []Constraint{ + {"p.Arr", Empty, true, nil}, + {"p.Arr", MinItems, 2, nil}, + }}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(p.Arr), v[0].Constraints[0].Chain[0], + "value can not be null; required parameter").Error()) + + // Not required + v = []Validation{ + {&Product{}, []Constraint{{"p", Null, true, + []Constraint{ + {"Arr", Null, false, []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MinItems, 2, nil}, + }}, + }, + }}}, + } + require.Nil(t, Validate(v)) + + // Parent not required + p = nil + v = []Validation{ + {p, []Constraint{{"p", Null, false, + []Constraint{ + {"Arr", Null, true, []Constraint{ + {"Arr", Empty, true, nil}, + {"Arr", MinItems, 2, nil}, + }}, + }, + }}}, + } + require.Nil(t, Validate(v)) +} + +func TestValidate_StructInStruct(t *testing.T) { + p := &Product{ + C: &Child{I: "hello"}, + } + v := []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{{"C", Null, true, + []Constraint{{"I", MinLength, 7, nil}}}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(p.C.I), v[0].Constraints[0].Chain[0].Chain[0], + "value length must be greater than or equal to 7").Error()) + + // required paramter - can't be Empty + p = &Product{ + C: &Child{I: ""}, + } + + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{{"C", Null, true, + []Constraint{{"I", Empty, true, nil}}}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(p.C.I), v[0].Constraints[0].Chain[0].Chain[0], + "value can not be null or empty; required parameter").Error()) + + // required paramter - can't be null + p = &Product{} + v = []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{{"C", Null, true, + []Constraint{{"I", Empty, true, nil}}}, + }, + }}}, + } + require.Equal(t, Validate(v).Error(), + createError(reflect.ValueOf(p.C), v[0].Constraints[0].Chain[0], + "value can not be null; required parameter").Error()) + + // Not required + v = []Validation{ + {&Product{}, []Constraint{{"p", Null, true, + []Constraint{{"p.C", Null, false, + []Constraint{{"p.C.I", Empty, true, nil}}}, + }, + }}}, + } + require.Nil(t, Validate(v)) + + // Parent not required + p = nil + v = []Validation{ + {p, []Constraint{{"p", Null, false, + []Constraint{{"p.C", Null, false, + []Constraint{{"p.C.I", Empty, true, nil}}}, + }, + }}}, + } + require.Nil(t, Validate(v)) +} + +func TestNewErrorWithValidationError(t *testing.T) { + p := &Product{} + v := []Validation{ + {p, []Constraint{{"p", Null, true, + []Constraint{{"p.C", Null, true, + []Constraint{{"p.C.I", Empty, true, nil}}}, + }, + }}}, + } + err := createError(reflect.ValueOf(p.C), v[0].Constraints[0].Chain[0], "value can not be null; required parameter") + z := fmt.Sprintf("batch.AccountClient#Create: Invalid input: %s", + err.Error()) + require.Equal(t, NewErrorWithValidationError(err, "batch.AccountClient", "Create").Error(), z) +} diff --git a/vendor/github.com/Azure/go-autorest/glide.lock b/vendor/github.com/Azure/go-autorest/glide.lock new file mode 100644 index 000000000..695d58cff --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/glide.lock @@ -0,0 +1,44 @@ +hash: 6e0121d946623e7e609280b1b18627e1c8a767fdece54cb97c4447c1167cbc46 +updated: 2017-08-31T13:58:01.034822883+01:00 +imports: +- name: github.com/dgrijalva/jwt-go + version: 2268707a8f0843315e2004ee4f1d021dc08baedf + subpackages: + - . +- name: github.com/dimchansky/utfbom + version: 6c6132ff69f0f6c088739067407b5d32c52e1d0f +- name: github.com/mitchellh/go-homedir + version: b8bc1bf767474819792c23f32d8286a45736f1c6 +- name: golang.org/x/crypto + version: 81e90905daefcd6fd217b62423c0908922eadb30 + repo: https://github.com/golang/crypto.git + vcs: git + subpackages: + - pkcs12 + - pkcs12/internal/rc2 +- name: golang.org/x/net + version: 66aacef3dd8a676686c7ae3716979581e8b03c47 + repo: https://github.com/golang/net.git + vcs: git + subpackages: + - . +- name: golang.org/x/text + version: 21e35d45962262c8ee80f6cb048dcf95ad0e9d79 + repo: https://github.com/golang/text.git + vcs: git + subpackages: + - . +testImports: +- name: github.com/davecgh/go-spew + version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 + subpackages: + - spew +- name: github.com/pmezard/go-difflib + version: d8ed2627bdf02c080bf22230dbb337003b7aba2d + subpackages: + - difflib +- name: github.com/stretchr/testify + version: 890a5c3458b43e6104ff5da8dfa139d013d77544 + subpackages: + - assert + - require diff --git a/vendor/github.com/Azure/go-autorest/glide.yaml b/vendor/github.com/Azure/go-autorest/glide.yaml new file mode 100644 index 000000000..375dcfd1a --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/glide.yaml @@ -0,0 +1,22 @@ +package: github.com/Azure/go-autorest +import: +- package: github.com/dgrijalva/jwt-go + subpackages: + - . +- package: golang.org/x/crypto + repo: https://github.com/golang/crypto.git + vcs: git + subpackages: + - pkcs12 +- package: golang.org/x/net + repo: https://github.com/golang/net.git + vcs: git + subpackages: + - . +- package: golang.org/x/text + repo: https://github.com/golang/text.git + vcs: git + subpackages: + - . +- package: github.com/mitchellh/go-homedir +- package: github.com/dimchansky/utfbom diff --git a/vendor/github.com/PuerkitoBio/purell/.gitignore b/vendor/github.com/PuerkitoBio/purell/.gitignore new file mode 100644 index 000000000..748e4c807 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/.gitignore @@ -0,0 +1,5 @@ +*.sublime-* +.DS_Store +*.swp +*.swo +tags diff --git a/vendor/github.com/PuerkitoBio/purell/.travis.yml b/vendor/github.com/PuerkitoBio/purell/.travis.yml new file mode 100644 index 000000000..facfc91c6 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - 1.4 + - 1.5 + - 1.6 + - tip diff --git a/vendor/github.com/PuerkitoBio/purell/README.md b/vendor/github.com/PuerkitoBio/purell/README.md new file mode 100644 index 000000000..09e8a32cb --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/README.md @@ -0,0 +1,187 @@ +# Purell + +Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know... + +Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc]. + +[![build status](https://secure.travis-ci.org/PuerkitoBio/purell.png)](http://travis-ci.org/PuerkitoBio/purell) + +## Install + +`go get github.com/PuerkitoBio/purell` + +## Changelog + +* **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121). +* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich). +* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]). +* **v0.2.0** : Add benchmarks, Attempt IDN support. +* **v0.1.0** : Initial release. + +## Examples + +From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."): + +```go +package purell + +import ( + "fmt" + "net/url" +) + +func ExampleNormalizeURLString() { + if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/", + FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil { + panic(err) + } else { + fmt.Print(normalized) + } + // Output: http://somewebsite.com:80/Amazing%3F/url/ +} + +func ExampleMustNormalizeURLString() { + normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/", + FlagsUnsafeGreedy) + fmt.Print(normalized) + + // Output: http://somewebsite.com/Amazing%FA/url +} + +func ExampleNormalizeURL() { + if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil { + panic(err) + } else { + normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment) + fmt.Print(normalized) + } + + // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0 +} +``` + +## API + +As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags: + +```go +const ( + // Safe normalizations + FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1 + FlagLowercaseHost // http://HOST -> http://host + FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF + FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA + FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$ + FlagRemoveDefaultPort // http://host:80 -> http://host + FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path + + // Usually safe normalizations + FlagRemoveTrailingSlash // http://host/path/ -> http://host/path + FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags) + FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c + + // Unsafe normalizations + FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/ + FlagRemoveFragment // http://host/path#fragment -> http://host/path + FlagForceHTTP // https://host -> http://host + FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b + FlagRemoveWWW // http://www.host/ -> http://host/ + FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags) + FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3 + + // Normalizations not in the wikipedia article, required to cover tests cases + // submitted by jehiah + FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147 + FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147 + FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147 + FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path + FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path + + // Convenience set of safe normalizations + FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator + + // For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags, + // while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix". + + // Convenience set of usually safe normalizations (includes FlagsSafe) + FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments + FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments + + // Convenience set of unsafe normalizations (includes FlagsUsuallySafe) + FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery + FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery + + // Convenience set of all available flags + FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator + FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator +) +``` + +For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set. + +The [full godoc reference is available on gopkgdoc][godoc]. + +Some things to note: + +* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it. + +* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*): + - %24 -> $ + - %26 -> & + - %2B-%3B -> +,-./0123456789:; + - %3D -> = + - %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ + - %5F -> _ + - %61-%7A -> abcdefghijklmnopqrstuvwxyz + - %7E -> ~ + + +* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization). + +* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell. + +* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object. + +### Safe vs Usually Safe vs Unsafe + +Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between. + +Consider the following URL: + +`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid` + +Normalizing with the `FlagsSafe` gives: + +`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid` + +With the `FlagsUsuallySafeGreedy`: + +`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid` + +And with `FlagsUnsafeGreedy`: + +`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3` + +## TODOs + +* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`. + +## Thanks / Contributions + +@rogpeppe +@jehiah +@opennota +@pchristopher1275 +@zenovich +@beeker1121 + +## License + +The [BSD 3-Clause license][bsd]. + +[bsd]: http://opensource.org/licenses/BSD-3-Clause +[wiki]: http://en.wikipedia.org/wiki/URL_normalization +[rfc]: http://tools.ietf.org/html/rfc3986#section-6 +[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell +[pr5]: https://github.com/PuerkitoBio/purell/pull/5 +[iss7]: https://github.com/PuerkitoBio/purell/issues/7 diff --git a/vendor/github.com/PuerkitoBio/purell/bench_test.go b/vendor/github.com/PuerkitoBio/purell/bench_test.go new file mode 100644 index 000000000..7549731fc --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/bench_test.go @@ -0,0 +1,57 @@ +package purell + +import ( + "testing" +) + +var ( + safeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/..//?" + usuallySafeUrl = "HttPS://..iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/" + unsafeUrl = "HttPS://..www.iaMHost..Test:443/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment" + allDWORDUrl = "HttPS://1113982867:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment" + allOctalUrl = "HttPS://0102.0146.07.0223:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment" + allHexUrl = "HttPS://0x42660793:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment" + allCombinedUrl = "HttPS://..0x42660793.:/paTh^A%ef//./%41PaTH/../final/index.html?t=val1&a=val4&z=val5&a=val1#fragment" +) + +func BenchmarkSafe(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(safeUrl, FlagsSafe) + } +} + +func BenchmarkUsuallySafe(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(usuallySafeUrl, FlagsUsuallySafeGreedy) + } +} + +func BenchmarkUnsafe(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(unsafeUrl, FlagsUnsafeGreedy) + } +} + +func BenchmarkAllDWORD(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(allDWORDUrl, FlagsAllGreedy) + } +} + +func BenchmarkAllOctal(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(allOctalUrl, FlagsAllGreedy) + } +} + +func BenchmarkAllHex(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(allHexUrl, FlagsAllGreedy) + } +} + +func BenchmarkAllCombined(b *testing.B) { + for i := 0; i < b.N; i++ { + NormalizeURLString(allCombinedUrl, FlagsAllGreedy) + } +} diff --git a/vendor/github.com/PuerkitoBio/purell/example_test.go b/vendor/github.com/PuerkitoBio/purell/example_test.go new file mode 100644 index 000000000..997b95369 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/example_test.go @@ -0,0 +1,35 @@ +package purell + +import ( + "fmt" + "net/url" +) + +func ExampleNormalizeURLString() { + if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/", + FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil { + panic(err) + } else { + fmt.Print(normalized) + } + // Output: http://somewebsite.com:80/Amazing%3F/url/ +} + +func ExampleMustNormalizeURLString() { + normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/", + FlagsUnsafeGreedy) + fmt.Print(normalized) + + // Output: http://somewebsite.com/Amazing%FA/url +} + +func ExampleNormalizeURL() { + if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil { + panic(err) + } else { + normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment) + fmt.Print(normalized) + } + + // Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0 +} diff --git a/vendor/github.com/PuerkitoBio/purell/purell_test.go b/vendor/github.com/PuerkitoBio/purell/purell_test.go new file mode 100644 index 000000000..a3732e5a3 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/purell_test.go @@ -0,0 +1,768 @@ +package purell + +import ( + "fmt" + "net/url" + "testing" +) + +type testCase struct { + nm string + src string + flgs NormalizationFlags + res string + parsed bool +} + +var ( + cases = [...]*testCase{ + &testCase{ + "LowerScheme", + "HTTP://www.SRC.ca", + FlagLowercaseScheme, + "http://www.SRC.ca", + false, + }, + &testCase{ + "LowerScheme2", + "http://www.SRC.ca", + FlagLowercaseScheme, + "http://www.SRC.ca", + false, + }, + &testCase{ + "LowerHost", + "HTTP://www.SRC.ca/", + FlagLowercaseHost, + "http://www.src.ca/", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "UpperEscapes", + `http://www.whatever.com/Some%aa%20Special%8Ecases/`, + FlagUppercaseEscapes, + "http://www.whatever.com/Some%AA%20Special%8Ecases/", + false, + }, + &testCase{ + "UnnecessaryEscapes", + `http://www.toto.com/%41%42%2E%44/%32%33%52%2D/%5f%7E`, + FlagDecodeUnnecessaryEscapes, + "http://www.toto.com/AB.D/23R-/_~", + false, + }, + &testCase{ + "RemoveDefaultPort", + "HTTP://www.SRC.ca:80/", + FlagRemoveDefaultPort, + "http://www.SRC.ca/", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveDefaultPort2", + "HTTP://www.SRC.ca:80", + FlagRemoveDefaultPort, + "http://www.SRC.ca", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveDefaultPort3", + "HTTP://www.SRC.ca:8080", + FlagRemoveDefaultPort, + "http://www.SRC.ca:8080", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "Safe", + "HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e", + FlagsSafe, + "http://www.src.ca/to%1Ato%8B%EE/OKnowABC~", + false, + }, + &testCase{ + "BothLower", + "HTTP://www.SRC.ca:80/to%1ato%8b%ee/OKnow%41%42%43%7e", + FlagLowercaseHost | FlagLowercaseScheme, + "http://www.src.ca:80/to%1Ato%8B%EE/OKnowABC~", + false, + }, + &testCase{ + "RemoveTrailingSlash", + "HTTP://www.SRC.ca:80/", + FlagRemoveTrailingSlash, + "http://www.SRC.ca:80", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveTrailingSlash2", + "HTTP://www.SRC.ca:80/toto/titi/", + FlagRemoveTrailingSlash, + "http://www.SRC.ca:80/toto/titi", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveTrailingSlash3", + "HTTP://www.SRC.ca:80/toto/titi/fin/?a=1", + FlagRemoveTrailingSlash, + "http://www.SRC.ca:80/toto/titi/fin?a=1", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "AddTrailingSlash", + "HTTP://www.SRC.ca:80", + FlagAddTrailingSlash, + "http://www.SRC.ca:80/", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "AddTrailingSlash2", + "HTTP://www.SRC.ca:80/toto/titi.html", + FlagAddTrailingSlash, + "http://www.SRC.ca:80/toto/titi.html/", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "AddTrailingSlash3", + "HTTP://www.SRC.ca:80/toto/titi/fin?a=1", + FlagAddTrailingSlash, + "http://www.SRC.ca:80/toto/titi/fin/?a=1", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveDotSegments", + "HTTP://root/a/b/./../../c/", + FlagRemoveDotSegments, + "http://root/c/", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveDotSegments2", + "HTTP://root/../a/b/./../c/../d", + FlagRemoveDotSegments, + "http://root/a/d", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "UsuallySafe", + "HTTP://www.SRC.ca:80/to%1ato%8b%ee/./c/d/../OKnow%41%42%43%7e/?a=b#test", + FlagsUsuallySafeGreedy, + "http://www.src.ca/to%1Ato%8B%EE/c/OKnowABC~?a=b#test", + false, + }, + &testCase{ + "RemoveDirectoryIndex", + "HTTP://root/a/b/c/default.aspx", + FlagRemoveDirectoryIndex, + "http://root/a/b/c/", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveDirectoryIndex2", + "HTTP://root/a/b/c/default#a=b", + FlagRemoveDirectoryIndex, + "http://root/a/b/c/default#a=b", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "RemoveFragment", + "HTTP://root/a/b/c/default#toto=tata", + FlagRemoveFragment, + "http://root/a/b/c/default", // Since Go1.1, scheme is automatically lowercased + false, + }, + &testCase{ + "ForceHTTP", + "https://root/a/b/c/default#toto=tata", + FlagForceHTTP, + "http://root/a/b/c/default#toto=tata", + false, + }, + &testCase{ + "RemoveDuplicateSlashes", + "https://root/a//b///c////default#toto=tata", + FlagRemoveDuplicateSlashes, + "https://root/a/b/c/default#toto=tata", + false, + }, + &testCase{ + "RemoveDuplicateSlashes2", + "https://root//a//b///c////default#toto=tata", + FlagRemoveDuplicateSlashes, + "https://root/a/b/c/default#toto=tata", + false, + }, + &testCase{ + "RemoveWWW", + "https://www.root/a/b/c/", + FlagRemoveWWW, + "https://root/a/b/c/", + false, + }, + &testCase{ + "RemoveWWW2", + "https://WwW.Root/a/b/c/", + FlagRemoveWWW, + "https://Root/a/b/c/", + false, + }, + &testCase{ + "AddWWW", + "https://Root/a/b/c/", + FlagAddWWW, + "https://www.Root/a/b/c/", + false, + }, + &testCase{ + "SortQuery", + "http://root/toto/?b=4&a=1&c=3&b=2&a=5", + FlagSortQuery, + "http://root/toto/?a=1&a=5&b=2&b=4&c=3", + false, + }, + &testCase{ + "RemoveEmptyQuerySeparator", + "http://root/toto/?", + FlagRemoveEmptyQuerySeparator, + "http://root/toto/", + false, + }, + &testCase{ + "Unsafe", + "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid", + FlagsUnsafeGreedy, + "http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3", + false, + }, + &testCase{ + "Safe2", + "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid", + FlagsSafe, + "https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid", + false, + }, + &testCase{ + "UsuallySafe2", + "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid", + FlagsUsuallySafeGreedy, + "https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid", + false, + }, + &testCase{ + "AddTrailingSlashBug", + "http://src.ca/", + FlagsAllNonGreedy, + "http://www.src.ca/", + false, + }, + &testCase{ + "SourceModified", + "HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid", + FlagsUnsafeGreedy, + "http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3", + true, + }, + &testCase{ + "IPv6-1", + "http://[2001:db8:1f70::999:de8:7648:6e8]/test", + FlagsSafe | FlagRemoveDotSegments, + "http://[2001:db8:1f70::999:de8:7648:6e8]/test", + false, + }, + &testCase{ + "IPv6-2", + "http://[::ffff:192.168.1.1]/test", + FlagsSafe | FlagRemoveDotSegments, + "http://[::ffff:192.168.1.1]/test", + false, + }, + &testCase{ + "IPv6-3", + "http://[::ffff:192.168.1.1]:80/test", + FlagsSafe | FlagRemoveDotSegments, + "http://[::ffff:192.168.1.1]/test", + false, + }, + &testCase{ + "IPv6-4", + "htTps://[::fFff:192.168.1.1]:443/test", + FlagsSafe | FlagRemoveDotSegments, + "https://[::ffff:192.168.1.1]/test", + false, + }, + &testCase{ + "FTP", + "ftp://user:pass@ftp.foo.net/foo/bar", + FlagsSafe | FlagRemoveDotSegments, + "ftp://user:pass@ftp.foo.net/foo/bar", + false, + }, + &testCase{ + "Standard-1", + "http://www.foo.com:80/foo", + FlagsSafe | FlagRemoveDotSegments, + "http://www.foo.com/foo", + false, + }, + &testCase{ + "Standard-2", + "http://www.foo.com:8000/foo", + FlagsSafe | FlagRemoveDotSegments, + "http://www.foo.com:8000/foo", + false, + }, + &testCase{ + "Standard-3", + "http://www.foo.com/%7ebar", + FlagsSafe | FlagRemoveDotSegments, + "http://www.foo.com/~bar", + false, + }, + &testCase{ + "Standard-4", + "http://www.foo.com/%7Ebar", + FlagsSafe | FlagRemoveDotSegments, + "http://www.foo.com/~bar", + false, + }, + &testCase{ + "Standard-5", + "http://USER:pass@www.Example.COM/foo/bar", + FlagsSafe | FlagRemoveDotSegments, + "http://USER:pass@www.example.com/foo/bar", + false, + }, + &testCase{ + "Standard-6", + "http://test.example/?a=%26&b=1", + FlagsSafe | FlagRemoveDotSegments, + "http://test.example/?a=%26&b=1", + false, + }, + &testCase{ + "Standard-7", + "http://test.example/%25/?p=%20val%20%25", + FlagsSafe | FlagRemoveDotSegments, + "http://test.example/%25/?p=%20val%20%25", + false, + }, + &testCase{ + "Standard-8", + "http://test.example/path/with a%20space+/", + FlagsSafe | FlagRemoveDotSegments, + "http://test.example/path/with%20a%20space+/", + false, + }, + &testCase{ + "Standard-9", + "http://test.example/?", + FlagsSafe | FlagRemoveDotSegments, + "http://test.example/", + false, + }, + &testCase{ + "Standard-10", + "http://a.COM/path/?b&a", + FlagsSafe | FlagRemoveDotSegments, + "http://a.com/path/?b&a", + false, + }, + &testCase{ + "StandardCasesAddTrailingSlash", + "http://test.example?", + FlagsSafe | FlagAddTrailingSlash, + "http://test.example/", + false, + }, + &testCase{ + "OctalIP-1", + "http://0123.011.0.4/", + FlagsSafe | FlagDecodeOctalHost, + "http://0123.011.0.4/", + false, + }, + &testCase{ + "OctalIP-2", + "http://0102.0146.07.0223/", + FlagsSafe | FlagDecodeOctalHost, + "http://66.102.7.147/", + false, + }, + &testCase{ + "OctalIP-3", + "http://0102.0146.07.0223.:23/", + FlagsSafe | FlagDecodeOctalHost, + "http://66.102.7.147.:23/", + false, + }, + &testCase{ + "OctalIP-4", + "http://USER:pass@0102.0146.07.0223../", + FlagsSafe | FlagDecodeOctalHost, + "http://USER:pass@66.102.7.147../", + false, + }, + &testCase{ + "DWORDIP-1", + "http://123.1113982867/", + FlagsSafe | FlagDecodeDWORDHost, + "http://123.1113982867/", + false, + }, + &testCase{ + "DWORDIP-2", + "http://1113982867/", + FlagsSafe | FlagDecodeDWORDHost, + "http://66.102.7.147/", + false, + }, + &testCase{ + "DWORDIP-3", + "http://1113982867.:23/", + FlagsSafe | FlagDecodeDWORDHost, + "http://66.102.7.147.:23/", + false, + }, + &testCase{ + "DWORDIP-4", + "http://USER:pass@1113982867../", + FlagsSafe | FlagDecodeDWORDHost, + "http://USER:pass@66.102.7.147../", + false, + }, + &testCase{ + "HexIP-1", + "http://0x123.1113982867/", + FlagsSafe | FlagDecodeHexHost, + "http://0x123.1113982867/", + false, + }, + &testCase{ + "HexIP-2", + "http://0x42660793/", + FlagsSafe | FlagDecodeHexHost, + "http://66.102.7.147/", + false, + }, + &testCase{ + "HexIP-3", + "http://0x42660793.:23/", + FlagsSafe | FlagDecodeHexHost, + "http://66.102.7.147.:23/", + false, + }, + &testCase{ + "HexIP-4", + "http://USER:pass@0x42660793../", + FlagsSafe | FlagDecodeHexHost, + "http://USER:pass@66.102.7.147../", + false, + }, + &testCase{ + "UnnecessaryHostDots-1", + "http://.www.foo.com../foo/bar.html", + FlagsSafe | FlagRemoveUnnecessaryHostDots, + "http://www.foo.com/foo/bar.html", + false, + }, + &testCase{ + "UnnecessaryHostDots-2", + "http://www.foo.com./foo/bar.html", + FlagsSafe | FlagRemoveUnnecessaryHostDots, + "http://www.foo.com/foo/bar.html", + false, + }, + &testCase{ + "UnnecessaryHostDots-3", + "http://www.foo.com.:81/foo", + FlagsSafe | FlagRemoveUnnecessaryHostDots, + "http://www.foo.com:81/foo", + false, + }, + &testCase{ + "UnnecessaryHostDots-4", + "http://www.example.com./", + FlagsSafe | FlagRemoveUnnecessaryHostDots, + "http://www.example.com/", + false, + }, + &testCase{ + "EmptyPort-1", + "http://www.thedraymin.co.uk:/main/?p=308", + FlagsSafe | FlagRemoveEmptyPortSeparator, + "http://www.thedraymin.co.uk/main/?p=308", + false, + }, + &testCase{ + "EmptyPort-2", + "http://www.src.ca:", + FlagsSafe | FlagRemoveEmptyPortSeparator, + "http://www.src.ca", + false, + }, + &testCase{ + "Slashes-1", + "http://test.example/foo/bar/.", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/bar/", + false, + }, + &testCase{ + "Slashes-2", + "http://test.example/foo/bar/./", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/bar/", + false, + }, + &testCase{ + "Slashes-3", + "http://test.example/foo/bar/..", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/", + false, + }, + &testCase{ + "Slashes-4", + "http://test.example/foo/bar/../", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/", + false, + }, + &testCase{ + "Slashes-5", + "http://test.example/foo/bar/../baz", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/baz", + false, + }, + &testCase{ + "Slashes-6", + "http://test.example/foo/bar/../..", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/", + false, + }, + &testCase{ + "Slashes-7", + "http://test.example/foo/bar/../../", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/", + false, + }, + &testCase{ + "Slashes-8", + "http://test.example/foo/bar/../../baz", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/baz", + false, + }, + &testCase{ + "Slashes-9", + "http://test.example/foo/bar/../../../baz", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/baz", + false, + }, + &testCase{ + "Slashes-10", + "http://test.example/foo/bar/../../../../baz", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/baz", + false, + }, + &testCase{ + "Slashes-11", + "http://test.example/./foo", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo", + false, + }, + &testCase{ + "Slashes-12", + "http://test.example/../foo", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo", + false, + }, + &testCase{ + "Slashes-13", + "http://test.example/foo.", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo.", + false, + }, + &testCase{ + "Slashes-14", + "http://test.example/.foo", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/.foo", + false, + }, + &testCase{ + "Slashes-15", + "http://test.example/foo..", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo..", + false, + }, + &testCase{ + "Slashes-16", + "http://test.example/..foo", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/..foo", + false, + }, + &testCase{ + "Slashes-17", + "http://test.example/./../foo", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo", + false, + }, + &testCase{ + "Slashes-18", + "http://test.example/./foo/.", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/", + false, + }, + &testCase{ + "Slashes-19", + "http://test.example/foo/./bar", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/bar", + false, + }, + &testCase{ + "Slashes-20", + "http://test.example/foo/../bar", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/bar", + false, + }, + &testCase{ + "Slashes-21", + "http://test.example/foo//", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/", + false, + }, + &testCase{ + "Slashes-22", + "http://test.example/foo///bar//", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "http://test.example/foo/bar/", + false, + }, + &testCase{ + "Relative", + "foo/bar", + FlagsAllGreedy, + "foo/bar", + false, + }, + &testCase{ + "Relative-1", + "./../foo", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "foo", + false, + }, + &testCase{ + "Relative-2", + "./foo/bar/../baz/../bang/..", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "foo/", + false, + }, + &testCase{ + "Relative-3", + "foo///bar//", + FlagsSafe | FlagRemoveDotSegments | FlagRemoveDuplicateSlashes, + "foo/bar/", + false, + }, + &testCase{ + "Relative-4", + "www.youtube.com", + FlagsUsuallySafeGreedy, + "www.youtube.com", + false, + }, + /*&testCase{ + "UrlNorm-5", + "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3", + FlagsSafe | FlagRemoveDotSegments, + "http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3", + false, + }, + &testCase{ + "UrlNorm-1", + "http://test.example/?a=%e3%82%82%26", + FlagsAllGreedy, + "http://test.example/?a=\xe3\x82\x82%26", + false, + },*/ + } +) + +func TestRunner(t *testing.T) { + for _, tc := range cases { + runCase(tc, t) + } +} + +func runCase(tc *testCase, t *testing.T) { + t.Logf("running %s...", tc.nm) + if tc.parsed { + u, e := url.Parse(tc.src) + if e != nil { + t.Errorf("%s - FAIL : %s", tc.nm, e) + return + } else { + NormalizeURL(u, tc.flgs) + if s := u.String(); s != tc.res { + t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s) + } + } + } else { + if s, e := NormalizeURLString(tc.src, tc.flgs); e != nil { + t.Errorf("%s - FAIL : %s", tc.nm, e) + } else if s != tc.res { + t.Errorf("%s - FAIL expected '%s', got '%s'", tc.nm, tc.res, s) + } + } +} + +func TestDecodeUnnecessaryEscapesAll(t *testing.T) { + var url = "http://host/" + + for i := 0; i < 256; i++ { + url += fmt.Sprintf("%%%02x", i) + } + if s, e := NormalizeURLString(url, FlagDecodeUnnecessaryEscapes); e != nil { + t.Fatalf("Got error %s", e.Error()) + } else { + const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22%23$%25&'()*+,-./0123456789:;%3C=%3E%3F@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" + if s != want { + t.Errorf("DecodeUnnecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s) + } + } +} + +func TestEncodeNecessaryEscapesAll(t *testing.T) { + var url = "http://host/" + + for i := 0; i < 256; i++ { + if i != 0x25 { + url += string(i) + } + } + if s, e := NormalizeURLString(url, FlagEncodeNecessaryEscapes); e != nil { + t.Fatalf("Got error %s", e.Error()) + } else { + const want = "http://host/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22#$&'()*+,-./0123456789:;%3C=%3E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%C2%80%C2%81%C2%82%C2%83%C2%84%C2%85%C2%86%C2%87%C2%88%C2%89%C2%8A%C2%8B%C2%8C%C2%8D%C2%8E%C2%8F%C2%90%C2%91%C2%92%C2%93%C2%94%C2%95%C2%96%C2%97%C2%98%C2%99%C2%9A%C2%9B%C2%9C%C2%9D%C2%9E%C2%9F%C2%A0%C2%A1%C2%A2%C2%A3%C2%A4%C2%A5%C2%A6%C2%A7%C2%A8%C2%A9%C2%AA%C2%AB%C2%AC%C2%AD%C2%AE%C2%AF%C2%B0%C2%B1%C2%B2%C2%B3%C2%B4%C2%B5%C2%B6%C2%B7%C2%B8%C2%B9%C2%BA%C2%BB%C2%BC%C2%BD%C2%BE%C2%BF%C3%80%C3%81%C3%82%C3%83%C3%84%C3%85%C3%86%C3%87%C3%88%C3%89%C3%8A%C3%8B%C3%8C%C3%8D%C3%8E%C3%8F%C3%90%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%9B%C3%9C%C3%9D%C3%9E%C3%9F%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%A8%C3%A9%C3%AA%C3%AB%C3%AC%C3%AD%C3%AE%C3%AF%C3%B0%C3%B1%C3%B2%C3%B3%C3%B4%C3%B5%C3%B6%C3%B7%C3%B8%C3%B9%C3%BA%C3%BB%C3%BC%C3%BD%C3%BE%C3%BF" + if s != want { + t.Errorf("EncodeNecessaryEscapesAll:\nwant\n%s\ngot\n%s", want, s) + } + } +} diff --git a/vendor/github.com/PuerkitoBio/purell/urlnorm_test.go b/vendor/github.com/PuerkitoBio/purell/urlnorm_test.go new file mode 100644 index 000000000..d1b2ca6c0 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/purell/urlnorm_test.go @@ -0,0 +1,53 @@ +package purell + +import ( + "testing" +) + +// Test cases merged from PR #1 +// Originally from https://github.com/jehiah/urlnorm/blob/master/test_urlnorm.py + +func assertMap(t *testing.T, cases map[string]string, f NormalizationFlags) { + for bad, good := range cases { + s, e := NormalizeURLString(bad, f) + if e != nil { + t.Errorf("%s normalizing %v to %v", e.Error(), bad, good) + } else { + if s != good { + t.Errorf("source: %v expected: %v got: %v", bad, good, s) + } + } + } +} + +// This tests normalization to a unicode representation +// precent escapes for unreserved values are unescaped to their unicode value +// tests normalization to idna domains +// test ip word handling, ipv6 address handling, and trailing domain periods +// in general, this matches google chromes unescaping for things in the address bar. +// spaces are converted to '+' (perhaphs controversial) +// http://code.google.com/p/google-url/ probably is another good reference for this approach +func TestUrlnorm(t *testing.T) { + testcases := map[string]string{ + "http://test.example/?a=%e3%82%82%26": "http://test.example/?a=%e3%82%82%26", + //"http://test.example/?a=%e3%82%82%26": "http://test.example/?a=\xe3\x82\x82%26", //should return a unicode character + "http://s.xn--q-bga.DE/": "http://s.xn--q-bga.de/", //should be in idna format + "http://XBLA\u306eXbox.com": "http://xn--xblaxbox-jf4g.com", //test utf8 and unicode + "http://президент.рф": "http://xn--d1abbgf6aiiy.xn--p1ai", + "http://ПРЕЗИДЕНТ.РФ": "http://xn--d1abbgf6aiiy.xn--p1ai", + "http://ab¥ヲ₩○.com": "http://xn--ab-ida8983azmfnvs.com", //test width folding + "http://\u00e9.com": "http://xn--9ca.com", + "http://e\u0301.com": "http://xn--9ca.com", + "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3": "http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3", + //"http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%82%BF%E3%83%94%E3%83%A9%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%91%E3%83%B3": "http://ja.wikipedia.org/wiki/\xe3\x82\xad\xe3\x83\xa3\xe3\x82\xbf\xe3\x83\x94\xe3\x83\xa9\xe3\x83\xbc\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\x91\xe3\x83\xb3", + + "http://test.example/\xe3\x82\xad": "http://test.example/%E3%82%AD", + //"http://test.example/\xe3\x82\xad": "http://test.example/\xe3\x82\xad", + "http://test.example/?p=%23val#test-%23-val%25": "http://test.example/?p=%23val#test-%23-val%25", //check that %23 (#) is not escaped where it shouldn't be + + "http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n": "http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n", + //"http://test.domain/I%C3%B1t%C3%ABrn%C3%A2ti%C3%B4n%EF%BF%BDliz%C3%A6ti%C3%B8n": "http://test.domain/I\xc3\xb1t\xc3\xabrn\xc3\xa2ti\xc3\xb4n\xef\xbf\xbdliz\xc3\xa6ti\xc3\xb8n", + } + + assertMap(t, testcases, FlagsSafe|FlagRemoveDotSegments) +} diff --git a/vendor/github.com/PuerkitoBio/urlesc/.travis.yml b/vendor/github.com/PuerkitoBio/urlesc/.travis.yml new file mode 100644 index 000000000..ba6b225f9 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/.travis.yml @@ -0,0 +1,15 @@ +language: go + +go: + - 1.4.x + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x + - tip + +install: + - go build . + +script: + - go test -v diff --git a/vendor/github.com/PuerkitoBio/urlesc/README.md b/vendor/github.com/PuerkitoBio/urlesc/README.md new file mode 100644 index 000000000..57aff0a53 --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/README.md @@ -0,0 +1,16 @@ +urlesc [![Build Status](https://travis-ci.org/PuerkitoBio/urlesc.svg?branch=master)](https://travis-ci.org/PuerkitoBio/urlesc) [![GoDoc](http://godoc.org/github.com/PuerkitoBio/urlesc?status.svg)](http://godoc.org/github.com/PuerkitoBio/urlesc) +====== + +Package urlesc implements query escaping as per RFC 3986. + +It contains some parts of the net/url package, modified so as to allow +some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)). + +## Install + + go get github.com/PuerkitoBio/urlesc + +## License + +Go license (BSD-3-Clause) + diff --git a/vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go b/vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go new file mode 100644 index 000000000..45202e1dd --- /dev/null +++ b/vendor/github.com/PuerkitoBio/urlesc/urlesc_test.go @@ -0,0 +1,641 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package urlesc + +import ( + "net/url" + "testing" +) + +type URLTest struct { + in string + out *url.URL + roundtrip string // expected result of reserializing the URL; empty means same as "in". +} + +var urltests = []URLTest{ + // no path + { + "http://www.google.com", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + }, + "", + }, + // path + { + "http://www.google.com/", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/", + }, + "", + }, + // path with hex escaping + { + "http://www.google.com/file%20one%26two", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/file one&two", + }, + "http://www.google.com/file%20one&two", + }, + // user + { + "ftp://webmaster@www.google.com/", + &url.URL{ + Scheme: "ftp", + User: url.User("webmaster"), + Host: "www.google.com", + Path: "/", + }, + "", + }, + // escape sequence in username + { + "ftp://john%20doe@www.google.com/", + &url.URL{ + Scheme: "ftp", + User: url.User("john doe"), + Host: "www.google.com", + Path: "/", + }, + "ftp://john%20doe@www.google.com/", + }, + // query + { + "http://www.google.com/?q=go+language", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language", + }, + "", + }, + // query with hex escaping: NOT parsed + { + "http://www.google.com/?q=go%20language", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go%20language", + }, + "", + }, + // %20 outside query + { + "http://www.google.com/a%20b?q=c+d", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/a b", + RawQuery: "q=c+d", + }, + "", + }, + // path without leading /, so no parsing + { + "http:www.google.com/?q=go+language", + &url.URL{ + Scheme: "http", + Opaque: "www.google.com/", + RawQuery: "q=go+language", + }, + "http:www.google.com/?q=go+language", + }, + // path without leading /, so no parsing + { + "http:%2f%2fwww.google.com/?q=go+language", + &url.URL{ + Scheme: "http", + Opaque: "%2f%2fwww.google.com/", + RawQuery: "q=go+language", + }, + "http:%2f%2fwww.google.com/?q=go+language", + }, + // non-authority with path + { + "mailto:/webmaster@golang.org", + &url.URL{ + Scheme: "mailto", + Path: "/webmaster@golang.org", + }, + "mailto:///webmaster@golang.org", // unfortunate compromise + }, + // non-authority + { + "mailto:webmaster@golang.org", + &url.URL{ + Scheme: "mailto", + Opaque: "webmaster@golang.org", + }, + "", + }, + // unescaped :// in query should not create a scheme + { + "/foo?query=http://bad", + &url.URL{ + Path: "/foo", + RawQuery: "query=http://bad", + }, + "", + }, + // leading // without scheme should create an authority + { + "//foo", + &url.URL{ + Host: "foo", + }, + "", + }, + // leading // without scheme, with userinfo, path, and query + { + "//user@foo/path?a=b", + &url.URL{ + User: url.User("user"), + Host: "foo", + Path: "/path", + RawQuery: "a=b", + }, + "", + }, + // Three leading slashes isn't an authority, but doesn't return an error. + // (We can't return an error, as this code is also used via + // ServeHTTP -> ReadRequest -> Parse, which is arguably a + // different URL parsing context, but currently shares the + // same codepath) + { + "///threeslashes", + &url.URL{ + Path: "///threeslashes", + }, + "", + }, + { + "http://user:password@google.com", + &url.URL{ + Scheme: "http", + User: url.UserPassword("user", "password"), + Host: "google.com", + }, + "http://user:password@google.com", + }, + // unescaped @ in username should not confuse host + { + "http://j@ne:password@google.com", + &url.URL{ + Scheme: "http", + User: url.UserPassword("j@ne", "password"), + Host: "google.com", + }, + "http://j%40ne:password@google.com", + }, + // unescaped @ in password should not confuse host + { + "http://jane:p@ssword@google.com", + &url.URL{ + Scheme: "http", + User: url.UserPassword("jane", "p@ssword"), + Host: "google.com", + }, + "http://jane:p%40ssword@google.com", + }, + { + "http://j@ne:password@google.com/p@th?q=@go", + &url.URL{ + Scheme: "http", + User: url.UserPassword("j@ne", "password"), + Host: "google.com", + Path: "/p@th", + RawQuery: "q=@go", + }, + "http://j%40ne:password@google.com/p@th?q=@go", + }, + { + "http://www.google.com/?q=go+language#foo", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language", + Fragment: "foo", + }, + "", + }, + { + "http://www.google.com/?q=go+language#foo%26bar", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language", + Fragment: "foo&bar", + }, + "http://www.google.com/?q=go+language#foo&bar", + }, + { + "file:///home/adg/rabbits", + &url.URL{ + Scheme: "file", + Host: "", + Path: "/home/adg/rabbits", + }, + "file:///home/adg/rabbits", + }, + // "Windows" paths are no exception to the rule. + // See golang.org/issue/6027, especially comment #9. + { + "file:///C:/FooBar/Baz.txt", + &url.URL{ + Scheme: "file", + Host: "", + Path: "/C:/FooBar/Baz.txt", + }, + "file:///C:/FooBar/Baz.txt", + }, + // case-insensitive scheme + { + "MaIlTo:webmaster@golang.org", + &url.URL{ + Scheme: "mailto", + Opaque: "webmaster@golang.org", + }, + "mailto:webmaster@golang.org", + }, + // Relative path + { + "a/b/c", + &url.URL{ + Path: "a/b/c", + }, + "a/b/c", + }, + // escaped '?' in username and password + { + "http://%3Fam:pa%3Fsword@google.com", + &url.URL{ + Scheme: "http", + User: url.UserPassword("?am", "pa?sword"), + Host: "google.com", + }, + "", + }, + // escaped '?' and '#' in path + { + "http://example.com/%3F%23", + &url.URL{ + Scheme: "http", + Host: "example.com", + Path: "?#", + }, + "", + }, + // unescaped [ ] ! ' ( ) * in path + { + "http://example.com/[]!'()*", + &url.URL{ + Scheme: "http", + Host: "example.com", + Path: "[]!'()*", + }, + "http://example.com/[]!'()*", + }, + // escaped : / ? # [ ] @ in username and password + { + "http://%3A%2F%3F:%23%5B%5D%40@example.com", + &url.URL{ + Scheme: "http", + User: url.UserPassword(":/?", "#[]@"), + Host: "example.com", + }, + "", + }, + // unescaped ! $ & ' ( ) * + , ; = in username and password + { + "http://!$&'():*+,;=@example.com", + &url.URL{ + Scheme: "http", + User: url.UserPassword("!$&'()", "*+,;="), + Host: "example.com", + }, + "", + }, + // unescaped = : / . ? = in query component + { + "http://example.com/?q=http://google.com/?q=", + &url.URL{ + Scheme: "http", + Host: "example.com", + Path: "/", + RawQuery: "q=http://google.com/?q=", + }, + "", + }, + // unescaped : / ? [ ] @ ! $ & ' ( ) * + , ; = in fragment + { + "http://example.com/#:/?%23[]@!$&'()*+,;=", + &url.URL{ + Scheme: "http", + Host: "example.com", + Path: "/", + Fragment: ":/?#[]@!$&'()*+,;=", + }, + "", + }, +} + +func DoTestString(t *testing.T, parse func(string) (*url.URL, error), name string, tests []URLTest) { + for _, tt := range tests { + u, err := parse(tt.in) + if err != nil { + t.Errorf("%s(%q) returned error %s", name, tt.in, err) + continue + } + expected := tt.in + if len(tt.roundtrip) > 0 { + expected = tt.roundtrip + } + s := Escape(u) + if s != expected { + t.Errorf("Escape(%s(%q)) == %q (expected %q)", name, tt.in, s, expected) + } + } +} + +func TestURLString(t *testing.T) { + DoTestString(t, url.Parse, "Parse", urltests) + + // no leading slash on path should prepend + // slash on String() call + noslash := URLTest{ + "http://www.google.com/search", + &url.URL{ + Scheme: "http", + Host: "www.google.com", + Path: "search", + }, + "", + } + s := Escape(noslash.out) + if s != noslash.in { + t.Errorf("Expected %s; go %s", noslash.in, s) + } +} + +type EscapeTest struct { + in string + out string + err error +} + +var escapeTests = []EscapeTest{ + { + "", + "", + nil, + }, + { + "abc", + "abc", + nil, + }, + { + "one two", + "one+two", + nil, + }, + { + "10%", + "10%25", + nil, + }, + { + " ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;", + "+?%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A/%40%24%27%28%29%2A%2C%3B", + nil, + }, +} + +func TestEscape(t *testing.T) { + for _, tt := range escapeTests { + actual := QueryEscape(tt.in) + if tt.out != actual { + t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out) + } + + // for bonus points, verify that escape:unescape is an identity. + roundtrip, err := url.QueryUnescape(actual) + if roundtrip != tt.in || err != nil { + t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]") + } + } +} + +var resolveReferenceTests = []struct { + base, rel, expected string +}{ + // Absolute URL references + {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"}, + {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"}, + {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"}, + + // Path-absolute references + {"http://foo.com/bar", "/baz", "http://foo.com/baz"}, + {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"}, + {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"}, + + // Scheme-relative + {"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"}, + + // Path-relative references: + + // ... current directory + {"http://foo.com", ".", "http://foo.com/"}, + {"http://foo.com/bar", ".", "http://foo.com/"}, + {"http://foo.com/bar/", ".", "http://foo.com/bar/"}, + + // ... going down + {"http://foo.com", "bar", "http://foo.com/bar"}, + {"http://foo.com/", "bar", "http://foo.com/bar"}, + {"http://foo.com/bar/baz", "quux", "http://foo.com/bar/quux"}, + + // ... going up + {"http://foo.com/bar/baz", "../quux", "http://foo.com/quux"}, + {"http://foo.com/bar/baz", "../../../../../quux", "http://foo.com/quux"}, + {"http://foo.com/bar", "..", "http://foo.com/"}, + {"http://foo.com/bar/baz", "./..", "http://foo.com/"}, + // ".." in the middle (issue 3560) + {"http://foo.com/bar/baz", "quux/dotdot/../tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/../tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/.././tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/./../tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/dotdot/././../../tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/dotdot/./.././../tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/dotdot/dotdot/./../../.././././tail", "http://foo.com/bar/quux/tail"}, + {"http://foo.com/bar/baz", "quux/./dotdot/../dotdot/../dot/./tail/..", "http://foo.com/bar/quux/dot/"}, + + // Remove any dot-segments prior to forming the target URI. + // http://tools.ietf.org/html/rfc3986#section-5.2.4 + {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/baz"}, + + // Triple dot isn't special + {"http://foo.com/bar", "...", "http://foo.com/..."}, + + // Fragment + {"http://foo.com/bar", ".#frag", "http://foo.com/#frag"}, + + // RFC 3986: Normal Examples + // http://tools.ietf.org/html/rfc3986#section-5.4.1 + {"http://a/b/c/d;p?q", "g:h", "g:h"}, + {"http://a/b/c/d;p?q", "g", "http://a/b/c/g"}, + {"http://a/b/c/d;p?q", "./g", "http://a/b/c/g"}, + {"http://a/b/c/d;p?q", "g/", "http://a/b/c/g/"}, + {"http://a/b/c/d;p?q", "/g", "http://a/g"}, + {"http://a/b/c/d;p?q", "//g", "http://g"}, + {"http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y"}, + {"http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y"}, + {"http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s"}, + {"http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s"}, + {"http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s"}, + {"http://a/b/c/d;p?q", ";x", "http://a/b/c/;x"}, + {"http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x"}, + {"http://a/b/c/d;p?q", "g;x?y#s", "http://a/b/c/g;x?y#s"}, + {"http://a/b/c/d;p?q", "", "http://a/b/c/d;p?q"}, + {"http://a/b/c/d;p?q", ".", "http://a/b/c/"}, + {"http://a/b/c/d;p?q", "./", "http://a/b/c/"}, + {"http://a/b/c/d;p?q", "..", "http://a/b/"}, + {"http://a/b/c/d;p?q", "../", "http://a/b/"}, + {"http://a/b/c/d;p?q", "../g", "http://a/b/g"}, + {"http://a/b/c/d;p?q", "../..", "http://a/"}, + {"http://a/b/c/d;p?q", "../../", "http://a/"}, + {"http://a/b/c/d;p?q", "../../g", "http://a/g"}, + + // RFC 3986: Abnormal Examples + // http://tools.ietf.org/html/rfc3986#section-5.4.2 + {"http://a/b/c/d;p?q", "../../../g", "http://a/g"}, + {"http://a/b/c/d;p?q", "../../../../g", "http://a/g"}, + {"http://a/b/c/d;p?q", "/./g", "http://a/g"}, + {"http://a/b/c/d;p?q", "/../g", "http://a/g"}, + {"http://a/b/c/d;p?q", "g.", "http://a/b/c/g."}, + {"http://a/b/c/d;p?q", ".g", "http://a/b/c/.g"}, + {"http://a/b/c/d;p?q", "g..", "http://a/b/c/g.."}, + {"http://a/b/c/d;p?q", "..g", "http://a/b/c/..g"}, + {"http://a/b/c/d;p?q", "./../g", "http://a/b/g"}, + {"http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/"}, + {"http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h"}, + {"http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h"}, + {"http://a/b/c/d;p?q", "g;x=1/./y", "http://a/b/c/g;x=1/y"}, + {"http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y"}, + {"http://a/b/c/d;p?q", "g?y/./x", "http://a/b/c/g?y/./x"}, + {"http://a/b/c/d;p?q", "g?y/../x", "http://a/b/c/g?y/../x"}, + {"http://a/b/c/d;p?q", "g#s/./x", "http://a/b/c/g#s/./x"}, + {"http://a/b/c/d;p?q", "g#s/../x", "http://a/b/c/g#s/../x"}, + + // Extras. + {"https://a/b/c/d;p?q", "//g?q", "https://g?q"}, + {"https://a/b/c/d;p?q", "//g#s", "https://g#s"}, + {"https://a/b/c/d;p?q", "//g/d/e/f?y#s", "https://g/d/e/f?y#s"}, + {"https://a/b/c/d;p#s", "?y", "https://a/b/c/d;p?y"}, + {"https://a/b/c/d;p?q#s", "?y", "https://a/b/c/d;p?y"}, +} + +func TestResolveReference(t *testing.T) { + mustParse := func(url_ string) *url.URL { + u, err := url.Parse(url_) + if err != nil { + t.Fatalf("Expected URL to parse: %q, got error: %v", url_, err) + } + return u + } + opaque := &url.URL{Scheme: "scheme", Opaque: "opaque"} + for _, test := range resolveReferenceTests { + base := mustParse(test.base) + rel := mustParse(test.rel) + url := base.ResolveReference(rel) + if Escape(url) != test.expected { + t.Errorf("URL(%q).ResolveReference(%q) == %q, got %q", test.base, test.rel, test.expected, Escape(url)) + } + // Ensure that new instances are returned. + if base == url { + t.Errorf("Expected URL.ResolveReference to return new URL instance.") + } + // Test the convenience wrapper too. + url, err := base.Parse(test.rel) + if err != nil { + t.Errorf("URL(%q).Parse(%q) failed: %v", test.base, test.rel, err) + } else if Escape(url) != test.expected { + t.Errorf("URL(%q).Parse(%q) == %q, got %q", test.base, test.rel, test.expected, Escape(url)) + } else if base == url { + // Ensure that new instances are returned for the wrapper too. + t.Errorf("Expected URL.Parse to return new URL instance.") + } + // Ensure Opaque resets the URL. + url = base.ResolveReference(opaque) + if *url != *opaque { + t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", url, opaque) + } + // Test the convenience wrapper with an opaque URL too. + url, err = base.Parse("scheme:opaque") + if err != nil { + t.Errorf(`URL(%q).Parse("scheme:opaque") failed: %v`, test.base, err) + } else if *url != *opaque { + t.Errorf("Parse failed to resolve opaque URL: want %#v, got %#v", url, opaque) + } else if base == url { + // Ensure that new instances are returned, again. + t.Errorf("Expected URL.Parse to return new URL instance.") + } + } +} + +type shouldEscapeTest struct { + in byte + mode encoding + escape bool +} + +var shouldEscapeTests = []shouldEscapeTest{ + // Unreserved characters (§2.3) + {'a', encodePath, false}, + {'a', encodeUserPassword, false}, + {'a', encodeQueryComponent, false}, + {'a', encodeFragment, false}, + {'z', encodePath, false}, + {'A', encodePath, false}, + {'Z', encodePath, false}, + {'0', encodePath, false}, + {'9', encodePath, false}, + {'-', encodePath, false}, + {'-', encodeUserPassword, false}, + {'-', encodeQueryComponent, false}, + {'-', encodeFragment, false}, + {'.', encodePath, false}, + {'_', encodePath, false}, + {'~', encodePath, false}, + + // User information (§3.2.1) + {':', encodeUserPassword, true}, + {'/', encodeUserPassword, true}, + {'?', encodeUserPassword, true}, + {'@', encodeUserPassword, true}, + {'$', encodeUserPassword, false}, + {'&', encodeUserPassword, false}, + {'+', encodeUserPassword, false}, + {',', encodeUserPassword, false}, + {';', encodeUserPassword, false}, + {'=', encodeUserPassword, false}, +} + +func TestShouldEscape(t *testing.T) { + for _, tt := range shouldEscapeTests { + if shouldEscape(tt.in, tt.mode) != tt.escape { + t.Errorf("shouldEscape(%q, %v) returned %v; expected %v", tt.in, tt.mode, !tt.escape, tt.escape) + } + } +} diff --git a/vendor/github.com/Sirupsen/logrus/.gitignore b/vendor/github.com/Sirupsen/logrus/.gitignore new file mode 100644 index 000000000..6b7d7d1e8 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/.gitignore @@ -0,0 +1,2 @@ +logrus +vendor diff --git a/vendor/github.com/Sirupsen/logrus/.travis.yml b/vendor/github.com/Sirupsen/logrus/.travis.yml new file mode 100644 index 000000000..1f953bebd --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/.travis.yml @@ -0,0 +1,51 @@ +language: go +env: + - GOMAXPROCS=4 GORACE=halt_on_error=1 +matrix: + include: + - go: 1.10.x + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v ./... + - go: 1.11.x + env: GO111MODULE=on + install: + - go mod download + script: + - go test -race -v ./... + - go: 1.11.x + env: GO111MODULE=off + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v ./... + - go: 1.10.x + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v -tags appengine ./... + - go: 1.11.x + env: GO111MODULE=on + install: + - go mod download + script: + - go test -race -v -tags appengine ./... + - go: 1.11.x + env: GO111MODULE=off + install: + - go get github.com/stretchr/testify/assert + - go get golang.org/x/crypto/ssh/terminal + - go get golang.org/x/sys/unix + - go get golang.org/x/sys/windows + script: + - go test -race -v -tags appengine ./... diff --git a/vendor/github.com/Sirupsen/logrus/CHANGELOG.md b/vendor/github.com/Sirupsen/logrus/CHANGELOG.md new file mode 100644 index 000000000..cb85d9f9f --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/CHANGELOG.md @@ -0,0 +1,165 @@ +# 1.2.0 +This new release introduces: + * A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued + * A new trace level named `Trace` whose level is below `Debug` + * A configurable exit function to be called upon a Fatal trace + * The `Level` object now implements `encoding.TextUnmarshaler` interface + +# 1.1.1 +This is a bug fix release. + * fix the build break on Solaris + * don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized + +# 1.1.0 +This new release introduces: + * several fixes: + * a fix for a race condition on entry formatting + * proper cleanup of previously used entries before putting them back in the pool + * the extra new line at the end of message in text formatter has been removed + * a new global public API to check if a level is activated: IsLevelEnabled + * the following methods have been added to the Logger object + * IsLevelEnabled + * SetFormatter + * SetOutput + * ReplaceHooks + * introduction of go module + * an indent configuration for the json formatter + * output colour support for windows + * the field sort function is now configurable for text formatter + * the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater + +# 1.0.6 + +This new release introduces: + * a new api WithTime which allows to easily force the time of the log entry + which is mostly useful for logger wrapper + * a fix reverting the immutability of the entry given as parameter to the hooks + a new configuration field of the json formatter in order to put all the fields + in a nested dictionnary + * a new SetOutput method in the Logger + * a new configuration of the textformatter to configure the name of the default keys + * a new configuration of the text formatter to disable the level truncation + +# 1.0.5 + +* Fix hooks race (#707) +* Fix panic deadlock (#695) + +# 1.0.4 + +* Fix race when adding hooks (#612) +* Fix terminal check in AppEngine (#635) + +# 1.0.3 + +* Replace example files with testable examples + +# 1.0.2 + +* bug: quote non-string values in text formatter (#583) +* Make (*Logger) SetLevel a public method + +# 1.0.1 + +* bug: fix escaping in text formatter (#575) + +# 1.0.0 + +* Officially changed name to lower-case +* bug: colors on Windows 10 (#541) +* bug: fix race in accessing level (#512) + +# 0.11.5 + +* feature: add writer and writerlevel to entry (#372) + +# 0.11.4 + +* bug: fix undefined variable on solaris (#493) + +# 0.11.3 + +* formatter: configure quoting of empty values (#484) +* formatter: configure quoting character (default is `"`) (#484) +* bug: fix not importing io correctly in non-linux environments (#481) + +# 0.11.2 + +* bug: fix windows terminal detection (#476) + +# 0.11.1 + +* bug: fix tty detection with custom out (#471) + +# 0.11.0 + +* performance: Use bufferpool to allocate (#370) +* terminal: terminal detection for app-engine (#343) +* feature: exit handler (#375) + +# 0.10.0 + +* feature: Add a test hook (#180) +* feature: `ParseLevel` is now case-insensitive (#326) +* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) +* performance: avoid re-allocations on `WithFields` (#335) + +# 0.9.0 + +* logrus/text_formatter: don't emit empty msg +* logrus/hooks/airbrake: move out of main repository +* logrus/hooks/sentry: move out of main repository +* logrus/hooks/papertrail: move out of main repository +* logrus/hooks/bugsnag: move out of main repository +* logrus/core: run tests with `-race` +* logrus/core: detect TTY based on `stderr` +* logrus/core: support `WithError` on logger +* logrus/core: Solaris support + +# 0.8.7 + +* logrus/core: fix possible race (#216) +* logrus/doc: small typo fixes and doc improvements + + +# 0.8.6 + +* hooks/raven: allow passing an initialized client + +# 0.8.5 + +* logrus/core: revert #208 + +# 0.8.4 + +* formatter/text: fix data race (#218) + +# 0.8.3 + +* logrus/core: fix entry log level (#208) +* logrus/core: improve performance of text formatter by 40% +* logrus/core: expose `LevelHooks` type +* logrus/core: add support for DragonflyBSD and NetBSD +* formatter/text: print structs more verbosely + +# 0.8.2 + +* logrus: fix more Fatal family functions + +# 0.8.1 + +* logrus: fix not exiting on `Fatalf` and `Fatalln` + +# 0.8.0 + +* logrus: defaults to stderr instead of stdout +* hooks/sentry: add special field for `*http.Request` +* formatter/text: ignore Windows for colors + +# 0.7.3 + +* formatter/\*: allow configuration of timestamp layout + +# 0.7.2 + +* formatter/text: Add configuration option for time format (#158) diff --git a/vendor/github.com/Sirupsen/logrus/README.md b/vendor/github.com/Sirupsen/logrus/README.md new file mode 100644 index 000000000..093bb13f8 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/README.md @@ -0,0 +1,493 @@ +# Logrus :walrus: [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) + +Logrus is a structured logger for Go (golang), completely API compatible with +the standard library logger. + +**Seeing weird case-sensitive problems?** It's in the past been possible to +import Logrus as both upper- and lower-case. Due to the Go package environment, +this caused issues in the community and we needed a standard. Some environments +experienced problems with the upper-case variant, so the lower-case was decided. +Everything using `logrus` will need to use the lower-case: +`github.com/sirupsen/logrus`. Any package that isn't, should be changed. + +To fix Glide, see [these +comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). +For an in-depth explanation of the casing issue, see [this +comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). + +**Are you interested in assisting in maintaining Logrus?** Currently I have a +lot of obligations, and I am unable to provide Logrus with the maintainership it +needs. If you'd like to help, please reach out to me at `simon at author's +username dot com`. + +Nicely color-coded in development (when a TTY is attached, otherwise just +plain text): + +![Colored](http://i.imgur.com/PY7qMwd.png) + +With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +or Splunk: + +```json +{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the +ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} + +{"level":"warning","msg":"The group's number increased tremendously!", +"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"A giant walrus appears!", +"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} + +{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", +"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} + +{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, +"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} +``` + +With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +attached, the output is compatible with the +[logfmt](http://godoc.org/github.com/kr/logfmt) format: + +```text +time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 +time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 +time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true +time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 +time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 +time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true +``` +To ensure this behaviour even if a TTY is attached, set your formatter as follows: + +```go + log.SetFormatter(&log.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) +``` + +#### Logging Method Name + +If you wish to add the calling method as a field, instruct the logger via: +```go +log.SetReportCaller(true) +``` +This adds the caller as 'method' like so: + +```json +{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by", +"time":"2014-03-10 19:57:38.562543129 -0400 EDT"} +``` + +```text +time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin +``` +Note that this does add measurable overhead - the cost will depend on the version of Go, but is +between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your +environment via benchmarks: +``` +go test -bench=.*CallerTracing +``` + + +#### Case-sensitivity + +The organization's name was changed to lower-case--and this will not be changed +back. If you are getting import conflicts due to case sensitivity, please use +the lower-case import: `github.com/sirupsen/logrus`. + +#### Example + +The simplest way to use Logrus is simply the package-level exported logger: + +```go +package main + +import ( + log "github.com/sirupsen/logrus" +) + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + }).Info("A walrus appears") +} +``` + +Note that it's completely api-compatible with the stdlib logger, so you can +replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` +and you'll now have the flexibility of Logrus. You can customize it all you +want: + +```go +package main + +import ( + "os" + log "github.com/sirupsen/logrus" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.SetFormatter(&log.JSONFormatter{}) + + // Output to stdout instead of the default stderr + // Can be any io.Writer, see below for File example + log.SetOutput(os.Stdout) + + // Only log the warning severity or above. + log.SetLevel(log.WarnLevel) +} + +func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(log.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(log.Fields{ + "omg": true, + "number": 100, + }).Fatal("The ice breaks!") + + // A common pattern is to re-use fields between logging statements by re-using + // the logrus.Entry returned from WithFields() + contextLogger := log.WithFields(log.Fields{ + "common": "this is a common field", + "other": "I also should be logged always", + }) + + contextLogger.Info("I'll be logged with common and other field") + contextLogger.Info("Me too") +} +``` + +For more advanced usage such as logging to multiple locations from the same +application, you can also create an instance of the `logrus` Logger: + +```go +package main + +import ( + "os" + "github.com/sirupsen/logrus" +) + +// Create a new instance of the logger. You can have any number of instances. +var log = logrus.New() + +func main() { + // The API for setting attributes is a little different than the package level + // exported logger. See Godoc. + log.Out = os.Stdout + + // You could set this to any `io.Writer` such as a file + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") +} +``` + +#### Fields + +Logrus encourages careful, structured logging through logging fields instead of +long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +to send event %s to topic %s with key %d")`, you should log the much more +discoverable: + +```go +log.WithFields(log.Fields{ + "event": event, + "topic": topic, + "key": key, +}).Fatal("Failed to send event") +``` + +We've found this API forces you to think about logging in a way that produces +much more useful logging messages. We've been in countless situations where just +a single added field to a log statement that was already there would've saved us +hours. The `WithFields` call is optional. + +In general, with Logrus using any of the `printf`-family functions should be +seen as a hint you should add a field, however, you can still use the +`printf`-family functions with Logrus. + +#### Default Fields + +Often it's helpful to have fields _always_ attached to log statements in an +application or parts of one. For example, you may want to always log the +`request_id` and `user_ip` in the context of a request. Instead of writing +`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +every line, you can create a `logrus.Entry` to pass around instead: + +```go +requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger.Warn("something not great happened") +``` + +#### Hooks + +You can add hooks for logging levels. For example to send errors to an exception +tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to +multiple places simultaneously, e.g. syslog. + +Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in +`init`: + +```go +import ( + log "github.com/sirupsen/logrus" + "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" + "log/syslog" +) + +func init() { + + // Use the Airbrake hook to report errors that have Error severity or above to + // an exception tracker. You can create custom hooks, see the Hooks section. + log.AddHook(airbrake.NewHook(123, "xyz", "production")) + + hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") + if err != nil { + log.Error("Unable to connect to local syslog daemon") + } else { + log.AddHook(hook) + } +} +``` +Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). + +A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) + + +#### Level logging + +Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. + +```go +log.Trace("Something very low level.") +log.Debug("Useful debugging information.") +log.Info("Something noteworthy happened!") +log.Warn("You should probably take a look at this.") +log.Error("Something failed but I'm not quitting.") +// Calls os.Exit(1) after logging +log.Fatal("Bye.") +// Calls panic() after logging +log.Panic("I'm bailing.") +``` + +You can set the logging level on a `Logger`, then it will only log entries with +that severity or anything above it: + +```go +// Will log anything that is info or above (warn, error, fatal, panic). Default. +log.SetLevel(log.InfoLevel) +``` + +It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +environment if your application has that. + +#### Entries + +Besides the fields added with `WithField` or `WithFields` some fields are +automatically added to all logging events: + +1. `time`. The timestamp when the entry was created. +2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after + the `AddFields` call. E.g. `Failed to send event.` +3. `level`. The logging level. E.g. `info`. + +#### Environments + +Logrus has no notion of environment. + +If you wish for hooks and formatters to only be used in specific environments, +you should handle that yourself. For example, if your application has a global +variable `Environment`, which is a string representation of the environment you +could do: + +```go +import ( + log "github.com/sirupsen/logrus" +) + +init() { + // do something here to set environment depending on an environment variable + // or command-line flag + if Environment == "production" { + log.SetFormatter(&log.JSONFormatter{}) + } else { + // The TextFormatter is default, you don't actually have to do this. + log.SetFormatter(&log.TextFormatter{}) + } +} +``` + +This configuration is how `logrus` was intended to be used, but JSON in +production is mostly only useful if you do log aggregation with tools like +Splunk or Logstash. + +#### Formatters + +The built-in logging formatters are: + +* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise + without colors. + * *Note:* to force colored output when there is no TTY, set the `ForceColors` + field to `true`. To force no colored output even if there is a TTY set the + `DisableColors` field to `true`. For Windows, see + [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). + * When colors are enabled, levels are truncated to 4 characters by default. To disable + truncation set the `DisableLevelTruncation` field to `true`. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). +* `logrus.JSONFormatter`. Logs fields as JSON. + * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + +Third party logging formatters: + +* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. +* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. +* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. +* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. + +You can define your formatter by implementing the `Formatter` interface, +requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a +`Fields` type (`map[string]interface{}`) with all your fields as well as the +default ones (see Entries section above): + +```go +type MyJSONFormatter struct { +} + +log.SetFormatter(new(MyJSONFormatter)) + +func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { + // Note this doesn't include Time, Level and Message which are available on + // the Entry. Consult `godoc` on information about those fields or read the + // source of the official loggers. + serialized, err := json.Marshal(entry.Data) + if err != nil { + return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) + } + return append(serialized, '\n'), nil +} +``` + +#### Logger as an `io.Writer` + +Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. + +```go +w := logger.Writer() +defer w.Close() + +srv := http.Server{ + // create a stdlib log.Logger that writes to + // logrus.Logger. + ErrorLog: log.New(w, "", 0), +} +``` + +Each line written to that writer will be printed the usual way, using formatters +and hooks. The level for those entries is `info`. + +This means that we can override the standard library logger easily: + +```go +logger := logrus.New() +logger.Formatter = &logrus.JSONFormatter{} + +// Use logrus for standard log output +// Note that `log` here references stdlib's log +// Not logrus imported under the name `log`. +log.SetOutput(logger.Writer()) +``` + +#### Rotation + +Log rotation is not provided with Logrus. Log rotation should be done by an +external program (like `logrotate(8)`) that can compress and delete old log +entries. It should not be a feature of the application-level logger. + +#### Tools + +| Tool | Description | +| ---- | ----------- | +|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| +|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | + +#### Testing + +Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: + +* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook +* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): + +```go +import( + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSomething(t*testing.T){ + logger, hook := test.NewNullLogger() + logger.Error("Helloerror") + + assert.Equal(t, 1, len(hook.Entries)) + assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) + assert.Equal(t, "Helloerror", hook.LastEntry().Message) + + hook.Reset() + assert.Nil(t, hook.LastEntry()) +} +``` + +#### Fatal handlers + +Logrus can register one or more functions that will be called when any `fatal` +level message is logged. The registered handlers will be executed before +logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need +to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. + +``` +... +handler := func() { + // gracefully shutdown something... +} +logrus.RegisterExitHandler(handler) +... +``` + +#### Thread safety + +By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. +If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. + +Situation when locking is not needed includes: + +* You have no hooks registered, or hooks calling is already thread-safe. + +* Writing to logger.Out is already thread-safe, for example: + + 1) logger.Out is protected by locks. + + 2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) + + (Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) diff --git a/vendor/github.com/Sirupsen/logrus/alt_exit_test.go b/vendor/github.com/Sirupsen/logrus/alt_exit_test.go new file mode 100644 index 000000000..0a2ff5650 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/alt_exit_test.go @@ -0,0 +1,99 @@ +package logrus + +import ( + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "time" +) + +func TestRegister(t *testing.T) { + current := len(handlers) + RegisterExitHandler(func() {}) + if len(handlers) != current+1 { + t.Fatalf("expected %d handlers, got %d", current+1, len(handlers)) + } +} + +func TestHandler(t *testing.T) { + testprog := testprogleader + testprog = append(testprog, getPackage()...) + testprog = append(testprog, testprogtrailer...) + tempDir, err := ioutil.TempDir("", "test_handler") + if err != nil { + log.Fatalf("can't create temp dir. %q", err) + } + defer os.RemoveAll(tempDir) + + gofile := filepath.Join(tempDir, "gofile.go") + if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil { + t.Fatalf("can't create go file. %q", err) + } + + outfile := filepath.Join(tempDir, "outfile.out") + arg := time.Now().UTC().String() + err = exec.Command("go", "run", gofile, outfile, arg).Run() + if err == nil { + t.Fatalf("completed normally, should have failed") + } + + data, err := ioutil.ReadFile(outfile) + if err != nil { + t.Fatalf("can't read output file %s. %q", outfile, err) + } + + if string(data) != arg { + t.Fatalf("bad data. Expected %q, got %q", data, arg) + } +} + +// getPackage returns the name of the current package, which makes running this +// test in a fork simpler +func getPackage() []byte { + pc, _, _, _ := runtime.Caller(0) + fullFuncName := runtime.FuncForPC(pc).Name() + idx := strings.LastIndex(fullFuncName, ".") + return []byte(fullFuncName[:idx]) // trim off function details +} + +var testprogleader = []byte(` +// Test program for atexit, gets output file and data as arguments and writes +// data to output file in atexit handler. +package main + +import ( + "`) +var testprogtrailer = []byte( + `" + "flag" + "fmt" + "io/ioutil" +) + +var outfile = "" +var data = "" + +func handler() { + ioutil.WriteFile(outfile, []byte(data), 0666) +} + +func badHandler() { + n := 0 + fmt.Println(1/n) +} + +func main() { + flag.Parse() + outfile = flag.Arg(0) + data = flag.Arg(1) + + logrus.RegisterExitHandler(handler) + logrus.RegisterExitHandler(badHandler) + logrus.Fatal("Bye bye") +} +`) diff --git a/vendor/github.com/Sirupsen/logrus/appveyor.yml b/vendor/github.com/Sirupsen/logrus/appveyor.yml new file mode 100644 index 000000000..96c2ce15f --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/appveyor.yml @@ -0,0 +1,14 @@ +version: "{build}" +platform: x64 +clone_folder: c:\gopath\src\github.com\sirupsen\logrus +environment: + GOPATH: c:\gopath +branches: + only: + - master +install: + - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% + - go version +build_script: + - go get -t + - go test diff --git a/vendor/github.com/Sirupsen/logrus/entry_test.go b/vendor/github.com/Sirupsen/logrus/entry_test.go new file mode 100644 index 000000000..a81e2b383 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/entry_test.go @@ -0,0 +1,115 @@ +package logrus + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEntryWithError(t *testing.T) { + + assert := assert.New(t) + + defer func() { + ErrorKey = "error" + }() + + err := fmt.Errorf("kaboom at layer %d", 4711) + + assert.Equal(err, WithError(err).Data["error"]) + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + + assert.Equal(err, entry.WithError(err).Data["error"]) + + ErrorKey = "err" + + assert.Equal(err, entry.WithError(err).Data["err"]) + +} + +func TestEntryPanicln(t *testing.T) { + errBoom := fmt.Errorf("boom time") + + defer func() { + p := recover() + assert.NotNil(t, p) + + switch pVal := p.(type) { + case *Entry: + assert.Equal(t, "kaboom", pVal.Message) + assert.Equal(t, errBoom, pVal.Data["err"]) + default: + t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) + } + }() + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + entry.WithField("err", errBoom).Panicln("kaboom") +} + +func TestEntryPanicf(t *testing.T) { + errBoom := fmt.Errorf("boom again") + + defer func() { + p := recover() + assert.NotNil(t, p) + + switch pVal := p.(type) { + case *Entry: + assert.Equal(t, "kaboom true", pVal.Message) + assert.Equal(t, errBoom, pVal.Data["err"]) + default: + t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) + } + }() + + logger := New() + logger.Out = &bytes.Buffer{} + entry := NewEntry(logger) + entry.WithField("err", errBoom).Panicf("kaboom %v", true) +} + +const ( + badMessage = "this is going to panic" + panicMessage = "this is broken" +) + +type panickyHook struct{} + +func (p *panickyHook) Levels() []Level { + return []Level{InfoLevel} +} + +func (p *panickyHook) Fire(entry *Entry) error { + if entry.Message == badMessage { + panic(panicMessage) + } + + return nil +} + +func TestEntryHooksPanic(t *testing.T) { + logger := New() + logger.Out = &bytes.Buffer{} + logger.Level = InfoLevel + logger.Hooks.Add(&panickyHook{}) + + defer func() { + p := recover() + assert.NotNil(t, p) + assert.Equal(t, panicMessage, p) + + entry := NewEntry(logger) + entry.Info("another message") + }() + + entry := NewEntry(logger) + entry.Info(badMessage) +} diff --git a/vendor/github.com/Sirupsen/logrus/example_basic_test.go b/vendor/github.com/Sirupsen/logrus/example_basic_test.go new file mode 100644 index 000000000..9ff56555b --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/example_basic_test.go @@ -0,0 +1,77 @@ +package logrus_test + +import ( + "os" + + "github.com/sirupsen/logrus" +) + +func Example_basic() { + var log = logrus.New() + log.Formatter = new(logrus.JSONFormatter) + log.Formatter = new(logrus.TextFormatter) //default + log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors + log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output + log.Level = logrus.TraceLevel + log.Out = os.Stdout + + // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) + // if err == nil { + // log.Out = file + // } else { + // log.Info("Failed to log to file, using default stderr") + // } + + defer func() { + err := recover() + if err != nil { + entry := err.(*logrus.Entry) + log.WithFields(logrus.Fields{ + "omg": true, + "err_animal": entry.Data["animal"], + "err_size": entry.Data["size"], + "err_level": entry.Level, + "err_message": entry.Message, + "number": 100, + }).Error("The ice breaks!") // or use Fatal() to force the process to exit with a nonzero code + } + }() + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "number": 0, + }).Trace("Went to the beach") + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "number": 8, + }).Debug("Started observing beach") + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(logrus.Fields{ + "temperature": -4, + }).Debug("Temperature changes") + + log.WithFields(logrus.Fields{ + "animal": "orca", + "size": 9009, + }).Panic("It's over 9000!") + + // Output: + // level=trace msg="Went to the beach" animal=walrus number=0 + // level=debug msg="Started observing beach" animal=walrus number=8 + // level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 + // level=warning msg="The group's number increased tremendously!" number=122 omg=true + // level=debug msg="Temperature changes" temperature=-4 + // level=panic msg="It's over 9000!" animal=orca size=9009 + // level=error msg="The ice breaks!" err_animal=orca err_level=panic err_message="It's over 9000!" err_size=9009 number=100 omg=true +} diff --git a/vendor/github.com/Sirupsen/logrus/example_global_hook_test.go b/vendor/github.com/Sirupsen/logrus/example_global_hook_test.go new file mode 100644 index 000000000..c81e448c2 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/example_global_hook_test.go @@ -0,0 +1,36 @@ +package logrus_test + +import ( + "github.com/sirupsen/logrus" + "os" +) + +var ( + mystring string +) + +type GlobalHook struct { +} + +func (h *GlobalHook) Levels() []logrus.Level { + return logrus.AllLevels +} + +func (h *GlobalHook) Fire(e *logrus.Entry) error { + e.Data["mystring"] = mystring + return nil +} + +func Example() { + l := logrus.New() + l.Out = os.Stdout + l.Formatter = &logrus.TextFormatter{DisableTimestamp: true, DisableColors: true} + l.AddHook(&GlobalHook{}) + mystring = "first value" + l.Info("first log") + mystring = "another value" + l.Info("second log") + // Output: + // level=info msg="first log" mystring="first value" + // level=info msg="second log" mystring="another value" +} diff --git a/vendor/github.com/Sirupsen/logrus/example_hook_test.go b/vendor/github.com/Sirupsen/logrus/example_hook_test.go new file mode 100644 index 000000000..15118d26b --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/example_hook_test.go @@ -0,0 +1,43 @@ +// +build !windows + +package logrus_test + +import ( + "log/syslog" + "os" + + "github.com/sirupsen/logrus" + slhooks "github.com/sirupsen/logrus/hooks/syslog" +) + +// An example on how to use a hook +func Example_hook() { + var log = logrus.New() + log.Formatter = new(logrus.TextFormatter) // default + log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors + log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output + if sl, err := slhooks.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""); err != nil { + log.Hooks.Add(sl) + } + log.Out = os.Stdout + + log.WithFields(logrus.Fields{ + "animal": "walrus", + "size": 10, + }).Info("A group of walrus emerges from the ocean") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 122, + }).Warn("The group's number increased tremendously!") + + log.WithFields(logrus.Fields{ + "omg": true, + "number": 100, + }).Error("The ice breaks!") + + // Output: + // level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 + // level=warning msg="The group's number increased tremendously!" number=122 omg=true + // level=error msg="The ice breaks!" number=100 omg=true +} diff --git a/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go b/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go new file mode 100644 index 000000000..d9481589f --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/formatter_bench_test.go @@ -0,0 +1,101 @@ +package logrus + +import ( + "fmt" + "testing" + "time" +) + +// smallFields is a small size data set for benchmarking +var smallFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", +} + +// largeFields is a large size data set for benchmarking +var largeFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", + "five": "six", + "seven": "eight", + "nine": "ten", + "eleven": "twelve", + "thirteen": "fourteen", + "fifteen": "sixteen", + "seventeen": "eighteen", + "nineteen": "twenty", + "a": "b", + "c": "d", + "e": "f", + "g": "h", + "i": "j", + "k": "l", + "m": "n", + "o": "p", + "q": "r", + "s": "t", + "u": "v", + "w": "x", + "y": "z", + "this": "will", + "make": "thirty", + "entries": "yeah", +} + +var errorFields = Fields{ + "foo": fmt.Errorf("bar"), + "baz": fmt.Errorf("qux"), +} + +func BenchmarkErrorTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields) +} + +func BenchmarkSmallTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) +} + +func BenchmarkLargeTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) +} + +func BenchmarkSmallColoredTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) +} + +func BenchmarkLargeColoredTextFormatter(b *testing.B) { + doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) +} + +func BenchmarkSmallJSONFormatter(b *testing.B) { + doBenchmark(b, &JSONFormatter{}, smallFields) +} + +func BenchmarkLargeJSONFormatter(b *testing.B) { + doBenchmark(b, &JSONFormatter{}, largeFields) +} + +func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { + logger := New() + + entry := &Entry{ + Time: time.Time{}, + Level: InfoLevel, + Message: "message", + Data: fields, + Logger: logger, + } + var d []byte + var err error + for i := 0; i < b.N; i++ { + d, err = formatter.Format(entry) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(d))) + } +} diff --git a/vendor/github.com/Sirupsen/logrus/go.mod b/vendor/github.com/Sirupsen/logrus/go.mod new file mode 100644 index 000000000..94574cc63 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/go.mod @@ -0,0 +1,11 @@ +module github.com/sirupsen/logrus + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.1 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/objx v0.1.1 // indirect + github.com/stretchr/testify v1.2.2 + golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 + golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 +) diff --git a/vendor/github.com/Sirupsen/logrus/go.sum b/vendor/github.com/Sirupsen/logrus/go.sum new file mode 100644 index 000000000..133d34ae1 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/Sirupsen/logrus/hook_test.go b/vendor/github.com/Sirupsen/logrus/hook_test.go new file mode 100644 index 000000000..b9675935b --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/hook_test.go @@ -0,0 +1,192 @@ +package logrus_test + +import ( + "bytes" + "encoding/json" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/sirupsen/logrus" + . "github.com/sirupsen/logrus/internal/testutils" +) + +type TestHook struct { + Fired bool +} + +func (hook *TestHook) Fire(entry *Entry) error { + hook.Fired = true + return nil +} + +func (hook *TestHook) Levels() []Level { + return []Level{ + TraceLevel, + DebugLevel, + InfoLevel, + WarnLevel, + ErrorLevel, + FatalLevel, + PanicLevel, + } +} + +func TestHookFires(t *testing.T) { + hook := new(TestHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + assert.Equal(t, hook.Fired, false) + + log.Print("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, true) + }) +} + +type ModifyHook struct { +} + +func (hook *ModifyHook) Fire(entry *Entry) error { + entry.Data["wow"] = "whale" + return nil +} + +func (hook *ModifyHook) Levels() []Level { + return []Level{ + TraceLevel, + DebugLevel, + InfoLevel, + WarnLevel, + ErrorLevel, + FatalLevel, + PanicLevel, + } +} + +func TestHookCanModifyEntry(t *testing.T) { + hook := new(ModifyHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.WithField("wow", "elephant").Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["wow"], "whale") + }) +} + +func TestCanFireMultipleHooks(t *testing.T) { + hook1 := new(ModifyHook) + hook2 := new(TestHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook1) + log.Hooks.Add(hook2) + + log.WithField("wow", "elephant").Print("test") + }, func(fields Fields) { + assert.Equal(t, fields["wow"], "whale") + assert.Equal(t, hook2.Fired, true) + }) +} + +type SingleLevelModifyHook struct { + ModifyHook +} + +func (h *SingleLevelModifyHook) Levels() []Level { + return []Level{InfoLevel} +} + +func TestHookEntryIsPristine(t *testing.T) { + l := New() + b := &bytes.Buffer{} + l.Formatter = &JSONFormatter{} + l.Out = b + l.AddHook(&SingleLevelModifyHook{}) + + l.Error("error message") + data := map[string]string{} + err := json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok := data["wow"] + require.False(t, ok) + b.Reset() + + l.Info("error message") + data = map[string]string{} + err = json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok = data["wow"] + require.True(t, ok) + b.Reset() + + l.Error("error message") + data = map[string]string{} + err = json.Unmarshal(b.Bytes(), &data) + require.NoError(t, err) + _, ok = data["wow"] + require.False(t, ok) + b.Reset() +} + +type ErrorHook struct { + Fired bool +} + +func (hook *ErrorHook) Fire(entry *Entry) error { + hook.Fired = true + return nil +} + +func (hook *ErrorHook) Levels() []Level { + return []Level{ + ErrorLevel, + } +} + +func TestErrorHookShouldntFireOnInfo(t *testing.T) { + hook := new(ErrorHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.Info("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, false) + }) +} + +func TestErrorHookShouldFireOnError(t *testing.T) { + hook := new(ErrorHook) + + LogAndAssertJSON(t, func(log *Logger) { + log.Hooks.Add(hook) + log.Error("test") + }, func(fields Fields) { + assert.Equal(t, hook.Fired, true) + }) +} + +func TestAddHookRace(t *testing.T) { + var wg sync.WaitGroup + wg.Add(2) + hook := new(ErrorHook) + LogAndAssertJSON(t, func(log *Logger) { + go func() { + defer wg.Done() + log.AddHook(hook) + }() + go func() { + defer wg.Done() + log.Error("test") + }() + wg.Wait() + }, func(fields Fields) { + // the line may have been logged + // before the hook was added, so we can't + // actually assert on the hook + }) +} diff --git a/vendor/github.com/Sirupsen/logrus/json_formatter_test.go b/vendor/github.com/Sirupsen/logrus/json_formatter_test.go new file mode 100644 index 000000000..695c36e54 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/json_formatter_test.go @@ -0,0 +1,346 @@ +package logrus + +import ( + "encoding/json" + "errors" + "fmt" + "runtime" + "strings" + "testing" +) + +func TestErrorNotLost(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("error", errors.New("wild walrus"))) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["error"] != "wild walrus" { + t.Fatal("Error field not set") + } +} + +func TestErrorNotLostOnFieldNotNamedError(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("omg", errors.New("wild walrus"))) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["omg"] != "wild walrus" { + t.Fatal("Error field not set") + } +} + +func TestFieldClashWithTime(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("time", "right now!")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.time"] != "right now!" { + t.Fatal("fields.time not set to original time field") + } + + if entry["time"] != "0001-01-01T00:00:00Z" { + t.Fatal("time field not set to current time, was: ", entry["time"]) + } +} + +func TestFieldClashWithMsg(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("msg", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.msg"] != "something" { + t.Fatal("fields.msg not set to original msg field") + } +} + +func TestFieldClashWithLevel(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.level"] != "something" { + t.Fatal("fields.level not set to original level field") + } +} + +func TestFieldClashWithRemappedFields(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyTime: "@timestamp", + FieldKeyLevel: "@level", + FieldKeyMsg: "@message", + }, + } + + b, err := formatter.Format(WithFields(Fields{ + "@timestamp": "@timestamp", + "@level": "@level", + "@message": "@message", + "timestamp": "timestamp", + "level": "level", + "msg": "msg", + })) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + for _, field := range []string{"timestamp", "level", "msg"} { + if entry[field] != field { + t.Errorf("Expected field %v to be untouched; got %v", field, entry[field]) + } + + remappedKey := fmt.Sprintf("fields.%s", field) + if remapped, ok := entry[remappedKey]; ok { + t.Errorf("Expected %s to be empty; got %v", remappedKey, remapped) + } + } + + for _, field := range []string{"@timestamp", "@level", "@message"} { + if entry[field] == field { + t.Errorf("Expected field %v to be mapped to an Entry value", field) + } + + remappedKey := fmt.Sprintf("fields.%s", field) + if remapped, ok := entry[remappedKey]; ok { + if remapped != field { + t.Errorf("Expected field %v to be copied to %s; got %v", field, remappedKey, remapped) + } + } else { + t.Errorf("Expected field %v to be copied to %s; was absent", field, remappedKey) + } + } +} + +func TestFieldsInNestedDictionary(t *testing.T) { + formatter := &JSONFormatter{ + DataKey: "args", + } + + logEntry := WithFields(Fields{ + "level": "level", + "test": "test", + }) + logEntry.Level = InfoLevel + + b, err := formatter.Format(logEntry) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + args := entry["args"].(map[string]interface{}) + + for _, field := range []string{"test", "level"} { + if value, present := args[field]; !present || value != field { + t.Errorf("Expected field %v to be present under 'args'; untouched", field) + } + } + + for _, field := range []string{"test", "fields.level"} { + if _, present := entry[field]; present { + t.Errorf("Expected field %v not to be present at top level", field) + } + } + + // with nested object, "level" shouldn't clash + if entry["level"] != "info" { + t.Errorf("Expected 'level' field to contain 'info'") + } +} + +func TestJSONEntryEndsWithNewline(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + if b[len(b)-1] != '\n' { + t.Fatal("Expected JSON log entry to end with a newline") + } +} + +func TestJSONMessageKey(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyMsg: "message", + }, + } + + b, err := formatter.Format(&Entry{Message: "oh hai"}) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) { + t.Fatal("Expected JSON to format message key") + } +} + +func TestJSONLevelKey(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyLevel: "somelevel", + }, + } + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, "somelevel") { + t.Fatal("Expected JSON to format level key") + } +} + +func TestJSONTimeKey(t *testing.T) { + formatter := &JSONFormatter{ + FieldMap: FieldMap{ + FieldKeyTime: "timeywimey", + }, + } + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, "timeywimey") { + t.Fatal("Expected JSON to format time key") + } +} + +func TestFieldDoesNotClashWithCaller(t *testing.T) { + SetReportCaller(false) + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("func", "howdy pardner")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["func"] != "howdy pardner" { + t.Fatal("func field replaced when ReportCaller=false") + } +} + +func TestFieldClashWithCaller(t *testing.T) { + SetReportCaller(true) + formatter := &JSONFormatter{} + e := WithField("func", "howdy pardner") + e.Caller = &runtime.Frame{Function: "somefunc"} + b, err := formatter.Format(e) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + entry := make(map[string]interface{}) + err = json.Unmarshal(b, &entry) + if err != nil { + t.Fatal("Unable to unmarshal formatted entry: ", err) + } + + if entry["fields.func"] != "howdy pardner" { + t.Fatalf("fields.func not set to original func field when ReportCaller=true (got '%s')", + entry["fields.func"]) + } + + if entry["func"] != "somefunc" { + t.Fatalf("func not set as expected when ReportCaller=true (got '%s')", + entry["func"]) + } + + SetReportCaller(false) // return to default value +} + +func TestJSONDisableTimestamp(t *testing.T) { + formatter := &JSONFormatter{ + DisableTimestamp: true, + } + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if strings.Contains(s, FieldKeyTime) { + t.Error("Did not prevent timestamp", s) + } +} + +func TestJSONEnableTimestamp(t *testing.T) { + formatter := &JSONFormatter{} + + b, err := formatter.Format(WithField("level", "something")) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + s := string(b) + if !strings.Contains(s, FieldKeyTime) { + t.Error("Timestamp not present", s) + } +} diff --git a/vendor/github.com/Sirupsen/logrus/logger_bench_test.go b/vendor/github.com/Sirupsen/logrus/logger_bench_test.go new file mode 100644 index 000000000..f0a768439 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/logger_bench_test.go @@ -0,0 +1,85 @@ +package logrus + +import ( + "io/ioutil" + "os" + "testing" +) + +// smallFields is a small size data set for benchmarking +var loggerFields = Fields{ + "foo": "bar", + "baz": "qux", + "one": "two", + "three": "four", +} + +func BenchmarkDummyLogger(b *testing.B) { + nullf, err := os.OpenFile("/dev/null", os.O_WRONLY, 0666) + if err != nil { + b.Fatalf("%v", err) + } + defer nullf.Close() + doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields) +} + +func BenchmarkDummyLoggerNoLock(b *testing.B) { + nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + b.Fatalf("%v", err) + } + defer nullf.Close() + doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields) +} + +func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) { + logger := Logger{ + Out: out, + Level: InfoLevel, + Formatter: formatter, + } + entry := logger.WithFields(fields) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + entry.Info("aaa") + } + }) +} + +func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) { + logger := Logger{ + Out: out, + Level: InfoLevel, + Formatter: formatter, + } + logger.SetNoLock() + entry := logger.WithFields(fields) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + entry.Info("aaa") + } + }) +} + +func BenchmarkLoggerJSONFormatter(b *testing.B) { + doLoggerBenchmarkWithFormatter(b, &JSONFormatter{}) +} + +func BenchmarkLoggerTextFormatter(b *testing.B) { + doLoggerBenchmarkWithFormatter(b, &TextFormatter{}) +} + +func doLoggerBenchmarkWithFormatter(b *testing.B, f Formatter) { + b.SetParallelism(100) + log := New() + log.Formatter = f + log.Out = ioutil.Discard + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + log. + WithField("foo1", "bar1"). + WithField("foo2", "bar2"). + Info("this is a dummy log") + } + }) +} diff --git a/vendor/github.com/Sirupsen/logrus/logger_test.go b/vendor/github.com/Sirupsen/logrus/logger_test.go new file mode 100644 index 000000000..73ba45061 --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/logger_test.go @@ -0,0 +1,42 @@ +package logrus + +import ( + "bytes" + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFieldValueError(t *testing.T) { + buf := &bytes.Buffer{} + l := &Logger{ + Out: buf, + Formatter: new(JSONFormatter), + Hooks: make(LevelHooks), + Level: DebugLevel, + } + l.WithField("func", func() {}).Info("test") + fmt.Println(buf.String()) + var data map[string]interface{} + json.Unmarshal(buf.Bytes(), &data) + _, ok := data[FieldKeyLogrusError] + require.True(t, ok) +} + +func TestNoFieldValueError(t *testing.T) { + buf := &bytes.Buffer{} + l := &Logger{ + Out: buf, + Formatter: new(JSONFormatter), + Hooks: make(LevelHooks), + Level: DebugLevel, + } + l.WithField("str", "str").Info("test") + fmt.Println(buf.String()) + var data map[string]interface{} + json.Unmarshal(buf.Bytes(), &data) + _, ok := data[FieldKeyLogrusError] + require.False(t, ok) +} diff --git a/vendor/github.com/Sirupsen/logrus/logrus_test.go b/vendor/github.com/Sirupsen/logrus/logrus_test.go new file mode 100644 index 000000000..b12d71c8c --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/logrus_test.go @@ -0,0 +1,716 @@ +package logrus_test + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + . "github.com/sirupsen/logrus" + . "github.com/sirupsen/logrus/internal/testutils" +) + +// TestReportCaller verifies that when ReportCaller is set, the 'func' field +// is added, and when it is unset it is not set or modified +// Verify that functions within the Logrus package aren't considered when +// discovering the caller. +func TestReportCallerWhenConfigured(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.ReportCaller = false + log.Print("testNoCaller") + }, func(fields Fields) { + assert.Equal(t, "testNoCaller", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Equal(t, nil, fields["func"]) + }) + + LogAndAssertJSON(t, func(log *Logger) { + log.ReportCaller = true + log.Print("testWithCaller") + }, func(fields Fields) { + assert.Equal(t, "testWithCaller", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Equal(t, + "github.com/sirupsen/logrus_test.TestReportCallerWhenConfigured.func3", fields["func"]) + }) +} + +func logSomething(t *testing.T, message string) Fields { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + logger.ReportCaller = true + + entry := logger.WithFields(Fields{ + "foo": "bar", + }) + + entry.Info(message) + + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + return fields +} + +// TestReportCallerHelperDirect - verify reference when logging from a regular function +func TestReportCallerHelperDirect(t *testing.T) { + fields := logSomething(t, "direct") + + assert.Equal(t, "direct", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"]) +} + +// TestReportCallerHelperDirect - verify reference when logging from a function called via pointer +func TestReportCallerHelperViaPointer(t *testing.T) { + fptr := logSomething + fields := fptr(t, "via pointer") + + assert.Equal(t, "via pointer", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"]) +} + +func TestPrint(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Print("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + }) +} + +func TestInfo(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "info", fields["level"]) + }) +} + +func TestWarn(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Warn("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "warning", fields["level"]) + }) +} + +func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln("test", "test") + }, func(fields Fields) { + assert.Equal(t, "test test", fields["msg"]) + }) +} + +func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln("test", 10) + }, func(fields Fields) { + assert.Equal(t, "test 10", fields["msg"]) + }) +} + +func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln(10, 10) + }, func(fields Fields) { + assert.Equal(t, "10 10", fields["msg"]) + }) +} + +func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Infoln(10, 10) + }, func(fields Fields) { + assert.Equal(t, "10 10", fields["msg"]) + }) +} + +func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test", 10) + }, func(fields Fields) { + assert.Equal(t, "test10", fields["msg"]) + }) +} + +func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.Info("test", "test") + }, func(fields Fields) { + assert.Equal(t, "testtest", fields["msg"]) + }) +} + +func TestWithFieldsShouldAllowAssignments(t *testing.T) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + localLog := logger.WithFields(Fields{ + "key1": "value1", + }) + + localLog.WithField("key2", "value2").Info("test") + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + assert.Equal(t, "value2", fields["key2"]) + assert.Equal(t, "value1", fields["key1"]) + + buffer = bytes.Buffer{} + fields = Fields{} + localLog.Info("test") + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.Nil(t, err) + + _, ok := fields["key2"] + assert.Equal(t, false, ok) + assert.Equal(t, "value1", fields["key1"]) +} + +func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("msg", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + }) +} + +func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("msg", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, "test", fields["msg"]) + assert.Equal(t, "hello", fields["fields.msg"]) + }) +} + +func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("time", "hello").Info("test") + }, func(fields Fields) { + assert.Equal(t, "hello", fields["fields.time"]) + }) +} + +func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) { + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("level", 1).Info("test") + }, func(fields Fields) { + assert.Equal(t, "info", fields["level"]) + assert.Equal(t, 1.0, fields["fields.level"]) // JSON has floats only + }) +} + +func TestDefaultFieldsAreNotPrefixed(t *testing.T) { + LogAndAssertText(t, func(log *Logger) { + ll := log.WithField("herp", "derp") + ll.Info("hello") + ll.Info("bye") + }, func(fields map[string]string) { + for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} { + if _, ok := fields[fieldName]; ok { + t.Fatalf("should not have prefixed %q: %v", fieldName, fields) + } + } + }) +} + +func TestWithTimeShouldOverrideTime(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithTime(now).Info("foobar") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(time.RFC3339)) + }) +} + +func TestWithTimeShouldNotOverrideFields(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithField("herp", "derp").WithTime(now).Info("blah") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(time.RFC3339)) + assert.Equal(t, fields["herp"], "derp") + }) +} + +func TestWithFieldShouldNotOverrideTime(t *testing.T) { + now := time.Now().Add(24 * time.Hour) + + LogAndAssertJSON(t, func(log *Logger) { + log.WithTime(now).WithField("herp", "derp").Info("blah") + }, func(fields Fields) { + assert.Equal(t, fields["time"], now.Format(time.RFC3339)) + assert.Equal(t, fields["herp"], "derp") + }) +} + +func TestTimeOverrideMultipleLogs(t *testing.T) { + var buffer bytes.Buffer + var firstFields, secondFields Fields + + logger := New() + logger.Out = &buffer + formatter := new(JSONFormatter) + formatter.TimestampFormat = time.StampMilli + logger.Formatter = formatter + + llog := logger.WithField("herp", "derp") + llog.Info("foo") + + err := json.Unmarshal(buffer.Bytes(), &firstFields) + assert.NoError(t, err, "should have decoded first message") + + buffer.Reset() + + time.Sleep(10 * time.Millisecond) + llog.Info("bar") + + err = json.Unmarshal(buffer.Bytes(), &secondFields) + assert.NoError(t, err, "should have decoded second message") + + assert.NotEqual(t, firstFields["time"], secondFields["time"], "timestamps should not be equal") +} + +func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) { + + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + + llog := logger.WithField("context", "eating raw fish") + + llog.Info("looks delicious") + + err := json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded first message") + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") + assert.Equal(t, fields["msg"], "looks delicious") + assert.Equal(t, fields["context"], "eating raw fish") + + buffer.Reset() + + llog.Warn("omg it is!") + + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded second message") + assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields") + assert.Equal(t, "omg it is!", fields["msg"]) + assert.Equal(t, "eating raw fish", fields["context"]) + assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") + +} + +func TestNestedLoggingReportsCorrectCaller(t *testing.T) { + var buffer bytes.Buffer + var fields Fields + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + logger.ReportCaller = true + + llog := logger.WithField("context", "eating raw fish") + + llog.Info("looks delicious") + + err := json.Unmarshal(buffer.Bytes(), &fields) + require.NoError(t, err, "should have decoded first message") + assert.Equal(t, 6, len(fields), "should have msg/time/level/func/context fields") + assert.Equal(t, "looks delicious", fields["msg"]) + assert.Equal(t, "eating raw fish", fields["context"]) + assert.Equal(t, + "github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"]) + cwd, err := os.Getwd() + require.NoError(t, err) + assert.Equal(t, filepath.ToSlash(cwd+"/logrus_test.go:340"), filepath.ToSlash(fields["file"].(string))) + + buffer.Reset() + + logger.WithFields(Fields{ + "Clyde": "Stubblefield", + }).WithFields(Fields{ + "Jab'o": "Starks", + }).WithFields(Fields{ + "uri": "https://www.youtube.com/watch?v=V5DTznu-9v0", + }).WithFields(Fields{ + "func": "y drummer", + }).WithFields(Fields{ + "James": "Brown", + }).Print("The hardest workin' man in show business") + + err = json.Unmarshal(buffer.Bytes(), &fields) + assert.NoError(t, err, "should have decoded second message") + assert.Equal(t, 11, len(fields), "should have all builtin fields plus foo,bar,baz,...") + assert.Equal(t, "Stubblefield", fields["Clyde"]) + assert.Equal(t, "Starks", fields["Jab'o"]) + assert.Equal(t, "https://www.youtube.com/watch?v=V5DTznu-9v0", fields["uri"]) + assert.Equal(t, "y drummer", fields["fields.func"]) + assert.Equal(t, "Brown", fields["James"]) + assert.Equal(t, "The hardest workin' man in show business", fields["msg"]) + assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry") + assert.Equal(t, + "github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"]) + require.NoError(t, err) + assert.Equal(t, filepath.ToSlash(cwd+"/logrus_test.go:365"), filepath.ToSlash(fields["file"].(string))) + + logger.ReportCaller = false // return to default value +} + +func logLoop(iterations int, reportCaller bool) { + var buffer bytes.Buffer + + logger := New() + logger.Out = &buffer + logger.Formatter = new(JSONFormatter) + logger.ReportCaller = reportCaller + + for i := 0; i < iterations; i++ { + logger.Infof("round %d of %d", i, iterations) + } +} + +// Assertions for upper bounds to reporting overhead +func TestCallerReportingOverhead(t *testing.T) { + iterations := 5000 + before := time.Now() + logLoop(iterations, false) + during := time.Now() + logLoop(iterations, true) + after := time.Now() + + elapsedNotReporting := during.Sub(before).Nanoseconds() + elapsedReporting := after.Sub(during).Nanoseconds() + + maxDelta := 1 * time.Second + assert.WithinDuration(t, during, before, maxDelta, + "%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)", + iterations, maxDelta.Seconds(), elapsedNotReporting) + assert.WithinDuration(t, after, during, maxDelta, + "%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)", + iterations, maxDelta.Seconds(), elapsedReporting) +} + +// benchmarks for both with and without caller-function reporting +func BenchmarkWithoutCallerTracing(b *testing.B) { + for i := 0; i < b.N; i++ { + logLoop(1000, false) + } +} + +func BenchmarkWithCallerTracing(b *testing.B) { + for i := 0; i < b.N; i++ { + logLoop(1000, true) + } +} + +func TestConvertLevelToString(t *testing.T) { + assert.Equal(t, "trace", TraceLevel.String()) + assert.Equal(t, "debug", DebugLevel.String()) + assert.Equal(t, "info", InfoLevel.String()) + assert.Equal(t, "warning", WarnLevel.String()) + assert.Equal(t, "error", ErrorLevel.String()) + assert.Equal(t, "fatal", FatalLevel.String()) + assert.Equal(t, "panic", PanicLevel.String()) +} + +func TestParseLevel(t *testing.T) { + l, err := ParseLevel("panic") + assert.Nil(t, err) + assert.Equal(t, PanicLevel, l) + + l, err = ParseLevel("PANIC") + assert.Nil(t, err) + assert.Equal(t, PanicLevel, l) + + l, err = ParseLevel("fatal") + assert.Nil(t, err) + assert.Equal(t, FatalLevel, l) + + l, err = ParseLevel("FATAL") + assert.Nil(t, err) + assert.Equal(t, FatalLevel, l) + + l, err = ParseLevel("error") + assert.Nil(t, err) + assert.Equal(t, ErrorLevel, l) + + l, err = ParseLevel("ERROR") + assert.Nil(t, err) + assert.Equal(t, ErrorLevel, l) + + l, err = ParseLevel("warn") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("WARN") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("warning") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("WARNING") + assert.Nil(t, err) + assert.Equal(t, WarnLevel, l) + + l, err = ParseLevel("info") + assert.Nil(t, err) + assert.Equal(t, InfoLevel, l) + + l, err = ParseLevel("INFO") + assert.Nil(t, err) + assert.Equal(t, InfoLevel, l) + + l, err = ParseLevel("debug") + assert.Nil(t, err) + assert.Equal(t, DebugLevel, l) + + l, err = ParseLevel("DEBUG") + assert.Nil(t, err) + assert.Equal(t, DebugLevel, l) + + l, err = ParseLevel("trace") + assert.Nil(t, err) + assert.Equal(t, TraceLevel, l) + + l, err = ParseLevel("TRACE") + assert.Nil(t, err) + assert.Equal(t, TraceLevel, l) + + l, err = ParseLevel("invalid") + assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error()) +} + +func TestUnmarshalText(t *testing.T) { + var u Level + for _, level := range AllLevels { + t.Run(level.String(), func(t *testing.T) { + assert.NoError(t, u.UnmarshalText([]byte(level.String()))) + assert.Equal(t, level, u) + }) + } + t.Run("invalid", func(t *testing.T) { + assert.Error(t, u.UnmarshalText([]byte("invalid"))) + }) +} + +func TestGetSetLevelRace(t *testing.T) { + wg := sync.WaitGroup{} + for i := 0; i < 100; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + if i%2 == 0 { + SetLevel(InfoLevel) + } else { + GetLevel() + } + }(i) + + } + wg.Wait() +} + +func TestLoggingRace(t *testing.T) { + logger := New() + + var wg sync.WaitGroup + wg.Add(100) + + for i := 0; i < 100; i++ { + go func() { + logger.Info("info") + wg.Done() + }() + } + wg.Wait() +} + +func TestLoggingRaceWithHooksOnEntry(t *testing.T) { + logger := New() + hook := new(ModifyHook) + logger.AddHook(hook) + entry := logger.WithField("context", "clue") + + var wg sync.WaitGroup + wg.Add(100) + + for i := 0; i < 100; i++ { + go func() { + entry.Info("info") + wg.Done() + }() + } + wg.Wait() +} + +func TestReplaceHooks(t *testing.T) { + old, cur := &TestHook{}, &TestHook{} + + logger := New() + logger.SetOutput(ioutil.Discard) + logger.AddHook(old) + + hooks := make(LevelHooks) + hooks.Add(cur) + replaced := logger.ReplaceHooks(hooks) + + logger.Info("test") + + assert.Equal(t, old.Fired, false) + assert.Equal(t, cur.Fired, true) + + logger.ReplaceHooks(replaced) + logger.Info("test") + assert.Equal(t, old.Fired, true) +} + +// Compile test +func TestLogrusInterfaces(t *testing.T) { + var buffer bytes.Buffer + // This verifies FieldLogger and Ext1FieldLogger work as designed. + // Please don't use them. Use Logger and Entry directly. + fn := func(xl Ext1FieldLogger) { + var l FieldLogger = xl + b := l.WithField("key", "value") + b.Debug("Test") + } + // test logger + logger := New() + logger.Out = &buffer + fn(logger) + + // test Entry + e := logger.WithField("another", "value") + fn(e) +} + +// Implements io.Writer using channels for synchronization, so we can wait on +// the Entry.Writer goroutine to write in a non-racey way. This does assume that +// there is a single call to Logger.Out for each message. +type channelWriter chan []byte + +func (cw channelWriter) Write(p []byte) (int, error) { + cw <- p + return len(p), nil +} + +func TestEntryWriter(t *testing.T) { + cw := channelWriter(make(chan []byte, 1)) + log := New() + log.Out = cw + log.Formatter = new(JSONFormatter) + log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n")) + + bs := <-cw + var fields Fields + err := json.Unmarshal(bs, &fields) + assert.Nil(t, err) + assert.Equal(t, fields["foo"], "bar") + assert.Equal(t, fields["level"], "warning") +} + +func TestLogLevelEnabled(t *testing.T) { + log := New() + log.SetLevel(PanicLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, false, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(FatalLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(ErrorLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, false, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(WarnLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, false, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(InfoLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, false, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(DebugLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, false, log.IsLevelEnabled(TraceLevel)) + + log.SetLevel(TraceLevel) + assert.Equal(t, true, log.IsLevelEnabled(PanicLevel)) + assert.Equal(t, true, log.IsLevelEnabled(FatalLevel)) + assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel)) + assert.Equal(t, true, log.IsLevelEnabled(WarnLevel)) + assert.Equal(t, true, log.IsLevelEnabled(InfoLevel)) + assert.Equal(t, true, log.IsLevelEnabled(DebugLevel)) + assert.Equal(t, true, log.IsLevelEnabled(TraceLevel)) +} + +func TestReportCallerOnTextFormatter(t *testing.T) { + l := New() + + l.Formatter.(*TextFormatter).ForceColors = true + l.Formatter.(*TextFormatter).DisableColors = false + l.WithFields(Fields{"func": "func", "file": "file"}).Info("test") + + l.Formatter.(*TextFormatter).ForceColors = false + l.Formatter.(*TextFormatter).DisableColors = true + l.WithFields(Fields{"func": "func", "file": "file"}).Info("test") +} diff --git a/vendor/github.com/Sirupsen/logrus/text_formatter_test.go b/vendor/github.com/Sirupsen/logrus/text_formatter_test.go new file mode 100644 index 000000000..b0d3a916a --- /dev/null +++ b/vendor/github.com/Sirupsen/logrus/text_formatter_test.go @@ -0,0 +1,480 @@ +package logrus + +import ( + "bytes" + "errors" + "fmt" + "os" + "sort" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFormatting(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + testCases := []struct { + value string + expected string + }{ + {`foo`, "time=\"0001-01-01T00:00:00Z\" level=panic test=foo\n"}, + } + + for _, tc := range testCases { + b, _ := tf.Format(WithField("test", tc.value)) + + if string(b) != tc.expected { + t.Errorf("formatting expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) + } + } +} + +func TestQuoting(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + checkQuoting := func(q bool, value interface{}) { + b, _ := tf.Format(WithField("test", value)) + idx := bytes.Index(b, ([]byte)("test=")) + cont := bytes.Contains(b[idx+5:], []byte("\"")) + if cont != q { + if q { + t.Errorf("quoting expected for: %#v", value) + } else { + t.Errorf("quoting not expected for: %#v", value) + } + } + } + + checkQuoting(false, "") + checkQuoting(false, "abcd") + checkQuoting(false, "v1.0") + checkQuoting(false, "1234567890") + checkQuoting(false, "/foobar") + checkQuoting(false, "foo_bar") + checkQuoting(false, "foo@bar") + checkQuoting(false, "foobar^") + checkQuoting(false, "+/-_^@f.oobar") + checkQuoting(true, "foobar$") + checkQuoting(true, "&foobar") + checkQuoting(true, "x y") + checkQuoting(true, "x,y") + checkQuoting(false, errors.New("invalid")) + checkQuoting(true, errors.New("invalid argument")) + + // Test for quoting empty fields. + tf.QuoteEmptyFields = true + checkQuoting(true, "") + checkQuoting(false, "abcd") + checkQuoting(true, errors.New("invalid argument")) +} + +func TestEscaping(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + testCases := []struct { + value string + expected string + }{ + {`ba"r`, `ba\"r`}, + {`ba'r`, `ba'r`}, + } + + for _, tc := range testCases { + b, _ := tf.Format(WithField("test", tc.value)) + if !bytes.Contains(b, []byte(tc.expected)) { + t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) + } + } +} + +func TestEscaping_Interface(t *testing.T) { + tf := &TextFormatter{DisableColors: true} + + ts := time.Now() + + testCases := []struct { + value interface{} + expected string + }{ + {ts, fmt.Sprintf("\"%s\"", ts.String())}, + {errors.New("error: something went wrong"), "\"error: something went wrong\""}, + } + + for _, tc := range testCases { + b, _ := tf.Format(WithField("test", tc.value)) + if !bytes.Contains(b, []byte(tc.expected)) { + t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) + } + } +} + +func TestTimestampFormat(t *testing.T) { + checkTimeStr := func(format string) { + customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format} + customStr, _ := customFormatter.Format(WithField("test", "test")) + timeStart := bytes.Index(customStr, ([]byte)("time=")) + timeEnd := bytes.Index(customStr, ([]byte)("level=")) + timeStr := customStr[timeStart+5+len("\"") : timeEnd-1-len("\"")] + if format == "" { + format = time.RFC3339 + } + _, e := time.Parse(format, (string)(timeStr)) + if e != nil { + t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e) + } + } + + checkTimeStr("2006-01-02T15:04:05.000000000Z07:00") + checkTimeStr("Mon Jan _2 15:04:05 2006") + checkTimeStr("") +} + +func TestDisableLevelTruncation(t *testing.T) { + entry := &Entry{ + Time: time.Now(), + Message: "testing", + } + keys := []string{} + timestampFormat := "Mon Jan 2 15:04:05 -0700 MST 2006" + checkDisableTruncation := func(disabled bool, level Level) { + tf := &TextFormatter{DisableLevelTruncation: disabled} + var b bytes.Buffer + entry.Level = level + tf.printColored(&b, entry, keys, timestampFormat) + logLine := (&b).String() + if disabled { + expected := strings.ToUpper(level.String()) + if !strings.Contains(logLine, expected) { + t.Errorf("level string expected to be %s when truncation disabled", expected) + } + } else { + expected := strings.ToUpper(level.String()) + if len(level.String()) > 4 { + if strings.Contains(logLine, expected) { + t.Errorf("level string %s expected to be truncated to %s when truncation is enabled", expected, expected[0:4]) + } + } else { + if !strings.Contains(logLine, expected) { + t.Errorf("level string expected to be %s when truncation is enabled and level string is below truncation threshold", expected) + } + } + } + } + + checkDisableTruncation(true, DebugLevel) + checkDisableTruncation(true, InfoLevel) + checkDisableTruncation(false, ErrorLevel) + checkDisableTruncation(false, InfoLevel) +} + +func TestDisableTimestampWithColoredOutput(t *testing.T) { + tf := &TextFormatter{DisableTimestamp: true, ForceColors: true} + + b, _ := tf.Format(WithField("test", "test")) + if strings.Contains(string(b), "[0000]") { + t.Error("timestamp not expected when DisableTimestamp is true") + } +} + +func TestNewlineBehavior(t *testing.T) { + tf := &TextFormatter{ForceColors: true} + + // Ensure a single new line is removed as per stdlib log + e := NewEntry(StandardLogger()) + e.Message = "test message\n" + b, _ := tf.Format(e) + if bytes.Contains(b, []byte("test message\n")) { + t.Error("first newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected newline to be removed.") + } + + // Ensure a double new line is reduced to a single new line + e = NewEntry(StandardLogger()) + e.Message = "test message\n\n" + b, _ = tf.Format(e) + if bytes.Contains(b, []byte("test message\n\n")) { + t.Error("Double newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected single newline") + } + if !bytes.Contains(b, []byte("test message\n")) { + t.Error("Double newline at end of Entry.Message did not result in a single newline after formatting") + } +} + +func TestTextFormatterFieldMap(t *testing.T) { + formatter := &TextFormatter{ + DisableColors: true, + FieldMap: FieldMap{ + FieldKeyMsg: "message", + FieldKeyLevel: "somelevel", + FieldKeyTime: "timeywimey", + }, + } + + entry := &Entry{ + Message: "oh hi", + Level: WarnLevel, + Time: time.Date(1981, time.February, 24, 4, 28, 3, 100, time.UTC), + Data: Fields{ + "field1": "f1", + "message": "messagefield", + "somelevel": "levelfield", + "timeywimey": "timeywimeyfield", + }, + } + + b, err := formatter.Format(entry) + if err != nil { + t.Fatal("Unable to format entry: ", err) + } + + assert.Equal(t, + `timeywimey="1981-02-24T04:28:03Z" `+ + `somelevel=warning `+ + `message="oh hi" `+ + `field1=f1 `+ + `fields.message=messagefield `+ + `fields.somelevel=levelfield `+ + `fields.timeywimey=timeywimeyfield`+"\n", + string(b), + "Formatted output doesn't respect FieldMap") +} + +func TestTextFormatterIsColored(t *testing.T) { + params := []struct { + name string + expectedResult bool + isTerminal bool + disableColor bool + forceColor bool + envColor bool + clicolorIsSet bool + clicolorForceIsSet bool + clicolorVal string + clicolorForceVal string + }{ + // Default values + { + name: "testcase1", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal + { + name: "testcase2", + expectedResult: true, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal with color disabled + { + name: "testcase3", + expectedResult: false, + isTerminal: true, + disableColor: true, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output not on terminal with color disabled + { + name: "testcase4", + expectedResult: false, + isTerminal: false, + disableColor: true, + forceColor: false, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output not on terminal with color forced + { + name: "testcase5", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: false, + clicolorIsSet: false, + clicolorForceIsSet: false, + }, + // Output on terminal with clicolor set to "0" + { + name: "testcase6", + expectedResult: false, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output on terminal with clicolor set to "1" + { + name: "testcase7", + expectedResult: true, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "0" + { + name: "testcase8", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output not on terminal with clicolor set to "1" + { + name: "testcase9", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "1" and force color + { + name: "testcase10", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "1", + }, + // Output not on terminal with clicolor set to "0" and force color + { + name: "testcase11", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: true, + envColor: true, + clicolorIsSet: true, + clicolorForceIsSet: false, + clicolorVal: "0", + }, + // Output not on terminal with clicolor_force set to "1" + { + name: "testcase12", + expectedResult: true, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "1", + }, + // Output not on terminal with clicolor_force set to "0" + { + name: "testcase13", + expectedResult: false, + isTerminal: false, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "0", + }, + // Output on terminal with clicolor_force set to "0" + { + name: "testcase14", + expectedResult: false, + isTerminal: true, + disableColor: false, + forceColor: false, + envColor: true, + clicolorIsSet: false, + clicolorForceIsSet: true, + clicolorForceVal: "0", + }, + } + + cleanenv := func() { + os.Unsetenv("CLICOLOR") + os.Unsetenv("CLICOLOR_FORCE") + } + + defer cleanenv() + + for _, val := range params { + t.Run("textformatter_"+val.name, func(subT *testing.T) { + tf := TextFormatter{ + isTerminal: val.isTerminal, + DisableColors: val.disableColor, + ForceColors: val.forceColor, + EnvironmentOverrideColors: val.envColor, + } + cleanenv() + if val.clicolorIsSet { + os.Setenv("CLICOLOR", val.clicolorVal) + } + if val.clicolorForceIsSet { + os.Setenv("CLICOLOR_FORCE", val.clicolorForceVal) + } + res := tf.isColored() + assert.Equal(subT, val.expectedResult, res) + }) + } +} + +func TestCustomSorting(t *testing.T) { + formatter := &TextFormatter{ + DisableColors: true, + SortingFunc: func(keys []string) { + sort.Slice(keys, func(i, j int) bool { + if keys[j] == "prefix" { + return false + } + if keys[i] == "prefix" { + return true + } + return strings.Compare(keys[i], keys[j]) == -1 + }) + }, + } + + entry := &Entry{ + Message: "Testing custom sort function", + Time: time.Now(), + Level: InfoLevel, + Data: Fields{ + "test": "testvalue", + "prefix": "the application prefix", + "blablabla": "blablabla", + }, + } + b, err := formatter.Format(entry) + require.NoError(t, err) + require.True(t, strings.HasPrefix(string(b), "prefix="), "format output is %q", string(b)) +} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/.travis.yml b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/.travis.yml new file mode 100644 index 000000000..bdb8aa485 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/.travis.yml @@ -0,0 +1,31 @@ +language: go + +sudo: false + +go: + - 1.8.x + - 1.9.x + - 1.10.x + +branches: + only: + - master + - pre-release + - dev-jxy + +install: + - go get -u github.com/golang/dep/cmd/dep + - dep ensure + +notifications: + webhooks: https://oapi.dingtalk.com/robot/send?access_token=096ed387df243a6d60835aadeccc47165f3813bc7cb81cdd0cfeadfd28e3acc1 + email: false + on_success: change + on_failure: always + +script: + - go vet ./sdk + - go vet ./services/... + - go build ./sdk + - go build ./services/... + - go test -v -timeout 60m ./integration/... diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/ChangeLog.txt b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/ChangeLog.txt new file mode 100644 index 000000000..9353d1f10 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/ChangeLog.txt @@ -0,0 +1,673 @@ +2018-08-28 Version: 1.27.6 +1, Add param for DescribeRegions,support AcceptLanguage,RegionEndpoint. + +2018-08-27 Version: 1.27.5 +1, add Ess alarm task api, CreateAlarm, DeleteAlarm, DescribeAlarms, DeleteAlarm, EnableAlarm, DisableAlarm + + +2018-08-27 Version: 1.27.4 +1, createInstance supported IpAddress param. + +2018-08-24 Version: 1.27.3 +1, Add api: DetectQRCode + +2018-08-23 Version: 1.27.2 +1, RunInstance add privateIpAddress. + +2018-08-23 Version: 1.27.1 +1, This is an example of release-log. +2, Please strictly follow this format to edit in English. +3, Format:Number + , + Space + Description + +2018-08-23 Version: 1.27.0 +1, Add CreateVpnGateway API. +2, Add product Ipv6Translator. + + +2018-08-22 Version: 1.26.2 +1, upgrade mongodb sdk. + +2018-08-22 Version: 1.26.0 +1, Add api CreateSimulatedSystemEvents, support creating one or more simulated system events. +2, Add api CancelSimulatedSystemEvents, support cancelling one or more simulated system events. + +2018-08-21 Version: 1.25.8 +1, DeleteFaceSearchImageByIdRequest add field: srcUri(String). +2, CreateFaceSetResponse add field: faces(Long). +3, GetFaceSetResponse add field: faces(Long). +4, Fix class Blurness in IndexFaceResponse. + +2018-08-21 Version: 1.25.7 +1, Repair describeLaunchTemplateVersions securityEnhancementStrategy type + +2018-08-17 Version: 1.25.6 +1, Add a new api called DeleteImage to clear the image resource. +2, Add the field called AdditionType and OutputType to GetMezzanineInfo api request. +3, Add the field called OutputType to GetMezzanineInfo api response. +4, Add the field called CreationTime and ModificationTime to GetPlayInfo api response. + +2018-08-17 Version: 1.25.5 +1, New apkpubkey fields for queryauthentication output parameter. +2, New packagename fields for queryauthentication output parameter. +3, New clientId fields for queryauthentication output parameter. + +2018-08-16 Version: 1.25.4 +1, ModifyScalingConfiguration add imageName. +2, CreateScalingConfiguration add imageName. + +2018-08-15 Version: 1.25.3 +1, Fix bug in GetMaterials API. +2, GetVerifyToken added a new param VerifyConfigs + +2018-08-15 Version: 1.25.2 +1, Add domain operation api AddLiveDomain,DeleteLiveDomain,DescribeLiveDomainDetail,StartLiveDomain,StopLiveDomain. +2, Add certificate operation api DescribeLiveCertificateDetail,DescribeLiveCertificateList,SetLiveDomainCertificate. +3, Add domain config api BatchSetLiveDomainConfigs,BatchDeleteLiveDomainConfigs,DeleteLiveSpecificConfig,DescribeLiveDomainConfigs. + +2018-08-15 Version: 1.25.1 +1, Update ecs tag to 20 maximum + + +2018-08-13 Version: 1.25.0 +1, New userinfo fields for registerface input parameter. +2, New userinfo fields for updateface input parameter. +3, New userinfo fields for queryface output parameter. + +2018-08-13 Version: 1.24.7 +1, Add cross domain support. +2, Add parameter SerialNumber to interface RebootSmartAccessGateway. + +2018-08-08 Version: 1.24.6 +1, The official release 4.0.0 + +2018-08-08 Version: 1.24.5 +1, Update FC apis. + +2018-08-08 Version: 1.24.4 +1, First release. + +2018-08-05 Version: 1.24.3 +1, Add Interface SubmitSubtitleJob +2, Support convert ttml、stl subtitle to vtt + +2018-08-04 Version: 1.24.2 +1, Add a new api called SetAuditSecurityIp to set audit security ip. +2, Add a new api called ListAuditSecurityIp to query audit security ip list. +3, Add a new api called UploadMediaByURL to bulk upload media based on urls. +4, Add the field called StorageLocation and TemplateGroupId to GetVideoInfo api response. +5, Add the field called StorageLocation and TemplateGroupId to GetVideoInfos api response. +6, Add the field called OutputType and Status to GetPlayInfo api response. + +2018-08-04 Version: 1.24.1 +1, CreateOfficeConversionTask add TgtFilePages field to specify the final uploaded page + +2018-08-03 Version: 1.24.0 +1, Add new API AddLocalNodes, for adding local machine to a hybrid cluster + +2018-08-02 Version: 1.23.7 +1, Add parameter(GroupId) for CreateNotifyPolicy,GetNotifyPolicy,DeleteNotifyPolicy,ListNotifyPolicy. + +2018-08-01 Version: 1.23.6 +1, Add parameter(DryRun) for CreateAlarm and UpdateAlarm. + +2018-08-01 Version: 1.23.5 +1, Add api: MoPenQueryCanvas, MoPenDoRecognize, MoPenSendMqttMessage, MoPenFindGroup + +2018-08-01 Version: 1.23.4 +1, Support describePrice for market image, add return detailInfo in interface describePrice + +2018-07-26 Version: 1.23.3 +1, Add RemoveTerminals API. + +2018-07-26 Version: 1.23.2 +1, Add new API: SendDryRunSystemEvent,PutMetricAlarm,DescribeAlarmsForDimensions,DescribeAlarms. + +2018-07-26 Version: 1.23.1 +1, Add BatchGetJobMetricInfo API. +2, Add BatchGetPluginConfigInfo API. +3, Add GetJobTopology API. + +2018-07-13 Version: 1.23.0 +1, New APIs for batch executing commands in cluster: InvokeShellCommand, ListCommands, etc. +2, New APIs for HybridCluster (link E-HPC with cluster in local IDC): CreateHybridCluster, etc. +3, New APIs for Container applications: AddContainerApp, etc. + +2018-07-13 Version: 1.22.6 +1, Release 2016-06-20 TableStore Open API + +2018-07-11 Version: 1.22.5 +1, new function: Attach and Detach Rds instance of scalingGroup. + + +2018-07-11 Version: 1.22.4 +1, Add DetectFaceAttributesService. +2, Add cloudauthPageUrl to GetVerifyTokenResponse. + +2018-07-10 Version: 1.22.3 +1, Add new API: EnableEventRule,DisableEventRule,DeleteEventTargets,DeleteEventRule,ListEventRules. +2, Modify the structured parameters for API: PutEventTargets,PutEventRule,DescribeEventRule. + +2018-07-09 Version: 1.22.2 +1, Add new API: DescribeEventRule,ListEventTargetsByRule,PutEventRule,PutEventTargets. +2, Add return value(Id) for NodeProcessCreate. + +2018-07-05 Version: 1.22.1 +1, new function, attach/detach load balancer of scalingGroup + +2018-07-05 Version: 1.22.0 +1, A new optional parameter 'Perspectives' is introduced to the 'Chat' API. By filling this parameter when calling 'Chat', you'll get the knowledge base content within the specified perspectives. + +2018-06-28 Version: 1.21.1 +1, ScalingConfiguration support hostName and passwordInherit +2, ScalingConfiguration support modify + +2018-06-27 Version: 1.21.0 +1, Modify QueryDomainRealNameVerificationInfo Api, add a return value IdentityCredentialUrl, which is domain real name verification image, you can download it via a HTTP get request,It has validity for 30 seconds. +2, Modify QueryRegistrantProfileRealNameVerificationInfo Api, add a return value IdentityCredentialUrl, which is domain real name verification image, you can download it via a HTTP get request,It has validity for 30 seconds + + +2018-06-27 Version: 1.20.6 +1, DescribeNetworkInterfaces support query with vpcId + +2018-06-22 Version: 1.20.5 +1, rtc openapi + + +2018-06-22 Version: 1.20.4 +1, Add new API: DeleteGroupDynamicRule,ListGroupDynamicRule,ApplyTemplate,PutGroupDynamicRule. +2, Add parameter(AlertIds) for CreateTask and ModifyTask. + +2018-06-21 Version: 1.20.3 +1, This is add InstanceList. + +2018-06-21 Version: 1.20.2 +1, This is add InstanceList. + +2018-06-20 Version: 1.20.1 +1, Add InstanceList in product security information query. + +2018-06-20 Version: 1.20.0 +1, This is the first version of jarvis-public. + +2018-06-20 Version: 1.19.6 +1, Add InstanceList in product security information query. + +2018-06-14 Version: 1.19.5 +1, Add passwordInherit. + +2018-06-13 Version: 1.19.4 +1, Add API AddCasterEpisodeGroupContent,CreateCaster. +2, Add Parameter fillMode for AddCasterLayout,ModifyCasterLayout. +3, Add return value fillMode DescribeCasterLayouts. +4, Update ErrorCode for StartCaster,StartCasterScene,DescribeCasters,CopyCaster. +5, Update ErrorCode for ModifyCasterLayout,DeleteCasterLayout,DeleteLiveAppRecordConfig. +6, Update ForbidLiveStream,DescribeLiveStreamsPublishList,DescribeLiveStreamsOnlineList. + +2018-06-13 Version: 1.19.3 +1, Add lifecycleHook. + +2018-06-08 Version: 1.19.2 +1, Add scdn interface,support scdn. + +2018-06-06 Version: 1.19.1 +1, Change the type of srcUid to int. + +2018-06-06 Version: 1.19.0 +1, Add interface DescribePhoneInfo, DescribeDdosDefenseInfo, DescribeRiskListDetail, DescribePunishList. + +2018-05-30 Version: 1.18.1 +1, Add new API: DescribeContact and GetContacts. +2, Add return value: alertRule for CreateTask. + +2018-05-29 Version: 1.18.0 +1, Add new interface DescribePhoneInfo to SDK. + +2018-05-28 Version: 1.17.0 +1, Add face 1-N,1-1 scan interface. + +2018-05-28 Version: 1.16.0 +1, ValidateSecurityGroup API + +2018-05-28 Version: 1.15.1 +1, add new openapi . + +2018-05-28 Version: 1.15.0 +1, This is an example of release-log. +2, Please strictly follow this format to edit in English. +3, Format:Number + , + Space + Description + +2018-05-26 Version: 1.14.2 +1, Add new interface InstallCloudAssistant, support Cloud Assistant client installation. +2, Add new interface DescribeCloudAssistantStatus, support Cloud Assistant client status detection. + +2018-05-25 Version: 1.14.1 +1, CreateAlarm,DeleteAlarm,UpdateAlarm,DisableAlarm,EnableAlarm,ListAlarm,ListAlarmHistory,ListContactGroup,PutMetricData,QueryMetricData,QueryMetricLast,QueryMetricList,QueryMetricTop remove useless parameter: callby_cms_owner. +2, QueryMetricList remove useless parameter: Page. +3, UpdateMyGroupMembers add parameter: Readers. +4, StopTasks,StartTasks,DeleteTasks add return value: Data. +5, ModifyTask remove invalid parameter: TaskType. +6, CreateTask fix bug: TaskName maybe duplicated. +7, Add lost return value for CreateTask. +8, DescribeISPAreaCity add parameter: isp and city. +9, remove api: PutMetricData. + +2018-05-23 Version: 1.14.0 +1, Add CreateDrdsAccount API, to support creating account for all databases of a DRDS instance. + +2018-05-23 Version: 1.13.1 +1, Add Function Compute interface,support Function Compute. + +2018-05-23 Version: 1.13.0 +1, Update API version to 2018-04-12. +2, New APIs in this new version: StartCluster, StopCluster, RecoverCluster, StartNodes, StopNodes, ListCustomImages. Support stopping a post-paid cluster or partial nodes of a cluster to save cost. +3, New parameters for CreateCluster API: EcsChargeType. Support creating a pre-paid cluster. +4, New parameters for CreateCluster API: DeploymentMode. Support creating a cluster with fewer manager nodes. + +2018-05-23 Version: 1.12.5 +1, This is an example of release-log. +2, Please strictly follow this format to edit in English. +3, Format:Number + , + Space + Description + +2018-05-22 Version: 1.12.4 +1, add DescribeMigrateTasks,DescribeOssDownloads,CheckRecoveryConditions. +2, modify DescribeDBInstanceAttribute. + +2018-05-17 Version: 1.12.3 +1, Supporting ethnicGroup and idCardStartDate fields in GetMaterials api + +2018-05-17 Version: 1.12.2 +1, the first version of private dns SDK + +2018-05-11 Version: 1.12.1 +1, Add Function Compute interface,support Function Compute. + +2018-05-09 Version: 1.12.0 +1, Add apis for domain broker. + +2018-05-08 Version: 1.11.3 +1, Add instance params. + +2018-05-08 Version: 1.11.2 +1, Remove DescribeAccountAttributes. + +2018-05-03 Version: 1.11.1 +1, Publish DRDS go sdk for the first time. +2, Support for creation/modification/deletion/description operation for DRDS instances and databases. + +2018-05-02 Version: 1.11.0 +1, Add new interface InstallCloudAssistant, support Cloud Assistant client installation. +2, Add new interface DescribeCloudAssistantStatus, support Cloud Assistant client status detection. + +2018-04-28 Version: 1.10.3 +1, Add api: DescribeTasks、StartTasks、StopTasks、DeleteTasks、ModifyTask、CreateTask、DescribeTaskDetail、DescribeISPAreaCity. + +2018-04-28 Version: 1.10.2 +1, Add dcdn domain interface,Support add、modify、delete、query dcdn domain. +2, Add dcdn config interface,Support set、delete、query domain config. + +2018-04-27 Version: 1.10.1 +1, release hsm open api +2, hsm open api includes DescribeRegions, DescribeInstances, ModityInstance, ConfigNetwork, ConfigWhiteList + +2018-04-26 Version: 1.10.0 +1, Add apis for domain group. +3, Add fields for QueryDomainList. + +2018-04-25 Version: 1.9.6 +1, CreateMyGroups add parameter "options" + +2018-04-24 Version: 1.9.5 +1, Add api:UpdateMyGroupMembers + +2018-04-24 Version: 1.9.4 +1, add interface FetchPhotos +2, add xflush log param unixTimestamp + +2018-04-23 Version: 1.9.3 +1, DescribeInstanceHistoryEvents adds parameter instanceEventTypes and instanceEventCycleStatuss. +2, InstanceId parameter is not necessary for DescribeInstanceHistoryEvents now. +3, DescribeInstancesFullStatus adds parameter instanceEventTypes. + +2018-04-23 Version: 1.9.2 +1, Add notificationConfiguration. +2, Add standby status. + +2018-04-20 Version: 1.9.1 +1, Interface DescribeAlarmHistory/ListAlarmHistory Add return value instanceName. + +2018-04-17 Version: 1.8.3 +1, EditPhotos add input param TakenAt +2, add FetchMomentPhotos +3, ListAlbums add return param Remark + +2018-04-16 Version: 1.8.2 +1, Release go sdk + + +2018-04-11 Version: 1.8.1 +1, GetLibrary/FetchLibraries add return ctime +2, Editphotos add input param takenAt + +2018-04-10 Version: 1.8.0 +1, Add three interfaces CreateNetworkInterfacePermission DeleteNetworkInterfacePermission DescribeNetworkInterfacePermissions. + +2018-04-10 Version: 1.7.3 +1, publish Project API. +2, publish Service API. +3, publish Service order API. +4, publish Credential API. +5, publish CAS API. + +2018-04-09 Version: 1.7.2 +1, Add api: QueryMetricData, QueryMetricTop, TaskConfigCreate, TaskConfigDelete, TaskConfigEnable, TaskConfigList, TaskConfigModify, TaskConfigUnhealthy +2, Remove api: PutSystemEvent + +2018-04-08 Version: 1.7.0 +1, Add voice asynchronous scan interface. + +2018-04-04 Version: 1.6.1 +1, add tablestore trigger pop api and sample code + +2018-04-04 Version: 1.6.0 +1, Add APIs for domain transfer in and transfer out. +2, Add APIs for poll and acknowledge domain task. + +2018-04-03 Version: 1.5.0 +1, Add APIs for domain transfer in and transfer out. +2, Add APIs for poll and acknowledge domain task. +3, Add API for query domain group list. + +2018-03-30 Version: 1.4.11 +1, API QueryCustomerSaleInfo arguments update. + +2018-03-29 Version: 1.4.10 +1, edit FetchLibraries return param format + +2018-03-29 Version: 1.4.9 +1, Add APIs: CreateAlias, UpdateAlias, DeleteAlias, ListAliases, ListAliasesByKeyId. +2, Add APIs: GetParametersForImport, ImportKeyMaterial, DeleteKeyMaterial. +3, Update KeyMetadata for CreateKey and DescribeKey. + +2018-03-29 Version: 1.4.8 +1, Cloud Enterprise Network SDK initial release. + +2018-03-29 Version: 1.4.7 +1, Cloud Enterprise Network SDK initial release. + +2018-03-27 Version: 1.4.6 +1, Rename QueryCustomerSaleInfo to RegionName. + +2018-03-27 Version: 1.4.5 +1, publish Project API. +2, publish Service API. +3, publish Service order API. +4, publish Credential API. +5, publish CAS API. + +2018-03-27 Version: 1.4.4 +1, add interface FetchLibraries + +2018-03-23 Version: 1.4.3 +1, interface DescribeInstanceTypes output InstancePpsRx InstancePpsTx + +2018-03-23 Version: 1.4.2 +1, interface DescribeInstanceTypes output InstancePpsRx InstancePpsTx + +2018-03-23 Version: 1.4.1 +1, ModifyPrepayInstanceSpec support migrateAcrossZone. + +2018-03-23 Version: 1.4.0 +1, Add 'QueryDevicesByAccount' and 'QueryDevicesByAlias' Api. +2, Remove 'QueryPushDetail' Api. + +2018-03-20 Version: 1.2.7 +1, add FetchAlbumTagPhotos +2, CreatePhoto add optional param TakenAt + +2018-03-16 Version: 1.2.6 +1, Update GetQuotaInstance API. + +2018-03-16 Version: 1.2.5 +1, Synchronize to the latest api list + + +2018-03-15 Version: 1.2.4 +1, Add QueryCustomerSaleInfo API. + + +2018-03-09 Version:1.2.3 +1, fix bug:modify error message when roleArn is wrong + +2018-03-13 Version: 1.2.2 +1, API GetQuotaHistoryInfo fix field error. + +2018-03-09 Version: 1.2.1 +1, complete api comments + +2018-03-09 Version: 1.2.0 +1, improve endpoint resolver + +2018-03-07 Version: 1.1.7 +1, add GetAlbumsByNames +2, add ListEvent/CreateEvent/EditEvent/DeleteEvent/GetEvent +3, add return IdStr for string + +2018-03-06 Version: 1.1.6 +1, add GetAlbumsByNames +2, add ListEvent/CreateEvent/EditEvent/DeleteEvent/GetEvent +3, add return IdStr for string + + +2018-03-06 Version: 1.1.5 +1, add GetAlbumsByNames +2, add ListEvent/CreateEvent/EditEvent/DeleteEvent/GetEvent +3, add return IdStr for string + +2018-02-28 Version: 1.1.3 +1, Add query resource inventory API. +2, Add query topology API. + +2018-02-28 Version: 1.1.2 +1, Add query topology API. + +2018-02-27 Version: 1.1.1 +1, Add Action API. + +2018-02-27 Version: 1.1.0 +1, add new api DescribeClusters,DescribeClusterLogs,DescribeClusterNodes,UpgradeClusterComponents + +2018-02-12 Version: 1.0.0 +1. Optimize the nested structs in all response, this will bring the following incompatibilities: + * Api response struct changes, conclude: + * ecs.DescribeNetworkInterfaces + * ecs.DescribeDeploymentSetTopology + * rds.DescribeDBInstanceIPArrayList + * rds.DescribeDBInstancesAsCsv + * slb.DescribeLoadBalancersRelatedEcs + * vpc.DescribeVpcAttribute + * vpc.DescribeVirtualBorderRouters + * mts.RegisterMediaDetailPerson + * mts.QueryEditingJobList + * mts.SubmitEditingJobs + * mts.QueryMediaListByURL + * mts.ListJob + * mts.QueryMediaList + * mts.QueryJobList + * mts.SubmitJobs + * ehpc.DescribeCluster + * aegis.GetEntityList + * aegis.DescribeStratety + + +2018-02-09 Version: 0.12.0 +1, Aliyun E-HPC service SDK, initial version. +2, Include APIs of E-HPC clusters, nodes, users, jobs, job templates etc. + +2018-02-07 Version: 0.11.4 +1, add the access interface of logs such as vulnerabilities, baselines, exceptions, etc. + +2018-02-06 Version: 0.11.3 +1, ModifyInstanceChargeType add instanceChargeType param, support prepay instance to postpay instance. +2, ModifyPrepayInstanceSpec add operatorType param, support downgrade prepay ecs. + +2018-02-02 Version: 0.11.2 +1, this version is new of captcha management and nvc analyze + +2018-01-31 Version: 0.11.1 +1. Fixed bugs that could cause signature errors while a ROA request contains lots of special symbols +2. Optimization of the serverError.Error() interface +3. When there is an error of "SignatureDoseNotMatch", it is now possible to tell user if the AccessKeySecret is wrong or caused by a sdk bug + +2018-01-29 Version: 0.11.0 +1, Support dep +2, Add 4 usage of credentials for each services +3, Standard interface naming + +2018-01-29 Version: 0.10.0 +1, Add 'notificationChannel' parameter to Push API + +2018-01-24 Version: 0.9.3 +1, Fixed a problem that the ActiveAlert interface name is not standard +2, Update ActiveAlert interface : ListProductOfActiveAlert / DisableActiveAlert / EnableActiveAlert + +2018-01-24 Version: 0.9.2 +1, Add ActiveAlert API : ListActiveAlertRuleRequest/ListProductOfActiceAlertRequest/EnableActiceAlertRequest/DisableActiceAlertRequest + +2018-01-24 Version: 0.9.1 +1. improve: asyncWithChan avoid panic of "write on closed channel" +2. improve: asyncWithChan support select case usage +3. bug fix: repeated signature nonce while retry +4. bug fix: calling request.GetUrl() ahead of client.DoAction() will cause problems + +2018-01-24 Version: 0.9.0 +1, Publish domain config interface, allow users to create or delete a domain protect config under DDoS Pro. +2, Publish domain config query interface, allow users to query a list of domain config or a single domain config. +3, Publish domain proxy modify interface, allow users to set domain transmit proxy. +4, Publish domain transmit rule config interface, including modify and delete type. +5, Publish domain black and white list config interface. +6, Publish domain cname auto status config interface. +7, Publish domain certificate upload interface. +8, Publish domain qps graph query interface. +9, Publish ip attack events and traffic graph query interface. + + +2018-01-23 Version: 0.8.3 +1, Tesla Dam API release. +2, Add ActionDiskCheck, ActionDiskMask, ActionDiskRma, HostGets. + + +2018-01-18 Version: 0.8.2 +1. Set default timeout to 10s +2. Make integration tests more stable +3. Fix the problem of LocationResolver in concurrency +4. Modifying the naming specification + +2018-01-18 Version: 0.8.1 +1, Update ECS go SDK to catch up with other langs. +2, DescribeImageSupportInstanceTypes add new param Filter and ActionType + +2018-01-16 Version: 0.8.0 +1, Add TriggerMode param in AddMediaWorkflow. +2, Add TriggerMode param in QueryMediaWorkflowList/SearchMediaWorkflow/UpdateMediaWorkflow. +3, Add interface UpdateMediaWorkflowTriggerMode. + +2018-01-11 Version: 0.7.8 +1. complete partly missed service codes +2. add default http method for roa requests + +2018-01-11 Version: 0.7.7 +1, Bug fix: Replenish user interface + +2018-01-11 Version: 0.7.6 +1, replace photo tag 2000 upgrade to 5000 +2, add TrashQuota + +2018-01-11 Version: 0.7.5 +1, Make the json.Unmarshal more robust + +2018-01-09 Version: 0.7.4 +1, Add integration tests + +2018-01-04 Version: 0.7.3 +1, Remove get entity info API, replaced by get entity instance. + +2018-01-03 Version: 0.7.2 +1, Bug fix: fix the ecs unmarshal bug + +2018-01-03 Version: 0.7.1 +1, Bug fix: fix the unmarshal bug + +2017-12-29 Version: 0.7.0 +1, First release for Domain-intl. +2, Add interfaces for domain name registration and management. + +2017-12-29 Version: 0.6.8 +1, Allow the setting of AcceptFormat in the Request. + +2017-12-26 Version: 0.6.5 +1, Add video AI service interface. + +2017-12-26 Version: 0.6.4 +1, Add video AI service interface. + +2017-12-20 Version: 0.6.3 +1, support tile dataset +2, use dimension value type to replace isDrillDown + +2017-12-20 Version: 0.6.2 +1, support tile dataset +2, use dimension value type to replace isDrillDown + + +2017-12-19 Version: 0.6.1 +1, InactivatePhotos support customer inactiveTime +2, support customer tags +3, ListPhotoTags、ListTags add param lang + +2017-12-18 Version: 0.6.0 +1, Add Scdn API. + +2017-12-18 Version: 0.5.7 +1, This is the first release of CCC Open API. + +2017-12-15 Version: 0.5.6 +1, Update SetReqAuthConfig. +2, Add Scdn API. + +2017-12-15 Version: 0.5.5 +1, fix test cases + +2017-12-15 Version: 0.5.4 +1, Add scdn API. +2, Update SetReqAuthConfig. + +2017-12-12 Version: 0.5.1 +1, remove unused fmt.print + +2017-12-08 Version: 0.5.0 +1, Add ARMSQueryDataSet, WhereInDimQuery interface. + +2017-12-08 Version: 0.4.0 +1, support endpoint.xml resolver + +2017-12-08 Version: 0.3.1 +1, Add ARMSQueryDataSet, WhereInDimQuery interface. + +2017-12-01 Version: 0.2.2 +1, Fix ineffassign problems + +2017-12-01 Version: 0.2.1 +1, Fix capitalizes the first letter in each word of header + +2017-11-28 Version: 0.2.0 +1, AK2.0 & StsToken + +2017-11-27 Version: 0.1.3 +1, format ft code with gofmt + +2017-11-27 Version: 0.1.2 +1, format code with gofmt + +2017-11-27 Version: 0.1.1 +1, add glide files + diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.lock b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.lock new file mode 100644 index 000000000..3084e5132 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.lock @@ -0,0 +1,77 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + name = "github.com/jmespath/go-jmespath" + packages = ["."] + revision = "0b12d6b5" + +[[projects]] + name = "github.com/json-iterator/go" + packages = ["."] + revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4" + version = "1.1.3" + +[[projects]] + name = "github.com/modern-go/concurrent" + packages = ["."] + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + name = "github.com/modern-go/reflect2" + packages = ["."] + revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f" + version = "1.0.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/satori/go.uuid" + packages = ["."] + revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3" + version = "v1.2.0" + +[[projects]] + name = "github.com/sirupsen/logrus" + packages = ["."] + revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" + version = "v1.0.5" + +[[projects]] + name = "github.com/stretchr/testify" + packages = ["assert"] + revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" + version = "v1.2.1" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + revision = "614d502a4dac94afa3a6ce146bd1736da82514c6" + +[[projects]] + branch = "master" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows" + ] + revision = "d99a578cf41bfccdeaf48b0845c823a4b8b0ad5e" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "d0ac3538ad51346f28f4bfa6f46b8a6b57847e683a90398178ebd7e5336f8aca" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.toml b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.toml new file mode 100644 index 000000000..3d2f256c7 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/Gopkg.toml @@ -0,0 +1,56 @@ +# 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 + +#ignored = [ +# "golang.org/x/sys/unix", +# "golang.org/x/sys/windows", +# "golang.org/x/crypto/ssh/terminal", +#] + +[[constraint]] + name = "github.com/jmespath/go-jmespath" + #version = "0.2.2" + revision = "0b12d6b5" + +[[constraint]] + name = "github.com/json-iterator/go" + version = "1.0.4" + +[[constraint]] + name = "github.com/satori/go.uuid" + version = "1.1.0" + +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "1.0.5" + +[[constraint]] + name = "github.com/stretchr/testify" + version = "1.1.4" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/README.md b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/README.md new file mode 100755 index 000000000..15e22a613 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/README.md @@ -0,0 +1,72 @@ +# Alibaba Cloud Go Software Development Kit +[![Build Status](https://travis-ci.org/aliyun/alibaba-cloud-sdk-go.svg?branch=master)](https://travis-ci.org/aliyun/alibaba-cloud-sdk-go) +[![Go Report Card](https://goreportcard.com/badge/github.com/aliyun/alibaba-cloud-sdk-go)](https://goreportcard.com/report/github.com/aliyun/alibaba-cloud-sdk-go) + +[中文文档](./README_zh.md) + +The Alibaba Cloud Go Software Development Kit (SDK) allows you to access Alibaba Cloud services such as Elastic Compute Service (ECS), Server Load Balancer (SLB), and CloudMonitor. You can access Alibaba Cloud services without the need to handle API related tasks, such as signing and constructing your requests. + +This document introduces how to obtain and call Alibaba Cloud Go SDK. + +If you have any problem while using Go SDK, please join the **DingTalk group: 11771185 (the official SDK customer service group of Alibaba Cloud)** for consultation. + +## Prerequisites + +- To use Alibaba Cloud Go SDK, you must have an Alibaba Cloud account as well as an AccessKey. + + The AccessKey is required when initializing `AcsClient`. You can create an AccessKey in the Alibaba Cloud console. For more information, see [Create an AccessKey](https://usercenter.console.aliyun.com/?spm=5176.doc52740.2.3.QKZk8w#/manage/ak). + + >**Note:** To increase the security of your account, we recommend that you use the AccessKey of the RAM user to access Alibaba Cloud services. + +- To use Alibaba Cloud Go SDK to access the APIs of a product, you must first activate the product on the [Alibaba Cloud console](https://home.console.aliyun.com/?spm=5176.doc52740.2.4.QKZk8w) if required. + + +## Install Go SDK + +Run the following commands to install Alibaba Cloud Go SDK: + +```powershell +glide get github.com/aliyun/alibaba-cloud-sdk-go +``` +## Use Go SDK + +The following code example shows the three main steps to use Alibaba Cloud Go SDK: + +1. Create the client. + +2. Create an API request and set parameters. + +3. Initiate the request and handle exceptions. + +```go +package main + +import ( + "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" + "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" + "fmt" +) + +func main() { + // Create an ECS client + ecsClient, err := ecs.NewClientWithAccessKey( + "", // Your Region ID + "", // Your AccessKey ID + "") // Your AccessKey Secret + if err != nil { + // Handle exceptions + panic(err) + } + // Create an API request and set parameters + request := ecs.CreateDescribeInstancesRequest() + // Set the request.PageSize to "10" + request.PageSize = requests.NewInteger(10) + // Initiate the request and handle exceptions + response, err := ecsClient.DescribeInstances(request) + if err != nil { + // Handle exceptions + panic(err) + } + fmt.Println(response) +} +``` \ No newline at end of file diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/README_zh.md b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/README_zh.md new file mode 100644 index 000000000..f2d21d0e8 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/README_zh.md @@ -0,0 +1,181 @@ +# 阿里云开发者Go工具套件 +[![Build Status](https://travis-ci.org/aliyun/alibaba-cloud-sdk-go.svg?branch=master)](https://travis-ci.org/aliyun/alibaba-cloud-sdk-go) +[![Go Report Card](https://goreportcard.com/badge/github.com/aliyun/alibaba-cloud-sdk-go)](https://goreportcard.com/report/github.com/aliyun/alibaba-cloud-sdk-go) + +欢迎使用阿里云开发者工具套件(SDK)。阿里云Go SDK让您不用复杂编程即可访问云服务器、云监控等多个阿里云服务。这里向您介绍如何获取阿里云Go SDK并开始调用。 + +如果您在使用SDK的过程中遇上任何问题,欢迎加入 **钉钉群: 11771185(阿里云官方SDK客户服务群)** 咨询 + +## 环境准备 +1. 要使用阿里云Go SDK,您需要一个云账号以及一对`Access Key ID`和`Access Key Secret`。 请在阿里云控制台中的[AccessKey管理页面](https://usercenter.console.aliyun.com/?spm=5176.doc52740.2.3.QKZk8w#/manage/ak)上创建和查看您的Access Key,或者联系您的系统管理员 +2. 要使用阿里云SDK访问某个产品的API,您需要事先在[阿里云控制台](https://home.console.aliyun.com/?spm=5176.doc52740.2.4.QKZk8w)中开通这个产品。 + +## SDK获取和安装 + +使用`go get`下载安装SDK + +``` +go get -u github.com/aliyun/alibaba-cloud-sdk-go/sdk +``` + +如果您使用了glide管理依赖,您也可以使用glide来安装阿里云GO SDK + +``` +glide get github.com/aliyun/alibaba-cloud-sdk-go +``` + +另外,阿里云Go SDK也会发布在 https://develop.aliyun.com/tools/sdk#/go 这个地址。 + +## 开始调用 +以下这个代码示例向您展示了调用阿里云GO SDK的3个主要步骤: + +1. 创建Client实例 +2. 创建API请求并设置参数 +3. 发起请求并处理异常 + +```go +package main + +import ( + "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" + "fmt" +) + +func main() { + // 创建ecsClient实例 + ecsClient, err := ecs.NewClientWithAccessKey( + "", // 您的可用区ID + "", // 您的Access Key ID + "") // 您的Access Key Secret + if err != nil { + // 异常处理 + panic(err) + } + // 创建API请求并设置参数 + request := ecs.CreateDescribeInstancesRequest() + request.PageSize = "10" + // 发起请求并处理异常 + response, err := ecsClient.DescribeInstances(request) + if err != nil { + // 异常处理 + panic(err) + } + fmt.Println(response) +} +``` + +在创建Client实例时,您需要填写3个参数:`Region ID`、`Access Key ID`和`Access Key Secret`。`Access Key ID`和`Access Key Secret`可以从控制台获得;而`Region ID`可以从[地域列表](https://help.aliyun.com/document_detail/40654.html?spm=5176.doc52740.2.8.FogWrd)中获得 + + +## Keepalive +阿里云Go SDK底层使用Go语言原生的`net/http`收发请求,因此配置方式与`net/http`相同,您可以通过config直接将配置传递给底层的httpClient +```go +httpTransport := http.Transport{ + // set http client options +} +config := sdk.NewConfig() + .WithHttpTransport(httpTransport) + .WithTimeout(timeout) +ecsClient, err := ecs.NewClientWithOptions(config) + +``` + +## 并发请求 + +* 因Go语言的并发特性,我们建议您在应用层面控制SDK的并发请求。 +* 为了方便您的使用,我们也提供了可直接使用的并发调用方式,相关的并发控制由SDK内部实现。 + +##### 开启SDK Client的并发功能 +```go +// 最大并发数 +poolSize := 2 +// 可缓存的最大请求数 +maxTaskQueueSize := 5 + +// 在创建时开启异步功能 +config := sdk.NewConfig() + .WithEnableAsync(true) + .WithGoRoutinePoolSize(poolSize) // 可选,默认5 + .WithMaxTaskQueueSize(maxTaskQueueSize) // 可选,默认1000 +ecsClient, err := ecs.NewClientWithOptions(config) + +// 也可以在client初始化后再开启 +client.EnableAsync(poolSize, maxTaskQueueSize) +``` + +##### 发起异步调用 +阿里云Go SDK支持两种方式的异步调用: + +1. 使用channel作为返回值 + ```go + responseChannel, errChannel := client.FooWithChan(request) + + // this will block + response := <-responseChannel + err = <-errChannel + ``` + +2. 使用callback控制回调 + + ```go + blocker := client.FooWithCallback(request, func(response *FooResponse, err error) { + // handle the response and err + }) + + // blocker 为(chan int),用于控制同步,返回1为成功,0为失败 + // 在<-blocker返回失败时,err依然会被传入的callback处理 + result := <-blocker + ``` + +## 泛化调用接口(CommonApi) + +##### 什么是CommonAPI +CommonAPI是阿里云SDK推出的,泛用型的API调用方式。CommonAPI具有以下几个特点: +1. 轻量:只需Core包即可发起调用,无需下载安装各产品线SDK。 +2. 简便:无需更新SDK即可调用最新发布的API。 +3. 快速迭代 + +##### 开始使用 + +CommonAPI,需要配合相应的API文档使用,以查询API的相关信息。 + +您可以在 [文档中心](https://help.aliyun.com/?spm=5176.8142029.388261.173.23896dfaav2hEF) 查询到所有产品的API文档。 + +发起一次CommonAPI请求,需要您查询到以下几个参数: +* 域名(domain):即该产品的通用访问域名,一版可以在"调用方式"页查看到 +* API版本(version):即该API的版本号,以’YYYY-MM-DD’的形式表现,一般可以在"公共参数"页面查到 +* 接口名称(apiName):即该API的名称 + +我们以Ecs产品的[DescribeInstanceStatus API](https://help.aliyun.com/document_detail/25505.html?spm=5176.doc25506.6.820.VbHnW6)为例 +```go +package main + +import ( + "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" + "github.com/aliyun/alibaba-cloud-sdk-go/sdk" + "fmt" +) + +func main() { + + client, err := sdk.NewClientWithAccessKey("cn-hangzhou", "{your_access_key_id}", "{your_access_key_id}") + if err != nil { + panic(err) + } + + request := requests.NewCommonRequest() + request.Domain = "ecs.aliyuncs.com" + request.Version = "2014-05-26" + request.ApiName = "DescribeInstanceStatus" + + request.QueryParams["PageNumber"] = "1" + request.QueryParams["PageSize"] = "30" + + response, err := client.ProcessCommonRequest(request) + if err != nil { + panic(err) + } + + fmt.Print(response.GetHttpContentString()) +} +``` diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/client_test.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/client_test.go new file mode 100644 index 000000000..58077a16b --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/client_test.go @@ -0,0 +1,573 @@ +/* + * 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 sdk + +import ( + "crypto/tls" + "encoding/json" + "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials" + "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" + "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" + "github.com/stretchr/testify/assert" + "io/ioutil" + "net/http" + "os" + "os/user" + "testing" +) + +var client, clientKeyPair, clientEcs, clientRoleArn, clientSts *Client + +type TestConfig struct { + AccessKeyId string + AccessKeySecret string + PublicKeyId string + PrivateKey string + RoleArn string + StsToken string + StsAk string + StsSecret string + ChildAK string + ChildSecret string +} + +type MockResponse struct { + Headers map[string]string + Body string + Params map[string]string + RemoteAddr string + RemoteHost string + QueryString string + RequestURL string +} + +func TestMain(m *testing.M) { + testSetup() + result := m.Run() + testTearDown() + os.Exit(result) +} + +func getConfigFromFile() *TestConfig { + usr, err := user.Current() + if err != nil { + panic(err) + } + configFilePath := usr.HomeDir + "/aliyun-sdk.json" + data, err := ioutil.ReadFile(configFilePath) + if err != nil { + panic(err) + } + var config TestConfig + json.Unmarshal(data, &config) + return &config +} + +func getConfigFromEnv() *TestConfig { + config := &TestConfig{ + AccessKeyId: os.Getenv("ACCESS_KEY_ID"), + AccessKeySecret: os.Getenv("ACCESS_KEY_SECRET"), + PublicKeyId: os.Getenv("PUBLIC_KEY_ID"), + PrivateKey: os.Getenv("PRIVATE_KEY"), + RoleArn: os.Getenv("ROLE_ARN"), + ChildAK: os.Getenv("CHILD_AK"), + ChildSecret: os.Getenv("CHILD_SECRET"), + StsToken: os.Getenv("STS_TOKEN"), + StsAk: os.Getenv("STS_AK"), + StsSecret: os.Getenv("STS_SECRET"), + } + if config.AccessKeyId == "" || os.Getenv("ENV_TYPE") != "CI" { + return nil + } else { + return config + } +} + +func testSetup() { + testConfig := getConfigFromEnv() + if testConfig == nil { + testConfig = getConfigFromFile() + } + + var err error + + clientConfig := NewConfig(). + WithEnableAsync(true). + WithGoRoutinePoolSize(5). + WithMaxTaskQueueSize(1000). + WithHttpTransport(&http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }) + //}). + //WithMaxRetryTime(15). + //WithTimeout(10) + + credential := &credentials.BaseCredential{ + AccessKeyId: testConfig.AccessKeyId, + AccessKeySecret: testConfig.AccessKeySecret, + } + client, err = NewClientWithOptions("cn-hangzhou", clientConfig, credential) + if err != nil { + panic(err) + } + + rsaKeypairCredential := credentials.NewRsaKeyPairCredential(testConfig.PrivateKey, testConfig.PublicKeyId, 3600) + clientKeyPair, err = NewClientWithOptions("cn-hangzhou", clientConfig, rsaKeypairCredential) + if err != nil { + panic(err) + } + + roleNameOnEcsCredential := credentials.NewStsRoleNameOnEcsCredential("conan") + clientEcs, err = NewClientWithOptions("cn-hangzhou", clientConfig, roleNameOnEcsCredential) + if err != nil { + panic(err) + } + + stsRoleArnCredential := credentials.NewStsRoleArnCredential(testConfig.ChildAK, testConfig.ChildSecret, testConfig.RoleArn, "clientTest", 3600) + clientRoleArn, err = NewClientWithOptions("cn-hangzhou", clientConfig, stsRoleArnCredential) + if err != nil { + panic(err) + } + + stsCredential := credentials.NewStsTokenCredential(testConfig.StsAk, testConfig.StsSecret, testConfig.StsToken) + clientSts, err = NewClientWithOptions("cn-hangzhou", clientConfig, stsCredential) + if err != nil { + panic(err) + } +} + +func testTearDown() { + +} + +func TestNewClientWithAccessKey(t *testing.T) { + assert.NotNil(t, client, "NewClientWithAccessKey failed") +} + +func TestRoaGet(t *testing.T) { + request := getFtTestRoaRequest() + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "HeaderParamValue", responseBean.Headers["Header-Param"]) +} + +func TestRoaPostForm(t *testing.T) { + request := getFtTestRoaRequest() + request.Method = requests.POST + request.FormParams["BodyParam"] = "BodyParamValue" + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "HeaderParamValue", responseBean.Headers["Header-Param"]) + assert.Equal(t, "BodyParamValue", responseBean.Params["BodyParam"]) +} + +func TestRoaPostStream(t *testing.T) { + request := getFtTestRoaRequest() + request.Method = requests.POST + request.Content = []byte("TestContent") + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "HeaderParamValue", responseBean.Headers["Header-Param"]) + assert.Equal(t, "TestContent", responseBean.Body) +} + +func TestRoaPostJson(t *testing.T) { + request := getFtTestRoaRequest() + request.Method = requests.POST + dataMap := map[string]string{"key": "value"} + data, err := json.Marshal(dataMap) + assert.Nil(t, err) + request.Content = data + request.SetContentType(requests.Json) + + response := &responses.BaseResponse{} + err = client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "HeaderParamValue", responseBean.Headers["Header-Param"]) + assert.Equal(t, requests.Json, responseBean.Headers["Content-Type"]) + assert.Equal(t, string(data), responseBean.Body) +} + +func TestRpcGet(t *testing.T) { + request := getFtTestRpcRequest() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +func TestRpcGetForHttps(t *testing.T) { + request := getFtTestRpcRequest() + request.Method = requests.GET + request.Scheme = requests.HTTPS + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +func TestRoaGetForHttps(t *testing.T) { + request := getFtTestRoaRequest() + request.Scheme = requests.HTTPS + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "HeaderParamValue", responseBean.Headers["Header-Param"]) +} + +func TestRpcPost(t *testing.T) { + request := getFtTestRpcRequest() + request.FormParams["BodyParam"] = "BodyParamValue" + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "BodyParamValue", responseBean.Params["BodyParam"]) +} + +func getFtTestRoaRequest() (request *requests.RoaRequest) { + request = &requests.RoaRequest{} + request.InitWithApiInfo("Ft", "2016-01-02", "TestRoaApi", "/web/cloudapi", "", "") + request.Domain = "ft.aliyuncs.com" + + request.Headers["Header-Param"] = "HeaderParamValue" + request.QueryParams["QueryParam"] = "QueryParamValue" + + return +} + +func getFtTestRpcRequest() (request *requests.RpcRequest) { + request = &requests.RpcRequest{} + request.InitWithApiInfo("Ft", "2016-01-01", "TestRpcApi", "", "") + request.Domain = "ft.aliyuncs.com" + request.QueryParams["QueryParam"] = "QueryParamValue" + return +} + +func getFtTestRpcRequestForEndpointLocation() (request *requests.RpcRequest) { + request = &requests.RpcRequest{} + request.InitWithApiInfo("Ft", "2016-01-01", "TestRpcApi", "ft", "openAPI") + request.RegionId = "ft-cn-hangzhou" + request.QueryParams["QueryParam"] = "QueryParamValue" + request.Domain = "ft.aliyuncs.com" + return +} + +func getFtTestRpcRequestForEndpointXml() (request *requests.RpcRequest) { + request = &requests.RpcRequest{} + request.InitWithApiInfo("Ft", "2016-01-01", "TestRpcApi", "", "") + request.RegionId = "cn-hangzhou" + request.QueryParams["QueryParam"] = "QueryParamValue" + request.Domain = "ft.aliyuncs.com" + return +} + +func TestCommonRpcRequest(t *testing.T) { + rpcRequest := requests.NewCommonRequest() + rpcRequest.Product = "Ft" + rpcRequest.Version = "2016-01-01" + rpcRequest.Domain = "ft.aliyuncs.com" + rpcRequest.ApiName = "TestRpcApi" + rpcRequest.Method = "POST" + + rpcRequest.QueryParams["QueryParam"] = "QueryParamValue" + rpcRequest.FormParams["BodyParam"] = "BodyParamValue" + + response, err := client.ProcessCommonRequest(rpcRequest) + + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "BodyParamValue", responseBean.Params["BodyParam"]) +} + +func TestCommonRoaRequest(t *testing.T) { + roaRequest := requests.NewCommonRequest() + roaRequest.Product = "Ft" + roaRequest.Version = "2016-01-02" + roaRequest.PathPattern = "/web/cloudapi" + roaRequest.Domain = "ft.aliyuncs.com" + roaRequest.Method = "POST" + + roaRequest.QueryParams["QueryParam"] = "QueryParamValue" + roaRequest.FormParams["BodyParam"] = "BodyParamValue" + + response, err := client.ProcessCommonRequest(roaRequest) + + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + assert.Equal(t, "BodyParamValue", responseBean.Params["BodyParam"]) +} + +func TestRpcGetForEndpointXml(t *testing.T) { + request := getFtTestRpcRequestForEndpointXml() + request.Method = requests.GET + request.RegionId = "cn-shanghai" + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +func TestRpcGetForLocation(t *testing.T) { + request := getFtTestRpcRequestForEndpointLocation() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +func TestRpcGetForLocationCache(t *testing.T) { + request := getFtTestRpcRequestForEndpointLocation() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := client.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + + request2 := getFtTestRpcRequestForEndpointLocation() + request2.Method = requests.GET + err = client.DoAction(request2, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +func TestRpcGetForKeyPair(t *testing.T) { + request := getFtTestRpcRequest() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := clientKeyPair.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +/*func TestRpcGetForEcs(t *testing.T) { + //测试接口,想测试的时候,要替换掉singer_ecs_instance中对应的变量,并且还要提供一个mock服务 + //requestUrl := "http://localhost:3500/latest/meta-data/ram/security-credentials/roleNameTest.json" + request := getFtTestRpcRequest() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := clientEcs.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + + err = clientEcs.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +}*/ + +func TestRpcGetForRoleArn(t *testing.T) { + request := getFtTestRpcRequest() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := clientRoleArn.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + + err = clientRoleArn.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +func TestRoaGetForRoleArn(t *testing.T) { + request := getFtTestRoaRequest() + request.Method = requests.GET + + response := &responses.BaseResponse{} + err := clientRoleArn.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + var responseBean MockResponse + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) + + err = clientRoleArn.DoAction(request, response) + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) + + json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) + + assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +} + +//测试Sts的时候要先获取一套stsToken和ak,由于有时效性,所以先把代码注释掉,测试的时候先获取stsToken完成后再调用 +//func TestRpcGetForSts(t *testing.T) { +// request := getFtTestRpcRequest() +// request.Method = requests.GET +// +// response := &responses.BaseResponse{} +// err := clientSts.DoAction(request, response) +// assert.Nil(t, err) +// assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) +// assert.NotNil(t, response.GetHttpContentString()) +// +// var responseBean MockResponse +// json.Unmarshal([]byte(response.GetHttpContentString()), &responseBean) +// +// assert.Equal(t, "QueryParamValue", responseBean.Params["QueryParam"]) +//} + +func TestCommonRoaRequestForAcceptXML(t *testing.T) { + roaRequest := requests.NewCommonRequest() + roaRequest.Product = "Acs" + roaRequest.Version = "2015-01-01" + roaRequest.ApiName = "GetGlobal" + roaRequest.PathPattern = "/" + roaRequest.Domain = "acs.aliyuncs.com" + roaRequest.AcceptFormat = "XML" + + response, err := client.ProcessCommonRequest(roaRequest) + + assert.Nil(t, err) + assert.Equal(t, http.StatusOK, response.GetHttpStatus(), response.GetHttpContentString()) + assert.NotNil(t, response.GetHttpContentString()) +} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints/mapping_resolver_test.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints/mapping_resolver_test.go new file mode 100644 index 000000000..e2fd40802 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints/mapping_resolver_test.go @@ -0,0 +1,19 @@ +package endpoints + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMappingResolver_TryResolve(t *testing.T) { + AddEndpointMapping("cn-hangzhou", "Ecs", "unreachable.aliyuncs.com") + resolveParam := &ResolveParam{ + RegionId: "cn-hangzhou", + Product: "ecs", + } + endpoint, err := Resolve(resolveParam) + assert.Nil(t, err) + assert.Equal(t, endpoint, "unreachable.aliyuncs.com") + fmt.Println("finished") +} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests/types_test.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests/types_test.go new file mode 100644 index 000000000..2deaebad7 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests/types_test.go @@ -0,0 +1,50 @@ +package requests + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNewInteger(t *testing.T) { + integer := NewInteger(123123) + assert.True(t, integer.HasValue()) + value, err := integer.GetValue() + assert.Nil(t, err) + assert.Equal(t, 123123, value) + var expected Integer + expected = "123123" + assert.Equal(t, expected, integer) +} + +func TestNewInteger64(t *testing.T) { + long := NewInteger64(123123123123123123) + assert.True(t, long.HasValue()) + value, err := long.GetValue64() + assert.Nil(t, err) + assert.Equal(t, int64(123123123123123123), value) + var expected Integer + expected = "123123123123123123" + assert.Equal(t, expected, long) +} + +func TestNewBoolean(t *testing.T) { + boolean := NewBoolean(false) + assert.True(t, boolean.HasValue()) + value, err := boolean.GetValue() + assert.Nil(t, err) + assert.Equal(t, false, value) + var expected Boolean + expected = "false" + assert.Equal(t, expected, boolean) +} + +func TestNewFloat(t *testing.T) { + float := NewFloat(123123.123123) + assert.True(t, float.HasValue()) + value, err := float.GetValue() + assert.Nil(t, err) + assert.Equal(t, 123123.123123, value) + var expected Float + expected = "123123.123123" + assert.Equal(t, expected, float) +} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses/json_parser_test.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses/json_parser_test.go new file mode 100644 index 000000000..31987be21 --- /dev/null +++ b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses/json_parser_test.go @@ -0,0 +1,145 @@ +package responses + +import ( + "encoding/json" + "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestFuzzyFieldUnmarshal(t *testing.T) { + from, err := getJsonBytes() + if err != nil { + panic(err) + } + fmt.Println("From:") + fmt.Println(string(from)) + to := &To{} + // support auto json type trans + initJsonParserOnce() + err = jsonParser.Unmarshal(from, to) + if err != nil { + panic(err) + } + + fmt.Println("To:") + bytesTo, _ := json.MarshalIndent(to, "", " ") + fmt.Println(string(bytesTo)) + + assert.Equal(t, "demo string", to.StrToStr) + assert.Equal(t, 123, to.StrToInt) + assert.Equal(t, int64(2147483648), to.StrToInt64) + assert.Equal(t, 1.23, to.StrToFloat) + assert.True(t, to.UpperFullStrToBool) + assert.True(t, to.UpperCamelStrToBool) + assert.True(t, to.LowerStrToBool) + + assert.Equal(t, "123", to.IntToStr) + assert.Equal(t, 123, to.IntToInt) + + assert.Equal(t, "2147483648", to.Int64ToStr) + assert.Equal(t, int64(2147483648), to.Int64ToInt64) + + assert.Equal(t, "true", to.BoolToStr) + assert.Equal(t, true, to.BoolToBool) + + assert.Equal(t, 0, to.EmptyStrToInt) + assert.Equal(t, int64(0), to.EmptyStrToInt64) + assert.Equal(t, float64(0), to.EmptyStrToFloat) + assert.Equal(t, false, to.EmptyStrToBool) + assert.Equal(t, "", to.EmptyStrToStr) +} + +func getJsonBytes() ([]byte, error) { + from := &From{ + StrToStr: "demo string", + StrToInt: "123", + StrToInt64: "2147483648", + StrToFloat: "1.23", + UpperFullStrToBool: "TRUE", + UpperCamelStrToBool: "True", + LowerStrToBool: "true", + + IntToStr: 123, + IntToInt: 123, + + Int64ToStr: int64(2147483648), + Int64ToInt64: int64(2147483648), + + FloatToStr: float64(1.23), + FloatToFloat: float64(1.23), + + BoolToStr: true, + BoolToBool: true, + + EmptyStrToInt: "", + EmptyStrToInt64: "", + EmptyStrToFloat: "", + EmptyStrToBool: "", + EmptyStrToStr: "", + } + + return json.MarshalIndent(from, "", " ") +} + +type From struct { + StrToStr string + StrToInt string + StrToInt64 string + StrToFloat string + UpperFullStrToBool string + UpperCamelStrToBool string + LowerStrToBool string + + IntToStr int + IntToInt int + + Int64ToStr int64 + Int64ToInt64 int64 + + FloatToStr float64 + FloatToFloat float64 + + BoolToStr bool + BoolToBool bool + + EmptyStrToInt string + EmptyStrToInt64 string + EmptyStrToFloat string + EmptyStrToBool string + EmptyStrToStr string +} + +type To struct { + StrToStr string + StrToInt int + StrToInt64 int64 + StrToFloat float64 + UpperFullStrToBool bool + UpperCamelStrToBool bool + LowerStrToBool bool + + IntToStr string + IntToInt int + + Int64ToStr string + Int64ToInt64 int64 + + FloatToStr string + FloatToFloat float64 + + BoolToStr string + BoolToBool bool + + EmptyStrToInt int + EmptyStrToInt64 int64 + EmptyStrToFloat float64 + EmptyStrToBool bool + EmptyStrToStr string + + NilToInt int + NilToInt64 int64 + NilToFloat float64 + NilToBool bool + NilToStr string +} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go deleted file mode 100644 index ef385f3a9..000000000 --- a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_to_android.go +++ /dev/null @@ -1,110 +0,0 @@ -package push - -//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. -// -// Code generated by Alibaba Cloud SDK Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" -) - -// PushNoticeToAndroid invokes the push.PushNoticeToAndroid API synchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoandroid.html -func (client *Client) PushNoticeToAndroid(request *PushNoticeToAndroidRequest) (response *PushNoticeToAndroidResponse, err error) { - response = CreatePushNoticeToAndroidResponse() - err = client.DoAction(request, response) - return -} - -// PushNoticeToAndroidWithChan invokes the push.PushNoticeToAndroid API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoandroid.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToAndroidWithChan(request *PushNoticeToAndroidRequest) (<-chan *PushNoticeToAndroidResponse, <-chan error) { - responseChan := make(chan *PushNoticeToAndroidResponse, 1) - errChan := make(chan error, 1) - err := client.AddAsyncTask(func() { - defer close(responseChan) - defer close(errChan) - response, err := client.PushNoticeToAndroid(request) - if err != nil { - errChan <- err - } else { - responseChan <- response - } - }) - if err != nil { - errChan <- err - close(responseChan) - close(errChan) - } - return responseChan, errChan -} - -// PushNoticeToAndroidWithCallback invokes the push.PushNoticeToAndroid API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoandroid.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToAndroidWithCallback(request *PushNoticeToAndroidRequest, callback func(response *PushNoticeToAndroidResponse, err error)) <-chan int { - result := make(chan int, 1) - err := client.AddAsyncTask(func() { - var response *PushNoticeToAndroidResponse - var err error - defer close(result) - response, err = client.PushNoticeToAndroid(request) - callback(response, err) - result <- 1 - }) - if err != nil { - defer close(result) - callback(nil, err) - result <- 0 - } - return result -} - -// PushNoticeToAndroidRequest is the request struct for api PushNoticeToAndroid -type PushNoticeToAndroidRequest struct { - *requests.RpcRequest - AppKey requests.Integer `position:"Query" name:"AppKey"` - Target string `position:"Query" name:"Target"` - TargetValue string `position:"Query" name:"TargetValue"` - Title string `position:"Query" name:"Title"` - Body string `position:"Query" name:"Body"` - JobKey string `position:"Query" name:"JobKey"` - ExtParameters string `position:"Query" name:"ExtParameters"` -} - -// PushNoticeToAndroidResponse is the response struct for api PushNoticeToAndroid -type PushNoticeToAndroidResponse struct { - *responses.BaseResponse - RequestId string `json:"RequestId" xml:"RequestId"` - MessageId string `json:"MessageId" xml:"MessageId"` -} - -// CreatePushNoticeToAndroidRequest creates a request to invoke PushNoticeToAndroid API -func CreatePushNoticeToAndroidRequest() (request *PushNoticeToAndroidRequest) { - request = &PushNoticeToAndroidRequest{ - RpcRequest: &requests.RpcRequest{}, - } - request.InitWithApiInfo("Push", "2016-08-01", "PushNoticeToAndroid", "", "") - return -} - -// CreatePushNoticeToAndroidResponse creates a response to parse from PushNoticeToAndroid response -func CreatePushNoticeToAndroidResponse() (response *PushNoticeToAndroidResponse) { - response = &PushNoticeToAndroidResponse{ - BaseResponse: &responses.BaseResponse{}, - } - return -} diff --git a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go b/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go deleted file mode 100644 index 73d1a588e..000000000 --- a/vendor/github.com/aliyun/alibaba-cloud-sdk-go/services/push/push_notice_toi_os.go +++ /dev/null @@ -1,111 +0,0 @@ -package push - -//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. -// -// Code generated by Alibaba Cloud SDK Code Generator. -// Changes may cause incorrect behavior and will be lost if the code is regenerated. - -import ( - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" - "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" -) - -// PushNoticeToiOS invokes the push.PushNoticeToiOS API synchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoios.html -func (client *Client) PushNoticeToiOS(request *PushNoticeToiOSRequest) (response *PushNoticeToiOSResponse, err error) { - response = CreatePushNoticeToiOSResponse() - err = client.DoAction(request, response) - return -} - -// PushNoticeToiOSWithChan invokes the push.PushNoticeToiOS API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoios.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToiOSWithChan(request *PushNoticeToiOSRequest) (<-chan *PushNoticeToiOSResponse, <-chan error) { - responseChan := make(chan *PushNoticeToiOSResponse, 1) - errChan := make(chan error, 1) - err := client.AddAsyncTask(func() { - defer close(responseChan) - defer close(errChan) - response, err := client.PushNoticeToiOS(request) - if err != nil { - errChan <- err - } else { - responseChan <- response - } - }) - if err != nil { - errChan <- err - close(responseChan) - close(errChan) - } - return responseChan, errChan -} - -// PushNoticeToiOSWithCallback invokes the push.PushNoticeToiOS API asynchronously -// api document: https://help.aliyun.com/api/push/pushnoticetoios.html -// asynchronous document: https://help.aliyun.com/document_detail/66220.html -func (client *Client) PushNoticeToiOSWithCallback(request *PushNoticeToiOSRequest, callback func(response *PushNoticeToiOSResponse, err error)) <-chan int { - result := make(chan int, 1) - err := client.AddAsyncTask(func() { - var response *PushNoticeToiOSResponse - var err error - defer close(result) - response, err = client.PushNoticeToiOS(request) - callback(response, err) - result <- 1 - }) - if err != nil { - defer close(result) - callback(nil, err) - result <- 0 - } - return result -} - -// PushNoticeToiOSRequest is the request struct for api PushNoticeToiOS -type PushNoticeToiOSRequest struct { - *requests.RpcRequest - AppKey requests.Integer `position:"Query" name:"AppKey"` - Target string `position:"Query" name:"Target"` - TargetValue string `position:"Query" name:"TargetValue"` - ApnsEnv string `position:"Query" name:"ApnsEnv"` - Title string `position:"Query" name:"Title"` - Body string `position:"Query" name:"Body"` - JobKey string `position:"Query" name:"JobKey"` - ExtParameters string `position:"Query" name:"ExtParameters"` -} - -// PushNoticeToiOSResponse is the response struct for api PushNoticeToiOS -type PushNoticeToiOSResponse struct { - *responses.BaseResponse - RequestId string `json:"RequestId" xml:"RequestId"` - MessageId string `json:"MessageId" xml:"MessageId"` -} - -// CreatePushNoticeToiOSRequest creates a request to invoke PushNoticeToiOS API -func CreatePushNoticeToiOSRequest() (request *PushNoticeToiOSRequest) { - request = &PushNoticeToiOSRequest{ - RpcRequest: &requests.RpcRequest{}, - } - request.InitWithApiInfo("Push", "2016-08-01", "PushNoticeToiOS", "", "") - return -} - -// CreatePushNoticeToiOSResponse creates a response to parse from PushNoticeToiOS response -func CreatePushNoticeToiOSResponse() (response *PushNoticeToiOSResponse) { - response = &PushNoticeToiOSResponse{ - BaseResponse: &responses.BaseResponse{}, - } - return -} diff --git a/vendor/github.com/aws/aws-sdk-go/.gitignore b/vendor/github.com/aws/aws-sdk-go/.gitignore new file mode 100644 index 000000000..fb11ceca0 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/.gitignore @@ -0,0 +1,11 @@ +dist +/doc +/doc-staging +.yardoc +Gemfile.lock +awstesting/integration/smoke/**/importmarker__.go +awstesting/integration/smoke/_test/ +/vendor/bin/ +/vendor/pkg/ +/vendor/src/ +/private/model/cli/gen-api/gen-api diff --git a/vendor/github.com/aws/aws-sdk-go/.godoc_config b/vendor/github.com/aws/aws-sdk-go/.godoc_config new file mode 100644 index 000000000..395878d6c --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/.godoc_config @@ -0,0 +1,14 @@ +{ + "PkgHandler": { + "Pattern": "/sdk-for-go/api/", + "StripPrefix": "/sdk-for-go/api", + "Include": ["/src/github.com/aws/aws-sdk-go/aws", "/src/github.com/aws/aws-sdk-go/service"], + "Exclude": ["/src/cmd", "/src/github.com/aws/aws-sdk-go/awstesting", "/src/github.com/aws/aws-sdk-go/awsmigrate"], + "IgnoredSuffixes": ["iface"] + }, + "Github": { + "Tag": "master", + "Repo": "/aws/aws-sdk-go", + "UseGithub": true + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/.travis.yml b/vendor/github.com/aws/aws-sdk-go/.travis.yml new file mode 100644 index 000000000..7659cd7d5 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/.travis.yml @@ -0,0 +1,51 @@ +language: go + +matrix: + allow_failures: + - go: tip + - go: 1.6.x + os: linux + include: + - os: linux + sudo: required + go: 1.5.x + # Use Go 1.5's vendoring experiment for 1.5 tests. + env: GO15VENDOREXPERIMENT=1 + - os: linux + sudo: required + go: 1.6.x + - os: linux + sudo: required + go: 1.7.x + - os: linux + sudo: required + go: 1.8.x + - os: linux + sudo: required + go: 1.9.x + - os: linux + sudo: required + go: 1.10.x + - os: linux + sudo: required + go: tip + - os: osx + go: 1.7.x + - os: osx + go: 1.8.x + - os: osx + go: 1.9.x + - os: osx + go: 1.10.x + - os: osx + go: tip + +install: + - make get-deps + +script: + - make unit-with-race-cover + +branches: + only: + - master diff --git a/vendor/github.com/aws/aws-sdk-go/CHANGELOG.md b/vendor/github.com/aws/aws-sdk-go/CHANGELOG.md new file mode 100644 index 000000000..7d6c6e759 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/CHANGELOG.md @@ -0,0 +1,3371 @@ +Release v1.13.54 (2018-05-22) +=== + +### Service Client Updates +* `service/ecs`: Updates service API and documentation + * Amazon Elastic Container Service (ECS) adds service discovery for services that use host or bridged network mode. ECS can now also register instance IPs for active tasks using bridged and host networking with Route 53, making them available via DNS. +* `service/inspector`: Updates service API + * We are launching the ability to target all EC2 instances. With this launch, resourceGroupArn is now optional for CreateAssessmentTarget and UpdateAssessmentTarget. If resourceGroupArn is not specified, all EC2 instances in the account in the AWS region are included in the assessment target. + +Release v1.13.53 (2018-05-21) +=== + +### Service Client Updates +* `service/cloudformation`: Updates service API and documentation + * 1) Filtered Update for StackSet based on Accounts and Regions: This feature will allow flexibility for the customers to roll out updates on a StackSet based on specific Accounts and Regions. 2) Support for customized ExecutionRoleName: This feature will allow customers to attach ExecutionRoleName to the StackSet thus ensuring more security and controlling the behavior of any AWS resources in the target accounts. + +Release v1.13.52 (2018-05-18) +=== + +### Service Client Updates +* `service/email`: Updates service documentation + * Fixed a broken link in the documentation for S3Action. +* `service/iot`: Updates service API and documentation + * We are releasing DeleteJob and DeleteJobExecution APIs to allow customer to delete resources created using AWS IoT Jobs. + +Release v1.13.51 (2018-05-17) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service documentation + * Documentation updates for codedeploy +* `service/cognito-idp`: Updates service API and documentation +* `service/ec2`: Updates service API and documentation + * You are now able to use instance storage (up to 1800 GB of NVMe based SSD) on C5 instances, the next generation of EC2's compute optimized instances in us-east-1, us-west-2, us-east-2, eu-west-1 and ca-central-1. C5 instances offer up to 72 vCPUs, 144 GiB of DDR4 instance memory, 25 Gbps in Network bandwidth and improved EBS and Networking bandwidth on smaller instance sizes to deliver improved performance for compute-intensive workloads.You can now run bare metal workloads on EC2 with i3.metal instances. As a new instance size belonging to the I3 instance family, i3.metal instances have the same characteristics as other instances in the family, including NVMe SSD-backed instance storage optimized for low latency, very high random I/O performance, and high sequential read throughput. I3.metal instances are powered by 2.3 GHz Intel Xeon processors, offering 36 hyper-threaded cores (72 logical processors), 512 GiB of memory, and 15.2 TB of NVMe SSD-backed instance storage. These instances deliver high networking throughput and lower latency with up to 25 Gbps of aggregate network bandwidth using Elastic Network Adapter (ENA)-based Enhanced Networking. + +Release v1.13.50 (2018-05-16) +=== + +### Service Client Updates +* `service/secretsmanager`: Updates service documentation + * Documentation updates for secretsmanager +* `service/servicecatalog`: Updates service API and documentation + * Users can now pass a new option to ListAcceptedPortfolioShares called portfolio-share-type with a value of AWS_SERVICECATALOG in order to access Getting Started Portfolios that contain selected products representing common customer use cases. + +Release v1.13.49 (2018-05-15) +=== + +### Service Client Updates +* `service/config`: Updates service API + +Release v1.13.48 (2018-05-14) +=== + +### Service Client Updates +* `service/codebuild`: Updates service API and documentation + * Adding support for more override fields for StartBuild API, add support for idempotency token field for StartBuild API in AWS CodeBuild. +* `service/iot1click-devices`: Adds new service +* `service/iot1click-projects`: Adds new service +* `service/organizations`: Updates service documentation + * Documentation updates for organizations + +Release v1.13.47 (2018-05-10) +=== + +### Service Client Updates +* `service/firehose`: Updates service API and documentation + * With this release, Amazon Kinesis Data Firehose can convert the format of your input data from JSON to Apache Parquet or Apache ORC before storing the data in Amazon S3. Parquet and ORC are columnar data formats that save space and enable faster queries compared to row-oriented formats like JSON. + +Release v1.13.46 (2018-05-10) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/gamelift`: Updates service API and documentation + * AutoScaling Target Tracking scaling simplification along with StartFleetActions and StopFleetActions APIs to suspend and resume automatic scaling at will. + +Release v1.13.45 (2018-05-10) +=== + +### Service Client Updates +* `service/budgets`: Updates service API and documentation + * Updating the regex for the NumericValue fields. +* `service/ec2`: Updates service API and documentation + * Enable support for latest flag with Get Console Output +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * Changes to support the Aurora MySQL Backtrack feature. + +Release v1.13.44 (2018-05-08) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Enable support for specifying CPU options during instance launch. +* `service/rds`: Updates service documentation + * Correction to the documentation about copying unencrypted snapshots. + +Release v1.13.43 (2018-05-07) +=== + +### Service Client Updates +* `service/alexaforbusiness`: Updates service API +* `service/budgets`: Updates service API and documentation + * "With this release, customers can use AWS Budgets to monitor how much of their Amazon EC2, Amazon RDS, Amazon Redshift, and Amazon ElastiCache instance usage is covered by reservations, and receive alerts when their coverage falls below the threshold they define." +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/es`: Updates service API, documentation, and paginators + * This change brings support for Reserved Instances to AWS Elasticsearch. +* `service/s3`: Updates service API and documentation + * Added BytesReturned details for Progress and Stats Events for Amazon S3 Select . + +Release v1.13.42 (2018-05-04) +=== + +### Service Client Updates +* `service/guardduty`: Updates service API, documentation, and paginators + * Amazon GuardDuty is adding five new API operations for creating and managing filters. For each filter, you can specify a criteria and an action. The action you specify is applied to findings that match the specified criteria. + +Release v1.13.41 (2018-05-03) +=== + +### Service Client Updates +* `service/appsync`: Updates service API and documentation +* `service/config`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/secretsmanager`: Updates service documentation + * Documentation updates for secretsmanager + +Release v1.13.40 (2018-05-02) +=== + +### Service Client Updates +* `service/acm`: Updates service documentation + * Documentation updates for acm +* `service/codepipeline`: Updates service API and documentation + * Added support for webhooks with accompanying definitions as needed in the AWS CodePipeline API Guide. +* `service/ec2`: Updates service API and documentation + * Amazon EC2 Fleet is a new feature that simplifies the provisioning of Amazon EC2 capacity across different EC2 instance types, Availability Zones, and the On-Demand, Reserved Instance, and Spot Instance purchase models. With a single API call, you can now provision capacity to achieve desired scale, performance, and cost. +* `service/ssm`: Updates service API and documentation + * Added support for new parameter, DocumentVersion, for SendCommand API. Users can now specify version of SSM document to be executed on the target(s). + +Release v1.13.39 (2018-04-30) +=== + +### Service Client Updates +* `service/alexaforbusiness`: Updates service API, documentation, and paginators +* `service/dynamodb`: Updates service API and documentation + * Adds two new APIs UpdateGlobalTableSettings and DescribeGlobalTableSettings. This update introduces new constraints in the CreateGlobalTable and UpdateGlobalTable APIs . Tables must have the same write capacity units. If Global Secondary Indexes exist then they must have the same write capacity units and key schema. +* `service/guardduty`: Updates service API and documentation + * You can disable the email notification when inviting GuardDuty members using the disableEmailNotification parameter in the InviteMembers operation. +* `service/route53domains`: Updates service API and documentation + * This release adds a SubmittedSince attribute to the ListOperations API, so you can list operations that were submitted after a specified date and time. +* `service/sagemaker`: Updates service API and documentation + * SageMaker has added support for VPC configuration for both Endpoints and Training Jobs. This allows you to connect from the instances running the Endpoint or Training Job to your VPC and any resources reachable in the VPC rather than being restricted to resources that were internet accessible. +* `service/workspaces`: Updates service API and documentation + * Added new IP Access Control APIs, an API to change the state of a Workspace, and the ADMIN_MAINTENANCE WorkSpace state. With the new IP Access Control APIs, you can now create/delete IP Access Control Groups, add/delete/update rules for IP Access Control Groups, Associate/Disassociate IP Access Control Groups to/from a WorkSpaces Directory, and Describe IP Based Access Control Groups. + +Release v1.13.38 (2018-04-26) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glacier`: Updates service documentation + * Documentation updates for Glacier to fix a broken link +* `service/secretsmanager`: Updates service documentation + * Documentation updates for secretsmanager + +Release v1.13.37 (2018-04-25) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service API and documentation + * AWS CodeDeploy has a new exception that indicates when a GitHub token is not valid. +* `service/rekognition`: Updates service documentation + * Documentation updates for Amazon Rekognition. +* `service/xray`: Updates service API and documentation + * Added PutEncryptionConfig and GetEncryptionConfig APIs for managing data encryption settings. Use PutEncryptionConfig to configure X-Ray to use an AWS Key Management Service customer master key to encrypt trace data at rest. + +Release v1.13.36 (2018-04-24) +=== + +### Service Client Updates +* `service/elasticbeanstalk`: Updates service API and documentation + * Support tracking Elastic Beanstalk resources in AWS Config. +* `service/secretsmanager`: Updates service documentation + * Documentation updates for secretsmanager + +Release v1.13.35 (2018-04-23) +=== + +### Service Client Updates +* `service/autoscaling-plans`: Updates service API and documentation +* `service/iot`: Updates service API and documentation + * Add IotAnalyticsAction which sends message data to an AWS IoT Analytics channel +* `service/iotanalytics`: Adds new service + +### SDK Enhancements +* `aws/endpoints`: Add Get Region description to endpoints package ([#1909](https://github.com/aws/aws-sdk-go/pull/1909)) + * Adds exposing the description field of the endpoints Region struct. + * Fixes [#1194](https://github.com/aws/aws-sdk-go/issues/1194) + +### SDK Bugs +* Fix XML unmarshaler not correctly unmarshaling list of timestamp values ([#1894](https://github.com/aws/aws-sdk-go/pull/1894)) + * Fixes a bug in the XML unmarshaler that would incorrectly try to unmarshal "time.Time" parameters that did not have the struct tag type on them. This would occur for nested lists like CloudWatch's GetMetricDataResponse MetricDataResults timestamp parameters. + * Fixes [#1892](https://github.com/aws/aws-sdk-go/issues/1892) +Release v1.13.34 (2018-04-20) +=== + +### Service Client Updates +* `service/firehose`: Updates service API and documentation + * With this release, Amazon Kinesis Data Firehose allows you to tag your delivery streams. Tags are metadata that you can create and use to manage your delivery streams. For more information about tagging, see AWS Tagging Strategies. For technical documentation, look for the tagging operations in the Amazon Kinesis Firehose API reference. +* `service/medialive`: Updates service API and documentation + * With AWS Elemental MediaLive you can now output live channels as RTMP (Real-Time Messaging Protocol) and RTMPS as the encrypted version of the protocol (Secure, over SSL/TLS). RTMP is the preferred protocol for sending live streams to popular social platforms which means you can send live channel content to social and sharing platforms in a secure and reliable way while continuing to stream to your own website, app or network. + +Release v1.13.33 (2018-04-19) +=== + +### Service Client Updates +* `service/ce`: Updates service API and documentation +* `service/codepipeline`: Updates service API and documentation + * Added new SourceRevision structure to Execution Summary with accompanying definitions as needed in the AWS CodePipeline API Guide. +* `service/devicefarm`: Updates service API and documentation + * Adding support for VPCEndpoint feature. Allows customers to be able to access their private endpoints/services running in their VPC during test automation. +* `service/ec2`: Updates service API and documentation + * Added support for customers to see the time at which a Dedicated Host was allocated or released. +* `service/rds`: Updates service API and documentation + * The ModifyDBCluster operation now includes an EngineVersion parameter. You can use this to upgrade the engine for a clustered database. +* `service/secretsmanager`: Updates service documentation and examples + * Documentation updates +* `service/ssm`: Updates service API and documentation + * Added new APIs DeleteInventory and DescribeInventoryDeletions, for customers to delete their custom inventory data. + +Release v1.13.32 (2018-04-10) +=== + +### Service Client Updates +* `service/dms`: Updates service API and documentation + * Native Change Data Capture start point and task recovery support in Database Migration Service. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glue`: Updates service API and documentation + * "AWS Glue now supports timeout values for ETL jobs. With this release, all new ETL jobs have a default timeout value of 48 hours. AWS Glue also now supports the ability to start a schedule or job events trigger when it is created." +* `service/mediapackage`: Updates service API and documentation + * Adds a new OriginEndpoint package type CmafPackage in MediaPackage. Origin endpoints can now be configured to use the Common Media Application Format (CMAF) media streaming format. This version of CmafPackage only supports HTTP Live Streaming (HLS) manifests with fragmented MP4. +* `service/ssm`: Updates service API and documentation + * Added TooManyUpdates exception for AddTagsToResource and RemoveTagsFromResource API +* `service/workmail`: Updates service API, documentation, and paginators + * Amazon WorkMail adds the ability to grant users and groups with "Full Access", "Send As" and "Send on Behalf" permissions on a given mailbox. + +Release v1.13.31 (2018-04-09) +=== + +### Service Client Updates +* `service/clouddirectory`: Updates service API and documentation + * Cloud Directory customers can fetch attributes within a facet on an object with the new GetObjectAttributes API and can fetch attributes from multiple facets or objects with the BatchGetObjectAttributes operation. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.30 (2018-04-06) +=== + +### Service Client Updates +* `service/batch`: Updates service API and documentation + * Support for Timeout in SubmitJob and RegisterJobDefinition + +Release v1.13.29 (2018-04-05) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/ssm`: Updates service documentation + +Release v1.13.28 (2018-04-04) +=== + +### Service Client Updates +* `service/acm`: Updates service API and documentation + * AWS Certificate Manager has added support for AWS Certificate Manager Private Certificate Authority (CA). Customers can now request private certificates with the RequestCertificate API, and also export private certificates with the ExportCertificate API. +* `service/acm-pca`: Adds new service +* `service/config`: Updates service API and documentation +* `service/fms`: Adds new service +* `service/monitoring`: Updates service API and documentation + * The new GetMetricData API enables you to collect batch amounts of metric data and optionally perform math expressions on the data. With one GetMetricData call you can retrieve as many as 100 different metrics and a total of 100,800 data points. +* `service/s3`: Updates service API and documentation + * ONEZONE_IA storage class stores object data in only one Availability Zone at a lower price than STANDARD_IA. This SDK release provides API support for this new storage class. +* `service/sagemaker`: Updates service API and documentation + * SageMaker is now supporting many additional instance types in previously supported families for Notebooks, Training Jobs, and Endpoints. Training Jobs and Endpoints now support instances in the m5 family in addition to the previously supported instance families. For specific instance types supported please see the documentation for the SageMaker API. +* `service/secretsmanager`: Adds new service + * AWS Secrets Manager enables you to easily create and manage the secrets that you use in your customer-facing apps. Instead of embedding credentials into your source code, you can dynamically query Secrets Manager from your app whenever you need credentials. You can automatically and frequently rotate your secrets without having to deploy updates to your apps. All secret values are encrypted when they're at rest with AWS KMS, and while they're in transit with HTTPS and TLS. +* `service/transcribe`: Updates service API, documentation, and paginators + +Release v1.13.27 (2018-04-03) +=== + +### Service Client Updates +* `service/devicefarm`: Updates service API and documentation + * Added Private Device Management feature. Customers can now manage their private devices efficiently - view their status, set labels and apply profiles on them. Customers can also schedule automated tests and remote access sessions on individual instances in their private device fleet. +* `service/lambda`: Updates service API and documentation + * added nodejs8.10 as a valid runtime +* `service/translate`: Updates service API and documentation + +Release v1.13.26 (2018-04-02) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * Amazon API Gateway now supports resource policies for APIs making it easier to set access controls for invoking APIs. +* `service/cloudfront`: Adds new service + * You can now use a new Amazon CloudFront capability called Field-Level Encryption to further enhance the security of sensitive data, such as credit card numbers or personally identifiable information (PII) like social security numbers. CloudFront's field-level encryption further encrypts sensitive data in an HTTPS form using field-specific encryption keys (which you supply) before a POST request is forwarded to your origin. This ensures that sensitive data can only be decrypted and viewed by certain components or services in your application stack. Field-level encryption is easy to setup. Simply configure the fields that have to be further encrypted by CloudFront using the public keys you specify and you can reduce attack surface for your sensitive data. +* `service/es`: Updates service API and documentation + * This adds Amazon Cognito authentication support to Kibana. + +Release v1.13.25 (2018-03-30) +=== + +### Service Client Updates +* `service/acm`: Updates service API and documentation + * Documentation updates for acm +* `service/connect`: Adds new service +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.24 (2018-03-29) +=== + +### Service Client Updates +* `service/alexaforbusiness`: Updates service API, documentation, and paginators +* `service/cloudformation`: Updates service API and documentation + * Enabling resource level permission control for StackSets APIs. Adding support for customers to use customized AdministrationRole to create security boundaries between different users. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/greengrass`: Updates service API and documentation + * Greengrass APIs now support creating Machine Learning resource types and configuring binary data as the input payload for Greengrass Lambda functions. +* `service/ssm`: Updates service API + * This Patch Manager release supports creating patch baselines for CentOS. + +Release v1.13.23 (2018-03-28) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/iam`: Updates service API and documentation + * Add support for Longer Role Sessions. Four APIs manage max session duration: GetRole, ListRoles, CreateRole, and the new API UpdateRole. The max session duration integer attribute is measured in seconds. +* `service/mturk-requester`: Updates service API and documentation +* `service/sts`: Updates service API and documentation + * Change utilizes the Max Session Duration attribute introduced for IAM Roles and allows STS customers to request session duration up to the Max Session Duration of 12 hours from AssumeRole based APIs. + +Release v1.13.22 (2018-03-27) +=== + +### Service Client Updates +* `service/acm`: Updates service API and documentation + * AWS Certificate Manager has added support for customers to disable Certificate Transparency logging on a per-certificate basis. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.21 (2018-03-26) +=== + +### Service Client Updates +* `service/dynamodb`: Updates service API and documentation + * Point-in-time recovery (PITR) provides continuous backups of your DynamoDB table data. With PITR, you do not have to worry about creating, maintaining, or scheduling backups. You enable PITR on your table and your backup is available for restore at any point in time from the moment you enable it, up to a maximum of the 35 preceding days. PITR provides continuous backups until you explicitly disable it. For more information, see the Amazon DynamoDB Developer Guide. + +Release v1.13.20 (2018-03-23) +=== + +### Service Client Updates +* `service/rds`: Updates service documentation + * Documentation updates for RDS + +Release v1.13.19 (2018-03-22) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * Feedback URL allows admins to provide a feedback link or a survey link for collecting user feedback while streaming sessions. When a feedback link is provided, streaming users will see a "Send Feedback" choice in their streaming session toolbar. On selecting this choice, user will be redirected to the link provided in a new browser tab. If a feedback link is not provided, users will not see the "Send Feedback" option. +* `service/codebuild`: Updates service API and documentation + * Adding support for branch filtering when using webhooks with AWS CodeBuild. +* `service/ecs`: Updates service API and documentation + * Amazon Elastic Container Service (ECS) now includes integrated Service Discovery using Route 53 Auto Naming. Customers can now specify a Route 53 Auto Naming service as part of an ECS service. ECS will register task IPs with Route 53, making them available via DNS in your VPC. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +### SDK Bugs +* `aws/endpoints`: Use service metadata for fallback signing name ([#1854](https://github.com/aws/aws-sdk-go/pull/1854)) + * Updates the SDK's endpoint resolution to fallback deriving the service's signing name from the service's modeled metadata in addition the endpoints modeled data. + * Fixes [#1850](https://github.com/aws/aws-sdk-go/issues/1850) +Release v1.13.18 (2018-03-21) +=== + +### Service Client Updates +* `service/serverlessrepo`: Updates service documentation + +Release v1.13.17 (2018-03-20) +=== + +### Service Client Updates +* `service/ce`: Updates service API and documentation +* `service/config`: Updates service API and documentation +* `service/ecs`: Updates service API and documentation + * Amazon ECS users can now mount a temporary volume in memory in containers and specify the shared memory that a container can use through the use of docker's 'tmpfs' and 'shm-size' features respectively. These fields can be specified under linuxParameters in ContainerDefinition in the Task Definition Template. +* `service/elasticbeanstalk`: Updates service documentation + * Documentation updates for the new Elastic Beanstalk API DescribeAccountAttributes. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/events`: Updates service API and documentation + * Added SQS FIFO queue target support +* `service/glue`: Updates service API and documentation + * API Updates for DevEndpoint: PublicKey is now optional for CreateDevEndpoint. The new DevEndpoint field PrivateAddress will be populated for DevEndpoints associated with a VPC. +* `service/medialive`: Updates service API and documentation + * AWS Elemental MediaLive has added support for updating Inputs and Input Security Groups. You can update Input Security Groups at any time and it will update all channels using that Input Security Group. Inputs can be updated as long as they are not attached to a currently running channel. + +Release v1.13.16 (2018-03-16) +=== + +### Service Client Updates +* `service/elasticbeanstalk`: Updates service API and documentation + * AWS Elastic Beanstalk is launching a new public API named DescribeAccountAttributes which allows customers to access account level attributes. In this release, the API will support quotas for resources such as applications, application versions, and environments. + +Release v1.13.15 (2018-03-15) +=== + +### Service Client Updates +* `service/organizations`: Updates service API and documentation + * This release adds additional reason codes to improve clarity to exceptions that can occur. +* `service/pinpoint`: Updates service API and documentation + * With this release, you can delete endpoints from your Amazon Pinpoint projects. Customers can now specify one of their leased dedicated long or short codes to send text messages. +* `service/sagemaker`: Updates service API, documentation, and paginators + * This release provides support for ml.p3.xlarge instance types for notebook instances. Lifecycle configuration is now available to customize your notebook instances on start; the configuration can be reused between multiple notebooks. If a notebook instance is attached to a VPC you can now opt out of internet access that by default is provided by SageMaker. + +Release v1.13.14 (2018-03-14) +=== + +### Service Client Updates +* `service/lightsail`: Updates service API and documentation + * Updates to existing Lightsail documentation + +Release v1.13.13 (2018-03-13) +=== + +### Service Client Updates +* `service/servicediscovery`: Updates service API and documentation + * This release adds support for custom health checks, which let you check the health of resources that aren't accessible over the internet. For example, you can use a custom health check when the instance is in an Amazon VPC. + +Release v1.13.12 (2018-03-12) +=== + +### Service Client Updates +* `service/cloudhsmv2`: Updates service API + * CreateCluster can now take both 8 and 17 character Subnet IDs. DeleteHsm can now take both 8 and 17 character ENI IDs. +* `service/discovery`: Updates service API and documentation + * Documentation updates for discovery +* `service/iot`: Updates service API and documentation + * We added new fields to the response of the following APIs. (1) describe-certificate: added new generationId, customerVersion fields (2) describe-ca-certificate: added new generationId, customerVersion and lastModifiedDate fields (3) get-policy: added generationId, creationDate and lastModifiedDate fields +* `service/redshift`: Updates service API and documentation + * DescribeClusterSnapshotsMessage with ClusterExists flag returns snapshots of existing clusters. Else both existing and deleted cluster snapshots are returned + +Release v1.13.11 (2018-03-08) +=== + +### Service Client Updates +* `service/AWSMigrationHub`: Updates service API and documentation +* `service/ecs`: Updates service API and documentation + * Amazon Elastic Container Service (ECS) now supports container health checks. Customers can now specify a docker container health check command and parameters in their task definition. ECS will monitor, report and take scheduling action based on the health status. +* `service/pinpoint`: Updates service API and documentation + * With this release, you can export endpoints from your Amazon Pinpoint projects. You can export a) all of the endpoints assigned to a project or b) the subset of endpoints assigned to a segment. +* `service/rds`: Updates service documentation + * Documentation updates for RDS + +Release v1.13.10 (2018-03-07) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/medialive`: Updates service API and documentation + * Updates API to model required traits and minimum/maximum constraints. + +Release v1.13.9 (2018-03-06) +=== + +### Service Client Updates +* `service/ecs`: Updates service documentation + * Documentation updates for Amazon ECS +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.8 (2018-03-01) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Added support for modifying Placement Group association of instances via ModifyInstancePlacement API. +* `service/events`: Updates service API and documentation + * Added BatchParameters to the PutTargets API +* `service/servicecatalog`: Updates service API and documentation + * This release of ServiceCatalog adds the DeleteTagOption API. +* `service/ssm`: Updates service API and documentation + * This Inventory release supports the status message details reported by the last sync for the resource data sync API. +* `service/storagegateway`: Updates service API and documentation + * AWS Storage Gateway (File) support for two new file share attributes are added. 1. Users can specify the S3 Canned ACL to use for new objects created in the file share. 2. Users can create file shares for requester-pays buckets. + +Release v1.13.7 (2018-02-28) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.6 (2018-02-27) +=== + +### Service Client Updates +* `service/ecr`: Updates service documentation + * Documentation updates for Amazon ECR. + +Release v1.13.5 (2018-02-26) +=== + +### Service Client Updates +* `service/route53`: Updates service API + * Added support for creating LBR rules using ap-northeast-3 region. +* `service/sts`: Updates service API and documentation + * Increased SAMLAssertion parameter size from 50000 to 100000 for AWS Security Token Service AssumeRoleWithSAML API to allow customers to pass bigger SAML assertions + +Release v1.13.4 (2018-02-23) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * This API update is to enable customers to copy their Amazon AppStream 2.0 images within and between AWS Regions +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.3 (2018-02-22) +=== + +### Service Client Updates +* `service/ce`: Updates service API and documentation +* `service/elasticloadbalancingv2`: Updates service documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.13.2 (2018-02-21) +=== + +### Service Client Updates +* `service/codecommit`: Updates service API and documentation + * This release adds an API for adding a file directly to an AWS CodeCommit repository without requiring a Git client. +* `service/ec2`: Updates service API and documentation + * Adds support for tagging an EBS snapshot as part of the API call that creates the EBS snapshot +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/serverlessrepo`: Updates service API, documentation, and paginators + +Release v1.13.1 (2018-02-20) +=== + +### Service Client Updates +* `service/autoscaling`: Updates service API and documentation + * Amazon EC2 Auto Scaling support for service-linked roles +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/waf`: Updates service API and documentation + * The new PermissionPolicy APIs in AWS WAF Regional allow customers to attach resource-based policies to their entities. +* `service/waf-regional`: Updates service API and documentation + +Release v1.13.0 (2018-02-19) +=== + +### Service Client Updates +* `service/config`: Updates service API + * With this release, AWS Config updated the ConfigurationItemStatus enum values. The values prior to this update did not represent appropriate values returned by GetResourceConfigHistory. You must update your code to enumerate the new enum values so this is a breaking change. To map old properties to new properties, use the following descriptions: New discovered resource - Old property: Discovered, New property: ResourceDiscovered. Updated resource - Old property: Ok, New property: OK. Deleted resource - Old property: Deleted, New property: ResourceDeleted or ResourceDeletedNotRecorded. Not-recorded resource - Old property: N/A, New property: ResourceNotRecorded or ResourceDeletedNotRecorded. + +Release v1.12.79 (2018-02-16) +=== + +### Service Client Updates +* `service/rds`: Updates service API and documentation + * Updates RDS API to indicate whether a DBEngine supports read replicas. + +Release v1.12.78 (2018-02-15) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/gamelift`: Updates service API and documentation + * Updates to allow Fleets to run on On-Demand or Spot instances. +* `service/mediaconvert`: Updates service API and documentation + * Nielsen ID3 tags can now be inserted into transport stream (TS) and HLS outputs. For more information on Nielsen configuration you can go to https://docs.aws.amazon.com/mediaconvert/latest/apireference/jobs.html#jobs-nielsenconfiguration + +Release v1.12.77 (2018-02-14) +=== + +### Service Client Updates +* `service/appsync`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lex-models`: Updates service API and documentation + +Release v1.12.76 (2018-02-13) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glacier`: Updates service documentation + * Documentation updates for glacier +* `service/route53`: Updates service API + * Added support for creating Private Hosted Zones and metric-based healthchecks in the ap-northeast-3 region for whitelisted customers. + +Release v1.12.75 (2018-02-12) +=== + +### Service Client Updates +* `service/cognito-idp`: Updates service API and documentation +* `service/ec2`: Updates service API and documentation + * Network interfaces now supply the following additional status of "associated" to better distinguish the current status. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/guardduty`: Updates service API and documentation + * Added PortProbeAction information to the Action section of the port probe-type finding. +* `service/kms`: Updates service API + * This release of AWS Key Management Service includes support for InvalidArnException in the RetireGrant API. +* `service/rds`: Updates service documentation + * Aurora MySQL now supports MySQL 5.7. + +Release v1.12.74 (2018-02-09) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Users can now better understand the longer ID opt-in status of their account using the two new APIs DescribeAggregateIdFormat and DescribePrincipalIdFormat +* `service/lex-models`: Updates service API and documentation +* `service/runtime.lex`: Updates service API and documentation + +Release v1.12.73 (2018-02-08) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * Adds support for allowing customers to provide a redirect URL for a stack. Users will be redirected to the link provided by the admin at the end of their streaming session. +* `service/budgets`: Updates service API and documentation + * Making budgetLimit and timePeriod optional, and updating budgets docs. +* `service/dms`: Updates service API, documentation, and paginators + * This release includes the addition of two new APIs: describe replication instance task logs and reboot instance. The first allows user to see how much storage each log for a task on a given instance is occupying. The second gives users the option to reboot the application software on the instance and force a fail over for MAZ instances to test robustness of their integration with our service. +* `service/ds`: Updates service API + * Updated the regex of some input parameters to support longer EC2 identifiers. +* `service/dynamodb`: Updates service API and documentation + * Amazon DynamoDB now supports server-side encryption using a default service key (alias/aws/dynamodb) from the AWS Key Management Service (KMS). AWS KMS is a service that combines secure, highly available hardware and software to provide a key management system scaled for the cloud. AWS KMS is used via the AWS Management Console or APIs to centrally create encryption keys, define the policies that control how keys can be used, and audit key usage to prove they are being used correctly. For more information, see the Amazon DynamoDB Developer Guide. +* `service/gamelift`: Updates service API and documentation + * Amazon GameLift FlexMatch added the StartMatchBackfill API. This API allows developers to add new players to an existing game session using the same matchmaking rules and player data that were used to initially create the session. +* `service/medialive`: Updates service API and documentation + * AWS Elemental MediaLive has added support for updating channel settings for idle channels. You can now update channel name, channel outputs and output destinations, encoder settings, user role ARN, and input specifications. Channel settings can be updated in the console or with API calls. Please note that running channels need to be stopped before they can be updated. We've also deprecated the 'Reserved' field. +* `service/mediastore`: Updates service API and documentation + * AWS Elemental MediaStore now supports per-container CORS configuration. + +Release v1.12.72 (2018-02-07) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glue`: Updates service API and documentation + * This new feature will now allow customers to add a customized json classifier. They can specify a json path to indicate the object, array or field of the json documents they'd like crawlers to inspect when they crawl json files. +* `service/servicecatalog`: Updates service API, documentation, and paginators + * This release of Service Catalog adds SearchProvisionedProducts API and ProvisionedProductPlan APIs. +* `service/servicediscovery`: Updates service API and documentation + * This release adds support for registering CNAME record types and creating Route 53 alias records that route traffic to Amazon Elastic Load Balancers using Amazon Route 53 Auto Naming APIs. +* `service/ssm`: Updates service API and documentation + * This Patch Manager release supports configuring Linux repos as part of patch baselines, controlling updates of non-OS security packages and also creating patch baselines for SUSE12 + +### SDK Enhancements +* `private/model/api`: Add validation to ensure there is no duplication of services in models/apis ([#1758](https://github.com/aws/aws-sdk-go/pull/1758)) + * Prevents the SDK from mistakenly generating code a single service multiple times with different model versions. +* `example/service/ec2/instancesbyRegion`: Fix typos in example ([#1762](https://github.com/aws/aws-sdk-go/pull/1762)) +* `private/model/api`: removing SDK API reference crosslinks from input/output shapes. (#1765) + +### SDK Bugs +* `aws/session`: Fix bug in session.New not supporting AWS_SDK_LOAD_CONFIG ([#1770](https://github.com/aws/aws-sdk-go/pull/1770)) + * Fixes a bug in the session.New function that was not correctly sourcing the shared configuration files' path. + * Fixes [#1771](https://github.com/aws/aws-sdk-go/pull/1771) +Release v1.12.71 (2018-02-05) +=== + +### Service Client Updates +* `service/acm`: Updates service documentation + * Documentation updates for acm +* `service/cloud9`: Updates service documentation and examples + * API usage examples for AWS Cloud9. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/kinesis`: Updates service API and documentation + * Using ListShards a Kinesis Data Streams customer or client can get information about shards in a data stream (including meta-data for each shard) without obtaining data stream level information. +* `service/opsworks`: Updates service API, documentation, and waiters + * AWS OpsWorks Stacks supports EBS encryption and HDD volume types. Also, a new DescribeOperatingSystems API is available, which lists all operating systems supported by OpsWorks Stacks. + +Release v1.12.70 (2018-01-26) +=== + +### Service Client Updates +* `service/devicefarm`: Updates service API and documentation + * Add InteractionMode in CreateRemoteAccessSession for DirectDeviceAccess feature. +* `service/medialive`: Updates service API and documentation + * Add InputSpecification to CreateChannel (specification of input attributes is used for channel sizing and affects pricing); add NotFoundException to DeleteInputSecurityGroups. +* `service/mturk-requester`: Updates service documentation + +Release v1.12.69 (2018-01-26) +=== + +### SDK Bugs +* `models/api`: Fix colliding names [#1754](https://github.com/aws/aws-sdk-go/pull/1754) [#1756](https://github.com/aws/aws-sdk-go/pull/1756) + * SDK had duplicate folders that were causing errors in some builds. + * Fixes [#1753](https://github.com/aws/aws-sdk-go/issues/1753) +Release v1.12.68 (2018-01-25) +=== + +### Service Client Updates +* `service/alexaforbusiness`: Updates service API and documentation +* `service/codebuild`: Updates service API and documentation + * Adding support for Shallow Clone and GitHub Enterprise in AWS CodeBuild. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/guardduty`: Adds new service + * Added the missing AccessKeyDetails object to the resource shape. +* `service/lambda`: Updates service API and documentation + * AWS Lambda now supports Revision ID on your function versions and aliases, to track and apply conditional updates when you are updating your function version or alias resources. + +### SDK Bugs +* `service/s3/s3manager`: Fix check for nil OrigErr in Error() [#1749](https://github.com/aws/aws-sdk-go/issues/1749) + * S3 Manager's `Error` type did not check for nil of `OrigErr` when calling `Error()` + * Fixes [#1748](https://github.com/aws/aws-sdk-go/issues/1748) +Release v1.12.67 (2018-01-22) +=== + +### Service Client Updates +* `service/budgets`: Updates service API and documentation + * Add additional costTypes: IncludeDiscount, UseAmortized, to support finer control for different charges included in a cost budget. + +Release v1.12.66 (2018-01-19) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glue`: Updates service API and documentation + * New AWS Glue DataCatalog APIs to manage table versions and a new feature to skip archiving of the old table version when updating table. +* `service/transcribe`: Adds new service + +Release v1.12.65 (2018-01-18) +=== + +### Service Client Updates +* `service/sagemaker`: Updates service API and documentation + * CreateTrainingJob and CreateEndpointConfig now supports KMS Key for volume encryption. + +Release v1.12.64 (2018-01-17) +=== + +### Service Client Updates +* `service/autoscaling-plans`: Updates service documentation +* `service/ec2`: Updates service documentation + * Documentation updates for EC2 + +Release v1.12.63 (2018-01-17) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service API and documentation +* `service/autoscaling-plans`: Adds new service +* `service/rds`: Updates service API and documentation + * With this release you can now integrate RDS DB instances with CloudWatch Logs. We have added parameters to the operations for creating and modifying DB instances (for example CreateDBInstance) to allow you to take advantage of this capability through the CLI and API. Once you enable this feature, a stream of log events will publish to CloudWatch Logs for each log type you enable. + +Release v1.12.62 (2018-01-15) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lambda`: Updates service API and documentation + * Support for creating Lambda Functions using 'dotnetcore2.0' and 'go1.x'. + +Release v1.12.61 (2018-01-12) +=== + +### Service Client Updates +* `service/glue`: Updates service API and documentation + * Support is added to generate ETL scripts in Scala which can now be run by AWS Glue ETL jobs. In addition, the trigger API now supports firing when any conditions are met (in addition to all conditions). Also, jobs can be triggered based on a "failed" or "stopped" job run (in addition to a "succeeded" job run). + +Release v1.12.60 (2018-01-11) +=== + +### Service Client Updates +* `service/elasticloadbalancing`: Updates service API and documentation +* `service/elasticloadbalancingv2`: Updates service API and documentation +* `service/rds`: Updates service API and documentation + * Read Replicas for Amazon RDS for MySQL, MariaDB, and PostgreSQL now support Multi-AZ deployments.Amazon RDS Read Replicas enable you to create one or more read-only copies of your database instance within the same AWS Region or in a different AWS Region. Updates made to the source database are asynchronously copied to the Read Replicas. In addition to providing scalability for read-heavy workloads, you can choose to promote a Read Replica to become standalone a DB instance when needed.Amazon RDS Multi-AZ Deployments provide enhanced availability for database instances within a single AWS Region. With Multi-AZ, your data is synchronously replicated to a standby in a different Availability Zone (AZ). In case of an infrastructure failure, Amazon RDS performs an automatic failover to the standby, minimizing disruption to your applications.You can now combine Read Replicas with Multi-AZ as part of a disaster recovery strategy for your production databases. A well-designed and tested plan is critical for maintaining business continuity after a disaster. Since Read Replicas can also be created in different regions than the source database, your Read Replica can be promoted to become the new production database in case of a regional disruption.You can also combine Read Replicas with Multi-AZ for your database engine upgrade process. You can create a Read Replica of your production database instance and upgrade it to a new database engine version. When the upgrade is complete, you can stop applications, promote the Read Replica to a standalone database instance and switch over your applications. Since the database instance is already a Multi-AZ deployment, no additional steps are needed.For more information, see the Amazon RDS User Guide. +* `service/ssm`: Updates service documentation + * Updates documentation for the HierarchyLevelLimitExceededException error. + +Release v1.12.59 (2018-01-09) +=== + +### Service Client Updates +* `service/kms`: Updates service documentation + * Documentation updates for AWS KMS + +Release v1.12.58 (2018-01-09) +=== + +### Service Client Updates +* `service/ds`: Updates service API and documentation + * On October 24 we introduced AWS Directory Service for Microsoft Active Directory (Standard Edition), also known as AWS Microsoft AD (Standard Edition), which is a managed Microsoft Active Directory (AD) that is optimized for small and midsize businesses (SMBs). With this SDK release, you can now create an AWS Microsoft AD directory using API. This enables you to run typical SMB workloads using a cost-effective, highly available, and managed Microsoft AD in the AWS Cloud. + +Release v1.12.57 (2018-01-08) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service API and documentation + * The AWS CodeDeploy API was updated to support DeleteGitHubAccountToken, a new method that deletes a GitHub account connection. +* `service/discovery`: Updates service API and documentation + * Documentation updates for AWS Application Discovery Service. +* `service/route53`: Updates service API and documentation + * This release adds an exception to the CreateTrafficPolicyVersion API operation. + +Release v1.12.56 (2018-01-05) +=== + +### Service Client Updates +* `service/inspector`: Updates service API, documentation, and examples + * Added 2 new attributes to the DescribeAssessmentTemplate response, indicating the total number of assessment runs and last assessment run ARN (if present.) +* `service/snowball`: Updates service documentation + * Documentation updates for snowball +* `service/ssm`: Updates service documentation + * Documentation updates for ssm + +Release v1.12.55 (2018-01-02) +=== + +### Service Client Updates +* `service/rds`: Updates service documentation + * Documentation updates for rds + +Release v1.12.54 (2017-12-29) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/workspaces`: Updates service API and documentation + * Modify WorkSpaces have been updated with flexible storage and switching of hardware bundles feature. The following configurations have been added to ModifyWorkSpacesProperties: storage and compute. This update provides the capability to configure the storage of a WorkSpace. It also adds the capability of switching hardware bundle of a WorkSpace by specifying an eligible compute (Value, Standard, Performance, Power). + +Release v1.12.53 (2017-12-22) +=== + +### Service Client Updates +* `service/ec2`: Updates service API + * This release fixes an issue with tags not showing in DescribeAddresses responses. +* `service/ecs`: Updates service API and documentation + * Amazon ECS users can now set a health check initialization wait period of their ECS services, the services that are associated with an Elastic Load Balancer (ELB) will wait for a period of time before the ELB become healthy. You can now configure this in Create and Update Service. +* `service/inspector`: Updates service API and documentation + * PreviewAgents API now returns additional fields within the AgentPreview data type. The API now shows the agent health and availability status for all instances included in the assessment target. This allows users to check the health status of Inspector Agents before running an assessment. In addition, it shows the instance ID, hostname, and IP address of the targeted instances. +* `service/sagemaker`: Updates service API and documentation + * SageMaker Models no longer support SupplementalContainers. API's that have been affected are CreateModel and DescribeModel. + +Release v1.12.52 (2017-12-21) +=== + +### Service Client Updates +* `service/codebuild`: Updates service API and documentation + * Adding support allowing AWS CodeBuild customers to select specific curated image versions. +* `service/ec2`: Updates service API and documentation + * Elastic IP tagging enables you to add key and value metadata to your Elastic IPs so that you can search, filter, and organize them according to your organization's needs. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/kinesisanalytics`: Updates service API and documentation + * Kinesis Analytics now supports AWS Lambda functions as output. + +Release v1.12.51 (2017-12-21) +=== + +### Service Client Updates +* `service/config`: Updates service API +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/iot`: Updates service API and documentation + * This release adds support for code signed Over-the-air update functionality for Amazon FreeRTOS. Users can now create and schedule Over-the-air updates to their Amazon FreeRTOS devices using these new APIs. + +Release v1.12.50 (2017-12-19) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * API Gateway now adds support for calling API with compressed payloads using one of the supported content codings, tagging an API stage for cost allocation, and returning API keys from a custom authorizer for use with a usage plan. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/mediastore-data`: Updates service documentation +* `service/route53`: Updates service API and documentation + * Route 53 added support for a new China (Ningxia) region, cn-northwest-1. You can now specify cn-northwest-1 as the region for latency-based or geoproximity routing. Route 53 also added support for a new EU (Paris) region, eu-west-3. You can now associate VPCs in eu-west-3 with private hosted zones and create alias records that route traffic to resources in eu-west-3. + +Release v1.12.49 (2017-12-19) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/monitoring`: Updates service documentation + * Documentation updates for monitoring + +Release v1.12.48 (2017-12-15) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * This API update is to enable customers to add tags to their Amazon AppStream 2.0 resources + +Release v1.12.47 (2017-12-14) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * Adds support for Cognito Authorizer scopes at the API method level. +* `service/email`: Updates service documentation + * Added information about the maximum number of transactions per second for the SendCustomVerificationEmail operation. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.46 (2017-12-12) +=== + +### Service Client Updates +* `service/workmail`: Adds new service + * Today, Amazon WorkMail released an administrative SDK and enabled AWS CloudTrail integration. With the administrative SDK, you can natively integrate WorkMail with your existing services. The SDK enables programmatic user, resource, and group management through API calls. This means your existing IT tools and workflows can now automate WorkMail management, and third party applications can streamline WorkMail migrations and account actions. + +Release v1.12.45 (2017-12-11) +=== + +### Service Client Updates +* `service/cognito-idp`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lex-models`: Updates service API and documentation +* `service/sagemaker`: Updates service API + * CreateModel API Update: The request parameter 'ExecutionRoleArn' has changed from optional to required. + +Release v1.12.44 (2017-12-08) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * This API update is to support the feature that allows customers to automatically consume the latest Amazon AppStream 2.0 agent as and when published by AWS. +* `service/ecs`: Updates service documentation + * Documentation updates for Windows containers. +* `service/monitoring`: Updates service API and documentation + * With this launch, you can now create a CloudWatch alarm that alerts you when M out of N datapoints of a metric are breaching your predefined threshold, such as three out of five times in any given five minutes interval or two out of six times in a thirty minutes interval. When M out of N datapoints are not breaching your threshold in an interval, the alarm will be in OK state. Please note that the M datapoints out of N datapoints in an interval can be of any order and does not need to be consecutive. Consequently, you can now get alerted even when the spikes in your metrics are intermittent over an interval. + +Release v1.12.43 (2017-12-07) +=== + +### Service Client Updates +* `service/email`: Updates service API, documentation, and paginators + * Customers can customize the emails that Amazon SES sends when verifying new identities. This feature is helpful for developers whose applications send email through Amazon SES on behalf of their customers. +* `service/es`: Updates service API and documentation + * Added support for encryption of data at rest on Amazon Elasticsearch Service using AWS KMS + +### SDK Bugs +* `models/apis` Fixes removes colliding sagemaker models folders ([#1686](https://github.com/aws/aws-sdk-go/pull/1686)) + * Fixes Release v1.12.42's SageMaker vs sagemaker model folders. +Release v1.12.42 (2017-12-06) +=== + +### Service Client Updates +* `service/clouddirectory`: Updates service API and documentation + * Amazon Cloud Directory makes it easier for you to apply schema changes across your directories with in-place schema upgrades. Your directories now remain available while backward-compatible schema changes are being applied, such as the addition of new fields. You also can view the history of your schema changes in Cloud Directory by using both major and minor version identifiers, which can help you track and audit schema versions across directories. +* `service/elasticbeanstalk`: Updates service documentation + * Documentation updates for AWS Elastic Beanstalk. +* `service/sagemaker`: Adds new service + * Initial waiters for common SageMaker workflows. + +Release v1.12.41 (2017-12-05) +=== + +### Service Client Updates +* `service/iot`: Updates service API and documentation + * Add error action API for RulesEngine. +* `service/servicecatalog`: Updates service API and documentation + * ServiceCatalog has two distinct personas for its use, an "admin" persona (who creates sets of products with different versions and prescribes who has access to them) and an "end-user" persona (who can launch cloud resources based on the configuration data their admins have given them access to). This API update will allow admin users to deactivate/activate product versions, end-user will only be able to access and launch active product versions. +* `service/servicediscovery`: Adds new service + * Amazon Route 53 Auto Naming lets you configure public or private namespaces that your microservice applications run in. When instances of the service become available, you can call the Auto Naming API to register the instance, and Amazon Route 53 automatically creates up to five DNS records and an optional health check. Clients that submit DNS queries for the service receive an answer that contains up to eight healthy records. + +Release v1.12.40 (2017-12-04) +=== + +### Service Client Updates +* `service/budgets`: Updates service API and documentation + * Add additional costTypes to support finer control for different charges included in a cost budget. +* `service/ecs`: Updates service documentation + * Documentation updates for ecs + +Release v1.12.39 (2017-12-01) +=== + +### Service Client Updates +* `service/SageMaker`: Updates service waiters + +Release v1.12.38 (2017-11-30) +=== + +### Service Client Updates +* `service/AWSMoneypenny`: Adds new service +* `service/Cloud9`: Adds new service +* `service/Serverless Registry`: Adds new service +* `service/apigateway`: Updates service API, documentation, and paginators + * Added support Private Integration and VPC Link features in API Gateway. This allows to create an API with the API Gateway private integration, thus providing clients access to HTTP/HTTPS resources in an Amazon VPC from outside of the VPC through a VpcLink resource. +* `service/ec2`: Updates service API and documentation + * Adds the following updates: 1. Spread Placement ensures that instances are placed on distinct hardware in order to reduce correlated failures. 2. Inter-region VPC Peering allows customers to peer VPCs across different AWS regions without requiring additional gateways, VPN connections or physical hardware +* `service/lambda`: Updates service API and documentation + * AWS Lambda now supports the ability to set the concurrency limits for individual functions, and increasing memory to 3008 MB. + +Release v1.12.37 (2017-11-30) +=== + +### Service Client Updates +* `service/Ardi`: Adds new service +* `service/autoscaling`: Updates service API and documentation + * You can now use Auto Scaling with EC2 Launch Templates via the CreateAutoScalingGroup and UpdateAutoScalingGroup APIs. +* `service/ec2`: Updates service API and documentation + * Adds the following updates: 1. T2 Unlimited enables high CPU performance for any period of time whenever required 2. You are now able to create and launch EC2 m5 and h1 instances +* `service/lightsail`: Updates service API and documentation + * This release adds support for load balancer and TLS/SSL certificate management. This set of APIs allows customers to create, manage, and scale secure load balanced applications on Lightsail infrastructure. To provide support for customers who manage their DNS on Lightsail, we've added the ability create an Alias A type record which can point to a load balancer DNS name via the CreateDomainEntry API http://docs.aws.amazon.com/lightsail/2016-11-28/api-reference/API_CreateDomainEntry.html. +* `service/ssm`: Updates service API and documentation + * This release updates AWS Systems Manager APIs to enable executing automations at controlled rate, target resources in a resource groups and execute entire automation at once or single step at a time. It is now also possible to use YAML, in addition to JSON, when creating Systems Manager documents. +* `service/waf`: Updates service API and documentation + * This release adds support for rule group and managed rule group. Rule group is a container of rules that customers can create, put rules in it and associate the rule group to a WebACL. All rules in a rule group will function identically as they would if each rule was individually associated to the WebACL. Managed rule group is a pre-configured rule group composed by our security partners and made available via the AWS Marketplace. Customers can subscribe to these managed rule groups, associate the managed rule group to their WebACL and start using them immediately to protect their resources. +* `service/waf-regional`: Updates service API and documentation + +Release v1.12.36 (2017-11-29) +=== + +### Service Client Updates +* `service/DeepInsight`: Adds new service +* `service/IronmanRuntime`: Adds new service +* `service/Orchestra - Laser`: Adds new service +* `service/SageMaker`: Adds new service +* `service/Shine`: Adds new service +* `service/archived.kinesisvideo`: Adds new service +* `service/data.kinesisvideo`: Adds new service +* `service/dynamodb`: Updates service API and documentation + * Amazon DynamoDB now supports the following features: Global Table and On-Demand Backup. Global Table is a fully-managed, multi-region, multi-master database. DynamoDB customers can now write anywhere and read anywhere with single-digit millisecond latency by performing database operations closest to where end users reside. Global Table also enables customers to disaster-proof their applications, keeping them running and data accessible even in the face of natural disasters or region disruptions. Customers can set up Global Table with just a few clicks in the AWS Management Console-no application rewrites required. On-Demand Backup capability is to protect data from loss due to application errors, and meet customers' archival needs for compliance and regulatory reasons. Customers can backup and restore their DynamoDB table data anytime, with a single-click in the AWS management console or a single API call. Backup and restore actions execute with zero impact on table performance or availability. For more information, see the Amazon DynamoDB Developer Guide. +* `service/ecs`: Updates service API and documentation + * Amazon Elastic Container Service (Amazon ECS) released a new launch type for running containers on a serverless infrastructure. The Fargate launch type allows you to run your containerized applications without the need to provision and manage the backend infrastructure. Just register your task definition and Fargate launches the container for you. +* `service/glacier`: Updates service API and documentation + * This release includes support for Glacier Select, a new feature that allows you to filter and analyze your Glacier archives and store the results in a user-specified S3 location. +* `service/greengrass`: Updates service API and documentation + * Greengrass OTA feature allows updating Greengrass Core and Greengrass OTA Agent. Local Resource Access feature allows Greengrass Lambdas to access local resources such as peripheral devices and volumes. +* `service/iot`: Updates service API and documentation + * This release adds support for a number of new IoT features, including AWS IoT Device Management (Jobs, Fleet Index and Thing Registration), Thing Groups, Policies on Thing Groups, Registry & Job Events, JSON Logs, Fine-Grained Logging Controls, Custom Authorization and AWS Service Authentication Using X.509 Certificates. +* `service/kinesisvideo`: Adds new service + * Announcing Amazon Kinesis Video Streams, a fully managed video ingestion and storage service. Kinesis Video Streams makes it easy to securely stream video from connected devices to AWS for machine learning, analytics, and processing. You can also stream other time-encoded data like RADAR and LIDAR signals using Kinesis Video Streams. +* `service/rekognition`: Updates service API, documentation, and paginators + * This release introduces Amazon Rekognition support for video analysis. +* `service/s3`: Updates service API and documentation + * This release includes support for Glacier Select, a new feature that allows you to filter and analyze your Glacier storage class objects and store the results in a user-specified S3 location. + +Release v1.12.35 (2017-11-29) +=== + +### Service Client Updates +* `service/AmazonMQ`: Adds new service +* `service/GuardDuty`: Adds new service +* `service/apigateway`: Updates service API and documentation + * Changes related to CanaryReleaseDeployment feature. Enables API developer to create a deployment as canary deployment and test API changes with percentage of customers before promoting changes to all customers. +* `service/batch`: Updates service API and documentation + * Add support for Array Jobs which allow users to easily submit many copies of a job with a single API call. This change also enhances the job dependency model to support N_TO_N and sequential dependency chains. The ListJobs and DescribeJobs APIs now have the ability to list or describe the status of entire Array Jobs or individual elements within the array. +* `service/cognito-idp`: Updates service API and documentation +* `service/deepdish`: Adds new service + * AWS AppSync is an enterprise-level, fully managed GraphQL service with real-time data synchronization and offline programming features. +* `service/ec2`: Updates service API and documentation + * Adds the following updates: 1. You are now able to host a service powered by AWS PrivateLink to provide private connectivity to other VPCs. You are now also able to create endpoints to other services powered by PrivateLink including AWS services, Marketplace Seller services or custom services created by yourself or other AWS VPC customers. 2. You are now able to save launch parameters in a single template that can be used with Auto Scaling, Spot Fleet, Spot, and On Demand instances. 3. You are now able to launch Spot instances via the RunInstances API, using a single additional parameter. RunInstances will response synchronously with an instance ID should capacity be available for your Spot request. 4. A simplified Spot pricing model which delivers low, predictable prices that adjust gradually, based on long-term trends in supply and demand. 5. Amazon EC2 Spot can now hibernate Amazon EBS-backed instances in the event of an interruption, so your workloads pick up from where they left off. Spot can fulfill your request by resuming instances from a hibernated state when capacity is available. +* `service/lambda`: Updates service API and documentation + * Lambda aliases can now shift traffic between two function versions, based on preassigned weights. + +Release v1.12.34 (2017-11-27) +=== + +### Service Client Updates +* `service/data.mediastore`: Adds new service +* `service/mediaconvert`: Adds new service + * AWS Elemental MediaConvert is a file-based video conversion service that transforms media into formats required for traditional broadcast and for internet streaming to multi-screen devices. +* `service/medialive`: Adds new service + * AWS Elemental MediaLive is a video service that lets you easily create live outputs for broadcast and streaming delivery. +* `service/mediapackage`: Adds new service + * AWS Elemental MediaPackage is a just-in-time video packaging and origination service that lets you format highly secure and reliable live outputs for a variety of devices. +* `service/mediastore`: Adds new service + * AWS Elemental MediaStore is an AWS storage service optimized for media. It gives you the performance, consistency, and low latency required to deliver live and on-demand video content. AWS Elemental MediaStore acts as the origin store in your video workflow. + +Release v1.12.33 (2017-11-22) +=== + +### Service Client Updates +* `service/acm`: Updates service API and documentation + * AWS Certificate Manager now supports the ability to import domainless certs and additional Key Types as well as an additional validation method for DNS. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.32 (2017-11-22) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * Add support for Access logs and customizable integration timeouts +* `service/cloudformation`: Updates service API and documentation + * 1) Instance-level parameter overrides (CloudFormation-StackSet feature): This feature will allow the customers to override the template parameters on specific stackInstances. Customers will also have ability to update their existing instances with/without parameter-overrides using a new API "UpdateStackInstances" 2) Add support for SSM parameters in CloudFormation - This feature will allow the customers to use Systems Manager parameters in CloudFormation templates. They will be able to see values for these parameters in Describe APIs. +* `service/codebuild`: Updates service API and documentation + * Adding support for accessing Amazon VPC resources from AWS CodeBuild, dependency caching and build badges. +* `service/elasticmapreduce`: Updates service API and documentation + * Enable Kerberos on Amazon EMR. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rekognition`: Updates service API and documentation + * This release includes updates to Amazon Rekognition for the following APIs. The new DetectText API allows you to recognize and extract textual content from images. Face Model Versioning has been added to operations that deal with face detection. +* `service/shield`: Updates service API, documentation, and paginators + * The AWS Shield SDK has been updated in order to support Elastic IP address protections, the addition of AttackProperties objects in DescribeAttack responses, and a new GetSubscriptionState operation. +* `service/storagegateway`: Updates service API and documentation + * AWS Storage Gateway now enables you to get notification when all your files written to your NFS file share have been uploaded to Amazon S3. Storage Gateway also enables guessing of the MIME type for uploaded objects based on file extensions. +* `service/xray`: Updates service API, documentation, and paginators + * Added automatic pagination support for AWS X-Ray APIs in the SDKs that support this feature. + +Release v1.12.31 (2017-11-20) +=== + +### Service Client Updates +* `service/apigateway`: Updates service documentation + * Documentation updates for Apigateway +* `service/codecommit`: Updates service API, documentation, and paginators + * AWS CodeCommit now supports pull requests. You can use pull requests to collaboratively review code changes for minor changes or fixes, major feature additions, or new versions of your released software. +* `service/firehose`: Updates service API and documentation + * This release includes a new Kinesis Firehose feature that supports Splunk as Kinesis Firehose delivery destination. You can now use Kinesis Firehose to ingest real-time data to Splunk in a serverless, reliable, and salable manner. This release also includes a new feature that allows you to configure Lambda buffer size in Kinesis Firehose data transformation feature. You can now customize the data buffer size before invoking Lambda function in Kinesis Firehose for data transformation. This feature allows you to flexibly trade-off processing and delivery latency with cost and efficiency based on your specific use cases and requirements. +* `service/iis`: Adds new service + * The AWS Cost Explorer API gives customers programmatic access to AWS cost and usage information, allowing them to perform adhoc queries and build interactive cost management applications that leverage this dataset. +* `service/kinesis`: Updates service API and documentation + * Customers can now obtain the important characteristics of their stream with DescribeStreamSummary. The response will not include the shard list for the stream but will have the number of open shards, and all the other fields included in the DescribeStream response. +* `service/workdocs`: Updates service API and documentation + * DescribeGroups API and miscellaneous enhancements + +### SDK Bugs +* `aws/client`: Retry delays for throttled exception were not limited to 5 minutes [#1654](https://github.com/aws/aws-sdk-go/pull/1654) + * Fixes [#1653](https://github.com/aws/aws-sdk-go/issues/1653) +Release v1.12.30 (2017-11-17) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service API and documentation +* `service/dms`: Updates service API, documentation, and paginators + * Support for migration task assessment. Support for data validation after the migration. +* `service/elasticloadbalancingv2`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * Amazon RDS now supports importing MySQL databases by using backup files from Amazon S3. +* `service/s3`: Updates service API + * Added ORC to the supported S3 Inventory formats. + +### SDK Bugs +* `private/protocol/restjson`: Define JSONValue marshaling for body and querystring ([#1640](https://github.com/aws/aws-sdk-go/pull/1640)) + * Adds support for APIs which use JSONValue for body and querystring targets. + * Fixes [#1636](https://github.com/aws/aws-sdk-go/issues/1636) +Release v1.12.29 (2017-11-16) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service API and documentation +* `service/ec2`: Updates service API + * You are now able to create and launch EC2 x1e smaller instance sizes +* `service/glue`: Updates service API and documentation + * API update for AWS Glue. New crawler configuration attribute enables customers to specify crawler behavior. New XML classifier enables classification of XML data. +* `service/opsworkscm`: Updates service API, documentation, and waiters + * Documentation updates for OpsWorks-cm: a new feature, OpsWorks for Puppet Enterprise, that allows users to create and manage OpsWorks-hosted Puppet Enterprise servers. +* `service/organizations`: Updates service API, documentation, and paginators + * This release adds APIs that you can use to enable and disable integration with AWS services designed to work with AWS Organizations. This integration allows the AWS service to perform operations on your behalf on all of the accounts in your organization. Although you can use these APIs yourself, we recommend that you instead use the commands provided in the other AWS service to enable integration with AWS Organizations. +* `service/route53`: Updates service API and documentation + * You can use Route 53's GetAccountLimit/GetHostedZoneLimit/GetReusableDelegationSetLimit APIs to view your current limits (including custom set limits) on Route 53 resources such as hosted zones and health checks. These APIs also return the number of each resource you're currently using to enable comparison against your current limits. + +Release v1.12.28 (2017-11-15) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * 1. Extended GetDocumentationParts operation to support retrieving documentation parts resources without contents. 2. Added hosted zone ID in the custom domain response. +* `service/email`: Updates service API, documentation, and examples + * SES launches Configuration Set Reputation Metrics and Email Pausing Today, two features that build upon the capabilities of the reputation dashboard. The first is the ability to export reputation metrics for individual configuration sets. The second is the ability to temporarily pause email sending, either at the configuration set level, or across your entire Amazon SES account. +* `service/polly`: Updates service API + * Amazon Polly adds Korean language support with new female voice - "Seoyeon" and new Indian English female voice - "Aditi" +* `service/states`: Updates service API and documentation + * You can now use the UpdateStateMachine API to update your state machine definition and role ARN. Existing executions will continue to use the previous definition and role ARN. You can use the DescribeStateMachineForExecution API to determine which state machine definition and role ARN is associated with an execution + +Release v1.12.27 (2017-11-14) +=== + +### Service Client Updates +* `service/ecs`: Updates service API and documentation + * Added new mode for Task Networking in ECS, called awsvpc mode. Mode configuration parameters to be passed in via awsvpcConfiguration. Updated APIs now use/show this new mode - RegisterTaskDefinition, CreateService, UpdateService, RunTask, StartTask. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lightsail`: Updates service API and documentation + * Lightsail now supports attached block storage, which allows you to scale your applications and protect application data with additional SSD-backed storage disks. This feature allows Lightsail customers to attach secure storage disks to their Lightsail instances and manage their attached disks, including creating and deleting disks, attaching and detaching disks from instances, and backing up disks via snapshot. +* `service/route53`: Updates service API and documentation + * When a Route 53 health check or hosted zone is created by a linked AWS service, the object now includes information about the service that created it. Hosted zones or health checks that are created by a linked service can't be updated or deleted using Route 53. +* `service/ssm`: Updates service API and documentation + * EC2 Systems Manager GetInventory API adds support for aggregation. + +### SDK Enhancements +* `aws/request`: Remove default port from HTTP host header ([#1618](https://github.com/aws/aws-sdk-go/pull/1618)) + * Updates the SDK to automatically remove default ports based on the URL's scheme when setting the HTTP Host header's value. + * Fixes [#1537](https://github.com/aws/aws-sdk-go/issues/1537) + +Release v1.12.26 (2017-11-09) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Introduces the following features: 1. Create a default subnet in an Availability Zone if no default subnet exists. 2. Spot Fleet integrates with Elastic Load Balancing to enable you to attach one or more load balancers to a Spot Fleet request. When you attach the load balancer, it automatically registers the instance in the Spot Fleet to the load balancers which distributes incoming traffic across the instances. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.25 (2017-11-08) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service API and documentation +* `service/batch`: Updates service documentation + * Documentation updates for AWS Batch. +* `service/ec2`: Updates service API and documentation + * AWS PrivateLink for Amazon Services - Customers can now privately access Amazon services from their Amazon Virtual Private Cloud (VPC), without using public IPs, and without requiring the traffic to traverse across the Internet. +* `service/elasticache`: Updates service API and documentation + * This release adds online resharding for ElastiCache for Redis offering, providing the ability to add and remove shards from a running cluster. Developers can now dynamically scale-out or scale-in their Redis cluster workloads to adapt to changes in demand. ElastiCache will resize the cluster by adding or removing shards and redistribute hash slots uniformly across the new shard configuration, all while the cluster continues to stay online and serves requests. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.24 (2017-11-07) +=== + +### Service Client Updates +* `service/elasticloadbalancingv2`: Updates service documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * DescribeOrderableDBInstanceOptions now returns the minimum and maximum allowed values for storage size, total provisioned IOPS, and provisioned IOPS per GiB for a DB instance. +* `service/s3`: Updates service API, documentation, and examples + * This releases adds support for 4 features: 1. Default encryption for S3 Bucket, 2. Encryption status in inventory and Encryption support for inventory. 3. Cross region replication of KMS-encrypted objects, and 4. ownership overwrite for CRR. + +Release v1.12.23 (2017-11-07) +=== + +### Service Client Updates +* `service/api.pricing`: Adds new service +* `service/ec2`: Updates service API + * You are now able to create and launch EC2 C5 instances, the next generation of EC2's compute-optimized instances, in us-east-1, us-west-2 and eu-west-1. C5 instances offer up to 72 vCPUs, 144 GiB of DDR4 instance memory, 25 Gbps in Network bandwidth and improved EBS and Networking bandwidth on smaller instance sizes to deliver improved performance for compute-intensive workloads. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/kms`: Updates service API, documentation, and examples + * Documentation updates for AWS KMS. +* `service/organizations`: Updates service documentation + * This release updates permission statements for several API operations, and corrects some other minor errors. +* `service/states`: Updates service API, documentation, and paginators + * Documentation update. + +Release v1.12.22 (2017-11-03) +=== + +### Service Client Updates +* `service/ecs`: Updates service API and documentation + * Amazon ECS users can now add devices to their containers and enable init process in containers through the use of docker's 'devices' and 'init' features. These fields can be specified under linuxParameters in ContainerDefinition in the Task Definition Template. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.21 (2017-11-02) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * This release supports creating and managing Regional and Edge-Optimized API endpoints. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +### SDK Bugs +* `aws/request`: Fix bug in request presign creating invalid URL ([#1624](https://github.com/aws/aws-sdk-go/pull/1624)) + * Fixes a bug the Request Presign and PresignRequest methods that would allow a invalid expire duration as input. A expire time of 0 would be interpreted by the SDK to generate a normal request signature, not a presigned URL. This caused the returned URL unusable. + * Fixes [#1617](https://github.com/aws/aws-sdk-go/issues/1617) +Release v1.12.20 (2017-11-01) +=== + +### Service Client Updates +* `service/acm`: Updates service documentation + * Documentation updates for ACM +* `service/cloudhsmv2`: Updates service documentation + * Minor documentation update for AWS CloudHSM (cloudhsmv2). +* `service/directconnect`: Updates service API and documentation + * AWS DirectConnect now provides support for Global Access for Virtual Private Cloud (VPC) via a new feature called Direct Connect Gateway. A Direct Connect Gateway will allow you to group multiple Direct Connect Private Virtual Interfaces (DX-VIF) and Private Virtual Gateways (VGW) from different AWS regions (but belonging to the same AWS Account) and pass traffic from any DX-VIF to any VPC in the grouping. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +### SDK Enhancements +* `aws/client`: Adding status code 429 to throttlable status codes in default retryer (#1621) + +Release v1.12.19 (2017-10-26) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.18 (2017-10-26) +=== + +### Service Client Updates +* `service/cloudfront`: Updates service API and documentation + * You can now specify additional options for MinimumProtocolVersion, which controls the SSL/TLS protocol that CloudFront uses to communicate with viewers. The minimum protocol version that you choose also determines the ciphers that CloudFront uses to encrypt the content that it returns to viewers. +* `service/ec2`: Updates service API + * You are now able to create and launch EC2 P3 instance, next generation GPU instances, optimized for machine learning and high performance computing applications. With up to eight NVIDIA Tesla V100 GPUs, P3 instances provide up to one petaflop of mixed-precision, 125 teraflops of single-precision, and 62 teraflops of double-precision floating point performance, as well as a 300 GB/s second-generation NVLink interconnect that enables high-speed, low-latency GPU-to-GPU communication. P3 instances also feature up to 64 vCPUs based on custom Intel Xeon E5 (Broadwell) processors, 488 GB of DRAM, and 25 Gbps of dedicated aggregate network bandwidth using the Elastic Network Adapter (ENA). +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.17 (2017-10-24) +=== + +### Service Client Updates +* `service/config`: Updates service API +* `service/elasticache`: Updates service API, documentation, and examples + * Amazon ElastiCache for Redis today announced support for data encryption both for data in-transit and data at-rest. The new encryption in-transit functionality enables ElastiCache for Redis customers to encrypt data for all communication between clients and Redis engine, and all intra-cluster Redis communication. The encryption at-rest functionality allows customers to encrypt their S3 based backups. Customers can begin using the new functionality by simply enabling this functionality via AWS console, and a small configuration change in their Redis clients. The ElastiCache for Redis service automatically manages life cycle of the certificates required for encryption, including the issuance, renewal and expiration of certificates. Additionally, as part of this launch, customers will gain the ability to start using the Redis AUTH command that provides an added level of authentication. +* `service/glue`: Adds new service + * AWS Glue: Adding a new API, BatchStopJobRun, to stop one or more job runs for a specified Job. +* `service/pinpoint`: Updates service API and documentation + * Added support for APNs VoIP messages. Added support for collapsible IDs, message priority, and TTL for APNs and FCM/GCM. + +Release v1.12.16 (2017-10-23) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/organizations`: Updates service API and documentation + * This release supports integrating other AWS services with AWS Organizations through the use of an IAM service-linked role called AWSServiceRoleForOrganizations. Certain operations automatically create that role if it does not already exist. + +Release v1.12.15 (2017-10-20) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Adding pagination support for DescribeSecurityGroups for EC2 Classic and VPC Security Groups + +Release v1.12.14 (2017-10-19) +=== + +### Service Client Updates +* `service/sqs`: Updates service API and documentation + * Added support for tracking cost allocation by adding, updating, removing, and listing the metadata tags of Amazon SQS queues. +* `service/ssm`: Updates service API and documentation + * EC2 Systems Manager versioning support for Parameter Store. Also support for referencing parameter versions in SSM Documents. + +Release v1.12.13 (2017-10-18) +=== + +### Service Client Updates +* `service/lightsail`: Updates service API and documentation + * This release adds support for Windows Server-based Lightsail instances. The GetInstanceAccessDetails API now returns the password of your Windows Server-based instance when using the default key pair. GetInstanceAccessDetails also returns a PasswordData object for Windows Server instances containing the ciphertext and keyPairName. The Blueprint data type now includes a list of platform values (LINUX_UNIX or WINDOWS). The Bundle data type now includes a list of SupportedPlatforms values (LINUX_UNIX or WINDOWS). + +Release v1.12.12 (2017-10-17) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/es`: Updates service API and documentation + * This release adds support for VPC access to Amazon Elasticsearch Service. + * This release adds support for VPC access to Amazon Elasticsearch Service. + +Release v1.12.11 (2017-10-16) +=== + +### Service Client Updates +* `service/cloudhsm`: Updates service API and documentation + * Documentation updates for AWS CloudHSM Classic. +* `service/ec2`: Updates service API and documentation + * You can now change the tenancy of your VPC from dedicated to default with a single API operation. For more details refer to the documentation for changing VPC tenancy. +* `service/es`: Updates service API and documentation + * AWS Elasticsearch adds support for enabling slow log publishing. Using slow log publishing options customers can configure and enable index/query slow log publishing of their domain to preferred AWS Cloudwatch log group. +* `service/rds`: Updates service API and waiters + * Adds waiters for DBSnapshotAvailable and DBSnapshotDeleted. +* `service/waf`: Updates service API and documentation + * This release adds support for regular expressions as match conditions in rules, and support for geographical location by country of request IP address as a match condition in rules. +* `service/waf-regional`: Updates service API and documentation + +Release v1.12.10 (2017-10-12) +=== + +### Service Client Updates +* `service/codecommit`: Updates service API and documentation + * This release includes the DeleteBranch API and a change to the contents of a Commit object. +* `service/dms`: Updates service API and documentation + * This change includes addition of new optional parameter to an existing API +* `service/elasticbeanstalk`: Updates service API and documentation + * Added the ability to add, delete or update Tags +* `service/polly`: Updates service API + * Amazon Polly exposes two new voices: "Matthew" (US English) and "Takumi" (Japanese) +* `service/rds`: Updates service API and documentation + * You can now call DescribeValidDBInstanceModifications to learn what modifications you can make to your DB instance. You can use this information when you call ModifyDBInstance. + +Release v1.12.9 (2017-10-11) +=== + +### Service Client Updates +* `service/ecr`: Updates service API, documentation, and paginators + * Adds support for new API set used to manage Amazon ECR repository lifecycle policies. Amazon ECR lifecycle policies enable you to specify the lifecycle management of images in a repository. The configuration is a set of one or more rules, where each rule defines an action for Amazon ECR to apply to an image. This allows the automation of cleaning up unused images, for example expiring images based on age or status. A lifecycle policy preview API is provided as well, which allows you to see the impact of a lifecycle policy on an image repository before you execute it +* `service/email`: Updates service API and documentation + * Added content related to email template management and templated email sending operations. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.12.8 (2017-10-10) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * This release includes updates to AWS Virtual Private Gateway. +* `service/elasticloadbalancingv2`: Updates service API and documentation +* `service/opsworkscm`: Updates service API and documentation + * Provide engine specific information for node associations. + +Release v1.12.7 (2017-10-06) +=== + +### Service Client Updates +* `service/sqs`: Updates service documentation + * Documentation updates regarding availability of FIFO queues and miscellaneous corrections. + +Release v1.12.6 (2017-10-05) +=== + +### Service Client Updates +* `service/redshift`: Updates service API and documentation + * DescribeEventSubscriptions API supports tag keys and tag values as request parameters. + +Release v1.12.5 (2017-10-04) +=== + +### Service Client Updates +* `service/kinesisanalytics`: Updates service API and documentation + * Kinesis Analytics now supports schema discovery on objects in S3. Additionally, Kinesis Analytics now supports input data preprocessing through Lambda. +* `service/route53domains`: Updates service API and documentation + * Added a new API that checks whether a domain name can be transferred to Amazon Route 53. + +### SDK Bugs +* `service/s3/s3crypto`: Correct PutObjectRequest documentation ([#1568](https://github.com/aws/aws-sdk-go/pull/1568)) + * s3Crypto's PutObjectRequest docstring example was using an incorrect value. Corrected the type used in the example. +Release v1.12.4 (2017-10-03) +=== + +### Service Client Updates +* `service/ec2`: Updates service API, documentation, and waiters + * This release includes service updates to AWS VPN. +* `service/ssm`: Updates service API and documentation + * EC2 Systems Manager support for tagging SSM Documents. Also support for tag-based permissions to restrict access to SSM Documents based on these tags. + +Release v1.12.3 (2017-10-02) +=== + +### Service Client Updates +* `service/cloudhsm`: Updates service documentation and paginators + * Documentation updates for CloudHSM + +Release v1.12.2 (2017-09-29) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * Includes APIs for managing and accessing image builders, and deleting images. +* `service/codebuild`: Updates service API and documentation + * Adding support for Building GitHub Pull Requests in AWS CodeBuild +* `service/mturk-requester`: Updates service API and documentation +* `service/organizations`: Updates service API and documentation + * This release flags the HandshakeParty structure's Type and Id fields as 'required'. They effectively were required in the past, as you received an error if you did not include them. This is now reflected at the API definition level. +* `service/route53`: Updates service API and documentation + * This change allows customers to reset elements of health check. + +### SDK Bugs +* `private/protocol/query`: Fix query protocol handling of nested byte slices ([#1557](https://github.com/aws/aws-sdk-go/issues/1557)) + * Fixes the query protocol to correctly marshal nested []byte values of API operations. +* `service/s3`: Fix PutObject and UploadPart API to include ContentMD5 field ([#1559](https://github.com/aws/aws-sdk-go/pull/1559)) + * Fixes the SDK's S3 PutObject and UploadPart API code generation to correctly render the ContentMD5 field into the associated input types for these two API operations. + * Fixes [#1553](https://github.com/aws/aws-sdk-go/pull/1553) +Release v1.12.1 (2017-09-27) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/pinpoint`: Updates service API and documentation + * Added two new push notification channels: Amazon Device Messaging (ADM) and, for push notification support in China, Baidu Cloud Push. Added support for APNs auth via .p8 key file. Added operation for direct message deliveries to user IDs, enabling you to message an individual user on multiple endpoints. + +Release v1.12.0 (2017-09-26) +=== + +### SDK Bugs +* `API Marshaler`: Revert REST JSON and XML protocol marshaler improvements + * Bug [#1550](https://github.com/aws/aws-sdk-go/issues/1550) identified a missed condition in the Amazon Route 53 RESTXML protocol marshaling causing requests to that service to fail. Reverting the marshaler improvements until the bug can be fixed. + +Release v1.11.0 (2017-09-26) +=== + +### Service Client Updates +* `service/cloudformation`: Updates service API and documentation + * You can now prevent a stack from being accidentally deleted by enabling termination protection on the stack. If you attempt to delete a stack with termination protection enabled, the deletion fails and the stack, including its status, remains unchanged. You can enable termination protection on a stack when you create it. Termination protection on stacks is disabled by default. After creation, you can set termination protection on a stack whose status is CREATE_COMPLETE, UPDATE_COMPLETE, or UPDATE_ROLLBACK_COMPLETE. + +### SDK Features +* Add dep Go dependency management metadata files (#1544) + * Adds the Go `dep` dependency management metadata files to the SDK. + * Fixes [#1451](https://github.com/aws/aws-sdk-go/issues/1451) + * Fixes [#634](https://github.com/aws/aws-sdk-go/issues/634) +* `service/dynamodb/expression`: Add expression building utility for DynamoDB ([#1527](https://github.com/aws/aws-sdk-go/pull/1527)) + * Adds a new package, expression, to the SDK providing builder utilities to create DynamoDB expressions safely taking advantage of type safety. +* `API Marshaler`: Add generated marshalers for RESTXML protocol ([#1409](https://github.com/aws/aws-sdk-go/pull/1409)) + * Updates the RESTXML protocol marshaler to use generated code instead of reflection for REST XML based services. +* `API Marshaler`: Add generated marshalers for RESTJSON protocol ([#1547](https://github.com/aws/aws-sdk-go/pull/1547)) + * Updates the RESTJSON protocol marshaler to use generated code instead of reflection for REST JSON based services. + +### SDK Enhancements +* `private/protocol`: Update format of REST JSON and XMl benchmarks ([#1546](https://github.com/aws/aws-sdk-go/pull/1546)) + * Updates the format of the REST JSON and XML benchmarks to be readable. RESTJSON benchmarks were updated to more accurately bench building of the protocol. + +Release v1.10.51 (2017-09-22) +=== + +### Service Client Updates +* `service/config`: Updates service API and documentation +* `service/ecs`: Updates service API and documentation + * Amazon ECS users can now add and drop Linux capabilities to their containers through the use of docker's cap-add and cap-drop features. Customers can specify the capabilities they wish to add or drop for each container in their task definition. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service documentation + * Documentation updates for rds + +Release v1.10.50 (2017-09-21) +=== + +### Service Client Updates +* `service/budgets`: Updates service API + * Including "DuplicateRecordException" in UpdateNotification and UpdateSubscriber. +* `service/ec2`: Updates service API and documentation + * Add EC2 APIs to copy Amazon FPGA Images (AFIs) within the same region and across multiple regions, delete AFIs, and modify AFI attributes. AFI attributes include name, description and granting/denying other AWS accounts to load the AFI. +* `service/logs`: Updates service API and documentation + * Adds support for associating LogGroups with KMS Keys. + +### SDK Bugs +* Fix greengrass service model being duplicated with different casing. ([#1541](https://github.com/aws/aws-sdk-go/pull/1541)) + * Fixes [#1540](https://github.com/aws/aws-sdk-go/issues/1540) + * Fixes [#1539](https://github.com/aws/aws-sdk-go/issues/1539) +Release v1.10.49 (2017-09-20) +=== + +### Service Client Updates +* `service/Greengrass`: Adds new service +* `service/appstream`: Updates service API and documentation + * API updates for supporting On-Demand fleets. +* `service/codepipeline`: Updates service API and documentation + * This change includes a PipelineMetadata object that is part of the output from the GetPipeline API that includes the Pipeline ARN, created, and updated timestamp. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * Introduces the --option-group-name parameter to the ModifyDBSnapshot CLI command. You can specify this parameter when you upgrade an Oracle DB snapshot. The same option group considerations apply when upgrading a DB snapshot as when upgrading a DB instance. For more information, see http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Oracle.html#USER_UpgradeDBInstance.Oracle.OGPG.OG +* `service/runtime.lex`: Updates service API and documentation + +Release v1.10.48 (2017-09-19) +=== + +### Service Client Updates +* `service/ec2`: Updates service API + * Fixed bug in EC2 clients preventing ElasticGpuSet from being set. + +### SDK Enhancements +* `aws/credentials`: Add EnvProviderName constant. ([#1531](https://github.com/aws/aws-sdk-go/issues/1531)) + * Adds the "EnvConfigCredentials" string literal as EnvProviderName constant. + * Fixes [#1444](https://github.com/aws/aws-sdk-go/issues/1444) + +Release v1.10.47 (2017-09-18) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Amazon EC2 now lets you opt for Spot instances to be stopped in the event of an interruption instead of being terminated. Your Spot request can be fulfilled again by restarting instances from a previously stopped state, subject to availability of capacity at or below your preferred price. When you submit a persistent Spot request, you can choose from "terminate" or "stop" as the instance interruption behavior. Choosing "stop" will shutdown your Spot instances so you can continue from this stopped state later on. This feature is only available for instances with Amazon EBS volume as their root device. +* `service/email`: Updates service API and documentation + * Amazon Simple Email Service (Amazon SES) now lets you customize the domains used for tracking open and click events. Previously, open and click tracking links referred to destinations hosted on domains operated by Amazon SES. With this feature, you can use your own branded domains for capturing open and click events. +* `service/iam`: Updates service API and documentation + * A new API, DeleteServiceLinkedRole, submits a service-linked role deletion request and returns a DeletionTaskId, which you can use to check the status of the deletion. + +Release v1.10.46 (2017-09-15) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * Add a new enum "REQUEST" to '--type ' field in the current create-authorizer API, and make "identitySource" optional. + +Release v1.10.45 (2017-09-14) +=== + +### Service Client Updates +* `service/codebuild`: Updates service API and documentation + * Supporting Parameter Store in environment variables for AWS CodeBuild +* `service/organizations`: Updates service documentation + * Documentation updates for AWS Organizations +* `service/servicecatalog`: Updates service API, documentation, and paginators + * This release of Service Catalog adds API support to copy products. + +Release v1.10.44 (2017-09-13) +=== + +### Service Client Updates +* `service/autoscaling`: Updates service API and documentation + * Customers can create Life Cycle Hooks at the time of creating Auto Scaling Groups through the CreateAutoScalingGroup API +* `service/batch`: Updates service documentation and examples + * Documentation updates for batch +* `service/ec2`: Updates service API + * You are now able to create and launch EC2 x1e.32xlarge instance, a new EC2 instance in the X1 family, in us-east-1, us-west-2, eu-west-1, and ap-northeast-1. x1e.32xlarge offers 128 vCPUs, 3,904 GiB of DDR4 instance memory, high memory bandwidth, large L3 caches, and leading reliability capabilities to boost the performance and reliability of in-memory applications. +* `service/events`: Updates service API and documentation + * Exposes ConcurrentModificationException as one of the valid exceptions for PutPermission and RemovePermission operation. + +### SDK Enhancements +* `service/autoscaling`: Fix documentation for PutScalingPolicy.AutoScalingGroupName [#1522](https://github.com/aws/aws-sdk-go/pull/1522) +* `service/s3/s3manager`: Clarify S3 Upload manager Concurrency config [#1521](https://github.com/aws/aws-sdk-go/pull/1521) + * Fixes [#1458](https://github.com/aws/aws-sdk-go/issues/1458) +* `service/dynamodb/dynamodbattribute`: Add support for time alias. [#1520](https://github.com/aws/aws-sdk-go/pull/1520) + * Related to [#1505](https://github.com/aws/aws-sdk-go/pull/1505) + +Release v1.10.43 (2017-09-12) +=== + +### Service Client Updates +* `service/ec2`: Updates service API + * Fixed bug in EC2 clients preventing HostOfferingSet from being set +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.10.42 (2017-09-12) +=== + +### Service Client Updates +* `service/devicefarm`: Updates service API and documentation + * DeviceFarm has added support for two features - RemoteDebugging and Customer Artifacts. Customers can now do remote Debugging on their Private Devices and can now retrieve custom files generated by their tests on the device and the device host (execution environment) on both public and private devices. + +Release v1.10.41 (2017-09-08) +=== + +### Service Client Updates +* `service/logs`: Updates service API and documentation + * Adds support for the PutResourcePolicy, DescribeResourcePolicy and DeleteResourcePolicy APIs. + +Release v1.10.40 (2017-09-07) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service documentation +* `service/ec2`: Updates service API and documentation + * With Tagging support, you can add Key and Value metadata to search, filter and organize your NAT Gateways according to your organization's needs. +* `service/elasticloadbalancingv2`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lex-models`: Updates service API and documentation +* `service/route53`: Updates service API and documentation + * You can configure Amazon Route 53 to log information about the DNS queries that Amazon Route 53 receives for your domains and subdomains. When you configure query logging, Amazon Route 53 starts to send logs to CloudWatch Logs. You can use various tools, including the AWS console, to access the query logs. + +Release v1.10.39 (2017-09-06) +=== + +### Service Client Updates +* `service/budgets`: Updates service API and documentation + * Add an optional "thresholdType" to notifications to support percentage or absolute value thresholds. + +Release v1.10.38 (2017-09-05) +=== + +### Service Client Updates +* `service/codestar`: Updates service API and documentation + * Added support to tag CodeStar projects. Tags can be used to organize and find CodeStar projects on key-value pairs that you can choose. For example, you could add a tag with a key of "Release" and a value of "Beta" to projects your organization is working on for an upcoming beta release. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.10.37 (2017-09-01) +=== + +### Service Client Updates +* `service/MobileHub`: Adds new service +* `service/gamelift`: Updates service API and documentation + * GameLift VPC resources can be peered with any other AWS VPC. R4 memory-optimized instances now available to deploy. +* `service/ssm`: Updates service API and documentation + * Adding KMS encryption support to SSM Inventory Resource Data Sync. Exposes the ClientToken parameter on SSM StartAutomationExecution to provide idempotent execution requests. + +Release v1.10.36 (2017-08-31) +=== + +### Service Client Updates +* `service/codebuild`: Updates service API, documentation, and examples + * The AWS CodeBuild HTTP API now provides the BatchDeleteBuilds operation, which enables you to delete existing builds. +* `service/ec2`: Updates service API and documentation + * Descriptions for Security Group Rules enables customers to be able to define a description for ingress and egress security group rules . The Descriptions for Security Group Rules feature supports one description field per Security Group rule for both ingress and egress rules . Descriptions for Security Group Rules provides a simple way to describe the purpose or function of a Security Group Rule allowing for easier customer identification of configuration elements . Prior to the release of Descriptions for Security Group Rules , customers had to maintain a separate system outside of AWS if they wanted to track Security Group Rule mapping and their purpose for being implemented. If a security group rule has already been created and you would like to update or change your description for that security group rule you can use the UpdateSecurityGroupRuleDescription API. +* `service/elasticloadbalancingv2`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lex-models`: Updates service API and documentation + +### SDK Bugs +* `aws/signer/v4`: Revert [#1491](https://github.com/aws/aws-sdk-go/issues/1491) as change conflicts with an undocumented AWS v4 signature test case. + * Related to: [#1495](https://github.com/aws/aws-sdk-go/issues/1495). +Release v1.10.35 (2017-08-30) +=== + +### Service Client Updates +* `service/application-autoscaling`: Updates service API and documentation +* `service/organizations`: Updates service API and documentation + * The exception ConstraintViolationException now contains a new reason subcode MASTERACCOUNT_MISSING_CONTACT_INFO to make it easier to understand why attempting to remove an account from an Organization can fail. We also improved several other of the text descriptions and examples. + +Release v1.10.34 (2017-08-29) +=== + +### Service Client Updates +* `service/config`: Updates service API and documentation +* `service/ec2`: Updates service API and documentation + * Provides capability to add secondary CIDR blocks to a VPC. + +### SDK Bugs +* `aws/signer/v4`: Fix Signing Unordered Multi Value Query Parameters ([#1491](https://github.com/aws/aws-sdk-go/pull/1491)) + * Removes sorting of query string values when calculating v4 signing as this is not part of the spec. The spec only requires the keys, not values, to be sorted which is achieved by Query.Encode(). +Release v1.10.33 (2017-08-25) +=== + +### Service Client Updates +* `service/cloudformation`: Updates service API and documentation + * Rollback triggers enable you to have AWS CloudFormation monitor the state of your application during stack creation and updating, and to roll back that operation if the application breaches the threshold of any of the alarms you've specified. +* `service/gamelift`: Updates service API + * Update spelling of MatchmakingTicket status values for internal consistency. +* `service/rds`: Updates service API and documentation + * Option group options now contain additional properties that identify requirements for certain options. Check these properties to determine if your DB instance must be in a VPC or have auto minor upgrade turned on before you can use an option. Check to see if you can downgrade the version of an option after you have installed it. + +### SDK Enhancements +* `example/service/ec2`: Add EC2 list instances example ([#1492](https://github.com/aws/aws-sdk-go/pull/1492)) + +Release v1.10.32 (2017-08-25) +=== + +### Service Client Updates +* `service/rekognition`: Updates service API, documentation, and examples + * Update the enum value of LandmarkType and GenderType to be consistent with service response + +Release v1.10.31 (2017-08-23) +=== + +### Service Client Updates +* `service/appstream`: Updates service documentation + * Documentation updates for appstream +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.10.30 (2017-08-22) +=== + +### Service Client Updates +* `service/ssm`: Updates service API and documentation + * Changes to associations in Systems Manager State Manager can now be recorded. Previously, when you edited associations, you could not go back and review older association settings. Now, associations are versioned, and can be named using human-readable strings, allowing you to see a trail of association changes. You can also perform rate-based scheduling, which allows you to schedule associations more granularly. + +Release v1.10.29 (2017-08-21) +=== + +### Service Client Updates +* `service/firehose`: Updates service API, documentation, and paginators + * This change will allow customers to attach a Firehose delivery stream to an existing Kinesis stream directly. You no longer need a forwarder to move data from a Kinesis stream to a Firehose delivery stream. You can now run your streaming applications on your Kinesis stream and easily attach a Firehose delivery stream to it for data delivery to S3, Redshift, or Elasticsearch concurrently. +* `service/route53`: Updates service API and documentation + * Amazon Route 53 now supports CAA resource record type. A CAA record controls which certificate authorities are allowed to issue certificates for the domain or subdomain. + +Release v1.10.28 (2017-08-18) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.10.27 (2017-08-16) +=== + +### Service Client Updates +* `service/gamelift`: Updates service API and documentation + * The Matchmaking Grouping Service is a new feature that groups player match requests for a given game together into game sessions based on developer configured rules. + +### SDK Enhancements +* `aws/arn`: aws/arn: Package for parsing and producing ARNs ([#1463](https://github.com/aws/aws-sdk-go/pull/1463)) + * Adds the `arn` package for AWS ARN parsing and building. Use this package to build AWS ARNs for services such as outlined in the [documentation](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). + +### SDK Bugs +* `aws/signer/v4`: Correct V4 presign signature to include content sha25 in URL ([#1469](https://github.com/aws/aws-sdk-go/pull/1469)) + * Updates the V4 signer so that when a Presign is generated the `X-Amz-Content-Sha256` header is added to the query string instead of being required to be in the header. This allows you to generate presigned URLs for GET requests, e.g S3.GetObject that do not require additional headers to be set by the downstream users of the presigned URL. + * Related To: [#1467](https://github.com/aws/aws-sdk-go/issues/1467) + +Release v1.10.26 (2017-08-15) +=== + +### Service Client Updates +* `service/ec2`: Updates service API + * Fixed bug in EC2 clients preventing HostReservation from being set +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.10.25 (2017-08-14) +=== + +### Service Client Updates +* `service/AWS Glue`: Adds new service +* `service/batch`: Updates service API and documentation + * This release enhances the DescribeJobs API to include the CloudWatch logStreamName attribute in ContainerDetail and ContainerDetailAttempt +* `service/cloudhsmv2`: Adds new service + * CloudHSM provides hardware security modules for protecting sensitive data and cryptographic keys within an EC2 VPC, and enable the customer to maintain control over key access and use. This is a second-generation of the service that will improve security, lower cost and provide better customer usability. +* `service/elasticfilesystem`: Updates service API, documentation, and paginators + * Customers can create encrypted EFS file systems and specify a KMS master key to encrypt it with. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/mgh`: Adds new service + * AWS Migration Hub provides a single location to track migrations across multiple AWS and partner solutions. Using Migration Hub allows you to choose the AWS and partner migration tools that best fit your needs, while providing visibility into the status of your entire migration portfolio. Migration Hub also provides key metrics and progress for individual applications, regardless of which tools are being used to migrate them. For example, you might use AWS Database Migration Service, AWS Server Migration Service, and partner migration tools to migrate an application comprised of a database, virtualized web servers, and a bare metal server. Using Migration Hub will provide you with a single screen that shows the migration progress of all the resources in the application. This allows you to quickly get progress updates across all of your migrations, easily identify and troubleshoot any issues, and reduce the overall time and effort spent on your migration projects. Migration Hub is available to all AWS customers at no additional charge. You only pay for the cost of the migration tools you use, and any resources being consumed on AWS. +* `service/ssm`: Updates service API and documentation + * Systems Manager Maintenance Windows include the following changes or enhancements: New task options using Systems Manager Automation, AWS Lambda, and AWS Step Functions; enhanced ability to edit the targets of a Maintenance Window, including specifying a target name and description, and ability to edit the owner field; enhanced ability to edits tasks; enhanced support for Run Command parameters; and you can now use a --safe flag when attempting to deregister a target. If this flag is enabled when you attempt to deregister a target, the system returns an error if the target is referenced by any task. Also, Systems Manager now includes Configuration Compliance to scan your fleet of managed instances for patch compliance and configuration inconsistencies. You can collect and aggregate data from multiple AWS accounts and Regions, and then drill down into specific resources that aren't compliant. +* `service/storagegateway`: Updates service API and documentation + * Add optional field ForceDelete to DeleteFileShare api. + +Release v1.10.24 (2017-08-11) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service API and documentation + * Adds support for specifying Application Load Balancers in deployment groups, for both in-place and blue/green deployments. +* `service/cognito-idp`: Updates service API and documentation +* `service/ec2`: Updates service API and documentation + * Provides customers an opportunity to recover an EIP that was released + +Release v1.10.23 (2017-08-10) +=== + +### Service Client Updates +* `service/clouddirectory`: Updates service API and documentation + * Enable BatchDetachPolicy +* `service/codebuild`: Updates service API + * Supporting Bitbucket as source type in AWS CodeBuild. + +Release v1.10.22 (2017-08-09) +=== + +### Service Client Updates +* `service/rds`: Updates service documentation + * Documentation updates for RDS. + +Release v1.10.21 (2017-08-09) +=== + +### Service Client Updates +* `service/elasticbeanstalk`: Updates service API and documentation + * Add support for paginating the result of DescribeEnvironments Include the ARN of described environments in DescribeEnvironments output + +### SDK Enhancements +* `aws`: Add pointer conversion utilities to transform int64 to time.Time [#1433](https://github.com/aws/aws-sdk-go/pull/1433) + * Adds `SecondsTimeValue` and `MillisecondsTimeValue` utilities. + +Release v1.10.20 (2017-08-01) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service API and documentation + * AWS CodeDeploy now supports the use of multiple tag groups in a single deployment group (an intersection of tags) to identify the instances for a deployment. When you create or update a deployment group, use the new ec2TagSet and onPremisesTagSet structures to specify up to three groups of tags. Only instances that are identified by at least one tag in each of the tag groups are included in the deployment group. +* `service/config`: Updates service API and documentation +* `service/ec2`: Updates service waiters + * Ec2 SpotInstanceRequestFulfilled waiter update +* `service/elasticloadbalancingv2`: Updates service waiters +* `service/email`: Updates service API, documentation, paginators, and examples + * This update adds information about publishing email open and click events. This update also adds information about publishing email events to Amazon Simple Notification Service (Amazon SNS). +* `service/pinpoint`: Updates service API and documentation + * This release of the Pinpoint SDK enables App management - create, delete, update operations, Raw Content delivery for APNs and GCM campaign messages and From Address override. + +Release v1.10.19 (2017-08-01) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/inspector`: Updates service API, documentation, and paginators + * Inspector's StopAssessmentRun API has been updated with a new input option - stopAction. This request parameter can be set to either START_EVALUATION or SKIP_EVALUATION. START_EVALUATION (the default value, and the previous behavior) stops the AWS agent data collection and begins the results evaluation for findings generation based on the data collected so far. SKIP_EVALUATION cancels the assessment run immediately, after which no findings are generated. +* `service/ssm`: Updates service API and documentation + * Adds a SendAutomationSignal API to SSM Service. This API is used to send a signal to an automation execution to change the current behavior or status of the execution. + +Release v1.10.18 (2017-07-27) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * The CreateDefaultVPC API enables you to create a new default VPC . You no longer need to contact AWS support, if your default VPC has been deleted. +* `service/kinesisanalytics`: Updates service API and documentation + * Added additional exception types and clarified documentation. + +Release v1.10.17 (2017-07-27) +=== + +### Service Client Updates +* `service/dynamodb`: Updates service documentation and examples + * Corrected a typo. +* `service/ec2`: Updates service API and documentation + * Amazon EC2 Elastic GPUs allow you to easily attach low-cost graphics acceleration to current generation EC2 instances. With Amazon EC2 Elastic GPUs, you can configure the right amount of graphics acceleration to your particular workload without being constrained by fixed hardware configurations and limited GPU selection. +* `service/monitoring`: Updates service documentation + * This release adds high resolution features to CloudWatch, with support for Custom Metrics down to 1 second and Alarms down to 10 seconds. + +Release v1.10.16 (2017-07-26) +=== + +### Service Client Updates +* `service/clouddirectory`: Updates service API and documentation + * Cloud Directory adds support for additional batch operations. +* `service/cloudformation`: Updates service API and documentation + * AWS CloudFormation StackSets enables you to manage stacks across multiple accounts and regions. + +### SDK Enhancements +* `aws/signer/v4`: Optimize V4 signer's header duplicate space stripping. [#1417](https://github.com/aws/aws-sdk-go/pull/1417) + +Release v1.10.15 (2017-07-24) +=== + +### Service Client Updates +* `service/appstream`: Updates service API, documentation, and waiters + * Amazon AppStream 2.0 image builders and fleets can now access applications and network resources that rely on Microsoft Active Directory (AD) for authentication and permissions. This new feature allows you to join your streaming instances to your AD, so you can use your existing AD user management tools. +* `service/ec2`: Updates service API and documentation + * Spot Fleet tagging capability allows customers to automatically tag instances launched by Spot Fleet. You can use this feature to label or distinguish instances created by distinct Spot Fleets. Tagging your EC2 instances also enables you to see instance cost allocation by tag in your AWS bill. + +### SDK Bugs +* `aws/signer/v4`: Fix out of bounds panic in stripExcessSpaces [#1412](https://github.com/aws/aws-sdk-go/pull/1412) + * Fixes the out of bands panic in stripExcessSpaces caused by an incorrect calculation of the stripToIdx value. Simplified to code also. + * Fixes [#1411](https://github.com/aws/aws-sdk-go/issues/1411) +Release v1.10.14 (2017-07-20) +=== + +### Service Client Updates +* `service/elasticmapreduce`: Updates service API and documentation + * Amazon EMR now includes the ability to use a custom Amazon Linux AMI and adjustable root volume size when launching a cluster. + +Release v1.10.13 (2017-07-19) +=== + +### Service Client Updates +* `service/budgets`: Updates service API and documentation + * Update budget Management API's to list/create/update RI_UTILIZATION type budget. Update budget Management API's to support DAILY timeUnit for RI_UTILIZATION type budget. + +### SDK Enhancements +* `service/s3`: Use interfaces assertions instead of ValuesAtPath for S3 field lookups. [#1401](https://github.com/aws/aws-sdk-go/pull/1401) + * Improves the performance across the board for all S3 API calls by removing the usage of `ValuesAtPath` being used for every S3 API call. + +### SDK Bugs +* `aws/request`: waiter test bug + * waiters_test.go file would sometimes fail due to travis hiccups. This occurs because a test would sometimes fail the cancel check and succeed the timeout. However, the timeout check should never occur in that test. This fix introduces a new field that dictates how waiters will sleep. +Release v1.10.12 (2017-07-17) +=== + +### Service Client Updates +* `service/cognito-idp`: Updates service API and documentation +* `service/lambda`: Updates service API and documentation + * Lambda@Edge lets you run code closer to your end users without provisioning or managing servers. With Lambda@Edge, your code runs in AWS edge locations, allowing you to respond to your end users at the lowest latency. Your code is triggered by Amazon CloudFront events, such as requests to and from origin servers and viewers, and it is ready to execute at every AWS edge location whenever a request for content is received. You just upload your Node.js code to AWS Lambda and Lambda takes care of everything required to run and scale your code with high availability. You only pay for the compute time you consume - there is no charge when your code is not running. + +Release v1.10.11 (2017-07-14) +=== + +### Service Client Updates +* `service/discovery`: Updates service API and documentation + * Adding feature to the Export API for Discovery Service to allow filters for the export task to allow export based on per agent id. +* `service/ec2`: Updates service API + * New EC2 GPU Graphics instance +* `service/marketplacecommerceanalytics`: Updates service documentation + * Update to Documentation Model For New Report Cadence / Reformat of Docs + +Release v1.10.10 (2017-07-13) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * Adds support for management of gateway responses. +* `service/ec2`: Updates service API and documentation + * X-ENI (or Cross-Account ENI) is a new feature that allows the attachment or association of Elastic Network Interfaces (ENI) between VPCs in different AWS accounts located in the same availability zone. With this new capability, service providers and partners can deliver managed solutions in a variety of new architectural patterns where the provider and consumer of the service are in different AWS accounts. +* `service/lex-models`: Updates service documentation + +Release v1.10.9 (2017-07-12) +=== + +### Service Client Updates +* `service/autoscaling`: Updates service API and documentation + * Auto Scaling now supports a new type of scaling policy called target tracking scaling policies that you can use to set up dynamic scaling for your application. +* `service/swf`: Updates service API, documentation, paginators, and examples + * Added support for attaching control data to Lambda tasks. Control data lets you attach arbitrary strings to your decisions and history events. + +Release v1.10.8 (2017-07-06) +=== + +### Service Client Updates +* `service/ds`: Updates service API, documentation, and paginators + * You can now improve the resilience and performance of your Microsoft AD directory by deploying additional domain controllers. Added UpdateNumberofDomainControllers API that allows you to update the number of domain controllers you want for your directory, and DescribeDomainControllers API that allows you to describe the detailed information of each domain controller of your directory. Also added the 'DesiredNumberOfDomainControllers' field to the DescribeDirectories API output for Microsoft AD. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/kinesis`: Updates service API and documentation + * You can now encrypt your data at rest within an Amazon Kinesis Stream using server-side encryption. Server-side encryption via AWS KMS makes it easy for customers to meet strict data management requirements by encrypting their data at rest within the Amazon Kinesis Streams, a fully managed real-time data processing service. +* `service/kms`: Updates service API and documentation + * This release of AWS Key Management Service introduces the ability to determine whether a key is AWS managed or customer managed. +* `service/ssm`: Updates service API and documentation + * Amazon EC2 Systems Manager now expands Patching support to Amazon Linux, Red Hat and Ubuntu in addition to the already supported Windows Server. + +Release v1.10.7 (2017-07-05) +=== + +### Service Client Updates +* `service/monitoring`: Updates service API and documentation + * We are excited to announce the availability of APIs and CloudFormation support for CloudWatch Dashboards. You can use the new dashboard APIs or CloudFormation templates to dynamically build and maintain dashboards to monitor your infrastructure and applications. There are four new dashboard APIs - PutDashboard, GetDashboard, DeleteDashboards, and ListDashboards APIs. PutDashboard is used to create a new dashboard or modify an existing one whereas GetDashboard is the API to get the details of a specific dashboard. ListDashboards and DeleteDashboards are used to get the names or delete multiple dashboards respectively. Getting started with dashboard APIs is similar to any other AWS APIs. The APIs can be accessed through AWS SDK or through CLI tools. +* `service/route53`: Updates service API and documentation + * Bug fix for InvalidChangeBatch exception. + +### SDK Enhancements +* `service/s3/s3manager`: adding cleanup function to batch objects [#1375](https://github.com/aws/aws-sdk-go/issues/1375) + * This enhancement will add an After field that will be called after each iteration of the batch operation. + +Release v1.10.6 (2017-06-30) +=== + +### Service Client Updates +* `service/marketplacecommerceanalytics`: Updates service documentation + * Documentation updates for AWS Marketplace Commerce Analytics. +* `service/s3`: Updates service API and documentation + * API Update for S3: Adding Object Tagging Header to MultipartUpload Initialization + +Release v1.10.5 (2017-06-29) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/events`: Updates service API and documentation + * CloudWatch Events now allows different AWS accounts to share events with each other through a new resource called event bus. Event buses accept events from AWS services, other AWS accounts and PutEvents API calls. Currently all AWS accounts have one default event bus. To send events to another account, customers simply write rules to match the events of interest and attach an event bus in the receiving account as the target to the rule. The PutTargets API has been updated to allow adding cross account event buses as targets. In addition, we have released two new APIs - PutPermission and RemovePermission - that enables customers to add/remove permissions to their default event bus. +* `service/gamelift`: Updates service API and documentation + * Allow developers to download GameLift fleet creation logs to assist with debugging. +* `service/ssm`: Updates service API and documentation + * Adding Resource Data Sync support to SSM Inventory. New APIs: * CreateResourceDataSync - creates a new resource data sync configuration, * ListResourceDataSync - lists existing resource data sync configurations, * DeleteResourceDataSync - deletes an existing resource data sync configuration. + +Release v1.10.4 (2017-06-27) +=== + +### Service Client Updates +* `service/servicecatalog`: Updates service API, documentation, and paginators + * Proper tagging of resources is critical to post-launch operations such as billing, cost allocation, and resource management. By using Service Catalog's TagOption Library, administrators can define a library of re-usable TagOptions that conform to company standards, and associate these with Service Catalog portfolios and products. Learn how to move your current tags to the new library, create new TagOptions, and view and associate your library items with portfolios and products. Understand how to ensure that the right tags are created on products launched through Service Catalog and how to provide users with defined selectable tags. + +### SDK Bugs +* `aws/signer/v4`: checking length on `stripExcessSpaces` [#1372](https://github.com/aws/aws-sdk-go/issues/1372) + * Fixes a bug where `stripExcessSpaces` did not check length against the slice. + * Fixes: [#1371](https://github.com/aws/aws-sdk-go/issues/1371) +Release v1.10.3 (2017-06-23) +=== + +### Service Client Updates +* `service/lambda`: Updates service API and documentation + * The Lambda Invoke API will now throw new exception InvalidRuntimeException (status code 502) for invokes with deprecated runtimes. + +Release v1.10.2 (2017-06-22) +=== + +### Service Client Updates +* `service/codepipeline`: Updates service API, documentation, and paginators + * A new API, ListPipelineExecutions, enables you to retrieve summary information about the most recent executions in a pipeline, including pipeline execution ID, status, start time, and last updated time. You can request information for a maximum of 100 executions. Pipeline execution data is available for the most recent 12 months of activity. +* `service/dms`: Updates service API and documentation + * Added tagging for DMS certificates. +* `service/elasticloadbalancing`: Updates service waiters +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lightsail`: Updates service API and documentation + * This release adds a new nextPageToken property to the result of the GetOperationsForResource API. Developers can now get the next set of items in a list by making subsequent calls to GetOperationsForResource API with the token from the previous call. This release also deprecates the nextPageCount property, which previously returned null (use the nextPageToken property instead). This release also deprecates the customImageName property on the CreateInstancesRequest class, which was previously ignored by the API. +* `service/route53`: Updates service API and documentation + * This release reintroduces the HealthCheckInUse exception. + +Release v1.10.1 (2017-06-21) +=== + +### Service Client Updates +* `service/dax`: Adds new service + * Amazon DynamoDB Accelerator (DAX) is a fully managed, highly available, in-memory cache for DynamoDB that delivers up to a 10x performance improvement - from milliseconds to microseconds - even at millions of requests per second. DAX does all the heavy lifting required to add in-memory acceleration to your DynamoDB tables, without requiring developers to manage cache invalidation, data population, or cluster management. +* `service/route53`: Updates service API and documentation + * Amazon Route 53 now supports multivalue answers in response to DNS queries, which lets you route traffic approximately randomly to multiple resources, such as web servers. Create one multivalue answer record for each resource and, optionally, associate an Amazon Route 53 health check with each record, and Amazon Route 53 responds to DNS queries with up to eight healthy records. +* `service/ssm`: Updates service API, documentation, and paginators + * Adding hierarchy support to the SSM Parameter Store API. Added support tor tagging. New APIs: GetParameter - retrieves one parameter, DeleteParameters - deletes multiple parameters (max number 10), GetParametersByPath - retrieves parameters located in the hierarchy. Updated APIs: PutParameter - added ability to enforce parameter value by applying regex (AllowedPattern), DescribeParameters - modified to support Tag filtering. +* `service/waf`: Updates service API and documentation + * You can now create, edit, update, and delete a new type of WAF rule with a rate tracking component. +* `service/waf-regional`: Updates service API and documentation + +Release v1.10.0 (2017-06-20) +=== + +### Service Client Updates +* `service/workdocs`: Updates service API and documentation + * This release provides a new API to retrieve the activities performed by WorkDocs users. + +### SDK Features +* `aws/credentials/plugincreds`: Add support for Go plugin for credentials [#1320](https://github.com/aws/aws-sdk-go/pull/1320) + * Adds support for using plugins to retrieve credentials for API requests. This change adds a new package plugincreds under aws/credentials. See the `example/aws/credentials/plugincreds` folder in the SDK for example usage. + +Release v1.9.00 (2017-06-19) +=== + +### Service Client Updates +* `service/organizations`: Updates service API and documentation + * Improvements to Exception Modeling + +### SDK Features +* `service/s3/s3manager`: Adds batch operations to s3manager [#1333](https://github.com/aws/aws-sdk-go/pull/1333) + * Allows for batch upload, download, and delete of objects. Also adds the interface pattern to allow for easy traversal of objects. E.G `DownloadWithIterator`, `UploadWithIterator`, and `BatchDelete`. `BatchDelete` also contains a utility iterator using the `ListObjects` API to easily delete a list of objects. + +Release v1.8.44 (2017-06-16) +=== + +### Service Client Updates +* `service/xray`: Updates service API, documentation, and paginators + * Add a response time histogram to the services in response of GetServiceGraph API. + +Release v1.8.43 (2017-06-15) +=== + +### Service Client Updates +* `service/ec2`: Updates service API and documentation + * Adds API to describe Amazon FPGA Images (AFIs) available to customers, which includes public AFIs, private AFIs that you own, and AFIs owned by other AWS accounts for which you have load permissions. +* `service/ecs`: Updates service API and documentation + * Added support for cpu, memory, and memory reservation container overrides on the RunTask and StartTask APIs. +* `service/iot`: Updates service API and documentation + * Revert the last release: remove CertificatePem from DescribeCertificate API. +* `service/servicecatalog`: Updates service API, documentation, and paginators + * Added ProvisioningArtifactSummaries to DescribeProductAsAdmin's output to show the provisioning artifacts belong to the product. Allow filtering by SourceProductId in SearchProductsAsAdmin for AWS Marketplace products. Added a verbose option to DescribeProvisioningArtifact to display the CloudFormation template used to create the provisioning artifact.Added DescribeProvisionedProduct API. Changed the type of ProvisionedProduct's Status to be distinct from Record's Status. New ProvisionedProduct's Status are AVAILABLE, UNDER_CHANGE, TAINTED, ERROR. Changed Record's Status set of values to CREATED, IN_PROGRESS, IN_PROGRESS_IN_ERROR, SUCCEEDED, FAILED. + +### SDK Bugs +* `private/model/api`: Fix RESTXML support for XML Namespace [#1343](https://github.com/aws/aws-sdk-go/pull/1343) + * Fixes a bug with the SDK's generation of services using the REST XML protocol not annotating shape references with the XML Namespace attribute. + * Fixes [#1334](https://github.com/aws/aws-sdk-go/pull/1334) +Release v1.8.42 (2017-06-14) +=== + +### Service Client Updates +* `service/applicationautoscaling`: Updates service API and documentation +* `service/clouddirectory`: Updates service documentation + * Documentation update for Cloud Directory + +Release v1.8.41 (2017-06-13) +=== + +### Service Client Updates +* `service/configservice`: Updates service API + +Release v1.8.40 (2017-06-13) +=== + +### Service Client Updates +* `service/rds`: Updates service API and documentation + * API Update for RDS: this update enables copy-on-write, a new Aurora MySQL Compatible Edition feature that allows users to restore their database, and support copy of TDE enabled snapshot cross region. + +### SDK Bugs +* `aws/request`: Fix NewErrParamMinLen to use correct ParamMinLenErrCode [#1336](https://github.com/aws/aws-sdk-go/issues/1336) + * Fixes the `NewErrParamMinLen` function returning the wrong error code. `ParamMinLenErrCode` should be returned not `ParamMinValueErrCode`. + * Fixes [#1335](https://github.com/aws/aws-sdk-go/issues/1335) +Release v1.8.39 (2017-06-09) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/opsworks`: Updates service API and documentation + * Tagging Support for AWS OpsWorks Stacks + +Release v1.8.38 (2017-06-08) +=== + +### Service Client Updates +* `service/iot`: Updates service API and documentation + * In addition to using certificate ID, AWS IoT customers can now obtain the description of a certificate with the certificate PEM. +* `service/pinpoint`: Updates service API and documentation + * Starting today Amazon Pinpoint adds SMS Text and Email Messaging support in addition to Mobile Push Notifications, providing developers, product managers and marketers with multi-channel messaging capabilities to drive user engagement in their applications. Pinpoint also enables backend services and applications to message users directly and provides advanced user and app analytics to understand user behavior and messaging performance. +* `service/rekognition`: Updates service API and documentation + * API Update for AmazonRekognition: Adding RecognizeCelebrities API + +Release v1.8.37 (2017-06-07) +=== + +### Service Client Updates +* `service/codebuild`: Updates service API and documentation + * Add support to APIs for privileged containers. This change would allow performing privileged operations like starting the Docker daemon inside builds possible in custom docker images. +* `service/greengrass`: Adds new service + * AWS Greengrass is software that lets you run local compute, messaging, and device state synchronization for connected devices in a secure way. With AWS Greengrass, connected devices can run AWS Lambda functions, keep device data in sync, and communicate with other devices securely even when not connected to the Internet. Using AWS Lambda, Greengrass ensures your IoT devices can respond quickly to local events, operate with intermittent connections, and minimize the cost of transmitting IoT data to the cloud. + +Release v1.8.36 (2017-06-06) +=== + +### Service Client Updates +* `service/acm`: Updates service documentation + * Documentation update for AWS Certificate Manager. +* `service/cloudfront`: Updates service documentation + * Doc update to fix incorrect prefix in S3OriginConfig +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/iot`: Updates service API + * Update client side validation for SalesForce action. + +Release v1.8.35 (2017-06-05) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * AppStream 2.0 Custom Security Groups allows you to easily control what network resources your streaming instances and images have access to. You can assign up to 5 security groups per Fleet to control the inbound and outbound network access to your streaming instances to specific IP ranges, network protocols, or ports. +* `service/iot`: Updates service API, documentation, paginators, and examples + * Added Salesforce action to IoT Rules Engine. + +Release v1.8.34 (2017-06-02) +=== + +### Service Client Updates +* `service/kinesisanalytics`: Updates service API, documentation, and paginators + * Kinesis Analytics publishes error messages CloudWatch logs in case of application misconfigurations +* `service/workdocs`: Updates service API and documentation + * This release includes new APIs to manage tags and custom metadata on resources and also new APIs to add and retrieve comments at the document level. + +Release v1.8.33 (2017-06-01) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service API and documentation + * AWS CodeDeploy has improved how it manages connections to GitHub accounts and repositories. You can now create and store up to 25 connections to GitHub accounts in order to associate AWS CodeDeploy applications with GitHub repositories. Each connection can support multiple repositories. You can create connections to up to 25 different GitHub accounts, or create more than one connection to a single account. The ListGitHubAccountTokenNames command has been introduced to retrieve the names of stored connections to GitHub accounts that you have created. The name of the connection to GitHub used for an AWS CodeDeploy application is also included in the ApplicationInfo structure. Two new fields, lastAttemptedDeployment and lastSuccessfulDeployment, have been added to DeploymentGroupInfo to improve the handling of deployment group information in the AWS CodeDeploy console. Information about these latest deployments can also be retrieved using the GetDeploymentGroup and BatchGetDeployment group requests. Also includes a region update (us-gov-west-1). +* `service/cognitoidentityprovider`: Updates service API, documentation, and paginators +* `service/elbv2`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lexmodelbuildingservice`: Updates service documentation and examples + +### SDK Enhancements +* `aws/defaults`: Exports shared credentials and config default filenames used by the SDK. [#1308](https://github.com/aws/aws-sdk-go/pull/1308) + * Adds SharedCredentialsFilename and SharedConfigFilename functions to defaults package. + +### SDK Bugs +* `aws/credentials`: Fixes shared credential provider's default filename on Windows. [#1308](https://github.com/aws/aws-sdk-go/pull/1308) + * The shared credentials provider would attempt to use the wrong filename on Windows if the `HOME` environment variable was defined. +* `service/s3/s3manager`: service/s3/s3manager: Fix Downloader ignoring Range get parameter [#1311](https://github.com/aws/aws-sdk-go/pull/1311) + * Fixes the S3 Download Manager ignoring the GetObjectInput's Range parameter. If this parameter is provided it will force the downloader to fallback to a single GetObject request disabling concurrency and automatic part size gets. + * Fixes [#1296](https://github.com/aws/aws-sdk-go/issues/1296) +Release v1.8.32 (2017-05-31) +=== + +### Service Client Updates +* `service/rds`: Updates service API and documentation + * Amazon RDS customers can now easily and quickly stop and start their DB instances. + +Release v1.8.31 (2017-05-30) +=== + +### Service Client Updates +* `service/clouddirectory`: Updates service API, documentation, and paginators + * Cloud Directory has launched support for Typed Links, enabling customers to create object-to-object relationships that are not hierarchical in nature. Typed Links enable customers to quickly query for data along these relationships. Customers can also enforce referential integrity using Typed Links, ensuring data in use is not inadvertently deleted. +* `service/s3`: Updates service paginators and examples + * New example snippets for Amazon S3. + +Release v1.8.30 (2017-05-25) +=== + +### Service Client Updates +* `service/appstream`: Updates service API and documentation + * Support added for persistent user storage, backed by S3. +* `service/rekognition`: Updates service API and documentation + * Updated the CompareFaces API response to include orientation information, unmatched faces, landmarks, pose, and quality of the compared faces. + +Release v1.8.29 (2017-05-24) +=== + +### Service Client Updates +* `service/iam`: Updates service API + * The unique ID and access key lengths were extended from 32 to 128 +* `service/storagegateway`: Updates service API and documentation + * Two Storage Gateway data types, Tape and TapeArchive, each have a new response element, TapeUsedInBytes. This element helps you manage your virtual tapes. By using TapeUsedInBytes, you can see the amount of data written to each virtual tape. +* `service/sts`: Updates service API, documentation, and paginators + * The unique ID and access key lengths were extended from 32 to 128. + +Release v1.8.28 (2017-05-23) +=== + +### Service Client Updates +* `service/databasemigrationservice`: Updates service API, documentation, paginators, and examples + * This release adds support for using Amazon S3 and Amazon DynamoDB as targets for database migration, and using MongoDB as a source for database migration. For more information, see the AWS Database Migration Service documentation. + +Release v1.8.27 (2017-05-22) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/resourcegroupstaggingapi`: Updates service API, documentation, and paginators + * You can now specify the number of resources returned per page in GetResources operation, as an optional parameter, to easily manage the list of resources returned by your queries. + +### SDK Bugs +* `aws/request`: Add support for PUT temporary redirects (307) [#1283](https://github.com/aws/aws-sdk-go/issues/1283) + * Adds support for Go 1.8's GetBody function allowing the SDK's http request using PUT and POST methods to be redirected with temporary redirects with 307 status code. + * Fixes: [#1267](https://github.com/aws/aws-sdk-go/issues/1267) +* `aws/request`: Add handling for retrying temporary errors during unmarshal [#1289](https://github.com/aws/aws-sdk-go/issues/1289) + * Adds support for retrying temporary errors that occur during unmarshaling of a request's response body. + * Fixes: [#1275](https://github.com/aws/aws-sdk-go/issues/1275) +Release v1.8.26 (2017-05-18) +=== + +### Service Client Updates +* `service/athena`: Adds new service + * This release adds support for Amazon Athena. Amazon Athena is an interactive query service that makes it easy to analyze data in Amazon S3 using standard SQL. Athena is serverless, so there is no infrastructure to manage, and you pay only for the queries that you run. +* `service/lightsail`: Updates service API, documentation, and paginators + * This release adds new APIs that make it easier to set network port configurations on Lightsail instances. Developers can now make a single request to both open and close public ports on an instance using the PutInstancePublicPorts operation. + +### SDK Bugs +* `aws/request`: Fix logging from reporting wrong retry request errors #1281 + * Fixes the SDK's retry request logging to report the the actual error that occurred, not a stubbed Unknown error message. + * Fixes the SDK's response logger to not output the response log multiple times per retry. +Release v1.8.25 (2017-05-17) +=== + +### Service Client Updates +* `service/autoscaling`: Updates service documentation, paginators, and examples + * Various Auto Scaling documentation updates +* `service/cloudwatchevents`: Updates service documentation + * Various CloudWatch Events documentation updates. +* `service/cloudwatchlogs`: Updates service documentation and paginators + * Various CloudWatch Logs documentation updates. +* `service/polly`: Updates service API + * Amazon Polly adds new German voice "Vicki" + +Release v1.8.24 (2017-05-16) +=== + +### Service Client Updates +* `service/codedeploy`: Updates service API and documentation + * This release introduces the previousRevision field in the responses to the GetDeployment and BatchGetDeployments actions. previousRevision provides information about the application revision that was deployed to the deployment group before the most recent successful deployment. Also, the fileExistsBehavior parameter has been added for CreateDeployment action requests. In the past, if the AWS CodeDeploy agent detected files in a target location that weren't part of the application revision from the most recent successful deployment, it would fail the current deployment by default. This new parameter provides options for how the agent handles these files: fail the deployment, retain the content, or overwrite the content. +* `service/gamelift`: Updates service API and documentation + * Allow developers to specify how metrics are grouped in CloudWatch for their GameLift fleets. Developers can also specify how many concurrent game sessions activate on a per-instance basis. +* `service/inspector`: Updates service API, documentation, paginators, and examples + * Adds ability to produce an assessment report that includes detailed and comprehensive results of a specified assessment run. +* `service/kms`: Updates service documentation + * Update documentation for KMS. + +Release v1.8.23 (2017-05-15) +=== + +### Service Client Updates +* `service/ssm`: Updates service API and documentation + * UpdateAssociation API now supports updating document name and targets of an association. GetAutomationExecution API can return FailureDetails as an optional field to the StepExecution Object, which contains failure type, failure stage as well as other failure related information for a failed step. + +### SDK Enhancements +* `aws/session`: SDK should be able to load multiple custom shared config files. [#1258](https://github.com/aws/aws-sdk-go/issues/1258) + * This change adds a `SharedConfigFiles` field to the `session.Options` type that allows you to specify the files, and their order, the SDK will use for loading shared configuration and credentials from when the `Session` is created. Use the `NewSessionWithOptions` Session constructor to specify these options. You'll also most likely want to enable support for the shared configuration file's additional attributes by setting `session.Option`'s `SharedConfigState` to `session.SharedConfigEnabled`. + +Release v1.8.22 (2017-05-11) +=== + +### Service Client Updates +* `service/elb`: Updates service API, documentation, and paginators +* `service/elbv2`: Updates service API and documentation +* `service/lexmodelbuildingservice`: Updates service API and documentation +* `service/organizations`: Updates service API, documentation, paginators, and examples + * AWS Organizations APIs that return an Account object now include the email address associated with the account’s root user. + +Release v1.8.21 (2017-05-09) +=== + +### Service Client Updates +* `service/codestar`: Updates service documentation + * Updated documentation for AWS CodeStar. +* `service/workspaces`: Updates service API, documentation, and paginators + * Doc-only Update for WorkSpaces + +Release v1.8.20 (2017-05-04) +=== + +### Service Client Updates +* `service/ecs`: Updates service API, documentation, and paginators + * Exposes container instance registration time in ECS:DescribeContainerInstances. +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/marketplaceentitlementservice`: Adds new service +* `service/lambda`: Updates service API and documentation + * Support for UpdateFunctionCode DryRun option + +Release v1.8.19 (2017-04-28) +=== + +### Service Client Updates +* `service/cloudformation`: Updates service waiters and paginators + * Adding back the removed waiters and paginators. + +Release v1.8.18 (2017-04-28) +=== + +### Service Client Updates +* `service/cloudformation`: Updates service API, documentation, waiters, paginators, and examples + * API update for CloudFormation: New optional parameter ClientRequestToken which can be used as an idempotency token to safely retry certain operations as well as tagging StackEvents. +* `service/rds`: Updates service API, documentation, and examples + * The DescribeDBClusterSnapshots API now returns a SourceDBClusterSnapshotArn field which identifies the source DB cluster snapshot of a copied snapshot. +* `service/rekognition`: Updates service API + * Fix for missing file type check +* `service/snowball`: Updates service API, documentation, and paginators + * The Snowball API has a new exception that can be thrown for list operation requests. +* `service/sqs`: Updates service API, documentation, and paginators + * Adding server-side encryption (SSE) support to SQS by integrating with AWS KMS; adding new queue attributes to SQS CreateQueue, SetQueueAttributes and GetQueueAttributes APIs to support SSE. + +Release v1.8.17 (2017-04-26) +=== + +### Service Client Updates +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * With Amazon Relational Database Service (Amazon RDS) running MySQL or Amazon Aurora, you can now authenticate to your DB instance using IAM database authentication. + +Release v1.8.16 (2017-04-21) +=== + +### Service Client Updates +* `service/appstream`: Updates service API, documentation, and paginators + * The new feature named "Default Internet Access" will enable Internet access from AppStream 2.0 instances - image builders and fleet instances. Admins will check a flag either through AWS management console for AppStream 2.0 or through API while creating an image builder or while creating/updating a fleet. +* `service/kinesis`: Updates service API, documentation, waiters, and paginators + * Adds a new waiter, StreamNotExists, to Kinesis. + +### SDK Enhancements +* `aws/endpoints`: Add utilities improving endpoints lookup (#1218) + * Adds several utilities to the endpoints packages to make looking up partitions, regions, and services easier. + * Fixes #994 + +### SDK Bugs +* `private/protocol/xml/xmlutil`: Fix unmarshaling dropping errors (#1219) + * The XML unmarshaler would drop any serialization or body read error that occurred on the floor effectively hiding any errors that would occur. + * Fixes #1205 +Release v1.8.15 (2017-04-20) +=== + +### Service Client Updates +* `service/devicefarm`: Updates service API and documentation + * API Update for AWS Device Farm: Support for Deals and Promotions +* `service/directconnect`: Updates service documentation + * Documentation updates for AWS Direct Connect. +* `service/elbv2`: Updates service waiters +* `service/kms`: Updates service documentation and examples + * Doc-only update for Key Management Service (KMS): Update docs for GrantConstraints and GenerateRandom +* `service/route53`: Updates service documentation + * Release notes: SDK documentation now includes examples for ChangeResourceRecordSets for all types of resource record set, such as weighted, alias, and failover. +* `service/route53domains`: Updates service API, documentation, and paginators + * Adding examples and other documentation updates. + +### SDK Enhancements +* `service/s3`: Add utilities to make getting a bucket's region easier (#1207) + * Adds two features which make it easier to get a bucket's region, `s3.NormalizeBucketLocation` and `s3manager.GetBucketRegion`. + +### SDK Bugs +* `service/s3`: Fix HeadObject's incorrect documented error codes (#1213) + * The HeadObject's model incorrectly states that the operation can return the NoSuchKey error code. + * Fixes #1208 + +Release v1.8.14 (2017-04-19) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * Add support for "embed" property. +* `service/codestar`: Adds new service + * AWS CodeStar is a cloud-based service for creating, managing, and working with software development projects on AWS. An AWS CodeStar project creates and integrates AWS services for your project development toolchain. AWS CodeStar also manages the permissions required for project users. +* `service/ec2`: Updates service API and documentation + * Adds support for creating an Amazon FPGA Image (AFI) from a specified design checkpoint (DCP). +* `service/iam`: Updates service API and documentation + * This changes introduces a new IAM role type, Service Linked Role, which works like a normal role but must be managed via services' control. +* `service/lambda`: Updates service API and documentation + * Lambda integration with CloudDebugger service to enable customers to enable tracing for the Lambda functions and send trace information to the CloudDebugger service. +* `service/lexmodelbuildingservice`: Adds new service +* `service/polly`: Updates service API, documentation, and paginators + * API Update for Amazon Polly: Add support for speech marks +* `service/rekognition`: Updates service API and documentation + * Given an image, the API detects explicit or suggestive adult content in the image and returns a list of corresponding labels with confidence scores, as well as a taxonomy (parent-child relation) for each label. + +Release v1.8.13 (2017-04-18) +=== + +### Service Client Updates +* `service/lambda`: Updates service API and documentation + * You can use tags to group and filter your Lambda functions, making it easier to analyze them for billing allocation purposes. For more information, see Tagging Lambda Functions. You can now write or upgrade your Lambda functions using Python version 3.6. For more information, see Programming Model for Authoring Lambda Functions in Python. Note: Features will be rolled out in the US regions on 4/19. + +### SDK Enhancements +* `aws/request`: add support for appengine's custom standard library (#1190) + * Remove syscall error checking on appengine platforms. + +Release v1.8.12 (2017-04-11) +=== + +### Service Client Updates +* `service/apigateway`: Updates service API and documentation + * API Gateway request validators +* `service/batch`: Updates service API and documentation + * API Update for AWS Batch: Customer provided AMI for MANAGED Compute Environment +* `service/gamelift`: Updates service API and documentation + * Allows developers to utilize an improved workflow when calling our Queues API and introduces a new feature that allows developers to specify a maximum allowable latency per Queue. +* `service/opsworks`: Updates service API, documentation, and paginators + * Cloudwatch Logs agent configuration can now be attached to OpsWorks Layers using CreateLayer and UpdateLayer. OpsWorks will then automatically install and manage the CloudWatch Logs agent on the instances part of the OpsWorks Layer. + +### SDK Bugs +* `aws/client`: Fix clients polluting handler list (#1197) + * Fixes the clients potentially polluting the passed in handler list with the client's customizations. This change ensures every client always works with a clean copy of the request handlers and it cannot pollute the handlers back upstream. + * Fixes #1184 +* `aws/request`: Fix waiter error match condition (#1195) + * Fixes the waiters's matching overwriting the request's err, effectively ignoring the error condition. This broke waiters with the FailureWaiterState matcher state. +Release v1.8.11 (2017-04-07) +=== + +### Service Client Updates +* `service/redshift`: Updates service API, documentation, and paginators + * This update adds the GetClusterCredentials API which is used to get temporary login credentials to the cluster. AccountWithRestoreAccess now has a new member AccountAlias, this is the identifier of the AWS support account authorized to restore the specified snapshot. This is added to support the feature where the customer can share their snapshot with the Amazon Redshift Support Account without having to manually specify the AWS Redshift Service account ID on the AWS Console/API. + +Release v1.8.10 (2017-04-06) +=== + +### Service Client Updates +* `service/elbv2`: Updates service documentation + +Release v1.8.9 (2017-04-05) +=== + +### Service Client Updates +* `service/elasticache`: Updates service API, documentation, paginators, and examples + * ElastiCache added support for testing the Elasticache Multi-AZ feature with Automatic Failover. + +Release v1.8.8 (2017-04-04) +=== + +### Service Client Updates +* `service/cloudwatch`: Updates service API, documentation, and paginators + * Amazon Web Services announced the immediate availability of two additional alarm configuration rules for Amazon CloudWatch Alarms. The first rule is for configuring missing data treatment. Customers have the options to treat missing data as alarm threshold breached, alarm threshold not breached, maintain alarm state and the current default treatment. The second rule is for alarms based on percentiles metrics that can trigger unnecassarily if the percentile is calculated from a small number of samples. The new rule can treat percentiles with low sample counts as same as missing data. If the first rule is enabled, the same treatment will be applied when an alarm encounters a percentile with low sample counts. + +Release v1.8.7 (2017-04-03) +=== + +### Service Client Updates +* `service/lexruntimeservice`: Updates service API and documentation + * Adds support to PostContent for speech input + +### SDK Enhancements +* `aws/request`: Improve handler copy, push back, push front performance (#1171) + * Minor optimization to the handler list's handling of copying and pushing request handlers to the handler list. +* Update codegen header to use Go std wording (#1172) + * Go recently accepted the proposal for standard generated file header wording in, https://golang.org/s/generatedcode. + +### SDK Bugs +* `service/dynamodb`: Fix DynamoDB using custom retryer (#1170) + * Fixes (#1139) the DynamoDB service client clobbering any custom retryer that was passed into the service client or Session's config. +Release v1.8.6 (2017-04-01) +=== + +### Service Client Updates +* `service/clouddirectory`: Updates service API and documentation + * ListObjectAttributes now supports filtering by facet. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.8.5 (2017-03-30) +=== + +### Service Client Updates +* `service/cloudformation`: Updates service waiters and paginators + * Adding paginators for ListExports and ListImports +* `service/cloudfront`: Adds new service + * Amazon CloudFront now supports user configurable HTTP Read and Keep-Alive Idle Timeouts for your Custom Origin Servers +* `service/configservice`: Updates service documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/resourcegroupstaggingapi`: Adds new service +* `service/storagegateway`: Updates service API and documentation + * File gateway mode in AWS Storage gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. Once a file share is created, any changes made externally to the S3 bucket will not be reflected by the gateway. Using the cache refresh feature in this update, the customer can trigger an on-demand scan of the keys in their S3 bucket and refresh the file namespace cached on the gateway. It takes as an input the fileShare ARN and refreshes the cache for only that file share. Additionally there is new functionality on file gateway that allows you configure what squash options they would like on their file share, this allows a customer to configure their gateway to not squash root permissions. This can be done by setting options in NfsOptions for CreateNfsFileShare and UpdateNfsFileShare APIs. + +Release v1.8.4 (2017-03-28) +=== + +### Service Client Updates +* `service/batch`: Updates service API, documentation, and paginators + * Customers can now provide a retryStrategy as part of the RegisterJobDefinition and SubmitJob API calls. The retryStrategy object has a number value for attempts. This is the number of non successful executions before a job is considered FAILED. In addition, the JobDetail object now has an attempts field and shows all execution attempts. +* `service/ec2`: Updates service API and documentation + * Customers can now tag their Amazon EC2 Instances and Amazon EBS Volumes at + the time of their creation. You can do this from the EC2 Instance launch + wizard or through the RunInstances or CreateVolume APIs. By tagging + resources at the time of creation, you can eliminate the need to run custom + tagging scripts after resource creation. In addition, you can now set + resource-level permissions on the CreateVolume, CreateTags, DeleteTags, and + the RunInstances APIs. This allows you to implement stronger security + policies by giving you more granular control over which users and groups + have access to these APIs. You can also enforce the use of tagging and + control what tag keys and values are set on your resources. When you combine + tag usage and resource-level IAM policies together, you can ensure your + instances and volumes are properly secured upon creation and achieve more + accurate cost allocation reporting. These new features are provided at no + additional cost. + +### SDK Enhancements +* `aws/request`: Add retry support for RequestTimeoutException (#1158) + * Adds support for retrying RequestTimeoutException error code that is returned by some services. + +### SDK Bugs +* `private/model/api`: Fix Waiter and Paginators panic on nil param inputs (#1157) + * Corrects the code generation for Paginators and waiters that caused a panic if nil input parameters were used with the operations. +Release v1.8.3 (2017-03-27) +=== + +## Service Client Updates +* `service/ssm`: Updates service API, documentation, and paginators + * Updated validation rules for SendCommand and RegisterTaskWithMaintenanceWindow APIs. +Release v1.8.2 (2017-03-24) +=== + +Service Client Updates +--- +* `service/applicationautoscaling`: Updates service API, documentation, and paginators + * Application AutoScaling is launching support for a new target resource (AppStream 2.0 Fleets) as a scalable target. +* `service/cloudtrail`: Updates service API and documentation + * Doc-only Update for CloudTrail: Add required parameters for GetEventSelectors and PutEventSelectors + +Release v1.8.1 (2017-03-23) +=== + +Service Client Updates +--- +* `service/applicationdiscoveryservice`: Updates service API, documentation, and paginators + * Adds export configuration options to the AWS Discovery Service API. +* `service/elbv2`: Updates waiters +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/lambda`: Updates service API and paginators + * Adds support for new runtime Node.js v6.10 for AWS Lambda service + +Release v1.8.0 (2017-03-22) +=== + +Service Client Updates +--- +* `service/codebuild`: Updates service documentation +* `service/directconnect`: Updates service API + * Deprecated DescribeConnectionLoa, DescribeInterconnectLoa, AllocateConnectionOnInterconnect and DescribeConnectionsOnInterconnect operations in favor of DescribeLoa, DescribeLoa, AllocateHostedConnection and DescribeHostedConnections respectively. +* `service/marketplacecommerceanalytics`: Updates service API, documentation, and paginators + * This update adds a new data set, us_sales_and_use_tax_records, which enables AWS Marketplace sellers to programmatically access to their U.S. Sales and Use Tax report data. +* `service/pinpoint`: Updates service API and documentation + * Amazon Pinpoint User Segmentation + * Added ability to segment endpoints by user attributes in addition to endpoint attributes. Amazon Pinpoint Event Stream Preview + * Added functionality to publish raw app analytics and campaign events data as events streams to Kinesis and Kinesis Firehose + * The feature provides developers with increased flexibility of exporting raw events to S3, Redshift, Elasticsearch using a Kinesis Firehose stream or enable real time event processing use cases using a Kinesis stream +* `service/rekognition`: Updates service documentation. + +SDK Features +--- +* `aws/request`: Add support for context.Context to SDK API operation requests (#1132) + * Adds support for context.Context to the SDK by adding `WithContext` methods for each API operation, Paginators and Waiters. e.g `PutObjectWithContext`. This change also adds the ability to provide request functional options to the method calls instead of requiring you to use the `Request` API operation method (e.g `PutObjectRequest`). + * Adds a `Complete` Request handler list that will be called ever time a request is completed. This includes both success and failure. Complete will only be called once per API operation request. + * `private/waiter` package moved from the private group to `aws/request/waiter` and made publicly available. + * Adds Context support to all API operations, Waiters(WaitUntil) and Paginators(Pages) methods. + * Adds Context support for s3manager and s3crypto clients. + +SDK Enhancements +--- +* `aws/signer/v4`: Adds support for unsigned payload signer config (#1130) + * Adds configuration option to the v4.Signer to specify the request's body should not be signed. This will only correclty function on services that support unsigned payload. e.g. S3, Glacier. + +SDK Bug Fixes +--- +* `service/s3`: Fix S3 HostID to be available in S3 request error message (#1131) + * Adds a new type s3.RequestFailure which exposes the S3 HostID value from a S3 API operation response. This is helpful when you have an error with S3, and need to contact support. Both RequestID and HostID are needed. +* `private/model/api`: Do not return a link if uid is empty (#1133) + * Fixes SDK's doc generation to not generate API reference doc links if the SDK us unable to create a valid link. +* `aws/request`: Optimization to handler list copy to prevent multiple alloc calls. (#1134) +Release v1.7.9 (2017-03-13) +=== + +Service Client Updates +--- +* `service/devicefarm`: Updates service API, documentation, paginators, and examples + * Network shaping allows users to simulate network connections and conditions while testing their Android, iOS, and web apps with AWS Device Farm. +* `service/cloudwatchevents`: Updates service API, documentation, and examples + +SDK Enhancement +=== +* `aws/session`: Add support for side loaded CA bundles (#1117) + * Adds supports for side loading Certificate Authority bundle files to the SDK using AWS_CA_BUNDLE environment variable or CustomCABundle session option. +* `service/s3/s3crypto`: Add support for AES/CBC/PKCS5Padding (#1124) + +SDK Bug +=== +* `service/rds`: Fixing issue when not providing `SourceRegion` on cross +region operations (#1127) +* `service/rds`: Enables cross region for `CopyDBClusterSnapshot` and +`CreateDBCluster` (#1128) + +Release v1.7.8 (2017-03-10) +=== + +Service Client Updates +--- +* `service/codedeploy`: Updates service paginators + * Add paginators for Codedeploy +* `service/emr`: Updates service API, documentation, and paginators + * This release includes support for instance fleets in Amazon EMR. + +Release v1.7.7 (2017-03-09) +=== + +Service Client Updates +--- +* `service/apigateway`: Updates service API, documentation, and paginators + * API Gateway has added support for ACM certificates on custom domain names. Both Amazon-issued certificates and uploaded third-part certificates are supported. +* `service/clouddirectory`: Updates service API, documentation, and paginators + * Introduces a new Cloud Directory API that enables you to retrieve all available parent paths for any type of object (a node, leaf node, policy node, and index node) in a hierarchy. + +Release v1.7.6 (2017-03-09) +=== + +Service Client Updates +--- +* `service/organizations`: Updates service documentation and examples + * Doc-only Update for Organizations: Add SDK Code Snippets +* `service/workdocs`: Adds new service + * The Administrative SDKs for Amazon WorkDocs provides full administrator level access to WorkDocs site resources, allowing developers to integrate their applications to manage WorkDocs users, content and permissions programmatically + +Release v1.7.5 (2017-03-08) +=== + +Service Client Updates +--- +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * Add support to using encrypted clusters as cross-region replication masters. Update CopyDBClusterSnapshot API to support encrypted cross region copy of Aurora cluster snapshots. + +Release v1.7.4 (2017-03-06) +=== + +Service Client Updates +--- +* `service/budgets`: Updates service API and paginators + * When creating or editing a budget via the AWS Budgets API you can define notifications that are sent to subscribers when the actual or forecasted value for cost or usage exceeds the notificationThreshold associated with the budget notification object. Starting today, the maximum allowed value for the notificationThreshold was raised from 100 to 300. This change was made to give you more flexibility when setting budget notifications. +* `service/cloudtrail`: Updates service documentation and paginators + * Doc-only update for AWSCloudTrail: Updated links/descriptions +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/opsworkscm`: Updates service API, documentation, and paginators + * OpsWorks for Chef Automate has added a new field "AssociatePublicIpAddress" to the CreateServer request, "CloudFormationStackArn" to the Server model and "TERMINATED" server state. + + +Release v1.7.3 (2017-02-28) +=== + +Service Client Updates +--- +* `service/mturk`: Renaming service + * service/mechanicalturkrequesterservice was renamed to service/mturk. Be sure to change any references of the old client to the new. + +Release v1.7.2 (2017-02-28) +=== + +Service Client Updates +--- +* `service/dynamodb`: Updates service API and documentation + * Release notes: Time to Live (TTL) is a feature that allows you to define when items in a table expire and can be purged from the database, so that you don't have to track expired data and delete it manually. With TTL enabled on a DynamoDB table, you can set a timestamp for deletion on a per-item basis, allowing you to limit storage usage to only those records that are relevant. +* `service/iam`: Updates service API, documentation, and paginators + * This release adds support for AWS Organizations service control policies (SCPs) to SimulatePrincipalPolicy operation. If there are SCPs associated with the simulated user's account, their effect on the result is captured in the OrganizationDecisionDetail element in the EvaluationResult. +* `service/mechanicalturkrequesterservice`: Adds new service + * Amazon Mechanical Turk is a web service that provides an on-demand, scalable, human workforce to complete jobs that humans can do better than computers, for example, recognizing objects in photos. +* `service/organizations`: Adds new service + * AWS Organizations is a web service that enables you to consolidate your multiple AWS accounts into an organization and centrally manage your accounts and their resources. +* `service/dynamodbstreams`: Updates service API, documentation, and paginators +* `service/waf`: Updates service API, documentation, and paginators + * Aws WAF - For GetSampledRequests action, changed max number of samples from 100 to 500. +* `service/wafregional`: Updates service API, documentation, and paginators + +Release v1.7.1 (2017-02-24) +=== + +Service Client Updates +--- +* `service/elasticsearchservice`: Updates service API, documentation, paginators, and examples + * Added three new API calls to existing Amazon Elasticsearch service to expose Amazon Elasticsearch imposed limits to customers. + +Release v1.7.0 (2017-02-23) +=== + +Service Client Updates +--- +* `service/ec2`: Updates service API + * New EC2 I3 instance type + +SDK Bug +--- +* `service/s3/s3manager`: Adding support for SSE (#1097) + * Fixes SSE fields not being applied to a part during multi part upload. + +SDK Feature +--- +* `aws/session`: Add support for AssumeRoles with MFA (#1088) + * Adds support for assuming IAM roles with MFA enabled. A TokenProvider func was added to stscreds.AssumeRoleProvider that will be called each time the role's credentials need to be refreshed. A basic token provider that sources the MFA token from stdin as stscreds.StdinTokenProvider. +* `aws/session`: Update SDK examples and docs to use session.Must (#1099) + * Updates the SDK's example and docs to use session.Must where possible to highlight its usage as apposed to session error checking that is most cases errors will be terminal to the application anyways. +Release v1.6.27 (2017-02-22) +=== + +Service Client Updates +--- +* `service/clouddirectory`: Updates service documentation + * ListObjectAttributes documentation updated based on forum feedback +* `service/elasticbeanstalk`: Updates service API, documentation, and paginators + * Elastic Beanstalk adds support for creating and managing custom platform. +* `service/gamelift`: Updates service API, documentation, and paginators + * Allow developers to configure global queues for creating GameSessions. Allow PlayerData on PlayerSessions to store player-specific data. +* `service/route53`: Updates service API, documentation, and examples + * Added support for operations CreateVPCAssociationAuthorization and DeleteVPCAssociationAuthorization to throw a ConcurrentModification error when a conflicting modification occurs in parallel to the authorizations in place for a given hosted zone. + +Release v1.6.26 (2017-02-21) +=== + +Service Client Updates +--- +* `service/ec2`: Updates service API and documentation + * Added the billingProduct parameter to the RegisterImage API. + +Release v1.6.25 (2017-02-17) +=== + +Service Client Updates +--- +* `service/directconnect`: Updates service API, documentation, and paginators + * This update will introduce the ability for Direct Connect customers to take advantage of Link Aggregation (LAG). This allows you to bundle many individual physical interfaces into a single logical interface, referred to as a LAG. This makes administration much simpler as the majority of configuration is done on the LAG while you are free to add or remove physical interfaces from the bundle as bandwidth demand increases or decreases. A concrete example of the simplification added by LAG is that customers need only a single BGP session as opposed to one session per physical connection. + +Release v1.6.24 (2017-02-16) +=== + +Service Client Updates +--- +* `service/cognitoidentity`: Updates service API, documentation, and paginators + * Allow createIdentityPool and updateIdentityPool API to set server side token check value on identity pool +* `service/configservice`: Updates service API and documentation + * AWS Config now supports a new test mode for the PutEvaluations API. Set the TestMode parameter to true in your custom rule to verify whether your AWS Lambda function will deliver evaluation results to AWS Config. No updates occur to your existing evaluations, and evaluation results are not sent to AWS Config. + +Release v1.6.23 (2017-02-15) +=== + +Service Client Updates +--- +* `service/kms`: Updates service API, documentation, paginators, and examples + * his release of AWS Key Management Service introduces the ability to tag keys. Tagging keys can help you organize your keys and track your KMS costs in the cost allocation report. This release also increases the maximum length of a key ID to accommodate ARNs that include a long key alias. + +Release v1.6.22 (2017-02-14) +=== + +Service Client Updates +--- +* `service/ec2`: Updates service API, documentation, and paginators + * Adds support for the new Modify Volumes apis. + +Release v1.6.21 (2017-02-11) +=== + +Service Client Updates +--- +* `service/storagegateway`: Updates service API, documentation, and paginators + * File gateway mode in AWS Storage gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. This is done by creating Nfs file shares using existing APIs CreateNfsFileShare. Using the feature in this update, the customer can restrict the clients that have read/write access to the gateway by specifying the list of clients as a list of IP addresses or CIDR blocks. This list can be specified using the API CreateNfsFileShare while creating new file shares, or UpdateNfsFileShare while update existing file shares. To find out the list of clients that have access, the existing API DescribeNfsFileShare will now output the list of clients that have access. + +Release v1.6.20 (2017-02-09) +=== + +Service Client Updates +--- +* `service/ec2`: Updates service API and documentation + * This feature allows customers to associate an IAM profile to running instances that do not have any. +* `service/rekognition`: Updates service API and documentation + * DetectFaces and IndexFaces operations now return an estimate of the age of the face as an age range. + +SDK Features +--- +* `aws/endpoints`: Add option to resolve unknown endpoints (#1074) +Release v1.6.19 (2017-02-08) +=== + +Service Client Updates +--- +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glacier`: Updates service examples + * Doc Update +* `service/lexruntimeservice`: Adds new service + * Preview release + +SDK Bug Fixes +--- +* `private/protocol/json`: Fixes json to throw an error if a float number is (+/-)Inf and NaN (#1068) +* `private/model/api`: Fix documentation error listing (#1067) + +SDK Features +--- +* `private/model`: Add service response error code generation (#1061) + +Release v1.6.18 (2017-01-27) +=== + +Service Client Updates +--- +* `service/clouddirectory`: Adds new service + * Amazon Cloud Directory is a highly scalable, high performance, multi-tenant directory service in the cloud. Its web-based directories make it easy for you to organize and manage application resources such as users, groups, locations, devices, policies, and the rich relationships between them. +* `service/codedeploy`: Updates service API, documentation, and paginators + * This release of AWS CodeDeploy introduces support for blue/green deployments. In a blue/green deployment, the current set of instances in a deployment group is replaced by new instances that have the latest application revision installed on them. After traffic is rerouted behind a load balancer to the replacement instances, the original instances can be terminated automatically or kept running for other uses. +* `service/ec2`: Updates service API and documentation + * Adds instance health check functionality to replace unhealthy EC2 Spot fleet instances with fresh ones. +* `service/rds`: Updates service API and documentation + * Snapshot Engine Version Upgrade + +Release v1.6.17 (2017-01-25) +=== + +Service Client Updates +--- +* `service/elbv2`: Updates service API, documentation, and paginators + * Application Load Balancers now support native Internet Protocol version 6 (IPv6) in an Amazon Virtual Private Cloud (VPC). With this ability, clients can now connect to the Application Load Balancer in a dual-stack mode via either IPv4 or IPv6. +* `service/rds`: Updates service API and documentation + * Cross Region Read Replica Copying (CreateDBInstanceReadReplica) + +Release v1.6.16 (2017-01-24) +=== + +Service Client Updates +--- +* `service/codebuild`: Updates service documentation and paginators + * Documentation updates +* `service/codecommit`: Updates service API, documentation, and paginators + * AWS CodeCommit now includes the option to view the differences between a commit and its parent commit from within the console. You can view the differences inline (Unified view) or side by side (Split view). To view information about the differences between a commit and something other than its parent, you can use the AWS CLI and the get-differences and get-blob commands, or you can use the GetDifferences and GetBlob APIs. +* `service/ecs`: Updates service API and documentation + * Amazon ECS now supports a state for container instances that can be used to drain a container instance in preparation for maintenance or cluster scale down. + +Release v1.6.15 (2017-01-20) +=== + +Service Client Updates +--- +* `service/acm`: Updates service API, documentation, and paginators + * Update for AWS Certificate Manager: Updated response elements for DescribeCertificate API in support of managed renewal +* `service/health`: Updates service documentation + +Release v1.6.14 (2017-01-19) +=== + +Service Client Updates +--- +* `service/ec2`: Updates service API, documentation, and paginators + * Amazon EC2 Spot instances now support dedicated tenancy, providing the ability to run Spot instances single-tenant manner on physically isolated hardware within a VPC to satisfy security, privacy, or other compliance requirements. Dedicated Spot instances can be requested using RequestSpotInstances and RequestSpotFleet. + +Release v1.6.13 (2017-01-18) +=== + +Service Client Updates +--- +* `service/rds`: Updates service API, documentation, and paginators + +Release v1.6.12 (2017-01-17) +=== + +Service Client Updates +--- +* `service/dynamodb`: Updates service API, documentation, and paginators + * Tagging Support for Amazon DynamoDB Tables and Indexes +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/glacier`: Updates service API, paginators, and examples + * Doc-only Update for Glacier: Added code snippets +* `service/polly`: Updates service documentation and examples + * Doc-only update for Amazon Polly -- added snippets +* `service/rekognition`: Updates service documentation and paginators + * Added code samples to Rekognition reference topics. +* `service/route53`: Updates service API and paginators + * Add ca-central-1 and eu-west-2 enum values to CloudWatchRegion enum + +Release v1.6.11 (2017-01-16) +=== + +Service Client Updates +--- +* `service/configservice`: Updates service API, documentation, and paginators +* `service/costandusagereportservice`: Adds new service + * The AWS Cost and Usage Report Service API allows you to enable and disable the Cost & Usage report, as well as modify the report name, the data granularity, and the delivery preferences. +* `service/dynamodb`: Updates service API, documentation, and examples + * Snippets for the DynamoDB API. +* `service/elasticache`: Updates service API, documentation, and examples + * Adds new code examples. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.6.10 (2017-01-04) +=== + +Service Client Updates +--- +* `service/configservice`: Updates service API and documentation + * AWSConfig is planning to add support for OversizedConfigurationItemChangeNotification message type in putConfigRule. After this release customers can use/write rules based on OversizedConfigurationItemChangeNotification mesage type. +* `service/efs`: Updates service API, documentation, and examples + * Doc-only Update for EFS: Added code snippets +* `service/iam`: Updates service documentation and examples +* `service/lambda`: Updates service documentation and examples + * Doc only updates for Lambda: Added code snippets +* `service/marketplacecommerceanalytics`: Updates service API and documentation + * Added support for data set disbursed_amount_by_instance_hours, with historical data available starting 2012-09-04. New data is published to this data set every 30 days. +* `service/rds`: Updates service documentation + * Updated documentation for CopyDBSnapshot. +* `service/rekognition`: Updates service documentation and examples + * Doc-only Update for Rekognition: Added code snippets +* `service/snowball`: Updates service examples +* `service/dynamodbstreams`: Updates service API and examples + * Doc-only Update for DynamoDB Streams: Added code snippets + +SDK Feature +--- +* `private/model/api`: Increasing the readability of code generated files. (#1024) +Release v1.6.9 (2016-12-30) +=== + +Service Client Updates +--- +* `service/codedeploy`: Updates service API and documentation + * CodeDeploy will support Iam Session Arns in addition to Iam User Arns for on premise host authentication. +* `service/ecs`: Updates service API and documentation + * Amazon EC2 Container Service (ECS) now supports the ability to customize the placement of tasks on container instances. +* `aws/endpoints`: Updated Regions and Endpoints metadata. + +Release v1.6.8 (2016-12-22) +=== + +Service Client Updates +--- +* `service/apigateway`: Updates service API and documentation + * Amazon API Gateway is adding support for generating SDKs in more languages. This update introduces two new operations used to dynamically discover these SDK types and what configuration each type accepts. +* `service/directoryservice`: Updates service documentation + * Added code snippets for the DS SDKs +* `service/elasticbeanstalk`: Updates service API and documentation +* `service/iam`: Updates service API and documentation + * Adds service-specific credentials to IAM service to make it easier to onboard CodeCommit customers. These are username/password credentials that work with a single service. +* `service/kms`: Updates service API, documentation, and examples + * Update docs and add SDK examples + +Release v1.6.7 (2016-12-22) +=== + +Service Client Updates +--- +* `service/ecr`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/rds`: Updates service API and documentation + * Cross Region Encrypted Snapshot Copying (CopyDBSnapshot) + +Release v1.6.6 (2016-12-20) +=== + +Service Client Updates +--- +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/firehose`: Updates service API, documentation, and examples + * Processing feature enables users to process and modify records before Amazon Firehose delivers them to destinations. +* `service/route53`: Updates service API and documentation + * Enum updates for eu-west-2 and ca-central-1 +* `service/storagegateway`: Updates service API, documentation, and examples + * File gateway is a new mode in the AWS Storage Gateway that support a file interface into S3, alongside the current block-based volume and VTL storage. File gateway combines a service and virtual software appliance, enabling you to store and retrieve objects in Amazon S3 using industry standard file protocols such as NFS. The software appliance, or gateway, is deployed into your on-premises environment as a virtual machine (VM) running on VMware ESXi. The gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. + +Release v1.6.5 (2016-12-19) +=== + +Service Client Updates +--- +* `service/cloudformation`: Updates service documentation + * Minor doc update for CloudFormation. +* `service/cloudtrail`: Updates service paginators +* `service/cognitoidentity`: Updates service API and documentation + * We are adding Groups to Cognito user pools. Developers can perform CRUD operations on groups, add and remove users from groups, list users in groups, etc. We are adding fine-grained role-based access control for Cognito identity pools. Developers can configure an identity pool to get the IAM role from an authenticated user's token, or they can configure rules that will map a user to a different role +* `service/applicationdiscoveryservice`: Updates service API and documentation + * Adds new APIs to group discovered servers into Applications with get summary and neighbors. Includes additional filters for ListConfigurations and DescribeAgents API. +* `service/inspector`: Updates service API, documentation, and examples + * Doc-only Update for Inspector: Adding SDK code snippets for Inspector +* `service/sqs`: Updates service documentation + +SDK Bug Fixes +--- +* `aws/request`: Add PriorRequestNotComplete to throttle retry codes (#1011) + * Fixes: Not retrying when PriorRequestNotComplete #1009 + +SDK Feature +--- +* `private/model/api`: Adds crosslinking to service documentation (#1010) + +Release v1.6.4 (2016-12-15) +=== + +Service Client Updates +--- +* `service/cognitoidentityprovider`: Updates service API and documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/ssm`: Updates service API and documentation + * This will provide customers with access to the Patch Baseline and Patch Compliance APIs. + +SDK Bug Fixes +--- +* `service/route53`: Fix URL path cleaning for Route53 API requests (#1006) + * Fixes: SerializationError when using Route53 ChangeResourceRecordSets #1005 +* `aws/request`: Add PriorRequestNotComplete to throttle retry codes (#1002) + * Fixes: Not retrying when PriorRequestNotComplete #1001 + +Release v1.6.3 (2016-12-14) +=== + +Service Client Updates +--- +* `service/batch`: Adds new service + * AWS Batch is a batch computing service that lets customers define queues and compute environments and then submit work as batch jobs. +* `service/databasemigrationservice`: Updates service API and documentation + * Adds support for SSL enabled Oracle endpoints and task modification. +* `service/elasticbeanstalk`: Updates service documentation +* `aws/endpoints`: Updated Regions and Endpoints metadata. +* `service/cloudwatchlogs`: Updates service API and documentation + * Add support for associating LogGroups with AWSTagris tags +* `service/marketplacecommerceanalytics`: Updates service API and documentation + * Add new enum to DataSetType: sales_compensation_billed_revenue +* `service/rds`: Updates service documentation + * Doc-only Update for RDS: New versions available in CreateDBInstance +* `service/sts`: Updates service documentation + * Adding Code Snippet Examples for SDKs for STS + +SDK Bug Fixes +--- +* `aws/request`: Fix retrying timeout requests (#981) + * Fixes: Requests Retrying is broken if the error was caused due to a client timeout #947 +* `aws/request`: Fix for Go 1.8 request incorrectly sent with body (#991) + * Fixes: service/route53: ListHostedZones hangs and then fails with go1.8 #984 +* private/protocol/rest: Use RawPath instead of Opaque (#993) + * Fixes: HTTP2 request failing with REST protocol services, e.g AWS X-Ray +* private/model/api: Generate REST-JSON JSONVersion correctly (#998) + * Fixes: REST-JSON protocol service code missing JSONVersion metadata. + +Release v1.6.2 (2016-12-08) +=== + +Service Client Updates +--- +* `service/cloudfront`: Add lambda function associations to cache behaviors +* `service/codepipeline`: This is a doc-only update request to incorporate some recent minor revisions to the doc content. +* `service/rds`: Updates service API and documentation +* `service/wafregional`: With this new feature, customers can use AWS WAF directly on Application Load Balancers in a VPC within available regions to protect their websites and web services from malicious attacks such as SQL injection, Cross Site Scripting, bad bots, etc. + +Release v1.6.1 (2016-12-07) +=== + +Service Client Updates +--- +* `service/config`: Updates service API +* `service/s3`: Updates service API +* `service/sqs`: Updates service API and documentation + +Release v1.6.0 (2016-12-06) +=== + +Service Client Updates +--- +* `service/config`: Updates service API and documentation +* `service/ec2`: Updates service API +* `service/sts`: Updates service API, documentation, and examples + +SDK Bug Fixes +--- +* private/protocol/xml/xmlutil: Fix SDK XML unmarshaler #975 + * Fixes GetBucketACL Grantee required type always nil. #916 + +SDK Feature +--- +* aws/endpoints: Add endpoint metadata to SDK #961 + * Adds Region and Endpoint metadata to the SDK. This allows you to enumerate regions and endpoint metadata based on a defined model embedded in the SDK. + +Release v1.5.13 (2016-12-01) +=== + +Service Client Updates +--- +* `service/apigateway`: Updates service API and documentation +* `service/appstream`: Adds new service +* `service/codebuild`: Adds new service +* `service/directconnect`: Updates service API and documentation +* `service/ec2`: Adds new service +* `service/elasticbeanstalk`: Updates service API and documentation +* `service/health`: Adds new service +* `service/lambda`: Updates service API and documentation +* `service/opsworkscm`: Adds new service +* `service/pinpoint`: Adds new service +* `service/shield`: Adds new service +* `service/ssm`: Updates service API and documentation +* `service/states`: Adds new service +* `service/xray`: Adds new service + +Release v1.5.12 (2016-11-30) +=== + +Service Client Updates +--- +* `service/lightsail`: Adds new service +* `service/polly`: Adds new service +* `service/rekognition`: Adds new service +* `service/snowball`: Updates service API and documentation + +Release v1.5.11 (2016-11-29) +=== + +Service Client Updates +--- +`service/s3`: Updates service API and documentation + +Release v1.5.10 (2016-11-22) +=== + +Service Client Updates +--- +* `service/cloudformation`: Updates service API and documentation +* `service/glacier`: Updates service API, documentation, and examples +* `service/route53`: Updates service API and documentation +* `service/s3`: Updates service API and documentation + +SDK Bug Fixes +--- +* `private/protocol/xml/xmlutil`: Fixes xml marshaler to unmarshal properly +into tagged fields +[#916](https://github.com/aws/aws-sdk-go/issues/916) + +Release v1.5.9 (2016-11-22) +=== + +Service Client Updates +--- +* `service/cloudtrail`: Updates service API and documentation +* `service/ecs`: Updates service API and documentation + +Release v1.5.8 (2016-11-18) +=== + +Service Client Updates +--- +* `service/application-autoscaling`: Updates service API and documentation +* `service/elasticmapreduce`: Updates service API and documentation +* `service/elastictranscoder`: Updates service API, documentation, and examples +* `service/gamelift`: Updates service API and documentation +* `service/lambda`: Updates service API and documentation + +Release v1.5.7 (2016-11-18) +=== + +Service Client Updates +--- +* `service/apigateway`: Updates service API and documentation +* `service/meteringmarketplace`: Updates service API and documentation +* `service/monitoring`: Updates service API and documentation +* `service/sqs`: Updates service API, documentation, and examples + +Release v1.5.6 (2016-11-16) +=== + +Service Client Updates +--- +`service/route53`: Updates service API and documentation +`service/servicecatalog`: Updates service API and documentation + +Release v1.5.5 (2016-11-15) +=== + +Service Client Updates +--- +* `service/ds`: Updates service API and documentation +* `service/elasticache`: Updates service API and documentation +* `service/kinesis`: Updates service API and documentation + +Release v1.5.4 (2016-11-15) +=== + +Service Client Updates +--- +* `service/cognito-idp`: Updates service API and documentation + +Release v1.5.3 (2016-11-11) +=== + +Service Client Updates +--- +* `service/cloudformation`: Updates service documentation and examples +* `service/logs`: Updates service API and documentation + +Release v1.5.2 (2016-11-03) +=== + +Service Client Updates +--- +* `service/directconnect`: Updates service API and documentation + +Release v1.5.1 (2016-11-02) +=== + +Service Client Updates +--- +* `service/email`: Updates service API and documentation + +Release v1.5.0 (2016-11-01) +=== + +Service Client Updates +--- +* `service/cloudformation`: Updates service API and documentation +* `service/ecr`: Updates service paginators + +SDK Feature Updates +--- +* `private/model/api`: Add generated setters for API parameters (#918) + * Adds setters to the SDK's API parameter types, and are a convenience method that reduce the need to use `aws.String` and like utility. + +Release v1.4.22 (2016-10-25) +=== + +Service Client Updates +--- +* `service/elasticloadbalancingv2`: Updates service documentation. +* `service/autoscaling`: Updates service documentation. + +Release v1.4.21 (2016-10-24) +=== + +Service Client Updates +--- +* `service/sms`: AWS Server Migration Service (SMS) is an agentless service which makes it easier and faster for you to migrate thousands of on-premises workloads to AWS. AWS SMS allows you to automate, schedule, and track incremental replications of live server volumes, making it easier for you to coordinate large-scale server migrations. +* `service/ecs`: Updates documentation. + +SDK Feature Updates +--- +* `private/models/api`: Improve code generation of documentation. + +Release v1.4.20 (2016-10-20) +=== + +Service Client Updates +--- +* `service/budgets`: Adds new service, AWS Budgets. +* `service/waf`: Updates service documentation. + +Release v1.4.19 (2016-10-18) +=== + +Service Client Updates +--- +* `service/cloudfront`: Updates service API and documentation. + * Ability to use Amazon CloudFront to deliver your content both via IPv6 and IPv4 using HTTP/HTTPS. +* `service/configservice`: Update service API and documentation. +* `service/iot`: Updates service API and documentation. +* `service/kinesisanalytics`: Updates service API and documentation. + * Whenever Amazon Kinesis Analytics is not able to detect schema for the given streaming source on DiscoverInputSchema API, we would return the raw records that was sampled to detect the schema. +* `service/rds`: Updates service API and documentation. + * Amazon Aurora integrates with other AWS services to allow you to extend your Aurora DB cluster to utilize other capabilities in the AWS cloud. Permission to access other AWS services is granted by creating an IAM role with the necessary permissions, and then associating the role with your DB cluster. + +SDK Feature Updates +--- +* `service/dynamodb/dynamodbattribute`: Add UnmarshalListOfMaps #897 + * Adds support for unmarshaling a list of maps. This is useful for unmarshaling the DynamoDB AttributeValue list of maps returned by APIs like Query and Scan. + +Release v1.4.18 (2016-10-17) +=== + +Service Model Updates +--- +* `service/route53`: Updates service API and documentation. + +Release v1.4.17 +=== + +Service Model Updates +--- +* `service/acm`: Update service API, and documentation. + * This change allows users to import third-party SSL/TLS certificates into ACM. +* `service/elasticbeanstalk`: Update service API, documentation, and pagination. + * Elastic Beanstalk DescribeApplicationVersions API is being updated to support pagination. +* `service/gamelift`: Update service API, and documentation. + * New APIs to protect game developer resource (builds, alias, fleets, instances, game sessions and player sessions) against abuse. + +SDK Features +--- +* `service/s3`: Add support for accelerate with dualstack [#887](https://github.com/aws/aws-sdk-go/issues/887) + +Release v1.4.16 (2016-10-13) +=== + +Service Model Updates +--- +* `service/ecr`: Update Amazon EC2 Container Registry service model + * DescribeImages is a new api used to expose image metadata which today includes image size and image creation timestamp. +* `service/elasticache`: Update Amazon ElastiCache service model + * Elasticache is launching a new major engine release of Redis, 3.2 (providing stability updates and new command sets over 2.8), as well as ElasticSupport for enabling Redis Cluster in 3.2, which provides support for multiple node groups to horizontally scale data, as well as superior engine failover capabilities + +SDK Bug Fixes +--- +* `aws/session`: Skip shared config on read errors [#883](https://github.com/aws/aws-sdk-go/issues/883) +* `aws/signer/v4`: Add support for URL.EscapedPath to signer [#885](https://github.com/aws/aws-sdk-go/issues/885) + +SDK Features +--- +* `private/model/api`: Add docs for errors to API operations [#881](https://github.com/aws/aws-sdk-go/issues/881) +* `private/model/api`: Improve field and waiter doc strings [#879](https://github.com/aws/aws-sdk-go/issues/879) +* `service/dynamodb/dynamodbattribute`: Allow multiple struct tag elements [#886](https://github.com/aws/aws-sdk-go/issues/886) +* Add build tags to internal SDK tools [#880](https://github.com/aws/aws-sdk-go/issues/880) + +Release v1.4.15 (2016-10-06) +=== + +Service Model Updates +--- +* `service/cognitoidentityprovider`: Update Amazon Cognito Identity Provider service model +* `service/devicefarm`: Update AWS Device Farm documentation +* `service/opsworks`: Update AWS OpsWorks service model +* `service/s3`: Update Amazon Simple Storage Service model +* `service/waf`: Update AWS WAF service model + +SDK Bug Fixes +--- +* `aws/request`: Fix HTTP Request Body race condition [#874](https://github.com/aws/aws-sdk-go/issues/874) + +SDK Feature Updates +--- +* `aws/ec2metadata`: Add support for EC2 User Data [#872](https://github.com/aws/aws-sdk-go/issues/872) +* `aws/signer/v4`: Remove logic determining if request needs to be resigned [#876](https://github.com/aws/aws-sdk-go/issues/876) + +Release v1.4.14 (2016-09-29) +=== +* `service/ec2`: api, documentation, and paginators updates. +* `service/s3`: api and documentation updates. + +Release v1.4.13 (2016-09-27) +=== +* `service/codepipeline`: documentation updates. +* `service/cloudformation`: api and documentation updates. +* `service/kms`: documentation updates. +* `service/elasticfilesystem`: documentation updates. +* `service/snowball`: documentation updates. diff --git a/vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md b/vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md new file mode 100644 index 000000000..8a1927a39 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md @@ -0,0 +1,5 @@ +### SDK Features + +### SDK Enhancements + +### SDK Bugs diff --git a/vendor/github.com/aws/aws-sdk-go/CODE_OF_CONDUCT.md b/vendor/github.com/aws/aws-sdk-go/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..3b6446687 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md b/vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md new file mode 100644 index 000000000..9f4a0c14c --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md @@ -0,0 +1,127 @@ +Contributing to the AWS SDK for Go + +We work hard to provide a high-quality and useful SDK, and we greatly value +feedback and contributions from our community. Whether it's a bug report, +new feature, correction, or additional documentation, we welcome your issues +and pull requests. Please read through this document before submitting any +issues or pull requests to ensure we have all the necessary information to +effectively respond to your bug report or contribution. + + +## Filing Bug Reports + +You can file bug reports against the SDK on the [GitHub issues][issues] page. + +If you are filing a report for a bug or regression in the SDK, it's extremely +helpful to provide as much information as possible when opening the original +issue. This helps us reproduce and investigate the possible bug without having +to wait for this extra information to be provided. Please read the following +guidelines prior to filing a bug report. + +1. Search through existing [issues][] to ensure that your specific issue has + not yet been reported. If it is a common issue, it is likely there is + already a bug report for your problem. + +2. Ensure that you have tested the latest version of the SDK. Although you + may have an issue against an older version of the SDK, we cannot provide + bug fixes for old versions. It's also possible that the bug may have been + fixed in the latest release. + +3. Provide as much information about your environment, SDK version, and + relevant dependencies as possible. For example, let us know what version + of Go you are using, which and version of the operating system, and the + the environment your code is running in. e.g Container. + +4. Provide a minimal test case that reproduces your issue or any error + information you related to your problem. We can provide feedback much + more quickly if we know what operations you are calling in the SDK. If + you cannot provide a full test case, provide as much code as you can + to help us diagnose the problem. Any relevant information should be provided + as well, like whether this is a persistent issue, or if it only occurs + some of the time. + + +## Submitting Pull Requests + +We are always happy to receive code and documentation contributions to the SDK. +Please be aware of the following notes prior to opening a pull request: + +1. The SDK is released under the [Apache license][license]. Any code you submit + will be released under that license. For substantial contributions, we may + ask you to sign a [Contributor License Agreement (CLA)][cla]. + +2. If you would like to implement support for a significant feature that is not + yet available in the SDK, please talk to us beforehand to avoid any + duplication of effort. + +3. Wherever possible, pull requests should contain tests as appropriate. + Bugfixes should contain tests that exercise the corrected behavior (i.e., the + test should fail without the bugfix and pass with it), and new features + should be accompanied by tests exercising the feature. + +4. Pull requests that contain failing tests will not be merged until the test + failures are addressed. Pull requests that cause a significant drop in the + SDK's test coverage percentage are unlikely to be merged until tests have + been added. + +5. The JSON files under the SDK's `models` folder are sourced from outside the SDK. + Such as `models/apis/ec2/2016-11-15/api.json`. We will not accept pull requests + directly on these models. If you discover an issue with the models please + create a [GitHub issue][issues] describing the issue. + +### Testing + +To run the tests locally, running the `make unit` command will `go get` the +SDK's testing dependencies, and run vet, link and unit tests for the SDK. + +``` +make unit +``` + +Standard go testing functionality is supported as well. To test SDK code that +is tagged with `codegen` you'll need to set the build tag in the go test +command. The `make unit` command will do this automatically. + +``` +go test -tags codegen ./private/... +``` + +See the `Makefile` for additional testing tags that can be used in testing. + +To test on multiple platform the SDK includes several DockerFiles under the +`awstesting/sandbox` folder, and associated make recipes to execute +unit testing within environments configured for specific Go versions. + +``` +make sandbox-test-go18 +``` + +To run all sandbox environments use the following make recipe + +``` +# Optionally update the Go tip that will be used during the batch testing +make update-aws-golang-tip + +# Run all SDK tests for supported Go versions in sandboxes +make sandbox-test +``` + +In addition the sandbox environment include make recipes for interactive modes +so you can run command within the Docker container and context of the SDK. + +``` +make sandbox-go18 +``` + +### Changelog + +You can see all release changes in the `CHANGELOG.md` file at the root of the +repository. The release notes added to this file will contain service client +updates, and major SDK changes. + +[issues]: https://github.com/aws/aws-sdk-go/issues +[pr]: https://github.com/aws/aws-sdk-go/pulls +[license]: http://aws.amazon.com/apache2.0/ +[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement +[releasenotes]: https://github.com/aws/aws-sdk-go/releases + diff --git a/vendor/github.com/aws/aws-sdk-go/Gopkg.lock b/vendor/github.com/aws/aws-sdk-go/Gopkg.lock new file mode 100644 index 000000000..854c94fdf --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/Gopkg.lock @@ -0,0 +1,20 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/go-ini/ini" + packages = ["."] + revision = "300e940a926eb277d3901b20bdfcc54928ad3642" + version = "v1.25.4" + +[[projects]] + name = "github.com/jmespath/go-jmespath" + packages = ["."] + revision = "0b12d6b5" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "51a86a867df617990082dec6b868e4efe2fdb2ed0e02a3daa93cd30f962b5085" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/aws/aws-sdk-go/Gopkg.toml b/vendor/github.com/aws/aws-sdk-go/Gopkg.toml new file mode 100644 index 000000000..664fc5955 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/Gopkg.toml @@ -0,0 +1,48 @@ + +# 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" + +ignored = [ + # Testing/Example/Codegen dependencies + "github.com/stretchr/testify", + "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/require", + "github.com/go-sql-driver/mysql", + "github.com/gucumber/gucumber", + "github.com/pkg/errors", + "golang.org/x/net", + "golang.org/x/net/html", + "golang.org/x/net/http2", + "golang.org/x/text", + "golang.org/x/text/html", + "golang.org/x/tools", + "golang.org/x/tools/go/loader", +] + + +[[constraint]] + name = "github.com/go-ini/ini" + version = "1.25.4" + +[[constraint]] + name = "github.com/jmespath/go-jmespath" + revision = "0b12d6b5" + #version = "0.2.2" diff --git a/vendor/github.com/aws/aws-sdk-go/Makefile b/vendor/github.com/aws/aws-sdk-go/Makefile new file mode 100644 index 000000000..83ccc1e62 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/Makefile @@ -0,0 +1,187 @@ +LINTIGNOREDOT='awstesting/integration.+should not use dot imports' +LINTIGNOREDOC='service/[^/]+/(api|service|waiters)\.go:.+(comment on exported|should have comment or be unexported)' +LINTIGNORECONST='service/[^/]+/(api|service|waiters)\.go:.+(type|struct field|const|func) ([^ ]+) should be ([^ ]+)' +LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)' +LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be ' +LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be ' +LINTIGNOREDEPS='vendor/.+\.go' +LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form' +UNIT_TEST_TAGS="example codegen awsinclude" + +SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src") +SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/") +SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/") +SDK_GO_1_4=$(shell go version | grep "go1.4") +SDK_GO_1_5=$(shell go version | grep "go1.5") +SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''') + +all: get-deps generate unit + +help: + @echo "Please use \`make ' where is one of" + @echo " api_info to print a list of services and versions" + @echo " docs to build SDK documentation" + @echo " build to go build the SDK" + @echo " unit to run unit tests" + @echo " integration to run integration tests" + @echo " performance to run performance tests" + @echo " verify to verify tests" + @echo " lint to lint the SDK" + @echo " vet to vet the SDK" + @echo " generate to go generate and make services" + @echo " gen-test to generate protocol tests" + @echo " gen-services to generate services" + @echo " get-deps to go get the SDK dependencies" + @echo " get-deps-tests to get the SDK's test dependencies" + @echo " get-deps-verify to get the SDK's verification dependencies" + +generate: gen-test gen-endpoints gen-services + +gen-test: gen-protocol-test + +gen-services: + go generate ./service + +gen-protocol-test: + go generate ./private/protocol/... + +gen-endpoints: + go generate ./models/endpoints/ + +build: + @echo "go build SDK and vendor packages" + @go build ${SDK_ONLY_PKGS} + +unit: get-deps-tests build verify + @echo "go test SDK and vendor packages" + @go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS) + +unit-with-race-cover: get-deps-tests build verify + @echo "go test SDK and vendor packages" + @go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS) + +integration: get-deps-tests integ-custom smoke-tests performance + +integ-custom: + go test -tags "integration" ./awstesting/integration/customizations/... + +cleanup-integ: + go run -tags "integration" ./awstesting/cmd/bucket_cleanup/main.go "aws-sdk-go-integration" + +smoke-tests: get-deps-tests + gucumber -go-tags "integration" ./awstesting/integration/smoke + +performance: get-deps-tests + AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance + +sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-go19 sandbox-test-gotip + +sandbox-build-go15: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" . +sandbox-go15: sandbox-build-go15 + docker run -i -t aws-sdk-go-1.5 bash +sandbox-test-go15: sandbox-build-go15 + docker run -t aws-sdk-go-1.5 + +sandbox-build-go15-novendorexp: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5-novendorexp -t "aws-sdk-go-1.5-novendorexp" . +sandbox-go15-novendorexp: sandbox-build-go15-novendorexp + docker run -i -t aws-sdk-go-1.5-novendorexp bash +sandbox-test-go15-novendorexp: sandbox-build-go15-novendorexp + docker run -t aws-sdk-go-1.5-novendorexp + +sandbox-build-go16: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.6 -t "aws-sdk-go-1.6" . +sandbox-go16: sandbox-build-go16 + docker run -i -t aws-sdk-go-1.6 bash +sandbox-test-go16: sandbox-build-go16 + docker run -t aws-sdk-go-1.6 + +sandbox-build-go17: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.7 -t "aws-sdk-go-1.7" . +sandbox-go17: sandbox-build-go17 + docker run -i -t aws-sdk-go-1.7 bash +sandbox-test-go17: sandbox-build-go17 + docker run -t aws-sdk-go-1.7 + +sandbox-build-go18: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.8" . +sandbox-go18: sandbox-build-go18 + docker run -i -t aws-sdk-go-1.8 bash +sandbox-test-go18: sandbox-build-go18 + docker run -t aws-sdk-go-1.8 + +sandbox-build-go19: + docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.9" . +sandbox-go19: sandbox-build-go19 + docker run -i -t aws-sdk-go-1.9 bash +sandbox-test-go19: sandbox-build-go19 + docker run -t aws-sdk-go-1.9 + +sandbox-build-gotip: + @echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container" + docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" . +sandbox-gotip: sandbox-build-gotip + docker run -i -t aws-sdk-go-tip bash +sandbox-test-gotip: sandbox-build-gotip + docker run -t aws-sdk-go-tip + +update-aws-golang-tip: + docker build --no-cache=true -f ./awstesting/sandbox/Dockerfile.golang-tip -t "aws-golang:tip" . + +verify: get-deps-verify lint vet + +lint: + @echo "go lint SDK and vendor packages" + @lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \ + lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD} -e ${LINTIGNOREPKGCOMMENT}`; \ + echo "$$lint"; \ + if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi + +SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate) +ifneq (,$(findstring go1.4, ${SDK_GO_VERSION})) + GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION} +else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION})) + GO_VET_CMD=go tool vet --all -shadow -example=false +else + GO_VET_CMD=go tool vet --all -shadow +endif + +vet: + ${GO_VET_CMD} ${SDK_BASE_FOLDERS} + +get-deps: get-deps-tests get-deps-verify + @echo "go get SDK dependencies" + @go get -v $(SDK_ONLY_PKGS) + +get-deps-tests: + @echo "go get SDK testing dependencies" + go get github.com/gucumber/gucumber/cmd/gucumber + go get github.com/stretchr/testify + go get github.com/smartystreets/goconvey + go get golang.org/x/net/html + go get golang.org/x/net/http2 + +get-deps-verify: + @echo "go get SDK verification utilities" + @if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi + +bench: + @echo "go bench SDK packages" + @go test -run NONE -bench . -benchmem -tags 'bench' $(SDK_ONLY_PKGS) + +bench-protocol: + @echo "go bench SDK protocol marshallers" + @go test -run NONE -bench . -benchmem -tags 'bench' ./private/protocol/... + +docs: + @echo "generate SDK docs" + @# This env variable, DOCS, is for internal use + @if [ -z ${AWS_DOC_GEN_TOOL} ]; then\ + rm -rf doc && bundle install && bundle exec yard;\ + else\ + $(AWS_DOC_GEN_TOOL) `pwd`;\ + fi + +api_info: + @go run private/model/cli/api-info/api-info.go diff --git a/vendor/github.com/aws/aws-sdk-go/README.md b/vendor/github.com/aws/aws-sdk-go/README.md new file mode 100644 index 000000000..3200765ea --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/README.md @@ -0,0 +1,451 @@ +[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt) + +# AWS SDK for Go + +aws-sdk-go is the official AWS SDK for the Go programming language. + +Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK. + +We [announced](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-2-0-developer-preview/) the Developer Preview for the [v2 AWS SDK for Go](https://github.com/aws/aws-sdk-go-v2). The v2 SDK is available at https://github.com/aws/aws-sdk-go-v2, and `go get github.com/aws/aws-sdk-go-v2` via `go get`. Check out the v2 SDK's [changes and updates](https://github.com/aws/aws-sdk-go-v2/blob/master/CHANGELOG.md), and let us know what you think. We want your feedback. + +## Installing + +If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder. + + go get -u github.com/aws/aws-sdk-go + +Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`. + + go get -u github.com/aws/aws-sdk-go/aws/... + go get -u github.com/aws/aws-sdk-go/service/... + +If you're looking to retrieve just the SDK without any dependencies use the following command. + + go get -d github.com/aws/aws-sdk-go/ + +These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment. + + rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor + +## Getting Help + +Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests. + +* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag. +* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go). +* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html). +* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new). + +## Opening Issues + +If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate. + +The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner. + +## Reference Documentation + +[`Getting Started Guide`](https://aws.amazon.com/sdk-for-go/) - This document is a general introduction how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The [Service Developer Guide](https://aws.amazon.com/documentation/) will help you get started using specific AWS services. + +[`SDK API Reference Documentation`](https://docs.aws.amazon.com/sdk-for-go/api/) - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters. + +[`Service Developer Guide`](https://aws.amazon.com/documentation/) - Use this documentation to learn how to interface with an AWS service. These are great guides both, if you're getting started with a service, or looking for more information on a service. You should not need this document for coding, though in some cases, services may supply helpful samples that you might want to look out for. + +[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services. + +## Overview of SDK's Packages + +The SDK is composed of two main components, SDK core, and service clients. +The SDK core packages are all available under the aws package at the root of +the SDK. Each client for a supported AWS service is available within its own +package under the service folder at the root of the SDK. + + * aws - SDK core, provides common shared types such as Config, Logger, + and utilities to make working with API parameters easier. + + * awserr - Provides the error interface that the SDK will use for all + errors that occur in the SDK's processing. This includes service API + response errors as well. The Error type is made up of a code and message. + Cast the SDK's returned error type to awserr.Error and call the Code + method to compare returned error to specific error codes. See the package's + documentation for additional values that can be extracted such as RequestID. + + * credentials - Provides the types and built in credentials providers + the SDK will use to retrieve AWS credentials to make API requests with. + Nested under this folder are also additional credentials providers such as + stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles. + + * endpoints - Provides the AWS Regions and Endpoints metadata for the SDK. + Use this to lookup AWS service endpoint information such as which services + are in a region, and what regions a service is in. Constants are also provided + for all region identifiers, e.g UsWest2RegionID for "us-west-2". + + * session - Provides initial default configuration, and load + configuration from external sources such as environment and shared + credentials file. + + * request - Provides the API request sending, and retry logic for the SDK. + This package also includes utilities for defining your own request + retryer, and configuring how the SDK processes the request. + + * service - Clients for AWS services. All services supported by the SDK are + available under this folder. + +## How to Use the SDK's AWS Service Clients + +The SDK includes the Go types and utilities you can use to make requests to +AWS service APIs. Within the service folder at the root of the SDK you'll find +a package for each AWS service the SDK supports. All service clients follows +a common pattern of creation and usage. + +When creating a client for an AWS service you'll first need to have a Session +value constructed. The Session provides shared configuration that can be shared +between your service clients. When service clients are created you can pass +in additional configuration via the aws.Config type to override configuration +provided by in the Session to create service client instances with custom +configuration. + +Once the service's client is created you can use it to make API requests the +AWS service. These clients are safe to use concurrently. + +## Configuring the SDK + +In the AWS SDK for Go, you can configure settings for service clients, such +as the log level and maximum number of retries. Most settings are optional; +however, for each service client, you must specify a region and your credentials. +The SDK uses these values to send requests to the correct AWS region and sign +requests with the correct credentials. You can specify these values as part +of a session or as environment variables. + +See the SDK's [configuration guide][config_guide] for more information. + +See the [session][session_pkg] package documentation for more information on how to use Session +with the SDK. + +See the [Config][config_typ] type in the [aws][aws_pkg] package for more information on configuration +options. + +[config_guide]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html +[session_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ +[config_typ]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config +[aws_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/ + +### Configuring Credentials + +When using the SDK you'll generally need your AWS credentials to authenticate +with AWS services. The SDK supports multiple methods of supporting these +credentials. By default the SDK will source credentials automatically from +its default credential chain. See the session package for more information +on this chain, and how to configure it. The common items in the credential +chain are the following: + + * Environment Credentials - Set of environment variables that are useful + when sub processes are created for specific roles. + + * Shared Credentials file (~/.aws/credentials) - This file stores your + credentials based on a profile name and is useful for local development. + + * EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials + to application running on an EC2 instance. This removes the need to manage + credential files in production. + +Credentials can be configured in code as well by setting the Config's Credentials +value to a custom provider or using one of the providers included with the +SDK to bypass the default credential chain and use a custom one. This is +helpful when you want to instruct the SDK to only use a specific set of +credentials or providers. + +This example creates a credential provider for assuming an IAM role, "myRoleARN" +and configures the S3 service client to use that role for API requests. + +```go + // Initial credentials loaded from SDK's default credential chain. Such as + // the environment, shared credentials (~/.aws/credentials), or EC2 Instance + // Role. These credentials will be used to to make the STS Assume Role API. + sess := session.Must(session.NewSession()) + + // Create the credentials from AssumeRoleProvider to assume the role + // referenced by the "myRoleARN" ARN. + creds := stscreds.NewCredentials(sess, "myRoleArn") + + // Create service client value configured for credentials + // from assumed role. + svc := s3.New(sess, &aws.Config{Credentials: creds}) +``` + +See the [credentials][credentials_pkg] package documentation for more information on credential +providers included with the SDK, and how to customize the SDK's usage of +credentials. + +The SDK has support for the shared configuration file (~/.aws/config). This +support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1", +or enabling the feature in code when creating a Session via the +Option's SharedConfigState parameter. + +```go + sess := session.Must(session.NewSessionWithOptions(session.Options{ + SharedConfigState: session.SharedConfigEnable, + })) +``` + +[credentials_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials + +### Configuring AWS Region + +In addition to the credentials you'll need to specify the region the SDK +will use to make AWS API requests to. In the SDK you can specify the region +either with an environment variable, or directly in code when a Session or +service client is created. The last value specified in code wins if the region +is specified multiple ways. + +To set the region via the environment variable set the "AWS_REGION" to the +region you want to the SDK to use. Using this method to set the region will +allow you to run your application in multiple regions without needing additional +code in the application to select the region. + + AWS_REGION=us-west-2 + +The endpoints package includes constants for all regions the SDK knows. The +values are all suffixed with RegionID. These values are helpful, because they +reduce the need to type the region string manually. + +To set the region on a Session use the aws package's Config struct parameter +Region to the AWS region you want the service clients created from the session to +use. This is helpful when you want to create multiple service clients, and +all of the clients make API requests to the same region. + +```go + sess := session.Must(session.NewSession(&aws.Config{ + Region: aws.String(endpoints.UsWest2RegionID), + })) +``` + +See the [endpoints][endpoints_pkg] package for the AWS Regions and Endpoints metadata. + +In addition to setting the region when creating a Session you can also set +the region on a per service client bases. This overrides the region of a +Session. This is helpful when you want to create service clients in specific +regions different from the Session's region. + +```go + svc := s3.New(sess, &aws.Config{ + Region: aws.String(endpoints.UsWest2RegionID), + }) +``` + +See the [Config][config_typ] type in the [aws][aws_pkg] package for more information and additional +options such as setting the Endpoint, and other service client configuration options. + +[endpoints_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/ + +## Making API Requests + +Once the client is created you can make an API request to the service. +Each API method takes a input parameter, and returns the service response +and an error. The SDK provides methods for making the API call in multiple ways. + +In this list we'll use the S3 ListObjects API as an example for the different +ways of making API requests. + + * ListObjects - Base API operation that will make the API request to the service. + + * ListObjectsRequest - API methods suffixed with Request will construct the + API request, but not send it. This is also helpful when you want to get a + presigned URL for a request, and share the presigned URL instead of your + application making the request directly. + + * ListObjectsPages - Same as the base API operation, but uses a callback to + automatically handle pagination of the API's response. + + * ListObjectsWithContext - Same as base API operation, but adds support for + the Context pattern. This is helpful for controlling the canceling of in + flight requests. See the Go standard library context package for more + information. This method also takes request package's Option functional + options as the variadic argument for modifying how the request will be + made, or extracting information from the raw HTTP response. + + * ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for + the Context pattern. Similar to ListObjectsWithContext this method also + takes the request package's Option function option types as the variadic + argument. + +In addition to the API operations the SDK also includes several higher level +methods that abstract checking for and waiting for an AWS resource to be in +a desired state. In this list we'll use WaitUntilBucketExists to demonstrate +the different forms of waiters. + + * WaitUntilBucketExists. - Method to make API request to query an AWS service for + a resource's state. Will return successfully when that state is accomplished. + + * WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds + support for the Context pattern. In addition these methods take request + package's WaiterOptions to configure the waiter, and how underlying request + will be made by the SDK. + +The API method will document which error codes the service might return for +the operation. These errors will also be available as const strings prefixed +with "ErrCode" in the service client's package. If there are no errors listed +in the API's SDK documentation you'll need to consult the AWS service's API +documentation for the errors that could be returned. + +```go + ctx := context.Background() + + result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{ + Bucket: aws.String("my-bucket"), + Key: aws.String("my-key"), + }) + if err != nil { + // Cast err to awserr.Error to handle specific error codes. + aerr, ok := err.(awserr.Error) + if ok && aerr.Code() == s3.ErrCodeNoSuchKey { + // Specific error code handling + } + return err + } + + // Make sure to close the body when done with it for S3 GetObject APIs or + // will leak connections. + defer result.Body.Close() + + fmt.Println("Object Size:", aws.Int64Value(result.ContentLength)) +``` + +### API Request Pagination and Resource Waiters + +Pagination helper methods are suffixed with "Pages", and provide the +functionality needed to round trip API page requests. Pagination methods +take a callback function that will be called for each page of the API's response. + +```go + objects := []string{} + err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{ + Bucket: aws.String(myBucket), + }, func(p *s3.ListObjectsOutput, lastPage bool) bool { + for _, o := range p.Contents { + objects = append(objects, aws.StringValue(o.Key)) + } + return true // continue paging + }) + if err != nil { + panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err)) + } + + fmt.Println("Objects in bucket:", objects) +``` + +Waiter helper methods provide the functionality to wait for an AWS resource +state. These methods abstract the logic needed to check the state of an +AWS resource, and wait until that resource is in a desired state. The waiter +will block until the resource is in the state that is desired, an error occurs, +or the waiter times out. If a resource times out the error code returned will +be request.WaiterResourceNotReadyErrorCode. + +```go + err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{ + Bucket: aws.String(myBucket), + }) + if err != nil { + aerr, ok := err.(awserr.Error) + if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode { + fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist") + } + panic(fmt.Errorf("failed to wait for bucket to exist, %v", err)) + } + fmt.Println("Bucket", myBucket, "exists") +``` + +## Complete SDK Example + +This example shows a complete working Go file which will upload a file to S3 +and use the Context pattern to implement timeout logic that will cancel the +request if it takes too long. This example highlights how to use sessions, +create a service client, make a request, handle the error, and process the +response. + +```go + package main + + import ( + "context" + "flag" + "fmt" + "os" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" + ) + + // Uploads a file to S3 given a bucket and object key. Also takes a duration + // value to terminate the update if it doesn't complete within that time. + // + // The AWS Region needs to be provided in the AWS shared config or on the + // environment variable as `AWS_REGION`. Credentials also must be provided + // Will default to shared config file, but can load from environment if provided. + // + // Usage: + // # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail + // go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt + func main() { + var bucket, key string + var timeout time.Duration + + flag.StringVar(&bucket, "b", "", "Bucket name.") + flag.StringVar(&key, "k", "", "Object key name.") + flag.DurationVar(&timeout, "d", 0, "Upload timeout.") + flag.Parse() + + // All clients require a Session. The Session provides the client with + // shared configuration such as region, endpoint, and credentials. A + // Session should be shared where possible to take advantage of + // configuration and credential caching. See the session package for + // more information. + sess := session.Must(session.NewSession()) + + // Create a new instance of the service's client with a Session. + // Optional aws.Config values can also be provided as variadic arguments + // to the New function. This option allows you to provide service + // specific configuration. + svc := s3.New(sess) + + // Create a context with a timeout that will abort the upload if it takes + // more than the passed in timeout. + ctx := context.Background() + var cancelFn func() + if timeout > 0 { + ctx, cancelFn = context.WithTimeout(ctx, timeout) + } + // Ensure the context is canceled to prevent leaking. + // See context package for more information, https://golang.org/pkg/context/ + defer cancelFn() + + // Uploads the object to S3. The Context will interrupt the request if the + // timeout expires. + _, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(key), + Body: os.Stdin, + }) + if err != nil { + if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode { + // If the SDK can determine the request or retry delay was canceled + // by a context the CanceledErrorCode error code will be returned. + fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err) + } else { + fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err) + } + os.Exit(1) + } + + fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key) + } +``` + +## License + +This SDK is distributed under the +[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0), +see LICENSE.txt and NOTICE.txt for more information. diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go new file mode 100644 index 000000000..007b37be1 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go @@ -0,0 +1,353 @@ +package awsutil_test + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "reflect" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/awsutil" +) + +func ExampleCopy() { + type Foo struct { + A int + B []*string + } + + // Create the initial value + str1 := "hello" + str2 := "bye bye" + f1 := &Foo{A: 1, B: []*string{&str1, &str2}} + + // Do the copy + var f2 Foo + awsutil.Copy(&f2, f1) + + // Print the result + fmt.Println(awsutil.Prettify(f2)) + + // Output: + // { + // A: 1, + // B: ["hello","bye bye"] + // } +} + +func TestCopy1(t *testing.T) { + type Bar struct { + a *int + B *int + c int + D int + } + type Foo struct { + A int + B []*string + C map[string]*int + D *time.Time + E *Bar + } + + // Create the initial value + str1 := "hello" + str2 := "bye bye" + int1 := 1 + int2 := 2 + intPtr1 := 1 + intPtr2 := 2 + now := time.Now() + f1 := &Foo{ + A: 1, + B: []*string{&str1, &str2}, + C: map[string]*int{ + "A": &int1, + "B": &int2, + }, + D: &now, + E: &Bar{ + &intPtr1, + &intPtr2, + 2, + 3, + }, + } + + // Do the copy + var f2 Foo + awsutil.Copy(&f2, f1) + + // Values are equal + if v1, v2 := f2.A, f1.A; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.B, f1.B; !reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.C, f1.C; !reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.D, f1.D; !v1.Equal(*v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.E.B, f1.E.B; !reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.E.D, f1.E.D; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + + // But pointers are not! + str3 := "nothello" + int3 := 57 + f2.A = 100 + *f2.B[0] = str3 + *f2.C["B"] = int3 + *f2.D = time.Now() + f2.E.a = &int3 + *f2.E.B = int3 + f2.E.c = 5 + f2.E.D = 5 + if v1, v2 := f2.A, f1.A; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.B, f1.B; reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.C, f1.C; reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.D, f1.D; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.E.a, f1.E.a; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.E.B, f1.E.B; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.E.c, f1.E.c; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.E.D, f1.E.D; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } +} + +func TestCopyNestedWithUnexported(t *testing.T) { + type Bar struct { + a int + B int + } + type Foo struct { + A string + B Bar + } + + f1 := &Foo{A: "string", B: Bar{a: 1, B: 2}} + + var f2 Foo + awsutil.Copy(&f2, f1) + + // Values match + if v1, v2 := f2.A, f1.A; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.B, f1.B; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.B.a, f1.B.a; v1 == v2 { + t.Errorf("expected values to be not equivalent, but received %v", v1) + } + if v1, v2 := f2.B.B, f2.B.B; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } +} + +func TestCopyIgnoreNilMembers(t *testing.T) { + type Foo struct { + A *string + B []string + C map[string]string + } + + f := &Foo{} + if v1 := f.A; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1 := f.B; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1 := f.C; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + + var f2 Foo + awsutil.Copy(&f2, f) + if v1 := f2.A; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1 := f2.B; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1 := f2.C; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + + fcopy := awsutil.CopyOf(f) + f3 := fcopy.(*Foo) + if v1 := f3.A; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1 := f3.B; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1 := f3.C; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } +} + +func TestCopyPrimitive(t *testing.T) { + str := "hello" + var s string + awsutil.Copy(&s, &str) + if v1, v2 := "hello", s; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } +} + +func TestCopyNil(t *testing.T) { + var s string + awsutil.Copy(&s, nil) + if v1, v2 := "", s; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } +} + +func TestCopyReader(t *testing.T) { + var buf io.Reader = bytes.NewReader([]byte("hello world")) + var r io.Reader + awsutil.Copy(&r, buf) + b, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + if v1, v2 := []byte("hello world"), b; !bytes.Equal(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + + // empty bytes because this is not a deep copy + b, err = ioutil.ReadAll(buf) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + if v1, v2 := []byte(""), b; !bytes.Equal(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } +} + +func TestCopyDifferentStructs(t *testing.T) { + type SrcFoo struct { + A int + B []*string + C map[string]*int + SrcUnique string + SameNameDiffType int + unexportedPtr *int + ExportedPtr *int + } + type DstFoo struct { + A int + B []*string + C map[string]*int + DstUnique int + SameNameDiffType string + unexportedPtr *int + ExportedPtr *int + } + + // Create the initial value + str1 := "hello" + str2 := "bye bye" + int1 := 1 + int2 := 2 + f1 := &SrcFoo{ + A: 1, + B: []*string{&str1, &str2}, + C: map[string]*int{ + "A": &int1, + "B": &int2, + }, + SrcUnique: "unique", + SameNameDiffType: 1, + unexportedPtr: &int1, + ExportedPtr: &int2, + } + + // Do the copy + var f2 DstFoo + awsutil.Copy(&f2, f1) + + // Values are equal + if v1, v2 := f2.A, f1.A; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.B, f1.B; !reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := f2.C, f1.C; !reflect.DeepEqual(v1, v2) { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := "unique", f1.SrcUnique; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := 1, f1.SameNameDiffType; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := 0, f2.DstUnique; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := "", f2.SameNameDiffType; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := int1, *f1.unexportedPtr; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1 := f2.unexportedPtr; v1 != nil { + t.Errorf("expected nil, but received %v", v1) + } + if v1, v2 := int2, *f1.ExportedPtr; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } + if v1, v2 := int2, *f2.ExportedPtr; v1 != v2 { + t.Errorf("expected values to be equivalent but received %v and %v", v1, v2) + } +} + +func ExampleCopyOf() { + type Foo struct { + A int + B []*string + } + + // Create the initial value + str1 := "hello" + str2 := "bye bye" + f1 := &Foo{A: 1, B: []*string{&str1, &str2}} + + // Do the copy + v := awsutil.CopyOf(f1) + var f2 *Foo = v.(*Foo) + + // Print the result + fmt.Println(awsutil.Prettify(f2)) + + // Output: + // { + // A: 1, + // B: ["hello","bye bye"] + // } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go new file mode 100644 index 000000000..18d3c5b8e --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go @@ -0,0 +1,30 @@ +package awsutil_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awsutil" +) + +func TestDeepEqual(t *testing.T) { + cases := []struct { + a, b interface{} + equal bool + }{ + {"a", "a", true}, + {"a", "b", false}, + {"a", aws.String(""), false}, + {"a", nil, false}, + {"a", aws.String("a"), true}, + {(*bool)(nil), (*bool)(nil), true}, + {(*bool)(nil), (*string)(nil), false}, + {nil, nil, true}, + } + + for i, c := range cases { + if awsutil.DeepEqual(c.a, c.b) != c.equal { + t.Errorf("%d, a:%v b:%v, %t", i, c.a, c.b, c.equal) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go new file mode 100644 index 000000000..58a05d6ce --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go @@ -0,0 +1,182 @@ +package awsutil_test + +import ( + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws/awsutil" +) + +type Struct struct { + A []Struct + z []Struct + B *Struct + D *Struct + C string + E map[string]string +} + +var data = Struct{ + A: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}}, + z: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}}, + B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}}, + C: "initial", +} +var data2 = Struct{A: []Struct{ + {A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}}, + {A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}}, +}} + +func TestValueAtPathSuccess(t *testing.T) { + var testCases = []struct { + expect []interface{} + data interface{} + path string + }{ + {[]interface{}{"initial"}, data, "C"}, + {[]interface{}{"value1"}, data, "A[0].C"}, + {[]interface{}{"value2"}, data, "A[1].C"}, + {[]interface{}{"value3"}, data, "A[2].C"}, + {[]interface{}{"value3"}, data, "a[2].c"}, + {[]interface{}{"value3"}, data, "A[-1].C"}, + {[]interface{}{"value1", "value2", "value3"}, data, "A[].C"}, + {[]interface{}{"terminal"}, data, "B . B . C"}, + {[]interface{}{"initial"}, data, "A.D.X || C"}, + {[]interface{}{"initial"}, data, "A[0].B || C"}, + {[]interface{}{ + Struct{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}}, + Struct{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}}, + }, data2, "A"}, + } + for i, c := range testCases { + v, err := awsutil.ValuesAtPath(c.data, c.path) + if err != nil { + t.Errorf("case %v, expected no error, %v", i, c.path) + } + if e, a := c.expect, v; !awsutil.DeepEqual(e, a) { + t.Errorf("case %v, %v", i, c.path) + } + } +} + +func TestValueAtPathFailure(t *testing.T) { + var testCases = []struct { + expect []interface{} + errContains string + data interface{} + path string + }{ + {nil, "", data, "C.x"}, + {nil, "SyntaxError: Invalid token: tDot", data, ".x"}, + {nil, "", data, "X.Y.Z"}, + {nil, "", data, "A[100].C"}, + {nil, "", data, "A[3].C"}, + {nil, "", data, "B.B.C.Z"}, + {nil, "", data, "z[-1].C"}, + {nil, "", nil, "A.B.C"}, + {[]interface{}{}, "", Struct{}, "A"}, + {nil, "", data, "A[0].B.C"}, + {nil, "", data, "D"}, + } + + for i, c := range testCases { + v, err := awsutil.ValuesAtPath(c.data, c.path) + if c.errContains != "" { + if !strings.Contains(err.Error(), c.errContains) { + t.Errorf("case %v, expected error, %v", i, c.path) + } + continue + } else { + if err != nil { + t.Errorf("case %v, expected no error, %v", i, c.path) + } + } + if e, a := c.expect, v; !awsutil.DeepEqual(e, a) { + t.Errorf("case %v, %v", i, c.path) + } + } +} + +func TestSetValueAtPathSuccess(t *testing.T) { + var s Struct + awsutil.SetValueAtPath(&s, "C", "test1") + awsutil.SetValueAtPath(&s, "B.B.C", "test2") + awsutil.SetValueAtPath(&s, "B.D.C", "test3") + if e, a := "test1", s.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + if e, a := "test2", s.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + if e, a := "test3", s.B.D.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + awsutil.SetValueAtPath(&s, "B.*.C", "test0") + if e, a := "test0", s.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + if e, a := "test0", s.B.D.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + var s2 Struct + awsutil.SetValueAtPath(&s2, "b.b.c", "test0") + if e, a := "test0", s2.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + awsutil.SetValueAtPath(&s2, "A", []Struct{{}}) + if e, a := []Struct{{}}, s2.A; !awsutil.DeepEqual(e, a) { + t.Errorf("expected %v, but received %v", e, a) + } + + str := "foo" + + s3 := Struct{} + awsutil.SetValueAtPath(&s3, "b.b.c", str) + if e, a := "foo", s3.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + s3 = Struct{B: &Struct{B: &Struct{C: str}}} + awsutil.SetValueAtPath(&s3, "b.b.c", nil) + if e, a := "", s3.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + s3 = Struct{} + awsutil.SetValueAtPath(&s3, "b.b.c", nil) + if e, a := "", s3.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + s3 = Struct{} + awsutil.SetValueAtPath(&s3, "b.b.c", &str) + if e, a := "foo", s3.B.B.C; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + var s4 struct{ Name *string } + awsutil.SetValueAtPath(&s4, "Name", str) + if e, a := str, *s4.Name; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + s4 = struct{ Name *string }{} + awsutil.SetValueAtPath(&s4, "Name", nil) + if e, a := (*string)(nil), s4.Name; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + s4 = struct{ Name *string }{Name: &str} + awsutil.SetValueAtPath(&s4, "Name", nil) + if e, a := (*string)(nil), s4.Name; e != a { + t.Errorf("expected %v, but received %v", e, a) + } + + s4 = struct{ Name *string }{} + awsutil.SetValueAtPath(&s4, "Name", &str) + if e, a := str, *s4.Name; e != a { + t.Errorf("expected %v, but received %v", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go b/vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go new file mode 100644 index 000000000..30d3b9997 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go @@ -0,0 +1,78 @@ +package client + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" +) + +func pushBackTestHandler(name string, list *request.HandlerList) *bool { + called := false + (*list).PushBackNamed(request.NamedHandler{ + Name: name, + Fn: func(r *request.Request) { + called = true + }, + }) + + return &called +} + +func pushFrontTestHandler(name string, list *request.HandlerList) *bool { + called := false + (*list).PushFrontNamed(request.NamedHandler{ + Name: name, + Fn: func(r *request.Request) { + called = true + }, + }) + + return &called +} + +func TestNewClient_CopyHandlers(t *testing.T) { + handlers := request.Handlers{} + firstCalled := pushBackTestHandler("first", &handlers.Send) + secondCalled := pushBackTestHandler("second", &handlers.Send) + + var clientHandlerCalled *bool + c := New(aws.Config{}, metadata.ClientInfo{}, handlers, + func(c *Client) { + clientHandlerCalled = pushFrontTestHandler("client handler", &c.Handlers.Send) + }, + ) + + if e, a := 2, handlers.Send.Len(); e != a { + t.Errorf("expect %d original handlers, got %d", e, a) + } + if e, a := 3, c.Handlers.Send.Len(); e != a { + t.Errorf("expect %d client handlers, got %d", e, a) + } + + handlers.Send.Run(nil) + if !*firstCalled { + t.Errorf("expect first handler to of been called") + } + *firstCalled = false + if !*secondCalled { + t.Errorf("expect second handler to of been called") + } + *secondCalled = false + if *clientHandlerCalled { + t.Errorf("expect client handler to not of been called, but was") + } + + c.Handlers.Send.Run(nil) + if !*firstCalled { + t.Errorf("expect client's first handler to of been called") + } + if !*secondCalled { + t.Errorf("expect client's second handler to of been called") + } + if !*clientHandlerCalled { + t.Errorf("expect client's client handler to of been called") + } + +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go b/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go new file mode 100644 index 000000000..fddba4e49 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go @@ -0,0 +1,189 @@ +package client + +import ( + "net/http" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/request" +) + +func TestRetryThrottleStatusCodes(t *testing.T) { + cases := []struct { + expectThrottle bool + expectRetry bool + r request.Request + }{ + { + false, + false, + request.Request{ + HTTPResponse: &http.Response{StatusCode: 200}, + }, + }, + { + true, + true, + request.Request{ + HTTPResponse: &http.Response{StatusCode: 429}, + }, + }, + { + true, + true, + request.Request{ + HTTPResponse: &http.Response{StatusCode: 502}, + }, + }, + { + true, + true, + request.Request{ + HTTPResponse: &http.Response{StatusCode: 503}, + }, + }, + { + true, + true, + request.Request{ + HTTPResponse: &http.Response{StatusCode: 504}, + }, + }, + { + false, + true, + request.Request{ + HTTPResponse: &http.Response{StatusCode: 500}, + }, + }, + } + + d := DefaultRetryer{NumMaxRetries: 10} + for i, c := range cases { + throttle := d.shouldThrottle(&c.r) + retry := d.ShouldRetry(&c.r) + + if e, a := c.expectThrottle, throttle; e != a { + t.Errorf("%d: expected %v, but received %v", i, e, a) + } + + if e, a := c.expectRetry, retry; e != a { + t.Errorf("%d: expected %v, but received %v", i, e, a) + } + } +} + +func TestCanUseRetryAfter(t *testing.T) { + cases := []struct { + r request.Request + e bool + }{ + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 200}, + }, + false, + }, + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 500}, + }, + false, + }, + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 429}, + }, + true, + }, + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 503}, + }, + true, + }, + } + + for i, c := range cases { + a := canUseRetryAfterHeader(&c.r) + if c.e != a { + t.Errorf("%d: expected %v, but received %v", i, c.e, a) + } + } +} + +func TestGetRetryDelay(t *testing.T) { + cases := []struct { + r request.Request + e time.Duration + equal bool + ok bool + }{ + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 429, Header: http.Header{"Retry-After": []string{"3600"}}}, + }, + 3600 * time.Second, + true, + true, + }, + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}}, + }, + 120 * time.Second, + true, + true, + }, + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}}, + }, + 1 * time.Second, + false, + true, + }, + { + request.Request{ + HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}}, + }, + 0 * time.Second, + true, + false, + }, + } + + for i, c := range cases { + a, ok := getRetryDelay(&c.r) + if c.ok != ok { + t.Errorf("%d: expected %v, but received %v", i, c.ok, ok) + } + + if (c.e != a) == c.equal { + t.Errorf("%d: expected %v, but received %v", i, c.e, a) + } + } +} + +func TestRetryDelay(t *testing.T) { + r := request.Request{} + for i := 0; i < 100; i++ { + rTemp := r + rTemp.HTTPResponse = &http.Response{StatusCode: 500, Header: http.Header{"Retry-After": []string{""}}} + rTemp.RetryCount = i + a, _ := getRetryDelay(&rTemp) + if a > 5*time.Minute { + t.Errorf("retry delay should never be greater than five minutes, received %d", a) + } + } + + for i := 0; i < 100; i++ { + rTemp := r + rTemp.RetryCount = i + rTemp.HTTPResponse = &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}} + a, _ := getRetryDelay(&rTemp) + if a > 5*time.Minute { + t.Errorf("retry delay should never be greater than five minutes, received %d", a) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go b/vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go new file mode 100644 index 000000000..f0e06b805 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go @@ -0,0 +1,144 @@ +package client + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/corehandlers" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/request" +) + +type mockCloser struct { + closed bool +} + +func (closer *mockCloser) Read(b []byte) (int, error) { + return 0, io.EOF +} + +func (closer *mockCloser) Close() error { + closer.closed = true + return nil +} + +func TestTeeReaderCloser(t *testing.T) { + expected := "FOO" + buf := bytes.NewBuffer([]byte(expected)) + lw := bytes.NewBuffer(nil) + c := &mockCloser{} + closer := teeReaderCloser{ + io.TeeReader(buf, lw), + c, + } + + b := make([]byte, len(expected)) + _, err := closer.Read(b) + closer.Close() + + if expected != lw.String() { + t.Errorf("Expected %q, but received %q", expected, lw.String()) + } + + if err != nil { + t.Errorf("Expected 'nil', but received %v", err) + } + + if !c.closed { + t.Error("Expected 'true', but received 'false'") + } +} + +func TestLogWriter(t *testing.T) { + expected := "FOO" + lw := &logWriter{nil, bytes.NewBuffer(nil)} + lw.Write([]byte(expected)) + + if expected != lw.buf.String() { + t.Errorf("Expected %q, but received %q", expected, lw.buf.String()) + } +} + +func TestLogRequest(t *testing.T) { + cases := []struct { + Body io.ReadSeeker + ExpectBody []byte + LogLevel aws.LogLevelType + }{ + { + Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("body content"))), + ExpectBody: []byte("body content"), + }, + { + Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("body content"))), + LogLevel: aws.LogDebugWithHTTPBody, + ExpectBody: []byte("body content"), + }, + { + Body: bytes.NewReader([]byte("body content")), + ExpectBody: []byte("body content"), + }, + { + Body: bytes.NewReader([]byte("body content")), + LogLevel: aws.LogDebugWithHTTPBody, + ExpectBody: []byte("body content"), + }, + } + + for i, c := range cases { + logW := bytes.NewBuffer(nil) + req := request.New( + aws.Config{ + Credentials: credentials.AnonymousCredentials, + Logger: &bufLogger{w: logW}, + LogLevel: aws.LogLevel(c.LogLevel), + }, + metadata.ClientInfo{ + Endpoint: "https://mock-service.mock-region.amazonaws.com", + }, + testHandlers(), + nil, + &request.Operation{ + Name: "APIName", + HTTPMethod: "POST", + HTTPPath: "/", + }, + struct{}{}, nil, + ) + req.SetReaderBody(c.Body) + req.Build() + + logRequest(req) + + b, err := ioutil.ReadAll(req.HTTPRequest.Body) + if err != nil { + t.Fatalf("%d, expect to read SDK request Body", i) + } + + if e, a := c.ExpectBody, b; !reflect.DeepEqual(e, a) { + t.Errorf("%d, expect %v body, got %v", i, e, a) + } + } +} + +type bufLogger struct { + w *bytes.Buffer +} + +func (l *bufLogger) Log(args ...interface{}) { + fmt.Fprintln(l.w, args...) +} + +func testHandlers() request.Handlers { + var handlers request.Handlers + + handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler) + + return handlers +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/config_test.go b/vendor/github.com/aws/aws-sdk-go/aws/config_test.go new file mode 100644 index 000000000..fe97a31fc --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/config_test.go @@ -0,0 +1,86 @@ +package aws + +import ( + "net/http" + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/aws/credentials" +) + +var testCredentials = credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + +var copyTestConfig = Config{ + Credentials: testCredentials, + Endpoint: String("CopyTestEndpoint"), + Region: String("COPY_TEST_AWS_REGION"), + DisableSSL: Bool(true), + HTTPClient: http.DefaultClient, + LogLevel: LogLevel(LogDebug), + Logger: NewDefaultLogger(), + MaxRetries: Int(3), + DisableParamValidation: Bool(true), + DisableComputeChecksums: Bool(true), + S3ForcePathStyle: Bool(true), +} + +func TestCopy(t *testing.T) { + want := copyTestConfig + got := copyTestConfig.Copy() + if !reflect.DeepEqual(*got, want) { + t.Errorf("Copy() = %+v", got) + t.Errorf(" want %+v", want) + } + + got.Region = String("other") + if got.Region == want.Region { + t.Errorf("Expect setting copy values not not reflect in source") + } +} + +func TestCopyReturnsNewInstance(t *testing.T) { + want := copyTestConfig + got := copyTestConfig.Copy() + if got == &want { + t.Errorf("Copy() = %p; want different instance as source %p", got, &want) + } +} + +var mergeTestZeroValueConfig = Config{} + +var mergeTestConfig = Config{ + Credentials: testCredentials, + Endpoint: String("MergeTestEndpoint"), + Region: String("MERGE_TEST_AWS_REGION"), + DisableSSL: Bool(true), + HTTPClient: http.DefaultClient, + LogLevel: LogLevel(LogDebug), + Logger: NewDefaultLogger(), + MaxRetries: Int(10), + DisableParamValidation: Bool(true), + DisableComputeChecksums: Bool(true), + S3ForcePathStyle: Bool(true), +} + +var mergeTests = []struct { + cfg *Config + in *Config + want *Config +}{ + {&Config{}, nil, &Config{}}, + {&Config{}, &mergeTestZeroValueConfig, &Config{}}, + {&Config{}, &mergeTestConfig, &mergeTestConfig}, +} + +func TestMerge(t *testing.T) { + for i, tt := range mergeTests { + got := tt.cfg.Copy() + got.MergeIn(tt.in) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Config %d %+v", i, tt.cfg) + t.Errorf(" Merge(%+v)", tt.in) + t.Errorf(" got %+v", got) + t.Errorf(" want %+v", tt.want) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/context_test.go b/vendor/github.com/aws/aws-sdk-go/aws/context_test.go new file mode 100644 index 000000000..d80a1bb6d --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/context_test.go @@ -0,0 +1,37 @@ +package aws_test + +import ( + "fmt" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/awstesting" +) + +func TestSleepWithContext(t *testing.T) { + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + + err := aws.SleepWithContext(ctx, 1*time.Millisecond) + if err != nil { + t.Errorf("expect context to not be canceled, got %v", err) + } +} + +func TestSleepWithContext_Canceled(t *testing.T) { + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + + expectErr := fmt.Errorf("context canceled") + + ctx.Error = expectErr + close(ctx.DoneCh) + + err := aws.SleepWithContext(ctx, 1*time.Millisecond) + if err == nil { + t.Fatalf("expect error, did not get one") + } + + if e, a := expectErr, err; e != a { + t.Errorf("expect %v error, got %v", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go b/vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go new file mode 100644 index 000000000..1a9461e1b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go @@ -0,0 +1,641 @@ +package aws + +import ( + "reflect" + "testing" + "time" +) + +var testCasesStringSlice = [][]string{ + {"a", "b", "c", "d", "e"}, + {"a", "b", "", "", "e"}, +} + +func TestStringSlice(t *testing.T) { + for idx, in := range testCasesStringSlice { + if in == nil { + continue + } + out := StringSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := StringValueSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesStringValueSlice = [][]*string{ + {String("a"), String("b"), nil, String("c")}, +} + +func TestStringValueSlice(t *testing.T) { + for idx, in := range testCasesStringValueSlice { + if in == nil { + continue + } + out := StringValueSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if in[i] == nil { + if out[i] != "" { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *(in[i]), out[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + + out2 := StringSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out2 { + if in[i] == nil { + if *(out2[i]) != "" { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *in[i], *out2[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + } +} + +var testCasesStringMap = []map[string]string{ + {"a": "1", "b": "2", "c": "3"}, +} + +func TestStringMap(t *testing.T) { + for idx, in := range testCasesStringMap { + if in == nil { + continue + } + out := StringMap(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := StringValueMap(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesBoolSlice = [][]bool{ + {true, true, false, false}, +} + +func TestBoolSlice(t *testing.T) { + for idx, in := range testCasesBoolSlice { + if in == nil { + continue + } + out := BoolSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := BoolValueSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesBoolValueSlice = [][]*bool{} + +func TestBoolValueSlice(t *testing.T) { + for idx, in := range testCasesBoolValueSlice { + if in == nil { + continue + } + out := BoolValueSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if in[i] == nil { + if out[i] { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *(in[i]), out[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + + out2 := BoolSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out2 { + if in[i] == nil { + if *(out2[i]) { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := in[i], out2[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + } +} + +var testCasesBoolMap = []map[string]bool{ + {"a": true, "b": false, "c": true}, +} + +func TestBoolMap(t *testing.T) { + for idx, in := range testCasesBoolMap { + if in == nil { + continue + } + out := BoolMap(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := BoolValueMap(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesIntSlice = [][]int{ + {1, 2, 3, 4}, +} + +func TestIntSlice(t *testing.T) { + for idx, in := range testCasesIntSlice { + if in == nil { + continue + } + out := IntSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := IntValueSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesIntValueSlice = [][]*int{} + +func TestIntValueSlice(t *testing.T) { + for idx, in := range testCasesIntValueSlice { + if in == nil { + continue + } + out := IntValueSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if in[i] == nil { + if out[i] != 0 { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *(in[i]), out[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + + out2 := IntSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out2 { + if in[i] == nil { + if *(out2[i]) != 0 { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := in[i], out2[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + } +} + +var testCasesIntMap = []map[string]int{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestIntMap(t *testing.T) { + for idx, in := range testCasesIntMap { + if in == nil { + continue + } + out := IntMap(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := IntValueMap(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesInt64Slice = [][]int64{ + {1, 2, 3, 4}, +} + +func TestInt64Slice(t *testing.T) { + for idx, in := range testCasesInt64Slice { + if in == nil { + continue + } + out := Int64Slice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := Int64ValueSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesInt64ValueSlice = [][]*int64{} + +func TestInt64ValueSlice(t *testing.T) { + for idx, in := range testCasesInt64ValueSlice { + if in == nil { + continue + } + out := Int64ValueSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if in[i] == nil { + if out[i] != 0 { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *(in[i]), out[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + + out2 := Int64Slice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out2 { + if in[i] == nil { + if *(out2[i]) != 0 { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := in[i], out2[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + } +} + +var testCasesInt64Map = []map[string]int64{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestInt64Map(t *testing.T) { + for idx, in := range testCasesInt64Map { + if in == nil { + continue + } + out := Int64Map(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := Int64ValueMap(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesFloat64Slice = [][]float64{ + {1, 2, 3, 4}, +} + +func TestFloat64Slice(t *testing.T) { + for idx, in := range testCasesFloat64Slice { + if in == nil { + continue + } + out := Float64Slice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := Float64ValueSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesFloat64ValueSlice = [][]*float64{} + +func TestFloat64ValueSlice(t *testing.T) { + for idx, in := range testCasesFloat64ValueSlice { + if in == nil { + continue + } + out := Float64ValueSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if in[i] == nil { + if out[i] != 0 { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *(in[i]), out[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + + out2 := Float64Slice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out2 { + if in[i] == nil { + if *(out2[i]) != 0 { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := in[i], out2[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + } +} + +var testCasesFloat64Map = []map[string]float64{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestFloat64Map(t *testing.T) { + for idx, in := range testCasesFloat64Map { + if in == nil { + continue + } + out := Float64Map(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := Float64ValueMap(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesTimeSlice = [][]time.Time{ + {time.Now(), time.Now().AddDate(100, 0, 0)}, +} + +func TestTimeSlice(t *testing.T) { + for idx, in := range testCasesTimeSlice { + if in == nil { + continue + } + out := TimeSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := TimeValueSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +var testCasesTimeValueSlice = [][]*time.Time{} + +func TestTimeValueSlice(t *testing.T) { + for idx, in := range testCasesTimeValueSlice { + if in == nil { + continue + } + out := TimeValueSlice(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if in[i] == nil { + if !out[i].IsZero() { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := *(in[i]), out[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + + out2 := TimeSlice(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out2 { + if in[i] == nil { + if !(*(out2[i])).IsZero() { + t.Errorf("Unexpected value at idx %d", idx) + } + } else { + if e, a := in[i], out2[i]; e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + } + } +} + +var testCasesTimeMap = []map[string]time.Time{ + {"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()}, +} + +func TestTimeMap(t *testing.T) { + for idx, in := range testCasesTimeMap { + if in == nil { + continue + } + out := TimeMap(in) + if e, a := len(out), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + for i := range out { + if e, a := in[i], *(out[i]); e != a { + t.Errorf("Unexpected value at idx %d", idx) + } + } + + out2 := TimeValueMap(out) + if e, a := len(out2), len(in); e != a { + t.Errorf("Unexpected len at idx %d", idx) + } + if e, a := in, out2; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected value at idx %d", idx) + } + } +} + +type TimeValueTestCase struct { + in int64 + outSecs time.Time + outMillis time.Time +} + +var testCasesTimeValue = []TimeValueTestCase{ + { + in: int64(1501558289000), + outSecs: time.Unix(1501558289, 0), + outMillis: time.Unix(1501558289, 0), + }, + { + in: int64(1501558289001), + outSecs: time.Unix(1501558289, 0), + outMillis: time.Unix(1501558289, 1*1000000), + }, +} + +func TestSecondsTimeValue(t *testing.T) { + for idx, testCase := range testCasesTimeValue { + out := SecondsTimeValue(&testCase.in) + if e, a := testCase.outSecs, out; e != a { + t.Errorf("Unexpected value for time value at %d", idx) + } + } +} + +func TestMillisecondsTimeValue(t *testing.T) { + for idx, testCase := range testCasesTimeValue { + out := MillisecondsTimeValue(&testCase.in) + if e, a := testCase.outMillis, out; e != a { + t.Errorf("Unexpected value for time value at %d", idx) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go new file mode 100644 index 000000000..b47afc249 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go @@ -0,0 +1,64 @@ +// +build go1.8 + +package corehandlers_test + +import ( + "crypto/tls" + "net/http" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/service/s3" + "golang.org/x/net/http2" +) + +func TestSendHandler_HEADNoBody(t *testing.T) { + TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile, err := awstesting.CreateTLSBundleFiles() + if err != nil { + panic(err) + } + defer awstesting.CleanupTLSBundleFiles(TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile) + + endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + transport := http.DefaultTransport.(*http.Transport) + // test server's certificate is self-signed certificate + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + http2.ConfigureTransport(transport) + + sess, err := session.NewSessionWithOptions(session.Options{ + Config: aws.Config{ + HTTPClient: &http.Client{}, + Endpoint: aws.String(endpoint), + Region: aws.String("mock-region"), + Credentials: credentials.AnonymousCredentials, + S3ForcePathStyle: aws.Bool(true), + }, + }) + + svc := s3.New(sess) + + req, _ := svc.HeadObjectRequest(&s3.HeadObjectInput{ + Bucket: aws.String("bucketname"), + Key: aws.String("keyname"), + }) + + if e, a := request.NoBody, req.HTTPRequest.Body; e != a { + t.Fatalf("expect %T request body, got %T", e, a) + } + + err = req.Send() + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := http.StatusOK, req.HTTPResponse.StatusCode; e != a { + t.Errorf("expect %d status code, got %d", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go new file mode 100644 index 000000000..1d715c9f3 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go @@ -0,0 +1,398 @@ +package corehandlers_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/corehandlers" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/s3" +) + +func TestValidateEndpointHandler(t *testing.T) { + os.Clearenv() + + svc := awstesting.NewClient(aws.NewConfig().WithRegion("us-west-2")) + svc.Handlers.Clear() + svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) + + req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + err := req.Build() + + if err != nil { + t.Errorf("expect no error, got %v", err) + } +} + +func TestValidateEndpointHandlerErrorRegion(t *testing.T) { + os.Clearenv() + + svc := awstesting.NewClient() + svc.Handlers.Clear() + svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler) + + req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + err := req.Build() + + if err == nil { + t.Errorf("expect error, got none") + } + if e, a := aws.ErrMissingRegion, err; e != a { + t.Errorf("expect %v to be %v", e, a) + } +} + +type mockCredsProvider struct { + expired bool + retrieveCalled bool +} + +func (m *mockCredsProvider) Retrieve() (credentials.Value, error) { + m.retrieveCalled = true + return credentials.Value{ProviderName: "mockCredsProvider"}, nil +} + +func (m *mockCredsProvider) IsExpired() bool { + return m.expired +} + +func TestAfterRetryRefreshCreds(t *testing.T) { + os.Clearenv() + credProvider := &mockCredsProvider{} + + svc := awstesting.NewClient(&aws.Config{ + Credentials: credentials.NewCredentials(credProvider), + MaxRetries: aws.Int(1), + }) + + svc.Handlers.Clear() + svc.Handlers.ValidateResponse.PushBack(func(r *request.Request) { + r.Error = awserr.New("UnknownError", "", nil) + r.HTTPResponse = &http.Response{StatusCode: 400, Body: ioutil.NopCloser(bytes.NewBuffer([]byte{}))} + }) + svc.Handlers.UnmarshalError.PushBack(func(r *request.Request) { + r.Error = awserr.New("ExpiredTokenException", "", nil) + }) + svc.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler) + + if !svc.Config.Credentials.IsExpired() { + t.Errorf("Expect to start out expired") + } + if credProvider.retrieveCalled { + t.Errorf("expect not called") + } + + req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + req.Send() + + if !svc.Config.Credentials.IsExpired() { + t.Errorf("Expect to start out expired") + } + if credProvider.retrieveCalled { + t.Errorf("expect not called") + } + + _, err := svc.Config.Credentials.Get() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if !credProvider.retrieveCalled { + t.Errorf("expect not called") + } +} + +func TestAfterRetryWithContextCanceled(t *testing.T) { + c := awstesting.NewClient() + + req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)} + req.SetContext(ctx) + + req.Error = fmt.Errorf("some error") + req.Retryable = aws.Bool(true) + req.HTTPResponse = &http.Response{ + StatusCode: 500, + } + + close(ctx.DoneCh) + ctx.Error = fmt.Errorf("context canceled") + + corehandlers.AfterRetryHandler.Fn(req) + + if req.Error == nil { + t.Fatalf("expect error but didn't receive one") + } + + aerr := req.Error.(awserr.Error) + + if e, a := request.CanceledErrorCode, aerr.Code(); e != a { + t.Errorf("expect %q, error code got %q", e, a) + } +} + +func TestAfterRetryWithContext(t *testing.T) { + c := awstesting.NewClient() + + req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)} + req.SetContext(ctx) + + req.Error = fmt.Errorf("some error") + req.Retryable = aws.Bool(true) + req.HTTPResponse = &http.Response{ + StatusCode: 500, + } + + corehandlers.AfterRetryHandler.Fn(req) + + if req.Error != nil { + t.Fatalf("expect no error, got %v", req.Error) + } + if e, a := 1, req.RetryCount; e != a { + t.Errorf("expect retry count to be %d, got %d", e, a) + } +} + +func TestSendWithContextCanceled(t *testing.T) { + c := awstesting.NewClient(&aws.Config{ + SleepDelay: func(dur time.Duration) { + t.Errorf("SleepDelay should not be called") + }, + }) + + req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)} + req.SetContext(ctx) + + req.Error = fmt.Errorf("some error") + req.Retryable = aws.Bool(true) + req.HTTPResponse = &http.Response{ + StatusCode: 500, + } + + close(ctx.DoneCh) + ctx.Error = fmt.Errorf("context canceled") + + corehandlers.SendHandler.Fn(req) + + if req.Error == nil { + t.Fatalf("expect error but didn't receive one") + } + + aerr := req.Error.(awserr.Error) + + if e, a := request.CanceledErrorCode, aerr.Code(); e != a { + t.Errorf("expect %q, error code got %q", e, a) + } +} + +type testSendHandlerTransport struct{} + +func (t *testSendHandlerTransport) RoundTrip(r *http.Request) (*http.Response, error) { + return nil, fmt.Errorf("mock error") +} + +func TestSendHandlerError(t *testing.T) { + svc := awstesting.NewClient(&aws.Config{ + HTTPClient: &http.Client{ + Transport: &testSendHandlerTransport{}, + }, + }) + svc.Handlers.Clear() + svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler) + r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + + r.Send() + + if r.Error == nil { + t.Errorf("expect error, got none") + } + if r.HTTPResponse == nil { + t.Errorf("expect response, got none") + } +} + +func TestSendWithoutFollowRedirects(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/original": + w.Header().Set("Location", "/redirected") + w.WriteHeader(301) + case "/redirected": + t.Fatalf("expect not to redirect, but was") + } + })) + + svc := awstesting.NewClient(&aws.Config{ + DisableSSL: aws.Bool(true), + Endpoint: aws.String(server.URL), + }) + svc.Handlers.Clear() + svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler) + + r := svc.NewRequest(&request.Operation{ + Name: "Operation", + HTTPPath: "/original", + }, nil, nil) + r.DisableFollowRedirects = true + + err := r.Send() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := 301, r.HTTPResponse.StatusCode; e != a { + t.Errorf("expect %d status code, got %d", e, a) + } +} + +func TestValidateReqSigHandler(t *testing.T) { + cases := []struct { + Req *request.Request + Resign bool + }{ + { + Req: &request.Request{ + Config: aws.Config{Credentials: credentials.AnonymousCredentials}, + Time: time.Now().Add(-15 * time.Minute), + }, + Resign: false, + }, + { + Req: &request.Request{ + Time: time.Now().Add(-15 * time.Minute), + }, + Resign: true, + }, + { + Req: &request.Request{ + Time: time.Now().Add(-1 * time.Minute), + }, + Resign: false, + }, + } + + for i, c := range cases { + resigned := false + c.Req.Handlers.Sign.PushBack(func(r *request.Request) { + resigned = true + }) + + corehandlers.ValidateReqSigHandler.Fn(c.Req) + + if c.Req.Error != nil { + t.Errorf("expect no error, got %v", c.Req.Error) + } + if e, a := c.Resign, resigned; e != a { + t.Errorf("%d, expect %v to be %v", i, e, a) + } + } +} + +func setupContentLengthTestServer(t *testing.T, hasContentLength bool, contentLength int64) *httptest.Server { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, ok := r.Header["Content-Length"] + if e, a := hasContentLength, ok; e != a { + t.Errorf("expect %v to be %v", e, a) + } + if hasContentLength { + if e, a := contentLength, r.ContentLength; e != a { + t.Errorf("expect %v to be %v", e, a) + } + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("expect no error, got %v", err) + } + r.Body.Close() + + authHeader := r.Header.Get("Authorization") + if hasContentLength { + if e, a := "content-length", authHeader; !strings.Contains(a, e) { + t.Errorf("expect %v to be in %v", e, a) + } + } else { + if e, a := "content-length", authHeader; strings.Contains(a, e) { + t.Errorf("expect %v to not be in %v", e, a) + } + } + + if e, a := contentLength, int64(len(b)); e != a { + t.Errorf("expect %v to be %v", e, a) + } + })) + + return server +} + +func TestBuildContentLength_ZeroBody(t *testing.T) { + server := setupContentLengthTestServer(t, false, 0) + + svc := s3.New(unit.Session, &aws.Config{ + Endpoint: aws.String(server.URL), + S3ForcePathStyle: aws.Bool(true), + DisableSSL: aws.Bool(true), + }) + _, err := svc.GetObject(&s3.GetObjectInput{ + Bucket: aws.String("bucketname"), + Key: aws.String("keyname"), + }) + + if err != nil { + t.Errorf("expect no error, got %v", err) + } +} + +func TestBuildContentLength_NegativeBody(t *testing.T) { + server := setupContentLengthTestServer(t, false, 0) + + svc := s3.New(unit.Session, &aws.Config{ + Endpoint: aws.String(server.URL), + S3ForcePathStyle: aws.Bool(true), + DisableSSL: aws.Bool(true), + }) + req, _ := svc.GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String("bucketname"), + Key: aws.String("keyname"), + }) + + req.HTTPRequest.Header.Set("Content-Length", "-1") + + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } +} + +func TestBuildContentLength_WithBody(t *testing.T) { + server := setupContentLengthTestServer(t, true, 1024) + + svc := s3.New(unit.Session, &aws.Config{ + Endpoint: aws.String(server.URL), + S3ForcePathStyle: aws.Bool(true), + DisableSSL: aws.Bool(true), + }) + _, err := svc.PutObject(&s3.PutObjectInput{ + Bucket: aws.String("bucketname"), + Key: aws.String("keyname"), + Body: bytes.NewReader(make([]byte, 1024)), + }) + + if err != nil { + t.Errorf("expect no error, got %v", err) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go new file mode 100644 index 000000000..e1d8a08fd --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator_test.go @@ -0,0 +1,286 @@ +package corehandlers_test + +import ( + "fmt" + "testing" + "reflect" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/corehandlers" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/kinesis" +) + +var testSvc = func() *client.Client { + s := &client.Client{ + Config: aws.Config{}, + ClientInfo: metadata.ClientInfo{ + ServiceName: "mock-service", + APIVersion: "2015-01-01", + }, + } + return s +}() + +type StructShape struct { + _ struct{} `type:"structure"` + + RequiredList []*ConditionalStructShape `required:"true"` + RequiredMap map[string]*ConditionalStructShape `required:"true"` + RequiredBool *bool `required:"true"` + OptionalStruct *ConditionalStructShape + + hiddenParameter *string +} + +func (s *StructShape) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "StructShape"} + if s.RequiredList == nil { + invalidParams.Add(request.NewErrParamRequired("RequiredList")) + } + if s.RequiredMap == nil { + invalidParams.Add(request.NewErrParamRequired("RequiredMap")) + } + if s.RequiredBool == nil { + invalidParams.Add(request.NewErrParamRequired("RequiredBool")) + } + if s.RequiredList != nil { + for i, v := range s.RequiredList { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "RequiredList", i), err.(request.ErrInvalidParams)) + } + } + } + if s.RequiredMap != nil { + for i, v := range s.RequiredMap { + if v == nil { + continue + } + if err := v.Validate(); err != nil { + invalidParams.AddNested(fmt.Sprintf("%s[%v]", "RequiredMap", i), err.(request.ErrInvalidParams)) + } + } + } + if s.OptionalStruct != nil { + if err := s.OptionalStruct.Validate(); err != nil { + invalidParams.AddNested("OptionalStruct", err.(request.ErrInvalidParams)) + } + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +type ConditionalStructShape struct { + _ struct{} `type:"structure"` + + Name *string `required:"true"` +} + +func (s *ConditionalStructShape) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "ConditionalStructShape"} + if s.Name == nil { + invalidParams.Add(request.NewErrParamRequired("Name")) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +func TestNoErrors(t *testing.T) { + input := &StructShape{ + RequiredList: []*ConditionalStructShape{}, + RequiredMap: map[string]*ConditionalStructShape{ + "key1": {Name: aws.String("Name")}, + "key2": {Name: aws.String("Name")}, + }, + RequiredBool: aws.Bool(true), + OptionalStruct: &ConditionalStructShape{Name: aws.String("Name")}, + } + + req := testSvc.NewRequest(&request.Operation{}, input, nil) + corehandlers.ValidateParametersHandler.Fn(req) + if req.Error != nil { + t.Fatalf("expect no error, got %v", req.Error) + } +} + +func TestMissingRequiredParameters(t *testing.T) { + input := &StructShape{} + req := testSvc.NewRequest(&request.Operation{}, input, nil) + corehandlers.ValidateParametersHandler.Fn(req) + + if req.Error == nil { + t.Fatalf("expect error") + } + if e, a := "InvalidParameter", req.Error.(awserr.Error).Code(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "3 validation error(s) found.", req.Error.(awserr.Error).Message(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + errs := req.Error.(awserr.BatchedErrors).OrigErrs() + if e, a := 3, len(errs); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "ParamRequiredError: missing required field, StructShape.RequiredList.", errs[0].Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "ParamRequiredError: missing required field, StructShape.RequiredMap.", errs[1].Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "ParamRequiredError: missing required field, StructShape.RequiredBool.", errs[2].Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + if e, a := "InvalidParameter: 3 validation error(s) found.\n- missing required field, StructShape.RequiredList.\n- missing required field, StructShape.RequiredMap.\n- missing required field, StructShape.RequiredBool.\n", req.Error.Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestNestedMissingRequiredParameters(t *testing.T) { + input := &StructShape{ + RequiredList: []*ConditionalStructShape{{}}, + RequiredMap: map[string]*ConditionalStructShape{ + "key1": {Name: aws.String("Name")}, + "key2": {}, + }, + RequiredBool: aws.Bool(true), + OptionalStruct: &ConditionalStructShape{}, + } + + req := testSvc.NewRequest(&request.Operation{}, input, nil) + corehandlers.ValidateParametersHandler.Fn(req) + + if req.Error == nil { + t.Fatalf("expect error") + } + if e, a := "InvalidParameter", req.Error.(awserr.Error).Code(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "3 validation error(s) found.", req.Error.(awserr.Error).Message(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + errs := req.Error.(awserr.BatchedErrors).OrigErrs() + if e, a := 3, len(errs); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "ParamRequiredError: missing required field, StructShape.RequiredList[0].Name.", errs[0].Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "ParamRequiredError: missing required field, StructShape.RequiredMap[key2].Name.", errs[1].Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "ParamRequiredError: missing required field, StructShape.OptionalStruct.Name.", errs[2].Error(); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +type testInput struct { + StringField *string `min:"5"` + ListField []string `min:"3"` + MapField map[string]string `min:"4"` +} + +func (s testInput) Validate() error { + invalidParams := request.ErrInvalidParams{Context: "testInput"} + if s.StringField != nil && len(*s.StringField) < 5 { + invalidParams.Add(request.NewErrParamMinLen("StringField", 5)) + } + if s.ListField != nil && len(s.ListField) < 3 { + invalidParams.Add(request.NewErrParamMinLen("ListField", 3)) + } + if s.MapField != nil && len(s.MapField) < 4 { + invalidParams.Add(request.NewErrParamMinLen("MapField", 4)) + } + + if invalidParams.Len() > 0 { + return invalidParams + } + return nil +} + +var testsFieldMin = []struct { + err awserr.Error + in testInput +}{ + { + err: func() awserr.Error { + invalidParams := request.ErrInvalidParams{Context: "testInput"} + invalidParams.Add(request.NewErrParamMinLen("StringField", 5)) + return invalidParams + }(), + in: testInput{StringField: aws.String("abcd")}, + }, + { + err: func() awserr.Error { + invalidParams := request.ErrInvalidParams{Context: "testInput"} + invalidParams.Add(request.NewErrParamMinLen("StringField", 5)) + invalidParams.Add(request.NewErrParamMinLen("ListField", 3)) + return invalidParams + }(), + in: testInput{StringField: aws.String("abcd"), ListField: []string{"a", "b"}}, + }, + { + err: func() awserr.Error { + invalidParams := request.ErrInvalidParams{Context: "testInput"} + invalidParams.Add(request.NewErrParamMinLen("StringField", 5)) + invalidParams.Add(request.NewErrParamMinLen("ListField", 3)) + invalidParams.Add(request.NewErrParamMinLen("MapField", 4)) + return invalidParams + }(), + in: testInput{StringField: aws.String("abcd"), ListField: []string{"a", "b"}, MapField: map[string]string{"a": "a", "b": "b"}}, + }, + { + err: nil, + in: testInput{StringField: aws.String("abcde"), + ListField: []string{"a", "b", "c"}, MapField: map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}}, + }, +} + +func TestValidateFieldMinParameter(t *testing.T) { + for i, c := range testsFieldMin { + req := testSvc.NewRequest(&request.Operation{}, &c.in, nil) + corehandlers.ValidateParametersHandler.Fn(req) + + if e, a := c.err, req.Error; !reflect.DeepEqual(e,a) { + t.Errorf("%d, expect %v, got %v", i, e, a) + } + } +} + +func BenchmarkValidateAny(b *testing.B) { + input := &kinesis.PutRecordsInput{ + StreamName: aws.String("stream"), + } + for i := 0; i < 100; i++ { + record := &kinesis.PutRecordsRequestEntry{ + Data: make([]byte, 10000), + PartitionKey: aws.String("partition"), + } + input.Records = append(input.Records, record) + } + + req, _ := kinesis.New(unit.Session).PutRecordsRequest(input) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + corehandlers.ValidateParametersHandler.Fn(req) + if err := req.Error; err != nil { + b.Fatalf("validation failed: %v", err) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent_test.go b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent_test.go new file mode 100644 index 000000000..4f6183560 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent_test.go @@ -0,0 +1,40 @@ +package corehandlers + +import ( + "net/http" + "os" + "testing" + + "github.com/aws/aws-sdk-go/aws/request" +) + +func TestAddHostExecEnvUserAgentHander(t *testing.T) { + cases := []struct { + ExecEnv string + Expect string + }{ + {ExecEnv: "Lambda", Expect: "exec_env/Lambda"}, + {ExecEnv: "", Expect: ""}, + {ExecEnv: "someThingCool", Expect: "exec_env/someThingCool"}, + } + + for i, c := range cases { + os.Clearenv() + os.Setenv(execEnvVar, c.ExecEnv) + + req := &request.Request{ + HTTPRequest: &http.Request{ + Header: http.Header{}, + }, + } + AddHostExecEnvUserAgentHander.Fn(req) + + if err := req.Error; err != nil { + t.Fatalf("%d, expect no error, got %v", i, err) + } + + if e, a := c.Expect, req.HTTPRequest.Header.Get("User-Agent"); e != a { + t.Errorf("%d, expect %v user agent, got %v", i, e, a) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider_test.go new file mode 100644 index 000000000..3b393a2ed --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider_test.go @@ -0,0 +1,154 @@ +package credentials + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/stretchr/testify/assert" +) + +type secondStubProvider struct { + creds Value + expired bool + err error +} + +func (s *secondStubProvider) Retrieve() (Value, error) { + s.expired = false + s.creds.ProviderName = "secondStubProvider" + return s.creds, s.err +} +func (s *secondStubProvider) IsExpired() bool { + return s.expired +} + +func TestChainProviderWithNames(t *testing.T) { + p := &ChainProvider{ + Providers: []Provider{ + &stubProvider{err: awserr.New("FirstError", "first provider error", nil)}, + &stubProvider{err: awserr.New("SecondError", "second provider error", nil)}, + &secondStubProvider{ + creds: Value{ + AccessKeyID: "AKIF", + SecretAccessKey: "NOSECRET", + SessionToken: "", + }, + }, + &stubProvider{ + creds: Value{ + AccessKeyID: "AKID", + SecretAccessKey: "SECRET", + SessionToken: "", + }, + }, + }, + } + + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + assert.Equal(t, "secondStubProvider", creds.ProviderName, "Expect provider name to match") + + // Also check credentials + assert.Equal(t, "AKIF", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "NOSECRET", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect session token to be empty") + +} + +func TestChainProviderGet(t *testing.T) { + p := &ChainProvider{ + Providers: []Provider{ + &stubProvider{err: awserr.New("FirstError", "first provider error", nil)}, + &stubProvider{err: awserr.New("SecondError", "second provider error", nil)}, + &stubProvider{ + creds: Value{ + AccessKeyID: "AKID", + SecretAccessKey: "SECRET", + SessionToken: "", + }, + }, + }, + } + + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect session token to be empty") +} + +func TestChainProviderIsExpired(t *testing.T) { + stubProvider := &stubProvider{expired: true} + p := &ChainProvider{ + Providers: []Provider{ + stubProvider, + }, + } + + assert.True(t, p.IsExpired(), "Expect expired to be true before any Retrieve") + _, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + assert.False(t, p.IsExpired(), "Expect not expired after retrieve") + + stubProvider.expired = true + assert.True(t, p.IsExpired(), "Expect return of expired provider") + + _, err = p.Retrieve() + assert.False(t, p.IsExpired(), "Expect not expired after retrieve") +} + +func TestChainProviderWithNoProvider(t *testing.T) { + p := &ChainProvider{ + Providers: []Provider{}, + } + + assert.True(t, p.IsExpired(), "Expect expired with no providers") + _, err := p.Retrieve() + assert.Equal(t, + ErrNoValidProvidersFoundInChain, + err, + "Expect no providers error returned") +} + +func TestChainProviderWithNoValidProvider(t *testing.T) { + errs := []error{ + awserr.New("FirstError", "first provider error", nil), + awserr.New("SecondError", "second provider error", nil), + } + p := &ChainProvider{ + Providers: []Provider{ + &stubProvider{err: errs[0]}, + &stubProvider{err: errs[1]}, + }, + } + + assert.True(t, p.IsExpired(), "Expect expired with no providers") + _, err := p.Retrieve() + + assert.Equal(t, + ErrNoValidProvidersFoundInChain, + err, + "Expect no providers error returned") +} + +func TestChainProviderWithNoValidProviderWithVerboseEnabled(t *testing.T) { + errs := []error{ + awserr.New("FirstError", "first provider error", nil), + awserr.New("SecondError", "second provider error", nil), + } + p := &ChainProvider{ + VerboseErrors: true, + Providers: []Provider{ + &stubProvider{err: errs[0]}, + &stubProvider{err: errs[1]}, + }, + } + + assert.True(t, p.IsExpired(), "Expect expired with no providers") + _, err := p.Retrieve() + + assert.Equal(t, + awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs), + err, + "Expect no providers error returned") +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials_test.go new file mode 100644 index 000000000..7b79ba985 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials_test.go @@ -0,0 +1,73 @@ +package credentials + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/stretchr/testify/assert" +) + +type stubProvider struct { + creds Value + expired bool + err error +} + +func (s *stubProvider) Retrieve() (Value, error) { + s.expired = false + s.creds.ProviderName = "stubProvider" + return s.creds, s.err +} +func (s *stubProvider) IsExpired() bool { + return s.expired +} + +func TestCredentialsGet(t *testing.T) { + c := NewCredentials(&stubProvider{ + creds: Value{ + AccessKeyID: "AKID", + SecretAccessKey: "SECRET", + SessionToken: "", + }, + expired: true, + }) + + creds, err := c.Get() + assert.Nil(t, err, "Expected no error") + assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect session token to be empty") +} + +func TestCredentialsGetWithError(t *testing.T) { + c := NewCredentials(&stubProvider{err: awserr.New("provider error", "", nil), expired: true}) + + _, err := c.Get() + assert.Equal(t, "provider error", err.(awserr.Error).Code(), "Expected provider error") +} + +func TestCredentialsExpire(t *testing.T) { + stub := &stubProvider{} + c := NewCredentials(stub) + + stub.expired = false + assert.True(t, c.IsExpired(), "Expected to start out expired") + c.Expire() + assert.True(t, c.IsExpired(), "Expected to be expired") + + c.forceRefresh = false + assert.False(t, c.IsExpired(), "Expected not to be expired") + + stub.expired = true + assert.True(t, c.IsExpired(), "Expected to be expired") +} + +func TestCredentialsGetWithProviderName(t *testing.T) { + stub := &stubProvider{} + + c := NewCredentials(stub) + + creds, err := c.Get() + assert.Nil(t, err, "Expected no error") + assert.Equal(t, creds.ProviderName, "stubProvider", "Expected provider name to match") +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go new file mode 100644 index 000000000..cccd4bffe --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go @@ -0,0 +1,159 @@ +package ec2rolecreds_test + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" + "github.com/aws/aws-sdk-go/aws/ec2metadata" + "github.com/aws/aws-sdk-go/awstesting/unit" +) + +const credsRespTmpl = `{ + "Code": "Success", + "Type": "AWS-HMAC", + "AccessKeyId" : "accessKey", + "SecretAccessKey" : "secret", + "Token" : "token", + "Expiration" : "%s", + "LastUpdated" : "2009-11-23T0:00:00Z" +}` + +const credsFailRespTmpl = `{ + "Code": "ErrorCode", + "Message": "ErrorMsg", + "LastUpdated": "2009-11-23T0:00:00Z" +}` + +func initTestServer(expireOn string, failAssume bool) *httptest.Server { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/latest/meta-data/iam/security-credentials" { + fmt.Fprintln(w, "RoleName") + } else if r.URL.Path == "/latest/meta-data/iam/security-credentials/RoleName" { + if failAssume { + fmt.Fprintf(w, credsFailRespTmpl) + } else { + fmt.Fprintf(w, credsRespTmpl, expireOn) + } + } else { + http.Error(w, "bad request", http.StatusBadRequest) + } + })) + + return server +} + +func TestEC2RoleProvider(t *testing.T) { + server := initTestServer("2014-12-16T01:51:37Z", false) + defer server.Close() + + p := &ec2rolecreds.EC2RoleProvider{ + Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}), + } + + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error, %v", err) + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "token", creds.SessionToken, "Expect session token to match") +} + +func TestEC2RoleProviderFailAssume(t *testing.T) { + server := initTestServer("2014-12-16T01:51:37Z", true) + defer server.Close() + + p := &ec2rolecreds.EC2RoleProvider{ + Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}), + } + + creds, err := p.Retrieve() + assert.Error(t, err, "Expect error") + + e := err.(awserr.Error) + assert.Equal(t, "ErrorCode", e.Code()) + assert.Equal(t, "ErrorMsg", e.Message()) + assert.Nil(t, e.OrigErr()) + + assert.Equal(t, "", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "", creds.SessionToken, "Expect session token to match") +} + +func TestEC2RoleProviderIsExpired(t *testing.T) { + server := initTestServer("2014-12-16T01:51:37Z", false) + defer server.Close() + + p := &ec2rolecreds.EC2RoleProvider{ + Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}), + } + p.CurrentTime = func() time.Time { + return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC) + } + + assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.") + + _, err := p.Retrieve() + assert.Nil(t, err, "Expect no error, %v", err) + + assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.") + + p.CurrentTime = func() time.Time { + return time.Date(3014, 12, 15, 21, 26, 0, 0, time.UTC) + } + + assert.True(t, p.IsExpired(), "Expect creds to be expired.") +} + +func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) { + server := initTestServer("2014-12-16T01:51:37Z", false) + defer server.Close() + + p := &ec2rolecreds.EC2RoleProvider{ + Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}), + ExpiryWindow: time.Hour * 1, + } + p.CurrentTime = func() time.Time { + return time.Date(2014, 12, 15, 0, 51, 37, 0, time.UTC) + } + + assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.") + + _, err := p.Retrieve() + assert.Nil(t, err, "Expect no error, %v", err) + + assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.") + + p.CurrentTime = func() time.Time { + return time.Date(2014, 12, 16, 0, 55, 37, 0, time.UTC) + } + + assert.True(t, p.IsExpired(), "Expect creds to be expired.") +} + +func BenchmarkEC3RoleProvider(b *testing.B) { + server := initTestServer("2014-12-16T01:51:37Z", false) + defer server.Close() + + p := &ec2rolecreds.EC2RoleProvider{ + Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}), + } + _, err := p.Retrieve() + if err != nil { + b.Fatal(err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := p.Retrieve(); err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider_test.go new file mode 100644 index 000000000..ad057a355 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider_test.go @@ -0,0 +1,111 @@ +package endpointcreds_test + +import ( + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/stretchr/testify/assert" +) + +func TestRetrieveRefreshableCredentials(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/path/to/endpoint", r.URL.Path) + assert.Equal(t, "application/json", r.Header.Get("Accept")) + assert.Equal(t, "else", r.URL.Query().Get("something")) + + encoder := json.NewEncoder(w) + err := encoder.Encode(map[string]interface{}{ + "AccessKeyID": "AKID", + "SecretAccessKey": "SECRET", + "Token": "TOKEN", + "Expiration": time.Now().Add(1 * time.Hour), + }) + + if err != nil { + fmt.Println("failed to write out creds", err) + } + })) + + client := endpointcreds.NewProviderClient(*unit.Session.Config, + unit.Session.Handlers, + server.URL+"/path/to/endpoint?something=else", + ) + creds, err := client.Retrieve() + + assert.NoError(t, err) + + assert.Equal(t, "AKID", creds.AccessKeyID) + assert.Equal(t, "SECRET", creds.SecretAccessKey) + assert.Equal(t, "TOKEN", creds.SessionToken) + assert.False(t, client.IsExpired()) + + client.(*endpointcreds.Provider).CurrentTime = func() time.Time { + return time.Now().Add(2 * time.Hour) + } + + assert.True(t, client.IsExpired()) +} + +func TestRetrieveStaticCredentials(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + encoder := json.NewEncoder(w) + err := encoder.Encode(map[string]interface{}{ + "AccessKeyID": "AKID", + "SecretAccessKey": "SECRET", + }) + + if err != nil { + fmt.Println("failed to write out creds", err) + } + })) + + client := endpointcreds.NewProviderClient(*unit.Session.Config, unit.Session.Handlers, server.URL) + creds, err := client.Retrieve() + + assert.NoError(t, err) + + assert.Equal(t, "AKID", creds.AccessKeyID) + assert.Equal(t, "SECRET", creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) + assert.False(t, client.IsExpired()) +} + +func TestFailedRetrieveCredentials(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(400) + encoder := json.NewEncoder(w) + err := encoder.Encode(map[string]interface{}{ + "Code": "Error", + "Message": "Message", + }) + + if err != nil { + fmt.Println("failed to write error", err) + } + })) + + client := endpointcreds.NewProviderClient(*unit.Session.Config, unit.Session.Handlers, server.URL) + creds, err := client.Retrieve() + + assert.Error(t, err) + aerr := err.(awserr.Error) + + assert.Equal(t, "CredentialsEndpointError", aerr.Code()) + assert.Equal(t, "failed to load credentials", aerr.Message()) + + aerr = aerr.OrigErr().(awserr.Error) + assert.Equal(t, "Error", aerr.Code()) + assert.Equal(t, "Message", aerr.Message()) + + assert.Empty(t, creds.AccessKeyID) + assert.Empty(t, creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) + assert.True(t, client.IsExpired()) +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider_test.go new file mode 100644 index 000000000..53f6ce256 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider_test.go @@ -0,0 +1,70 @@ +package credentials + +import ( + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +func TestEnvProviderRetrieve(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_ACCESS_KEY_ID", "access") + os.Setenv("AWS_SECRET_ACCESS_KEY", "secret") + os.Setenv("AWS_SESSION_TOKEN", "token") + + e := EnvProvider{} + creds, err := e.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "access", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "token", creds.SessionToken, "Expect session token to match") +} + +func TestEnvProviderIsExpired(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_ACCESS_KEY_ID", "access") + os.Setenv("AWS_SECRET_ACCESS_KEY", "secret") + os.Setenv("AWS_SESSION_TOKEN", "token") + + e := EnvProvider{} + + assert.True(t, e.IsExpired(), "Expect creds to be expired before retrieve.") + + _, err := e.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.False(t, e.IsExpired(), "Expect creds to not be expired after retrieve.") +} + +func TestEnvProviderNoAccessKeyID(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_SECRET_ACCESS_KEY", "secret") + + e := EnvProvider{} + creds, err := e.Retrieve() + assert.Equal(t, ErrAccessKeyIDNotFound, err, "ErrAccessKeyIDNotFound expected, but was %#v error: %#v", creds, err) +} + +func TestEnvProviderNoSecretAccessKey(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_ACCESS_KEY_ID", "access") + + e := EnvProvider{} + creds, err := e.Retrieve() + assert.Equal(t, ErrSecretAccessKeyNotFound, err, "ErrSecretAccessKeyNotFound expected, but was %#v error: %#v", creds, err) +} + +func TestEnvProviderAlternateNames(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_ACCESS_KEY", "access") + os.Setenv("AWS_SECRET_KEY", "secret") + + e := EnvProvider{} + creds, err := e.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "access", creds.AccessKeyID, "Expected access key ID") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expected secret access key") + assert.Empty(t, creds.SessionToken, "Expected no token") +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini b/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini new file mode 100644 index 000000000..7fc91d9d2 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini @@ -0,0 +1,12 @@ +[default] +aws_access_key_id = accessKey +aws_secret_access_key = secret +aws_session_token = token + +[no_token] +aws_access_key_id = accessKey +aws_secret_access_key = secret + +[with_colon] +aws_access_key_id: accessKey +aws_secret_access_key: secret diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider_test.go new file mode 100644 index 000000000..1eb45f263 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider_test.go @@ -0,0 +1,136 @@ +package credentials + +import ( + "os" + "path/filepath" + "testing" + + "github.com/aws/aws-sdk-go/internal/shareddefaults" + "github.com/stretchr/testify/assert" +) + +func TestSharedCredentialsProvider(t *testing.T) { + os.Clearenv() + + p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""} + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "token", creds.SessionToken, "Expect session token to match") +} + +func TestSharedCredentialsProviderIsExpired(t *testing.T) { + os.Clearenv() + + p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""} + + assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve") + + _, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve") +} + +func TestSharedCredentialsProviderWithAWS_SHARED_CREDENTIALS_FILE(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "example.ini") + p := SharedCredentialsProvider{} + creds, err := p.Retrieve() + + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "token", creds.SessionToken, "Expect session token to match") +} + +func TestSharedCredentialsProviderWithAWS_SHARED_CREDENTIALS_FILEAbsPath(t *testing.T) { + os.Clearenv() + wd, err := os.Getwd() + assert.NoError(t, err) + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", filepath.Join(wd, "example.ini")) + p := SharedCredentialsProvider{} + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "token", creds.SessionToken, "Expect session token to match") +} + +func TestSharedCredentialsProviderWithAWS_PROFILE(t *testing.T) { + os.Clearenv() + os.Setenv("AWS_PROFILE", "no_token") + + p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""} + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect no token") +} + +func TestSharedCredentialsProviderWithoutTokenFromProfile(t *testing.T) { + os.Clearenv() + + p := SharedCredentialsProvider{Filename: "example.ini", Profile: "no_token"} + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect no token") +} + +func TestSharedCredentialsProviderColonInCredFile(t *testing.T) { + os.Clearenv() + + p := SharedCredentialsProvider{Filename: "example.ini", Profile: "with_colon"} + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect no token") +} + +func TestSharedCredentialsProvider_DefaultFilename(t *testing.T) { + os.Clearenv() + os.Setenv("USERPROFILE", "profile_dir") + os.Setenv("HOME", "home_dir") + + // default filename and profile + p := SharedCredentialsProvider{} + + filename, err := p.filename() + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := shareddefaults.SharedCredentialsFilename(), filename; e != a { + t.Errorf("expect %q filename, got %q", e, a) + } +} + +func BenchmarkSharedCredentialsProvider(b *testing.B) { + os.Clearenv() + + p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""} + _, err := p.Retrieve() + if err != nil { + b.Fatal(err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := p.Retrieve() + if err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider_test.go new file mode 100644 index 000000000..ea0123696 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider_test.go @@ -0,0 +1,34 @@ +package credentials + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestStaticProviderGet(t *testing.T) { + s := StaticProvider{ + Value: Value{ + AccessKeyID: "AKID", + SecretAccessKey: "SECRET", + SessionToken: "", + }, + } + + creds, err := s.Retrieve() + assert.Nil(t, err, "Expect no error") + assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match") + assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match") + assert.Empty(t, creds.SessionToken, "Expect no session token") +} + +func TestStaticProviderIsExpired(t *testing.T) { + s := StaticProvider{ + Value: Value{ + AccessKeyID: "AKID", + SecretAccessKey: "SECRET", + SessionToken: "", + }, + } + + assert.False(t, s.IsExpired(), "Expect static credentials to never expire") +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider_test.go b/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider_test.go new file mode 100644 index 000000000..4c0212a01 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider_test.go @@ -0,0 +1,150 @@ +package stscreds + +import ( + "fmt" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sts" + "github.com/stretchr/testify/assert" +) + +type stubSTS struct { + TestInput func(*sts.AssumeRoleInput) +} + +func (s *stubSTS) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) { + if s.TestInput != nil { + s.TestInput(input) + } + expiry := time.Now().Add(60 * time.Minute) + return &sts.AssumeRoleOutput{ + Credentials: &sts.Credentials{ + // Just reflect the role arn to the provider. + AccessKeyId: input.RoleArn, + SecretAccessKey: aws.String("assumedSecretAccessKey"), + SessionToken: aws.String("assumedSessionToken"), + Expiration: &expiry, + }, + }, nil +} + +func TestAssumeRoleProvider(t *testing.T) { + stub := &stubSTS{} + p := &AssumeRoleProvider{ + Client: stub, + RoleARN: "roleARN", + } + + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "roleARN", creds.AccessKeyID, "Expect access key ID to be reflected role ARN") + assert.Equal(t, "assumedSecretAccessKey", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "assumedSessionToken", creds.SessionToken, "Expect session token to match") +} + +func TestAssumeRoleProvider_WithTokenCode(t *testing.T) { + stub := &stubSTS{ + TestInput: func(in *sts.AssumeRoleInput) { + assert.Equal(t, "0123456789", *in.SerialNumber) + assert.Equal(t, "code", *in.TokenCode) + }, + } + p := &AssumeRoleProvider{ + Client: stub, + RoleARN: "roleARN", + SerialNumber: aws.String("0123456789"), + TokenCode: aws.String("code"), + } + + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "roleARN", creds.AccessKeyID, "Expect access key ID to be reflected role ARN") + assert.Equal(t, "assumedSecretAccessKey", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "assumedSessionToken", creds.SessionToken, "Expect session token to match") +} + +func TestAssumeRoleProvider_WithTokenProvider(t *testing.T) { + stub := &stubSTS{ + TestInput: func(in *sts.AssumeRoleInput) { + assert.Equal(t, "0123456789", *in.SerialNumber) + assert.Equal(t, "code", *in.TokenCode) + }, + } + p := &AssumeRoleProvider{ + Client: stub, + RoleARN: "roleARN", + SerialNumber: aws.String("0123456789"), + TokenProvider: func() (string, error) { + return "code", nil + }, + } + + creds, err := p.Retrieve() + assert.Nil(t, err, "Expect no error") + + assert.Equal(t, "roleARN", creds.AccessKeyID, "Expect access key ID to be reflected role ARN") + assert.Equal(t, "assumedSecretAccessKey", creds.SecretAccessKey, "Expect secret access key to match") + assert.Equal(t, "assumedSessionToken", creds.SessionToken, "Expect session token to match") +} + +func TestAssumeRoleProvider_WithTokenProviderError(t *testing.T) { + stub := &stubSTS{ + TestInput: func(in *sts.AssumeRoleInput) { + assert.Fail(t, "API request should not of been called") + }, + } + p := &AssumeRoleProvider{ + Client: stub, + RoleARN: "roleARN", + SerialNumber: aws.String("0123456789"), + TokenProvider: func() (string, error) { + return "", fmt.Errorf("error occurred") + }, + } + + creds, err := p.Retrieve() + assert.Error(t, err) + + assert.Empty(t, creds.AccessKeyID) + assert.Empty(t, creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) +} + +func TestAssumeRoleProvider_MFAWithNoToken(t *testing.T) { + stub := &stubSTS{ + TestInput: func(in *sts.AssumeRoleInput) { + assert.Fail(t, "API request should not of been called") + }, + } + p := &AssumeRoleProvider{ + Client: stub, + RoleARN: "roleARN", + SerialNumber: aws.String("0123456789"), + } + + creds, err := p.Retrieve() + assert.Error(t, err) + + assert.Empty(t, creds.AccessKeyID) + assert.Empty(t, creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) +} + +func BenchmarkAssumeRoleProvider(b *testing.B) { + stub := &stubSTS{} + p := &AssumeRoleProvider{ + Client: stub, + RoleARN: "roleARN", + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := p.Retrieve(); err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults_test.go b/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults_test.go new file mode 100644 index 000000000..cb0646838 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults_test.go @@ -0,0 +1,116 @@ +package defaults + +import ( + "fmt" + "os" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" + "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds" + "github.com/aws/aws-sdk-go/aws/request" +) + +func TestHTTPCredProvider(t *testing.T) { + origFn := lookupHostFn + defer func() { lookupHostFn = origFn }() + + lookupHostFn = func(host string) ([]string, error) { + m := map[string]struct { + Addrs []string + Err error + }{ + "localhost": {Addrs: []string{"::1", "127.0.0.1"}}, + "actuallylocal": {Addrs: []string{"127.0.0.2"}}, + "notlocal": {Addrs: []string{"::1", "127.0.0.1", "192.168.1.10"}}, + "www.example.com": {Addrs: []string{"10.10.10.10"}}, + } + + h, ok := m[host] + if !ok { + t.Fatalf("unknown host in test, %v", host) + return nil, fmt.Errorf("unknown host") + } + + return h.Addrs, h.Err + } + + cases := []struct { + Host string + Fail bool + }{ + {"localhost", false}, + {"actuallylocal", false}, + {"127.0.0.1", false}, + {"127.1.1.1", false}, + {"[::1]", false}, + {"www.example.com", true}, + {"169.254.170.2", true}, + } + + defer os.Clearenv() + + for i, c := range cases { + u := fmt.Sprintf("http://%s/abc/123", c.Host) + os.Setenv(httpProviderEnvVar, u) + + provider := RemoteCredProvider(aws.Config{}, request.Handlers{}) + if provider == nil { + t.Fatalf("%d, expect provider not to be nil, but was", i) + } + + if c.Fail { + creds, err := provider.Retrieve() + if err == nil { + t.Fatalf("%d, expect error but got none", i) + } else { + aerr := err.(awserr.Error) + if e, a := "CredentialsEndpointError", aerr.Code(); e != a { + t.Errorf("%d, expect %s error code, got %s", i, e, a) + } + } + if e, a := endpointcreds.ProviderName, creds.ProviderName; e != a { + t.Errorf("%d, expect %s provider name got %s", i, e, a) + } + } else { + httpProvider := provider.(*endpointcreds.Provider) + if e, a := u, httpProvider.Client.Endpoint; e != a { + t.Errorf("%d, expect %q endpoint, got %q", i, e, a) + } + } + } +} + +func TestECSCredProvider(t *testing.T) { + defer os.Clearenv() + os.Setenv(ecsCredsProviderEnvVar, "/abc/123") + + provider := RemoteCredProvider(aws.Config{}, request.Handlers{}) + if provider == nil { + t.Fatalf("expect provider not to be nil, but was") + } + + httpProvider := provider.(*endpointcreds.Provider) + if httpProvider == nil { + t.Fatalf("expect provider not to be nil, but was") + } + if e, a := "http://169.254.170.2/abc/123", httpProvider.Client.Endpoint; e != a { + t.Errorf("expect %q endpoint, got %q", e, a) + } +} + +func TestDefaultEC2RoleProvider(t *testing.T) { + provider := RemoteCredProvider(aws.Config{}, request.Handlers{}) + if provider == nil { + t.Fatalf("expect provider not to be nil, but was") + } + + ec2Provider := provider.(*ec2rolecreds.EC2RoleProvider) + if ec2Provider == nil { + t.Fatalf("expect provider not to be nil, but was") + } + if e, a := "http://169.254.169.254/latest", ec2Provider.Client.Endpoint; e != a { + t.Errorf("expect %q endpoint, got %q", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api_test.go b/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api_test.go new file mode 100644 index 000000000..7dde1fb36 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api_test.go @@ -0,0 +1,289 @@ +package ec2metadata_test + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "path" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/ec2metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting/unit" +) + +const instanceIdentityDocument = `{ + "devpayProductCodes" : null, + "availabilityZone" : "us-east-1d", + "privateIp" : "10.158.112.84", + "version" : "2010-08-31", + "region" : "us-east-1", + "instanceId" : "i-1234567890abcdef0", + "billingProducts" : null, + "instanceType" : "t1.micro", + "accountId" : "123456789012", + "pendingTime" : "2015-11-19T16:32:11Z", + "imageId" : "ami-5fb8c835", + "kernelId" : "aki-919dcaf8", + "ramdiskId" : null, + "architecture" : "x86_64" +}` + +const validIamInfo = `{ + "Code" : "Success", + "LastUpdated" : "2016-03-17T12:27:32Z", + "InstanceProfileArn" : "arn:aws:iam::123456789012:instance-profile/my-instance-profile", + "InstanceProfileId" : "AIPAABCDEFGHIJKLMN123" +}` + +const unsuccessfulIamInfo = `{ + "Code" : "Failed", + "LastUpdated" : "2016-03-17T12:27:32Z", + "InstanceProfileArn" : "arn:aws:iam::123456789012:instance-profile/my-instance-profile", + "InstanceProfileId" : "AIPAABCDEFGHIJKLMN123" +}` + +func initTestServer(path string, resp string) *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.RequestURI != path { + http.Error(w, "not found", http.StatusNotFound) + return + } + + w.Write([]byte(resp)) + })) +} + +func TestEndpoint(t *testing.T) { + c := ec2metadata.New(unit.Session) + op := &request.Operation{ + Name: "GetMetadata", + HTTPMethod: "GET", + HTTPPath: path.Join("/", "meta-data", "testpath"), + } + + req := c.NewRequest(op, nil, nil) + if e, a := "http://169.254.169.254/latest", req.ClientInfo.Endpoint; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "http://169.254.169.254/latest/meta-data/testpath", req.HTTPRequest.URL.String(); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestGetMetadata(t *testing.T) { + server := initTestServer( + "/latest/meta-data/some/path", + "success", // real response includes suffix + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + resp, err := c.GetMetadata("some/path") + + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := "success", resp; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestGetUserData(t *testing.T) { + server := initTestServer( + "/latest/user-data", + "success", // real response includes suffix + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + resp, err := c.GetUserData() + + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := "success", resp; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestGetUserData_Error(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + reader := strings.NewReader(` + + + + 404 - Not Found + + +

404 - Not Found

+ +`) + w.Header().Set("Content-Type", "text/html") + w.Header().Set("Content-Length", fmt.Sprintf("%d", reader.Len())) + w.WriteHeader(http.StatusNotFound) + io.Copy(w, reader) + })) + + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + resp, err := c.GetUserData() + if err == nil { + t.Errorf("expect error") + } + if len(resp) != 0 { + t.Errorf("expect empty, got %v", resp) + } + + aerr := err.(awserr.Error) + if e, a := "NotFoundError", aerr.Code(); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestGetRegion(t *testing.T) { + server := initTestServer( + "/latest/meta-data/placement/availability-zone", + "us-west-2a", // real response includes suffix + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + region, err := c.Region() + + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := "us-west-2", region; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestMetadataAvailable(t *testing.T) { + server := initTestServer( + "/latest/meta-data/instance-id", + "instance-id", + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + if !c.Available() { + t.Errorf("expect available") + } +} + +func TestMetadataIAMInfo_success(t *testing.T) { + server := initTestServer( + "/latest/meta-data/iam/info", + validIamInfo, + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + iamInfo, err := c.IAMInfo() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := "Success", iamInfo.Code; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "arn:aws:iam::123456789012:instance-profile/my-instance-profile", iamInfo.InstanceProfileArn; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "AIPAABCDEFGHIJKLMN123", iamInfo.InstanceProfileID; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestMetadataIAMInfo_failure(t *testing.T) { + server := initTestServer( + "/latest/meta-data/iam/info", + unsuccessfulIamInfo, + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + iamInfo, err := c.IAMInfo() + if err == nil { + t.Errorf("expect error") + } + if e, a := "", iamInfo.Code; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "", iamInfo.InstanceProfileArn; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "", iamInfo.InstanceProfileID; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestMetadataNotAvailable(t *testing.T) { + c := ec2metadata.New(unit.Session) + c.Handlers.Send.Clear() + c.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &http.Response{ + StatusCode: int(0), + Status: http.StatusText(int(0)), + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + } + r.Error = awserr.New("RequestError", "send request failed", nil) + r.Retryable = aws.Bool(true) // network errors are retryable + }) + + if c.Available() { + t.Errorf("expect not available") + } +} + +func TestMetadataErrorResponse(t *testing.T) { + c := ec2metadata.New(unit.Session) + c.Handlers.Send.Clear() + c.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &http.Response{ + StatusCode: http.StatusBadRequest, + Status: http.StatusText(http.StatusBadRequest), + Body: ioutil.NopCloser(strings.NewReader("error message text")), + } + r.Retryable = aws.Bool(false) // network errors are retryable + }) + + data, err := c.GetMetadata("uri/path") + if len(data) != 0 { + t.Errorf("expect empty, got %v", data) + } + if e, a := "error message text", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v to be in %v", e, a) + } +} + +func TestEC2RoleProviderInstanceIdentity(t *testing.T) { + server := initTestServer( + "/latest/dynamic/instance-identity/document", + instanceIdentityDocument, + ) + defer server.Close() + c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}) + + doc, err := c.GetInstanceIdentityDocument() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := doc.AccountID, "123456789012"; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := doc.AvailabilityZone, "us-east-1d"; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := doc.Region, "us-east-1"; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service_test.go b/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service_test.go new file mode 100644 index 000000000..6902e0b1e --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service_test.go @@ -0,0 +1,120 @@ +package ec2metadata_test + +import ( + "net/http" + "net/http/httptest" + "os" + "strings" + "sync" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/ec2metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" +) + +func TestClientOverrideDefaultHTTPClientTimeout(t *testing.T) { + svc := ec2metadata.New(unit.Session) + + if e, a := http.DefaultClient, svc.Config.HTTPClient; e == a { + t.Errorf("expect %v, not to equal %v", e, a) + } + + if e, a := 5*time.Second, svc.Config.HTTPClient.Timeout; e != a { + t.Errorf("expect %v to be %v", e, a) + } +} + +func TestClientNotOverrideDefaultHTTPClientTimeout(t *testing.T) { + http.DefaultClient.Transport = &http.Transport{} + defer func() { + http.DefaultClient.Transport = nil + }() + + svc := ec2metadata.New(unit.Session) + + if e, a := http.DefaultClient, svc.Config.HTTPClient; e != a { + t.Errorf("expect %v, got %v", e, a) + } + + tr := svc.Config.HTTPClient.Transport.(*http.Transport) + if tr == nil { + t.Fatalf("expect transport not to be nil") + } + if tr.Dial != nil { + t.Errorf("expect dial to be nil, was not") + } +} + +func TestClientDisableOverrideDefaultHTTPClientTimeout(t *testing.T) { + svc := ec2metadata.New(unit.Session, aws.NewConfig().WithEC2MetadataDisableTimeoutOverride(true)) + + if e, a := http.DefaultClient, svc.Config.HTTPClient; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestClientOverrideDefaultHTTPClientTimeoutRace(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("us-east-1a")) + })) + + cfg := aws.NewConfig().WithEndpoint(server.URL) + runEC2MetadataClients(t, cfg, 100) +} + +func TestClientOverrideDefaultHTTPClientTimeoutRaceWithTransport(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("us-east-1a")) + })) + + cfg := aws.NewConfig().WithEndpoint(server.URL).WithHTTPClient(&http.Client{ + Transport: http.DefaultTransport, + }) + + runEC2MetadataClients(t, cfg, 100) +} + +func TestClientDisableIMDS(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + os.Setenv("AWS_EC2_METADATA_DISABLED", "true") + + svc := ec2metadata.New(unit.Session) + resp, err := svc.Region() + if err == nil { + t.Fatalf("expect error, got none") + } + if len(resp) != 0 { + t.Errorf("expect no response, got %v", resp) + } + + aerr := err.(awserr.Error) + if e, a := request.CanceledErrorCode, aerr.Code(); e != a { + t.Errorf("expect %v error code, got %v", e, a) + } + if e, a := "AWS_EC2_METADATA_DISABLED", aerr.Message(); !strings.Contains(a, e) { + t.Errorf("expect %v in error message, got %v", e, a) + } +} + +func runEC2MetadataClients(t *testing.T, cfg *aws.Config, atOnce int) { + var wg sync.WaitGroup + wg.Add(atOnce) + for i := 0; i < atOnce; i++ { + go func() { + svc := ec2metadata.New(unit.Session, cfg) + _, err := svc.Region() + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + wg.Done() + }() + } + wg.Wait() +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode_test.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode_test.go new file mode 100644 index 000000000..319390721 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode_test.go @@ -0,0 +1,117 @@ +package endpoints + +import ( + "strings" + "testing" +) + +func TestDecodeEndpoints_V3(t *testing.T) { + const v3Doc = ` +{ + "version": 3, + "partitions": [ + { + "defaults": { + "hostname": "{service}.{region}.{dnsSuffix}", + "protocols": [ + "https" + ], + "signatureVersions": [ + "v4" + ] + }, + "dnsSuffix": "amazonaws.com", + "partition": "aws", + "partitionName": "AWS Standard", + "regionRegex": "^(us|eu|ap|sa|ca)\\-\\w+\\-\\d+$", + "regions": { + "ap-northeast-1": { + "description": "Asia Pacific (Tokyo)" + } + }, + "services": { + "acm": { + "endpoints": { + "ap-northeast-1": {} + } + }, + "s3": { + "endpoints": { + "ap-northeast-1": {} + } + } + } + } + ] +}` + + resolver, err := DecodeModel(strings.NewReader(v3Doc)) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + endpoint, err := resolver.EndpointFor("acm", "ap-northeast-1") + if err != nil { + t.Fatalf("failed to resolve endpoint, %v", err) + } + + if a, e := endpoint.URL, "https://acm.ap-northeast-1.amazonaws.com"; a != e { + t.Errorf("expected %q URL got %q", e, a) + } + + p := resolver.(partitions)[0] + + s3Defaults := p.Services["s3"].Defaults + if a, e := s3Defaults.HasDualStack, boxedTrue; a != e { + t.Errorf("expect s3 service to have dualstack enabled") + } + if a, e := s3Defaults.DualStackHostname, "{service}.dualstack.{region}.{dnsSuffix}"; a != e { + t.Errorf("expect s3 dualstack host pattern to be %q, got %q", e, a) + } + + ec2metaEndpoint := p.Services["ec2metadata"].Endpoints["aws-global"] + if a, e := ec2metaEndpoint.Hostname, "169.254.169.254/latest"; a != e { + t.Errorf("expect ec2metadata host to be %q, got %q", e, a) + } +} + +func TestDecodeEndpoints_NoPartitions(t *testing.T) { + const doc = `{ "version": 3 }` + + resolver, err := DecodeModel(strings.NewReader(doc)) + if err == nil { + t.Fatalf("expected error") + } + + if resolver != nil { + t.Errorf("expect resolver to be nil") + } +} + +func TestDecodeEndpoints_UnsupportedVersion(t *testing.T) { + const doc = `{ "version": 2 }` + + resolver, err := DecodeModel(strings.NewReader(doc)) + if err == nil { + t.Fatalf("expected error decoding model") + } + + if resolver != nil { + t.Errorf("expect resolver to be nil") + } +} + +func TestDecodeModelOptionsSet(t *testing.T) { + var actual DecodeModelOptions + actual.Set(func(o *DecodeModelOptions) { + o.SkipCustomizations = true + }) + + expect := DecodeModelOptions{ + SkipCustomizations: true, + } + + if actual != expect { + t.Errorf("expect %v options got %v", expect, actual) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints_test.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints_test.go new file mode 100644 index 000000000..de0e53026 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints_test.go @@ -0,0 +1,342 @@ +package endpoints + +import "testing" + +func TestEnumDefaultPartitions(t *testing.T) { + resolver := DefaultResolver() + enum, ok := resolver.(EnumPartitions) + + if ok != true { + t.Fatalf("resolver must satisfy EnumPartition interface") + } + + ps := enum.Partitions() + + if a, e := len(ps), len(defaultPartitions); a != e { + t.Errorf("expected %d partitions, got %d", e, a) + } +} + +func TestEnumDefaultRegions(t *testing.T) { + expectPart := defaultPartitions[0] + partEnum := defaultPartitions[0].Partition() + + regEnum := partEnum.Regions() + + if a, e := len(regEnum), len(expectPart.Regions); a != e { + t.Errorf("expected %d regions, got %d", e, a) + } +} + +func TestEnumPartitionServices(t *testing.T) { + expectPart := testPartitions[0] + partEnum := testPartitions[0].Partition() + + if a, e := partEnum.ID(), "part-id"; a != e { + t.Errorf("expect %q partition ID, got %q", e, a) + } + + svcEnum := partEnum.Services() + + if a, e := len(svcEnum), len(expectPart.Services); a != e { + t.Errorf("expected %d regions, got %d", e, a) + } +} + +func TestEnumRegionServices(t *testing.T) { + p := testPartitions[0].Partition() + + rs := p.Regions() + + if a, e := len(rs), 2; a != e { + t.Errorf("expect %d regions got %d", e, a) + } + + if _, ok := rs["us-east-1"]; !ok { + t.Errorf("expect us-east-1 region to be found, was not") + } + if _, ok := rs["us-west-2"]; !ok { + t.Errorf("expect us-west-2 region to be found, was not") + } + + r := rs["us-east-1"] + + if a, e := r.ID(), "us-east-1"; a != e { + t.Errorf("expect %q region ID, got %q", e, a) + } + + if a, e := r.Description(), "region description"; a != e { + t.Errorf("expect %q region Description, got %q", e, a) + } + + ss := r.Services() + if a, e := len(ss), 1; a != e { + t.Errorf("expect %d services for us-east-1, got %d", e, a) + } + + if _, ok := ss["service1"]; !ok { + t.Errorf("expect service1 service to be found, was not") + } + + resolved, err := r.ResolveEndpoint("service1") + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if a, e := resolved.URL, "https://service1.us-east-1.amazonaws.com"; a != e { + t.Errorf("expect %q resolved URL, got %q", e, a) + } +} + +func TestEnumServiceRegions(t *testing.T) { + p := testPartitions[0].Partition() + + rs := p.Services()["service1"].Regions() + if e, a := 2, len(rs); e != a { + t.Errorf("expect %d regions, got %d", e, a) + } + + if _, ok := rs["us-east-1"]; !ok { + t.Errorf("expect region to be found") + } + if _, ok := rs["us-west-2"]; !ok { + t.Errorf("expect region to be found") + } +} + +func TestEnumServicesEndpoints(t *testing.T) { + p := testPartitions[0].Partition() + + ss := p.Services() + + if a, e := len(ss), 5; a != e { + t.Errorf("expect %d regions got %d", e, a) + } + + if _, ok := ss["service1"]; !ok { + t.Errorf("expect service1 region to be found, was not") + } + if _, ok := ss["service2"]; !ok { + t.Errorf("expect service2 region to be found, was not") + } + + s := ss["service1"] + if a, e := s.ID(), "service1"; a != e { + t.Errorf("expect %q service ID, got %q", e, a) + } + + resolved, err := s.ResolveEndpoint("us-west-2") + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if a, e := resolved.URL, "https://service1.us-west-2.amazonaws.com"; a != e { + t.Errorf("expect %q resolved URL, got %q", e, a) + } +} + +func TestEnumEndpoints(t *testing.T) { + p := testPartitions[0].Partition() + s := p.Services()["service1"] + + es := s.Endpoints() + if a, e := len(es), 2; a != e { + t.Errorf("expect %d endpoints for service2, got %d", e, a) + } + if _, ok := es["us-east-1"]; !ok { + t.Errorf("expect us-east-1 to be found, was not") + } + + e := es["us-east-1"] + if a, e := e.ID(), "us-east-1"; a != e { + t.Errorf("expect %q endpoint ID, got %q", e, a) + } + if a, e := e.ServiceID(), "service1"; a != e { + t.Errorf("expect %q service ID, got %q", e, a) + } + + resolved, err := e.ResolveEndpoint() + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if a, e := resolved.URL, "https://service1.us-east-1.amazonaws.com"; a != e { + t.Errorf("expect %q resolved URL, got %q", e, a) + } +} + +func TestResolveEndpointForPartition(t *testing.T) { + enum := testPartitions.Partitions()[0] + + expected, err := testPartitions.EndpointFor("service1", "us-east-1") + + actual, err := enum.EndpointFor("service1", "us-east-1") + if err != nil { + t.Fatalf("unexpected error, %v", err) + } + + if expected != actual { + t.Errorf("expect resolved endpoint to be %v, but got %v", expected, actual) + } +} + +func TestAddScheme(t *testing.T) { + cases := []struct { + In string + Expect string + DisableSSL bool + }{ + { + In: "https://example.com", + Expect: "https://example.com", + }, + { + In: "example.com", + Expect: "https://example.com", + }, + { + In: "http://example.com", + Expect: "http://example.com", + }, + { + In: "example.com", + Expect: "http://example.com", + DisableSSL: true, + }, + { + In: "https://example.com", + Expect: "https://example.com", + DisableSSL: true, + }, + } + + for i, c := range cases { + actual := AddScheme(c.In, c.DisableSSL) + if actual != c.Expect { + t.Errorf("%d, expect URL to be %q, got %q", i, c.Expect, actual) + } + } +} + +func TestResolverFunc(t *testing.T) { + var resolver Resolver + + resolver = ResolverFunc(func(s, r string, opts ...func(*Options)) (ResolvedEndpoint, error) { + return ResolvedEndpoint{ + URL: "https://service.region.dnssuffix.com", + SigningRegion: "region", + SigningName: "service", + }, nil + }) + + resolved, err := resolver.EndpointFor("service", "region", func(o *Options) { + o.DisableSSL = true + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if a, e := resolved.URL, "https://service.region.dnssuffix.com"; a != e { + t.Errorf("expect %q endpoint URL, got %q", e, a) + } + + if a, e := resolved.SigningRegion, "region"; a != e { + t.Errorf("expect %q region, got %q", e, a) + } + if a, e := resolved.SigningName, "service"; a != e { + t.Errorf("expect %q signing name, got %q", e, a) + } +} + +func TestOptionsSet(t *testing.T) { + var actual Options + actual.Set(DisableSSLOption, UseDualStackOption, StrictMatchingOption) + + expect := Options{ + DisableSSL: true, + UseDualStack: true, + StrictMatching: true, + } + + if actual != expect { + t.Errorf("expect %v options got %v", expect, actual) + } +} + +func TestRegionsForService(t *testing.T) { + ps := DefaultPartitions() + + var expect map[string]Region + var serviceID string + for _, s := range ps[0].Services() { + expect = s.Regions() + serviceID = s.ID() + if len(expect) > 0 { + break + } + } + + actual, ok := RegionsForService(ps, ps[0].ID(), serviceID) + if !ok { + t.Fatalf("expect regions to be found, was not") + } + + if len(actual) == 0 { + t.Fatalf("expect service %s to have regions", serviceID) + } + if e, a := len(expect), len(actual); e != a { + t.Fatalf("expect %d regions, got %d", e, a) + } + + for id, r := range actual { + if e, a := id, r.ID(); e != a { + t.Errorf("expect %s region id, got %s", e, a) + } + if _, ok := expect[id]; !ok { + t.Errorf("expect %s region to be found", id) + } + if a, e := r.Description(), expect[id].desc; a != e { + t.Errorf("expect %q region Description, got %q", e, a) + } + } +} + +func TestRegionsForService_NotFound(t *testing.T) { + ps := testPartitions.Partitions() + + actual, ok := RegionsForService(ps, ps[0].ID(), "service-not-exists") + if ok { + t.Fatalf("expect no regions to be found, but were") + } + if len(actual) != 0 { + t.Errorf("expect no regions, got %v", actual) + } +} + +func TestPartitionForRegion(t *testing.T) { + ps := DefaultPartitions() + expect := ps[len(ps)%2] + + var regionID string + for id := range expect.Regions() { + regionID = id + break + } + + actual, ok := PartitionForRegion(ps, regionID) + if !ok { + t.Fatalf("expect partition to be found") + } + if e, a := expect.ID(), actual.ID(); e != a { + t.Errorf("expect %s partition, got %s", e, a) + } +} + +func TestPartitionForRegion_NotFound(t *testing.T) { + ps := DefaultPartitions() + + actual, ok := PartitionForRegion(ps, "regionNotExists") + if ok { + t.Errorf("expect no partition to be found, got %v", actual) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/example_test.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/example_test.go new file mode 100644 index 000000000..007fed2f9 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/example_test.go @@ -0,0 +1,66 @@ +package endpoints_test + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/sqs" +) + +func ExampleEnumPartitions() { + resolver := endpoints.DefaultResolver() + partitions := resolver.(endpoints.EnumPartitions).Partitions() + + for _, p := range partitions { + fmt.Println("Regions for", p.ID()) + for id := range p.Regions() { + fmt.Println("*", id) + } + + fmt.Println("Services for", p.ID()) + for id := range p.Services() { + fmt.Println("*", id) + } + } +} + +func ExampleResolverFunc() { + myCustomResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) { + if service == endpoints.S3ServiceID { + return endpoints.ResolvedEndpoint{ + URL: "s3.custom.endpoint.com", + SigningRegion: "custom-signing-region", + }, nil + } + + return endpoints.DefaultResolver().EndpointFor(service, region, optFns...) + } + + sess := session.Must(session.NewSession(&aws.Config{ + Region: aws.String("us-west-2"), + EndpointResolver: endpoints.ResolverFunc(myCustomResolver), + })) + + // Create the S3 service client with the shared session. This will + // automatically use the S3 custom endpoint configured in the custom + // endpoint resolver wrapping the default endpoint resolver. + s3Svc := s3.New(sess) + // Operation calls will be made to the custom endpoint. + s3Svc.GetObject(&s3.GetObjectInput{ + Bucket: aws.String("myBucket"), + Key: aws.String("myObjectKey"), + }) + + // Create the SQS service client with the shared session. This will + // fallback to the default endpoint resolver because the customization + // passes any non S3 service endpoint resolve to the default resolver. + sqsSvc := sqs.New(sess) + // Operation calls will be made to the default endpoint for SQS for the + // region configured. + sqsSvc.ReceiveMessage(&sqs.ReceiveMessageInput{ + QueueUrl: aws.String("my-queue-url"), + }) +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_test.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_test.go new file mode 100644 index 000000000..0b8b00673 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_test.go @@ -0,0 +1,541 @@ +package endpoints + +import ( + "encoding/json" + "reflect" + "regexp" + "testing" +) + +func TestUnmarshalRegionRegex(t *testing.T) { + var input = []byte(` +{ + "regionRegex": "^(us|eu|ap|sa|ca)\\-\\w+\\-\\d+$" +}`) + + p := partition{} + err := json.Unmarshal(input, &p) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + expectRegexp, err := regexp.Compile(`^(us|eu|ap|sa|ca)\-\w+\-\d+$`) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := expectRegexp.String(), p.RegionRegex.Regexp.String(); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestUnmarshalRegion(t *testing.T) { + var input = []byte(` +{ + "aws-global": { + "description": "AWS partition-global endpoint" + }, + "us-east-1": { + "description": "US East (N. Virginia)" + } +}`) + + rs := regions{} + err := json.Unmarshal(input, &rs) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := 2, len(rs); e != a { + t.Errorf("expect %v len, got %v", e, a) + } + r, ok := rs["aws-global"] + if !ok { + t.Errorf("expect found, was not") + } + if e, a := "AWS partition-global endpoint", r.Description; e != a { + t.Errorf("expect %v, got %v", e, a) + } + + r, ok = rs["us-east-1"] + if !ok { + t.Errorf("expect found, was not") + } + if e, a := "US East (N. Virginia)", r.Description; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestUnmarshalServices(t *testing.T) { + var input = []byte(` +{ + "acm": { + "endpoints": { + "us-east-1": {} + } + }, + "apigateway": { + "isRegionalized": true, + "endpoints": { + "us-east-1": {}, + "us-west-2": {} + } + }, + "notRegionalized": { + "isRegionalized": false, + "endpoints": { + "us-east-1": {}, + "us-west-2": {} + } + } +}`) + + ss := services{} + err := json.Unmarshal(input, &ss) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := 3, len(ss); e != a { + t.Errorf("expect %v len, got %v", e, a) + } + s, ok := ss["acm"] + if !ok { + t.Errorf("expect found, was not") + } + if e, a := 1, len(s.Endpoints); e != a { + t.Errorf("expect %v len, got %v", e, a) + } + if e, a := boxedBoolUnset, s.IsRegionalized; e != a { + t.Errorf("expect %v, got %v", e, a) + } + + s, ok = ss["apigateway"] + if !ok { + t.Errorf("expect found, was not") + } + if e, a := 2, len(s.Endpoints); e != a { + t.Errorf("expect %v len, got %v", e, a) + } + if e, a := boxedTrue, s.IsRegionalized; e != a { + t.Errorf("expect %v, got %v", e, a) + } + + s, ok = ss["notRegionalized"] + if !ok { + t.Errorf("expect found, was not") + } + if e, a := 2, len(s.Endpoints); e != a { + t.Errorf("expect %v len, got %v", e, a) + } + if e, a := boxedFalse, s.IsRegionalized; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestUnmarshalEndpoints(t *testing.T) { + var inputs = []byte(` +{ + "aws-global": { + "hostname": "cloudfront.amazonaws.com", + "protocols": [ + "http", + "https" + ], + "signatureVersions": [ "v4" ], + "credentialScope": { + "region": "us-east-1", + "service": "serviceName" + }, + "sslCommonName": "commonName" + }, + "us-east-1": {} +}`) + + es := endpoints{} + err := json.Unmarshal(inputs, &es) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := 2, len(es); e != a { + t.Errorf("expect %v len, got %v", e, a) + } + s, ok := es["aws-global"] + if !ok { + t.Errorf("expect found, was not") + } + if e, a := "cloudfront.amazonaws.com", s.Hostname; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := []string{"http", "https"}, s.Protocols; !reflect.DeepEqual(e, a) { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := []string{"v4"}, s.SignatureVersions; !reflect.DeepEqual(e, a) { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := (credentialScope{"us-east-1", "serviceName"}), s.CredentialScope; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "commonName", s.SSLCommonName; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestEndpointResolve(t *testing.T) { + defs := []endpoint{ + { + Hostname: "{service}.{region}.{dnsSuffix}", + SignatureVersions: []string{"v2"}, + SSLCommonName: "sslCommonName", + }, + { + Hostname: "other-hostname", + Protocols: []string{"http"}, + CredentialScope: credentialScope{ + Region: "signing_region", + Service: "signing_service", + }, + }, + } + + e := endpoint{ + Hostname: "{service}.{region}.{dnsSuffix}", + Protocols: []string{"http", "https"}, + SignatureVersions: []string{"v4"}, + SSLCommonName: "new sslCommonName", + } + + resolved := e.resolve("service", "region", "dnsSuffix", + defs, Options{}, + ) + + if e, a := "https://service.region.dnsSuffix", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "signing_service", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "signing_region", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "v4", resolved.SigningMethod; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestEndpointMergeIn(t *testing.T) { + expected := endpoint{ + Hostname: "other hostname", + Protocols: []string{"http"}, + SignatureVersions: []string{"v4"}, + SSLCommonName: "ssl common name", + CredentialScope: credentialScope{ + Region: "region", + Service: "service", + }, + } + + actual := endpoint{} + actual.mergeIn(endpoint{ + Hostname: "other hostname", + Protocols: []string{"http"}, + SignatureVersions: []string{"v4"}, + SSLCommonName: "ssl common name", + CredentialScope: credentialScope{ + Region: "region", + Service: "service", + }, + }) + + if e, a := expected, actual; !reflect.DeepEqual(e, a) { + t.Errorf("expect %v, got %v", e, a) + } +} + +var testPartitions = partitions{ + partition{ + ID: "part-id", + Name: "partitionName", + DNSSuffix: "amazonaws.com", + RegionRegex: regionRegex{ + Regexp: func() *regexp.Regexp { + reg, _ := regexp.Compile("^(us|eu|ap|sa|ca)\\-\\w+\\-\\d+$") + return reg + }(), + }, + Defaults: endpoint{ + Hostname: "{service}.{region}.{dnsSuffix}", + Protocols: []string{"https"}, + SignatureVersions: []string{"v4"}, + }, + Regions: regions{ + "us-east-1": region{ + Description: "region description", + }, + "us-west-2": region{}, + }, + Services: services{ + "s3": service{}, + "service1": service{ + Defaults: endpoint{ + CredentialScope: credentialScope{ + Service: "service1", + }, + }, + Endpoints: endpoints{ + "us-east-1": {}, + "us-west-2": { + HasDualStack: boxedTrue, + DualStackHostname: "{service}.dualstack.{region}.{dnsSuffix}", + }, + }, + }, + "service2": service{ + Defaults: endpoint{ + CredentialScope: credentialScope{ + Service: "service2", + }, + }, + }, + "httpService": service{ + Defaults: endpoint{ + Protocols: []string{"http"}, + }, + }, + "globalService": service{ + IsRegionalized: boxedFalse, + PartitionEndpoint: "aws-global", + Endpoints: endpoints{ + "aws-global": endpoint{ + CredentialScope: credentialScope{ + Region: "us-east-1", + }, + Hostname: "globalService.amazonaws.com", + }, + }, + }, + }, + }, +} + +func TestResolveEndpoint(t *testing.T) { + resolved, err := testPartitions.EndpointFor("service2", "us-west-2") + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "https://service2.us-west-2.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-west-2", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "service2", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if resolved.SigningNameDerived { + t.Errorf("expect the signing name not to be derived, but was") + } +} + +func TestResolveEndpoint_DisableSSL(t *testing.T) { + resolved, err := testPartitions.EndpointFor("service2", "us-west-2", DisableSSLOption) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "http://service2.us-west-2.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-west-2", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "service2", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if resolved.SigningNameDerived { + t.Errorf("expect the signing name not to be derived, but was") + } +} + +func TestResolveEndpoint_UseDualStack(t *testing.T) { + resolved, err := testPartitions.EndpointFor("service1", "us-west-2", UseDualStackOption) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "https://service1.dualstack.us-west-2.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-west-2", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "service1", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if resolved.SigningNameDerived { + t.Errorf("expect the signing name not to be derived, but was") + } +} + +func TestResolveEndpoint_HTTPProtocol(t *testing.T) { + resolved, err := testPartitions.EndpointFor("httpService", "us-west-2") + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "http://httpService.us-west-2.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-west-2", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "httpService", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if !resolved.SigningNameDerived { + t.Errorf("expect the signing name to be derived") + } +} + +func TestResolveEndpoint_UnknownService(t *testing.T) { + _, err := testPartitions.EndpointFor("unknownservice", "us-west-2") + + if err == nil { + t.Errorf("expect error, got none") + } + + _, ok := err.(UnknownServiceError) + if !ok { + t.Errorf("expect error to be UnknownServiceError") + } +} + +func TestResolveEndpoint_ResolveUnknownService(t *testing.T) { + resolved, err := testPartitions.EndpointFor("unknown-service", "us-region-1", + ResolveUnknownServiceOption) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if e, a := "https://unknown-service.us-region-1.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-region-1", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "unknown-service", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if !resolved.SigningNameDerived { + t.Errorf("expect the signing name to be derived") + } +} + +func TestResolveEndpoint_UnknownMatchedRegion(t *testing.T) { + resolved, err := testPartitions.EndpointFor("service2", "us-region-1") + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "https://service2.us-region-1.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-region-1", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "service2", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if resolved.SigningNameDerived { + t.Errorf("expect the signing name not to be derived, but was") + } +} + +func TestResolveEndpoint_UnknownRegion(t *testing.T) { + resolved, err := testPartitions.EndpointFor("service2", "unknownregion") + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "https://service2.unknownregion.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "unknownregion", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "service2", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if resolved.SigningNameDerived { + t.Errorf("expect the signing name not to be derived, but was") + } +} + +func TestResolveEndpoint_StrictPartitionUnknownEndpoint(t *testing.T) { + _, err := testPartitions[0].EndpointFor("service2", "unknownregion", StrictMatchingOption) + + if err == nil { + t.Errorf("expect error, got none") + } + + _, ok := err.(UnknownEndpointError) + if !ok { + t.Errorf("expect error to be UnknownEndpointError") + } +} + +func TestResolveEndpoint_StrictPartitionsUnknownEndpoint(t *testing.T) { + _, err := testPartitions.EndpointFor("service2", "us-region-1", StrictMatchingOption) + + if err == nil { + t.Errorf("expect error, got none") + } + + _, ok := err.(UnknownEndpointError) + if !ok { + t.Errorf("expect error to be UnknownEndpointError") + } +} + +func TestResolveEndpoint_NotRegionalized(t *testing.T) { + resolved, err := testPartitions.EndpointFor("globalService", "us-west-2") + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "https://globalService.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-east-1", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "globalService", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if !resolved.SigningNameDerived { + t.Errorf("expect the signing name to be derived") + } +} + +func TestResolveEndpoint_AwsGlobal(t *testing.T) { + resolved, err := testPartitions.EndpointFor("globalService", "aws-global") + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := "https://globalService.amazonaws.com", resolved.URL; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-east-1", resolved.SigningRegion; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "globalService", resolved.SigningName; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if !resolved.SigningNameDerived { + t.Errorf("expect the signing name to be derived") + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other_test.go new file mode 100644 index 000000000..aba8eb4e8 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_other_test.go @@ -0,0 +1,9 @@ +// +build appengine plan9 + +package request_test + +import ( + "errors" +) + +var stubConnectionResetError = errors.New("connection reset") diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_test.go new file mode 100644 index 000000000..bb5f6bddc --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/connection_reset_error_test.go @@ -0,0 +1,11 @@ +// +build !appengine,!plan9 + +package request_test + +import ( + "net" + "os" + "syscall" +) + +var stubConnectionResetError = &net.OpError{Err: &os.SyscallError{Syscall: "read", Err: syscall.ECONNRESET}} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/handlers_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/handlers_test.go new file mode 100644 index 000000000..b2da558d6 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/handlers_test.go @@ -0,0 +1,266 @@ +package request_test + +import ( + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/s3" +) + +func TestHandlerList(t *testing.T) { + s := "" + r := &request.Request{} + l := request.HandlerList{} + l.PushBack(func(r *request.Request) { + s += "a" + r.Data = s + }) + l.Run(r) + if e, a := "a", s; e != a { + t.Errorf("expect %q update got %q", e, a) + } + if e, a := "a", r.Data.(string); e != a { + t.Errorf("expect %q data update got %q", e, a) + } +} + +func TestMultipleHandlers(t *testing.T) { + r := &request.Request{} + l := request.HandlerList{} + l.PushBack(func(r *request.Request) { r.Data = nil }) + l.PushFront(func(r *request.Request) { r.Data = aws.Bool(true) }) + l.Run(r) + if r.Data != nil { + t.Error("Expected handler to execute") + } +} + +func TestNamedHandlers(t *testing.T) { + l := request.HandlerList{} + named := request.NamedHandler{Name: "Name", Fn: func(r *request.Request) {}} + named2 := request.NamedHandler{Name: "NotName", Fn: func(r *request.Request) {}} + l.PushBackNamed(named) + l.PushBackNamed(named) + l.PushBackNamed(named2) + l.PushBack(func(r *request.Request) {}) + if e, a := 4, l.Len(); e != a { + t.Errorf("expect %d list length, got %d", e, a) + } + l.Remove(named) + if e, a := 2, l.Len(); e != a { + t.Errorf("expect %d list length, got %d", e, a) + } +} + +func TestSwapHandlers(t *testing.T) { + firstHandlerCalled := 0 + swappedOutHandlerCalled := 0 + swappedInHandlerCalled := 0 + + l := request.HandlerList{} + named := request.NamedHandler{Name: "Name", Fn: func(r *request.Request) { + firstHandlerCalled++ + }} + named2 := request.NamedHandler{Name: "SwapOutName", Fn: func(r *request.Request) { + swappedOutHandlerCalled++ + }} + l.PushBackNamed(named) + l.PushBackNamed(named2) + l.PushBackNamed(named) + + l.SwapNamed(request.NamedHandler{Name: "SwapOutName", Fn: func(r *request.Request) { + swappedInHandlerCalled++ + }}) + + l.Run(&request.Request{}) + + if e, a := 2, firstHandlerCalled; e != a { + t.Errorf("expect first handler to be called %d, was called %d times", e, a) + } + if n := swappedOutHandlerCalled; n != 0 { + t.Errorf("expect swapped out handler to not be called, was called %d times", n) + } + if e, a := 1, swappedInHandlerCalled; e != a { + t.Errorf("expect swapped in handler to be called %d, was called %d times", e, a) + } +} + +func TestSetBackNamed_Exists(t *testing.T) { + firstHandlerCalled := 0 + swappedOutHandlerCalled := 0 + swappedInHandlerCalled := 0 + + l := request.HandlerList{} + named := request.NamedHandler{Name: "Name", Fn: func(r *request.Request) { + firstHandlerCalled++ + }} + named2 := request.NamedHandler{Name: "SwapOutName", Fn: func(r *request.Request) { + swappedOutHandlerCalled++ + }} + l.PushBackNamed(named) + l.PushBackNamed(named2) + + l.SetBackNamed(request.NamedHandler{Name: "SwapOutName", Fn: func(r *request.Request) { + swappedInHandlerCalled++ + }}) + + l.Run(&request.Request{}) + + if e, a := 1, firstHandlerCalled; e != a { + t.Errorf("expect first handler to be called %d, was called %d times", e, a) + } + if n := swappedOutHandlerCalled; n != 0 { + t.Errorf("expect swapped out handler to not be called, was called %d times", n) + } + if e, a := 1, swappedInHandlerCalled; e != a { + t.Errorf("expect swapped in handler to be called %d, was called %d times", e, a) + } +} + +func TestSetBackNamed_NotExists(t *testing.T) { + firstHandlerCalled := 0 + secondHandlerCalled := 0 + swappedInHandlerCalled := 0 + + l := request.HandlerList{} + named := request.NamedHandler{Name: "Name", Fn: func(r *request.Request) { + firstHandlerCalled++ + }} + named2 := request.NamedHandler{Name: "OtherName", Fn: func(r *request.Request) { + secondHandlerCalled++ + }} + l.PushBackNamed(named) + l.PushBackNamed(named2) + + l.SetBackNamed(request.NamedHandler{Name: "SwapOutName", Fn: func(r *request.Request) { + swappedInHandlerCalled++ + }}) + + l.Run(&request.Request{}) + + if e, a := 1, firstHandlerCalled; e != a { + t.Errorf("expect first handler to be called %d, was called %d times", e, a) + } + if e, a := 1, secondHandlerCalled; e != a { + t.Errorf("expect second handler to be called %d, was called %d times", e, a) + } + if e, a := 1, swappedInHandlerCalled; e != a { + t.Errorf("expect swapped in handler to be called %d, was called %d times", e, a) + } +} + +func TestLoggedHandlers(t *testing.T) { + expectedHandlers := []string{"name1", "name2"} + l := request.HandlerList{} + loggedHandlers := []string{} + l.AfterEachFn = request.HandlerListLogItem + cfg := aws.Config{Logger: aws.LoggerFunc(func(args ...interface{}) { + loggedHandlers = append(loggedHandlers, args[2].(string)) + })} + + named1 := request.NamedHandler{Name: "name1", Fn: func(r *request.Request) {}} + named2 := request.NamedHandler{Name: "name2", Fn: func(r *request.Request) {}} + l.PushBackNamed(named1) + l.PushBackNamed(named2) + l.Run(&request.Request{Config: cfg}) + + if !reflect.DeepEqual(expectedHandlers, loggedHandlers) { + t.Errorf("expect handlers executed %v to match logged handlers, %v", + expectedHandlers, loggedHandlers) + } +} + +func TestStopHandlers(t *testing.T) { + l := request.HandlerList{} + stopAt := 1 + l.AfterEachFn = func(item request.HandlerListRunItem) bool { + return item.Index != stopAt + } + + called := 0 + l.PushBackNamed(request.NamedHandler{Name: "name1", Fn: func(r *request.Request) { + called++ + }}) + l.PushBackNamed(request.NamedHandler{Name: "name2", Fn: func(r *request.Request) { + called++ + }}) + l.PushBackNamed(request.NamedHandler{Name: "name3", Fn: func(r *request.Request) { + t.Fatalf("third handler should not be called") + }}) + l.Run(&request.Request{}) + + if e, a := 2, called; e != a { + t.Errorf("expect %d handlers called, got %d", e, a) + } +} + +func BenchmarkNewRequest(b *testing.B) { + svc := s3.New(unit.Session) + + for i := 0; i < b.N; i++ { + r, _ := svc.GetObjectRequest(nil) + if r == nil { + b.Fatal("r should not be nil") + } + } +} + +func BenchmarkHandlersCopy(b *testing.B) { + handlers := request.Handlers{} + + handlers.Validate.PushBack(func(r *request.Request) {}) + handlers.Validate.PushBack(func(r *request.Request) {}) + handlers.Build.PushBack(func(r *request.Request) {}) + handlers.Build.PushBack(func(r *request.Request) {}) + handlers.Send.PushBack(func(r *request.Request) {}) + handlers.Send.PushBack(func(r *request.Request) {}) + handlers.Unmarshal.PushBack(func(r *request.Request) {}) + handlers.Unmarshal.PushBack(func(r *request.Request) {}) + + for i := 0; i < b.N; i++ { + h := handlers.Copy() + if e, a := handlers.Validate.Len(), h.Validate.Len(); e != a { + b.Fatalf("expected %d handlers got %d", e, a) + } + } +} + +func BenchmarkHandlersPushBack(b *testing.B) { + handlers := request.Handlers{} + + for i := 0; i < b.N; i++ { + h := handlers.Copy() + h.Validate.PushBack(func(r *request.Request) {}) + h.Validate.PushBack(func(r *request.Request) {}) + h.Validate.PushBack(func(r *request.Request) {}) + h.Validate.PushBack(func(r *request.Request) {}) + } +} + +func BenchmarkHandlersPushFront(b *testing.B) { + handlers := request.Handlers{} + + for i := 0; i < b.N; i++ { + h := handlers.Copy() + h.Validate.PushFront(func(r *request.Request) {}) + h.Validate.PushFront(func(r *request.Request) {}) + h.Validate.PushFront(func(r *request.Request) {}) + h.Validate.PushFront(func(r *request.Request) {}) + } +} + +func BenchmarkHandlersClear(b *testing.B) { + handlers := request.Handlers{} + + for i := 0; i < b.N; i++ { + h := handlers.Copy() + h.Validate.PushFront(func(r *request.Request) {}) + h.Validate.PushFront(func(r *request.Request) {}) + h.Validate.PushFront(func(r *request.Request) {}) + h.Validate.PushFront(func(r *request.Request) {}) + h.Clear() + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/http_request_copy_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/http_request_copy_test.go new file mode 100644 index 000000000..4a4f8550b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/http_request_copy_test.go @@ -0,0 +1,34 @@ +package request + +import ( + "bytes" + "io/ioutil" + "net/http" + "net/url" + "sync" + "testing" +) + +func TestRequestCopyRace(t *testing.T) { + origReq := &http.Request{URL: &url.URL{}, Header: http.Header{}} + origReq.Header.Set("Header", "OrigValue") + + var wg sync.WaitGroup + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + req := copyHTTPRequest(origReq, ioutil.NopCloser(&bytes.Buffer{})) + req.Header.Set("Header", "Value") + go func() { + req2 := copyHTTPRequest(req, ioutil.NopCloser(&bytes.Buffer{})) + req2.Header.Add("Header", "Value2") + }() + _ = req.Header.Get("Header") + wg.Done() + }() + _ = origReq.Header.Get("Header") + } + origReq.Header.Get("Header") + + wg.Wait() +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/http_request_retry_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/http_request_retry_test.go new file mode 100644 index 000000000..2ce9ef4c3 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/http_request_retry_test.go @@ -0,0 +1,37 @@ +// +build go1.5 + +package request_test + +import ( + "errors" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting/mock" + "github.com/stretchr/testify/assert" +) + +func TestRequestCancelRetry(t *testing.T) { + c := make(chan struct{}) + + reqNum := 0 + s := mock.NewMockClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.Clear() + s.Handlers.UnmarshalMeta.Clear() + s.Handlers.UnmarshalError.Clear() + s.Handlers.Send.PushFront(func(r *request.Request) { + reqNum++ + r.Error = errors.New("net/http: request canceled") + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + r.HTTPRequest.Cancel = c + close(c) + + err := r.Send() + assert.True(t, strings.Contains(err.Error(), "canceled")) + assert.Equal(t, 1, reqNum) +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader_test.go new file mode 100644 index 000000000..e5ec043b8 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/offset_reader_test.go @@ -0,0 +1,140 @@ +package request + +import ( + "bytes" + "io" + "math/rand" + "sync" + "testing" + "time" + + "github.com/aws/aws-sdk-go/internal/sdkio" + "github.com/stretchr/testify/assert" +) + +func TestOffsetReaderRead(t *testing.T) { + buf := []byte("testData") + reader := &offsetReader{buf: bytes.NewReader(buf)} + + tempBuf := make([]byte, len(buf)) + + n, err := reader.Read(tempBuf) + + assert.Equal(t, n, len(buf)) + assert.Nil(t, err) + assert.Equal(t, buf, tempBuf) +} + +func TestOffsetReaderSeek(t *testing.T) { + buf := []byte("testData") + reader := newOffsetReader(bytes.NewReader(buf), 0) + + orig, err := reader.Seek(0, sdkio.SeekCurrent) + assert.NoError(t, err) + assert.Equal(t, int64(0), orig) + + n, err := reader.Seek(0, sdkio.SeekEnd) + assert.NoError(t, err) + assert.Equal(t, int64(len(buf)), n) + + n, err = reader.Seek(orig, sdkio.SeekStart) + assert.NoError(t, err) + assert.Equal(t, int64(0), n) +} + +func TestOffsetReaderClose(t *testing.T) { + buf := []byte("testData") + reader := &offsetReader{buf: bytes.NewReader(buf)} + + err := reader.Close() + assert.Nil(t, err) + + tempBuf := make([]byte, len(buf)) + n, err := reader.Read(tempBuf) + assert.Equal(t, n, 0) + assert.Equal(t, err, io.EOF) +} + +func TestOffsetReaderCloseAndCopy(t *testing.T) { + buf := []byte("testData") + tempBuf := make([]byte, len(buf)) + reader := &offsetReader{buf: bytes.NewReader(buf)} + + newReader := reader.CloseAndCopy(0) + + n, err := reader.Read(tempBuf) + assert.Equal(t, n, 0) + assert.Equal(t, err, io.EOF) + + n, err = newReader.Read(tempBuf) + assert.Equal(t, n, len(buf)) + assert.Nil(t, err) + assert.Equal(t, buf, tempBuf) +} + +func TestOffsetReaderCloseAndCopyOffset(t *testing.T) { + buf := []byte("testData") + tempBuf := make([]byte, len(buf)) + reader := &offsetReader{buf: bytes.NewReader(buf)} + + newReader := reader.CloseAndCopy(4) + n, err := newReader.Read(tempBuf) + assert.Equal(t, n, len(buf)-4) + assert.Nil(t, err) + + expected := []byte{'D', 'a', 't', 'a', 0, 0, 0, 0} + assert.Equal(t, expected, tempBuf) +} + +func TestOffsetReaderRace(t *testing.T) { + wg := sync.WaitGroup{} + + f := func(reader *offsetReader) { + defer wg.Done() + var err error + buf := make([]byte, 1) + _, err = reader.Read(buf) + for err != io.EOF { + _, err = reader.Read(buf) + } + + } + + closeFn := func(reader *offsetReader) { + defer wg.Done() + time.Sleep(time.Duration(rand.Intn(20)+1) * time.Millisecond) + reader.Close() + } + for i := 0; i < 50; i++ { + reader := &offsetReader{buf: bytes.NewReader(make([]byte, 1024*1024))} + wg.Add(1) + go f(reader) + wg.Add(1) + go closeFn(reader) + } + wg.Wait() +} + +func BenchmarkOffsetReader(b *testing.B) { + bufSize := 1024 * 1024 * 100 + buf := make([]byte, bufSize) + reader := &offsetReader{buf: bytes.NewReader(buf)} + + tempBuf := make([]byte, 1024) + + for i := 0; i < b.N; i++ { + reader.Read(tempBuf) + } +} + +func BenchmarkBytesReader(b *testing.B) { + bufSize := 1024 * 1024 * 100 + buf := make([]byte, bufSize) + reader := bytes.NewReader(buf) + + tempBuf := make([]byte, 1024) + + for i := 0; i < b.N; i++ { + reader.Read(tempBuf) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_5_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_5_test.go new file mode 100644 index 000000000..91b4e7b3b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_5_test.go @@ -0,0 +1,11 @@ +// +build !go1.6 + +package request_test + +import ( + "errors" + + "github.com/aws/aws-sdk-go/aws/awserr" +) + +var errTimeout = awserr.New("foo", "bar", errors.New("net/http: request canceled Timeout")) diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_6_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_6_test.go new file mode 100644 index 000000000..d0314abe9 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_6_test.go @@ -0,0 +1,51 @@ +// +build go1.6 + +package request_test + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/defaults" + "github.com/aws/aws-sdk-go/aws/request" +) + +// go version 1.4 and 1.5 do not return an error. Version 1.5 will url encode +// the uri while 1.4 will not +func TestRequestInvalidEndpoint(t *testing.T) { + endpoint := "http://localhost:90 " + + r := request.New( + aws.Config{}, + metadata.ClientInfo{Endpoint: endpoint}, + defaults.Handlers(), + client.DefaultRetryer{}, + &request.Operation{}, + nil, + nil, + ) + + assert.Error(t, r.Error) +} + +type timeoutErr struct { + error +} + +var errTimeout = awserr.New("foo", "bar", &timeoutErr{ + errors.New("net/http: request canceled"), +}) + +func (e *timeoutErr) Timeout() bool { + return true +} + +func (e *timeoutErr) Temporary() bool { + return true +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7_test.go new file mode 100644 index 000000000..ca6150cb0 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_7_test.go @@ -0,0 +1,24 @@ +// +build !go1.8 + +package request + +import ( + "net/http" + "strings" + "testing" +) + +func TestResetBody_WithEmptyBody(t *testing.T) { + r := Request{ + HTTPRequest: &http.Request{}, + } + + reader := strings.NewReader("") + r.Body = reader + + r.ResetBody() + + if a, e := r.HTTPRequest.Body, (noBody{}); a != e { + t.Errorf("expected request body to be set to reader, got %#v", r.HTTPRequest.Body) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8_test.go new file mode 100644 index 000000000..8f3b0f04e --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_1_8_test.go @@ -0,0 +1,85 @@ +// +build go1.8 + +package request_test + +import ( + "bytes" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" +) + +func TestResetBody_WithEmptyBody(t *testing.T) { + r := request.Request{ + HTTPRequest: &http.Request{}, + } + + reader := strings.NewReader("") + r.Body = reader + + r.ResetBody() + + if a, e := r.HTTPRequest.Body, http.NoBody; a != e { + t.Errorf("expected request body to be set to reader, got %#v", + r.HTTPRequest.Body) + } +} + +func TestRequest_FollowPUTRedirects(t *testing.T) { + const bodySize = 1024 + + redirectHit := 0 + endpointHit := 0 + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/redirect-me": + u := *r.URL + u.Path = "/endpoint" + w.Header().Set("Location", u.String()) + w.WriteHeader(307) + redirectHit++ + case "/endpoint": + b := bytes.Buffer{} + io.Copy(&b, r.Body) + r.Body.Close() + if e, a := bodySize, b.Len(); e != a { + t.Fatalf("expect %d body size, got %d", e, a) + } + endpointHit++ + default: + t.Fatalf("unexpected endpoint used, %q", r.URL.String()) + } + })) + + svc := awstesting.NewClient(&aws.Config{ + Region: unit.Session.Config.Region, + DisableSSL: aws.Bool(true), + Endpoint: aws.String(server.URL), + }) + + req := svc.NewRequest(&request.Operation{ + Name: "Operation", + HTTPMethod: "PUT", + HTTPPath: "/redirect-me", + }, &struct{}{}, &struct{}{}) + req.SetReaderBody(bytes.NewReader(make([]byte, bodySize))) + + err := req.Send() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := 1, redirectHit; e != a { + t.Errorf("expect %d redirect hits, got %d", e, a) + } + if e, a := 1, endpointHit; e != a { + t.Errorf("expect %d endpoint hits, got %d", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_context_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_context_test.go new file mode 100644 index 000000000..2af286756 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_context_test.go @@ -0,0 +1,46 @@ +package request_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws/corehandlers" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" +) + +func TestRequest_SetContext(t *testing.T) { + svc := awstesting.NewClient() + svc.Handlers.Clear() + svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler) + + r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + r.SetContext(ctx) + + ctx.Error = fmt.Errorf("context canceled") + close(ctx.DoneCh) + + err := r.Send() + if err == nil { + t.Fatalf("expected error, got none") + } + + // Only check against canceled because go 1.6 will not use the context's + // Err(). + if e, a := "canceled", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %q to be in %q, but was not", e, a) + } +} + +func TestRequest_SetContextPanic(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("expect SetContext to panic, did not") + } + }() + r := &request.Request{} + + r.SetContext(nil) +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_internal_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_internal_test.go new file mode 100644 index 000000000..966f93455 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_internal_test.go @@ -0,0 +1,27 @@ +package request + +import ( + "testing" +) + +func TestCopy(t *testing.T) { + handlers := Handlers{} + op := &Operation{} + op.HTTPMethod = "Foo" + req := &Request{} + req.Operation = op + req.Handlers = handlers + + r := req.copy() + + if r == req { + t.Fatal("expect request pointer copy to be different") + } + if r.Operation == req.Operation { + t.Errorf("expect request operation pointer to be different") + } + + if e, a := req.Operation.HTTPMethod, r.Operation.HTTPMethod; e != a { + t.Errorf("expect %q http method, got %q", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination_test.go new file mode 100644 index 000000000..b942e014f --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_pagination_test.go @@ -0,0 +1,619 @@ +package request_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/dynamodb" + "github.com/aws/aws-sdk-go/service/route53" + "github.com/aws/aws-sdk-go/service/s3" +) + +// Use DynamoDB methods for simplicity +func TestPaginationQueryPage(t *testing.T) { + db := dynamodb.New(unit.Session) + tokens, pages, numPages, gotToEnd := []map[string]*dynamodb.AttributeValue{}, []map[string]*dynamodb.AttributeValue{}, 0, false + + reqNum := 0 + resps := []*dynamodb.QueryOutput{ + { + LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}}, + Count: aws.Int64(1), + Items: []map[string]*dynamodb.AttributeValue{ + { + "key": {S: aws.String("key1")}, + }, + }, + }, + { + LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}}, + Count: aws.Int64(1), + Items: []map[string]*dynamodb.AttributeValue{ + { + "key": {S: aws.String("key2")}, + }, + }, + }, + { + LastEvaluatedKey: map[string]*dynamodb.AttributeValue{}, + Count: aws.Int64(1), + Items: []map[string]*dynamodb.AttributeValue{ + { + "key": {S: aws.String("key3")}, + }, + }, + }, + } + + db.Handlers.Send.Clear() // mock sending + db.Handlers.Unmarshal.Clear() + db.Handlers.UnmarshalMeta.Clear() + db.Handlers.ValidateResponse.Clear() + db.Handlers.Build.PushBack(func(r *request.Request) { + in := r.Params.(*dynamodb.QueryInput) + if in == nil { + tokens = append(tokens, nil) + } else if len(in.ExclusiveStartKey) != 0 { + tokens = append(tokens, in.ExclusiveStartKey) + } + }) + db.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = resps[reqNum] + reqNum++ + }) + + params := &dynamodb.QueryInput{ + Limit: aws.Int64(2), + TableName: aws.String("tablename"), + } + err := db.QueryPages(params, func(p *dynamodb.QueryOutput, last bool) bool { + numPages++ + for _, item := range p.Items { + pages = append(pages, item) + } + if last { + if gotToEnd { + assert.Fail(t, "last=true happened twice") + } + gotToEnd = true + } + return true + }) + assert.Nil(t, err) + + assert.Equal(t, + []map[string]*dynamodb.AttributeValue{ + {"key": {S: aws.String("key1")}}, + {"key": {S: aws.String("key2")}}, + }, tokens) + assert.Equal(t, + []map[string]*dynamodb.AttributeValue{ + {"key": {S: aws.String("key1")}}, + {"key": {S: aws.String("key2")}}, + {"key": {S: aws.String("key3")}}, + }, pages) + assert.Equal(t, 3, numPages) + assert.True(t, gotToEnd) + assert.Nil(t, params.ExclusiveStartKey) +} + +// Use DynamoDB methods for simplicity +func TestPagination(t *testing.T) { + db := dynamodb.New(unit.Session) + tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false + + reqNum := 0 + resps := []*dynamodb.ListTablesOutput{ + {TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")}, + {TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")}, + {TableNames: []*string{aws.String("Table5")}}, + } + + db.Handlers.Send.Clear() // mock sending + db.Handlers.Unmarshal.Clear() + db.Handlers.UnmarshalMeta.Clear() + db.Handlers.ValidateResponse.Clear() + db.Handlers.Build.PushBack(func(r *request.Request) { + in := r.Params.(*dynamodb.ListTablesInput) + if in == nil { + tokens = append(tokens, "") + } else if in.ExclusiveStartTableName != nil { + tokens = append(tokens, *in.ExclusiveStartTableName) + } + }) + db.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = resps[reqNum] + reqNum++ + }) + + params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)} + err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool { + numPages++ + for _, t := range p.TableNames { + pages = append(pages, *t) + } + if last { + if gotToEnd { + assert.Fail(t, "last=true happened twice") + } + gotToEnd = true + } + return true + }) + + assert.Equal(t, []string{"Table2", "Table4"}, tokens) + assert.Equal(t, []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages) + assert.Equal(t, 3, numPages) + assert.True(t, gotToEnd) + assert.Nil(t, err) + assert.Nil(t, params.ExclusiveStartTableName) +} + +// Use DynamoDB methods for simplicity +func TestPaginationEachPage(t *testing.T) { + db := dynamodb.New(unit.Session) + tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false + + reqNum := 0 + resps := []*dynamodb.ListTablesOutput{ + {TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")}, + {TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")}, + {TableNames: []*string{aws.String("Table5")}}, + } + + db.Handlers.Send.Clear() // mock sending + db.Handlers.Unmarshal.Clear() + db.Handlers.UnmarshalMeta.Clear() + db.Handlers.ValidateResponse.Clear() + db.Handlers.Build.PushBack(func(r *request.Request) { + in := r.Params.(*dynamodb.ListTablesInput) + if in == nil { + tokens = append(tokens, "") + } else if in.ExclusiveStartTableName != nil { + tokens = append(tokens, *in.ExclusiveStartTableName) + } + }) + db.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = resps[reqNum] + reqNum++ + }) + + params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)} + req, _ := db.ListTablesRequest(params) + err := req.EachPage(func(p interface{}, last bool) bool { + numPages++ + for _, t := range p.(*dynamodb.ListTablesOutput).TableNames { + pages = append(pages, *t) + } + if last { + if gotToEnd { + assert.Fail(t, "last=true happened twice") + } + gotToEnd = true + } + + return true + }) + + assert.Equal(t, []string{"Table2", "Table4"}, tokens) + assert.Equal(t, []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages) + assert.Equal(t, 3, numPages) + assert.True(t, gotToEnd) + assert.Nil(t, err) +} + +// Use DynamoDB methods for simplicity +func TestPaginationEarlyExit(t *testing.T) { + db := dynamodb.New(unit.Session) + numPages, gotToEnd := 0, false + + reqNum := 0 + resps := []*dynamodb.ListTablesOutput{ + {TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")}, + {TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")}, + {TableNames: []*string{aws.String("Table5")}}, + } + + db.Handlers.Send.Clear() // mock sending + db.Handlers.Unmarshal.Clear() + db.Handlers.UnmarshalMeta.Clear() + db.Handlers.ValidateResponse.Clear() + db.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = resps[reqNum] + reqNum++ + }) + + params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)} + err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool { + numPages++ + if numPages == 2 { + return false + } + if last { + if gotToEnd { + assert.Fail(t, "last=true happened twice") + } + gotToEnd = true + } + return true + }) + + assert.Equal(t, 2, numPages) + assert.False(t, gotToEnd) + assert.Nil(t, err) +} + +func TestSkipPagination(t *testing.T) { + client := s3.New(unit.Session) + client.Handlers.Send.Clear() // mock sending + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + client.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = &s3.HeadBucketOutput{} + }) + + req, _ := client.HeadBucketRequest(&s3.HeadBucketInput{Bucket: aws.String("bucket")}) + + numPages, gotToEnd := 0, false + req.EachPage(func(p interface{}, last bool) bool { + numPages++ + if last { + gotToEnd = true + } + return true + }) + assert.Equal(t, 1, numPages) + assert.True(t, gotToEnd) +} + +// Use S3 for simplicity +func TestPaginationTruncation(t *testing.T) { + client := s3.New(unit.Session) + + reqNum := 0 + resps := []*s3.ListObjectsOutput{ + {IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key1")}}}, + {IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key2")}}}, + {IsTruncated: aws.Bool(false), Contents: []*s3.Object{{Key: aws.String("Key3")}}}, + {IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key4")}}}, + } + + client.Handlers.Send.Clear() // mock sending + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + client.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = resps[reqNum] + reqNum++ + }) + + params := &s3.ListObjectsInput{Bucket: aws.String("bucket")} + + results := []string{} + err := client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool { + results = append(results, *p.Contents[0].Key) + return true + }) + + assert.Equal(t, []string{"Key1", "Key2", "Key3"}, results) + assert.Nil(t, err) + + // Try again without truncation token at all + reqNum = 0 + resps[1].IsTruncated = nil + resps[2].IsTruncated = aws.Bool(true) + results = []string{} + err = client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool { + results = append(results, *p.Contents[0].Key) + return true + }) + + assert.Equal(t, []string{"Key1", "Key2"}, results) + assert.Nil(t, err) +} + +func TestPaginationNilToken(t *testing.T) { + client := route53.New(unit.Session) + + reqNum := 0 + resps := []*route53.ListResourceRecordSetsOutput{ + { + ResourceRecordSets: []*route53.ResourceRecordSet{ + {Name: aws.String("first.example.com.")}, + }, + IsTruncated: aws.Bool(true), + NextRecordName: aws.String("second.example.com."), + NextRecordType: aws.String("MX"), + NextRecordIdentifier: aws.String("second"), + MaxItems: aws.String("1"), + }, + { + ResourceRecordSets: []*route53.ResourceRecordSet{ + {Name: aws.String("second.example.com.")}, + }, + IsTruncated: aws.Bool(true), + NextRecordName: aws.String("third.example.com."), + NextRecordType: aws.String("MX"), + MaxItems: aws.String("1"), + }, + { + ResourceRecordSets: []*route53.ResourceRecordSet{ + {Name: aws.String("third.example.com.")}, + }, + IsTruncated: aws.Bool(false), + MaxItems: aws.String("1"), + }, + } + client.Handlers.Send.Clear() // mock sending + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + + idents := []string{} + client.Handlers.Build.PushBack(func(r *request.Request) { + p := r.Params.(*route53.ListResourceRecordSetsInput) + idents = append(idents, aws.StringValue(p.StartRecordIdentifier)) + + }) + client.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = resps[reqNum] + reqNum++ + }) + + params := &route53.ListResourceRecordSetsInput{ + HostedZoneId: aws.String("id-zone"), + } + + results := []string{} + err := client.ListResourceRecordSetsPages(params, func(p *route53.ListResourceRecordSetsOutput, last bool) bool { + results = append(results, *p.ResourceRecordSets[0].Name) + return true + }) + + assert.NoError(t, err) + assert.Equal(t, []string{"", "second", ""}, idents) + assert.Equal(t, []string{"first.example.com.", "second.example.com.", "third.example.com."}, results) +} + +func TestPaginationNilInput(t *testing.T) { + // Code generation doesn't have a great way to verify the code is correct + // other than being run via unit tests in the SDK. This should be fixed + // So code generation can be validated independently. + + client := s3.New(unit.Session) + client.Handlers.Validate.Clear() + client.Handlers.Send.Clear() // mock sending + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + client.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = &s3.ListObjectsOutput{} + }) + + gotToEnd := false + numPages := 0 + err := client.ListObjectsPages(nil, func(p *s3.ListObjectsOutput, last bool) bool { + numPages++ + if last { + gotToEnd = true + } + return true + }) + + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } + if e, a := 1, numPages; e != a { + t.Errorf("expect %d number pages but got %d", e, a) + } + if !gotToEnd { + t.Errorf("expect to of gotten to end, did not") + } +} + +func TestPaginationWithContextNilInput(t *testing.T) { + // Code generation doesn't have a great way to verify the code is correct + // other than being run via unit tests in the SDK. This should be fixed + // So code generation can be validated independently. + + client := s3.New(unit.Session) + client.Handlers.Validate.Clear() + client.Handlers.Send.Clear() // mock sending + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + client.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = &s3.ListObjectsOutput{} + }) + + gotToEnd := false + numPages := 0 + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + err := client.ListObjectsPagesWithContext(ctx, nil, func(p *s3.ListObjectsOutput, last bool) bool { + numPages++ + if last { + gotToEnd = true + } + return true + }) + + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } + if e, a := 1, numPages; e != a { + t.Errorf("expect %d number pages but got %d", e, a) + } + if !gotToEnd { + t.Errorf("expect to of gotten to end, did not") + } +} + +func TestPagination_Standalone(t *testing.T) { + type testPageInput struct { + NextToken *string + } + type testPageOutput struct { + Value *string + NextToken *string + } + type testCase struct { + Value, PrevToken, NextToken *string + } + + cases := [][]testCase{ + { + testCase{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")}, + testCase{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")}, + testCase{aws.String("ThirdValue"), aws.String("SecondToken"), nil}, + }, + { + testCase{aws.String("FirstValue"), aws.String("InitalToken"), aws.String("FirstToken")}, + testCase{aws.String("SecondValue"), aws.String("FirstToken"), aws.String("SecondToken")}, + testCase{aws.String("ThirdValue"), aws.String("SecondToken"), aws.String("")}, + }, + } + + for _, c := range cases { + input := testPageInput{ + NextToken: c[0].PrevToken, + } + + svc := awstesting.NewClient() + i := 0 + p := request.Pagination{ + NewRequest: func() (*request.Request, error) { + r := svc.NewRequest( + &request.Operation{ + Name: "Operation", + Paginator: &request.Paginator{ + InputTokens: []string{"NextToken"}, + OutputTokens: []string{"NextToken"}, + }, + }, + &input, &testPageOutput{}, + ) + // Setup handlers for testing + r.Handlers.Clear() + r.Handlers.Build.PushBack(func(req *request.Request) { + if e, a := len(c), i+1; a > e { + t.Fatalf("expect no more than %d requests, got %d", e, a) + } + in := req.Params.(*testPageInput) + if e, a := aws.StringValue(c[i].PrevToken), aws.StringValue(in.NextToken); e != a { + t.Errorf("%d, expect NextToken input %q, got %q", i, e, a) + } + }) + r.Handlers.Unmarshal.PushBack(func(req *request.Request) { + out := &testPageOutput{ + Value: c[i].Value, + } + if c[i].NextToken != nil { + next := *c[i].NextToken + out.NextToken = aws.String(next) + } + req.Data = out + }) + return r, nil + }, + } + + for p.Next() { + data := p.Page().(*testPageOutput) + + if e, a := aws.StringValue(c[i].Value), aws.StringValue(data.Value); e != a { + t.Errorf("%d, expect Value to be %q, got %q", i, e, a) + } + if e, a := aws.StringValue(c[i].NextToken), aws.StringValue(data.NextToken); e != a { + t.Errorf("%d, expect NextToken to be %q, got %q", i, e, a) + } + + i++ + } + if e, a := len(c), i; e != a { + t.Errorf("expected to process %d pages, did %d", e, a) + } + if err := p.Err(); err != nil { + t.Fatalf("%d, expected no error, got %v", i, err) + } + } +} + +// Benchmarks +var benchResps = []*dynamodb.ListTablesOutput{ + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")}, + {TableNames: []*string{aws.String("TABLE")}}, +} + +var benchDb = func() *dynamodb.DynamoDB { + db := dynamodb.New(unit.Session) + db.Handlers.Send.Clear() // mock sending + db.Handlers.Unmarshal.Clear() + db.Handlers.UnmarshalMeta.Clear() + db.Handlers.ValidateResponse.Clear() + return db +} + +func BenchmarkCodegenIterator(b *testing.B) { + reqNum := 0 + db := benchDb() + db.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = benchResps[reqNum] + reqNum++ + }) + + input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)} + iter := func(fn func(*dynamodb.ListTablesOutput, bool) bool) error { + page, _ := db.ListTablesRequest(input) + for ; page != nil; page = page.NextPage() { + page.Send() + out := page.Data.(*dynamodb.ListTablesOutput) + if result := fn(out, !page.HasNextPage()); page.Error != nil || !result { + return page.Error + } + } + return nil + } + + for i := 0; i < b.N; i++ { + reqNum = 0 + iter(func(p *dynamodb.ListTablesOutput, last bool) bool { + return true + }) + } +} + +func BenchmarkEachPageIterator(b *testing.B) { + reqNum := 0 + db := benchDb() + db.Handlers.Unmarshal.PushBack(func(r *request.Request) { + r.Data = benchResps[reqNum] + reqNum++ + }) + + input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)} + for i := 0; i < b.N; i++ { + reqNum = 0 + req, _ := db.ListTablesRequest(input) + req.EachPage(func(p interface{}, last bool) bool { + return true + }) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_resetbody_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_resetbody_test.go new file mode 100644 index 000000000..d7845b752 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_resetbody_test.go @@ -0,0 +1,107 @@ +package request + +import ( + "bytes" + "io" + "net/http" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" +) + +func TestResetBody_WithBodyContents(t *testing.T) { + r := Request{ + HTTPRequest: &http.Request{}, + } + + reader := strings.NewReader("abc") + r.Body = reader + + r.ResetBody() + + if v, ok := r.HTTPRequest.Body.(*offsetReader); !ok || v == nil { + t.Errorf("expected request body to be set to reader, got %#v", + r.HTTPRequest.Body) + } +} + +type mockReader struct{} + +func (mockReader) Read([]byte) (int, error) { + return 0, io.EOF +} + +func TestResetBody_ExcludeEmptyUnseekableBodyByMethod(t *testing.T) { + cases := []struct { + Method string + Body io.ReadSeeker + IsNoBody bool + }{ + { + Method: "GET", + IsNoBody: true, + Body: aws.ReadSeekCloser(mockReader{}), + }, + { + Method: "HEAD", + IsNoBody: true, + Body: aws.ReadSeekCloser(mockReader{}), + }, + { + Method: "DELETE", + IsNoBody: true, + Body: aws.ReadSeekCloser(mockReader{}), + }, + { + Method: "PUT", + IsNoBody: false, + Body: aws.ReadSeekCloser(mockReader{}), + }, + { + Method: "PATCH", + IsNoBody: false, + Body: aws.ReadSeekCloser(mockReader{}), + }, + { + Method: "POST", + IsNoBody: false, + Body: aws.ReadSeekCloser(mockReader{}), + }, + { + Method: "GET", + IsNoBody: false, + Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("abc"))), + }, + { + Method: "GET", + IsNoBody: true, + Body: aws.ReadSeekCloser(bytes.NewBuffer(nil)), + }, + { + Method: "POST", + IsNoBody: false, + Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("abc"))), + }, + { + Method: "POST", + IsNoBody: true, + Body: aws.ReadSeekCloser(bytes.NewBuffer(nil)), + }, + } + + for i, c := range cases { + r := Request{ + HTTPRequest: &http.Request{}, + Operation: &Operation{ + HTTPMethod: c.Method, + }, + } + r.SetReaderBody(c.Body) + + if a, e := r.HTTPRequest.Body == NoBody, c.IsNoBody; a != e { + t.Errorf("%d, expect body to be set to noBody(%t), but was %t", i, e, a) + } + } + +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/request_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/request_test.go new file mode 100644 index 000000000..0e4cef06b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/request_test.go @@ -0,0 +1,1121 @@ +package request_test + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "reflect" + "runtime" + "strconv" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/corehandlers" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/defaults" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" + "github.com/aws/aws-sdk-go/private/protocol/rest" +) + +type testData struct { + Data string +} + +func body(str string) io.ReadCloser { + return ioutil.NopCloser(bytes.NewReader([]byte(str))) +} + +func unmarshal(req *request.Request) { + defer req.HTTPResponse.Body.Close() + if req.Data != nil { + json.NewDecoder(req.HTTPResponse.Body).Decode(req.Data) + } + return +} + +func unmarshalError(req *request.Request) { + bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body) + if err != nil { + req.Error = awserr.New("UnmarshaleError", req.HTTPResponse.Status, err) + return + } + if len(bodyBytes) == 0 { + req.Error = awserr.NewRequestFailure( + awserr.New("UnmarshaleError", req.HTTPResponse.Status, fmt.Errorf("empty body")), + req.HTTPResponse.StatusCode, + "", + ) + return + } + var jsonErr jsonErrorResponse + if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil { + req.Error = awserr.New("UnmarshaleError", "JSON unmarshal", err) + return + } + req.Error = awserr.NewRequestFailure( + awserr.New(jsonErr.Code, jsonErr.Message, nil), + req.HTTPResponse.StatusCode, + "", + ) +} + +type jsonErrorResponse struct { + Code string `json:"__type"` + Message string `json:"message"` +} + +// test that retries occur for 5xx status codes +func TestRequestRecoverRetry5xx(t *testing.T) { + reqNum := 0 + reqs := []http.Response{ + {StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + {StatusCode: 502, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + {StatusCode: 200, Body: body(`{"data":"valid"}`)}, + } + + s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &reqs[reqNum] + reqNum++ + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } + if e, a := 2, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + if e, a := "valid", out.Data; e != a { + t.Errorf("expect %q output got %q", e, a) + } +} + +// test that retries occur for 4xx status codes with a response type that can be retried - see `shouldRetry` +func TestRequestRecoverRetry4xxRetryable(t *testing.T) { + reqNum := 0 + reqs := []http.Response{ + {StatusCode: 400, Body: body(`{"__type":"Throttling","message":"Rate exceeded."}`)}, + {StatusCode: 400, Body: body(`{"__type":"ProvisionedThroughputExceededException","message":"Rate exceeded."}`)}, + {StatusCode: 429, Body: body(`{"__type":"FooException","message":"Rate exceeded."}`)}, + {StatusCode: 200, Body: body(`{"data":"valid"}`)}, + } + + s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &reqs[reqNum] + reqNum++ + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } + if e, a := 3, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + if e, a := "valid", out.Data; e != a { + t.Errorf("expect %q output got %q", e, a) + } +} + +// test that retries don't occur for 4xx status codes with a response type that can't be retried +func TestRequest4xxUnretryable(t *testing.T) { + s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &http.Response{StatusCode: 401, Body: body(`{"__type":"SignatureDoesNotMatch","message":"Signature does not match."}`)} + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err == nil { + t.Fatalf("expect error, but did not get one") + } + aerr := err.(awserr.RequestFailure) + if e, a := 401, aerr.StatusCode(); e != a { + t.Errorf("expect %d status code, got %d", e, a) + } + if e, a := "SignatureDoesNotMatch", aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + if e, a := "Signature does not match.", aerr.Message(); e != a { + t.Errorf("expect %q error message, got %q", e, a) + } + if e, a := 0, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } +} + +func TestRequestExhaustRetries(t *testing.T) { + delays := []time.Duration{} + sleepDelay := func(delay time.Duration) { + delays = append(delays, delay) + } + + reqNum := 0 + reqs := []http.Response{ + {StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + {StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + {StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + {StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + } + + s := awstesting.NewClient(aws.NewConfig().WithSleepDelay(sleepDelay)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &reqs[reqNum] + reqNum++ + }) + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + err := r.Send() + if err == nil { + t.Fatalf("expect error, but did not get one") + } + aerr := err.(awserr.RequestFailure) + if e, a := 500, aerr.StatusCode(); e != a { + t.Errorf("expect %d status code, got %d", e, a) + } + if e, a := "UnknownError", aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + if e, a := "An error occurred.", aerr.Message(); e != a { + t.Errorf("expect %q error message, got %q", e, a) + } + if e, a := 3, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + + expectDelays := []struct{ min, max time.Duration }{{30, 59}, {60, 118}, {120, 236}} + for i, v := range delays { + min := expectDelays[i].min * time.Millisecond + max := expectDelays[i].max * time.Millisecond + if !(min <= v && v <= max) { + t.Errorf("Expect delay to be within range, i:%d, v:%s, min:%s, max:%s", + i, v, min, max) + } + } +} + +// test that the request is retried after the credentials are expired. +func TestRequestRecoverExpiredCreds(t *testing.T) { + reqNum := 0 + reqs := []http.Response{ + {StatusCode: 400, Body: body(`{"__type":"ExpiredTokenException","message":"expired token"}`)}, + {StatusCode: 200, Body: body(`{"data":"valid"}`)}, + } + + s := awstesting.NewClient(&aws.Config{MaxRetries: aws.Int(10), Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "")}) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + + credExpiredBeforeRetry := false + credExpiredAfterRetry := false + + s.Handlers.AfterRetry.PushBack(func(r *request.Request) { + credExpiredAfterRetry = r.Config.Credentials.IsExpired() + }) + + s.Handlers.Sign.Clear() + s.Handlers.Sign.PushBack(func(r *request.Request) { + r.Config.Credentials.Get() + }) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &reqs[reqNum] + reqNum++ + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if credExpiredBeforeRetry { + t.Errorf("Expect valid creds before retry check") + } + if !credExpiredAfterRetry { + t.Errorf("Expect expired creds after retry check") + } + if s.Config.Credentials.IsExpired() { + t.Errorf("Expect valid creds after cred expired recovery") + } + + if e, a := 1, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + if e, a := "valid", out.Data; e != a { + t.Errorf("expect %q output got %q", e, a) + } +} + +func TestMakeAddtoUserAgentHandler(t *testing.T) { + fn := request.MakeAddToUserAgentHandler("name", "version", "extra1", "extra2") + r := &request.Request{HTTPRequest: &http.Request{Header: http.Header{}}} + r.HTTPRequest.Header.Set("User-Agent", "foo/bar") + fn(r) + + if e, a := "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"); e != a { + t.Errorf("expect %q user agent, got %q", e, a) + } +} + +func TestMakeAddtoUserAgentFreeFormHandler(t *testing.T) { + fn := request.MakeAddToUserAgentFreeFormHandler("name/version (extra1; extra2)") + r := &request.Request{HTTPRequest: &http.Request{Header: http.Header{}}} + r.HTTPRequest.Header.Set("User-Agent", "foo/bar") + fn(r) + + if e, a := "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"); e != a { + t.Errorf("expect %q user agent, got %q", e, a) + } +} + +func TestRequestUserAgent(t *testing.T) { + s := awstesting.NewClient(&aws.Config{Region: aws.String("us-east-1")}) + // s.Handlers.Validate.Clear() + + req := s.NewRequest(&request.Operation{Name: "Operation"}, nil, &testData{}) + req.HTTPRequest.Header.Set("User-Agent", "foo/bar") + if err := req.Build(); err != nil { + t.Fatalf("expect no error, got %v", err) + } + + expectUA := fmt.Sprintf("foo/bar %s/%s (%s; %s; %s)", + aws.SDKName, aws.SDKVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH) + if e, a := expectUA, req.HTTPRequest.Header.Get("User-Agent"); e != a { + t.Errorf("expect %q user agent, got %q", e, a) + } +} + +func TestRequestThrottleRetries(t *testing.T) { + delays := []time.Duration{} + sleepDelay := func(delay time.Duration) { + delays = append(delays, delay) + } + + reqNum := 0 + reqs := []http.Response{ + {StatusCode: 500, Body: body(`{"__type":"Throttling","message":"An error occurred."}`)}, + {StatusCode: 500, Body: body(`{"__type":"Throttling","message":"An error occurred."}`)}, + {StatusCode: 500, Body: body(`{"__type":"Throttling","message":"An error occurred."}`)}, + {StatusCode: 500, Body: body(`{"__type":"Throttling","message":"An error occurred."}`)}, + } + + s := awstesting.NewClient(aws.NewConfig().WithSleepDelay(sleepDelay)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &reqs[reqNum] + reqNum++ + }) + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + err := r.Send() + if err == nil { + t.Fatalf("expect error, but did not get one") + } + aerr := err.(awserr.RequestFailure) + if e, a := 500, aerr.StatusCode(); e != a { + t.Errorf("expect %d status code, got %d", e, a) + } + if e, a := "Throttling", aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + if e, a := "An error occurred.", aerr.Message(); e != a { + t.Errorf("expect %q error message, got %q", e, a) + } + if e, a := 3, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + + expectDelays := []struct{ min, max time.Duration }{{500, 999}, {1000, 1998}, {2000, 3996}} + for i, v := range delays { + min := expectDelays[i].min * time.Millisecond + max := expectDelays[i].max * time.Millisecond + if !(min <= v && v <= max) { + t.Errorf("Expect delay to be within range, i:%d, v:%s, min:%s, max:%s", + i, v, min, max) + } + } +} + +// test that retries occur for request timeouts when response.Body can be nil +func TestRequestRecoverTimeoutWithNilBody(t *testing.T) { + reqNum := 0 + reqs := []*http.Response{ + {StatusCode: 0, Body: nil}, // body can be nil when requests time out + {StatusCode: 200, Body: body(`{"data":"valid"}`)}, + } + errors := []error{ + errTimeout, nil, + } + + s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.AfterRetry.Clear() // force retry on all errors + s.Handlers.AfterRetry.PushBack(func(r *request.Request) { + if r.Error != nil { + r.Error = nil + r.Retryable = aws.Bool(true) + r.RetryCount++ + } + }) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = reqs[reqNum] + r.Error = errors[reqNum] + reqNum++ + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } + if e, a := 1, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + if e, a := "valid", out.Data; e != a { + t.Errorf("expect %q output got %q", e, a) + } +} + +func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) { + reqNum := 0 + reqs := []*http.Response{ + nil, + {StatusCode: 200, Body: body(`{"data":"valid"}`)}, + } + errors := []error{ + errTimeout, + nil, + } + + s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.AfterRetry.Clear() // force retry on all errors + s.Handlers.AfterRetry.PushBack(func(r *request.Request) { + if r.Error != nil { + r.Error = nil + r.Retryable = aws.Bool(true) + r.RetryCount++ + } + }) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = reqs[reqNum] + r.Error = errors[reqNum] + reqNum++ + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } + if e, a := 1, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + if e, a := "valid", out.Data; e != a { + t.Errorf("expect %q output got %q", e, a) + } +} + +func TestRequest_NoBody(t *testing.T) { + cases := []string{ + "GET", "HEAD", "DELETE", + "PUT", "POST", "PATCH", + } + + for i, c := range cases { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if v := r.TransferEncoding; len(v) > 0 { + t.Errorf("%d, expect no body sent with Transfer-Encoding, %v", i, v) + } + + outMsg := []byte(`{"Value": "abc"}`) + + if b, err := ioutil.ReadAll(r.Body); err != nil { + t.Fatalf("%d, expect no error reading request body, got %v", i, err) + } else if n := len(b); n > 0 { + t.Errorf("%d, expect no request body, got %d bytes", i, n) + } + + w.Header().Set("Content-Length", strconv.Itoa(len(outMsg))) + if _, err := w.Write(outMsg); err != nil { + t.Fatalf("%d, expect no error writing server response, got %v", i, err) + } + })) + + s := awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + MaxRetries: aws.Int(0), + Endpoint: aws.String(server.URL), + DisableSSL: aws.Bool(true), + }) + s.Handlers.Build.PushBack(rest.Build) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + + in := struct { + Bucket *string `location:"uri" locationName:"bucket"` + Key *string `location:"uri" locationName:"key"` + }{ + Bucket: aws.String("mybucket"), Key: aws.String("myKey"), + } + + out := struct { + Value *string + }{} + + r := s.NewRequest(&request.Operation{ + Name: "OpName", HTTPMethod: c, HTTPPath: "/{bucket}/{key+}", + }, &in, &out) + + if err := r.Send(); err != nil { + t.Fatalf("%d, expect no error sending request, got %v", i, err) + } + } +} + +func TestIsSerializationErrorRetryable(t *testing.T) { + testCases := []struct { + err error + expected bool + }{ + { + err: awserr.New(request.ErrCodeSerialization, "foo error", nil), + expected: false, + }, + { + err: awserr.New("ErrFoo", "foo error", nil), + expected: false, + }, + { + err: nil, + expected: false, + }, + { + err: awserr.New(request.ErrCodeSerialization, "foo error", stubConnectionResetError), + expected: true, + }, + } + + for i, c := range testCases { + r := &request.Request{ + Error: c.err, + } + if r.IsErrorRetryable() != c.expected { + t.Errorf("Case %d: Expected %v, but received %v", i+1, c.expected, !c.expected) + } + } +} + +func TestWithLogLevel(t *testing.T) { + r := &request.Request{} + + opt := request.WithLogLevel(aws.LogDebugWithHTTPBody) + r.ApplyOptions(opt) + + if !r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) { + t.Errorf("expect log level to be set, but was not, %v", + r.Config.LogLevel.Value()) + } +} + +func TestWithGetResponseHeader(t *testing.T) { + r := &request.Request{} + + var val, val2 string + r.ApplyOptions( + request.WithGetResponseHeader("x-a-header", &val), + request.WithGetResponseHeader("x-second-header", &val2), + ) + + r.HTTPResponse = &http.Response{ + Header: func() http.Header { + h := http.Header{} + h.Set("x-a-header", "first") + h.Set("x-second-header", "second") + return h + }(), + } + r.Handlers.Complete.Run(r) + + if e, a := "first", val; e != a { + t.Errorf("expect %q header value got %q", e, a) + } + if e, a := "second", val2; e != a { + t.Errorf("expect %q header value got %q", e, a) + } +} + +func TestWithGetResponseHeaders(t *testing.T) { + r := &request.Request{} + + var headers http.Header + opt := request.WithGetResponseHeaders(&headers) + + r.ApplyOptions(opt) + + r.HTTPResponse = &http.Response{ + Header: func() http.Header { + h := http.Header{} + h.Set("x-a-header", "headerValue") + return h + }(), + } + r.Handlers.Complete.Run(r) + + if e, a := "headerValue", headers.Get("x-a-header"); e != a { + t.Errorf("expect %q header value got %q", e, a) + } +} + +type connResetCloser struct { +} + +func (rc *connResetCloser) Read(b []byte) (int, error) { + return 0, stubConnectionResetError +} + +func (rc *connResetCloser) Close() error { + return nil +} + +func TestSerializationErrConnectionReset(t *testing.T) { + count := 0 + handlers := request.Handlers{} + handlers.Send.PushBack(func(r *request.Request) { + count++ + r.HTTPResponse = &http.Response{} + r.HTTPResponse.Body = &connResetCloser{} + }) + + handlers.Sign.PushBackNamed(v4.SignRequestHandler) + handlers.Build.PushBackNamed(jsonrpc.BuildHandler) + handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler) + handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler) + handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler) + handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler) + + op := &request.Operation{ + Name: "op", + HTTPMethod: "POST", + HTTPPath: "/", + } + + meta := metadata.ClientInfo{ + ServiceName: "fooService", + SigningName: "foo", + SigningRegion: "foo", + Endpoint: "localhost", + APIVersion: "2001-01-01", + JSONVersion: "1.1", + TargetPrefix: "Foo", + } + cfg := unit.Session.Config.Copy() + cfg.MaxRetries = aws.Int(5) + + req := request.New( + *cfg, + meta, + handlers, + client.DefaultRetryer{NumMaxRetries: 5}, + op, + &struct { + }{}, + &struct { + }{}, + ) + + osErr := stubConnectionResetError + req.ApplyOptions(request.WithResponseReadTimeout(time.Second)) + err := req.Send() + if err == nil { + t.Error("Expected rror 'SerializationError', but received nil") + } + if aerr, ok := err.(awserr.Error); ok && aerr.Code() != "SerializationError" { + t.Errorf("Expected 'SerializationError', but received %q", aerr.Code()) + } else if !ok { + t.Errorf("Expected 'awserr.Error', but received %v", reflect.TypeOf(err)) + } else if aerr.OrigErr().Error() != osErr.Error() { + t.Errorf("Expected %q, but received %q", osErr.Error(), aerr.OrigErr().Error()) + } + + if count != 6 { + t.Errorf("Expected '6', but received %d", count) + } +} + +type testRetryer struct { + shouldRetry bool +} + +func (d *testRetryer) MaxRetries() int { + return 3 +} + +// RetryRules returns the delay duration before retrying this request again +func (d *testRetryer) RetryRules(r *request.Request) time.Duration { + return time.Duration(time.Millisecond) +} + +func (d *testRetryer) ShouldRetry(r *request.Request) bool { + d.shouldRetry = true + if r.Retryable != nil { + return *r.Retryable + } + + if r.HTTPResponse.StatusCode >= 500 { + return true + } + return r.IsErrorRetryable() +} + +func TestEnforceShouldRetryCheck(t *testing.T) { + tp := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + ResponseHeaderTimeout: 1 * time.Millisecond, + } + + client := &http.Client{Transport: tp} + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // This server should wait forever. Requests will timeout and the SDK should + // attempt to retry. + select {} + })) + + retryer := &testRetryer{} + s := awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + MaxRetries: aws.Int(0), + Endpoint: aws.String(server.URL), + DisableSSL: aws.Bool(true), + Retryer: retryer, + HTTPClient: client, + EnforceShouldRetryCheck: aws.Bool(true), + }) + + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err == nil { + t.Fatalf("expect error, but got nil") + } + if e, a := 3, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } + if !retryer.shouldRetry { + t.Errorf("expect 'true' for ShouldRetry, but got %v", retryer.shouldRetry) + } +} + +type errReader struct { + err error +} + +func (reader *errReader) Read(b []byte) (int, error) { + return 0, reader.err +} + +func (reader *errReader) Close() error { + return nil +} + +func TestIsNoBodyReader(t *testing.T) { + cases := []struct { + reader io.ReadCloser + expect bool + }{ + {ioutil.NopCloser(bytes.NewReader([]byte("abc"))), false}, + {ioutil.NopCloser(bytes.NewReader(nil)), false}, + {nil, false}, + {request.NoBody, true}, + } + + for i, c := range cases { + if e, a := c.expect, request.NoBody == c.reader; e != a { + t.Errorf("%d, expect %t match, but was %t", i, e, a) + } + } +} + +func TestRequest_TemporaryRetry(t *testing.T) { + done := make(chan struct{}) + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Length", "1024") + w.WriteHeader(http.StatusOK) + + w.Write(make([]byte, 100)) + + f := w.(http.Flusher) + f.Flush() + + <-done + })) + + client := &http.Client{ + Timeout: 100 * time.Millisecond, + } + + svc := awstesting.NewClient(&aws.Config{ + Region: unit.Session.Config.Region, + MaxRetries: aws.Int(1), + HTTPClient: client, + DisableSSL: aws.Bool(true), + Endpoint: aws.String(server.URL), + }) + + req := svc.NewRequest(&request.Operation{ + Name: "name", HTTPMethod: "GET", HTTPPath: "/path", + }, &struct{}{}, &struct{}{}) + + req.Handlers.Unmarshal.PushBack(func(r *request.Request) { + defer req.HTTPResponse.Body.Close() + _, err := io.Copy(ioutil.Discard, req.HTTPResponse.Body) + r.Error = awserr.New(request.ErrCodeSerialization, "error", err) + }) + + err := req.Send() + if err == nil { + t.Errorf("expect error, got none") + } + close(done) + + aerr := err.(awserr.Error) + if e, a := request.ErrCodeSerialization, aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + + if e, a := 1, req.RetryCount; e != a { + t.Errorf("expect %d retries, got %d", e, a) + } + + type temporary interface { + Temporary() bool + } + + terr := aerr.OrigErr().(temporary) + if !terr.Temporary() { + t.Errorf("expect temporary error, was not") + } +} + +func TestRequest_Presign(t *testing.T) { + presign := func(r *request.Request, expire time.Duration) (string, http.Header, error) { + u, err := r.Presign(expire) + return u, nil, err + } + presignRequest := func(r *request.Request, expire time.Duration) (string, http.Header, error) { + return r.PresignRequest(expire) + } + mustParseURL := func(v string) *url.URL { + u, err := url.Parse(v) + if err != nil { + panic(err) + } + return u + } + + cases := []struct { + Expire time.Duration + PresignFn func(*request.Request, time.Duration) (string, http.Header, error) + SignerFn func(*request.Request) + URL string + Header http.Header + Err string + }{ + { + PresignFn: presign, + Err: request.ErrCodeInvalidPresignExpire, + }, + { + PresignFn: presignRequest, + Err: request.ErrCodeInvalidPresignExpire, + }, + { + Expire: -1, + PresignFn: presign, + Err: request.ErrCodeInvalidPresignExpire, + }, + { + // Presign clear NotHoist + Expire: 1 * time.Minute, + PresignFn: func(r *request.Request, dur time.Duration) (string, http.Header, error) { + r.NotHoist = true + return presign(r, dur) + }, + SignerFn: func(r *request.Request) { + r.HTTPRequest.URL = mustParseURL("https://endpoint/presignedURL") + if r.NotHoist { + r.Error = fmt.Errorf("expect NotHoist to be cleared") + } + }, + URL: "https://endpoint/presignedURL", + }, + { + // PresignRequest does not clear NotHoist + Expire: 1 * time.Minute, + PresignFn: func(r *request.Request, dur time.Duration) (string, http.Header, error) { + r.NotHoist = true + return presignRequest(r, dur) + }, + SignerFn: func(r *request.Request) { + r.HTTPRequest.URL = mustParseURL("https://endpoint/presignedURL") + if !r.NotHoist { + r.Error = fmt.Errorf("expect NotHoist not to be cleared") + } + }, + URL: "https://endpoint/presignedURL", + }, + { + // PresignRequest returns signed headers + Expire: 1 * time.Minute, + PresignFn: presignRequest, + SignerFn: func(r *request.Request) { + r.HTTPRequest.URL = mustParseURL("https://endpoint/presignedURL") + r.HTTPRequest.Header.Set("UnsigndHeader", "abc") + r.SignedHeaderVals = http.Header{ + "X-Amzn-Header": []string{"abc", "123"}, + "X-Amzn-Header2": []string{"efg", "456"}, + } + }, + URL: "https://endpoint/presignedURL", + Header: http.Header{ + "X-Amzn-Header": []string{"abc", "123"}, + "X-Amzn-Header2": []string{"efg", "456"}, + }, + }, + } + + svc := awstesting.NewClient() + svc.Handlers.Clear() + for i, c := range cases { + req := svc.NewRequest(&request.Operation{ + Name: "name", HTTPMethod: "GET", HTTPPath: "/path", + }, &struct{}{}, &struct{}{}) + req.Handlers.Sign.PushBack(c.SignerFn) + + u, h, err := c.PresignFn(req, c.Expire) + if len(c.Err) != 0 { + if e, a := c.Err, err.Error(); !strings.Contains(a, e) { + t.Errorf("%d, expect %v to be in %v", i, e, a) + } + continue + } else if err != nil { + t.Errorf("%d, expect no error, got %v", i, err) + continue + } + if e, a := c.URL, u; e != a { + t.Errorf("%d, expect %v URL, got %v", i, e, a) + } + if e, a := c.Header, h; !reflect.DeepEqual(e, a) { + t.Errorf("%d, expect %v header got %v", i, e, a) + } + } +} + +func TestNew_EndpointWithDefaultPort(t *testing.T) { + endpoint := "https://estest.us-east-1.es.amazonaws.com:443" + expectedRequestHost := "estest.us-east-1.es.amazonaws.com" + + r := request.New( + aws.Config{}, + metadata.ClientInfo{Endpoint: endpoint}, + defaults.Handlers(), + client.DefaultRetryer{}, + &request.Operation{}, + nil, + nil, + ) + + if h := r.HTTPRequest.Host; h != expectedRequestHost { + t.Errorf("expect %v host, got %q", expectedRequestHost, h) + } +} + +func TestSanitizeHostForHeader(t *testing.T) { + cases := []struct { + url string + expectedRequestHost string + }{ + {"https://estest.us-east-1.es.amazonaws.com:443", "estest.us-east-1.es.amazonaws.com"}, + {"https://estest.us-east-1.es.amazonaws.com", "estest.us-east-1.es.amazonaws.com"}, + {"https://localhost:9200", "localhost:9200"}, + {"http://localhost:80", "localhost"}, + {"http://localhost:8080", "localhost:8080"}, + } + + for _, c := range cases { + r, _ := http.NewRequest("GET", c.url, nil) + request.SanitizeHostForHeader(r) + + if h := r.Host; h != c.expectedRequestHost { + t.Errorf("expect %v host, got %q", c.expectedRequestHost, h) + } + } +} + +func TestRequestWillRetry_ByBody(t *testing.T) { + svc := awstesting.NewClient() + + cases := []struct { + WillRetry bool + HTTPMethod string + Body io.ReadSeeker + IsReqNoBody bool + }{ + { + WillRetry: true, + HTTPMethod: "GET", + Body: bytes.NewReader([]byte{}), + IsReqNoBody: true, + }, + { + WillRetry: true, + HTTPMethod: "GET", + Body: bytes.NewReader(nil), + IsReqNoBody: true, + }, + { + WillRetry: true, + HTTPMethod: "POST", + Body: bytes.NewReader([]byte("abc123")), + }, + { + WillRetry: true, + HTTPMethod: "POST", + Body: aws.ReadSeekCloser(bytes.NewReader([]byte("abc123"))), + }, + { + WillRetry: true, + HTTPMethod: "GET", + Body: aws.ReadSeekCloser(bytes.NewBuffer(nil)), + IsReqNoBody: true, + }, + { + WillRetry: true, + HTTPMethod: "POST", + Body: aws.ReadSeekCloser(bytes.NewBuffer(nil)), + IsReqNoBody: true, + }, + { + WillRetry: false, + HTTPMethod: "POST", + Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("abc123"))), + }, + } + + for i, c := range cases { + req := svc.NewRequest(&request.Operation{ + Name: "Operation", + HTTPMethod: c.HTTPMethod, + HTTPPath: "/", + }, nil, nil) + req.SetReaderBody(c.Body) + req.Build() + + req.Error = fmt.Errorf("some error") + req.Retryable = aws.Bool(true) + req.HTTPResponse = &http.Response{ + StatusCode: 500, + } + + if e, a := c.IsReqNoBody, request.NoBody == req.HTTPRequest.Body; e != a { + t.Errorf("%d, expect request to be no body, %t, got %t, %T", i, e, a, req.HTTPRequest.Body) + } + + if e, a := c.WillRetry, req.WillRetry(); e != a { + t.Errorf("%d, expect %t willRetry, got %t", i, e, a) + } + + if req.Error == nil { + t.Fatalf("%d, expect error, got none", i) + } + if e, a := "some error", req.Error.Error(); !strings.Contains(a, e) { + t.Errorf("%d, expect %q error in %q", i, e, a) + } + if e, a := 0, req.RetryCount; e != a { + t.Errorf("%d, expect retry count to be %d, got %d", i, e, a) + } + } +} + +func Test501NotRetrying(t *testing.T) { + reqNum := 0 + reqs := []http.Response{ + {StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)}, + {StatusCode: 501, Body: body(`{"__type":"NotImplemented","message":"An error occurred."}`)}, + {StatusCode: 200, Body: body(`{"data":"valid"}`)}, + } + + s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10)) + s.Handlers.Validate.Clear() + s.Handlers.Unmarshal.PushBack(unmarshal) + s.Handlers.UnmarshalError.PushBack(unmarshalError) + s.Handlers.Send.Clear() // mock sending + s.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &reqs[reqNum] + reqNum++ + }) + out := &testData{} + r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out) + err := r.Send() + if err == nil { + t.Fatal("expect error, but got none") + } + + aerr := err.(awserr.Error) + if e, a := "NotImplemented", aerr.Code(); e != a { + t.Errorf("expected error code %q, but received %q", e, a) + } + if e, a := 1, int(r.RetryCount); e != a { + t.Errorf("expect %d retry count, got %d", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/retryer_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/retryer_test.go new file mode 100644 index 000000000..a8787487e --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/retryer_test.go @@ -0,0 +1,62 @@ +package request + +import ( + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws/awserr" +) + +func TestRequestThrottling(t *testing.T) { + req := Request{} + + req.Error = awserr.New("Throttling", "", nil) + if e, a := true, req.IsErrorThrottle(); e != a { + t.Errorf("expect %t to be throttled, was %t", e, a) + } +} + +type mockTempError bool + +func (e mockTempError) Error() string { + return fmt.Sprintf("mock temporary error: %t", e.Temporary()) +} +func (e mockTempError) Temporary() bool { + return bool(e) +} + +func TestIsErrorRetryable(t *testing.T) { + cases := []struct { + Err error + IsTemp bool + }{ + { + Err: awserr.New(ErrCodeSerialization, "temporary error", mockTempError(true)), + IsTemp: true, + }, + { + Err: awserr.New(ErrCodeSerialization, "temporary error", mockTempError(false)), + IsTemp: false, + }, + { + Err: awserr.New(ErrCodeSerialization, "some error", errors.New("blah")), + IsTemp: false, + }, + { + Err: awserr.New("SomeError", "some error", nil), + IsTemp: false, + }, + { + Err: awserr.New("RequestError", "some error", nil), + IsTemp: true, + }, + } + + for i, c := range cases { + retryable := IsErrorRetryable(c.Err) + if e, a := c.IsTemp, retryable; e != a { + t.Errorf("%d, expect %t temporary error, got %t", i, e, a) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_benchmark_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_benchmark_test.go new file mode 100644 index 000000000..33e1b2d18 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_benchmark_test.go @@ -0,0 +1,76 @@ +package request_test + +import ( + "bytes" + "io/ioutil" + "net/http" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" +) + +func BenchmarkTimeoutReadCloser(b *testing.B) { + resp := ` + { + "Bar": "qux" + } + ` + + handlers := request.Handlers{} + + handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &http.Response{ + StatusCode: http.StatusOK, + Body: ioutil.NopCloser(bytes.NewBuffer([]byte(resp))), + } + }) + handlers.Sign.PushBackNamed(v4.SignRequestHandler) + handlers.Build.PushBackNamed(jsonrpc.BuildHandler) + handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler) + handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler) + handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler) + + op := &request.Operation{ + Name: "op", + HTTPMethod: "POST", + HTTPPath: "/", + } + + meta := metadata.ClientInfo{ + ServiceName: "fooService", + SigningName: "foo", + SigningRegion: "foo", + Endpoint: "localhost", + APIVersion: "2001-01-01", + JSONVersion: "1.1", + TargetPrefix: "Foo", + } + + req := request.New( + *unit.Session.Config, + meta, + handlers, + client.DefaultRetryer{NumMaxRetries: 5}, + op, + &struct { + Foo *string + }{}, + &struct { + Bar *string + }{}, + ) + + req.ApplyOptions(request.WithResponseReadTimeout(15 * time.Second)) + for i := 0; i < b.N; i++ { + err := req.Send() + if err != nil { + b.Errorf("Expected no error, but received %v", err) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_test.go new file mode 100644 index 000000000..c814158da --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/timeout_read_closer_test.go @@ -0,0 +1,118 @@ +package request + +import ( + "bytes" + "io" + "io/ioutil" + "net/http" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/awserr" +) + +type testReader struct { + duration time.Duration + count int +} + +func (r *testReader) Read(b []byte) (int, error) { + if r.count > 0 { + r.count-- + return len(b), nil + } + time.Sleep(r.duration) + return 0, io.EOF +} + +func (r *testReader) Close() error { + return nil +} + +func TestTimeoutReadCloser(t *testing.T) { + reader := timeoutReadCloser{ + reader: &testReader{ + duration: time.Second, + count: 5, + }, + duration: time.Millisecond, + } + b := make([]byte, 100) + _, err := reader.Read(b) + if err != nil { + t.Log(err) + } +} + +func TestTimeoutReadCloserSameDuration(t *testing.T) { + reader := timeoutReadCloser{ + reader: &testReader{ + duration: time.Millisecond, + count: 5, + }, + duration: time.Millisecond, + } + b := make([]byte, 100) + _, err := reader.Read(b) + if err != nil { + t.Log(err) + } +} + +func TestWithResponseReadTimeout(t *testing.T) { + r := Request{ + HTTPResponse: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader(nil)), + }, + } + r.ApplyOptions(WithResponseReadTimeout(time.Second)) + err := r.Send() + if err != nil { + t.Error(err) + } + v, ok := r.HTTPResponse.Body.(*timeoutReadCloser) + if !ok { + t.Error("Expected the body to be a timeoutReadCloser") + } + if v.duration != time.Second { + t.Errorf("Expected %v, but receive %v\n", time.Second, v.duration) + } +} + +func TestAdaptToResponseTimeout(t *testing.T) { + testCases := []struct { + childErr error + r Request + expectedRootCode string + }{ + { + childErr: awserr.New(ErrCodeResponseTimeout, "timeout!", nil), + r: Request{ + Error: awserr.New("ErrTest", "FooBar", awserr.New(ErrCodeResponseTimeout, "timeout!", nil)), + }, + expectedRootCode: ErrCodeResponseTimeout, + }, + { + childErr: awserr.New(ErrCodeResponseTimeout+"1", "timeout!", nil), + r: Request{ + Error: awserr.New("ErrTest", "FooBar", awserr.New(ErrCodeResponseTimeout+"1", "timeout!", nil)), + }, + expectedRootCode: "ErrTest", + }, + { + r: Request{ + Error: awserr.New("ErrTest", "FooBar", nil), + }, + expectedRootCode: "ErrTest", + }, + } + + for i, c := range testCases { + adaptToResponseTimeoutError(&c.r) + if aerr, ok := c.r.Error.(awserr.Error); !ok { + t.Errorf("Case %d: Expected 'awserr', but received %v", i+1, c.r.Error) + } else if aerr.Code() != c.expectedRootCode { + t.Errorf("Case %d: Expected %q, but received %s", i+1, c.expectedRootCode, aerr.Code()) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/request/waiter_test.go b/vendor/github.com/aws/aws-sdk-go/aws/request/waiter_test.go new file mode 100644 index 000000000..db0f92df1 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/request/waiter_test.go @@ -0,0 +1,654 @@ +package request_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/s3" +) + +type mockClient struct { + *client.Client +} +type MockInput struct{} +type MockOutput struct { + States []*MockState +} +type MockState struct { + State *string +} + +func (c *mockClient) MockRequest(input *MockInput) (*request.Request, *MockOutput) { + op := &request.Operation{ + Name: "Mock", + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &MockInput{} + } + + output := &MockOutput{} + req := c.NewRequest(op, input, output) + req.Data = output + return req, output +} + +func BuildNewMockRequest(c *mockClient, in *MockInput) func([]request.Option) (*request.Request, error) { + return func(opts []request.Option) (*request.Request, error) { + req, _ := c.MockRequest(in) + req.ApplyOptions(opts...) + return req, nil + } +} + +func TestWaiterPathAll(t *testing.T) { + svc := &mockClient{Client: awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + })} + svc.Handlers.Send.Clear() // mock sending + svc.Handlers.Unmarshal.Clear() + svc.Handlers.UnmarshalMeta.Clear() + svc.Handlers.ValidateResponse.Clear() + + reqNum := 0 + resps := []*MockOutput{ + { // Request 1 + States: []*MockState{ + {State: aws.String("pending")}, + {State: aws.String("pending")}, + }, + }, + { // Request 2 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("pending")}, + }, + }, + { // Request 3 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("running")}, + }, + }, + } + + numBuiltReq := 0 + svc.Handlers.Build.PushBack(func(r *request.Request) { + numBuiltReq++ + }) + svc.Handlers.Unmarshal.PushBack(func(r *request.Request) { + if reqNum >= len(resps) { + assert.Fail(t, "too many polling requests made") + return + } + r.Data = resps[reqNum] + reqNum++ + }) + + w := request.Waiter{ + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(0), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.PathAllWaiterMatch, + Argument: "States[].State", + Expected: "running", + }, + }, + NewRequest: BuildNewMockRequest(svc, &MockInput{}), + } + + err := w.WaitWithContext(aws.BackgroundContext()) + assert.NoError(t, err) + assert.Equal(t, 3, numBuiltReq) + assert.Equal(t, 3, reqNum) +} + +func TestWaiterPath(t *testing.T) { + svc := &mockClient{Client: awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + })} + svc.Handlers.Send.Clear() // mock sending + svc.Handlers.Unmarshal.Clear() + svc.Handlers.UnmarshalMeta.Clear() + svc.Handlers.ValidateResponse.Clear() + + reqNum := 0 + resps := []*MockOutput{ + { // Request 1 + States: []*MockState{ + {State: aws.String("pending")}, + {State: aws.String("pending")}, + }, + }, + { // Request 2 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("pending")}, + }, + }, + { // Request 3 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("running")}, + }, + }, + } + + numBuiltReq := 0 + svc.Handlers.Build.PushBack(func(r *request.Request) { + numBuiltReq++ + }) + svc.Handlers.Unmarshal.PushBack(func(r *request.Request) { + if reqNum >= len(resps) { + assert.Fail(t, "too many polling requests made") + return + } + r.Data = resps[reqNum] + reqNum++ + }) + + w := request.Waiter{ + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(0), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.PathWaiterMatch, + Argument: "States[].State", + Expected: "running", + }, + }, + NewRequest: BuildNewMockRequest(svc, &MockInput{}), + } + + err := w.WaitWithContext(aws.BackgroundContext()) + assert.NoError(t, err) + assert.Equal(t, 3, numBuiltReq) + assert.Equal(t, 3, reqNum) +} + +func TestWaiterFailure(t *testing.T) { + svc := &mockClient{Client: awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + })} + svc.Handlers.Send.Clear() // mock sending + svc.Handlers.Unmarshal.Clear() + svc.Handlers.UnmarshalMeta.Clear() + svc.Handlers.ValidateResponse.Clear() + + reqNum := 0 + resps := []*MockOutput{ + { // Request 1 + States: []*MockState{ + {State: aws.String("pending")}, + {State: aws.String("pending")}, + }, + }, + { // Request 2 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("pending")}, + }, + }, + { // Request 3 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("stopping")}, + }, + }, + } + + numBuiltReq := 0 + svc.Handlers.Build.PushBack(func(r *request.Request) { + numBuiltReq++ + }) + svc.Handlers.Unmarshal.PushBack(func(r *request.Request) { + if reqNum >= len(resps) { + assert.Fail(t, "too many polling requests made") + return + } + r.Data = resps[reqNum] + reqNum++ + }) + + w := request.Waiter{ + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(0), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.PathAllWaiterMatch, + Argument: "States[].State", + Expected: "running", + }, + { + State: request.FailureWaiterState, + Matcher: request.PathAnyWaiterMatch, + Argument: "States[].State", + Expected: "stopping", + }, + }, + NewRequest: BuildNewMockRequest(svc, &MockInput{}), + } + + err := w.WaitWithContext(aws.BackgroundContext()).(awserr.Error) + assert.Error(t, err) + assert.Equal(t, request.WaiterResourceNotReadyErrorCode, err.Code()) + assert.Equal(t, "failed waiting for successful resource state", err.Message()) + assert.Equal(t, 3, numBuiltReq) + assert.Equal(t, 3, reqNum) +} + +func TestWaiterError(t *testing.T) { + svc := &mockClient{Client: awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + })} + svc.Handlers.Send.Clear() // mock sending + svc.Handlers.Unmarshal.Clear() + svc.Handlers.UnmarshalMeta.Clear() + svc.Handlers.UnmarshalError.Clear() + svc.Handlers.ValidateResponse.Clear() + + reqNum := 0 + resps := []*MockOutput{ + { // Request 1 + States: []*MockState{ + {State: aws.String("pending")}, + {State: aws.String("pending")}, + }, + }, + { // Request 1, error case retry + }, + { // Request 2, error case failure + }, + { // Request 3 + States: []*MockState{ + {State: aws.String("running")}, + {State: aws.String("running")}, + }, + }, + } + reqErrs := make([]error, len(resps)) + reqErrs[1] = awserr.New("MockException", "mock exception message", nil) + reqErrs[2] = awserr.New("FailureException", "mock failure exception message", nil) + + numBuiltReq := 0 + svc.Handlers.Build.PushBack(func(r *request.Request) { + numBuiltReq++ + }) + svc.Handlers.Send.PushBack(func(r *request.Request) { + code := 200 + if reqNum == 1 { + code = 400 + } + r.HTTPResponse = &http.Response{ + StatusCode: code, + Status: http.StatusText(code), + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + } + }) + svc.Handlers.Unmarshal.PushBack(func(r *request.Request) { + if reqNum >= len(resps) { + assert.Fail(t, "too many polling requests made") + return + } + r.Data = resps[reqNum] + reqNum++ + }) + svc.Handlers.UnmarshalMeta.PushBack(func(r *request.Request) { + // If there was an error unmarshal error will be called instead of unmarshal + // need to increment count here also + if err := reqErrs[reqNum]; err != nil { + r.Error = err + reqNum++ + } + }) + + w := request.Waiter{ + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(0), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.PathAllWaiterMatch, + Argument: "States[].State", + Expected: "running", + }, + { + State: request.RetryWaiterState, + Matcher: request.ErrorWaiterMatch, + Argument: "", + Expected: "MockException", + }, + { + State: request.FailureWaiterState, + Matcher: request.ErrorWaiterMatch, + Argument: "", + Expected: "FailureException", + }, + }, + NewRequest: BuildNewMockRequest(svc, &MockInput{}), + } + + err := w.WaitWithContext(aws.BackgroundContext()) + if err == nil { + t.Fatalf("expected error, but did not get one") + } + aerr := err.(awserr.Error) + if e, a := request.WaiterResourceNotReadyErrorCode, aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + if e, a := 3, numBuiltReq; e != a { + t.Errorf("expect %d built requests got %d", e, a) + } + if e, a := 3, reqNum; e != a { + t.Errorf("expect %d reqNum got %d", e, a) + } +} + +func TestWaiterStatus(t *testing.T) { + svc := &mockClient{Client: awstesting.NewClient(&aws.Config{ + Region: aws.String("mock-region"), + })} + svc.Handlers.Send.Clear() // mock sending + svc.Handlers.Unmarshal.Clear() + svc.Handlers.UnmarshalMeta.Clear() + svc.Handlers.ValidateResponse.Clear() + + reqNum := 0 + svc.Handlers.Build.PushBack(func(r *request.Request) { + reqNum++ + }) + svc.Handlers.Send.PushBack(func(r *request.Request) { + code := 200 + if reqNum == 3 { + code = 404 + r.Error = awserr.New("NotFound", "Not Found", nil) + } + r.HTTPResponse = &http.Response{ + StatusCode: code, + Status: http.StatusText(code), + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + } + }) + + w := request.Waiter{ + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(0), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.StatusWaiterMatch, + Argument: "", + Expected: 404, + }, + }, + NewRequest: BuildNewMockRequest(svc, &MockInput{}), + } + + err := w.WaitWithContext(aws.BackgroundContext()) + assert.NoError(t, err) + assert.Equal(t, 3, reqNum) +} + +func TestWaiter_ApplyOptions(t *testing.T) { + w := request.Waiter{} + + logger := aws.NewDefaultLogger() + + w.ApplyOptions( + request.WithWaiterLogger(logger), + request.WithWaiterRequestOptions(request.WithLogLevel(aws.LogDebug)), + request.WithWaiterMaxAttempts(2), + request.WithWaiterDelay(request.ConstantWaiterDelay(5*time.Second)), + ) + + if e, a := logger, w.Logger; e != a { + t.Errorf("expect logger to be set, and match, was not, %v, %v", e, a) + } + + if len(w.RequestOptions) != 1 { + t.Fatalf("expect request options to be set to only a single option, %v", w.RequestOptions) + } + r := request.Request{} + r.ApplyOptions(w.RequestOptions...) + if e, a := aws.LogDebug, r.Config.LogLevel.Value(); e != a { + t.Errorf("expect %v loglevel got %v", e, a) + } + + if e, a := 2, w.MaxAttempts; e != a { + t.Errorf("expect %d retryer max attempts, got %d", e, a) + } + if e, a := 5*time.Second, w.Delay(0); e != a { + t.Errorf("expect %d retryer delay, got %d", e, a) + } +} + +func TestWaiter_WithContextCanceled(t *testing.T) { + c := awstesting.NewClient() + + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + reqCount := 0 + + w := request.Waiter{ + Name: "TestWaiter", + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(1 * time.Millisecond), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.StatusWaiterMatch, + Expected: 200, + }, + }, + Logger: aws.NewDefaultLogger(), + NewRequest: func(opts []request.Option) (*request.Request, error) { + req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + req.HTTPResponse = &http.Response{StatusCode: http.StatusNotFound} + req.Handlers.Clear() + req.Data = struct{}{} + req.Handlers.Send.PushBack(func(r *request.Request) { + if reqCount == 1 { + ctx.Error = fmt.Errorf("context canceled") + close(ctx.DoneCh) + } + reqCount++ + }) + + return req, nil + }, + } + + w.SleepWithContext = func(c aws.Context, delay time.Duration) error { + context := c.(*awstesting.FakeContext) + select { + case <-context.DoneCh: + return context.Err() + default: + return nil + } + } + + err := w.WaitWithContext(ctx) + + if err == nil { + t.Fatalf("expect waiter to be canceled.") + } + aerr := err.(awserr.Error) + if e, a := request.CanceledErrorCode, aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + if e, a := 2, reqCount; e != a { + t.Errorf("expect %d requests, got %d", e, a) + } +} + +func TestWaiter_WithContext(t *testing.T) { + c := awstesting.NewClient() + + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + reqCount := 0 + + statuses := []int{http.StatusNotFound, http.StatusOK} + + w := request.Waiter{ + Name: "TestWaiter", + MaxAttempts: 10, + Delay: request.ConstantWaiterDelay(1 * time.Millisecond), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.StatusWaiterMatch, + Expected: 200, + }, + }, + Logger: aws.NewDefaultLogger(), + NewRequest: func(opts []request.Option) (*request.Request, error) { + req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + req.HTTPResponse = &http.Response{StatusCode: statuses[reqCount]} + req.Handlers.Clear() + req.Data = struct{}{} + req.Handlers.Send.PushBack(func(r *request.Request) { + if reqCount == 1 { + ctx.Error = fmt.Errorf("context canceled") + close(ctx.DoneCh) + } + reqCount++ + }) + + return req, nil + }, + } + + err := w.WaitWithContext(ctx) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := 2, reqCount; e != a { + t.Errorf("expect %d requests, got %d", e, a) + } +} + +func TestWaiter_AttemptsExpires(t *testing.T) { + c := awstesting.NewClient() + + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + reqCount := 0 + + w := request.Waiter{ + Name: "TestWaiter", + MaxAttempts: 2, + Delay: request.ConstantWaiterDelay(1 * time.Millisecond), + SleepWithContext: aws.SleepWithContext, + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.StatusWaiterMatch, + Expected: 200, + }, + }, + Logger: aws.NewDefaultLogger(), + NewRequest: func(opts []request.Option) (*request.Request, error) { + req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil) + req.HTTPResponse = &http.Response{StatusCode: http.StatusNotFound} + req.Handlers.Clear() + req.Data = struct{}{} + req.Handlers.Send.PushBack(func(r *request.Request) { + reqCount++ + }) + + return req, nil + }, + } + + err := w.WaitWithContext(ctx) + + if err == nil { + t.Fatalf("expect error did not get one") + } + aerr := err.(awserr.Error) + if e, a := request.WaiterResourceNotReadyErrorCode, aerr.Code(); e != a { + t.Errorf("expect %q error code, got %q", e, a) + } + if e, a := 2, reqCount; e != a { + t.Errorf("expect %d requests, got %d", e, a) + } +} + +func TestWaiterNilInput(t *testing.T) { + // Code generation doesn't have a great way to verify the code is correct + // other than being run via unit tests in the SDK. This should be fixed + // So code generation can be validated independently. + + client := s3.New(unit.Session) + client.Handlers.Validate.Clear() + client.Handlers.Send.Clear() // mock sending + client.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &http.Response{ + StatusCode: http.StatusOK, + } + }) + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + client.Config.SleepDelay = func(dur time.Duration) {} + + // Ensure waiters do not panic on nil input. It doesn't make sense to + // call a waiter without an input, Validation will + err := client.WaitUntilBucketExists(nil) + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } +} + +func TestWaiterWithContextNilInput(t *testing.T) { + // Code generation doesn't have a great way to verify the code is correct + // other than being run via unit tests in the SDK. This should be fixed + // So code generation can be validated independently. + + client := s3.New(unit.Session) + client.Handlers.Validate.Clear() + client.Handlers.Send.Clear() // mock sending + client.Handlers.Send.PushBack(func(r *request.Request) { + r.HTTPResponse = &http.Response{ + StatusCode: http.StatusOK, + } + }) + client.Handlers.Unmarshal.Clear() + client.Handlers.UnmarshalMeta.Clear() + client.Handlers.ValidateResponse.Clear() + + // Ensure waiters do not panic on nil input + ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})} + err := client.WaitUntilBucketExistsWithContext(ctx, nil, + request.WithWaiterDelay(request.ConstantWaiterDelay(0)), + request.WithWaiterMaxAttempts(1), + ) + if err != nil { + t.Fatalf("expect no error, but got %v", err) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/custom_ca_bundle_test.go b/vendor/github.com/aws/aws-sdk-go/aws/session/custom_ca_bundle_test.go new file mode 100644 index 000000000..a89c0af59 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/session/custom_ca_bundle_test.go @@ -0,0 +1,243 @@ +package session + +import ( + "bytes" + "fmt" + "net" + "net/http" + "os" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/awstesting" +) + +var TLSBundleCertFile string +var TLSBundleKeyFile string +var TLSBundleCAFile string + +func TestMain(m *testing.M) { + var err error + + TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile, err = awstesting.CreateTLSBundleFiles() + if err != nil { + panic(err) + } + + fmt.Println("TestMain", TLSBundleCertFile, TLSBundleKeyFile) + + code := m.Run() + + err = awstesting.CleanupTLSBundleFiles(TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile) + if err != nil { + panic(err) + } + + os.Exit(code) +} + +func TestNewSession_WithCustomCABundle_Env(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + os.Setenv("AWS_CA_BUNDLE", TLSBundleCAFile) + + s, err := NewSession(&aws.Config{ + HTTPClient: &http.Client{}, + Endpoint: aws.String(endpoint), + Region: aws.String("mock-region"), + Credentials: credentials.AnonymousCredentials, + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if s == nil { + t.Fatalf("expect session to be created, got none") + } + + req, _ := http.NewRequest("GET", *s.Config.Endpoint, nil) + resp, err := s.Config.HTTPClient.Do(req) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := http.StatusOK, resp.StatusCode; e != a { + t.Errorf("expect %d status code, got %d", e, a) + } +} + +func TestNewSession_WithCustomCABundle_EnvNotExists(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_CA_BUNDLE", "file-not-exists") + + s, err := NewSession() + if err == nil { + t.Fatalf("expect error, got none") + } + if e, a := "LoadCustomCABundleError", err.(awserr.Error).Code(); e != a { + t.Errorf("expect %s error code, got %s", e, a) + } + if s != nil { + t.Errorf("expect nil session, got %v", s) + } +} + +func TestNewSession_WithCustomCABundle_Option(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + s, err := NewSessionWithOptions(Options{ + Config: aws.Config{ + HTTPClient: &http.Client{}, + Endpoint: aws.String(endpoint), + Region: aws.String("mock-region"), + Credentials: credentials.AnonymousCredentials, + }, + CustomCABundle: bytes.NewReader(awstesting.TLSBundleCA), + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if s == nil { + t.Fatalf("expect session to be created, got none") + } + + req, _ := http.NewRequest("GET", *s.Config.Endpoint, nil) + resp, err := s.Config.HTTPClient.Do(req) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := http.StatusOK, resp.StatusCode; e != a { + t.Errorf("expect %d status code, got %d", e, a) + } +} + +func TestNewSession_WithCustomCABundle_OptionPriority(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + os.Setenv("AWS_CA_BUNDLE", "file-not-exists") + + s, err := NewSessionWithOptions(Options{ + Config: aws.Config{ + HTTPClient: &http.Client{}, + Endpoint: aws.String(endpoint), + Region: aws.String("mock-region"), + Credentials: credentials.AnonymousCredentials, + }, + CustomCABundle: bytes.NewReader(awstesting.TLSBundleCA), + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if s == nil { + t.Fatalf("expect session to be created, got none") + } + + req, _ := http.NewRequest("GET", *s.Config.Endpoint, nil) + resp, err := s.Config.HTTPClient.Do(req) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := http.StatusOK, resp.StatusCode; e != a { + t.Errorf("expect %d status code, got %d", e, a) + } +} + +type mockRoundTripper struct{} + +func (m *mockRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + return nil, nil +} + +func TestNewSession_WithCustomCABundle_UnsupportedTransport(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + s, err := NewSessionWithOptions(Options{ + Config: aws.Config{ + HTTPClient: &http.Client{ + Transport: &mockRoundTripper{}, + }, + }, + CustomCABundle: bytes.NewReader(awstesting.TLSBundleCA), + }) + if err == nil { + t.Fatalf("expect error, got none") + } + if e, a := "LoadCustomCABundleError", err.(awserr.Error).Code(); e != a { + t.Errorf("expect %s error code, got %s", e, a) + } + if s != nil { + t.Errorf("expect nil session, got %v", s) + } + aerrMsg := err.(awserr.Error).Message() + if e, a := "transport unsupported type", aerrMsg; !strings.Contains(a, e) { + t.Errorf("expect %s to be in %s", e, a) + } +} + +func TestNewSession_WithCustomCABundle_TransportSet(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + s, err := NewSessionWithOptions(Options{ + Config: aws.Config{ + Endpoint: aws.String(endpoint), + Region: aws.String("mock-region"), + Credentials: credentials.AnonymousCredentials, + HTTPClient: &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).Dial, + TLSHandshakeTimeout: 2 * time.Second, + }, + }, + }, + CustomCABundle: bytes.NewReader(awstesting.TLSBundleCA), + }) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if s == nil { + t.Fatalf("expect session to be created, got none") + } + + req, _ := http.NewRequest("GET", *s.Config.Endpoint, nil) + resp, err := s.Config.HTTPClient.Do(req) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + if e, a := http.StatusOK, resp.StatusCode; e != a { + t.Errorf("expect %d status code, got %d", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/env_config_test.go b/vendor/github.com/aws/aws-sdk-go/aws/session/env_config_test.go new file mode 100644 index 000000000..3a0b6464d --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/session/env_config_test.go @@ -0,0 +1,306 @@ +package session + +import ( + "os" + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/internal/shareddefaults" +) + +func TestLoadEnvConfig_Creds(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + cases := []struct { + Env map[string]string + Val credentials.Value + }{ + { + Env: map[string]string{ + "AWS_ACCESS_KEY": "AKID", + }, + Val: credentials.Value{}, + }, + { + Env: map[string]string{ + "AWS_ACCESS_KEY_ID": "AKID", + }, + Val: credentials.Value{}, + }, + { + Env: map[string]string{ + "AWS_SECRET_KEY": "SECRET", + }, + Val: credentials.Value{}, + }, + { + Env: map[string]string{ + "AWS_SECRET_ACCESS_KEY": "SECRET", + }, + Val: credentials.Value{}, + }, + { + Env: map[string]string{ + "AWS_ACCESS_KEY_ID": "AKID", + "AWS_SECRET_ACCESS_KEY": "SECRET", + }, + Val: credentials.Value{ + AccessKeyID: "AKID", SecretAccessKey: "SECRET", + ProviderName: "EnvConfigCredentials", + }, + }, + { + Env: map[string]string{ + "AWS_ACCESS_KEY": "AKID", + "AWS_SECRET_KEY": "SECRET", + }, + Val: credentials.Value{ + AccessKeyID: "AKID", SecretAccessKey: "SECRET", + ProviderName: "EnvConfigCredentials", + }, + }, + { + Env: map[string]string{ + "AWS_ACCESS_KEY": "AKID", + "AWS_SECRET_KEY": "SECRET", + "AWS_SESSION_TOKEN": "TOKEN", + }, + Val: credentials.Value{ + AccessKeyID: "AKID", SecretAccessKey: "SECRET", SessionToken: "TOKEN", + ProviderName: "EnvConfigCredentials", + }, + }, + } + + for _, c := range cases { + os.Clearenv() + + for k, v := range c.Env { + os.Setenv(k, v) + } + + cfg := loadEnvConfig() + if !reflect.DeepEqual(c.Val, cfg.Creds) { + t.Errorf("expect credentials to match.\n%s", + awstesting.SprintExpectActual(c.Val, cfg.Creds)) + } + } +} + +func TestLoadEnvConfig(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + cases := []struct { + Env map[string]string + UseSharedConfigCall bool + Config envConfig + }{ + { + Env: map[string]string{ + "AWS_REGION": "region", + "AWS_PROFILE": "profile", + }, + Config: envConfig{ + Region: "region", Profile: "profile", + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + }, + { + Env: map[string]string{ + "AWS_REGION": "region", + "AWS_DEFAULT_REGION": "default_region", + "AWS_PROFILE": "profile", + "AWS_DEFAULT_PROFILE": "default_profile", + }, + Config: envConfig{ + Region: "region", Profile: "profile", + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + }, + { + Env: map[string]string{ + "AWS_REGION": "region", + "AWS_DEFAULT_REGION": "default_region", + "AWS_PROFILE": "profile", + "AWS_DEFAULT_PROFILE": "default_profile", + "AWS_SDK_LOAD_CONFIG": "1", + }, + Config: envConfig{ + Region: "region", Profile: "profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + }, + { + Env: map[string]string{ + "AWS_DEFAULT_REGION": "default_region", + "AWS_DEFAULT_PROFILE": "default_profile", + }, + Config: envConfig{ + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + }, + { + Env: map[string]string{ + "AWS_DEFAULT_REGION": "default_region", + "AWS_DEFAULT_PROFILE": "default_profile", + "AWS_SDK_LOAD_CONFIG": "1", + }, + Config: envConfig{ + Region: "default_region", Profile: "default_profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + }, + { + Env: map[string]string{ + "AWS_REGION": "region", + "AWS_PROFILE": "profile", + }, + Config: envConfig{ + Region: "region", Profile: "profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + UseSharedConfigCall: true, + }, + { + Env: map[string]string{ + "AWS_REGION": "region", + "AWS_DEFAULT_REGION": "default_region", + "AWS_PROFILE": "profile", + "AWS_DEFAULT_PROFILE": "default_profile", + }, + Config: envConfig{ + Region: "region", Profile: "profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + UseSharedConfigCall: true, + }, + { + Env: map[string]string{ + "AWS_REGION": "region", + "AWS_DEFAULT_REGION": "default_region", + "AWS_PROFILE": "profile", + "AWS_DEFAULT_PROFILE": "default_profile", + "AWS_SDK_LOAD_CONFIG": "1", + }, + Config: envConfig{ + Region: "region", Profile: "profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + UseSharedConfigCall: true, + }, + { + Env: map[string]string{ + "AWS_DEFAULT_REGION": "default_region", + "AWS_DEFAULT_PROFILE": "default_profile", + }, + Config: envConfig{ + Region: "default_region", Profile: "default_profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + UseSharedConfigCall: true, + }, + { + Env: map[string]string{ + "AWS_DEFAULT_REGION": "default_region", + "AWS_DEFAULT_PROFILE": "default_profile", + "AWS_SDK_LOAD_CONFIG": "1", + }, + Config: envConfig{ + Region: "default_region", Profile: "default_profile", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + UseSharedConfigCall: true, + }, + { + Env: map[string]string{ + "AWS_CA_BUNDLE": "custom_ca_bundle", + }, + Config: envConfig{ + CustomCABundle: "custom_ca_bundle", + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + }, + { + Env: map[string]string{ + "AWS_CA_BUNDLE": "custom_ca_bundle", + }, + Config: envConfig{ + CustomCABundle: "custom_ca_bundle", + EnableSharedConfig: true, + SharedCredentialsFile: shareddefaults.SharedCredentialsFilename(), + SharedConfigFile: shareddefaults.SharedConfigFilename(), + }, + UseSharedConfigCall: true, + }, + { + Env: map[string]string{ + "AWS_SHARED_CREDENTIALS_FILE": "/path/to/credentials/file", + "AWS_CONFIG_FILE": "/path/to/config/file", + }, + Config: envConfig{ + SharedCredentialsFile: "/path/to/credentials/file", + SharedConfigFile: "/path/to/config/file", + }, + }, + } + + for _, c := range cases { + os.Clearenv() + + for k, v := range c.Env { + os.Setenv(k, v) + } + + var cfg envConfig + if c.UseSharedConfigCall { + cfg = loadSharedEnvConfig() + } else { + cfg = loadEnvConfig() + } + + if !reflect.DeepEqual(c.Config, cfg) { + t.Errorf("expect config to match.\n%s", + awstesting.SprintExpectActual(c.Config, cfg)) + } + } +} + +func TestSetEnvValue(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + os.Setenv("empty_key", "") + os.Setenv("second_key", "2") + os.Setenv("third_key", "3") + + var dst string + setFromEnvVal(&dst, []string{ + "empty_key", "first_key", "second_key", "third_key", + }) + + if e, a := "2", dst; e != a { + t.Errorf("expect %s value from environment, got %s", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/session_test.go b/vendor/github.com/aws/aws-sdk-go/aws/session/session_test.go new file mode 100644 index 000000000..9612b3150 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/session/session_test.go @@ -0,0 +1,446 @@ +package session + +import ( + "bytes" + "fmt" + "net/http" + "net/http/httptest" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/defaults" + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/service/s3" +) + +func TestNewDefaultSession(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + s := New(&aws.Config{Region: aws.String("region")}) + + assert.Equal(t, "region", *s.Config.Region) + assert.Equal(t, http.DefaultClient, s.Config.HTTPClient) + assert.NotNil(t, s.Config.Logger) + assert.Equal(t, aws.LogOff, *s.Config.LogLevel) +} + +func TestNew_WithCustomCreds(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + customCreds := credentials.NewStaticCredentials("AKID", "SECRET", "TOKEN") + s := New(&aws.Config{Credentials: customCreds}) + + assert.Equal(t, customCreds, s.Config.Credentials) +} + +type mockLogger struct { + *bytes.Buffer +} + +func (w mockLogger) Log(args ...interface{}) { + fmt.Fprintln(w, args...) +} + +func TestNew_WithSessionLoadError(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_CONFIG_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "assume_role_invalid_source_profile") + + logger := bytes.Buffer{} + s := New(&aws.Config{Logger: &mockLogger{&logger}}) + + assert.NotNil(t, s) + + svc := s3.New(s) + _, err := svc.ListBuckets(&s3.ListBucketsInput{}) + + assert.Error(t, err) + assert.Contains(t, logger.String(), "ERROR: failed to create session with AWS_SDK_LOAD_CONFIG enabled") + assert.Contains(t, err.Error(), SharedConfigAssumeRoleError{ + RoleARN: "assume_role_invalid_source_profile_role_arn", + }.Error()) +} + +func TestSessionCopy(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_REGION", "orig_region") + + s := Session{ + Config: defaults.Config(), + Handlers: defaults.Handlers(), + } + + newSess := s.Copy(&aws.Config{Region: aws.String("new_region")}) + + assert.Equal(t, "orig_region", *s.Config.Region) + assert.Equal(t, "new_region", *newSess.Config.Region) +} + +func TestSessionClientConfig(t *testing.T) { + s, err := NewSession(&aws.Config{ + Credentials: credentials.AnonymousCredentials, + Region: aws.String("orig_region"), + EndpointResolver: endpoints.ResolverFunc( + func(service, region string, opts ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) { + if e, a := "mock-service", service; e != a { + t.Errorf("expect %q service, got %q", e, a) + } + if e, a := "other-region", region; e != a { + t.Errorf("expect %q region, got %q", e, a) + } + return endpoints.ResolvedEndpoint{ + URL: "https://" + service + "." + region + ".amazonaws.com", + SigningRegion: region, + }, nil + }, + ), + }) + assert.NoError(t, err) + + cfg := s.ClientConfig("mock-service", &aws.Config{Region: aws.String("other-region")}) + + assert.Equal(t, "https://mock-service.other-region.amazonaws.com", cfg.Endpoint) + assert.Equal(t, "other-region", cfg.SigningRegion) + assert.Equal(t, "other-region", *cfg.Config.Region) +} + +func TestNewSession_NoCredentials(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + s, err := NewSession() + assert.NoError(t, err) + + assert.NotNil(t, s.Config.Credentials) + assert.NotEqual(t, credentials.AnonymousCredentials, s.Config.Credentials) +} + +func TestNewSessionWithOptions_OverrideProfile(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "other_profile") + + s, err := NewSessionWithOptions(Options{ + Profile: "full_profile", + }) + assert.NoError(t, err) + + assert.Equal(t, "full_profile_region", *s.Config.Region) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, "full_profile_akid", creds.AccessKeyID) + assert.Equal(t, "full_profile_secret", creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) + assert.Contains(t, creds.ProviderName, "SharedConfigCredentials") +} + +func TestNewSessionWithOptions_OverrideSharedConfigEnable(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "0") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "full_profile") + + s, err := NewSessionWithOptions(Options{ + SharedConfigState: SharedConfigEnable, + }) + assert.NoError(t, err) + + assert.Equal(t, "full_profile_region", *s.Config.Region) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, "full_profile_akid", creds.AccessKeyID) + assert.Equal(t, "full_profile_secret", creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) + assert.Contains(t, creds.ProviderName, "SharedConfigCredentials") +} + +func TestNewSessionWithOptions_OverrideSharedConfigDisable(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "full_profile") + + s, err := NewSessionWithOptions(Options{ + SharedConfigState: SharedConfigDisable, + }) + assert.NoError(t, err) + + assert.Empty(t, *s.Config.Region) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, "full_profile_akid", creds.AccessKeyID) + assert.Equal(t, "full_profile_secret", creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) + assert.Contains(t, creds.ProviderName, "SharedConfigCredentials") +} + +func TestNewSessionWithOptions_OverrideSharedConfigFiles(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "config_file_load_order") + + s, err := NewSessionWithOptions(Options{ + SharedConfigFiles: []string{testConfigOtherFilename}, + }) + assert.NoError(t, err) + + assert.Equal(t, "shared_config_other_region", *s.Config.Region) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, "shared_config_other_akid", creds.AccessKeyID) + assert.Equal(t, "shared_config_other_secret", creds.SecretAccessKey) + assert.Empty(t, creds.SessionToken) + assert.Contains(t, creds.ProviderName, "SharedConfigCredentials") +} + +func TestNewSessionWithOptions_Overrides(t *testing.T) { + cases := []struct { + InEnvs map[string]string + InProfile string + OutRegion string + OutCreds credentials.Value + }{ + { + InEnvs: map[string]string{ + "AWS_SDK_LOAD_CONFIG": "0", + "AWS_SHARED_CREDENTIALS_FILE": testConfigFilename, + "AWS_PROFILE": "other_profile", + }, + InProfile: "full_profile", + OutRegion: "full_profile_region", + OutCreds: credentials.Value{ + AccessKeyID: "full_profile_akid", + SecretAccessKey: "full_profile_secret", + ProviderName: "SharedConfigCredentials", + }, + }, + { + InEnvs: map[string]string{ + "AWS_SDK_LOAD_CONFIG": "0", + "AWS_SHARED_CREDENTIALS_FILE": testConfigFilename, + "AWS_REGION": "env_region", + "AWS_ACCESS_KEY": "env_akid", + "AWS_SECRET_ACCESS_KEY": "env_secret", + "AWS_PROFILE": "other_profile", + }, + InProfile: "full_profile", + OutRegion: "env_region", + OutCreds: credentials.Value{ + AccessKeyID: "env_akid", + SecretAccessKey: "env_secret", + ProviderName: "EnvConfigCredentials", + }, + }, + { + InEnvs: map[string]string{ + "AWS_SDK_LOAD_CONFIG": "0", + "AWS_SHARED_CREDENTIALS_FILE": testConfigFilename, + "AWS_CONFIG_FILE": testConfigOtherFilename, + "AWS_PROFILE": "shared_profile", + }, + InProfile: "config_file_load_order", + OutRegion: "shared_config_region", + OutCreds: credentials.Value{ + AccessKeyID: "shared_config_akid", + SecretAccessKey: "shared_config_secret", + ProviderName: "SharedConfigCredentials", + }, + }, + } + + for _, c := range cases { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + for k, v := range c.InEnvs { + os.Setenv(k, v) + } + + s, err := NewSessionWithOptions(Options{ + Profile: c.InProfile, + SharedConfigState: SharedConfigEnable, + }) + assert.NoError(t, err) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, c.OutRegion, *s.Config.Region) + assert.Equal(t, c.OutCreds.AccessKeyID, creds.AccessKeyID) + assert.Equal(t, c.OutCreds.SecretAccessKey, creds.SecretAccessKey) + assert.Equal(t, c.OutCreds.SessionToken, creds.SessionToken) + assert.Contains(t, creds.ProviderName, c.OutCreds.ProviderName) + } +} + +const assumeRoleRespMsg = ` + + + + arn:aws:sts::account_id:assumed-role/role/session_name + AKID:session_name + + + AKID + SECRET + SESSION_TOKEN + %s + + + + request-id + + +` + +func TestSesisonAssumeRole(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_REGION", "us-east-1") + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "assume_role_w_creds") + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(fmt.Sprintf(assumeRoleRespMsg, time.Now().Add(15*time.Minute).Format("2006-01-02T15:04:05Z")))) + })) + + s, err := NewSession(&aws.Config{Endpoint: aws.String(server.URL), DisableSSL: aws.Bool(true)}) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, "AKID", creds.AccessKeyID) + assert.Equal(t, "SECRET", creds.SecretAccessKey) + assert.Equal(t, "SESSION_TOKEN", creds.SessionToken) + assert.Contains(t, creds.ProviderName, "AssumeRoleProvider") +} + +func TestSessionAssumeRole_WithMFA(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_REGION", "us-east-1") + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "assume_role_w_creds") + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.FormValue("SerialNumber"), "0123456789") + assert.Equal(t, r.FormValue("TokenCode"), "tokencode") + + w.Write([]byte(fmt.Sprintf(assumeRoleRespMsg, time.Now().Add(15*time.Minute).Format("2006-01-02T15:04:05Z")))) + })) + + customProviderCalled := false + sess, err := NewSessionWithOptions(Options{ + Profile: "assume_role_w_mfa", + Config: aws.Config{ + Region: aws.String("us-east-1"), + Endpoint: aws.String(server.URL), + DisableSSL: aws.Bool(true), + }, + SharedConfigState: SharedConfigEnable, + AssumeRoleTokenProvider: func() (string, error) { + customProviderCalled = true + + return "tokencode", nil + }, + }) + assert.NoError(t, err) + + creds, err := sess.Config.Credentials.Get() + assert.NoError(t, err) + assert.True(t, customProviderCalled) + + assert.Equal(t, "AKID", creds.AccessKeyID) + assert.Equal(t, "SECRET", creds.SecretAccessKey) + assert.Equal(t, "SESSION_TOKEN", creds.SessionToken) + assert.Contains(t, creds.ProviderName, "AssumeRoleProvider") +} + +func TestSessionAssumeRole_WithMFA_NoTokenProvider(t *testing.T) { + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_REGION", "us-east-1") + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "assume_role_w_creds") + + _, err := NewSessionWithOptions(Options{ + Profile: "assume_role_w_mfa", + SharedConfigState: SharedConfigEnable, + }) + assert.Equal(t, err, AssumeRoleTokenProviderNotSetError{}) +} + +func TestSessionAssumeRole_DisableSharedConfig(t *testing.T) { + // Backwards compatibility with Shared config disabled + // assume role should not be built into the config. + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "0") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "assume_role_w_creds") + + s, err := NewSession() + assert.NoError(t, err) + + creds, err := s.Config.Credentials.Get() + assert.NoError(t, err) + assert.Equal(t, "assume_role_w_creds_akid", creds.AccessKeyID) + assert.Equal(t, "assume_role_w_creds_secret", creds.SecretAccessKey) + assert.Contains(t, creds.ProviderName, "SharedConfigCredentials") +} + +func TestSessionAssumeRole_InvalidSourceProfile(t *testing.T) { + // Backwards compatibility with Shared config disabled + // assume role should not be built into the config. + oldEnv := initSessionTestEnv() + defer awstesting.PopEnv(oldEnv) + + os.Setenv("AWS_SDK_LOAD_CONFIG", "1") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename) + os.Setenv("AWS_PROFILE", "assume_role_invalid_source_profile") + + s, err := NewSession() + assert.Error(t, err) + assert.Contains(t, err.Error(), "SharedConfigAssumeRoleError: failed to load assume role") + assert.Nil(t, s) +} + +func initSessionTestEnv() (oldEnv []string) { + oldEnv = awstesting.StashEnv() + os.Setenv("AWS_CONFIG_FILE", "file_not_exists") + os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "file_not_exists") + + return oldEnv +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config_test.go b/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config_test.go new file mode 100644 index 000000000..3a07b8d97 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config_test.go @@ -0,0 +1,274 @@ +package session + +import ( + "fmt" + "path/filepath" + "testing" + + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/go-ini/ini" + "github.com/stretchr/testify/assert" +) + +var ( + testConfigFilename = filepath.Join("testdata", "shared_config") + testConfigOtherFilename = filepath.Join("testdata", "shared_config_other") +) + +func TestLoadSharedConfig(t *testing.T) { + cases := []struct { + Filenames []string + Profile string + Expected sharedConfig + Err error + }{ + { + Filenames: []string{"file_not_exists"}, + Profile: "default", + }, + { + Filenames: []string{testConfigFilename}, + Expected: sharedConfig{ + Region: "default_region", + }, + }, + { + Filenames: []string{testConfigOtherFilename, testConfigFilename}, + Profile: "config_file_load_order", + Expected: sharedConfig{ + Region: "shared_config_region", + Creds: credentials.Value{ + AccessKeyID: "shared_config_akid", + SecretAccessKey: "shared_config_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + }, + }, + { + Filenames: []string{testConfigFilename, testConfigOtherFilename}, + Profile: "config_file_load_order", + Expected: sharedConfig{ + Region: "shared_config_other_region", + Creds: credentials.Value{ + AccessKeyID: "shared_config_other_akid", + SecretAccessKey: "shared_config_other_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigOtherFilename), + }, + }, + }, + { + Filenames: []string{testConfigOtherFilename, testConfigFilename}, + Profile: "assume_role", + Expected: sharedConfig{ + AssumeRole: assumeRoleConfig{ + RoleARN: "assume_role_role_arn", + SourceProfile: "complete_creds", + }, + AssumeRoleSource: &sharedConfig{ + Creds: credentials.Value{ + AccessKeyID: "complete_creds_akid", + SecretAccessKey: "complete_creds_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + }, + }, + }, + { + Filenames: []string{testConfigOtherFilename, testConfigFilename}, + Profile: "assume_role_invalid_source_profile", + Expected: sharedConfig{ + AssumeRole: assumeRoleConfig{ + RoleARN: "assume_role_invalid_source_profile_role_arn", + SourceProfile: "profile_not_exists", + }, + }, + Err: SharedConfigAssumeRoleError{RoleARN: "assume_role_invalid_source_profile_role_arn"}, + }, + { + Filenames: []string{testConfigOtherFilename, testConfigFilename}, + Profile: "assume_role_w_creds", + Expected: sharedConfig{ + Creds: credentials.Value{ + AccessKeyID: "assume_role_w_creds_akid", + SecretAccessKey: "assume_role_w_creds_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + AssumeRole: assumeRoleConfig{ + RoleARN: "assume_role_w_creds_role_arn", + SourceProfile: "assume_role_w_creds", + ExternalID: "1234", + RoleSessionName: "assume_role_w_creds_session_name", + }, + AssumeRoleSource: &sharedConfig{ + Creds: credentials.Value{ + AccessKeyID: "assume_role_w_creds_akid", + SecretAccessKey: "assume_role_w_creds_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + }, + }, + }, + { + Filenames: []string{testConfigOtherFilename, testConfigFilename}, + Profile: "assume_role_wo_creds", + Expected: sharedConfig{ + AssumeRole: assumeRoleConfig{ + RoleARN: "assume_role_wo_creds_role_arn", + SourceProfile: "assume_role_wo_creds", + }, + }, + Err: SharedConfigAssumeRoleError{RoleARN: "assume_role_wo_creds_role_arn"}, + }, + { + Filenames: []string{filepath.Join("testdata", "shared_config_invalid_ini")}, + Profile: "profile_name", + Err: SharedConfigLoadError{Filename: filepath.Join("testdata", "shared_config_invalid_ini")}, + }, + } + + for i, c := range cases { + cfg, err := loadSharedConfig(c.Profile, c.Filenames) + if c.Err != nil { + assert.Contains(t, err.Error(), c.Err.Error(), "expected error, %d", i) + continue + } + + assert.NoError(t, err, "unexpected error, %d", i) + assert.Equal(t, c.Expected, cfg, "not equal, %d", i) + } +} + +func TestLoadSharedConfigFromFile(t *testing.T) { + filename := testConfigFilename + f, err := ini.Load(filename) + if err != nil { + t.Fatalf("failed to load test config file, %s, %v", filename, err) + } + iniFile := sharedConfigFile{IniData: f, Filename: filename} + + cases := []struct { + Profile string + Expected sharedConfig + Err error + }{ + { + Profile: "default", + Expected: sharedConfig{Region: "default_region"}, + }, + { + Profile: "alt_profile_name", + Expected: sharedConfig{Region: "alt_profile_name_region"}, + }, + { + Profile: "short_profile_name_first", + Expected: sharedConfig{Region: "short_profile_name_first_short"}, + }, + { + Profile: "partial_creds", + Expected: sharedConfig{}, + }, + { + Profile: "complete_creds", + Expected: sharedConfig{ + Creds: credentials.Value{ + AccessKeyID: "complete_creds_akid", + SecretAccessKey: "complete_creds_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + }, + }, + { + Profile: "complete_creds_with_token", + Expected: sharedConfig{ + Creds: credentials.Value{ + AccessKeyID: "complete_creds_with_token_akid", + SecretAccessKey: "complete_creds_with_token_secret", + SessionToken: "complete_creds_with_token_token", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + }, + }, + { + Profile: "full_profile", + Expected: sharedConfig{ + Creds: credentials.Value{ + AccessKeyID: "full_profile_akid", + SecretAccessKey: "full_profile_secret", + ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename), + }, + Region: "full_profile_region", + }, + }, + { + Profile: "partial_assume_role", + Expected: sharedConfig{}, + }, + { + Profile: "assume_role", + Expected: sharedConfig{ + AssumeRole: assumeRoleConfig{ + RoleARN: "assume_role_role_arn", + SourceProfile: "complete_creds", + }, + }, + }, + { + Profile: "assume_role_w_mfa", + Expected: sharedConfig{ + AssumeRole: assumeRoleConfig{ + RoleARN: "assume_role_role_arn", + SourceProfile: "complete_creds", + MFASerial: "0123456789", + }, + }, + }, + { + Profile: "does_not_exists", + Err: SharedConfigProfileNotExistsError{Profile: "does_not_exists"}, + }, + } + + for i, c := range cases { + cfg := sharedConfig{} + + err := cfg.setFromIniFile(c.Profile, iniFile) + if c.Err != nil { + assert.Contains(t, err.Error(), c.Err.Error(), "expected error, %d", i) + continue + } + + assert.NoError(t, err, "unexpected error, %d", i) + assert.Equal(t, c.Expected, cfg, "not equal, %d", i) + } +} + +func TestLoadSharedConfigIniFiles(t *testing.T) { + cases := []struct { + Filenames []string + Expected []sharedConfigFile + }{ + { + Filenames: []string{"not_exists", testConfigFilename}, + Expected: []sharedConfigFile{ + {Filename: testConfigFilename}, + }, + }, + { + Filenames: []string{testConfigFilename, testConfigOtherFilename}, + Expected: []sharedConfigFile{ + {Filename: testConfigFilename}, + {Filename: testConfigOtherFilename}, + }, + }, + } + + for i, c := range cases { + files, err := loadSharedConfigIniFiles(c.Filenames) + assert.NoError(t, err, "unexpected error, %d", i) + assert.Equal(t, len(c.Expected), len(files), "expected num files, %d", i) + + for i, expectedFile := range c.Expected { + assert.Equal(t, expectedFile.Filename, files[i].Filename) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_5_test.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_5_test.go new file mode 100644 index 000000000..2e591c27f --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_5_test.go @@ -0,0 +1,86 @@ +// +build go1.5 + +package v4_test + +import ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting/unit" +) + +func TestStandaloneSign(t *testing.T) { + creds := unit.Session.Config.Credentials + signer := v4.NewSigner(creds) + + for _, c := range standaloneSignCases { + host := fmt.Sprintf("https://%s.%s.%s.amazonaws.com", + c.SubDomain, c.Region, c.Service) + + req, err := http.NewRequest("GET", host, nil) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + + // URL.EscapedPath() will be used by the signer to get the + // escaped form of the request's URI path. + req.URL.Path = c.OrigURI + req.URL.RawQuery = c.OrigQuery + + _, err = signer.Sign(req, nil, c.Service, c.Region, time.Unix(0, 0)) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + + actual := req.Header.Get("Authorization") + if e, a := c.ExpSig, actual; e != a { + t.Errorf("expected %v, but recieved %v", e, a) + } + if e, a := c.OrigURI, req.URL.Path; e != a { + t.Errorf("expected %v, but recieved %v", e, a) + } + if e, a := c.EscapedURI, req.URL.EscapedPath(); e != a { + t.Errorf("expected %v, but recieved %v", e, a) + } + } +} + +func TestStandaloneSign_RawPath(t *testing.T) { + creds := unit.Session.Config.Credentials + signer := v4.NewSigner(creds) + + for _, c := range standaloneSignCases { + host := fmt.Sprintf("https://%s.%s.%s.amazonaws.com", + c.SubDomain, c.Region, c.Service) + + req, err := http.NewRequest("GET", host, nil) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + + // URL.EscapedPath() will be used by the signer to get the + // escaped form of the request's URI path. + req.URL.Path = c.OrigURI + req.URL.RawPath = c.EscapedURI + req.URL.RawQuery = c.OrigQuery + + _, err = signer.Sign(req, nil, c.Service, c.Region, time.Unix(0, 0)) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + + actual := req.Header.Get("Authorization") + if e, a := c.ExpSig, actual; e != a { + t.Errorf("expected %v, but recieved %v", e, a) + } + if e, a := c.OrigURI, req.URL.Path; e != a { + t.Errorf("expected %v, but recieved %v", e, a) + } + if e, a := c.EscapedURI, req.URL.EscapedPath(); e != a { + t.Errorf("expected %v, but recieved %v", e, a) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_test.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_test.go new file mode 100644 index 000000000..93d664b23 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_test.go @@ -0,0 +1,254 @@ +package v4_test + +import ( + "net/http" + "net/url" + "reflect" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/s3" +) + +var standaloneSignCases = []struct { + OrigURI string + OrigQuery string + Region, Service, SubDomain string + ExpSig string + EscapedURI string +}{ + { + OrigURI: `/logs-*/_search`, + OrigQuery: `pretty=true`, + Region: "us-west-2", Service: "es", SubDomain: "hostname-clusterkey", + EscapedURI: `/logs-%2A/_search`, + ExpSig: `AWS4-HMAC-SHA256 Credential=AKID/19700101/us-west-2/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=79d0760751907af16f64a537c1242416dacf51204a7dd5284492d15577973b91`, + }, +} + +func TestPresignHandler(t *testing.T) { + svc := s3.New(unit.Session) + req, _ := svc.PutObjectRequest(&s3.PutObjectInput{ + Bucket: aws.String("bucket"), + Key: aws.String("key"), + ContentDisposition: aws.String("a+b c$d"), + ACL: aws.String("public-read"), + }) + req.Time = time.Unix(0, 0) + urlstr, err := req.Presign(5 * time.Minute) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + expectedHost := "bucket.s3.mock-region.amazonaws.com" + expectedDate := "19700101T000000Z" + expectedHeaders := "content-disposition;host;x-amz-acl" + expectedSig := "a46583256431b09eb45ba4af2e6286d96a9835ed13721023dc8076dfdcb90fcb" + expectedCred := "AKID/19700101/mock-region/s3/aws4_request" + + u, _ := url.Parse(urlstr) + urlQ := u.Query() + if e, a := expectedHost, u.Host; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedSig, urlQ.Get("X-Amz-Signature"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedCred, urlQ.Get("X-Amz-Credential"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedHeaders, urlQ.Get("X-Amz-SignedHeaders"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedDate, urlQ.Get("X-Amz-Date"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "300", urlQ.Get("X-Amz-Expires"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "UNSIGNED-PAYLOAD", urlQ.Get("X-Amz-Content-Sha256"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + if e, a := "+", urlstr; strings.Contains(a, e) { // + encoded as %20 + t.Errorf("expect %v not to be in %v", e, a) + } +} + +func TestPresignRequest(t *testing.T) { + svc := s3.New(unit.Session) + req, _ := svc.PutObjectRequest(&s3.PutObjectInput{ + Bucket: aws.String("bucket"), + Key: aws.String("key"), + ContentDisposition: aws.String("a+b c$d"), + ACL: aws.String("public-read"), + }) + req.Time = time.Unix(0, 0) + urlstr, headers, err := req.PresignRequest(5 * time.Minute) + + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + expectedHost := "bucket.s3.mock-region.amazonaws.com" + expectedDate := "19700101T000000Z" + expectedHeaders := "content-disposition;host;x-amz-acl" + expectedSig := "a46583256431b09eb45ba4af2e6286d96a9835ed13721023dc8076dfdcb90fcb" + expectedCred := "AKID/19700101/mock-region/s3/aws4_request" + expectedHeaderMap := http.Header{ + "x-amz-acl": []string{"public-read"}, + "content-disposition": []string{"a+b c$d"}, + } + + u, _ := url.Parse(urlstr) + urlQ := u.Query() + if e, a := expectedHost, u.Host; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedSig, urlQ.Get("X-Amz-Signature"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedCred, urlQ.Get("X-Amz-Credential"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedHeaders, urlQ.Get("X-Amz-SignedHeaders"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedDate, urlQ.Get("X-Amz-Date"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedHeaderMap, headers; !reflect.DeepEqual(e, a) { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "300", urlQ.Get("X-Amz-Expires"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "UNSIGNED-PAYLOAD", urlQ.Get("X-Amz-Content-Sha256"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + if e, a := "+", urlstr; strings.Contains(a, e) { // + encoded as %20 + t.Errorf("expect %v not to be in %v", e, a) + } +} + +func TestStandaloneSign_CustomURIEscape(t *testing.T) { + var expectSig = `AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=6601e883cc6d23871fd6c2a394c5677ea2b8c82b04a6446786d64cd74f520967` + + creds := unit.Session.Config.Credentials + signer := v4.NewSigner(creds, func(s *v4.Signer) { + s.DisableURIPathEscaping = true + }) + + host := "https://subdomain.us-east-1.es.amazonaws.com" + req, err := http.NewRequest("GET", host, nil) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + req.URL.Path = `/log-*/_search` + req.URL.Opaque = "//subdomain.us-east-1.es.amazonaws.com/log-%2A/_search" + + _, err = signer.Sign(req, nil, "es", "us-east-1", time.Unix(0, 0)) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + actual := req.Header.Get("Authorization") + if e, a := expectSig, actual; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestStandaloneSign_WithPort(t *testing.T) { + + cases := []struct { + description string + url string + expectedSig string + }{ + { + "default HTTPS port", + "https://estest.us-east-1.es.amazonaws.com:443/_search", + "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=e573fc9aa3a156b720976419319be98fb2824a3abc2ddd895ecb1d1611c6a82d", + }, + { + "default HTTP port", + "http://example.com:80/_search", + "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=54ebe60c4ae03a40948b849e13c333523235f38002e2807059c64a9a8c7cb951", + }, + { + "non-standard HTTP port", + "http://example.com:9200/_search", + "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=cd9d926a460f8d3b58b57beadbd87666dc667e014c0afaa4cea37b2867f51b4f", + }, + { + "non-standard HTTPS port", + "https://example.com:9200/_search", + "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=cd9d926a460f8d3b58b57beadbd87666dc667e014c0afaa4cea37b2867f51b4f", + }, + } + + for _, c := range cases { + signer := v4.NewSigner(unit.Session.Config.Credentials) + req, _ := http.NewRequest("GET", c.url, nil) + _, err := signer.Sign(req, nil, "es", "us-east-1", time.Unix(0, 0)) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + actual := req.Header.Get("Authorization") + if e, a := c.expectedSig, actual; e != a { + t.Errorf("%s, expect %v, got %v", c.description, e, a) + } + } +} + +func TestStandalonePresign_WithPort(t *testing.T) { + + cases := []struct { + description string + url string + expectedSig string + }{ + { + "default HTTPS port", + "https://estest.us-east-1.es.amazonaws.com:443/_search", + "0abcf61a351063441296febf4b485734d780634fba8cf1e7d9769315c35255d6", + }, + { + "default HTTP port", + "http://example.com:80/_search", + "fce9976dd6c849c21adfa6d3f3e9eefc651d0e4a2ccd740d43efddcccfdc8179", + }, + { + "non-standard HTTP port", + "http://example.com:9200/_search", + "f33c25a81c735e42bef35ed5e9f720c43940562e3e616ff0777bf6dde75249b0", + }, + { + "non-standard HTTPS port", + "https://example.com:9200/_search", + "f33c25a81c735e42bef35ed5e9f720c43940562e3e616ff0777bf6dde75249b0", + }, + } + + for _, c := range cases { + signer := v4.NewSigner(unit.Session.Config.Credentials) + req, _ := http.NewRequest("GET", c.url, nil) + _, err := signer.Presign(req, nil, "es", "us-east-1", 5 * time.Minute, time.Unix(0, 0)) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + actual := req.URL.Query().Get("X-Amz-Signature") + if e, a := c.expectedSig, actual; e != a { + t.Errorf("%s, expect %v, got %v", c.description, e, a) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules_test.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules_test.go new file mode 100644 index 000000000..f4be951ac --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/header_rules_test.go @@ -0,0 +1,77 @@ +package v4 + +import ( + "testing" +) + +func TestRuleCheckWhitelist(t *testing.T) { + w := whitelist{ + mapRule{ + "Cache-Control": struct{}{}, + }, + } + + if !w.IsValid("Cache-Control") { + t.Error("expected true value") + } + if w.IsValid("Cache-") { + t.Error("expected false value") + } +} + +func TestRuleCheckBlacklist(t *testing.T) { + b := blacklist{ + mapRule{ + "Cache-Control": struct{}{}, + }, + } + + if b.IsValid("Cache-Control") { + t.Error("expected false value") + } + if !b.IsValid("Cache-") { + t.Error("expected true value") + } +} + +func TestRuleCheckPattern(t *testing.T) { + p := patterns{"X-Amz-Meta-"} + + if !p.IsValid("X-Amz-Meta-") { + t.Error("expected true value") + } + if !p.IsValid("X-Amz-Meta-Star") { + t.Error("expected true value") + } + if p.IsValid("Cache-") { + t.Error("expected false value") + } +} + +func TestRuleComplexWhitelist(t *testing.T) { + w := rules{ + whitelist{ + mapRule{ + "Cache-Control": struct{}{}, + }, + }, + patterns{"X-Amz-Meta-"}, + } + + r := rules{ + inclusiveRules{patterns{"X-Amz-"}, blacklist{w}}, + } + + if !r.IsValid("X-Amz-Blah") { + t.Error("expected true value") + } + if r.IsValid("X-Amz-Meta-") { + t.Error("expected false value") + } + if r.IsValid("X-Amz-Meta-Star") { + t.Error("expected false value") + } + if r.IsValid("Cache-Control") { + t.Error("expected false value") + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4_test.go b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4_test.go new file mode 100644 index 000000000..16bc7378a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/signer/v4/v4_test.go @@ -0,0 +1,717 @@ +package v4 + +import ( + "bytes" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "reflect" + "strconv" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" +) + +func TestStripExcessHeaders(t *testing.T) { + vals := []string{ + "", + "123", + "1 2 3", + "1 2 3 ", + " 1 2 3", + "1 2 3", + "1 23", + "1 2 3", + "1 2 ", + " 1 2 ", + "12 3", + "12 3 1", + "12 3 1", + "12 3 1abc123", + } + + expected := []string{ + "", + "123", + "1 2 3", + "1 2 3", + "1 2 3", + "1 2 3", + "1 23", + "1 2 3", + "1 2", + "1 2", + "12 3", + "12 3 1", + "12 3 1", + "12 3 1abc123", + } + + stripExcessSpaces(vals) + for i := 0; i < len(vals); i++ { + if e, a := expected[i], vals[i]; e != a { + t.Errorf("%d, expect %v, got %v", i, e, a) + } + } +} + +func buildRequest(serviceName, region, body string) (*http.Request, io.ReadSeeker) { + reader := strings.NewReader(body) + return buildRequestWithBodyReader(serviceName, region, reader) +} + +func buildRequestWithBodyReader(serviceName, region string, body io.Reader) (*http.Request, io.ReadSeeker) { + var bodyLen int + + type lenner interface { + Len() int + } + if lr, ok := body.(lenner); ok { + bodyLen = lr.Len() + } + + endpoint := "https://" + serviceName + "." + region + ".amazonaws.com" + req, _ := http.NewRequest("POST", endpoint, body) + req.URL.Opaque = "//example.org/bucket/key-._~,!@#$%^&*()" + req.Header.Set("X-Amz-Target", "prefix.Operation") + req.Header.Set("Content-Type", "application/x-amz-json-1.0") + + if bodyLen > 0 { + req.Header.Set("Content-Length", strconv.Itoa(bodyLen)) + } + + req.Header.Set("X-Amz-Meta-Other-Header", "some-value=!@#$%^&* (+)") + req.Header.Add("X-Amz-Meta-Other-Header_With_Underscore", "some-value=!@#$%^&* (+)") + req.Header.Add("X-amz-Meta-Other-Header_With_Underscore", "some-value=!@#$%^&* (+)") + + var seeker io.ReadSeeker + if sr, ok := body.(io.ReadSeeker); ok { + seeker = sr + } else { + seeker = aws.ReadSeekCloser(body) + } + + return req, seeker +} + +func buildSigner() Signer { + return Signer{ + Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"), + } +} + +func removeWS(text string) string { + text = strings.Replace(text, " ", "", -1) + text = strings.Replace(text, "\n", "", -1) + text = strings.Replace(text, "\t", "", -1) + return text +} + +func assertEqual(t *testing.T, expected, given string) { + if removeWS(expected) != removeWS(given) { + t.Errorf("\nExpected: %s\nGiven: %s", expected, given) + } +} + +func TestPresignRequest(t *testing.T) { + req, body := buildRequest("dynamodb", "us-east-1", "{}") + + signer := buildSigner() + signer.Presign(req, body, "dynamodb", "us-east-1", 300*time.Second, time.Unix(0, 0)) + + expectedDate := "19700101T000000Z" + expectedHeaders := "content-length;content-type;host;x-amz-meta-other-header;x-amz-meta-other-header_with_underscore" + expectedSig := "122f0b9e091e4ba84286097e2b3404a1f1f4c4aad479adda95b7dff0ccbe5581" + expectedCred := "AKID/19700101/us-east-1/dynamodb/aws4_request" + expectedTarget := "prefix.Operation" + + q := req.URL.Query() + if e, a := expectedSig, q.Get("X-Amz-Signature"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedCred, q.Get("X-Amz-Credential"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedHeaders, q.Get("X-Amz-SignedHeaders"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedDate, q.Get("X-Amz-Date"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if a := q.Get("X-Amz-Meta-Other-Header"); len(a) != 0 { + t.Errorf("expect %v to be empty", a) + } + if e, a := expectedTarget, q.Get("X-Amz-Target"); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestPresignBodyWithArrayRequest(t *testing.T) { + req, body := buildRequest("dynamodb", "us-east-1", "{}") + req.URL.RawQuery = "Foo=z&Foo=o&Foo=m&Foo=a" + + signer := buildSigner() + signer.Presign(req, body, "dynamodb", "us-east-1", 300*time.Second, time.Unix(0, 0)) + + expectedDate := "19700101T000000Z" + expectedHeaders := "content-length;content-type;host;x-amz-meta-other-header;x-amz-meta-other-header_with_underscore" + expectedSig := "e3ac55addee8711b76c6d608d762cff285fe8b627a057f8b5ec9268cf82c08b1" + expectedCred := "AKID/19700101/us-east-1/dynamodb/aws4_request" + expectedTarget := "prefix.Operation" + + q := req.URL.Query() + if e, a := expectedSig, q.Get("X-Amz-Signature"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedCred, q.Get("X-Amz-Credential"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedHeaders, q.Get("X-Amz-SignedHeaders"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := expectedDate, q.Get("X-Amz-Date"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if a := q.Get("X-Amz-Meta-Other-Header"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } + if e, a := expectedTarget, q.Get("X-Amz-Target"); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignRequest(t *testing.T) { + req, body := buildRequest("dynamodb", "us-east-1", "{}") + signer := buildSigner() + signer.Sign(req, body, "dynamodb", "us-east-1", time.Unix(0, 0)) + + expectedDate := "19700101T000000Z" + expectedSig := "AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/dynamodb/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-amz-meta-other-header;x-amz-meta-other-header_with_underscore;x-amz-security-token;x-amz-target, Signature=a518299330494908a70222cec6899f6f32f297f8595f6df1776d998936652ad9" + + q := req.Header + if e, a := expectedSig, q.Get("Authorization"); e != a { + t.Errorf("expect\n%v\nactual\n%v\n", e, a) + } + if e, a := expectedDate, q.Get("X-Amz-Date"); e != a { + t.Errorf("expect\n%v\nactual\n%v\n", e, a) + } +} + +func TestSignBodyS3(t *testing.T) { + req, body := buildRequest("s3", "us-east-1", "hello") + signer := buildSigner() + signer.Sign(req, body, "s3", "us-east-1", time.Now()) + hash := req.Header.Get("X-Amz-Content-Sha256") + if e, a := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignBodyGlacier(t *testing.T) { + req, body := buildRequest("glacier", "us-east-1", "hello") + signer := buildSigner() + signer.Sign(req, body, "glacier", "us-east-1", time.Now()) + hash := req.Header.Get("X-Amz-Content-Sha256") + if e, a := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestPresignEmptyBodyS3(t *testing.T) { + req, body := buildRequest("s3", "us-east-1", "hello") + signer := buildSigner() + signer.Presign(req, body, "s3", "us-east-1", 5*time.Minute, time.Now()) + hash := req.Header.Get("X-Amz-Content-Sha256") + if e, a := "UNSIGNED-PAYLOAD", hash; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignUnseekableBody(t *testing.T) { + req, body := buildRequestWithBodyReader("mock-service", "mock-region", bytes.NewBuffer([]byte("hello"))) + signer := buildSigner() + _, err := signer.Sign(req, body, "mock-service", "mock-region", time.Now()) + if err == nil { + t.Fatalf("expect error signing request") + } + + if e, a := "unseekable request body", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %q to be in %q", e, a) + } +} + +func TestSignUnsignedPayloadUnseekableBody(t *testing.T) { + req, body := buildRequestWithBodyReader("mock-service", "mock-region", bytes.NewBuffer([]byte("hello"))) + + signer := buildSigner() + signer.UnsignedPayload = true + + _, err := signer.Sign(req, body, "mock-service", "mock-region", time.Now()) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + hash := req.Header.Get("X-Amz-Content-Sha256") + if e, a := "UNSIGNED-PAYLOAD", hash; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignPreComputedHashUnseekableBody(t *testing.T) { + req, body := buildRequestWithBodyReader("mock-service", "mock-region", bytes.NewBuffer([]byte("hello"))) + + signer := buildSigner() + + req.Header.Set("X-Amz-Content-Sha256", "some-content-sha256") + _, err := signer.Sign(req, body, "mock-service", "mock-region", time.Now()) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + hash := req.Header.Get("X-Amz-Content-Sha256") + if e, a := "some-content-sha256", hash; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignPrecomputedBodyChecksum(t *testing.T) { + req, body := buildRequest("dynamodb", "us-east-1", "hello") + req.Header.Set("X-Amz-Content-Sha256", "PRECOMPUTED") + signer := buildSigner() + signer.Sign(req, body, "dynamodb", "us-east-1", time.Now()) + hash := req.Header.Get("X-Amz-Content-Sha256") + if e, a := "PRECOMPUTED", hash; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestAnonymousCredentials(t *testing.T) { + svc := awstesting.NewClient(&aws.Config{Credentials: credentials.AnonymousCredentials}) + r := svc.NewRequest( + &request.Operation{ + Name: "BatchGetItem", + HTTPMethod: "POST", + HTTPPath: "/", + }, + nil, + nil, + ) + SignSDKRequest(r) + + urlQ := r.HTTPRequest.URL.Query() + if a := urlQ.Get("X-Amz-Signature"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } + if a := urlQ.Get("X-Amz-Credential"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } + if a := urlQ.Get("X-Amz-SignedHeaders"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } + if a := urlQ.Get("X-Amz-Date"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } + + hQ := r.HTTPRequest.Header + if a := hQ.Get("Authorization"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } + if a := hQ.Get("X-Amz-Date"); len(a) != 0 { + t.Errorf("expect %v to be empty, was not", a) + } +} + +func TestIgnoreResignRequestWithValidCreds(t *testing.T) { + svc := awstesting.NewClient(&aws.Config{ + Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"), + Region: aws.String("us-west-2"), + }) + r := svc.NewRequest( + &request.Operation{ + Name: "BatchGetItem", + HTTPMethod: "POST", + HTTPPath: "/", + }, + nil, + nil, + ) + + SignSDKRequest(r) + sig := r.HTTPRequest.Header.Get("Authorization") + + signSDKRequestWithCurrTime(r, func() time.Time { + // Simulate one second has passed so that signature's date changes + // when it is resigned. + return time.Now().Add(1 * time.Second) + }) + if e, a := sig, r.HTTPRequest.Header.Get("Authorization"); e == a { + t.Errorf("expect %v to be %v, but was not", e, a) + } +} + +func TestIgnorePreResignRequestWithValidCreds(t *testing.T) { + svc := awstesting.NewClient(&aws.Config{ + Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "SESSION"), + Region: aws.String("us-west-2"), + }) + r := svc.NewRequest( + &request.Operation{ + Name: "BatchGetItem", + HTTPMethod: "POST", + HTTPPath: "/", + }, + nil, + nil, + ) + r.ExpireTime = time.Minute * 10 + + SignSDKRequest(r) + sig := r.HTTPRequest.URL.Query().Get("X-Amz-Signature") + + signSDKRequestWithCurrTime(r, func() time.Time { + // Simulate one second has passed so that signature's date changes + // when it is resigned. + return time.Now().Add(1 * time.Second) + }) + if e, a := sig, r.HTTPRequest.URL.Query().Get("X-Amz-Signature"); e == a { + t.Errorf("expect %v to be %v, but was not", e, a) + } +} + +func TestResignRequestExpiredCreds(t *testing.T) { + creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + svc := awstesting.NewClient(&aws.Config{Credentials: creds}) + r := svc.NewRequest( + &request.Operation{ + Name: "BatchGetItem", + HTTPMethod: "POST", + HTTPPath: "/", + }, + nil, + nil, + ) + SignSDKRequest(r) + querySig := r.HTTPRequest.Header.Get("Authorization") + var origSignedHeaders string + for _, p := range strings.Split(querySig, ", ") { + if strings.HasPrefix(p, "SignedHeaders=") { + origSignedHeaders = p[len("SignedHeaders="):] + break + } + } + if a := origSignedHeaders; len(a) == 0 { + t.Errorf("expect not to be empty, but was") + } + if e, a := origSignedHeaders, "authorization"; strings.Contains(a, e) { + t.Errorf("expect %v to not be in %v, but was", e, a) + } + origSignedAt := r.LastSignedAt + + creds.Expire() + + signSDKRequestWithCurrTime(r, func() time.Time { + // Simulate one second has passed so that signature's date changes + // when it is resigned. + return time.Now().Add(1 * time.Second) + }) + updatedQuerySig := r.HTTPRequest.Header.Get("Authorization") + if e, a := querySig, updatedQuerySig; e == a { + t.Errorf("expect %v to be %v, was not", e, a) + } + + var updatedSignedHeaders string + for _, p := range strings.Split(updatedQuerySig, ", ") { + if strings.HasPrefix(p, "SignedHeaders=") { + updatedSignedHeaders = p[len("SignedHeaders="):] + break + } + } + if a := updatedSignedHeaders; len(a) == 0 { + t.Errorf("expect not to be empty, but was") + } + if e, a := updatedQuerySig, "authorization"; strings.Contains(a, e) { + t.Errorf("expect %v to not be in %v, but was", e, a) + } + if e, a := origSignedAt, r.LastSignedAt; e == a { + t.Errorf("expect %v to be %v, was not", e, a) + } +} + +func TestPreResignRequestExpiredCreds(t *testing.T) { + provider := &credentials.StaticProvider{Value: credentials.Value{ + AccessKeyID: "AKID", + SecretAccessKey: "SECRET", + SessionToken: "SESSION", + }} + creds := credentials.NewCredentials(provider) + svc := awstesting.NewClient(&aws.Config{Credentials: creds}) + r := svc.NewRequest( + &request.Operation{ + Name: "BatchGetItem", + HTTPMethod: "POST", + HTTPPath: "/", + }, + nil, + nil, + ) + r.ExpireTime = time.Minute * 10 + + SignSDKRequest(r) + querySig := r.HTTPRequest.URL.Query().Get("X-Amz-Signature") + signedHeaders := r.HTTPRequest.URL.Query().Get("X-Amz-SignedHeaders") + if a := signedHeaders; len(a) == 0 { + t.Errorf("expect not to be empty, but was") + } + origSignedAt := r.LastSignedAt + + creds.Expire() + + signSDKRequestWithCurrTime(r, func() time.Time { + // Simulate the request occurred 15 minutes in the past + return time.Now().Add(-48 * time.Hour) + }) + if e, a := querySig, r.HTTPRequest.URL.Query().Get("X-Amz-Signature"); e == a { + t.Errorf("expect %v to be %v, was not", e, a) + } + resignedHeaders := r.HTTPRequest.URL.Query().Get("X-Amz-SignedHeaders") + if e, a := signedHeaders, resignedHeaders; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := signedHeaders, "x-amz-signedHeaders"; strings.Contains(a, e) { + t.Errorf("expect %v to not be in %v, but was", e, a) + } + if e, a := origSignedAt, r.LastSignedAt; e == a { + t.Errorf("expect %v to be %v, was not", e, a) + } +} + +func TestResignRequestExpiredRequest(t *testing.T) { + creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + svc := awstesting.NewClient(&aws.Config{Credentials: creds}) + r := svc.NewRequest( + &request.Operation{ + Name: "BatchGetItem", + HTTPMethod: "POST", + HTTPPath: "/", + }, + nil, + nil, + ) + + SignSDKRequest(r) + querySig := r.HTTPRequest.Header.Get("Authorization") + origSignedAt := r.LastSignedAt + + signSDKRequestWithCurrTime(r, func() time.Time { + // Simulate the request occurred 15 minutes in the past + return time.Now().Add(15 * time.Minute) + }) + if e, a := querySig, r.HTTPRequest.Header.Get("Authorization"); e == a { + t.Errorf("expect %v to be %v, was not", e, a) + } + if e, a := origSignedAt, r.LastSignedAt; e == a { + t.Errorf("expect %v to be %v, was not", e, a) + } +} + +func TestSignWithRequestBody(t *testing.T) { + creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + signer := NewSigner(creds) + + expectBody := []byte("abc123") + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + b, err := ioutil.ReadAll(r.Body) + r.Body.Close() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := expectBody, b; !reflect.DeepEqual(e, a) { + t.Errorf("expect %v, got %v", e, a) + } + w.WriteHeader(http.StatusOK) + })) + + req, err := http.NewRequest("POST", server.URL, nil) + + _, err = signer.Sign(req, bytes.NewReader(expectBody), "service", "region", time.Now()) + if err != nil { + t.Errorf("expect not no error, got %v", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("expect not no error, got %v", err) + } + if e, a := http.StatusOK, resp.StatusCode; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignWithRequestBody_Overwrite(t *testing.T) { + creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + signer := NewSigner(creds) + + var expectBody []byte + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + b, err := ioutil.ReadAll(r.Body) + r.Body.Close() + if err != nil { + t.Errorf("expect not no error, got %v", err) + } + if e, a := len(expectBody), len(b); e != a { + t.Errorf("expect %v, got %v", e, a) + } + w.WriteHeader(http.StatusOK) + })) + + req, err := http.NewRequest("GET", server.URL, strings.NewReader("invalid body")) + + _, err = signer.Sign(req, nil, "service", "region", time.Now()) + req.ContentLength = 0 + + if err != nil { + t.Errorf("expect not no error, got %v", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("expect not no error, got %v", err) + } + if e, a := http.StatusOK, resp.StatusCode; e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestBuildCanonicalRequest(t *testing.T) { + req, body := buildRequest("dynamodb", "us-east-1", "{}") + req.URL.RawQuery = "Foo=z&Foo=o&Foo=m&Foo=a" + ctx := &signingCtx{ + ServiceName: "dynamodb", + Region: "us-east-1", + Request: req, + Body: body, + Query: req.URL.Query(), + Time: time.Now(), + ExpireTime: 5 * time.Second, + } + + ctx.buildCanonicalString() + expected := "https://example.org/bucket/key-._~,!@#$%^&*()?Foo=z&Foo=o&Foo=m&Foo=a" + if e, a := expected, ctx.Request.URL.String(); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestSignWithBody_ReplaceRequestBody(t *testing.T) { + creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + req, seekerBody := buildRequest("dynamodb", "us-east-1", "{}") + req.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) + + s := NewSigner(creds) + origBody := req.Body + + _, err := s.Sign(req, seekerBody, "dynamodb", "us-east-1", time.Now()) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if req.Body == origBody { + t.Errorf("expeect request body to not be origBody") + } + + if req.Body == nil { + t.Errorf("expect request body to be changed but was nil") + } +} + +func TestSignWithBody_NoReplaceRequestBody(t *testing.T) { + creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION") + req, seekerBody := buildRequest("dynamodb", "us-east-1", "{}") + req.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) + + s := NewSigner(creds, func(signer *Signer) { + signer.DisableRequestBodyOverwrite = true + }) + + origBody := req.Body + + _, err := s.Sign(req, seekerBody, "dynamodb", "us-east-1", time.Now()) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if req.Body != origBody { + t.Errorf("expect request body to not be chagned") + } +} + +func TestRequestHost(t *testing.T) { + req, body := buildRequest("dynamodb", "us-east-1", "{}") + req.URL.RawQuery = "Foo=z&Foo=o&Foo=m&Foo=a" + req.Host = "myhost" + ctx := &signingCtx{ + ServiceName: "dynamodb", + Region: "us-east-1", + Request: req, + Body: body, + Query: req.URL.Query(), + Time: time.Now(), + ExpireTime: 5 * time.Second, + } + + ctx.buildCanonicalHeaders(ignoredHeaders, ctx.Request.Header) + if !strings.Contains(ctx.canonicalHeaders, "host:"+req.Host) { + t.Errorf("canonical host header invalid") + } +} + +func BenchmarkPresignRequest(b *testing.B) { + signer := buildSigner() + req, body := buildRequest("dynamodb", "us-east-1", "{}") + for i := 0; i < b.N; i++ { + signer.Presign(req, body, "dynamodb", "us-east-1", 300*time.Second, time.Now()) + } +} + +func BenchmarkSignRequest(b *testing.B) { + signer := buildSigner() + req, body := buildRequest("dynamodb", "us-east-1", "{}") + for i := 0; i < b.N; i++ { + signer.Sign(req, body, "dynamodb", "us-east-1", time.Now()) + } +} + +var stripExcessSpaceCases = []string{ + `AWS4-HMAC-SHA256 Credential=AKIDFAKEIDFAKEID/20160628/us-west-2/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=1234567890abcdef1234567890abcdef1234567890abcdef`, + `123 321 123 321`, + ` 123 321 123 321 `, + ` 123 321 123 321 `, + "123", + "1 2 3", + " 1 2 3", + "1 2 3", + "1 23", + "1 2 3", + "1 2 ", + " 1 2 ", + "12 3", + "12 3 1", + "12 3 1", + "12 3 1abc123", +} + +func BenchmarkStripExcessSpaces(b *testing.B) { + for i := 0; i < b.N; i++ { + // Make sure to start with a copy of the cases + cases := append([]string{}, stripExcessSpaceCases...) + stripExcessSpaces(cases) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/aws/types_test.go b/vendor/github.com/aws/aws-sdk-go/aws/types_test.go new file mode 100644 index 000000000..e399ef573 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/aws/types_test.go @@ -0,0 +1,92 @@ +package aws + +import ( + "bytes" + "math/rand" + "testing" +) + +func TestWriteAtBuffer(t *testing.T) { + b := &WriteAtBuffer{} + + n, err := b.WriteAt([]byte{1}, 0) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + if e, a := 1, n; e != a { + t.Errorf("expected %d, but recieved %d", e, a) + } + + n, err = b.WriteAt([]byte{1, 1, 1}, 5) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + if e, a := 3, n; e != a { + t.Errorf("expected %d, but recieved %d", e, a) + } + + n, err = b.WriteAt([]byte{2}, 1) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + if e, a := 1, n; e != a { + t.Errorf("expected %d, but recieved %d", e, a) + } + + n, err = b.WriteAt([]byte{3}, 2) + if err != nil { + t.Errorf("expected no error, but received %v", err) + } + if e, a := 1, n; e != a { + t.Errorf("expected %d, but received %d", e, a) + } + + if !bytes.Equal([]byte{1, 2, 3, 0, 0, 1, 1, 1}, b.Bytes()) { + t.Errorf("expected %v, but received %v", []byte{1, 2, 3, 0, 0, 1, 1, 1}, b.Bytes()) + } +} + +func BenchmarkWriteAtBuffer(b *testing.B) { + buf := &WriteAtBuffer{} + r := rand.New(rand.NewSource(1)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + to := r.Intn(10) * 4096 + bs := make([]byte, to) + buf.WriteAt(bs, r.Int63n(10)*4096) + } +} + +func BenchmarkWriteAtBufferOrderedWrites(b *testing.B) { + // test the performance of a WriteAtBuffer when written in an + // ordered fashion. This is similar to the behavior of the + // s3.Downloader, since downloads the first chunk of the file, then + // the second, and so on. + // + // This test simulates a 150MB file being written in 30 ordered 5MB chunks. + chunk := int64(5e6) + max := chunk * 30 + // we'll write the same 5MB chunk every time + tmp := make([]byte, chunk) + for i := 0; i < b.N; i++ { + buf := &WriteAtBuffer{} + for i := int64(0); i < max; i += chunk { + buf.WriteAt(tmp, i) + } + } +} + +func BenchmarkWriteAtBufferParallel(b *testing.B) { + buf := &WriteAtBuffer{} + r := rand.New(rand.NewSource(1)) + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + to := r.Intn(10) * 4096 + bs := make([]byte, to) + buf.WriteAt(bs, r.Int63n(10)*4096) + } + }) +} diff --git a/vendor/github.com/aws/aws-sdk-go/buildspec.yml b/vendor/github.com/aws/aws-sdk-go/buildspec.yml new file mode 100644 index 000000000..427208edf --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/buildspec.yml @@ -0,0 +1,21 @@ +version: 0.2 + +phases: + build: + commands: + - echo Build started on `date` + - export GOPATH=/go + - export SDK_CB_ROOT=`pwd` + - export SDK_GO_ROOT=/go/src/github.com/aws/aws-sdk-go + - mkdir -p /go/src/github.com/aws + - ln -s $SDK_CB_ROOT $SDK_GO_ROOT + - cd $SDK_GO_ROOT + - make unit + - cd $SDK_CB_ROOT + - #echo Compiling the Go code... + post_build: + commands: + - echo Build completed on `date` +#artifacts: +# files: +# - hello diff --git a/vendor/github.com/aws/aws-sdk-go/doc.go b/vendor/github.com/aws/aws-sdk-go/doc.go new file mode 100644 index 000000000..32b806a4a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/doc.go @@ -0,0 +1,405 @@ +// Package sdk is the official AWS SDK for the Go programming language. +// +// The AWS SDK for Go provides APIs and utilities that developers can use to +// build Go applications that use AWS services, such as Amazon Elastic Compute +// Cloud (Amazon EC2) and Amazon Simple Storage Service (Amazon S3). +// +// The SDK removes the complexity of coding directly against a web service +// interface. It hides a lot of the lower-level plumbing, such as authentication, +// request retries, and error handling. +// +// The SDK also includes helpful utilities on top of the AWS APIs that add additional +// capabilities and functionality. For example, the Amazon S3 Download and Upload +// Manager will automatically split up large objects into multiple parts and +// transfer them concurrently. +// +// See the s3manager package documentation for more information. +// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/ +// +// Getting More Information +// +// Checkout the Getting Started Guide and API Reference Docs detailed the SDK's +// components and details on each AWS client the SDK supports. +// +// The Getting Started Guide provides examples and detailed description of how +// to get setup with the SDK. +// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/welcome.html +// +// The API Reference Docs include a detailed breakdown of the SDK's components +// such as utilities and AWS clients. Use this as a reference of the Go types +// included with the SDK, such as AWS clients, API operations, and API parameters. +// https://docs.aws.amazon.com/sdk-for-go/api/ +// +// Overview of SDK's Packages +// +// The SDK is composed of two main components, SDK core, and service clients. +// The SDK core packages are all available under the aws package at the root of +// the SDK. Each client for a supported AWS service is available within its own +// package under the service folder at the root of the SDK. +// +// * aws - SDK core, provides common shared types such as Config, Logger, +// and utilities to make working with API parameters easier. +// +// * awserr - Provides the error interface that the SDK will use for all +// errors that occur in the SDK's processing. This includes service API +// response errors as well. The Error type is made up of a code and message. +// Cast the SDK's returned error type to awserr.Error and call the Code +// method to compare returned error to specific error codes. See the package's +// documentation for additional values that can be extracted such as RequestId. +// +// * credentials - Provides the types and built in credentials providers +// the SDK will use to retrieve AWS credentials to make API requests with. +// Nested under this folder are also additional credentials providers such as +// stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles. +// +// * endpoints - Provides the AWS Regions and Endpoints metadata for the SDK. +// Use this to lookup AWS service endpoint information such as which services +// are in a region, and what regions a service is in. Constants are also provided +// for all region identifiers, e.g UsWest2RegionID for "us-west-2". +// +// * session - Provides initial default configuration, and load +// configuration from external sources such as environment and shared +// credentials file. +// +// * request - Provides the API request sending, and retry logic for the SDK. +// This package also includes utilities for defining your own request +// retryer, and configuring how the SDK processes the request. +// +// * service - Clients for AWS services. All services supported by the SDK are +// available under this folder. +// +// How to Use the SDK's AWS Service Clients +// +// The SDK includes the Go types and utilities you can use to make requests to +// AWS service APIs. Within the service folder at the root of the SDK you'll find +// a package for each AWS service the SDK supports. All service clients follows +// a common pattern of creation and usage. +// +// When creating a client for an AWS service you'll first need to have a Session +// value constructed. The Session provides shared configuration that can be shared +// between your service clients. When service clients are created you can pass +// in additional configuration via the aws.Config type to override configuration +// provided by in the Session to create service client instances with custom +// configuration. +// +// Once the service's client is created you can use it to make API requests the +// AWS service. These clients are safe to use concurrently. +// +// Configuring the SDK +// +// In the AWS SDK for Go, you can configure settings for service clients, such +// as the log level and maximum number of retries. Most settings are optional; +// however, for each service client, you must specify a region and your credentials. +// The SDK uses these values to send requests to the correct AWS region and sign +// requests with the correct credentials. You can specify these values as part +// of a session or as environment variables. +// +// See the SDK's configuration guide for more information. +// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html +// +// See the session package documentation for more information on how to use Session +// with the SDK. +// https://docs.aws.amazon.com/sdk-for-go/api/aws/session/ +// +// See the Config type in the aws package for more information on configuration +// options. +// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config +// +// Configuring Credentials +// +// When using the SDK you'll generally need your AWS credentials to authenticate +// with AWS services. The SDK supports multiple methods of supporting these +// credentials. By default the SDK will source credentials automatically from +// its default credential chain. See the session package for more information +// on this chain, and how to configure it. The common items in the credential +// chain are the following: +// +// * Environment Credentials - Set of environment variables that are useful +// when sub processes are created for specific roles. +// +// * Shared Credentials file (~/.aws/credentials) - This file stores your +// credentials based on a profile name and is useful for local development. +// +// * EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials +// to application running on an EC2 instance. This removes the need to manage +// credential files in production. +// +// Credentials can be configured in code as well by setting the Config's Credentials +// value to a custom provider or using one of the providers included with the +// SDK to bypass the default credential chain and use a custom one. This is +// helpful when you want to instruct the SDK to only use a specific set of +// credentials or providers. +// +// This example creates a credential provider for assuming an IAM role, "myRoleARN" +// and configures the S3 service client to use that role for API requests. +// +// // Initial credentials loaded from SDK's default credential chain. Such as +// // the environment, shared credentials (~/.aws/credentials), or EC2 Instance +// // Role. These credentials will be used to to make the STS Assume Role API. +// sess := session.Must(session.NewSession()) +// +// // Create the credentials from AssumeRoleProvider to assume the role +// // referenced by the "myRoleARN" ARN. +// creds := stscreds.NewCredentials(sess, "myRoleArn") +// +// // Create service client value configured for credentials +// // from assumed role. +// svc := s3.New(sess, &aws.Config{Credentials: creds})/ +// +// See the credentials package documentation for more information on credential +// providers included with the SDK, and how to customize the SDK's usage of +// credentials. +// https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials +// +// The SDK has support for the shared configuration file (~/.aws/config). This +// support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1", +// or enabling the feature in code when creating a Session via the +// Option's SharedConfigState parameter. +// +// sess := session.Must(session.NewSessionWithOptions(session.Options{ +// SharedConfigState: session.SharedConfigEnable, +// })) +// +// Configuring AWS Region +// +// In addition to the credentials you'll need to specify the region the SDK +// will use to make AWS API requests to. In the SDK you can specify the region +// either with an environment variable, or directly in code when a Session or +// service client is created. The last value specified in code wins if the region +// is specified multiple ways. +// +// To set the region via the environment variable set the "AWS_REGION" to the +// region you want to the SDK to use. Using this method to set the region will +// allow you to run your application in multiple regions without needing additional +// code in the application to select the region. +// +// AWS_REGION=us-west-2 +// +// The endpoints package includes constants for all regions the SDK knows. The +// values are all suffixed with RegionID. These values are helpful, because they +// reduce the need to type the region string manually. +// +// To set the region on a Session use the aws package's Config struct parameter +// Region to the AWS region you want the service clients created from the session to +// use. This is helpful when you want to create multiple service clients, and +// all of the clients make API requests to the same region. +// +// sess := session.Must(session.NewSession(&aws.Config{ +// Region: aws.String(endpoints.UsWest2RegionID), +// })) +// +// See the endpoints package for the AWS Regions and Endpoints metadata. +// https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/ +// +// In addition to setting the region when creating a Session you can also set +// the region on a per service client bases. This overrides the region of a +// Session. This is helpful when you want to create service clients in specific +// regions different from the Session's region. +// +// svc := s3.New(sess, &aws.Config{ +// Region: aws.String(endpoints.UsWest2RegionID), +// }) +// +// See the Config type in the aws package for more information and additional +// options such as setting the Endpoint, and other service client configuration options. +// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config +// +// Making API Requests +// +// Once the client is created you can make an API request to the service. +// Each API method takes a input parameter, and returns the service response +// and an error. The SDK provides methods for making the API call in multiple ways. +// +// In this list we'll use the S3 ListObjects API as an example for the different +// ways of making API requests. +// +// * ListObjects - Base API operation that will make the API request to the service. +// +// * ListObjectsRequest - API methods suffixed with Request will construct the +// API request, but not send it. This is also helpful when you want to get a +// presigned URL for a request, and share the presigned URL instead of your +// application making the request directly. +// +// * ListObjectsPages - Same as the base API operation, but uses a callback to +// automatically handle pagination of the API's response. +// +// * ListObjectsWithContext - Same as base API operation, but adds support for +// the Context pattern. This is helpful for controlling the canceling of in +// flight requests. See the Go standard library context package for more +// information. This method also takes request package's Option functional +// options as the variadic argument for modifying how the request will be +// made, or extracting information from the raw HTTP response. +// +// * ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for +// the Context pattern. Similar to ListObjectsWithContext this method also +// takes the request package's Option function option types as the variadic +// argument. +// +// In addition to the API operations the SDK also includes several higher level +// methods that abstract checking for and waiting for an AWS resource to be in +// a desired state. In this list we'll use WaitUntilBucketExists to demonstrate +// the different forms of waiters. +// +// * WaitUntilBucketExists. - Method to make API request to query an AWS service for +// a resource's state. Will return successfully when that state is accomplished. +// +// * WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds +// support for the Context pattern. In addition these methods take request +// package's WaiterOptions to configure the waiter, and how underlying request +// will be made by the SDK. +// +// The API method will document which error codes the service might return for +// the operation. These errors will also be available as const strings prefixed +// with "ErrCode" in the service client's package. If there are no errors listed +// in the API's SDK documentation you'll need to consult the AWS service's API +// documentation for the errors that could be returned. +// +// ctx := context.Background() +// +// result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{ +// Bucket: aws.String("my-bucket"), +// Key: aws.String("my-key"), +// }) +// if err != nil { +// // Cast err to awserr.Error to handle specific error codes. +// aerr, ok := err.(awserr.Error) +// if ok && aerr.Code() == s3.ErrCodeNoSuchKey { +// // Specific error code handling +// } +// return err +// } +// +// // Make sure to close the body when done with it for S3 GetObject APIs or +// // will leak connections. +// defer result.Body.Close() +// +// fmt.Println("Object Size:", aws.StringValue(result.ContentLength)) +// +// API Request Pagination and Resource Waiters +// +// Pagination helper methods are suffixed with "Pages", and provide the +// functionality needed to round trip API page requests. Pagination methods +// take a callback function that will be called for each page of the API's response. +// +// objects := []string{} +// err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{ +// Bucket: aws.String(myBucket), +// }, func(p *s3.ListObjectsOutput, lastPage bool) bool { +// for _, o := range p.Contents { +// objects = append(objects, aws.StringValue(o.Key)) +// } +// return true // continue paging +// }) +// if err != nil { +// panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err)) +// } +// +// fmt.Println("Objects in bucket:", objects) +// +// Waiter helper methods provide the functionality to wait for an AWS resource +// state. These methods abstract the logic needed to to check the state of an +// AWS resource, and wait until that resource is in a desired state. The waiter +// will block until the resource is in the state that is desired, an error occurs, +// or the waiter times out. If a resource times out the error code returned will +// be request.WaiterResourceNotReadyErrorCode. +// +// err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{ +// Bucket: aws.String(myBucket), +// }) +// if err != nil { +// aerr, ok := err.(awserr.Error) +// if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode { +// fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist") +// } +// panic(fmt.Errorf("failed to wait for bucket to exist, %v", err)) +// } +// fmt.Println("Bucket", myBucket, "exists") +// +// Complete SDK Example +// +// This example shows a complete working Go file which will upload a file to S3 +// and use the Context pattern to implement timeout logic that will cancel the +// request if it takes too long. This example highlights how to use sessions, +// create a service client, make a request, handle the error, and process the +// response. +// +// package main +// +// import ( +// "context" +// "flag" +// "fmt" +// "os" +// "time" +// +// "github.com/aws/aws-sdk-go/aws" +// "github.com/aws/aws-sdk-go/aws/awserr" +// "github.com/aws/aws-sdk-go/aws/request" +// "github.com/aws/aws-sdk-go/aws/session" +// "github.com/aws/aws-sdk-go/service/s3" +// ) +// +// // Uploads a file to S3 given a bucket and object key. Also takes a duration +// // value to terminate the update if it doesn't complete within that time. +// // +// // The AWS Region needs to be provided in the AWS shared config or on the +// // environment variable as `AWS_REGION`. Credentials also must be provided +// // Will default to shared config file, but can load from environment if provided. +// // +// // Usage: +// // # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail +// // go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt +// func main() { +// var bucket, key string +// var timeout time.Duration +// +// flag.StringVar(&bucket, "b", "", "Bucket name.") +// flag.StringVar(&key, "k", "", "Object key name.") +// flag.DurationVar(&timeout, "d", 0, "Upload timeout.") +// flag.Parse() +// +// // All clients require a Session. The Session provides the client with +// // shared configuration such as region, endpoint, and credentials. A +// // Session should be shared where possible to take advantage of +// // configuration and credential caching. See the session package for +// // more information. +// sess := session.Must(session.NewSession()) +// +// // Create a new instance of the service's client with a Session. +// // Optional aws.Config values can also be provided as variadic arguments +// // to the New function. This option allows you to provide service +// // specific configuration. +// svc := s3.New(sess) +// +// // Create a context with a timeout that will abort the upload if it takes +// // more than the passed in timeout. +// ctx := context.Background() +// var cancelFn func() +// if timeout > 0 { +// ctx, cancelFn = context.WithTimeout(ctx, timeout) +// } +// // Ensure the context is canceled to prevent leaking. +// // See context package for more information, https://golang.org/pkg/context/ +// defer cancelFn() +// +// // Uploads the object to S3. The Context will interrupt the request if the +// // timeout expires. +// _, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{ +// Bucket: aws.String(bucket), +// Key: aws.String(key), +// Body: os.Stdin, +// }) +// if err != nil { +// if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode { +// // If the SDK can determine the request or retry delay was canceled +// // by a context the CanceledErrorCode error code will be returned. +// fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err) +// } else { +// fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err) +// } +// os.Exit(1) +// } +// +// fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key) +// } +package sdk diff --git a/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_other_test.go b/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_other_test.go new file mode 100644 index 000000000..a2fd4558b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_other_test.go @@ -0,0 +1,40 @@ +package shareddefaults_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/internal/shareddefaults" +) + +func TestSharedCredsFilename(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + os.Setenv("HOME", "home_dir") + os.Setenv("USERPROFILE", "profile_dir") + + expect := filepath.Join("home_dir", ".aws", "credentials") + + name := shareddefaults.SharedCredentialsFilename() + if e, a := expect, name; e != a { + t.Errorf("expect %q shared creds filename, got %q", e, a) + } +} + +func TestSharedConfigFilename(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + os.Setenv("HOME", "home_dir") + os.Setenv("USERPROFILE", "profile_dir") + + expect := filepath.Join("home_dir", ".aws", "config") + + name := shareddefaults.SharedConfigFilename() + if e, a := expect, name; e != a { + t.Errorf("expect %q shared config filename, got %q", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_windows_test.go b/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_windows_test.go new file mode 100644 index 000000000..afe96b17d --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/internal/shareddefaults/shared_config_windows_test.go @@ -0,0 +1,40 @@ +package shareddefaults_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/internal/shareddefaults" +) + +func TestSharedCredsFilename(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + os.Setenv("HOME", "home_dir") + os.Setenv("USERPROFILE", "profile_dir") + + expect := filepath.Join("profile_dir", ".aws", "credentials") + + name := shareddefaults.SharedCredentialsFilename() + if e, a := expect, name; e != a { + t.Errorf("expect %q shared creds filename, got %q", e, a) + } +} + +func TestSharedConfigFilename(t *testing.T) { + env := awstesting.StashEnv() + defer awstesting.PopEnv(env) + + os.Setenv("HOME", "home_dir") + os.Setenv("USERPROFILE", "profile_dir") + + expect := filepath.Join("profile_dir", ".aws", "config") + + name := shareddefaults.SharedConfigFilename() + if e, a := expect, name; e != a { + t.Errorf("expect %q shared config filename, got %q", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/README.md b/vendor/github.com/aws/aws-sdk-go/private/README.md new file mode 100644 index 000000000..5bdb4c50a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/README.md @@ -0,0 +1,4 @@ +## AWS SDK for Go Private packages ## +`private` is a collection of packages used internally by the SDK, and is subject to have breaking changes. This package is not `internal` so that if you really need to use its functionality, and understand breaking changes will be made, you are able to. + +These packages will be refactored in the future so that the API generator and model parsers are exposed cleanly on their own. Making it easier for you to generate your own code based on the API models. diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_bench_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_bench_test.go new file mode 100644 index 000000000..e135b9360 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_bench_test.go @@ -0,0 +1,85 @@ +// +build bench + +package ec2query_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/private/protocol/ec2query" + "github.com/aws/aws-sdk-go/service/ec2" +) + +func BenchmarkEC2QueryBuild_Complex_ec2AuthorizeSecurityGroupEgress(b *testing.B) { + params := &ec2.AuthorizeSecurityGroupEgressInput{ + GroupId: aws.String("String"), // Required + CidrIp: aws.String("String"), + DryRun: aws.Bool(true), + FromPort: aws.Int64(1), + IpPermissions: []*ec2.IpPermission{ + { // Required + FromPort: aws.Int64(1), + IpProtocol: aws.String("String"), + IpRanges: []*ec2.IpRange{ + { // Required + CidrIp: aws.String("String"), + }, + // More values... + }, + PrefixListIds: []*ec2.PrefixListId{ + { // Required + PrefixListId: aws.String("String"), + }, + // More values... + }, + ToPort: aws.Int64(1), + UserIdGroupPairs: []*ec2.UserIdGroupPair{ + { // Required + GroupId: aws.String("String"), + GroupName: aws.String("String"), + UserId: aws.String("String"), + }, + // More values... + }, + }, + // More values... + }, + IpProtocol: aws.String("String"), + SourceSecurityGroupName: aws.String("String"), + SourceSecurityGroupOwnerId: aws.String("String"), + ToPort: aws.Int64(1), + } + + benchEC2QueryBuild(b, "AuthorizeSecurityGroupEgress", params) +} + +func BenchmarkEC2QueryBuild_Simple_ec2AttachNetworkInterface(b *testing.B) { + params := &ec2.AttachNetworkInterfaceInput{ + DeviceIndex: aws.Int64(1), // Required + InstanceId: aws.String("String"), // Required + NetworkInterfaceId: aws.String("String"), // Required + DryRun: aws.Bool(true), + } + + benchEC2QueryBuild(b, "AttachNetworkInterface", params) +} + +func benchEC2QueryBuild(b *testing.B, opName string, params interface{}) { + svc := awstesting.NewClient() + svc.ServiceName = "ec2" + svc.APIVersion = "2015-04-15" + + for i := 0; i < b.N; i++ { + r := svc.NewRequest(&request.Operation{ + Name: opName, + HTTPMethod: "POST", + HTTPPath: "/", + }, params, nil) + ec2query.Build(r) + if r.Error != nil { + b.Fatal("Unexpected error", r.Error) + } + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_test.go new file mode 100644 index 000000000..28f81b60b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/build_test.go @@ -0,0 +1,2092 @@ +package ec2query_test + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/ec2query" + "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" + "github.com/aws/aws-sdk-go/private/util" +) + +var _ bytes.Buffer // always import bytes +var _ http.Request +var _ json.Marshaler +var _ time.Time +var _ xmlutil.XMLNode +var _ xml.Attr +var _ = ioutil.Discard +var _ = util.Trim("") +var _ = url.Values{} +var _ = io.EOF +var _ = aws.String +var _ = fmt.Println +var _ = reflect.Value{} + +func init() { + protocol.RandReader = &awstesting.ZeroReader{} +} + +// InputService1ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService1ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService1ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService1ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService1ProtocolTest client from just a session. +// svc := inputservice1protocoltest.New(mySession) +// +// // Create a InputService1ProtocolTest client with additional configuration +// svc := inputservice1protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService1ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService1ProtocolTest { + c := p.ClientConfig("inputservice1protocoltest", cfgs...) + return newInputService1ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService1ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService1ProtocolTest { + svc := &InputService1ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice1protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService1ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService1ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService1TestCaseOperation1 = "OperationName" + +// InputService1TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService1TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService1TestCaseOperation1 for more information on using the InputService1TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService1TestCaseOperation1Request method. +// req, resp := client.InputService1TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input *InputService1TestShapeInputService1TestCaseOperation1Input) (req *request.Request, output *InputService1TestShapeInputService1TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService1TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService1TestShapeInputService1TestCaseOperation1Input{} + } + + output = &InputService1TestShapeInputService1TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService1TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService1TestCaseOperation1 for usage and error information. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputService1TestCaseOperation1Input) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) { + req, out := c.InputService1TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService1TestCaseOperation1WithContext is the same as InputService1TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService1TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation1WithContext(ctx aws.Context, input *InputService1TestShapeInputService1TestCaseOperation1Input, opts ...request.Option) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) { + req, out := c.InputService1TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService1TestShapeInputService1TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + Bar *string `type:"string"` + + Foo *string `type:"string"` +} + +// SetBar sets the Bar field's value. +func (s *InputService1TestShapeInputService1TestCaseOperation1Input) SetBar(v string) *InputService1TestShapeInputService1TestCaseOperation1Input { + s.Bar = &v + return s +} + +// SetFoo sets the Foo field's value. +func (s *InputService1TestShapeInputService1TestCaseOperation1Input) SetFoo(v string) *InputService1TestShapeInputService1TestCaseOperation1Input { + s.Foo = &v + return s +} + +type InputService1TestShapeInputService1TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService2ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService2ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService2ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService2ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService2ProtocolTest client from just a session. +// svc := inputservice2protocoltest.New(mySession) +// +// // Create a InputService2ProtocolTest client with additional configuration +// svc := inputservice2protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService2ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService2ProtocolTest { + c := p.ClientConfig("inputservice2protocoltest", cfgs...) + return newInputService2ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService2ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService2ProtocolTest { + svc := &InputService2ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice2protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService2ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService2ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService2TestCaseOperation1 = "OperationName" + +// InputService2TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService2TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService2TestCaseOperation1 for more information on using the InputService2TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService2TestCaseOperation1Request method. +// req, resp := client.InputService2TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input *InputService2TestShapeInputService2TestCaseOperation1Input) (req *request.Request, output *InputService2TestShapeInputService2TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService2TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService2TestShapeInputService2TestCaseOperation1Input{} + } + + output = &InputService2TestShapeInputService2TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService2TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService2TestCaseOperation1 for usage and error information. +func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputService2TestCaseOperation1Input) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) { + req, out := c.InputService2TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService2TestCaseOperation1WithContext is the same as InputService2TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService2TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService2ProtocolTest) InputService2TestCaseOperation1WithContext(ctx aws.Context, input *InputService2TestShapeInputService2TestCaseOperation1Input, opts ...request.Option) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) { + req, out := c.InputService2TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService2TestShapeInputService2TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + Bar *string `locationName:"barLocationName" type:"string"` + + Foo *string `type:"string"` + + Yuck *string `locationName:"yuckLocationName" queryName:"yuckQueryName" type:"string"` +} + +// SetBar sets the Bar field's value. +func (s *InputService2TestShapeInputService2TestCaseOperation1Input) SetBar(v string) *InputService2TestShapeInputService2TestCaseOperation1Input { + s.Bar = &v + return s +} + +// SetFoo sets the Foo field's value. +func (s *InputService2TestShapeInputService2TestCaseOperation1Input) SetFoo(v string) *InputService2TestShapeInputService2TestCaseOperation1Input { + s.Foo = &v + return s +} + +// SetYuck sets the Yuck field's value. +func (s *InputService2TestShapeInputService2TestCaseOperation1Input) SetYuck(v string) *InputService2TestShapeInputService2TestCaseOperation1Input { + s.Yuck = &v + return s +} + +type InputService2TestShapeInputService2TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService3ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService3ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService3ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService3ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService3ProtocolTest client from just a session. +// svc := inputservice3protocoltest.New(mySession) +// +// // Create a InputService3ProtocolTest client with additional configuration +// svc := inputservice3protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService3ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService3ProtocolTest { + c := p.ClientConfig("inputservice3protocoltest", cfgs...) + return newInputService3ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService3ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService3ProtocolTest { + svc := &InputService3ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice3protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService3ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService3ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService3TestCaseOperation1 = "OperationName" + +// InputService3TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService3TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService3TestCaseOperation1 for more information on using the InputService3TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService3TestCaseOperation1Request method. +// req, resp := client.InputService3TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input *InputService3TestShapeInputService3TestCaseOperation1Input) (req *request.Request, output *InputService3TestShapeInputService3TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService3TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService3TestShapeInputService3TestCaseOperation1Input{} + } + + output = &InputService3TestShapeInputService3TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService3TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService3TestCaseOperation1 for usage and error information. +func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputService3TestCaseOperation1Input) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) { + req, out := c.InputService3TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService3TestCaseOperation1WithContext is the same as InputService3TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService3TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService3ProtocolTest) InputService3TestCaseOperation1WithContext(ctx aws.Context, input *InputService3TestShapeInputService3TestCaseOperation1Input, opts ...request.Option) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) { + req, out := c.InputService3TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService3TestShapeInputService3TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + StructArg *InputService3TestShapeStructType `locationName:"Struct" type:"structure"` +} + +// SetStructArg sets the StructArg field's value. +func (s *InputService3TestShapeInputService3TestCaseOperation1Input) SetStructArg(v *InputService3TestShapeStructType) *InputService3TestShapeInputService3TestCaseOperation1Input { + s.StructArg = v + return s +} + +type InputService3TestShapeInputService3TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService3TestShapeStructType struct { + _ struct{} `type:"structure"` + + ScalarArg *string `locationName:"Scalar" type:"string"` +} + +// SetScalarArg sets the ScalarArg field's value. +func (s *InputService3TestShapeStructType) SetScalarArg(v string) *InputService3TestShapeStructType { + s.ScalarArg = &v + return s +} + +// InputService4ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService4ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService4ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService4ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService4ProtocolTest client from just a session. +// svc := inputservice4protocoltest.New(mySession) +// +// // Create a InputService4ProtocolTest client with additional configuration +// svc := inputservice4protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService4ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService4ProtocolTest { + c := p.ClientConfig("inputservice4protocoltest", cfgs...) + return newInputService4ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService4ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService4ProtocolTest { + svc := &InputService4ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice4protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService4ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService4ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService4TestCaseOperation1 = "OperationName" + +// InputService4TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService4TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService4TestCaseOperation1 for more information on using the InputService4TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService4TestCaseOperation1Request method. +// req, resp := client.InputService4TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input *InputService4TestShapeInputService4TestCaseOperation1Input) (req *request.Request, output *InputService4TestShapeInputService4TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService4TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService4TestShapeInputService4TestCaseOperation1Input{} + } + + output = &InputService4TestShapeInputService4TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService4TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService4TestCaseOperation1 for usage and error information. +func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputService4TestCaseOperation1Input) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) { + req, out := c.InputService4TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService4TestCaseOperation1WithContext is the same as InputService4TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService4TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService4ProtocolTest) InputService4TestCaseOperation1WithContext(ctx aws.Context, input *InputService4TestShapeInputService4TestCaseOperation1Input, opts ...request.Option) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) { + req, out := c.InputService4TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService4TestShapeInputService4TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + ListBools []*bool `type:"list"` + + ListFloats []*float64 `type:"list"` + + ListIntegers []*int64 `type:"list"` + + ListStrings []*string `type:"list"` +} + +// SetListBools sets the ListBools field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation1Input) SetListBools(v []*bool) *InputService4TestShapeInputService4TestCaseOperation1Input { + s.ListBools = v + return s +} + +// SetListFloats sets the ListFloats field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation1Input) SetListFloats(v []*float64) *InputService4TestShapeInputService4TestCaseOperation1Input { + s.ListFloats = v + return s +} + +// SetListIntegers sets the ListIntegers field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation1Input) SetListIntegers(v []*int64) *InputService4TestShapeInputService4TestCaseOperation1Input { + s.ListIntegers = v + return s +} + +// SetListStrings sets the ListStrings field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation1Input) SetListStrings(v []*string) *InputService4TestShapeInputService4TestCaseOperation1Input { + s.ListStrings = v + return s +} + +type InputService4TestShapeInputService4TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService5ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService5ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService5ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService5ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService5ProtocolTest client from just a session. +// svc := inputservice5protocoltest.New(mySession) +// +// // Create a InputService5ProtocolTest client with additional configuration +// svc := inputservice5protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService5ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService5ProtocolTest { + c := p.ClientConfig("inputservice5protocoltest", cfgs...) + return newInputService5ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService5ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService5ProtocolTest { + svc := &InputService5ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice5protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService5ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService5ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService5TestCaseOperation1 = "OperationName" + +// InputService5TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService5TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService5TestCaseOperation1 for more information on using the InputService5TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService5TestCaseOperation1Request method. +// req, resp := client.InputService5TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input *InputService5TestShapeInputService5TestCaseOperation1Input) (req *request.Request, output *InputService5TestShapeInputService5TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService5TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService5TestShapeInputService5TestCaseOperation1Input{} + } + + output = &InputService5TestShapeInputService5TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService5TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService5TestCaseOperation1 for usage and error information. +func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputService5TestCaseOperation1Input) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) { + req, out := c.InputService5TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService5TestCaseOperation1WithContext is the same as InputService5TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService5TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService5ProtocolTest) InputService5TestCaseOperation1WithContext(ctx aws.Context, input *InputService5TestShapeInputService5TestCaseOperation1Input, opts ...request.Option) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) { + req, out := c.InputService5TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService5TestShapeInputService5TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + ListArg []*string `locationName:"ListMemberName" locationNameList:"item" type:"list"` +} + +// SetListArg sets the ListArg field's value. +func (s *InputService5TestShapeInputService5TestCaseOperation1Input) SetListArg(v []*string) *InputService5TestShapeInputService5TestCaseOperation1Input { + s.ListArg = v + return s +} + +type InputService5TestShapeInputService5TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService6ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService6ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService6ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService6ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService6ProtocolTest client from just a session. +// svc := inputservice6protocoltest.New(mySession) +// +// // Create a InputService6ProtocolTest client with additional configuration +// svc := inputservice6protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService6ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService6ProtocolTest { + c := p.ClientConfig("inputservice6protocoltest", cfgs...) + return newInputService6ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService6ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService6ProtocolTest { + svc := &InputService6ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice6protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService6ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService6ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService6TestCaseOperation1 = "OperationName" + +// InputService6TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService6TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService6TestCaseOperation1 for more information on using the InputService6TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService6TestCaseOperation1Request method. +// req, resp := client.InputService6TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input *InputService6TestShapeInputService6TestCaseOperation1Input) (req *request.Request, output *InputService6TestShapeInputService6TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService6TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService6TestShapeInputService6TestCaseOperation1Input{} + } + + output = &InputService6TestShapeInputService6TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService6TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService6TestCaseOperation1 for usage and error information. +func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputService6TestCaseOperation1Input) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) { + req, out := c.InputService6TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService6TestCaseOperation1WithContext is the same as InputService6TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService6TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService6ProtocolTest) InputService6TestCaseOperation1WithContext(ctx aws.Context, input *InputService6TestShapeInputService6TestCaseOperation1Input, opts ...request.Option) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) { + req, out := c.InputService6TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService6TestShapeInputService6TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + ListArg []*string `locationName:"ListMemberName" queryName:"ListQueryName" locationNameList:"item" type:"list"` +} + +// SetListArg sets the ListArg field's value. +func (s *InputService6TestShapeInputService6TestCaseOperation1Input) SetListArg(v []*string) *InputService6TestShapeInputService6TestCaseOperation1Input { + s.ListArg = v + return s +} + +type InputService6TestShapeInputService6TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService7ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService7ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService7ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService7ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService7ProtocolTest client from just a session. +// svc := inputservice7protocoltest.New(mySession) +// +// // Create a InputService7ProtocolTest client with additional configuration +// svc := inputservice7protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService7ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService7ProtocolTest { + c := p.ClientConfig("inputservice7protocoltest", cfgs...) + return newInputService7ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService7ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService7ProtocolTest { + svc := &InputService7ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice7protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService7ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService7ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService7TestCaseOperation1 = "OperationName" + +// InputService7TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService7TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService7TestCaseOperation1 for more information on using the InputService7TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService7TestCaseOperation1Request method. +// req, resp := client.InputService7TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input *InputService7TestShapeInputService7TestCaseOperation1Input) (req *request.Request, output *InputService7TestShapeInputService7TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService7TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService7TestShapeInputService7TestCaseOperation1Input{} + } + + output = &InputService7TestShapeInputService7TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService7TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService7TestCaseOperation1 for usage and error information. +func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputService7TestCaseOperation1Input) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) { + req, out := c.InputService7TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService7TestCaseOperation1WithContext is the same as InputService7TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService7TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService7ProtocolTest) InputService7TestCaseOperation1WithContext(ctx aws.Context, input *InputService7TestShapeInputService7TestCaseOperation1Input, opts ...request.Option) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) { + req, out := c.InputService7TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService7TestShapeInputService7TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + // BlobArg is automatically base64 encoded/decoded by the SDK. + BlobArg []byte `type:"blob"` +} + +// SetBlobArg sets the BlobArg field's value. +func (s *InputService7TestShapeInputService7TestCaseOperation1Input) SetBlobArg(v []byte) *InputService7TestShapeInputService7TestCaseOperation1Input { + s.BlobArg = v + return s +} + +type InputService7TestShapeInputService7TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService8ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService8ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService8ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService8ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService8ProtocolTest client from just a session. +// svc := inputservice8protocoltest.New(mySession) +// +// // Create a InputService8ProtocolTest client with additional configuration +// svc := inputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService8ProtocolTest { + c := p.ClientConfig("inputservice8protocoltest", cfgs...) + return newInputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService8ProtocolTest { + svc := &InputService8ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice8protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService8ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService8ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService8TestCaseOperation1 = "OperationName" + +// InputService8TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService8TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService8TestCaseOperation1 for more information on using the InputService8TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService8TestCaseOperation1Request method. +// req, resp := client.InputService8TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input *InputService8TestShapeInputService8TestCaseOperation1Input) (req *request.Request, output *InputService8TestShapeInputService8TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService8TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService8TestShapeInputService8TestCaseOperation1Input{} + } + + output = &InputService8TestShapeInputService8TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService8TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService8TestCaseOperation1 for usage and error information. +func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputService8TestCaseOperation1Input) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) { + req, out := c.InputService8TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService8TestCaseOperation1WithContext is the same as InputService8TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService8TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService8ProtocolTest) InputService8TestCaseOperation1WithContext(ctx aws.Context, input *InputService8TestShapeInputService8TestCaseOperation1Input, opts ...request.Option) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) { + req, out := c.InputService8TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService8TestShapeInputService8TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + TimeArg *time.Time `type:"timestamp" timestampFormat:"iso8601"` +} + +// SetTimeArg sets the TimeArg field's value. +func (s *InputService8TestShapeInputService8TestCaseOperation1Input) SetTimeArg(v time.Time) *InputService8TestShapeInputService8TestCaseOperation1Input { + s.TimeArg = &v + return s +} + +type InputService8TestShapeInputService8TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService9ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService9ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService9ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService9ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService9ProtocolTest client from just a session. +// svc := inputservice9protocoltest.New(mySession) +// +// // Create a InputService9ProtocolTest client with additional configuration +// svc := inputservice9protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService9ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService9ProtocolTest { + c := p.ClientConfig("inputservice9protocoltest", cfgs...) + return newInputService9ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService9ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService9ProtocolTest { + svc := &InputService9ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice9protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService9ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService9ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService9TestCaseOperation1 = "OperationName" + +// InputService9TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService9TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService9TestCaseOperation1 for more information on using the InputService9TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService9TestCaseOperation1Request method. +// req, resp := client.InputService9TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService9ProtocolTest) InputService9TestCaseOperation1Request(input *InputService9TestShapeInputService9TestCaseOperation2Input) (req *request.Request, output *InputService9TestShapeInputService9TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService9TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService9TestShapeInputService9TestCaseOperation2Input{} + } + + output = &InputService9TestShapeInputService9TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService9TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService9TestCaseOperation1 for usage and error information. +func (c *InputService9ProtocolTest) InputService9TestCaseOperation1(input *InputService9TestShapeInputService9TestCaseOperation2Input) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) { + req, out := c.InputService9TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService9TestCaseOperation1WithContext is the same as InputService9TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService9TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService9ProtocolTest) InputService9TestCaseOperation1WithContext(ctx aws.Context, input *InputService9TestShapeInputService9TestCaseOperation2Input, opts ...request.Option) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) { + req, out := c.InputService9TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService9TestCaseOperation2 = "OperationName" + +// InputService9TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService9TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService9TestCaseOperation2 for more information on using the InputService9TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService9TestCaseOperation2Request method. +// req, resp := client.InputService9TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService9ProtocolTest) InputService9TestCaseOperation2Request(input *InputService9TestShapeInputService9TestCaseOperation2Input) (req *request.Request, output *InputService9TestShapeInputService9TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService9TestCaseOperation2, + HTTPPath: "/", + } + + if input == nil { + input = &InputService9TestShapeInputService9TestCaseOperation2Input{} + } + + output = &InputService9TestShapeInputService9TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService9TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService9TestCaseOperation2 for usage and error information. +func (c *InputService9ProtocolTest) InputService9TestCaseOperation2(input *InputService9TestShapeInputService9TestCaseOperation2Input) (*InputService9TestShapeInputService9TestCaseOperation2Output, error) { + req, out := c.InputService9TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService9TestCaseOperation2WithContext is the same as InputService9TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService9TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService9ProtocolTest) InputService9TestCaseOperation2WithContext(ctx aws.Context, input *InputService9TestShapeInputService9TestCaseOperation2Input, opts ...request.Option) (*InputService9TestShapeInputService9TestCaseOperation2Output, error) { + req, out := c.InputService9TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService9TestShapeInputService9TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService9TestShapeInputService9TestCaseOperation2Input struct { + _ struct{} `type:"structure"` + + Token *string `type:"string" idempotencyToken:"true"` +} + +// SetToken sets the Token field's value. +func (s *InputService9TestShapeInputService9TestCaseOperation2Input) SetToken(v string) *InputService9TestShapeInputService9TestCaseOperation2Input { + s.Token = &v + return s +} + +type InputService9TestShapeInputService9TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +// InputService10ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService10ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService10ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService10ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService10ProtocolTest client from just a session. +// svc := inputservice10protocoltest.New(mySession) +// +// // Create a InputService10ProtocolTest client with additional configuration +// svc := inputservice10protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService10ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService10ProtocolTest { + c := p.ClientConfig("inputservice10protocoltest", cfgs...) + return newInputService10ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService10ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService10ProtocolTest { + svc := &InputService10ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice10protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService10ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService10ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService10TestCaseOperation1 = "OperationName" + +// InputService10TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService10TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService10TestCaseOperation1 for more information on using the InputService10TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService10TestCaseOperation1Request method. +// req, resp := client.InputService10TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService10ProtocolTest) InputService10TestCaseOperation1Request(input *InputService10TestShapeInputService10TestCaseOperation2Input) (req *request.Request, output *InputService10TestShapeInputService10TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService10TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService10TestShapeInputService10TestCaseOperation2Input{} + } + + output = &InputService10TestShapeInputService10TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService10TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService10TestCaseOperation1 for usage and error information. +func (c *InputService10ProtocolTest) InputService10TestCaseOperation1(input *InputService10TestShapeInputService10TestCaseOperation2Input) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) { + req, out := c.InputService10TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService10TestCaseOperation1WithContext is the same as InputService10TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService10TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService10ProtocolTest) InputService10TestCaseOperation1WithContext(ctx aws.Context, input *InputService10TestShapeInputService10TestCaseOperation2Input, opts ...request.Option) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) { + req, out := c.InputService10TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService10TestCaseOperation2 = "OperationName" + +// InputService10TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService10TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService10TestCaseOperation2 for more information on using the InputService10TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService10TestCaseOperation2Request method. +// req, resp := client.InputService10TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService10ProtocolTest) InputService10TestCaseOperation2Request(input *InputService10TestShapeInputService10TestCaseOperation2Input) (req *request.Request, output *InputService10TestShapeInputService10TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService10TestCaseOperation2, + HTTPPath: "/", + } + + if input == nil { + input = &InputService10TestShapeInputService10TestCaseOperation2Input{} + } + + output = &InputService10TestShapeInputService10TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(ec2query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService10TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService10TestCaseOperation2 for usage and error information. +func (c *InputService10ProtocolTest) InputService10TestCaseOperation2(input *InputService10TestShapeInputService10TestCaseOperation2Input) (*InputService10TestShapeInputService10TestCaseOperation2Output, error) { + req, out := c.InputService10TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService10TestCaseOperation2WithContext is the same as InputService10TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService10TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService10ProtocolTest) InputService10TestCaseOperation2WithContext(ctx aws.Context, input *InputService10TestShapeInputService10TestCaseOperation2Input, opts ...request.Option) (*InputService10TestShapeInputService10TestCaseOperation2Output, error) { + req, out := c.InputService10TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService10TestShapeInputService10TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService10TestShapeInputService10TestCaseOperation2Input struct { + _ struct{} `type:"structure"` + + FooEnum *string `type:"string" enum:"InputService10TestShapeEnumType"` + + ListEnums []*string `type:"list"` +} + +// SetFooEnum sets the FooEnum field's value. +func (s *InputService10TestShapeInputService10TestCaseOperation2Input) SetFooEnum(v string) *InputService10TestShapeInputService10TestCaseOperation2Input { + s.FooEnum = &v + return s +} + +// SetListEnums sets the ListEnums field's value. +func (s *InputService10TestShapeInputService10TestCaseOperation2Input) SetListEnums(v []*string) *InputService10TestShapeInputService10TestCaseOperation2Input { + s.ListEnums = v + return s +} + +type InputService10TestShapeInputService10TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +const ( + // EnumTypeFoo is a InputService10TestShapeEnumType enum value + EnumTypeFoo = "foo" + + // EnumTypeBar is a InputService10TestShapeEnumType enum value + EnumTypeBar = "bar" +) + +// +// Tests begin here +// + +func TestInputService1ProtocolTestScalarMembersCase1(t *testing.T) { + svc := NewInputService1ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService1TestShapeInputService1TestCaseOperation1Input{ + Bar: aws.String("val2"), + Foo: aws.String("val1"), + } + req, _ := svc.InputService1TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Bar=val2&Foo=val1&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService2ProtocolTestStructureWithLocationNameAndQueryNameAppliedToMembersCase1(t *testing.T) { + svc := NewInputService2ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService2TestShapeInputService2TestCaseOperation1Input{ + Bar: aws.String("val2"), + Foo: aws.String("val1"), + Yuck: aws.String("val3"), + } + req, _ := svc.InputService2TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&BarLocationName=val2&Foo=val1&Version=2014-01-01&yuckQueryName=val3`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService3ProtocolTestNestedStructureMembersCase1(t *testing.T) { + svc := NewInputService3ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService3TestShapeInputService3TestCaseOperation1Input{ + StructArg: &InputService3TestShapeStructType{ + ScalarArg: aws.String("foo"), + }, + } + req, _ := svc.InputService3TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Struct.Scalar=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService4ProtocolTestListTypesCase1(t *testing.T) { + svc := NewInputService4ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService4TestShapeInputService4TestCaseOperation1Input{ + ListBools: []*bool{ + aws.Bool(true), + aws.Bool(false), + aws.Bool(false), + }, + ListFloats: []*float64{ + aws.Float64(1.1), + aws.Float64(2.718), + aws.Float64(3.14), + }, + ListIntegers: []*int64{ + aws.Int64(0), + aws.Int64(1), + aws.Int64(2), + }, + ListStrings: []*string{ + aws.String("foo"), + aws.String("bar"), + aws.String("baz"), + }, + } + req, _ := svc.InputService4TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListBools.1=true&ListBools.2=false&ListBools.3=false&ListFloats.1=1.1&ListFloats.2=2.718&ListFloats.3=3.14&ListIntegers.1=0&ListIntegers.2=1&ListIntegers.3=2&ListStrings.1=foo&ListStrings.2=bar&ListStrings.3=baz&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService5ProtocolTestListWithLocationNameAppliedToMemberCase1(t *testing.T) { + svc := NewInputService5ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService5TestShapeInputService5TestCaseOperation1Input{ + ListArg: []*string{ + aws.String("a"), + aws.String("b"), + aws.String("c"), + }, + } + req, _ := svc.InputService5TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListMemberName.1=a&ListMemberName.2=b&ListMemberName.3=c&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService6ProtocolTestListWithLocationNameAndQueryNameCase1(t *testing.T) { + svc := NewInputService6ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService6TestShapeInputService6TestCaseOperation1Input{ + ListArg: []*string{ + aws.String("a"), + aws.String("b"), + aws.String("c"), + }, + } + req, _ := svc.InputService6TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListQueryName.1=a&ListQueryName.2=b&ListQueryName.3=c&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService7ProtocolTestBase64EncodedBlobsCase1(t *testing.T) { + svc := NewInputService7ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService7TestShapeInputService7TestCaseOperation1Input{ + BlobArg: []byte("foo"), + } + req, _ := svc.InputService7TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&BlobArg=Zm9v&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) { + svc := NewInputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService8TestShapeInputService8TestCaseOperation1Input{ + TimeArg: aws.Time(time.Unix(1422172800, 0)), + } + req, _ := svc.InputService8TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&TimeArg=2015-01-25T08%3A00%3A00Z&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService9ProtocolTestIdempotencyTokenAutoFillCase1(t *testing.T) { + svc := NewInputService9ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService9TestShapeInputService9TestCaseOperation2Input{ + Token: aws.String("abc123"), + } + req, _ := svc.InputService9TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Token=abc123&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService9ProtocolTestIdempotencyTokenAutoFillCase2(t *testing.T) { + svc := NewInputService9ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService9TestShapeInputService9TestCaseOperation2Input{} + req, _ := svc.InputService9TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Token=00000000-0000-4000-8000-000000000000&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService10ProtocolTestEnumCase1(t *testing.T) { + svc := NewInputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService10TestShapeInputService10TestCaseOperation2Input{ + ListEnums: []*string{ + aws.String("foo"), + aws.String(""), + aws.String("bar"), + }, + } + req, _ := svc.InputService10TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListEnums.1=foo&ListEnums.2=&ListEnums.3=bar&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService10ProtocolTestEnumCase2(t *testing.T) { + svc := NewInputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService10TestShapeInputService10TestCaseOperation2Input{} + req, _ := svc.InputService10TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + ec2query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal_test.go new file mode 100644 index 000000000..0e2377c36 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/ec2query/unmarshal_test.go @@ -0,0 +1,1869 @@ +package ec2query_test + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/ec2query" + "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" + "github.com/aws/aws-sdk-go/private/util" +) + +var _ bytes.Buffer // always import bytes +var _ http.Request +var _ json.Marshaler +var _ time.Time +var _ xmlutil.XMLNode +var _ xml.Attr +var _ = ioutil.Discard +var _ = util.Trim("") +var _ = url.Values{} +var _ = io.EOF +var _ = aws.String +var _ = fmt.Println +var _ = reflect.Value{} + +func init() { + protocol.RandReader = &awstesting.ZeroReader{} +} + +// OutputService1ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService1ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService1ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService1ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService1ProtocolTest client from just a session. +// svc := outputservice1protocoltest.New(mySession) +// +// // Create a OutputService1ProtocolTest client with additional configuration +// svc := outputservice1protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService1ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService1ProtocolTest { + c := p.ClientConfig("outputservice1protocoltest", cfgs...) + return newOutputService1ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService1ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService1ProtocolTest { + svc := &OutputService1ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice1protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService1ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService1ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService1TestCaseOperation1 = "OperationName" + +// OutputService1TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService1TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService1TestCaseOperation1 for more information on using the OutputService1TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService1TestCaseOperation1Request method. +// req, resp := client.OutputService1TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1Request(input *OutputService1TestShapeOutputService1TestCaseOperation1Input) (req *request.Request, output *OutputService1TestShapeOutputService1TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService1TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService1TestShapeOutputService1TestCaseOperation1Input{} + } + + output = &OutputService1TestShapeOutputService1TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService1TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService1TestCaseOperation1 for usage and error information. +func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1(input *OutputService1TestShapeOutputService1TestCaseOperation1Input) (*OutputService1TestShapeOutputService1TestCaseOperation1Output, error) { + req, out := c.OutputService1TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService1TestCaseOperation1WithContext is the same as OutputService1TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService1TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1WithContext(ctx aws.Context, input *OutputService1TestShapeOutputService1TestCaseOperation1Input, opts ...request.Option) (*OutputService1TestShapeOutputService1TestCaseOperation1Output, error) { + req, out := c.OutputService1TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService1TestShapeOutputService1TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService1TestShapeOutputService1TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Char *string `type:"character"` + + Double *float64 `type:"double"` + + FalseBool *bool `type:"boolean"` + + Float *float64 `type:"float"` + + Long *int64 `type:"long"` + + Num *int64 `locationName:"FooNum" type:"integer"` + + Str *string `type:"string"` + + TrueBool *bool `type:"boolean"` +} + +// SetChar sets the Char field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetChar(v string) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Char = &v + return s +} + +// SetDouble sets the Double field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetDouble(v float64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Double = &v + return s +} + +// SetFalseBool sets the FalseBool field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetFalseBool(v bool) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.FalseBool = &v + return s +} + +// SetFloat sets the Float field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetFloat(v float64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Float = &v + return s +} + +// SetLong sets the Long field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetLong(v int64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Long = &v + return s +} + +// SetNum sets the Num field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetNum(v int64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Num = &v + return s +} + +// SetStr sets the Str field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetStr(v string) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Str = &v + return s +} + +// SetTrueBool sets the TrueBool field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetTrueBool(v bool) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.TrueBool = &v + return s +} + +// OutputService2ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService2ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService2ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService2ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService2ProtocolTest client from just a session. +// svc := outputservice2protocoltest.New(mySession) +// +// // Create a OutputService2ProtocolTest client with additional configuration +// svc := outputservice2protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService2ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService2ProtocolTest { + c := p.ClientConfig("outputservice2protocoltest", cfgs...) + return newOutputService2ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService2ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService2ProtocolTest { + svc := &OutputService2ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice2protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService2ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService2ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService2TestCaseOperation1 = "OperationName" + +// OutputService2TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService2TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService2TestCaseOperation1 for more information on using the OutputService2TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService2TestCaseOperation1Request method. +// req, resp := client.OutputService2TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1Request(input *OutputService2TestShapeOutputService2TestCaseOperation1Input) (req *request.Request, output *OutputService2TestShapeOutputService2TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService2TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService2TestShapeOutputService2TestCaseOperation1Input{} + } + + output = &OutputService2TestShapeOutputService2TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService2TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService2TestCaseOperation1 for usage and error information. +func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1(input *OutputService2TestShapeOutputService2TestCaseOperation1Input) (*OutputService2TestShapeOutputService2TestCaseOperation1Output, error) { + req, out := c.OutputService2TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService2TestCaseOperation1WithContext is the same as OutputService2TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService2TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1WithContext(ctx aws.Context, input *OutputService2TestShapeOutputService2TestCaseOperation1Input, opts ...request.Option) (*OutputService2TestShapeOutputService2TestCaseOperation1Output, error) { + req, out := c.OutputService2TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService2TestShapeOutputService2TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService2TestShapeOutputService2TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + // Blob is automatically base64 encoded/decoded by the SDK. + Blob []byte `type:"blob"` +} + +// SetBlob sets the Blob field's value. +func (s *OutputService2TestShapeOutputService2TestCaseOperation1Output) SetBlob(v []byte) *OutputService2TestShapeOutputService2TestCaseOperation1Output { + s.Blob = v + return s +} + +// OutputService3ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService3ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService3ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService3ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService3ProtocolTest client from just a session. +// svc := outputservice3protocoltest.New(mySession) +// +// // Create a OutputService3ProtocolTest client with additional configuration +// svc := outputservice3protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService3ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService3ProtocolTest { + c := p.ClientConfig("outputservice3protocoltest", cfgs...) + return newOutputService3ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService3ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService3ProtocolTest { + svc := &OutputService3ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice3protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService3ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService3ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService3TestCaseOperation1 = "OperationName" + +// OutputService3TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService3TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService3TestCaseOperation1 for more information on using the OutputService3TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService3TestCaseOperation1Request method. +// req, resp := client.OutputService3TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1Request(input *OutputService3TestShapeOutputService3TestCaseOperation1Input) (req *request.Request, output *OutputService3TestShapeOutputService3TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService3TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService3TestShapeOutputService3TestCaseOperation1Input{} + } + + output = &OutputService3TestShapeOutputService3TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService3TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService3TestCaseOperation1 for usage and error information. +func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1(input *OutputService3TestShapeOutputService3TestCaseOperation1Input) (*OutputService3TestShapeOutputService3TestCaseOperation1Output, error) { + req, out := c.OutputService3TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService3TestCaseOperation1WithContext is the same as OutputService3TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService3TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1WithContext(ctx aws.Context, input *OutputService3TestShapeOutputService3TestCaseOperation1Input, opts ...request.Option) (*OutputService3TestShapeOutputService3TestCaseOperation1Output, error) { + req, out := c.OutputService3TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService3TestShapeOutputService3TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService3TestShapeOutputService3TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `type:"list"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetListMember(v []*string) *OutputService3TestShapeOutputService3TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService4ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService4ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService4ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService4ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService4ProtocolTest client from just a session. +// svc := outputservice4protocoltest.New(mySession) +// +// // Create a OutputService4ProtocolTest client with additional configuration +// svc := outputservice4protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService4ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService4ProtocolTest { + c := p.ClientConfig("outputservice4protocoltest", cfgs...) + return newOutputService4ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService4ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService4ProtocolTest { + svc := &OutputService4ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice4protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService4ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService4ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService4TestCaseOperation1 = "OperationName" + +// OutputService4TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService4TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService4TestCaseOperation1 for more information on using the OutputService4TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService4TestCaseOperation1Request method. +// req, resp := client.OutputService4TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (req *request.Request, output *OutputService4TestShapeOutputService4TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService4TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService4TestShapeOutputService4TestCaseOperation1Input{} + } + + output = &OutputService4TestShapeOutputService4TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService4TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService4TestCaseOperation1 for usage and error information. +func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (*OutputService4TestShapeOutputService4TestCaseOperation1Output, error) { + req, out := c.OutputService4TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService4TestCaseOperation1WithContext is the same as OutputService4TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService4TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1WithContext(ctx aws.Context, input *OutputService4TestShapeOutputService4TestCaseOperation1Input, opts ...request.Option) (*OutputService4TestShapeOutputService4TestCaseOperation1Output, error) { + req, out := c.OutputService4TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService4TestShapeOutputService4TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService4TestShapeOutputService4TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `locationNameList:"item" type:"list"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService4TestShapeOutputService4TestCaseOperation1Output) SetListMember(v []*string) *OutputService4TestShapeOutputService4TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService5ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService5ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService5ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService5ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService5ProtocolTest client from just a session. +// svc := outputservice5protocoltest.New(mySession) +// +// // Create a OutputService5ProtocolTest client with additional configuration +// svc := outputservice5protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService5ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService5ProtocolTest { + c := p.ClientConfig("outputservice5protocoltest", cfgs...) + return newOutputService5ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService5ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService5ProtocolTest { + svc := &OutputService5ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice5protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService5ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService5ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService5TestCaseOperation1 = "OperationName" + +// OutputService5TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService5TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService5TestCaseOperation1 for more information on using the OutputService5TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService5TestCaseOperation1Request method. +// req, resp := client.OutputService5TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1Request(input *OutputService5TestShapeOutputService5TestCaseOperation1Input) (req *request.Request, output *OutputService5TestShapeOutputService5TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService5TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService5TestShapeOutputService5TestCaseOperation1Input{} + } + + output = &OutputService5TestShapeOutputService5TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService5TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService5TestCaseOperation1 for usage and error information. +func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1(input *OutputService5TestShapeOutputService5TestCaseOperation1Input) (*OutputService5TestShapeOutputService5TestCaseOperation1Output, error) { + req, out := c.OutputService5TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService5TestCaseOperation1WithContext is the same as OutputService5TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService5TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1WithContext(ctx aws.Context, input *OutputService5TestShapeOutputService5TestCaseOperation1Input, opts ...request.Option) (*OutputService5TestShapeOutputService5TestCaseOperation1Output, error) { + req, out := c.OutputService5TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService5TestShapeOutputService5TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService5TestShapeOutputService5TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `type:"list" flattened:"true"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService5TestShapeOutputService5TestCaseOperation1Output) SetListMember(v []*string) *OutputService5TestShapeOutputService5TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService6ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService6ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService6ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService6ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService6ProtocolTest client from just a session. +// svc := outputservice6protocoltest.New(mySession) +// +// // Create a OutputService6ProtocolTest client with additional configuration +// svc := outputservice6protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService6ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService6ProtocolTest { + c := p.ClientConfig("outputservice6protocoltest", cfgs...) + return newOutputService6ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService6ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService6ProtocolTest { + svc := &OutputService6ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice6protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService6ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService6ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService6TestCaseOperation1 = "OperationName" + +// OutputService6TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService6TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService6TestCaseOperation1 for more information on using the OutputService6TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService6TestCaseOperation1Request method. +// req, resp := client.OutputService6TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1Request(input *OutputService6TestShapeOutputService6TestCaseOperation1Input) (req *request.Request, output *OutputService6TestShapeOutputService6TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService6TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService6TestShapeOutputService6TestCaseOperation1Input{} + } + + output = &OutputService6TestShapeOutputService6TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService6TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService6TestCaseOperation1 for usage and error information. +func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1(input *OutputService6TestShapeOutputService6TestCaseOperation1Input) (*OutputService6TestShapeOutputService6TestCaseOperation1Output, error) { + req, out := c.OutputService6TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService6TestCaseOperation1WithContext is the same as OutputService6TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService6TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1WithContext(ctx aws.Context, input *OutputService6TestShapeOutputService6TestCaseOperation1Input, opts ...request.Option) (*OutputService6TestShapeOutputService6TestCaseOperation1Output, error) { + req, out := c.OutputService6TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService6TestShapeOutputService6TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService6TestShapeOutputService6TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*OutputService6TestShapeStructureType `type:"map"` +} + +// SetMap sets the Map field's value. +func (s *OutputService6TestShapeOutputService6TestCaseOperation1Output) SetMap(v map[string]*OutputService6TestShapeStructureType) *OutputService6TestShapeOutputService6TestCaseOperation1Output { + s.Map = v + return s +} + +type OutputService6TestShapeStructureType struct { + _ struct{} `type:"structure"` + + Foo *string `locationName:"foo" type:"string"` +} + +// SetFoo sets the Foo field's value. +func (s *OutputService6TestShapeStructureType) SetFoo(v string) *OutputService6TestShapeStructureType { + s.Foo = &v + return s +} + +// OutputService7ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService7ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService7ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService7ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService7ProtocolTest client from just a session. +// svc := outputservice7protocoltest.New(mySession) +// +// // Create a OutputService7ProtocolTest client with additional configuration +// svc := outputservice7protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService7ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService7ProtocolTest { + c := p.ClientConfig("outputservice7protocoltest", cfgs...) + return newOutputService7ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService7ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService7ProtocolTest { + svc := &OutputService7ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice7protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService7ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService7ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService7TestCaseOperation1 = "OperationName" + +// OutputService7TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService7TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService7TestCaseOperation1 for more information on using the OutputService7TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService7TestCaseOperation1Request method. +// req, resp := client.OutputService7TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1Request(input *OutputService7TestShapeOutputService7TestCaseOperation1Input) (req *request.Request, output *OutputService7TestShapeOutputService7TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService7TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService7TestShapeOutputService7TestCaseOperation1Input{} + } + + output = &OutputService7TestShapeOutputService7TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService7TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService7TestCaseOperation1 for usage and error information. +func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1(input *OutputService7TestShapeOutputService7TestCaseOperation1Input) (*OutputService7TestShapeOutputService7TestCaseOperation1Output, error) { + req, out := c.OutputService7TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService7TestCaseOperation1WithContext is the same as OutputService7TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService7TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1WithContext(ctx aws.Context, input *OutputService7TestShapeOutputService7TestCaseOperation1Input, opts ...request.Option) (*OutputService7TestShapeOutputService7TestCaseOperation1Output, error) { + req, out := c.OutputService7TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService7TestShapeOutputService7TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService7TestShapeOutputService7TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*string `type:"map" flattened:"true"` +} + +// SetMap sets the Map field's value. +func (s *OutputService7TestShapeOutputService7TestCaseOperation1Output) SetMap(v map[string]*string) *OutputService7TestShapeOutputService7TestCaseOperation1Output { + s.Map = v + return s +} + +// OutputService8ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService8ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService8ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService8ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService8ProtocolTest client from just a session. +// svc := outputservice8protocoltest.New(mySession) +// +// // Create a OutputService8ProtocolTest client with additional configuration +// svc := outputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService8ProtocolTest { + c := p.ClientConfig("outputservice8protocoltest", cfgs...) + return newOutputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService8ProtocolTest { + svc := &OutputService8ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice8protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService8ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService8ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService8TestCaseOperation1 = "OperationName" + +// OutputService8TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService8TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService8TestCaseOperation1 for more information on using the OutputService8TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService8TestCaseOperation1Request method. +// req, resp := client.OutputService8TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1Request(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (req *request.Request, output *OutputService8TestShapeOutputService8TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService8TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService8TestShapeOutputService8TestCaseOperation1Input{} + } + + output = &OutputService8TestShapeOutputService8TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService8TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService8TestCaseOperation1 for usage and error information. +func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (*OutputService8TestShapeOutputService8TestCaseOperation1Output, error) { + req, out := c.OutputService8TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService8TestCaseOperation1WithContext is the same as OutputService8TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService8TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1WithContext(ctx aws.Context, input *OutputService8TestShapeOutputService8TestCaseOperation1Input, opts ...request.Option) (*OutputService8TestShapeOutputService8TestCaseOperation1Output, error) { + req, out := c.OutputService8TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService8TestShapeOutputService8TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService8TestShapeOutputService8TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*string `locationNameKey:"foo" locationNameValue:"bar" type:"map" flattened:"true"` +} + +// SetMap sets the Map field's value. +func (s *OutputService8TestShapeOutputService8TestCaseOperation1Output) SetMap(v map[string]*string) *OutputService8TestShapeOutputService8TestCaseOperation1Output { + s.Map = v + return s +} + +// OutputService9ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService9ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService9ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService9ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService9ProtocolTest client from just a session. +// svc := outputservice9protocoltest.New(mySession) +// +// // Create a OutputService9ProtocolTest client with additional configuration +// svc := outputservice9protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService9ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService9ProtocolTest { + c := p.ClientConfig("outputservice9protocoltest", cfgs...) + return newOutputService9ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService9ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService9ProtocolTest { + svc := &OutputService9ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice9protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService9ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService9ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService9TestCaseOperation1 = "OperationName" + +// OutputService9TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService9TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService9TestCaseOperation1 for more information on using the OutputService9TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService9TestCaseOperation1Request method. +// req, resp := client.OutputService9TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1Request(input *OutputService9TestShapeOutputService9TestCaseOperation1Input) (req *request.Request, output *OutputService9TestShapeOutputService9TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService9TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService9TestShapeOutputService9TestCaseOperation1Input{} + } + + output = &OutputService9TestShapeOutputService9TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService9TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService9TestCaseOperation1 for usage and error information. +func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1(input *OutputService9TestShapeOutputService9TestCaseOperation1Input) (*OutputService9TestShapeOutputService9TestCaseOperation1Output, error) { + req, out := c.OutputService9TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService9TestCaseOperation1WithContext is the same as OutputService9TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService9TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1WithContext(ctx aws.Context, input *OutputService9TestShapeOutputService9TestCaseOperation1Input, opts ...request.Option) (*OutputService9TestShapeOutputService9TestCaseOperation1Output, error) { + req, out := c.OutputService9TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService9TestShapeOutputService9TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService9TestShapeOutputService9TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Foo *string `type:"string"` +} + +// SetFoo sets the Foo field's value. +func (s *OutputService9TestShapeOutputService9TestCaseOperation1Output) SetFoo(v string) *OutputService9TestShapeOutputService9TestCaseOperation1Output { + s.Foo = &v + return s +} + +// OutputService10ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService10ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService10ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService10ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService10ProtocolTest client from just a session. +// svc := outputservice10protocoltest.New(mySession) +// +// // Create a OutputService10ProtocolTest client with additional configuration +// svc := outputservice10protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService10ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService10ProtocolTest { + c := p.ClientConfig("outputservice10protocoltest", cfgs...) + return newOutputService10ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService10ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService10ProtocolTest { + svc := &OutputService10ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice10protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(ec2query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(ec2query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(ec2query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(ec2query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService10ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService10ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService10TestCaseOperation1 = "OperationName" + +// OutputService10TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService10TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService10TestCaseOperation1 for more information on using the OutputService10TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService10TestCaseOperation1Request method. +// req, resp := client.OutputService10TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService10ProtocolTest) OutputService10TestCaseOperation1Request(input *OutputService10TestShapeOutputService10TestCaseOperation1Input) (req *request.Request, output *OutputService10TestShapeOutputService10TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService10TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService10TestShapeOutputService10TestCaseOperation1Input{} + } + + output = &OutputService10TestShapeOutputService10TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService10TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService10TestCaseOperation1 for usage and error information. +func (c *OutputService10ProtocolTest) OutputService10TestCaseOperation1(input *OutputService10TestShapeOutputService10TestCaseOperation1Input) (*OutputService10TestShapeOutputService10TestCaseOperation1Output, error) { + req, out := c.OutputService10TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService10TestCaseOperation1WithContext is the same as OutputService10TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService10TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService10ProtocolTest) OutputService10TestCaseOperation1WithContext(ctx aws.Context, input *OutputService10TestShapeOutputService10TestCaseOperation1Input, opts ...request.Option) (*OutputService10TestShapeOutputService10TestCaseOperation1Output, error) { + req, out := c.OutputService10TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService10TestShapeOutputService10TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService10TestShapeOutputService10TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + FooEnum *string `type:"string" enum:"OutputService10TestShapeEC2EnumType"` + + ListEnums []*string `type:"list"` +} + +// SetFooEnum sets the FooEnum field's value. +func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetFooEnum(v string) *OutputService10TestShapeOutputService10TestCaseOperation1Output { + s.FooEnum = &v + return s +} + +// SetListEnums sets the ListEnums field's value. +func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetListEnums(v []*string) *OutputService10TestShapeOutputService10TestCaseOperation1Output { + s.ListEnums = v + return s +} + +const ( + // EC2EnumTypeFoo is a OutputService10TestShapeEC2EnumType enum value + EC2EnumTypeFoo = "foo" + + // EC2EnumTypeBar is a OutputService10TestShapeEC2EnumType enum value + EC2EnumTypeBar = "bar" +) + +// +// Tests begin here +// + +func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) { + svc := NewOutputService1ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("myname123falsetrue1.21.3200arequest-id")) + req, out := svc.OutputService1TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "a", *out.Char; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := 1.3, *out.Double; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := false, *out.FalseBool; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := 1.2, *out.Float; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := int64(200), *out.Long; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := int64(123), *out.Num; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "myname", *out.Str; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := true, *out.TrueBool; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService2ProtocolTestBlobCase1(t *testing.T) { + svc := NewOutputService2ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("dmFsdWU=requestid")) + req, out := svc.OutputService2TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "value", string(out.Blob); e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService3ProtocolTestListsCase1(t *testing.T) { + svc := NewOutputService3ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abc123requestid")) + req, out := svc.OutputService3TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "123", *out.ListMember[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService4ProtocolTestListWithCustomMemberNameCase1(t *testing.T) { + svc := NewOutputService4ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abc123requestid")) + req, out := svc.OutputService4TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "123", *out.ListMember[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService5ProtocolTestFlattenedListCase1(t *testing.T) { + svc := NewOutputService5ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abc123requestid")) + req, out := svc.OutputService5TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "123", *out.ListMember[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService6ProtocolTestNormalMapCase1(t *testing.T) { + svc := NewOutputService6ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarbazbamrequestid")) + req, out := svc.OutputService6TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bam", *out.Map["baz"].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.Map["qux"].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService7ProtocolTestFlattenedMapCase1(t *testing.T) { + svc := NewOutputService7ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarbazbamrequestid")) + req, out := svc.OutputService7TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bam", *out.Map["baz"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.Map["qux"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService8ProtocolTestNamedMapCase1(t *testing.T) { + svc := NewOutputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarbazbamrequestid")) + req, out := svc.OutputService8TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bam", *out.Map["baz"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.Map["qux"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService9ProtocolTestEmptyStringCase1(t *testing.T) { + svc := NewOutputService9ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("requestid")) + req, out := svc.OutputService9TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "", *out.Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService10ProtocolTestEnumOutputCase1(t *testing.T) { + svc := NewOutputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("foofoobar")) + req, out := svc.OutputService10TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + ec2query.UnmarshalMeta(req) + ec2query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "foo", *out.FooEnum; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "foo", *out.ListEnums[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.ListEnums[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency_test.go new file mode 100644 index 000000000..b6ea23562 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/idempotency_test.go @@ -0,0 +1,106 @@ +package protocol_test + +import ( + "reflect" + "testing" + + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/stretchr/testify/assert" +) + +func TestCanSetIdempotencyToken(t *testing.T) { + cases := []struct { + CanSet bool + Case interface{} + }{ + { + true, + struct { + Field *string `idempotencyToken:"true"` + }{}, + }, + { + true, + struct { + Field string `idempotencyToken:"true"` + }{}, + }, + { + false, + struct { + Field *string `idempotencyToken:"true"` + }{Field: new(string)}, + }, + { + false, + struct { + Field string `idempotencyToken:"true"` + }{Field: "value"}, + }, + { + false, + struct { + Field *int `idempotencyToken:"true"` + }{}, + }, + { + false, + struct { + Field *string + }{}, + }, + } + + for i, c := range cases { + v := reflect.Indirect(reflect.ValueOf(c.Case)) + ty := v.Type() + canSet := protocol.CanSetIdempotencyToken(v.Field(0), ty.Field(0)) + assert.Equal(t, c.CanSet, canSet, "Expect case %d can set to match", i) + } +} + +func TestSetIdempotencyToken(t *testing.T) { + cases := []struct { + Case interface{} + }{ + { + &struct { + Field *string `idempotencyToken:"true"` + }{}, + }, + { + &struct { + Field string `idempotencyToken:"true"` + }{}, + }, + { + &struct { + Field *string `idempotencyToken:"true"` + }{Field: new(string)}, + }, + { + &struct { + Field string `idempotencyToken:"true"` + }{Field: ""}, + }, + } + + for i, c := range cases { + v := reflect.Indirect(reflect.ValueOf(c.Case)) + + protocol.SetIdempotencyToken(v.Field(0)) + assert.NotEmpty(t, v.Field(0).Interface(), "Expect case %d to be set", i) + } +} + +func TestUUIDVersion4(t *testing.T) { + uuid := protocol.UUIDVersion4(make([]byte, 16)) + assert.Equal(t, `00000000-0000-4000-8000-000000000000`, uuid) + + b := make([]byte, 16) + for i := 0; i < len(b); i++ { + b[i] = 1 + } + uuid = protocol.UUIDVersion4(b) + assert.Equal(t, `01010101-0101-4101-8101-010101010101`, uuid) +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue_test.go new file mode 100644 index 000000000..66a3c8cde --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/jsonvalue_test.go @@ -0,0 +1,93 @@ +package protocol + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" +) + +var testJSONValueCases = []struct { + Value aws.JSONValue + Mode EscapeMode + String string +}{ + { + Value: aws.JSONValue{ + "abc": 123., + }, + Mode: NoEscape, + String: `{"abc":123}`, + }, + { + Value: aws.JSONValue{ + "abc": 123., + }, + Mode: Base64Escape, + String: `eyJhYmMiOjEyM30=`, + }, + { + Value: aws.JSONValue{ + "abc": 123., + }, + Mode: QuotedEscape, + String: `"{\"abc\":123}"`, + }, +} + +func TestEncodeJSONValue(t *testing.T) { + for i, c := range testJSONValueCases { + str, err := EncodeJSONValue(c.Value, c.Mode) + if err != nil { + t.Fatalf("%d, expect no error, got %v", i, err) + } + if e, a := c.String, str; e != a { + t.Errorf("%d, expect %v encoded value, got %v", i, e, a) + } + } +} + +func TestDecodeJSONValue(t *testing.T) { + for i, c := range testJSONValueCases { + val, err := DecodeJSONValue(c.String, c.Mode) + if err != nil { + t.Fatalf("%d, expect no error, got %v", i, err) + } + if e, a := c.Value, val; !reflect.DeepEqual(e, a) { + t.Errorf("%d, expect %v encoded value, got %v", i, e, a) + } + } +} + +func TestEncodeJSONValue_PanicUnkownMode(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("expect panic, got none") + } else { + reason := fmt.Sprintf("%v", r) + if e, a := "unknown EscapeMode", reason; !strings.Contains(a, e) { + t.Errorf("expect %q to be in %v", e, a) + } + } + }() + + val := aws.JSONValue{} + + EncodeJSONValue(val, 123456) +} +func TestDecodeJSONValue_PanicUnkownMode(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("expect panic, got none") + } else { + reason := fmt.Sprintf("%v", r) + if e, a := "unknown EscapeMode", reason; !strings.Contains(a, e) { + t.Errorf("expect %q to be in %v", e, a) + } + } + }() + + DecodeJSONValue(`{"abc":123}`, 123456) +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/protocol_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/protocol_test.go new file mode 100644 index 000000000..eb2e155be --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/protocol_test.go @@ -0,0 +1,203 @@ +package protocol_test + +import ( + "net/http" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/ec2query" + "github.com/aws/aws-sdk-go/private/protocol/jsonrpc" + "github.com/aws/aws-sdk-go/private/protocol/query" + "github.com/aws/aws-sdk-go/private/protocol/rest" + "github.com/aws/aws-sdk-go/private/protocol/restjson" + "github.com/aws/aws-sdk-go/private/protocol/restxml" +) + +func xmlData(set bool, b []byte, size, delta int) { + const openingTags = "" + const closingTags = "" + if !set { + copy(b, []byte(openingTags)) + } + if size == 0 { + copy(b[delta-len(closingTags):], []byte(closingTags)) + } +} + +func jsonData(set bool, b []byte, size, delta int) { + if !set { + copy(b, []byte("{\"A\": \"")) + } + if size == 0 { + copy(b[delta-len("\"}"):], []byte("\"}")) + } +} + +func buildNewRequest(data interface{}) *request.Request { + v := url.Values{} + v.Set("test", "TEST") + v.Add("test1", "TEST1") + + req := &request.Request{ + HTTPRequest: &http.Request{ + Header: make(http.Header), + Body: &awstesting.ReadCloser{Size: 2048}, + URL: &url.URL{ + RawQuery: v.Encode(), + }, + }, + Params: &struct { + LocationName string `locationName:"test"` + }{ + "Test", + }, + ClientInfo: metadata.ClientInfo{ + ServiceName: "test", + TargetPrefix: "test", + JSONVersion: "test", + APIVersion: "test", + Endpoint: "test", + SigningName: "test", + SigningRegion: "test", + }, + Operation: &request.Operation{ + Name: "test", + }, + } + req.HTTPResponse = &http.Response{ + Body: &awstesting.ReadCloser{Size: 2048}, + Header: http.Header{ + "X-Amzn-Requestid": []string{"1"}, + }, + StatusCode: http.StatusOK, + } + + if data == nil { + data = &struct { + _ struct{} `type:"structure"` + LocationName *string `locationName:"testName"` + Location *string `location:"statusCode"` + A *string `type:"string"` + }{} + } + + req.Data = data + + return req +} + +type expected struct { + dataType int + closed bool + size int + errExists bool +} + +const ( + jsonType = iota + xmlType +) + +func checkForLeak(data interface{}, build, fn func(*request.Request), t *testing.T, result expected) { + req := buildNewRequest(data) + reader := req.HTTPResponse.Body.(*awstesting.ReadCloser) + switch result.dataType { + case jsonType: + reader.FillData = jsonData + case xmlType: + reader.FillData = xmlData + } + build(req) + fn(req) + + if result.errExists { + assert.NotNil(t, req.Error) + } else { + assert.Nil(t, req.Error) + } + + assert.Equal(t, reader.Closed, result.closed) + assert.Equal(t, reader.Size, result.size) +} + +func TestJSONRpc(t *testing.T) { + checkForLeak(nil, jsonrpc.Build, jsonrpc.Unmarshal, t, expected{jsonType, true, 0, false}) + checkForLeak(nil, jsonrpc.Build, jsonrpc.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + checkForLeak(nil, jsonrpc.Build, jsonrpc.UnmarshalError, t, expected{jsonType, true, 0, true}) +} + +func TestQuery(t *testing.T) { + checkForLeak(nil, query.Build, query.Unmarshal, t, expected{jsonType, true, 0, false}) + checkForLeak(nil, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + checkForLeak(nil, query.Build, query.UnmarshalError, t, expected{jsonType, true, 0, true}) +} + +func TestRest(t *testing.T) { + // case 1: Payload io.ReadSeeker + checkForLeak(nil, rest.Build, rest.Unmarshal, t, expected{jsonType, false, 2048, false}) + checkForLeak(nil, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + + // case 2: Payload *string + // should close the body + dataStr := struct { + _ struct{} `type:"structure" payload:"Payload"` + LocationName *string `locationName:"testName"` + Location *string `location:"statusCode"` + A *string `type:"string"` + Payload *string `locationName:"payload" type:"blob" required:"true"` + }{} + checkForLeak(&dataStr, rest.Build, rest.Unmarshal, t, expected{jsonType, true, 0, false}) + checkForLeak(&dataStr, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + + // case 3: Payload []byte + // should close the body + dataBytes := struct { + _ struct{} `type:"structure" payload:"Payload"` + LocationName *string `locationName:"testName"` + Location *string `location:"statusCode"` + A *string `type:"string"` + Payload []byte `locationName:"payload" type:"blob" required:"true"` + }{} + checkForLeak(&dataBytes, rest.Build, rest.Unmarshal, t, expected{jsonType, true, 0, false}) + checkForLeak(&dataBytes, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + + // case 4: Payload unsupported type + // should close the body + dataUnsupported := struct { + _ struct{} `type:"structure" payload:"Payload"` + LocationName *string `locationName:"testName"` + Location *string `location:"statusCode"` + A *string `type:"string"` + Payload string `locationName:"payload" type:"blob" required:"true"` + }{} + checkForLeak(&dataUnsupported, rest.Build, rest.Unmarshal, t, expected{jsonType, true, 0, true}) + checkForLeak(&dataUnsupported, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) +} + +func TestRestJSON(t *testing.T) { + checkForLeak(nil, restjson.Build, restjson.Unmarshal, t, expected{jsonType, true, 0, false}) + checkForLeak(nil, restjson.Build, restjson.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + checkForLeak(nil, restjson.Build, restjson.UnmarshalError, t, expected{jsonType, true, 0, true}) +} + +func TestRestXML(t *testing.T) { + checkForLeak(nil, restxml.Build, restxml.Unmarshal, t, expected{xmlType, true, 0, false}) + checkForLeak(nil, restxml.Build, restxml.UnmarshalMeta, t, expected{xmlType, false, 2048, false}) + checkForLeak(nil, restxml.Build, restxml.UnmarshalError, t, expected{xmlType, true, 0, true}) +} + +func TestXML(t *testing.T) { + checkForLeak(nil, ec2query.Build, ec2query.Unmarshal, t, expected{jsonType, true, 0, false}) + checkForLeak(nil, ec2query.Build, ec2query.UnmarshalMeta, t, expected{jsonType, false, 2048, false}) + checkForLeak(nil, ec2query.Build, ec2query.UnmarshalError, t, expected{jsonType, true, 0, true}) +} + +func TestProtocol(t *testing.T) { + checkForLeak(nil, restxml.Build, protocol.UnmarshalDiscardBody, t, expected{xmlType, true, 0, false}) +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build_test.go new file mode 100644 index 000000000..0cef7b41a --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/build_test.go @@ -0,0 +1,4056 @@ +package query_test + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/query" + "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" + "github.com/aws/aws-sdk-go/private/util" +) + +var _ bytes.Buffer // always import bytes +var _ http.Request +var _ json.Marshaler +var _ time.Time +var _ xmlutil.XMLNode +var _ xml.Attr +var _ = ioutil.Discard +var _ = util.Trim("") +var _ = url.Values{} +var _ = io.EOF +var _ = aws.String +var _ = fmt.Println +var _ = reflect.Value{} + +func init() { + protocol.RandReader = &awstesting.ZeroReader{} +} + +// InputService1ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService1ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService1ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService1ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService1ProtocolTest client from just a session. +// svc := inputservice1protocoltest.New(mySession) +// +// // Create a InputService1ProtocolTest client with additional configuration +// svc := inputservice1protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService1ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService1ProtocolTest { + c := p.ClientConfig("inputservice1protocoltest", cfgs...) + return newInputService1ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService1ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService1ProtocolTest { + svc := &InputService1ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice1protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService1ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService1ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService1TestCaseOperation1 = "OperationName" + +// InputService1TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService1TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService1TestCaseOperation1 for more information on using the InputService1TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService1TestCaseOperation1Request method. +// req, resp := client.InputService1TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input *InputService1TestShapeInputService1TestCaseOperation3Input) (req *request.Request, output *InputService1TestShapeInputService1TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService1TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService1TestShapeInputService1TestCaseOperation3Input{} + } + + output = &InputService1TestShapeInputService1TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService1TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService1TestCaseOperation1 for usage and error information. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputService1TestCaseOperation3Input) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) { + req, out := c.InputService1TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService1TestCaseOperation1WithContext is the same as InputService1TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService1TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation1WithContext(ctx aws.Context, input *InputService1TestShapeInputService1TestCaseOperation3Input, opts ...request.Option) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) { + req, out := c.InputService1TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService1TestCaseOperation2 = "OperationName" + +// InputService1TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService1TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService1TestCaseOperation2 for more information on using the InputService1TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService1TestCaseOperation2Request method. +// req, resp := client.InputService1TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService1ProtocolTest) InputService1TestCaseOperation2Request(input *InputService1TestShapeInputService1TestCaseOperation3Input) (req *request.Request, output *InputService1TestShapeInputService1TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService1TestCaseOperation2, + HTTPPath: "/", + } + + if input == nil { + input = &InputService1TestShapeInputService1TestCaseOperation3Input{} + } + + output = &InputService1TestShapeInputService1TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService1TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService1TestCaseOperation2 for usage and error information. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation2(input *InputService1TestShapeInputService1TestCaseOperation3Input) (*InputService1TestShapeInputService1TestCaseOperation2Output, error) { + req, out := c.InputService1TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService1TestCaseOperation2WithContext is the same as InputService1TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService1TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation2WithContext(ctx aws.Context, input *InputService1TestShapeInputService1TestCaseOperation3Input, opts ...request.Option) (*InputService1TestShapeInputService1TestCaseOperation2Output, error) { + req, out := c.InputService1TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService1TestCaseOperation3 = "OperationName" + +// InputService1TestCaseOperation3Request generates a "aws/request.Request" representing the +// client's request for the InputService1TestCaseOperation3 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService1TestCaseOperation3 for more information on using the InputService1TestCaseOperation3 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService1TestCaseOperation3Request method. +// req, resp := client.InputService1TestCaseOperation3Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService1ProtocolTest) InputService1TestCaseOperation3Request(input *InputService1TestShapeInputService1TestCaseOperation3Input) (req *request.Request, output *InputService1TestShapeInputService1TestCaseOperation3Output) { + op := &request.Operation{ + Name: opInputService1TestCaseOperation3, + HTTPPath: "/", + } + + if input == nil { + input = &InputService1TestShapeInputService1TestCaseOperation3Input{} + } + + output = &InputService1TestShapeInputService1TestCaseOperation3Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService1TestCaseOperation3 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService1TestCaseOperation3 for usage and error information. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation3(input *InputService1TestShapeInputService1TestCaseOperation3Input) (*InputService1TestShapeInputService1TestCaseOperation3Output, error) { + req, out := c.InputService1TestCaseOperation3Request(input) + return out, req.Send() +} + +// InputService1TestCaseOperation3WithContext is the same as InputService1TestCaseOperation3 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService1TestCaseOperation3 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService1ProtocolTest) InputService1TestCaseOperation3WithContext(ctx aws.Context, input *InputService1TestShapeInputService1TestCaseOperation3Input, opts ...request.Option) (*InputService1TestShapeInputService1TestCaseOperation3Output, error) { + req, out := c.InputService1TestCaseOperation3Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService1TestShapeInputService1TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService1TestShapeInputService1TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +type InputService1TestShapeInputService1TestCaseOperation3Input struct { + _ struct{} `type:"structure"` + + Bar *string `type:"string"` + + Baz *bool `type:"boolean"` + + Foo *string `type:"string"` +} + +// SetBar sets the Bar field's value. +func (s *InputService1TestShapeInputService1TestCaseOperation3Input) SetBar(v string) *InputService1TestShapeInputService1TestCaseOperation3Input { + s.Bar = &v + return s +} + +// SetBaz sets the Baz field's value. +func (s *InputService1TestShapeInputService1TestCaseOperation3Input) SetBaz(v bool) *InputService1TestShapeInputService1TestCaseOperation3Input { + s.Baz = &v + return s +} + +// SetFoo sets the Foo field's value. +func (s *InputService1TestShapeInputService1TestCaseOperation3Input) SetFoo(v string) *InputService1TestShapeInputService1TestCaseOperation3Input { + s.Foo = &v + return s +} + +type InputService1TestShapeInputService1TestCaseOperation3Output struct { + _ struct{} `type:"structure"` +} + +// InputService2ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService2ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService2ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService2ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService2ProtocolTest client from just a session. +// svc := inputservice2protocoltest.New(mySession) +// +// // Create a InputService2ProtocolTest client with additional configuration +// svc := inputservice2protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService2ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService2ProtocolTest { + c := p.ClientConfig("inputservice2protocoltest", cfgs...) + return newInputService2ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService2ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService2ProtocolTest { + svc := &InputService2ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice2protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService2ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService2ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService2TestCaseOperation1 = "OperationName" + +// InputService2TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService2TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService2TestCaseOperation1 for more information on using the InputService2TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService2TestCaseOperation1Request method. +// req, resp := client.InputService2TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input *InputService2TestShapeInputService2TestCaseOperation1Input) (req *request.Request, output *InputService2TestShapeInputService2TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService2TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService2TestShapeInputService2TestCaseOperation1Input{} + } + + output = &InputService2TestShapeInputService2TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService2TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService2TestCaseOperation1 for usage and error information. +func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputService2TestCaseOperation1Input) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) { + req, out := c.InputService2TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService2TestCaseOperation1WithContext is the same as InputService2TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService2TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService2ProtocolTest) InputService2TestCaseOperation1WithContext(ctx aws.Context, input *InputService2TestShapeInputService2TestCaseOperation1Input, opts ...request.Option) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) { + req, out := c.InputService2TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService2TestShapeInputService2TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + StructArg *InputService2TestShapeStructType `type:"structure"` +} + +// SetStructArg sets the StructArg field's value. +func (s *InputService2TestShapeInputService2TestCaseOperation1Input) SetStructArg(v *InputService2TestShapeStructType) *InputService2TestShapeInputService2TestCaseOperation1Input { + s.StructArg = v + return s +} + +type InputService2TestShapeInputService2TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService2TestShapeStructType struct { + _ struct{} `type:"structure"` + + ScalarArg *string `type:"string"` +} + +// SetScalarArg sets the ScalarArg field's value. +func (s *InputService2TestShapeStructType) SetScalarArg(v string) *InputService2TestShapeStructType { + s.ScalarArg = &v + return s +} + +// InputService3ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService3ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService3ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService3ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService3ProtocolTest client from just a session. +// svc := inputservice3protocoltest.New(mySession) +// +// // Create a InputService3ProtocolTest client with additional configuration +// svc := inputservice3protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService3ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService3ProtocolTest { + c := p.ClientConfig("inputservice3protocoltest", cfgs...) + return newInputService3ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService3ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService3ProtocolTest { + svc := &InputService3ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice3protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService3ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService3ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService3TestCaseOperation1 = "OperationName" + +// InputService3TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService3TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService3TestCaseOperation1 for more information on using the InputService3TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService3TestCaseOperation1Request method. +// req, resp := client.InputService3TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input *InputService3TestShapeInputService3TestCaseOperation2Input) (req *request.Request, output *InputService3TestShapeInputService3TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService3TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService3TestShapeInputService3TestCaseOperation2Input{} + } + + output = &InputService3TestShapeInputService3TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService3TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService3TestCaseOperation1 for usage and error information. +func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputService3TestCaseOperation2Input) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) { + req, out := c.InputService3TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService3TestCaseOperation1WithContext is the same as InputService3TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService3TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService3ProtocolTest) InputService3TestCaseOperation1WithContext(ctx aws.Context, input *InputService3TestShapeInputService3TestCaseOperation2Input, opts ...request.Option) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) { + req, out := c.InputService3TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService3TestCaseOperation2 = "OperationName" + +// InputService3TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService3TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService3TestCaseOperation2 for more information on using the InputService3TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService3TestCaseOperation2Request method. +// req, resp := client.InputService3TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService3ProtocolTest) InputService3TestCaseOperation2Request(input *InputService3TestShapeInputService3TestCaseOperation2Input) (req *request.Request, output *InputService3TestShapeInputService3TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService3TestCaseOperation2, + HTTPPath: "/", + } + + if input == nil { + input = &InputService3TestShapeInputService3TestCaseOperation2Input{} + } + + output = &InputService3TestShapeInputService3TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService3TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService3TestCaseOperation2 for usage and error information. +func (c *InputService3ProtocolTest) InputService3TestCaseOperation2(input *InputService3TestShapeInputService3TestCaseOperation2Input) (*InputService3TestShapeInputService3TestCaseOperation2Output, error) { + req, out := c.InputService3TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService3TestCaseOperation2WithContext is the same as InputService3TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService3TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService3ProtocolTest) InputService3TestCaseOperation2WithContext(ctx aws.Context, input *InputService3TestShapeInputService3TestCaseOperation2Input, opts ...request.Option) (*InputService3TestShapeInputService3TestCaseOperation2Output, error) { + req, out := c.InputService3TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService3TestShapeInputService3TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService3TestShapeInputService3TestCaseOperation2Input struct { + _ struct{} `type:"structure"` + + ListArg []*string `type:"list"` +} + +// SetListArg sets the ListArg field's value. +func (s *InputService3TestShapeInputService3TestCaseOperation2Input) SetListArg(v []*string) *InputService3TestShapeInputService3TestCaseOperation2Input { + s.ListArg = v + return s +} + +type InputService3TestShapeInputService3TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +// InputService4ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService4ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService4ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService4ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService4ProtocolTest client from just a session. +// svc := inputservice4protocoltest.New(mySession) +// +// // Create a InputService4ProtocolTest client with additional configuration +// svc := inputservice4protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService4ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService4ProtocolTest { + c := p.ClientConfig("inputservice4protocoltest", cfgs...) + return newInputService4ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService4ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService4ProtocolTest { + svc := &InputService4ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice4protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService4ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService4ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService4TestCaseOperation1 = "OperationName" + +// InputService4TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService4TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService4TestCaseOperation1 for more information on using the InputService4TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService4TestCaseOperation1Request method. +// req, resp := client.InputService4TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input *InputService4TestShapeInputService4TestCaseOperation2Input) (req *request.Request, output *InputService4TestShapeInputService4TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService4TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService4TestShapeInputService4TestCaseOperation2Input{} + } + + output = &InputService4TestShapeInputService4TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService4TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService4TestCaseOperation1 for usage and error information. +func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputService4TestCaseOperation2Input) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) { + req, out := c.InputService4TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService4TestCaseOperation1WithContext is the same as InputService4TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService4TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService4ProtocolTest) InputService4TestCaseOperation1WithContext(ctx aws.Context, input *InputService4TestShapeInputService4TestCaseOperation2Input, opts ...request.Option) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) { + req, out := c.InputService4TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService4TestCaseOperation2 = "OperationName" + +// InputService4TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService4TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService4TestCaseOperation2 for more information on using the InputService4TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService4TestCaseOperation2Request method. +// req, resp := client.InputService4TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService4ProtocolTest) InputService4TestCaseOperation2Request(input *InputService4TestShapeInputService4TestCaseOperation2Input) (req *request.Request, output *InputService4TestShapeInputService4TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService4TestCaseOperation2, + HTTPPath: "/", + } + + if input == nil { + input = &InputService4TestShapeInputService4TestCaseOperation2Input{} + } + + output = &InputService4TestShapeInputService4TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService4TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService4TestCaseOperation2 for usage and error information. +func (c *InputService4ProtocolTest) InputService4TestCaseOperation2(input *InputService4TestShapeInputService4TestCaseOperation2Input) (*InputService4TestShapeInputService4TestCaseOperation2Output, error) { + req, out := c.InputService4TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService4TestCaseOperation2WithContext is the same as InputService4TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService4TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService4ProtocolTest) InputService4TestCaseOperation2WithContext(ctx aws.Context, input *InputService4TestShapeInputService4TestCaseOperation2Input, opts ...request.Option) (*InputService4TestShapeInputService4TestCaseOperation2Output, error) { + req, out := c.InputService4TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService4TestShapeInputService4TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService4TestShapeInputService4TestCaseOperation2Input struct { + _ struct{} `type:"structure"` + + ListArg []*string `type:"list" flattened:"true"` + + NamedListArg []*string `locationNameList:"Foo" type:"list" flattened:"true"` + + ScalarArg *string `type:"string"` +} + +// SetListArg sets the ListArg field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation2Input) SetListArg(v []*string) *InputService4TestShapeInputService4TestCaseOperation2Input { + s.ListArg = v + return s +} + +// SetNamedListArg sets the NamedListArg field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation2Input) SetNamedListArg(v []*string) *InputService4TestShapeInputService4TestCaseOperation2Input { + s.NamedListArg = v + return s +} + +// SetScalarArg sets the ScalarArg field's value. +func (s *InputService4TestShapeInputService4TestCaseOperation2Input) SetScalarArg(v string) *InputService4TestShapeInputService4TestCaseOperation2Input { + s.ScalarArg = &v + return s +} + +type InputService4TestShapeInputService4TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +// InputService5ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService5ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService5ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService5ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService5ProtocolTest client from just a session. +// svc := inputservice5protocoltest.New(mySession) +// +// // Create a InputService5ProtocolTest client with additional configuration +// svc := inputservice5protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService5ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService5ProtocolTest { + c := p.ClientConfig("inputservice5protocoltest", cfgs...) + return newInputService5ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService5ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService5ProtocolTest { + svc := &InputService5ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice5protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService5ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService5ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService5TestCaseOperation1 = "OperationName" + +// InputService5TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService5TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService5TestCaseOperation1 for more information on using the InputService5TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService5TestCaseOperation1Request method. +// req, resp := client.InputService5TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input *InputService5TestShapeInputService5TestCaseOperation1Input) (req *request.Request, output *InputService5TestShapeInputService5TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService5TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService5TestShapeInputService5TestCaseOperation1Input{} + } + + output = &InputService5TestShapeInputService5TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService5TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService5TestCaseOperation1 for usage and error information. +func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputService5TestCaseOperation1Input) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) { + req, out := c.InputService5TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService5TestCaseOperation1WithContext is the same as InputService5TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService5TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService5ProtocolTest) InputService5TestCaseOperation1WithContext(ctx aws.Context, input *InputService5TestShapeInputService5TestCaseOperation1Input, opts ...request.Option) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) { + req, out := c.InputService5TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService5TestShapeInputService5TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + MapArg map[string]*string `type:"map" flattened:"true"` +} + +// SetMapArg sets the MapArg field's value. +func (s *InputService5TestShapeInputService5TestCaseOperation1Input) SetMapArg(v map[string]*string) *InputService5TestShapeInputService5TestCaseOperation1Input { + s.MapArg = v + return s +} + +type InputService5TestShapeInputService5TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService6ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService6ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService6ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService6ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService6ProtocolTest client from just a session. +// svc := inputservice6protocoltest.New(mySession) +// +// // Create a InputService6ProtocolTest client with additional configuration +// svc := inputservice6protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService6ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService6ProtocolTest { + c := p.ClientConfig("inputservice6protocoltest", cfgs...) + return newInputService6ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService6ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService6ProtocolTest { + svc := &InputService6ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice6protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService6ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService6ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService6TestCaseOperation1 = "OperationName" + +// InputService6TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService6TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService6TestCaseOperation1 for more information on using the InputService6TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService6TestCaseOperation1Request method. +// req, resp := client.InputService6TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input *InputService6TestShapeInputService6TestCaseOperation1Input) (req *request.Request, output *InputService6TestShapeInputService6TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService6TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService6TestShapeInputService6TestCaseOperation1Input{} + } + + output = &InputService6TestShapeInputService6TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService6TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService6TestCaseOperation1 for usage and error information. +func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputService6TestCaseOperation1Input) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) { + req, out := c.InputService6TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService6TestCaseOperation1WithContext is the same as InputService6TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService6TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService6ProtocolTest) InputService6TestCaseOperation1WithContext(ctx aws.Context, input *InputService6TestShapeInputService6TestCaseOperation1Input, opts ...request.Option) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) { + req, out := c.InputService6TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService6TestShapeInputService6TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + ListArg []*string `locationNameList:"item" type:"list"` +} + +// SetListArg sets the ListArg field's value. +func (s *InputService6TestShapeInputService6TestCaseOperation1Input) SetListArg(v []*string) *InputService6TestShapeInputService6TestCaseOperation1Input { + s.ListArg = v + return s +} + +type InputService6TestShapeInputService6TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService7ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService7ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService7ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService7ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService7ProtocolTest client from just a session. +// svc := inputservice7protocoltest.New(mySession) +// +// // Create a InputService7ProtocolTest client with additional configuration +// svc := inputservice7protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService7ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService7ProtocolTest { + c := p.ClientConfig("inputservice7protocoltest", cfgs...) + return newInputService7ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService7ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService7ProtocolTest { + svc := &InputService7ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice7protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService7ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService7ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService7TestCaseOperation1 = "OperationName" + +// InputService7TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService7TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService7TestCaseOperation1 for more information on using the InputService7TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService7TestCaseOperation1Request method. +// req, resp := client.InputService7TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input *InputService7TestShapeInputService7TestCaseOperation1Input) (req *request.Request, output *InputService7TestShapeInputService7TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService7TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService7TestShapeInputService7TestCaseOperation1Input{} + } + + output = &InputService7TestShapeInputService7TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService7TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService7TestCaseOperation1 for usage and error information. +func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputService7TestCaseOperation1Input) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) { + req, out := c.InputService7TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService7TestCaseOperation1WithContext is the same as InputService7TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService7TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService7ProtocolTest) InputService7TestCaseOperation1WithContext(ctx aws.Context, input *InputService7TestShapeInputService7TestCaseOperation1Input, opts ...request.Option) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) { + req, out := c.InputService7TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService7TestShapeInputService7TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + ListArg []*string `locationNameList:"ListArgLocation" type:"list" flattened:"true"` + + ScalarArg *string `type:"string"` +} + +// SetListArg sets the ListArg field's value. +func (s *InputService7TestShapeInputService7TestCaseOperation1Input) SetListArg(v []*string) *InputService7TestShapeInputService7TestCaseOperation1Input { + s.ListArg = v + return s +} + +// SetScalarArg sets the ScalarArg field's value. +func (s *InputService7TestShapeInputService7TestCaseOperation1Input) SetScalarArg(v string) *InputService7TestShapeInputService7TestCaseOperation1Input { + s.ScalarArg = &v + return s +} + +type InputService7TestShapeInputService7TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService8ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService8ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService8ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService8ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService8ProtocolTest client from just a session. +// svc := inputservice8protocoltest.New(mySession) +// +// // Create a InputService8ProtocolTest client with additional configuration +// svc := inputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService8ProtocolTest { + c := p.ClientConfig("inputservice8protocoltest", cfgs...) + return newInputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService8ProtocolTest { + svc := &InputService8ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice8protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService8ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService8ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService8TestCaseOperation1 = "OperationName" + +// InputService8TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService8TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService8TestCaseOperation1 for more information on using the InputService8TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService8TestCaseOperation1Request method. +// req, resp := client.InputService8TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input *InputService8TestShapeInputService8TestCaseOperation1Input) (req *request.Request, output *InputService8TestShapeInputService8TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService8TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService8TestShapeInputService8TestCaseOperation1Input{} + } + + output = &InputService8TestShapeInputService8TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService8TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService8TestCaseOperation1 for usage and error information. +func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputService8TestCaseOperation1Input) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) { + req, out := c.InputService8TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService8TestCaseOperation1WithContext is the same as InputService8TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService8TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService8ProtocolTest) InputService8TestCaseOperation1WithContext(ctx aws.Context, input *InputService8TestShapeInputService8TestCaseOperation1Input, opts ...request.Option) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) { + req, out := c.InputService8TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService8TestShapeInputService8TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + MapArg map[string]*string `type:"map"` +} + +// SetMapArg sets the MapArg field's value. +func (s *InputService8TestShapeInputService8TestCaseOperation1Input) SetMapArg(v map[string]*string) *InputService8TestShapeInputService8TestCaseOperation1Input { + s.MapArg = v + return s +} + +type InputService8TestShapeInputService8TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService9ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService9ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService9ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService9ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService9ProtocolTest client from just a session. +// svc := inputservice9protocoltest.New(mySession) +// +// // Create a InputService9ProtocolTest client with additional configuration +// svc := inputservice9protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService9ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService9ProtocolTest { + c := p.ClientConfig("inputservice9protocoltest", cfgs...) + return newInputService9ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService9ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService9ProtocolTest { + svc := &InputService9ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice9protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService9ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService9ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService9TestCaseOperation1 = "OperationName" + +// InputService9TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService9TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService9TestCaseOperation1 for more information on using the InputService9TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService9TestCaseOperation1Request method. +// req, resp := client.InputService9TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService9ProtocolTest) InputService9TestCaseOperation1Request(input *InputService9TestShapeInputService9TestCaseOperation1Input) (req *request.Request, output *InputService9TestShapeInputService9TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService9TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService9TestShapeInputService9TestCaseOperation1Input{} + } + + output = &InputService9TestShapeInputService9TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService9TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService9TestCaseOperation1 for usage and error information. +func (c *InputService9ProtocolTest) InputService9TestCaseOperation1(input *InputService9TestShapeInputService9TestCaseOperation1Input) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) { + req, out := c.InputService9TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService9TestCaseOperation1WithContext is the same as InputService9TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService9TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService9ProtocolTest) InputService9TestCaseOperation1WithContext(ctx aws.Context, input *InputService9TestShapeInputService9TestCaseOperation1Input, opts ...request.Option) (*InputService9TestShapeInputService9TestCaseOperation1Output, error) { + req, out := c.InputService9TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService9TestShapeInputService9TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + MapArg map[string]*string `locationNameKey:"TheKey" locationNameValue:"TheValue" type:"map"` +} + +// SetMapArg sets the MapArg field's value. +func (s *InputService9TestShapeInputService9TestCaseOperation1Input) SetMapArg(v map[string]*string) *InputService9TestShapeInputService9TestCaseOperation1Input { + s.MapArg = v + return s +} + +type InputService9TestShapeInputService9TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService10ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService10ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService10ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService10ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService10ProtocolTest client from just a session. +// svc := inputservice10protocoltest.New(mySession) +// +// // Create a InputService10ProtocolTest client with additional configuration +// svc := inputservice10protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService10ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService10ProtocolTest { + c := p.ClientConfig("inputservice10protocoltest", cfgs...) + return newInputService10ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService10ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService10ProtocolTest { + svc := &InputService10ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice10protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService10ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService10ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService10TestCaseOperation1 = "OperationName" + +// InputService10TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService10TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService10TestCaseOperation1 for more information on using the InputService10TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService10TestCaseOperation1Request method. +// req, resp := client.InputService10TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService10ProtocolTest) InputService10TestCaseOperation1Request(input *InputService10TestShapeInputService10TestCaseOperation1Input) (req *request.Request, output *InputService10TestShapeInputService10TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService10TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService10TestShapeInputService10TestCaseOperation1Input{} + } + + output = &InputService10TestShapeInputService10TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService10TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService10TestCaseOperation1 for usage and error information. +func (c *InputService10ProtocolTest) InputService10TestCaseOperation1(input *InputService10TestShapeInputService10TestCaseOperation1Input) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) { + req, out := c.InputService10TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService10TestCaseOperation1WithContext is the same as InputService10TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService10TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService10ProtocolTest) InputService10TestCaseOperation1WithContext(ctx aws.Context, input *InputService10TestShapeInputService10TestCaseOperation1Input, opts ...request.Option) (*InputService10TestShapeInputService10TestCaseOperation1Output, error) { + req, out := c.InputService10TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService10TestShapeInputService10TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + // BlobArg is automatically base64 encoded/decoded by the SDK. + BlobArg []byte `type:"blob"` +} + +// SetBlobArg sets the BlobArg field's value. +func (s *InputService10TestShapeInputService10TestCaseOperation1Input) SetBlobArg(v []byte) *InputService10TestShapeInputService10TestCaseOperation1Input { + s.BlobArg = v + return s +} + +type InputService10TestShapeInputService10TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService11ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService11ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService11ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService11ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService11ProtocolTest client from just a session. +// svc := inputservice11protocoltest.New(mySession) +// +// // Create a InputService11ProtocolTest client with additional configuration +// svc := inputservice11protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService11ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService11ProtocolTest { + c := p.ClientConfig("inputservice11protocoltest", cfgs...) + return newInputService11ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService11ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService11ProtocolTest { + svc := &InputService11ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice11protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService11ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService11ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService11TestCaseOperation1 = "OperationName" + +// InputService11TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService11TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService11TestCaseOperation1 for more information on using the InputService11TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService11TestCaseOperation1Request method. +// req, resp := client.InputService11TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService11ProtocolTest) InputService11TestCaseOperation1Request(input *InputService11TestShapeInputService11TestCaseOperation1Input) (req *request.Request, output *InputService11TestShapeInputService11TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService11TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService11TestShapeInputService11TestCaseOperation1Input{} + } + + output = &InputService11TestShapeInputService11TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService11TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService11TestCaseOperation1 for usage and error information. +func (c *InputService11ProtocolTest) InputService11TestCaseOperation1(input *InputService11TestShapeInputService11TestCaseOperation1Input) (*InputService11TestShapeInputService11TestCaseOperation1Output, error) { + req, out := c.InputService11TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService11TestCaseOperation1WithContext is the same as InputService11TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService11TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService11ProtocolTest) InputService11TestCaseOperation1WithContext(ctx aws.Context, input *InputService11TestShapeInputService11TestCaseOperation1Input, opts ...request.Option) (*InputService11TestShapeInputService11TestCaseOperation1Output, error) { + req, out := c.InputService11TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService11TestShapeInputService11TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + BlobArgs [][]byte `type:"list" flattened:"true"` +} + +// SetBlobArgs sets the BlobArgs field's value. +func (s *InputService11TestShapeInputService11TestCaseOperation1Input) SetBlobArgs(v [][]byte) *InputService11TestShapeInputService11TestCaseOperation1Input { + s.BlobArgs = v + return s +} + +type InputService11TestShapeInputService11TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService12ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService12ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService12ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService12ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService12ProtocolTest client from just a session. +// svc := inputservice12protocoltest.New(mySession) +// +// // Create a InputService12ProtocolTest client with additional configuration +// svc := inputservice12protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService12ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService12ProtocolTest { + c := p.ClientConfig("inputservice12protocoltest", cfgs...) + return newInputService12ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService12ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService12ProtocolTest { + svc := &InputService12ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice12protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService12ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService12ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService12TestCaseOperation1 = "OperationName" + +// InputService12TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService12TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService12TestCaseOperation1 for more information on using the InputService12TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService12TestCaseOperation1Request method. +// req, resp := client.InputService12TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService12ProtocolTest) InputService12TestCaseOperation1Request(input *InputService12TestShapeInputService12TestCaseOperation1Input) (req *request.Request, output *InputService12TestShapeInputService12TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService12TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService12TestShapeInputService12TestCaseOperation1Input{} + } + + output = &InputService12TestShapeInputService12TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService12TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService12TestCaseOperation1 for usage and error information. +func (c *InputService12ProtocolTest) InputService12TestCaseOperation1(input *InputService12TestShapeInputService12TestCaseOperation1Input) (*InputService12TestShapeInputService12TestCaseOperation1Output, error) { + req, out := c.InputService12TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService12TestCaseOperation1WithContext is the same as InputService12TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService12TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService12ProtocolTest) InputService12TestCaseOperation1WithContext(ctx aws.Context, input *InputService12TestShapeInputService12TestCaseOperation1Input, opts ...request.Option) (*InputService12TestShapeInputService12TestCaseOperation1Output, error) { + req, out := c.InputService12TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService12TestShapeInputService12TestCaseOperation1Input struct { + _ struct{} `type:"structure"` + + TimeArg *time.Time `type:"timestamp" timestampFormat:"iso8601"` +} + +// SetTimeArg sets the TimeArg field's value. +func (s *InputService12TestShapeInputService12TestCaseOperation1Input) SetTimeArg(v time.Time) *InputService12TestShapeInputService12TestCaseOperation1Input { + s.TimeArg = &v + return s +} + +type InputService12TestShapeInputService12TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +// InputService13ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService13ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService13ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService13ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService13ProtocolTest client from just a session. +// svc := inputservice13protocoltest.New(mySession) +// +// // Create a InputService13ProtocolTest client with additional configuration +// svc := inputservice13protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService13ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService13ProtocolTest { + c := p.ClientConfig("inputservice13protocoltest", cfgs...) + return newInputService13ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService13ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService13ProtocolTest { + svc := &InputService13ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice13protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService13ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService13ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService13TestCaseOperation1 = "OperationName" + +// InputService13TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService13TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService13TestCaseOperation1 for more information on using the InputService13TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService13TestCaseOperation1Request method. +// req, resp := client.InputService13TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService13ProtocolTest) InputService13TestCaseOperation1Request(input *InputService13TestShapeInputService13TestCaseOperation6Input) (req *request.Request, output *InputService13TestShapeInputService13TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService13TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &InputService13TestShapeInputService13TestCaseOperation6Input{} + } + + output = &InputService13TestShapeInputService13TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService13TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService13TestCaseOperation1 for usage and error information. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation1(input *InputService13TestShapeInputService13TestCaseOperation6Input) (*InputService13TestShapeInputService13TestCaseOperation1Output, error) { + req, out := c.InputService13TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService13TestCaseOperation1WithContext is the same as InputService13TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService13TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation1WithContext(ctx aws.Context, input *InputService13TestShapeInputService13TestCaseOperation6Input, opts ...request.Option) (*InputService13TestShapeInputService13TestCaseOperation1Output, error) { + req, out := c.InputService13TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService13TestCaseOperation2 = "OperationName" + +// InputService13TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService13TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService13TestCaseOperation2 for more information on using the InputService13TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService13TestCaseOperation2Request method. +// req, resp := client.InputService13TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService13ProtocolTest) InputService13TestCaseOperation2Request(input *InputService13TestShapeInputService13TestCaseOperation6Input) (req *request.Request, output *InputService13TestShapeInputService13TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService13TestCaseOperation2, + HTTPPath: "/", + } + + if input == nil { + input = &InputService13TestShapeInputService13TestCaseOperation6Input{} + } + + output = &InputService13TestShapeInputService13TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService13TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService13TestCaseOperation2 for usage and error information. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation2(input *InputService13TestShapeInputService13TestCaseOperation6Input) (*InputService13TestShapeInputService13TestCaseOperation2Output, error) { + req, out := c.InputService13TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService13TestCaseOperation2WithContext is the same as InputService13TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService13TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation2WithContext(ctx aws.Context, input *InputService13TestShapeInputService13TestCaseOperation6Input, opts ...request.Option) (*InputService13TestShapeInputService13TestCaseOperation2Output, error) { + req, out := c.InputService13TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService13TestCaseOperation3 = "OperationName" + +// InputService13TestCaseOperation3Request generates a "aws/request.Request" representing the +// client's request for the InputService13TestCaseOperation3 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService13TestCaseOperation3 for more information on using the InputService13TestCaseOperation3 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService13TestCaseOperation3Request method. +// req, resp := client.InputService13TestCaseOperation3Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService13ProtocolTest) InputService13TestCaseOperation3Request(input *InputService13TestShapeInputService13TestCaseOperation6Input) (req *request.Request, output *InputService13TestShapeInputService13TestCaseOperation3Output) { + op := &request.Operation{ + Name: opInputService13TestCaseOperation3, + HTTPPath: "/", + } + + if input == nil { + input = &InputService13TestShapeInputService13TestCaseOperation6Input{} + } + + output = &InputService13TestShapeInputService13TestCaseOperation3Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService13TestCaseOperation3 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService13TestCaseOperation3 for usage and error information. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation3(input *InputService13TestShapeInputService13TestCaseOperation6Input) (*InputService13TestShapeInputService13TestCaseOperation3Output, error) { + req, out := c.InputService13TestCaseOperation3Request(input) + return out, req.Send() +} + +// InputService13TestCaseOperation3WithContext is the same as InputService13TestCaseOperation3 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService13TestCaseOperation3 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation3WithContext(ctx aws.Context, input *InputService13TestShapeInputService13TestCaseOperation6Input, opts ...request.Option) (*InputService13TestShapeInputService13TestCaseOperation3Output, error) { + req, out := c.InputService13TestCaseOperation3Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService13TestCaseOperation4 = "OperationName" + +// InputService13TestCaseOperation4Request generates a "aws/request.Request" representing the +// client's request for the InputService13TestCaseOperation4 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService13TestCaseOperation4 for more information on using the InputService13TestCaseOperation4 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService13TestCaseOperation4Request method. +// req, resp := client.InputService13TestCaseOperation4Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService13ProtocolTest) InputService13TestCaseOperation4Request(input *InputService13TestShapeInputService13TestCaseOperation6Input) (req *request.Request, output *InputService13TestShapeInputService13TestCaseOperation4Output) { + op := &request.Operation{ + Name: opInputService13TestCaseOperation4, + HTTPPath: "/", + } + + if input == nil { + input = &InputService13TestShapeInputService13TestCaseOperation6Input{} + } + + output = &InputService13TestShapeInputService13TestCaseOperation4Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService13TestCaseOperation4 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService13TestCaseOperation4 for usage and error information. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation4(input *InputService13TestShapeInputService13TestCaseOperation6Input) (*InputService13TestShapeInputService13TestCaseOperation4Output, error) { + req, out := c.InputService13TestCaseOperation4Request(input) + return out, req.Send() +} + +// InputService13TestCaseOperation4WithContext is the same as InputService13TestCaseOperation4 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService13TestCaseOperation4 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation4WithContext(ctx aws.Context, input *InputService13TestShapeInputService13TestCaseOperation6Input, opts ...request.Option) (*InputService13TestShapeInputService13TestCaseOperation4Output, error) { + req, out := c.InputService13TestCaseOperation4Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService13TestCaseOperation5 = "OperationName" + +// InputService13TestCaseOperation5Request generates a "aws/request.Request" representing the +// client's request for the InputService13TestCaseOperation5 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService13TestCaseOperation5 for more information on using the InputService13TestCaseOperation5 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService13TestCaseOperation5Request method. +// req, resp := client.InputService13TestCaseOperation5Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService13ProtocolTest) InputService13TestCaseOperation5Request(input *InputService13TestShapeInputService13TestCaseOperation6Input) (req *request.Request, output *InputService13TestShapeInputService13TestCaseOperation5Output) { + op := &request.Operation{ + Name: opInputService13TestCaseOperation5, + HTTPPath: "/", + } + + if input == nil { + input = &InputService13TestShapeInputService13TestCaseOperation6Input{} + } + + output = &InputService13TestShapeInputService13TestCaseOperation5Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService13TestCaseOperation5 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService13TestCaseOperation5 for usage and error information. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation5(input *InputService13TestShapeInputService13TestCaseOperation6Input) (*InputService13TestShapeInputService13TestCaseOperation5Output, error) { + req, out := c.InputService13TestCaseOperation5Request(input) + return out, req.Send() +} + +// InputService13TestCaseOperation5WithContext is the same as InputService13TestCaseOperation5 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService13TestCaseOperation5 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation5WithContext(ctx aws.Context, input *InputService13TestShapeInputService13TestCaseOperation6Input, opts ...request.Option) (*InputService13TestShapeInputService13TestCaseOperation5Output, error) { + req, out := c.InputService13TestCaseOperation5Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService13TestCaseOperation6 = "OperationName" + +// InputService13TestCaseOperation6Request generates a "aws/request.Request" representing the +// client's request for the InputService13TestCaseOperation6 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService13TestCaseOperation6 for more information on using the InputService13TestCaseOperation6 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService13TestCaseOperation6Request method. +// req, resp := client.InputService13TestCaseOperation6Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService13ProtocolTest) InputService13TestCaseOperation6Request(input *InputService13TestShapeInputService13TestCaseOperation6Input) (req *request.Request, output *InputService13TestShapeInputService13TestCaseOperation6Output) { + op := &request.Operation{ + Name: opInputService13TestCaseOperation6, + HTTPPath: "/", + } + + if input == nil { + input = &InputService13TestShapeInputService13TestCaseOperation6Input{} + } + + output = &InputService13TestShapeInputService13TestCaseOperation6Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService13TestCaseOperation6 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService13TestCaseOperation6 for usage and error information. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation6(input *InputService13TestShapeInputService13TestCaseOperation6Input) (*InputService13TestShapeInputService13TestCaseOperation6Output, error) { + req, out := c.InputService13TestCaseOperation6Request(input) + return out, req.Send() +} + +// InputService13TestCaseOperation6WithContext is the same as InputService13TestCaseOperation6 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService13TestCaseOperation6 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService13ProtocolTest) InputService13TestCaseOperation6WithContext(ctx aws.Context, input *InputService13TestShapeInputService13TestCaseOperation6Input, opts ...request.Option) (*InputService13TestShapeInputService13TestCaseOperation6Output, error) { + req, out := c.InputService13TestCaseOperation6Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService13TestShapeInputService13TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService13TestShapeInputService13TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +type InputService13TestShapeInputService13TestCaseOperation3Output struct { + _ struct{} `type:"structure"` +} + +type InputService13TestShapeInputService13TestCaseOperation4Output struct { + _ struct{} `type:"structure"` +} + +type InputService13TestShapeInputService13TestCaseOperation5Output struct { + _ struct{} `type:"structure"` +} + +type InputService13TestShapeInputService13TestCaseOperation6Input struct { + _ struct{} `type:"structure"` + + RecursiveStruct *InputService13TestShapeRecursiveStructType `type:"structure"` +} + +// SetRecursiveStruct sets the RecursiveStruct field's value. +func (s *InputService13TestShapeInputService13TestCaseOperation6Input) SetRecursiveStruct(v *InputService13TestShapeRecursiveStructType) *InputService13TestShapeInputService13TestCaseOperation6Input { + s.RecursiveStruct = v + return s +} + +type InputService13TestShapeInputService13TestCaseOperation6Output struct { + _ struct{} `type:"structure"` +} + +type InputService13TestShapeRecursiveStructType struct { + _ struct{} `type:"structure"` + + NoRecurse *string `type:"string"` + + RecursiveList []*InputService13TestShapeRecursiveStructType `type:"list"` + + RecursiveMap map[string]*InputService13TestShapeRecursiveStructType `type:"map"` + + RecursiveStruct *InputService13TestShapeRecursiveStructType `type:"structure"` +} + +// SetNoRecurse sets the NoRecurse field's value. +func (s *InputService13TestShapeRecursiveStructType) SetNoRecurse(v string) *InputService13TestShapeRecursiveStructType { + s.NoRecurse = &v + return s +} + +// SetRecursiveList sets the RecursiveList field's value. +func (s *InputService13TestShapeRecursiveStructType) SetRecursiveList(v []*InputService13TestShapeRecursiveStructType) *InputService13TestShapeRecursiveStructType { + s.RecursiveList = v + return s +} + +// SetRecursiveMap sets the RecursiveMap field's value. +func (s *InputService13TestShapeRecursiveStructType) SetRecursiveMap(v map[string]*InputService13TestShapeRecursiveStructType) *InputService13TestShapeRecursiveStructType { + s.RecursiveMap = v + return s +} + +// SetRecursiveStruct sets the RecursiveStruct field's value. +func (s *InputService13TestShapeRecursiveStructType) SetRecursiveStruct(v *InputService13TestShapeRecursiveStructType) *InputService13TestShapeRecursiveStructType { + s.RecursiveStruct = v + return s +} + +// InputService14ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService14ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService14ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService14ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService14ProtocolTest client from just a session. +// svc := inputservice14protocoltest.New(mySession) +// +// // Create a InputService14ProtocolTest client with additional configuration +// svc := inputservice14protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService14ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService14ProtocolTest { + c := p.ClientConfig("inputservice14protocoltest", cfgs...) + return newInputService14ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService14ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService14ProtocolTest { + svc := &InputService14ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice14protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService14ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService14ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService14TestCaseOperation1 = "OperationName" + +// InputService14TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService14TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService14TestCaseOperation1 for more information on using the InputService14TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService14TestCaseOperation1Request method. +// req, resp := client.InputService14TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService14ProtocolTest) InputService14TestCaseOperation1Request(input *InputService14TestShapeInputService14TestCaseOperation2Input) (req *request.Request, output *InputService14TestShapeInputService14TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService14TestCaseOperation1, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &InputService14TestShapeInputService14TestCaseOperation2Input{} + } + + output = &InputService14TestShapeInputService14TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService14TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService14TestCaseOperation1 for usage and error information. +func (c *InputService14ProtocolTest) InputService14TestCaseOperation1(input *InputService14TestShapeInputService14TestCaseOperation2Input) (*InputService14TestShapeInputService14TestCaseOperation1Output, error) { + req, out := c.InputService14TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService14TestCaseOperation1WithContext is the same as InputService14TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService14TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService14ProtocolTest) InputService14TestCaseOperation1WithContext(ctx aws.Context, input *InputService14TestShapeInputService14TestCaseOperation2Input, opts ...request.Option) (*InputService14TestShapeInputService14TestCaseOperation1Output, error) { + req, out := c.InputService14TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService14TestCaseOperation2 = "OperationName" + +// InputService14TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService14TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService14TestCaseOperation2 for more information on using the InputService14TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService14TestCaseOperation2Request method. +// req, resp := client.InputService14TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService14ProtocolTest) InputService14TestCaseOperation2Request(input *InputService14TestShapeInputService14TestCaseOperation2Input) (req *request.Request, output *InputService14TestShapeInputService14TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService14TestCaseOperation2, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &InputService14TestShapeInputService14TestCaseOperation2Input{} + } + + output = &InputService14TestShapeInputService14TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService14TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService14TestCaseOperation2 for usage and error information. +func (c *InputService14ProtocolTest) InputService14TestCaseOperation2(input *InputService14TestShapeInputService14TestCaseOperation2Input) (*InputService14TestShapeInputService14TestCaseOperation2Output, error) { + req, out := c.InputService14TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService14TestCaseOperation2WithContext is the same as InputService14TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService14TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService14ProtocolTest) InputService14TestCaseOperation2WithContext(ctx aws.Context, input *InputService14TestShapeInputService14TestCaseOperation2Input, opts ...request.Option) (*InputService14TestShapeInputService14TestCaseOperation2Output, error) { + req, out := c.InputService14TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService14TestShapeInputService14TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService14TestShapeInputService14TestCaseOperation2Input struct { + _ struct{} `type:"structure"` + + Token *string `type:"string" idempotencyToken:"true"` +} + +// SetToken sets the Token field's value. +func (s *InputService14TestShapeInputService14TestCaseOperation2Input) SetToken(v string) *InputService14TestShapeInputService14TestCaseOperation2Input { + s.Token = &v + return s +} + +type InputService14TestShapeInputService14TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +// InputService15ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// InputService15ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type InputService15ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the InputService15ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a InputService15ProtocolTest client from just a session. +// svc := inputservice15protocoltest.New(mySession) +// +// // Create a InputService15ProtocolTest client with additional configuration +// svc := inputservice15protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewInputService15ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *InputService15ProtocolTest { + c := p.ClientConfig("inputservice15protocoltest", cfgs...) + return newInputService15ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newInputService15ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *InputService15ProtocolTest { + svc := &InputService15ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "inputservice15protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "2014-01-01", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a InputService15ProtocolTest operation and runs any +// custom request initialization. +func (c *InputService15ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opInputService15TestCaseOperation1 = "OperationName" + +// InputService15TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the InputService15TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService15TestCaseOperation1 for more information on using the InputService15TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService15TestCaseOperation1Request method. +// req, resp := client.InputService15TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService15ProtocolTest) InputService15TestCaseOperation1Request(input *InputService15TestShapeInputService15TestCaseOperation3Input) (req *request.Request, output *InputService15TestShapeInputService15TestCaseOperation1Output) { + op := &request.Operation{ + Name: opInputService15TestCaseOperation1, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &InputService15TestShapeInputService15TestCaseOperation3Input{} + } + + output = &InputService15TestShapeInputService15TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService15TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService15TestCaseOperation1 for usage and error information. +func (c *InputService15ProtocolTest) InputService15TestCaseOperation1(input *InputService15TestShapeInputService15TestCaseOperation3Input) (*InputService15TestShapeInputService15TestCaseOperation1Output, error) { + req, out := c.InputService15TestCaseOperation1Request(input) + return out, req.Send() +} + +// InputService15TestCaseOperation1WithContext is the same as InputService15TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService15TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService15ProtocolTest) InputService15TestCaseOperation1WithContext(ctx aws.Context, input *InputService15TestShapeInputService15TestCaseOperation3Input, opts ...request.Option) (*InputService15TestShapeInputService15TestCaseOperation1Output, error) { + req, out := c.InputService15TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService15TestCaseOperation2 = "OperationName" + +// InputService15TestCaseOperation2Request generates a "aws/request.Request" representing the +// client's request for the InputService15TestCaseOperation2 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService15TestCaseOperation2 for more information on using the InputService15TestCaseOperation2 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService15TestCaseOperation2Request method. +// req, resp := client.InputService15TestCaseOperation2Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService15ProtocolTest) InputService15TestCaseOperation2Request(input *InputService15TestShapeInputService15TestCaseOperation3Input) (req *request.Request, output *InputService15TestShapeInputService15TestCaseOperation2Output) { + op := &request.Operation{ + Name: opInputService15TestCaseOperation2, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &InputService15TestShapeInputService15TestCaseOperation3Input{} + } + + output = &InputService15TestShapeInputService15TestCaseOperation2Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService15TestCaseOperation2 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService15TestCaseOperation2 for usage and error information. +func (c *InputService15ProtocolTest) InputService15TestCaseOperation2(input *InputService15TestShapeInputService15TestCaseOperation3Input) (*InputService15TestShapeInputService15TestCaseOperation2Output, error) { + req, out := c.InputService15TestCaseOperation2Request(input) + return out, req.Send() +} + +// InputService15TestCaseOperation2WithContext is the same as InputService15TestCaseOperation2 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService15TestCaseOperation2 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService15ProtocolTest) InputService15TestCaseOperation2WithContext(ctx aws.Context, input *InputService15TestShapeInputService15TestCaseOperation3Input, opts ...request.Option) (*InputService15TestShapeInputService15TestCaseOperation2Output, error) { + req, out := c.InputService15TestCaseOperation2Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +const opInputService15TestCaseOperation3 = "OperationName" + +// InputService15TestCaseOperation3Request generates a "aws/request.Request" representing the +// client's request for the InputService15TestCaseOperation3 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See InputService15TestCaseOperation3 for more information on using the InputService15TestCaseOperation3 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the InputService15TestCaseOperation3Request method. +// req, resp := client.InputService15TestCaseOperation3Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *InputService15ProtocolTest) InputService15TestCaseOperation3Request(input *InputService15TestShapeInputService15TestCaseOperation3Input) (req *request.Request, output *InputService15TestShapeInputService15TestCaseOperation3Output) { + op := &request.Operation{ + Name: opInputService15TestCaseOperation3, + HTTPMethod: "POST", + HTTPPath: "/", + } + + if input == nil { + input = &InputService15TestShapeInputService15TestCaseOperation3Input{} + } + + output = &InputService15TestShapeInputService15TestCaseOperation3Output{} + req = c.newRequest(op, input, output) + req.Handlers.Unmarshal.Remove(query.UnmarshalHandler) + req.Handlers.Unmarshal.PushBackNamed(protocol.UnmarshalDiscardBodyHandler) + return +} + +// InputService15TestCaseOperation3 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation InputService15TestCaseOperation3 for usage and error information. +func (c *InputService15ProtocolTest) InputService15TestCaseOperation3(input *InputService15TestShapeInputService15TestCaseOperation3Input) (*InputService15TestShapeInputService15TestCaseOperation3Output, error) { + req, out := c.InputService15TestCaseOperation3Request(input) + return out, req.Send() +} + +// InputService15TestCaseOperation3WithContext is the same as InputService15TestCaseOperation3 with the addition of +// the ability to pass a context and additional request options. +// +// See InputService15TestCaseOperation3 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *InputService15ProtocolTest) InputService15TestCaseOperation3WithContext(ctx aws.Context, input *InputService15TestShapeInputService15TestCaseOperation3Input, opts ...request.Option) (*InputService15TestShapeInputService15TestCaseOperation3Output, error) { + req, out := c.InputService15TestCaseOperation3Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type InputService15TestShapeInputService15TestCaseOperation1Output struct { + _ struct{} `type:"structure"` +} + +type InputService15TestShapeInputService15TestCaseOperation2Output struct { + _ struct{} `type:"structure"` +} + +type InputService15TestShapeInputService15TestCaseOperation3Input struct { + _ struct{} `type:"structure"` + + FooEnum *string `type:"string" enum:"InputService15TestShapeEnumType"` + + ListEnums []*string `type:"list"` +} + +// SetFooEnum sets the FooEnum field's value. +func (s *InputService15TestShapeInputService15TestCaseOperation3Input) SetFooEnum(v string) *InputService15TestShapeInputService15TestCaseOperation3Input { + s.FooEnum = &v + return s +} + +// SetListEnums sets the ListEnums field's value. +func (s *InputService15TestShapeInputService15TestCaseOperation3Input) SetListEnums(v []*string) *InputService15TestShapeInputService15TestCaseOperation3Input { + s.ListEnums = v + return s +} + +type InputService15TestShapeInputService15TestCaseOperation3Output struct { + _ struct{} `type:"structure"` +} + +const ( + // EnumTypeFoo is a InputService15TestShapeEnumType enum value + EnumTypeFoo = "foo" + + // EnumTypeBar is a InputService15TestShapeEnumType enum value + EnumTypeBar = "bar" +) + +// +// Tests begin here +// + +func TestInputService1ProtocolTestScalarMembersCase1(t *testing.T) { + svc := NewInputService1ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService1TestShapeInputService1TestCaseOperation3Input{ + Bar: aws.String("val2"), + Foo: aws.String("val1"), + } + req, _ := svc.InputService1TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Bar=val2&Foo=val1&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService1ProtocolTestScalarMembersCase2(t *testing.T) { + svc := NewInputService1ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService1TestShapeInputService1TestCaseOperation3Input{ + Baz: aws.Bool(true), + } + req, _ := svc.InputService1TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Baz=true&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService1ProtocolTestScalarMembersCase3(t *testing.T) { + svc := NewInputService1ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService1TestShapeInputService1TestCaseOperation3Input{ + Baz: aws.Bool(false), + } + req, _ := svc.InputService1TestCaseOperation3Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Baz=false&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService2ProtocolTestNestedStructureMembersCase1(t *testing.T) { + svc := NewInputService2ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService2TestShapeInputService2TestCaseOperation1Input{ + StructArg: &InputService2TestShapeStructType{ + ScalarArg: aws.String("foo"), + }, + } + req, _ := svc.InputService2TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&StructArg.ScalarArg=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService3ProtocolTestListTypesCase1(t *testing.T) { + svc := NewInputService3ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService3TestShapeInputService3TestCaseOperation2Input{ + ListArg: []*string{ + aws.String("foo"), + aws.String("bar"), + aws.String("baz"), + }, + } + req, _ := svc.InputService3TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListArg.member.1=foo&ListArg.member.2=bar&ListArg.member.3=baz&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService3ProtocolTestListTypesCase2(t *testing.T) { + svc := NewInputService3ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService3TestShapeInputService3TestCaseOperation2Input{ + ListArg: []*string{}, + } + req, _ := svc.InputService3TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListArg=&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService4ProtocolTestFlattenedListCase1(t *testing.T) { + svc := NewInputService4ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService4TestShapeInputService4TestCaseOperation2Input{ + ListArg: []*string{ + aws.String("a"), + aws.String("b"), + aws.String("c"), + }, + ScalarArg: aws.String("foo"), + } + req, _ := svc.InputService4TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListArg.1=a&ListArg.2=b&ListArg.3=c&ScalarArg=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService4ProtocolTestFlattenedListCase2(t *testing.T) { + svc := NewInputService4ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService4TestShapeInputService4TestCaseOperation2Input{ + NamedListArg: []*string{ + aws.String("a"), + }, + } + req, _ := svc.InputService4TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Foo.1=a&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService5ProtocolTestSerializeFlattenedMapTypeCase1(t *testing.T) { + svc := NewInputService5ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService5TestShapeInputService5TestCaseOperation1Input{ + MapArg: map[string]*string{ + "key1": aws.String("val1"), + "key2": aws.String("val2"), + }, + } + req, _ := svc.InputService5TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&MapArg.1.key=key1&MapArg.1.value=val1&MapArg.2.key=key2&MapArg.2.value=val2&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService6ProtocolTestNonFlattenedListWithLocationNameCase1(t *testing.T) { + svc := NewInputService6ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService6TestShapeInputService6TestCaseOperation1Input{ + ListArg: []*string{ + aws.String("a"), + aws.String("b"), + aws.String("c"), + }, + } + req, _ := svc.InputService6TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListArg.item.1=a&ListArg.item.2=b&ListArg.item.3=c&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService7ProtocolTestFlattenedListWithLocationNameCase1(t *testing.T) { + svc := NewInputService7ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService7TestShapeInputService7TestCaseOperation1Input{ + ListArg: []*string{ + aws.String("a"), + aws.String("b"), + aws.String("c"), + }, + ScalarArg: aws.String("foo"), + } + req, _ := svc.InputService7TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&ListArgLocation.1=a&ListArgLocation.2=b&ListArgLocation.3=c&ScalarArg=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService8ProtocolTestSerializeMapTypeCase1(t *testing.T) { + svc := NewInputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService8TestShapeInputService8TestCaseOperation1Input{ + MapArg: map[string]*string{ + "key1": aws.String("val1"), + "key2": aws.String("val2"), + }, + } + req, _ := svc.InputService8TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&MapArg.entry.1.key=key1&MapArg.entry.1.value=val1&MapArg.entry.2.key=key2&MapArg.entry.2.value=val2&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService9ProtocolTestSerializeMapTypeWithLocationNameCase1(t *testing.T) { + svc := NewInputService9ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService9TestShapeInputService9TestCaseOperation1Input{ + MapArg: map[string]*string{ + "key1": aws.String("val1"), + "key2": aws.String("val2"), + }, + } + req, _ := svc.InputService9TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&MapArg.entry.1.TheKey=key1&MapArg.entry.1.TheValue=val1&MapArg.entry.2.TheKey=key2&MapArg.entry.2.TheValue=val2&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService10ProtocolTestBase64EncodedBlobsCase1(t *testing.T) { + svc := NewInputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService10TestShapeInputService10TestCaseOperation1Input{ + BlobArg: []byte("foo"), + } + req, _ := svc.InputService10TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&BlobArg=Zm9v&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService11ProtocolTestBase64EncodedBlobsNestedCase1(t *testing.T) { + svc := NewInputService11ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService11TestShapeInputService11TestCaseOperation1Input{ + BlobArgs: [][]byte{ + []byte("foo"), + }, + } + req, _ := svc.InputService11TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&BlobArgs.1=Zm9v&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService12ProtocolTestTimestampValuesCase1(t *testing.T) { + svc := NewInputService12ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService12TestShapeInputService12TestCaseOperation1Input{ + TimeArg: aws.Time(time.Unix(1422172800, 0)), + } + req, _ := svc.InputService12TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&TimeArg=2015-01-25T08%3A00%3A00Z&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService13ProtocolTestRecursiveShapesCase1(t *testing.T) { + svc := NewInputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService13TestShapeInputService13TestCaseOperation6Input{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + NoRecurse: aws.String("foo"), + }, + } + req, _ := svc.InputService13TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&RecursiveStruct.NoRecurse=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService13ProtocolTestRecursiveShapesCase2(t *testing.T) { + svc := NewInputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService13TestShapeInputService13TestCaseOperation6Input{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + NoRecurse: aws.String("foo"), + }, + }, + } + req, _ := svc.InputService13TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&RecursiveStruct.RecursiveStruct.NoRecurse=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService13ProtocolTestRecursiveShapesCase3(t *testing.T) { + svc := NewInputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService13TestShapeInputService13TestCaseOperation6Input{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + NoRecurse: aws.String("foo"), + }, + }, + }, + }, + } + req, _ := svc.InputService13TestCaseOperation3Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&RecursiveStruct.RecursiveStruct.RecursiveStruct.RecursiveStruct.NoRecurse=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService13ProtocolTestRecursiveShapesCase4(t *testing.T) { + svc := NewInputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService13TestShapeInputService13TestCaseOperation6Input{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveList: []*InputService13TestShapeRecursiveStructType{ + { + NoRecurse: aws.String("foo"), + }, + { + NoRecurse: aws.String("bar"), + }, + }, + }, + } + req, _ := svc.InputService13TestCaseOperation4Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&RecursiveStruct.RecursiveList.member.1.NoRecurse=foo&RecursiveStruct.RecursiveList.member.2.NoRecurse=bar&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService13ProtocolTestRecursiveShapesCase5(t *testing.T) { + svc := NewInputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService13TestShapeInputService13TestCaseOperation6Input{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveList: []*InputService13TestShapeRecursiveStructType{ + { + NoRecurse: aws.String("foo"), + }, + { + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + NoRecurse: aws.String("bar"), + }, + }, + }, + }, + } + req, _ := svc.InputService13TestCaseOperation5Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&RecursiveStruct.RecursiveList.member.1.NoRecurse=foo&RecursiveStruct.RecursiveList.member.2.RecursiveStruct.NoRecurse=bar&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService13ProtocolTestRecursiveShapesCase6(t *testing.T) { + svc := NewInputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService13TestShapeInputService13TestCaseOperation6Input{ + RecursiveStruct: &InputService13TestShapeRecursiveStructType{ + RecursiveMap: map[string]*InputService13TestShapeRecursiveStructType{ + "bar": { + NoRecurse: aws.String("bar"), + }, + "foo": { + NoRecurse: aws.String("foo"), + }, + }, + }, + } + req, _ := svc.InputService13TestCaseOperation6Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&RecursiveStruct.RecursiveMap.entry.1.key=foo&RecursiveStruct.RecursiveMap.entry.1.value.NoRecurse=foo&RecursiveStruct.RecursiveMap.entry.2.key=bar&RecursiveStruct.RecursiveMap.entry.2.value.NoRecurse=bar&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService14ProtocolTestIdempotencyTokenAutoFillCase1(t *testing.T) { + svc := NewInputService14ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService14TestShapeInputService14TestCaseOperation2Input{ + Token: aws.String("abc123"), + } + req, _ := svc.InputService14TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Token=abc123&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService14ProtocolTestIdempotencyTokenAutoFillCase2(t *testing.T) { + svc := NewInputService14ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService14TestShapeInputService14TestCaseOperation2Input{} + req, _ := svc.InputService14TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Token=00000000-0000-4000-8000-000000000000&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService15ProtocolTestEnumCase1(t *testing.T) { + svc := NewInputService15ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService15TestShapeInputService15TestCaseOperation3Input{ + FooEnum: aws.String("foo"), + ListEnums: []*string{ + aws.String("foo"), + aws.String(""), + aws.String("bar"), + }, + } + req, _ := svc.InputService15TestCaseOperation1Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&FooEnum=foo&ListEnums.member.1=foo&ListEnums.member.2=&ListEnums.member.3=bar&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService15ProtocolTestEnumCase2(t *testing.T) { + svc := NewInputService15ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService15TestShapeInputService15TestCaseOperation3Input{ + FooEnum: aws.String("foo"), + } + req, _ := svc.InputService15TestCaseOperation2Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&FooEnum=foo&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} + +func TestInputService15ProtocolTestEnumCase3(t *testing.T) { + svc := NewInputService15ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + input := &InputService15TestShapeInputService15TestCaseOperation3Input{} + req, _ := svc.InputService15TestCaseOperation3Request(input) + r := req.HTTPRequest + + // build request + query.Build(req) + if req.Error != nil { + t.Errorf("expect no error, got %v", req.Error) + } + + // assert body + if r.Body == nil { + t.Errorf("expect body not to be nil") + } + body, _ := ioutil.ReadAll(r.Body) + awstesting.AssertQuery(t, `Action=OperationName&Version=2014-01-01`, util.Trim(string(body))) + + // assert URL + awstesting.AssertURL(t, "https://test/", r.URL.String()) + + // assert headers + +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_test.go new file mode 100644 index 000000000..17cdd3594 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/query/unmarshal_test.go @@ -0,0 +1,2991 @@ +package query_test + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/aws/aws-sdk-go/private/protocol/query" + "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" + "github.com/aws/aws-sdk-go/private/util" +) + +var _ bytes.Buffer // always import bytes +var _ http.Request +var _ json.Marshaler +var _ time.Time +var _ xmlutil.XMLNode +var _ xml.Attr +var _ = ioutil.Discard +var _ = util.Trim("") +var _ = url.Values{} +var _ = io.EOF +var _ = aws.String +var _ = fmt.Println +var _ = reflect.Value{} + +func init() { + protocol.RandReader = &awstesting.ZeroReader{} +} + +// OutputService1ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService1ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService1ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService1ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService1ProtocolTest client from just a session. +// svc := outputservice1protocoltest.New(mySession) +// +// // Create a OutputService1ProtocolTest client with additional configuration +// svc := outputservice1protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService1ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService1ProtocolTest { + c := p.ClientConfig("outputservice1protocoltest", cfgs...) + return newOutputService1ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService1ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService1ProtocolTest { + svc := &OutputService1ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice1protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService1ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService1ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService1TestCaseOperation1 = "OperationName" + +// OutputService1TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService1TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService1TestCaseOperation1 for more information on using the OutputService1TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService1TestCaseOperation1Request method. +// req, resp := client.OutputService1TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1Request(input *OutputService1TestShapeOutputService1TestCaseOperation1Input) (req *request.Request, output *OutputService1TestShapeOutputService1TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService1TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService1TestShapeOutputService1TestCaseOperation1Input{} + } + + output = &OutputService1TestShapeOutputService1TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService1TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService1TestCaseOperation1 for usage and error information. +func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1(input *OutputService1TestShapeOutputService1TestCaseOperation1Input) (*OutputService1TestShapeOutputService1TestCaseOperation1Output, error) { + req, out := c.OutputService1TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService1TestCaseOperation1WithContext is the same as OutputService1TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService1TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1WithContext(ctx aws.Context, input *OutputService1TestShapeOutputService1TestCaseOperation1Input, opts ...request.Option) (*OutputService1TestShapeOutputService1TestCaseOperation1Output, error) { + req, out := c.OutputService1TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService1TestShapeOutputService1TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService1TestShapeOutputService1TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Char *string `type:"character"` + + Double *float64 `type:"double"` + + FalseBool *bool `type:"boolean"` + + Float *float64 `type:"float"` + + Long *int64 `type:"long"` + + Num *int64 `locationName:"FooNum" type:"integer"` + + Str *string `type:"string"` + + Timestamp *time.Time `type:"timestamp" timestampFormat:"iso8601"` + + TrueBool *bool `type:"boolean"` +} + +// SetChar sets the Char field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetChar(v string) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Char = &v + return s +} + +// SetDouble sets the Double field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetDouble(v float64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Double = &v + return s +} + +// SetFalseBool sets the FalseBool field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetFalseBool(v bool) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.FalseBool = &v + return s +} + +// SetFloat sets the Float field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetFloat(v float64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Float = &v + return s +} + +// SetLong sets the Long field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetLong(v int64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Long = &v + return s +} + +// SetNum sets the Num field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetNum(v int64) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Num = &v + return s +} + +// SetStr sets the Str field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetStr(v string) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Str = &v + return s +} + +// SetTimestamp sets the Timestamp field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetTimestamp(v time.Time) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.Timestamp = &v + return s +} + +// SetTrueBool sets the TrueBool field's value. +func (s *OutputService1TestShapeOutputService1TestCaseOperation1Output) SetTrueBool(v bool) *OutputService1TestShapeOutputService1TestCaseOperation1Output { + s.TrueBool = &v + return s +} + +// OutputService2ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService2ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService2ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService2ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService2ProtocolTest client from just a session. +// svc := outputservice2protocoltest.New(mySession) +// +// // Create a OutputService2ProtocolTest client with additional configuration +// svc := outputservice2protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService2ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService2ProtocolTest { + c := p.ClientConfig("outputservice2protocoltest", cfgs...) + return newOutputService2ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService2ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService2ProtocolTest { + svc := &OutputService2ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice2protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService2ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService2ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService2TestCaseOperation1 = "OperationName" + +// OutputService2TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService2TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService2TestCaseOperation1 for more information on using the OutputService2TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService2TestCaseOperation1Request method. +// req, resp := client.OutputService2TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1Request(input *OutputService2TestShapeOutputService2TestCaseOperation1Input) (req *request.Request, output *OutputService2TestShapeOutputService2TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService2TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService2TestShapeOutputService2TestCaseOperation1Input{} + } + + output = &OutputService2TestShapeOutputService2TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService2TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService2TestCaseOperation1 for usage and error information. +func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1(input *OutputService2TestShapeOutputService2TestCaseOperation1Input) (*OutputService2TestShapeOutputService2TestCaseOperation1Output, error) { + req, out := c.OutputService2TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService2TestCaseOperation1WithContext is the same as OutputService2TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService2TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1WithContext(ctx aws.Context, input *OutputService2TestShapeOutputService2TestCaseOperation1Input, opts ...request.Option) (*OutputService2TestShapeOutputService2TestCaseOperation1Output, error) { + req, out := c.OutputService2TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService2TestShapeOutputService2TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService2TestShapeOutputService2TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Num *int64 `type:"integer"` + + Str *string `type:"string"` +} + +// SetNum sets the Num field's value. +func (s *OutputService2TestShapeOutputService2TestCaseOperation1Output) SetNum(v int64) *OutputService2TestShapeOutputService2TestCaseOperation1Output { + s.Num = &v + return s +} + +// SetStr sets the Str field's value. +func (s *OutputService2TestShapeOutputService2TestCaseOperation1Output) SetStr(v string) *OutputService2TestShapeOutputService2TestCaseOperation1Output { + s.Str = &v + return s +} + +// OutputService3ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService3ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService3ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService3ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService3ProtocolTest client from just a session. +// svc := outputservice3protocoltest.New(mySession) +// +// // Create a OutputService3ProtocolTest client with additional configuration +// svc := outputservice3protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService3ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService3ProtocolTest { + c := p.ClientConfig("outputservice3protocoltest", cfgs...) + return newOutputService3ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService3ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService3ProtocolTest { + svc := &OutputService3ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice3protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService3ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService3ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService3TestCaseOperation1 = "OperationName" + +// OutputService3TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService3TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService3TestCaseOperation1 for more information on using the OutputService3TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService3TestCaseOperation1Request method. +// req, resp := client.OutputService3TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1Request(input *OutputService3TestShapeOutputService3TestCaseOperation1Input) (req *request.Request, output *OutputService3TestShapeOutputService3TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService3TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService3TestShapeOutputService3TestCaseOperation1Input{} + } + + output = &OutputService3TestShapeOutputService3TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService3TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService3TestCaseOperation1 for usage and error information. +func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1(input *OutputService3TestShapeOutputService3TestCaseOperation1Input) (*OutputService3TestShapeOutputService3TestCaseOperation1Output, error) { + req, out := c.OutputService3TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService3TestCaseOperation1WithContext is the same as OutputService3TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService3TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1WithContext(ctx aws.Context, input *OutputService3TestShapeOutputService3TestCaseOperation1Input, opts ...request.Option) (*OutputService3TestShapeOutputService3TestCaseOperation1Output, error) { + req, out := c.OutputService3TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService3TestShapeOutputService3TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService3TestShapeOutputService3TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + // Blob is automatically base64 encoded/decoded by the SDK. + Blob []byte `type:"blob"` +} + +// SetBlob sets the Blob field's value. +func (s *OutputService3TestShapeOutputService3TestCaseOperation1Output) SetBlob(v []byte) *OutputService3TestShapeOutputService3TestCaseOperation1Output { + s.Blob = v + return s +} + +// OutputService4ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService4ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService4ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService4ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService4ProtocolTest client from just a session. +// svc := outputservice4protocoltest.New(mySession) +// +// // Create a OutputService4ProtocolTest client with additional configuration +// svc := outputservice4protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService4ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService4ProtocolTest { + c := p.ClientConfig("outputservice4protocoltest", cfgs...) + return newOutputService4ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService4ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService4ProtocolTest { + svc := &OutputService4ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice4protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService4ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService4ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService4TestCaseOperation1 = "OperationName" + +// OutputService4TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService4TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService4TestCaseOperation1 for more information on using the OutputService4TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService4TestCaseOperation1Request method. +// req, resp := client.OutputService4TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (req *request.Request, output *OutputService4TestShapeOutputService4TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService4TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService4TestShapeOutputService4TestCaseOperation1Input{} + } + + output = &OutputService4TestShapeOutputService4TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService4TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService4TestCaseOperation1 for usage and error information. +func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (*OutputService4TestShapeOutputService4TestCaseOperation1Output, error) { + req, out := c.OutputService4TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService4TestCaseOperation1WithContext is the same as OutputService4TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService4TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1WithContext(ctx aws.Context, input *OutputService4TestShapeOutputService4TestCaseOperation1Input, opts ...request.Option) (*OutputService4TestShapeOutputService4TestCaseOperation1Output, error) { + req, out := c.OutputService4TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService4TestShapeOutputService4TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService4TestShapeOutputService4TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `type:"list"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService4TestShapeOutputService4TestCaseOperation1Output) SetListMember(v []*string) *OutputService4TestShapeOutputService4TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService5ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService5ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService5ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService5ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService5ProtocolTest client from just a session. +// svc := outputservice5protocoltest.New(mySession) +// +// // Create a OutputService5ProtocolTest client with additional configuration +// svc := outputservice5protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService5ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService5ProtocolTest { + c := p.ClientConfig("outputservice5protocoltest", cfgs...) + return newOutputService5ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService5ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService5ProtocolTest { + svc := &OutputService5ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice5protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService5ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService5ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService5TestCaseOperation1 = "OperationName" + +// OutputService5TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService5TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService5TestCaseOperation1 for more information on using the OutputService5TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService5TestCaseOperation1Request method. +// req, resp := client.OutputService5TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1Request(input *OutputService5TestShapeOutputService5TestCaseOperation1Input) (req *request.Request, output *OutputService5TestShapeOutputService5TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService5TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService5TestShapeOutputService5TestCaseOperation1Input{} + } + + output = &OutputService5TestShapeOutputService5TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService5TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService5TestCaseOperation1 for usage and error information. +func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1(input *OutputService5TestShapeOutputService5TestCaseOperation1Input) (*OutputService5TestShapeOutputService5TestCaseOperation1Output, error) { + req, out := c.OutputService5TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService5TestCaseOperation1WithContext is the same as OutputService5TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService5TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1WithContext(ctx aws.Context, input *OutputService5TestShapeOutputService5TestCaseOperation1Input, opts ...request.Option) (*OutputService5TestShapeOutputService5TestCaseOperation1Output, error) { + req, out := c.OutputService5TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService5TestShapeOutputService5TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService5TestShapeOutputService5TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `locationNameList:"item" type:"list"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService5TestShapeOutputService5TestCaseOperation1Output) SetListMember(v []*string) *OutputService5TestShapeOutputService5TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService6ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService6ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService6ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService6ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService6ProtocolTest client from just a session. +// svc := outputservice6protocoltest.New(mySession) +// +// // Create a OutputService6ProtocolTest client with additional configuration +// svc := outputservice6protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService6ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService6ProtocolTest { + c := p.ClientConfig("outputservice6protocoltest", cfgs...) + return newOutputService6ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService6ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService6ProtocolTest { + svc := &OutputService6ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice6protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService6ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService6ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService6TestCaseOperation1 = "OperationName" + +// OutputService6TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService6TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService6TestCaseOperation1 for more information on using the OutputService6TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService6TestCaseOperation1Request method. +// req, resp := client.OutputService6TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1Request(input *OutputService6TestShapeOutputService6TestCaseOperation1Input) (req *request.Request, output *OutputService6TestShapeOutputService6TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService6TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService6TestShapeOutputService6TestCaseOperation1Input{} + } + + output = &OutputService6TestShapeOutputService6TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService6TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService6TestCaseOperation1 for usage and error information. +func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1(input *OutputService6TestShapeOutputService6TestCaseOperation1Input) (*OutputService6TestShapeOutputService6TestCaseOperation1Output, error) { + req, out := c.OutputService6TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService6TestCaseOperation1WithContext is the same as OutputService6TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService6TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1WithContext(ctx aws.Context, input *OutputService6TestShapeOutputService6TestCaseOperation1Input, opts ...request.Option) (*OutputService6TestShapeOutputService6TestCaseOperation1Output, error) { + req, out := c.OutputService6TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService6TestShapeOutputService6TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService6TestShapeOutputService6TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `type:"list" flattened:"true"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService6TestShapeOutputService6TestCaseOperation1Output) SetListMember(v []*string) *OutputService6TestShapeOutputService6TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService7ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService7ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService7ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService7ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService7ProtocolTest client from just a session. +// svc := outputservice7protocoltest.New(mySession) +// +// // Create a OutputService7ProtocolTest client with additional configuration +// svc := outputservice7protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService7ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService7ProtocolTest { + c := p.ClientConfig("outputservice7protocoltest", cfgs...) + return newOutputService7ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService7ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService7ProtocolTest { + svc := &OutputService7ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice7protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService7ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService7ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService7TestCaseOperation1 = "OperationName" + +// OutputService7TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService7TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService7TestCaseOperation1 for more information on using the OutputService7TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService7TestCaseOperation1Request method. +// req, resp := client.OutputService7TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1Request(input *OutputService7TestShapeOutputService7TestCaseOperation1Input) (req *request.Request, output *OutputService7TestShapeOutputService7TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService7TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService7TestShapeOutputService7TestCaseOperation1Input{} + } + + output = &OutputService7TestShapeOutputService7TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService7TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService7TestCaseOperation1 for usage and error information. +func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1(input *OutputService7TestShapeOutputService7TestCaseOperation1Input) (*OutputService7TestShapeOutputService7TestCaseOperation1Output, error) { + req, out := c.OutputService7TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService7TestCaseOperation1WithContext is the same as OutputService7TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService7TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1WithContext(ctx aws.Context, input *OutputService7TestShapeOutputService7TestCaseOperation1Input, opts ...request.Option) (*OutputService7TestShapeOutputService7TestCaseOperation1Output, error) { + req, out := c.OutputService7TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService7TestShapeOutputService7TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService7TestShapeOutputService7TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + ListMember []*string `type:"list" flattened:"true"` +} + +// SetListMember sets the ListMember field's value. +func (s *OutputService7TestShapeOutputService7TestCaseOperation1Output) SetListMember(v []*string) *OutputService7TestShapeOutputService7TestCaseOperation1Output { + s.ListMember = v + return s +} + +// OutputService8ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService8ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService8ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService8ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService8ProtocolTest client from just a session. +// svc := outputservice8protocoltest.New(mySession) +// +// // Create a OutputService8ProtocolTest client with additional configuration +// svc := outputservice8protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService8ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService8ProtocolTest { + c := p.ClientConfig("outputservice8protocoltest", cfgs...) + return newOutputService8ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService8ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService8ProtocolTest { + svc := &OutputService8ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice8protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService8ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService8ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService8TestCaseOperation1 = "OperationName" + +// OutputService8TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService8TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService8TestCaseOperation1 for more information on using the OutputService8TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService8TestCaseOperation1Request method. +// req, resp := client.OutputService8TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1Request(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (req *request.Request, output *OutputService8TestShapeOutputService8TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService8TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService8TestShapeOutputService8TestCaseOperation1Input{} + } + + output = &OutputService8TestShapeOutputService8TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService8TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService8TestCaseOperation1 for usage and error information. +func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (*OutputService8TestShapeOutputService8TestCaseOperation1Output, error) { + req, out := c.OutputService8TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService8TestCaseOperation1WithContext is the same as OutputService8TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService8TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1WithContext(ctx aws.Context, input *OutputService8TestShapeOutputService8TestCaseOperation1Input, opts ...request.Option) (*OutputService8TestShapeOutputService8TestCaseOperation1Output, error) { + req, out := c.OutputService8TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService8TestShapeOutputService8TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService8TestShapeOutputService8TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + List []*OutputService8TestShapeStructureShape `type:"list"` +} + +// SetList sets the List field's value. +func (s *OutputService8TestShapeOutputService8TestCaseOperation1Output) SetList(v []*OutputService8TestShapeStructureShape) *OutputService8TestShapeOutputService8TestCaseOperation1Output { + s.List = v + return s +} + +type OutputService8TestShapeStructureShape struct { + _ struct{} `type:"structure"` + + Bar *string `type:"string"` + + Baz *string `type:"string"` + + Foo *string `type:"string"` +} + +// SetBar sets the Bar field's value. +func (s *OutputService8TestShapeStructureShape) SetBar(v string) *OutputService8TestShapeStructureShape { + s.Bar = &v + return s +} + +// SetBaz sets the Baz field's value. +func (s *OutputService8TestShapeStructureShape) SetBaz(v string) *OutputService8TestShapeStructureShape { + s.Baz = &v + return s +} + +// SetFoo sets the Foo field's value. +func (s *OutputService8TestShapeStructureShape) SetFoo(v string) *OutputService8TestShapeStructureShape { + s.Foo = &v + return s +} + +// OutputService9ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService9ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService9ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService9ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService9ProtocolTest client from just a session. +// svc := outputservice9protocoltest.New(mySession) +// +// // Create a OutputService9ProtocolTest client with additional configuration +// svc := outputservice9protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService9ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService9ProtocolTest { + c := p.ClientConfig("outputservice9protocoltest", cfgs...) + return newOutputService9ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService9ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService9ProtocolTest { + svc := &OutputService9ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice9protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService9ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService9ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService9TestCaseOperation1 = "OperationName" + +// OutputService9TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService9TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService9TestCaseOperation1 for more information on using the OutputService9TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService9TestCaseOperation1Request method. +// req, resp := client.OutputService9TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1Request(input *OutputService9TestShapeOutputService9TestCaseOperation1Input) (req *request.Request, output *OutputService9TestShapeOutputService9TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService9TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService9TestShapeOutputService9TestCaseOperation1Input{} + } + + output = &OutputService9TestShapeOutputService9TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService9TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService9TestCaseOperation1 for usage and error information. +func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1(input *OutputService9TestShapeOutputService9TestCaseOperation1Input) (*OutputService9TestShapeOutputService9TestCaseOperation1Output, error) { + req, out := c.OutputService9TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService9TestCaseOperation1WithContext is the same as OutputService9TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService9TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService9ProtocolTest) OutputService9TestCaseOperation1WithContext(ctx aws.Context, input *OutputService9TestShapeOutputService9TestCaseOperation1Input, opts ...request.Option) (*OutputService9TestShapeOutputService9TestCaseOperation1Output, error) { + req, out := c.OutputService9TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService9TestShapeOutputService9TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService9TestShapeOutputService9TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + List []*OutputService9TestShapeStructureShape `type:"list" flattened:"true"` +} + +// SetList sets the List field's value. +func (s *OutputService9TestShapeOutputService9TestCaseOperation1Output) SetList(v []*OutputService9TestShapeStructureShape) *OutputService9TestShapeOutputService9TestCaseOperation1Output { + s.List = v + return s +} + +type OutputService9TestShapeStructureShape struct { + _ struct{} `type:"structure"` + + Bar *string `type:"string"` + + Baz *string `type:"string"` + + Foo *string `type:"string"` +} + +// SetBar sets the Bar field's value. +func (s *OutputService9TestShapeStructureShape) SetBar(v string) *OutputService9TestShapeStructureShape { + s.Bar = &v + return s +} + +// SetBaz sets the Baz field's value. +func (s *OutputService9TestShapeStructureShape) SetBaz(v string) *OutputService9TestShapeStructureShape { + s.Baz = &v + return s +} + +// SetFoo sets the Foo field's value. +func (s *OutputService9TestShapeStructureShape) SetFoo(v string) *OutputService9TestShapeStructureShape { + s.Foo = &v + return s +} + +// OutputService10ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService10ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService10ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService10ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService10ProtocolTest client from just a session. +// svc := outputservice10protocoltest.New(mySession) +// +// // Create a OutputService10ProtocolTest client with additional configuration +// svc := outputservice10protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService10ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService10ProtocolTest { + c := p.ClientConfig("outputservice10protocoltest", cfgs...) + return newOutputService10ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService10ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService10ProtocolTest { + svc := &OutputService10ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice10protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService10ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService10ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService10TestCaseOperation1 = "OperationName" + +// OutputService10TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService10TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService10TestCaseOperation1 for more information on using the OutputService10TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService10TestCaseOperation1Request method. +// req, resp := client.OutputService10TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService10ProtocolTest) OutputService10TestCaseOperation1Request(input *OutputService10TestShapeOutputService10TestCaseOperation1Input) (req *request.Request, output *OutputService10TestShapeOutputService10TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService10TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService10TestShapeOutputService10TestCaseOperation1Input{} + } + + output = &OutputService10TestShapeOutputService10TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService10TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService10TestCaseOperation1 for usage and error information. +func (c *OutputService10ProtocolTest) OutputService10TestCaseOperation1(input *OutputService10TestShapeOutputService10TestCaseOperation1Input) (*OutputService10TestShapeOutputService10TestCaseOperation1Output, error) { + req, out := c.OutputService10TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService10TestCaseOperation1WithContext is the same as OutputService10TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService10TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService10ProtocolTest) OutputService10TestCaseOperation1WithContext(ctx aws.Context, input *OutputService10TestShapeOutputService10TestCaseOperation1Input, opts ...request.Option) (*OutputService10TestShapeOutputService10TestCaseOperation1Output, error) { + req, out := c.OutputService10TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService10TestShapeOutputService10TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService10TestShapeOutputService10TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + List []*string `locationNameList:"NamedList" type:"list" flattened:"true"` +} + +// SetList sets the List field's value. +func (s *OutputService10TestShapeOutputService10TestCaseOperation1Output) SetList(v []*string) *OutputService10TestShapeOutputService10TestCaseOperation1Output { + s.List = v + return s +} + +// OutputService11ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService11ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService11ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService11ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService11ProtocolTest client from just a session. +// svc := outputservice11protocoltest.New(mySession) +// +// // Create a OutputService11ProtocolTest client with additional configuration +// svc := outputservice11protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService11ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService11ProtocolTest { + c := p.ClientConfig("outputservice11protocoltest", cfgs...) + return newOutputService11ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService11ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService11ProtocolTest { + svc := &OutputService11ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice11protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService11ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService11ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService11TestCaseOperation1 = "OperationName" + +// OutputService11TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService11TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService11TestCaseOperation1 for more information on using the OutputService11TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService11TestCaseOperation1Request method. +// req, resp := client.OutputService11TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService11ProtocolTest) OutputService11TestCaseOperation1Request(input *OutputService11TestShapeOutputService11TestCaseOperation1Input) (req *request.Request, output *OutputService11TestShapeOutputService11TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService11TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService11TestShapeOutputService11TestCaseOperation1Input{} + } + + output = &OutputService11TestShapeOutputService11TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService11TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService11TestCaseOperation1 for usage and error information. +func (c *OutputService11ProtocolTest) OutputService11TestCaseOperation1(input *OutputService11TestShapeOutputService11TestCaseOperation1Input) (*OutputService11TestShapeOutputService11TestCaseOperation1Output, error) { + req, out := c.OutputService11TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService11TestCaseOperation1WithContext is the same as OutputService11TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService11TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService11ProtocolTest) OutputService11TestCaseOperation1WithContext(ctx aws.Context, input *OutputService11TestShapeOutputService11TestCaseOperation1Input, opts ...request.Option) (*OutputService11TestShapeOutputService11TestCaseOperation1Output, error) { + req, out := c.OutputService11TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService11TestShapeOutputService11TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService11TestShapeOutputService11TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*OutputService11TestShapeStructType `type:"map"` +} + +// SetMap sets the Map field's value. +func (s *OutputService11TestShapeOutputService11TestCaseOperation1Output) SetMap(v map[string]*OutputService11TestShapeStructType) *OutputService11TestShapeOutputService11TestCaseOperation1Output { + s.Map = v + return s +} + +type OutputService11TestShapeStructType struct { + _ struct{} `type:"structure"` + + Foo *string `locationName:"foo" type:"string"` +} + +// SetFoo sets the Foo field's value. +func (s *OutputService11TestShapeStructType) SetFoo(v string) *OutputService11TestShapeStructType { + s.Foo = &v + return s +} + +// OutputService12ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService12ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService12ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService12ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService12ProtocolTest client from just a session. +// svc := outputservice12protocoltest.New(mySession) +// +// // Create a OutputService12ProtocolTest client with additional configuration +// svc := outputservice12protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService12ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService12ProtocolTest { + c := p.ClientConfig("outputservice12protocoltest", cfgs...) + return newOutputService12ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService12ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService12ProtocolTest { + svc := &OutputService12ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice12protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService12ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService12ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService12TestCaseOperation1 = "OperationName" + +// OutputService12TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService12TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService12TestCaseOperation1 for more information on using the OutputService12TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService12TestCaseOperation1Request method. +// req, resp := client.OutputService12TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService12ProtocolTest) OutputService12TestCaseOperation1Request(input *OutputService12TestShapeOutputService12TestCaseOperation1Input) (req *request.Request, output *OutputService12TestShapeOutputService12TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService12TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService12TestShapeOutputService12TestCaseOperation1Input{} + } + + output = &OutputService12TestShapeOutputService12TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService12TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService12TestCaseOperation1 for usage and error information. +func (c *OutputService12ProtocolTest) OutputService12TestCaseOperation1(input *OutputService12TestShapeOutputService12TestCaseOperation1Input) (*OutputService12TestShapeOutputService12TestCaseOperation1Output, error) { + req, out := c.OutputService12TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService12TestCaseOperation1WithContext is the same as OutputService12TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService12TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService12ProtocolTest) OutputService12TestCaseOperation1WithContext(ctx aws.Context, input *OutputService12TestShapeOutputService12TestCaseOperation1Input, opts ...request.Option) (*OutputService12TestShapeOutputService12TestCaseOperation1Output, error) { + req, out := c.OutputService12TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService12TestShapeOutputService12TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService12TestShapeOutputService12TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*string `type:"map" flattened:"true"` +} + +// SetMap sets the Map field's value. +func (s *OutputService12TestShapeOutputService12TestCaseOperation1Output) SetMap(v map[string]*string) *OutputService12TestShapeOutputService12TestCaseOperation1Output { + s.Map = v + return s +} + +// OutputService13ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService13ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService13ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService13ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService13ProtocolTest client from just a session. +// svc := outputservice13protocoltest.New(mySession) +// +// // Create a OutputService13ProtocolTest client with additional configuration +// svc := outputservice13protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService13ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService13ProtocolTest { + c := p.ClientConfig("outputservice13protocoltest", cfgs...) + return newOutputService13ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService13ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService13ProtocolTest { + svc := &OutputService13ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice13protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService13ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService13ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService13TestCaseOperation1 = "OperationName" + +// OutputService13TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService13TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService13TestCaseOperation1 for more information on using the OutputService13TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService13TestCaseOperation1Request method. +// req, resp := client.OutputService13TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService13ProtocolTest) OutputService13TestCaseOperation1Request(input *OutputService13TestShapeOutputService13TestCaseOperation1Input) (req *request.Request, output *OutputService13TestShapeOutputService13TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService13TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService13TestShapeOutputService13TestCaseOperation1Input{} + } + + output = &OutputService13TestShapeOutputService13TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService13TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService13TestCaseOperation1 for usage and error information. +func (c *OutputService13ProtocolTest) OutputService13TestCaseOperation1(input *OutputService13TestShapeOutputService13TestCaseOperation1Input) (*OutputService13TestShapeOutputService13TestCaseOperation1Output, error) { + req, out := c.OutputService13TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService13TestCaseOperation1WithContext is the same as OutputService13TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService13TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService13ProtocolTest) OutputService13TestCaseOperation1WithContext(ctx aws.Context, input *OutputService13TestShapeOutputService13TestCaseOperation1Input, opts ...request.Option) (*OutputService13TestShapeOutputService13TestCaseOperation1Output, error) { + req, out := c.OutputService13TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService13TestShapeOutputService13TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService13TestShapeOutputService13TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*string `locationName:"Attribute" locationNameKey:"Name" locationNameValue:"Value" type:"map" flattened:"true"` +} + +// SetMap sets the Map field's value. +func (s *OutputService13TestShapeOutputService13TestCaseOperation1Output) SetMap(v map[string]*string) *OutputService13TestShapeOutputService13TestCaseOperation1Output { + s.Map = v + return s +} + +// OutputService14ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService14ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService14ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService14ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService14ProtocolTest client from just a session. +// svc := outputservice14protocoltest.New(mySession) +// +// // Create a OutputService14ProtocolTest client with additional configuration +// svc := outputservice14protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService14ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService14ProtocolTest { + c := p.ClientConfig("outputservice14protocoltest", cfgs...) + return newOutputService14ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService14ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService14ProtocolTest { + svc := &OutputService14ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice14protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService14ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService14ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService14TestCaseOperation1 = "OperationName" + +// OutputService14TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService14TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService14TestCaseOperation1 for more information on using the OutputService14TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService14TestCaseOperation1Request method. +// req, resp := client.OutputService14TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService14ProtocolTest) OutputService14TestCaseOperation1Request(input *OutputService14TestShapeOutputService14TestCaseOperation1Input) (req *request.Request, output *OutputService14TestShapeOutputService14TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService14TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService14TestShapeOutputService14TestCaseOperation1Input{} + } + + output = &OutputService14TestShapeOutputService14TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService14TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService14TestCaseOperation1 for usage and error information. +func (c *OutputService14ProtocolTest) OutputService14TestCaseOperation1(input *OutputService14TestShapeOutputService14TestCaseOperation1Input) (*OutputService14TestShapeOutputService14TestCaseOperation1Output, error) { + req, out := c.OutputService14TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService14TestCaseOperation1WithContext is the same as OutputService14TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService14TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService14ProtocolTest) OutputService14TestCaseOperation1WithContext(ctx aws.Context, input *OutputService14TestShapeOutputService14TestCaseOperation1Input, opts ...request.Option) (*OutputService14TestShapeOutputService14TestCaseOperation1Output, error) { + req, out := c.OutputService14TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService14TestShapeOutputService14TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService14TestShapeOutputService14TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Map map[string]*string `locationNameKey:"foo" locationNameValue:"bar" type:"map" flattened:"true"` +} + +// SetMap sets the Map field's value. +func (s *OutputService14TestShapeOutputService14TestCaseOperation1Output) SetMap(v map[string]*string) *OutputService14TestShapeOutputService14TestCaseOperation1Output { + s.Map = v + return s +} + +// OutputService15ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService15ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService15ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService15ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService15ProtocolTest client from just a session. +// svc := outputservice15protocoltest.New(mySession) +// +// // Create a OutputService15ProtocolTest client with additional configuration +// svc := outputservice15protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService15ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService15ProtocolTest { + c := p.ClientConfig("outputservice15protocoltest", cfgs...) + return newOutputService15ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService15ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService15ProtocolTest { + svc := &OutputService15ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice15protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService15ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService15ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService15TestCaseOperation1 = "OperationName" + +// OutputService15TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService15TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService15TestCaseOperation1 for more information on using the OutputService15TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService15TestCaseOperation1Request method. +// req, resp := client.OutputService15TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService15ProtocolTest) OutputService15TestCaseOperation1Request(input *OutputService15TestShapeOutputService15TestCaseOperation1Input) (req *request.Request, output *OutputService15TestShapeOutputService15TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService15TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService15TestShapeOutputService15TestCaseOperation1Input{} + } + + output = &OutputService15TestShapeOutputService15TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService15TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService15TestCaseOperation1 for usage and error information. +func (c *OutputService15ProtocolTest) OutputService15TestCaseOperation1(input *OutputService15TestShapeOutputService15TestCaseOperation1Input) (*OutputService15TestShapeOutputService15TestCaseOperation1Output, error) { + req, out := c.OutputService15TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService15TestCaseOperation1WithContext is the same as OutputService15TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService15TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService15ProtocolTest) OutputService15TestCaseOperation1WithContext(ctx aws.Context, input *OutputService15TestShapeOutputService15TestCaseOperation1Input, opts ...request.Option) (*OutputService15TestShapeOutputService15TestCaseOperation1Output, error) { + req, out := c.OutputService15TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService15TestShapeOutputService15TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService15TestShapeOutputService15TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + Foo *string `type:"string"` +} + +// SetFoo sets the Foo field's value. +func (s *OutputService15TestShapeOutputService15TestCaseOperation1Output) SetFoo(v string) *OutputService15TestShapeOutputService15TestCaseOperation1Output { + s.Foo = &v + return s +} + +// OutputService16ProtocolTest provides the API operation methods for making requests to +// . See this package's package overview docs +// for details on the service. +// +// OutputService16ProtocolTest methods are safe to use concurrently. It is not safe to +// modify mutate any of the struct's properties though. +type OutputService16ProtocolTest struct { + *client.Client +} + +// New creates a new instance of the OutputService16ProtocolTest client with a session. +// If additional configuration is needed for the client instance use the optional +// aws.Config parameter to add your extra config. +// +// Example: +// // Create a OutputService16ProtocolTest client from just a session. +// svc := outputservice16protocoltest.New(mySession) +// +// // Create a OutputService16ProtocolTest client with additional configuration +// svc := outputservice16protocoltest.New(mySession, aws.NewConfig().WithRegion("us-west-2")) +func NewOutputService16ProtocolTest(p client.ConfigProvider, cfgs ...*aws.Config) *OutputService16ProtocolTest { + c := p.ClientConfig("outputservice16protocoltest", cfgs...) + return newOutputService16ProtocolTestClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName) +} + +// newClient creates, initializes and returns a new service client instance. +func newOutputService16ProtocolTestClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *OutputService16ProtocolTest { + svc := &OutputService16ProtocolTest{ + Client: client.New( + cfg, + metadata.ClientInfo{ + ServiceName: "outputservice16protocoltest", + SigningName: signingName, + SigningRegion: signingRegion, + Endpoint: endpoint, + APIVersion: "", + }, + handlers, + ), + } + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(query.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(query.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(query.UnmarshalMetaHandler) + svc.Handlers.UnmarshalError.PushBackNamed(query.UnmarshalErrorHandler) + + return svc +} + +// newRequest creates a new request for a OutputService16ProtocolTest operation and runs any +// custom request initialization. +func (c *OutputService16ProtocolTest) newRequest(op *request.Operation, params, data interface{}) *request.Request { + req := c.NewRequest(op, params, data) + + return req +} + +const opOutputService16TestCaseOperation1 = "OperationName" + +// OutputService16TestCaseOperation1Request generates a "aws/request.Request" representing the +// client's request for the OutputService16TestCaseOperation1 operation. The "output" return +// value will be populated with the request's response once the request completes +// successfuly. +// +// Use "Send" method on the returned Request to send the API call to the service. +// the "output" return value is not valid until after Send returns without error. +// +// See OutputService16TestCaseOperation1 for more information on using the OutputService16TestCaseOperation1 +// API call, and error handling. +// +// This method is useful when you want to inject custom logic or configuration +// into the SDK's request lifecycle. Such as custom headers, or retry logic. +// +// +// // Example sending a request using the OutputService16TestCaseOperation1Request method. +// req, resp := client.OutputService16TestCaseOperation1Request(params) +// +// err := req.Send() +// if err == nil { // resp is now filled +// fmt.Println(resp) +// } +func (c *OutputService16ProtocolTest) OutputService16TestCaseOperation1Request(input *OutputService16TestShapeOutputService16TestCaseOperation1Input) (req *request.Request, output *OutputService16TestShapeOutputService16TestCaseOperation1Output) { + op := &request.Operation{ + Name: opOutputService16TestCaseOperation1, + HTTPPath: "/", + } + + if input == nil { + input = &OutputService16TestShapeOutputService16TestCaseOperation1Input{} + } + + output = &OutputService16TestShapeOutputService16TestCaseOperation1Output{} + req = c.newRequest(op, input, output) + return +} + +// OutputService16TestCaseOperation1 API operation for . +// +// Returns awserr.Error for service API and SDK errors. Use runtime type assertions +// with awserr.Error's Code and Message methods to get detailed information about +// the error. +// +// See the AWS API reference guide for 's +// API operation OutputService16TestCaseOperation1 for usage and error information. +func (c *OutputService16ProtocolTest) OutputService16TestCaseOperation1(input *OutputService16TestShapeOutputService16TestCaseOperation1Input) (*OutputService16TestShapeOutputService16TestCaseOperation1Output, error) { + req, out := c.OutputService16TestCaseOperation1Request(input) + return out, req.Send() +} + +// OutputService16TestCaseOperation1WithContext is the same as OutputService16TestCaseOperation1 with the addition of +// the ability to pass a context and additional request options. +// +// See OutputService16TestCaseOperation1 for details on how to use this API operation. +// +// The context must be non-nil and will be used for request cancellation. If +// the context is nil a panic will occur. In the future the SDK may create +// sub-contexts for http.Requests. See https://golang.org/pkg/context/ +// for more information on using Contexts. +func (c *OutputService16ProtocolTest) OutputService16TestCaseOperation1WithContext(ctx aws.Context, input *OutputService16TestShapeOutputService16TestCaseOperation1Input, opts ...request.Option) (*OutputService16TestShapeOutputService16TestCaseOperation1Output, error) { + req, out := c.OutputService16TestCaseOperation1Request(input) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return out, req.Send() +} + +type OutputService16TestShapeOutputService16TestCaseOperation1Input struct { + _ struct{} `type:"structure"` +} + +type OutputService16TestShapeOutputService16TestCaseOperation1Output struct { + _ struct{} `type:"structure"` + + FooEnum *string `type:"string" enum:"OutputService16TestShapeEC2EnumType"` + + ListEnums []*string `type:"list"` +} + +// SetFooEnum sets the FooEnum field's value. +func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetFooEnum(v string) *OutputService16TestShapeOutputService16TestCaseOperation1Output { + s.FooEnum = &v + return s +} + +// SetListEnums sets the ListEnums field's value. +func (s *OutputService16TestShapeOutputService16TestCaseOperation1Output) SetListEnums(v []*string) *OutputService16TestShapeOutputService16TestCaseOperation1Output { + s.ListEnums = v + return s +} + +const ( + // EC2EnumTypeFoo is a OutputService16TestShapeEC2EnumType enum value + EC2EnumTypeFoo = "foo" + + // EC2EnumTypeBar is a OutputService16TestShapeEC2EnumType enum value + EC2EnumTypeBar = "bar" +) + +// +// Tests begin here +// + +func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) { + svc := NewOutputService1ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("myname123falsetrue1.21.3200a2015-01-25T08:00:00Zrequest-id")) + req, out := svc.OutputService1TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "a", *out.Char; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := 1.3, *out.Double; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := false, *out.FalseBool; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := 1.2, *out.Float; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := int64(200), *out.Long; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := int64(123), *out.Num; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "myname", *out.Str; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := time.Unix(1.4221728e+09, 0).UTC().String(), out.Timestamp.String(); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := true, *out.TrueBool; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService2ProtocolTestNotAllMembersInResponseCase1(t *testing.T) { + svc := NewOutputService2ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("mynamerequest-id")) + req, out := svc.OutputService2TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "myname", *out.Str; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService3ProtocolTestBlobCase1(t *testing.T) { + svc := NewOutputService3ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("dmFsdWU=requestid")) + req, out := svc.OutputService3TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "value", string(out.Blob); e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService4ProtocolTestListsCase1(t *testing.T) { + svc := NewOutputService4ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abc123requestid")) + req, out := svc.OutputService4TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "123", *out.ListMember[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService5ProtocolTestListWithCustomMemberNameCase1(t *testing.T) { + svc := NewOutputService5ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abc123requestid")) + req, out := svc.OutputService5TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "123", *out.ListMember[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService6ProtocolTestFlattenedListCase1(t *testing.T) { + svc := NewOutputService6ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abc123requestid")) + req, out := svc.OutputService6TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "123", *out.ListMember[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService7ProtocolTestFlattenedSingleElementListCase1(t *testing.T) { + svc := NewOutputService7ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abcrequestid")) + req, out := svc.OutputService7TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "abc", *out.ListMember[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService8ProtocolTestListOfStructuresCase1(t *testing.T) { + svc := NewOutputService8ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("firstfoofirstbarfirstbazsecondfoosecondbarsecondbazrequestid")) + req, out := svc.OutputService8TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "firstbar", *out.List[0].Bar; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "firstbaz", *out.List[0].Baz; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "firstfoo", *out.List[0].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "secondbar", *out.List[1].Bar; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "secondbaz", *out.List[1].Baz; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "secondfoo", *out.List[1].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService9ProtocolTestFlattenedListOfStructuresCase1(t *testing.T) { + svc := NewOutputService9ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("firstfoofirstbarfirstbazsecondfoosecondbarsecondbazrequestid")) + req, out := svc.OutputService9TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "firstbar", *out.List[0].Bar; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "firstbaz", *out.List[0].Baz; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "firstfoo", *out.List[0].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "secondbar", *out.List[1].Bar; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "secondbaz", *out.List[1].Baz; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "secondfoo", *out.List[1].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService10ProtocolTestFlattenedListWithLocationNameCase1(t *testing.T) { + svc := NewOutputService10ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("abrequestid")) + req, out := svc.OutputService10TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "a", *out.List[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "b", *out.List[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService11ProtocolTestNormalMapCase1(t *testing.T) { + svc := NewOutputService11ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarbazbamrequestid")) + req, out := svc.OutputService11TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bam", *out.Map["baz"].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.Map["qux"].Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService12ProtocolTestFlattenedMapCase1(t *testing.T) { + svc := NewOutputService12ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarbazbamrequestid")) + req, out := svc.OutputService12TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bam", *out.Map["baz"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.Map["qux"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService13ProtocolTestFlattenedMapInShapeDefinitionCase1(t *testing.T) { + svc := NewOutputService13ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarrequestid")) + req, out := svc.OutputService13TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bar", *out.Map["qux"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService14ProtocolTestNamedMapCase1(t *testing.T) { + svc := NewOutputService14ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("quxbarbazbamrequestid")) + req, out := svc.OutputService14TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "bam", *out.Map["baz"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.Map["qux"]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService15ProtocolTestEmptyStringCase1(t *testing.T) { + svc := NewOutputService15ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("requestid")) + req, out := svc.OutputService15TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "", *out.Foo; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} + +func TestOutputService16ProtocolTestEnumOutputCase1(t *testing.T) { + svc := NewOutputService16ProtocolTest(unit.Session, &aws.Config{Endpoint: aws.String("https://test")}) + + buf := bytes.NewReader([]byte("foofoobar")) + req, out := svc.OutputService16TestCaseOperation1Request(nil) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}} + + // set headers + + // unmarshal response + query.UnmarshalMeta(req) + query.Unmarshal(req) + if req.Error != nil { + t.Errorf("expect not error, got %v", req.Error) + } + + // assert response + if out == nil { + t.Errorf("expect not to be nil") + } + if e, a := "foo", *out.FooEnum; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "foo", *out.ListEnums[0]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "bar", *out.ListEnums[1]; e != a { + t.Errorf("expect %v, got %v", e, a) + } + +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build_test.go new file mode 100644 index 000000000..9f18081a9 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/build_test.go @@ -0,0 +1,63 @@ +package rest + +import ( + "net/http" + "net/url" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" +) + +func TestCleanPath(t *testing.T) { + uri := &url.URL{ + Path: "//foo//bar", + Scheme: "https", + Host: "host", + } + cleanPath(uri) + + expected := "https://host/foo/bar" + if a, e := uri.String(), expected; a != e { + t.Errorf("expect %q URI, got %q", e, a) + } +} + +func TestMarshalPath(t *testing.T) { + in := struct { + Bucket *string `location:"uri" locationName:"bucket"` + Key *string `location:"uri" locationName:"key"` + }{ + Bucket: aws.String("mybucket"), + Key: aws.String("my/cool+thing space/object世界"), + } + + expectURL := `/mybucket/my/cool+thing space/object世界` + expectEscapedURL := `/mybucket/my/cool%2Bthing%20space/object%E4%B8%96%E7%95%8C` + + req := &request.Request{ + HTTPRequest: &http.Request{ + URL: &url.URL{Scheme: "https", Host: "exmaple.com", Path: "/{bucket}/{key+}"}, + }, + Params: &in, + } + + Build(req) + + if req.Error != nil { + t.Fatalf("unexpected error, %v", req.Error) + } + + if a, e := req.HTTPRequest.URL.Path, expectURL; a != e { + t.Errorf("expect %q URI, got %q", e, a) + } + + if a, e := req.HTTPRequest.URL.RawPath, expectEscapedURL; a != e { + t.Errorf("expect %q escaped URI, got %q", e, a) + } + + if a, e := req.HTTPRequest.URL.EscapedPath(), expectEscapedURL; a != e { + t.Errorf("expect %q escaped URI, got %q", e, a) + } + +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/rest_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/rest_test.go new file mode 100644 index 000000000..46457b279 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/rest/rest_test.go @@ -0,0 +1,63 @@ +package rest_test + +import ( + "bytes" + "io/ioutil" + "net/http" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/client/metadata" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/private/protocol/rest" +) + +func TestUnsetHeaders(t *testing.T) { + cfg := &aws.Config{Region: aws.String("us-west-2")} + c := unit.Session.ClientConfig("testService", cfg) + svc := client.New( + *cfg, + metadata.ClientInfo{ + ServiceName: "testService", + SigningName: c.SigningName, + SigningRegion: c.SigningRegion, + Endpoint: c.Endpoint, + APIVersion: "", + }, + c.Handlers, + ) + + // Handlers + svc.Handlers.Sign.PushBackNamed(v4.SignRequestHandler) + svc.Handlers.Build.PushBackNamed(rest.BuildHandler) + svc.Handlers.Unmarshal.PushBackNamed(rest.UnmarshalHandler) + svc.Handlers.UnmarshalMeta.PushBackNamed(rest.UnmarshalMetaHandler) + op := &request.Operation{ + Name: "test-operation", + HTTPPath: "/", + } + + input := &struct { + Foo aws.JSONValue `location:"header" locationName:"x-amz-foo" type:"jsonvalue"` + Bar aws.JSONValue `location:"header" locationName:"x-amz-bar" type:"jsonvalue"` + }{} + + output := &struct { + Foo aws.JSONValue `location:"header" locationName:"x-amz-foo" type:"jsonvalue"` + Bar aws.JSONValue `location:"header" locationName:"x-amz-bar" type:"jsonvalue"` + }{} + + req := svc.NewRequest(op, input, output) + req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBuffer(nil)), Header: http.Header{}} + req.HTTPResponse.Header.Set("X-Amz-Foo", "e30=") + + // unmarshal response + rest.UnmarshalMeta(req) + rest.Unmarshal(req) + if req.Error != nil { + t.Fatal(req.Error) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_test.go new file mode 100644 index 000000000..2733e993d --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_test.go @@ -0,0 +1,40 @@ +package protocol_test + +import ( + "net/http" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/private/protocol" + "github.com/stretchr/testify/assert" +) + +type mockCloser struct { + *strings.Reader + Closed bool +} + +func (m *mockCloser) Close() error { + m.Closed = true + return nil +} + +func TestUnmarshalDrainBody(t *testing.T) { + b := &mockCloser{Reader: strings.NewReader("example body")} + r := &request.Request{HTTPResponse: &http.Response{ + Body: b, + }} + + protocol.UnmarshalDiscardBody(r) + assert.NoError(t, r.Error) + assert.Equal(t, 0, b.Len()) + assert.True(t, b.Closed) +} + +func TestUnmarshalDrainBodyNoBody(t *testing.T) { + r := &request.Request{HTTPResponse: &http.Response{}} + + protocol.UnmarshalDiscardBody(r) + assert.NoError(t, r.Error) +} diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal_test.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal_test.go new file mode 100644 index 000000000..1185d2328 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal_test.go @@ -0,0 +1,142 @@ +package xmlutil + +import ( + "encoding/xml" + "fmt" + "io" + "reflect" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awsutil" +) + +type mockBody struct { + DoneErr error + Body io.Reader +} + +func (m *mockBody) Read(p []byte) (int, error) { + n, err := m.Body.Read(p) + if (n == 0 || err == io.EOF) && m.DoneErr != nil { + return n, m.DoneErr + } + + return n, err +} + +type mockOutput struct { + _ struct{} `type:"structure"` + String *string `type:"string"` + Integer *int64 `type:"integer"` + Nested *mockNestedStruct `type:"structure"` + List []*mockListElem `locationName:"List" locationNameList:"Elem" type:"list"` + Closed *mockClosedTags `type:"structure"` +} +type mockNestedStruct struct { + _ struct{} `type:"structure"` + NestedString *string `type:"string"` + NestedInt *int64 `type:"integer"` +} +type mockClosedTags struct { + _ struct{} `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` + Attr *string `locationName:"xsi:attrval" type:"string" xmlAttribute:"true"` +} +type mockListElem struct { + _ struct{} `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` + String *string `type:"string"` + NestedElem *mockNestedListElem `type:"structure"` +} +type mockNestedListElem struct { + _ struct{} `type:"structure" xmlPrefix:"xsi" xmlURI:"http://www.w3.org/2001/XMLSchema-instance"` + + String *string `type:"string"` + Type *string `locationName:"xsi:type" type:"string" xmlAttribute:"true"` +} + +func TestUnmarshal(t *testing.T) { + const xmlBodyStr = ` + + string value + 123 + + + nested string value + 321 + + + + + nested elem string value + + elem string value + + +` + + expect := mockOutput{ + String: aws.String("string value"), + Integer: aws.Int64(123), + Closed: &mockClosedTags{ + Attr: aws.String("attr value"), + }, + Nested: &mockNestedStruct{ + NestedString: aws.String("nested string value"), + NestedInt: aws.Int64(321), + }, + List: []*mockListElem{ + { + String: aws.String("elem string value"), + NestedElem: &mockNestedListElem{ + String: aws.String("nested elem string value"), + Type: aws.String("type"), + }, + }, + }, + } + + actual := mockOutput{} + decoder := xml.NewDecoder(strings.NewReader(xmlBodyStr)) + err := UnmarshalXML(&actual, decoder, "") + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + + if !reflect.DeepEqual(expect, actual) { + t.Errorf("expect unmarshal to match\nExpect: %s\nActual: %s", + awsutil.Prettify(expect), awsutil.Prettify(actual)) + } +} + +func TestUnmarshal_UnexpectedEOF(t *testing.T) { + const partialXMLBody = ` + first value + Second val` + + out := struct { + First *string `locationName:"First" type:"string"` + Second *string `locationName:"Second" type:"string"` + }{} + + expect := out + expect.First = aws.String("first") + expect.Second = aws.String("second") + + expectErr := fmt.Errorf("expected read error") + + body := &mockBody{ + DoneErr: expectErr, + Body: strings.NewReader(partialXMLBody), + } + + decoder := xml.NewDecoder(body) + err := UnmarshalXML(&out, decoder, "") + + if err == nil { + t.Fatalf("expect error, got none") + } + if e, a := expectErr, err; e != a { + t.Errorf("expect %v error in %v, but was not", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/customizations_test.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/customizations_test.go new file mode 100644 index 000000000..08ff2cf0b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/customizations_test.go @@ -0,0 +1,48 @@ +package ec2_test + +import ( + "io/ioutil" + "net/url" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/ec2" +) + +func TestCopySnapshotPresignedURL(t *testing.T) { + svc := ec2.New(unit.Session, &aws.Config{Region: aws.String("us-west-2")}) + + func() { + defer func() { + if r := recover(); r != nil { + t.Fatalf("expect CopySnapshotRequest with nill") + } + }() + // Doesn't panic on nil input + req, _ := svc.CopySnapshotRequest(nil) + req.Sign() + }() + + req, _ := svc.CopySnapshotRequest(&ec2.CopySnapshotInput{ + SourceRegion: aws.String("us-west-1"), + SourceSnapshotId: aws.String("snap-id"), + }) + req.Sign() + + b, _ := ioutil.ReadAll(req.HTTPRequest.Body) + q, _ := url.ParseQuery(string(b)) + u, _ := url.QueryUnescape(q.Get("PresignedUrl")) + if e, a := "us-west-2", q.Get("DestinationRegion"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + if e, a := "us-west-1", q.Get("SourceRegion"); e != a { + t.Errorf("expect %v, got %v", e, a) + } + + r := regexp.MustCompile(`^https://ec2\.us-west-1\.amazonaws\.com/.+&DestinationRegion=us-west-2`) + if !r.MatchString(u) { + t.Errorf("expect %v to match, got %v", r.String(), u) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/examples_test.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/examples_test.go new file mode 100644 index 000000000..fdc8670ca --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/examples_test.go @@ -0,0 +1,4213 @@ +// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. + +package ec2_test + +import ( + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ec2" +) + +var _ time.Duration +var _ strings.Reader +var _ aws.Config + +func parseTime(layout, value string) *time.Time { + t, err := time.Parse(layout, value) + if err != nil { + panic(err) + } + return &t +} + +// To allocate an Elastic IP address for EC2-VPC +// +// This example allocates an Elastic IP address to use with an instance in a VPC. +func ExampleEC2_AllocateAddress_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AllocateAddressInput{ + Domain: aws.String("vpc"), + } + + result, err := svc.AllocateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To allocate an Elastic IP address for EC2-Classic +// +// This example allocates an Elastic IP address to use with an instance in EC2-Classic. +func ExampleEC2_AllocateAddress_shared01() { + svc := ec2.New(session.New()) + input := &ec2.AllocateAddressInput{} + + result, err := svc.AllocateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To assign a specific secondary private IP address to an interface +// +// This example assigns the specified secondary private IP address to the specified +// network interface. +func ExampleEC2_AssignPrivateIpAddresses_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AssignPrivateIpAddressesInput{ + NetworkInterfaceId: aws.String("eni-e5aa89a3"), + PrivateIpAddresses: []*string{ + aws.String("10.0.0.82"), + }, + } + + result, err := svc.AssignPrivateIpAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To assign secondary private IP addresses that Amazon EC2 selects to an interface +// +// This example assigns two secondary private IP addresses to the specified network +// interface. Amazon EC2 automatically assigns these IP addresses from the available +// IP addresses in the CIDR block range of the subnet the network interface is associated +// with. +func ExampleEC2_AssignPrivateIpAddresses_shared01() { + svc := ec2.New(session.New()) + input := &ec2.AssignPrivateIpAddressesInput{ + NetworkInterfaceId: aws.String("eni-e5aa89a3"), + SecondaryPrivateIpAddressCount: aws.Int64(2), + } + + result, err := svc.AssignPrivateIpAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To associate an Elastic IP address in EC2-VPC +// +// This example associates the specified Elastic IP address with the specified instance +// in a VPC. +func ExampleEC2_AssociateAddress_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AssociateAddressInput{ + AllocationId: aws.String("eipalloc-64d5890a"), + InstanceId: aws.String("i-0b263919b6498b123"), + } + + result, err := svc.AssociateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To associate an Elastic IP address with a network interface +// +// This example associates the specified Elastic IP address with the specified network +// interface. +func ExampleEC2_AssociateAddress_shared01() { + svc := ec2.New(session.New()) + input := &ec2.AssociateAddressInput{ + AllocationId: aws.String("eipalloc-64d5890a"), + NetworkInterfaceId: aws.String("eni-1a2b3c4d"), + } + + result, err := svc.AssociateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To associate an Elastic IP address in EC2-Classic +// +// This example associates an Elastic IP address with an instance in EC2-Classic. +func ExampleEC2_AssociateAddress_shared02() { + svc := ec2.New(session.New()) + input := &ec2.AssociateAddressInput{ + InstanceId: aws.String("i-07ffe74c7330ebf53"), + PublicIp: aws.String("198.51.100.0"), + } + + result, err := svc.AssociateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To associate a DHCP options set with a VPC +// +// This example associates the specified DHCP options set with the specified VPC. +func ExampleEC2_AssociateDhcpOptions_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AssociateDhcpOptionsInput{ + DhcpOptionsId: aws.String("dopt-d9070ebb"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.AssociateDhcpOptions(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To associate the default DHCP options set with a VPC +// +// This example associates the default DHCP options set with the specified VPC. +func ExampleEC2_AssociateDhcpOptions_shared01() { + svc := ec2.New(session.New()) + input := &ec2.AssociateDhcpOptionsInput{ + DhcpOptionsId: aws.String("default"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.AssociateDhcpOptions(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To associate a route table with a subnet +// +// This example associates the specified route table with the specified subnet. +func ExampleEC2_AssociateRouteTable_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AssociateRouteTableInput{ + RouteTableId: aws.String("rtb-22574640"), + SubnetId: aws.String("subnet-9d4a7b6"), + } + + result, err := svc.AssociateRouteTable(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To attach an Internet gateway to a VPC +// +// This example attaches the specified Internet gateway to the specified VPC. +func ExampleEC2_AttachInternetGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AttachInternetGatewayInput{ + InternetGatewayId: aws.String("igw-c0a643a9"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.AttachInternetGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To attach a network interface to an instance +// +// This example attaches the specified network interface to the specified instance. +func ExampleEC2_AttachNetworkInterface_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AttachNetworkInterfaceInput{ + DeviceIndex: aws.Int64(1), + InstanceId: aws.String("i-1234567890abcdef0"), + NetworkInterfaceId: aws.String("eni-e5aa89a3"), + } + + result, err := svc.AttachNetworkInterface(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To attach a volume to an instance +// +// This example attaches a volume (``vol-1234567890abcdef0``) to an instance (``i-01474ef662b89480``) +// as ``/dev/sdf``. +func ExampleEC2_AttachVolume_shared00() { + svc := ec2.New(session.New()) + input := &ec2.AttachVolumeInput{ + Device: aws.String("/dev/sdf"), + InstanceId: aws.String("i-01474ef662b89480"), + VolumeId: aws.String("vol-1234567890abcdef0"), + } + + result, err := svc.AttachVolume(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To cancel a Spot fleet request +// +// This example cancels the specified Spot fleet request and terminates its associated +// Spot Instances. +func ExampleEC2_CancelSpotFleetRequests_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CancelSpotFleetRequestsInput{ + SpotFleetRequestIds: []*string{ + aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + }, + TerminateInstances: aws.Bool(true), + } + + result, err := svc.CancelSpotFleetRequests(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To cancel a Spot fleet request without terminating its Spot Instances +// +// This example cancels the specified Spot fleet request without terminating its associated +// Spot Instances. +func ExampleEC2_CancelSpotFleetRequests_shared01() { + svc := ec2.New(session.New()) + input := &ec2.CancelSpotFleetRequestsInput{ + SpotFleetRequestIds: []*string{ + aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + }, + TerminateInstances: aws.Bool(false), + } + + result, err := svc.CancelSpotFleetRequests(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To cancel Spot Instance requests +// +// This example cancels a Spot Instance request. +func ExampleEC2_CancelSpotInstanceRequests_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CancelSpotInstanceRequestsInput{ + SpotInstanceRequestIds: []*string{ + aws.String("sir-08b93456"), + }, + } + + result, err := svc.CancelSpotInstanceRequests(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To confirm the product instance +// +// This example determines whether the specified product code is associated with the +// specified instance. +func ExampleEC2_ConfirmProductInstance_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ConfirmProductInstanceInput{ + InstanceId: aws.String("i-1234567890abcdef0"), + ProductCode: aws.String("774F4FF8"), + } + + result, err := svc.ConfirmProductInstance(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To copy a snapshot +// +// This example copies a snapshot with the snapshot ID of ``snap-066877671789bd71b`` +// from the ``us-west-2`` region to the ``us-east-1`` region and adds a short description +// to identify the snapshot. +func ExampleEC2_CopySnapshot_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CopySnapshotInput{ + Description: aws.String("This is my copied snapshot."), + DestinationRegion: aws.String("us-east-1"), + SourceRegion: aws.String("us-west-2"), + SourceSnapshotId: aws.String("snap-066877671789bd71b"), + } + + result, err := svc.CopySnapshot(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a customer gateway +// +// This example creates a customer gateway with the specified IP address for its outside +// interface. +func ExampleEC2_CreateCustomerGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateCustomerGatewayInput{ + BgpAsn: aws.Int64(65534), + PublicIp: aws.String("12.1.2.3"), + Type: aws.String("ipsec.1"), + } + + result, err := svc.CreateCustomerGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a DHCP options set +// +// This example creates a DHCP options set. +func ExampleEC2_CreateDhcpOptions_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateDhcpOptionsInput{ + DhcpConfigurations: []*ec2.NewDhcpConfiguration{ + { + Key: aws.String("domain-name-servers"), + Values: []*string{ + aws.String("10.2.5.1"), + aws.String("10.2.5.2"), + }, + }, + }, + } + + result, err := svc.CreateDhcpOptions(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create an Internet gateway +// +// This example creates an Internet gateway. +func ExampleEC2_CreateInternetGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateInternetGatewayInput{} + + result, err := svc.CreateInternetGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a key pair +// +// This example creates a key pair named my-key-pair. +func ExampleEC2_CreateKeyPair_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateKeyPairInput{ + KeyName: aws.String("my-key-pair"), + } + + result, err := svc.CreateKeyPair(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a NAT gateway +// +// This example creates a NAT gateway in subnet subnet-1a2b3c4d and associates an Elastic +// IP address with the allocation ID eipalloc-37fc1a52 with the NAT gateway. +func ExampleEC2_CreateNatGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateNatGatewayInput{ + AllocationId: aws.String("eipalloc-37fc1a52"), + SubnetId: aws.String("subnet-1a2b3c4d"), + } + + result, err := svc.CreateNatGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a network ACL +// +// This example creates a network ACL for the specified VPC. +func ExampleEC2_CreateNetworkAcl_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateNetworkAclInput{ + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.CreateNetworkAcl(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a network ACL entry +// +// This example creates an entry for the specified network ACL. The rule allows ingress +// traffic from anywhere (0.0.0.0/0) on UDP port 53 (DNS) into any associated subnet. +func ExampleEC2_CreateNetworkAclEntry_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateNetworkAclEntryInput{ + CidrBlock: aws.String("0.0.0.0/0"), + Egress: aws.Bool(false), + NetworkAclId: aws.String("acl-5fb85d36"), + PortRange: &ec2.PortRange{ + From: aws.Int64(53), + To: aws.Int64(53), + }, + Protocol: aws.String("udp"), + RuleAction: aws.String("allow"), + RuleNumber: aws.Int64(100), + } + + result, err := svc.CreateNetworkAclEntry(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a network interface +// +// This example creates a network interface for the specified subnet. +func ExampleEC2_CreateNetworkInterface_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateNetworkInterfaceInput{ + Description: aws.String("my network interface"), + Groups: []*string{ + aws.String("sg-903004f8"), + }, + PrivateIpAddress: aws.String("10.0.2.17"), + SubnetId: aws.String("subnet-9d4a7b6c"), + } + + result, err := svc.CreateNetworkInterface(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a placement group +// +// This example creates a placement group with the specified name. +func ExampleEC2_CreatePlacementGroup_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreatePlacementGroupInput{ + GroupName: aws.String("my-cluster"), + Strategy: aws.String("cluster"), + } + + result, err := svc.CreatePlacementGroup(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a route +// +// This example creates a route for the specified route table. The route matches all +// traffic (0.0.0.0/0) and routes it to the specified Internet gateway. +func ExampleEC2_CreateRoute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateRouteInput{ + DestinationCidrBlock: aws.String("0.0.0.0/0"), + GatewayId: aws.String("igw-c0a643a9"), + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.CreateRoute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a route table +// +// This example creates a route table for the specified VPC. +func ExampleEC2_CreateRouteTable_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateRouteTableInput{ + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.CreateRouteTable(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a snapshot +// +// This example creates a snapshot of the volume with a volume ID of ``vol-1234567890abcdef0`` +// and a short description to identify the snapshot. +func ExampleEC2_CreateSnapshot_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateSnapshotInput{ + Description: aws.String("This is my root volume snapshot."), + VolumeId: aws.String("vol-1234567890abcdef0"), + } + + result, err := svc.CreateSnapshot(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a Spot Instance datafeed +// +// This example creates a Spot Instance data feed for your AWS account. +func ExampleEC2_CreateSpotDatafeedSubscription_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateSpotDatafeedSubscriptionInput{ + Bucket: aws.String("my-s3-bucket"), + Prefix: aws.String("spotdata"), + } + + result, err := svc.CreateSpotDatafeedSubscription(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a subnet +// +// This example creates a subnet in the specified VPC with the specified CIDR block. +// We recommend that you let us select an Availability Zone for you. +func ExampleEC2_CreateSubnet_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateSubnetInput{ + CidrBlock: aws.String("10.0.1.0/24"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.CreateSubnet(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To add a tag to a resource +// +// This example adds the tag Stack=production to the specified image, or overwrites +// an existing tag for the AMI where the tag key is Stack. +func ExampleEC2_CreateTags_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateTagsInput{ + Resources: []*string{ + aws.String("ami-78a54011"), + }, + Tags: []*ec2.Tag{ + { + Key: aws.String("Stack"), + Value: aws.String("production"), + }, + }, + } + + result, err := svc.CreateTags(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a new volume +// +// This example creates an 80 GiB General Purpose (SSD) volume in the Availability Zone +// ``us-east-1a``. +func ExampleEC2_CreateVolume_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateVolumeInput{ + AvailabilityZone: aws.String("us-east-1a"), + Size: aws.Int64(80), + VolumeType: aws.String("gp2"), + } + + result, err := svc.CreateVolume(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a new Provisioned IOPS (SSD) volume from a snapshot +// +// This example creates a new Provisioned IOPS (SSD) volume with 1000 provisioned IOPS +// from a snapshot in the Availability Zone ``us-east-1a``. +func ExampleEC2_CreateVolume_shared01() { + svc := ec2.New(session.New()) + input := &ec2.CreateVolumeInput{ + AvailabilityZone: aws.String("us-east-1a"), + Iops: aws.Int64(1000), + SnapshotId: aws.String("snap-066877671789bd71b"), + VolumeType: aws.String("io1"), + } + + result, err := svc.CreateVolume(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a VPC +// +// This example creates a VPC with the specified CIDR block. +func ExampleEC2_CreateVpc_shared00() { + svc := ec2.New(session.New()) + input := &ec2.CreateVpcInput{ + CidrBlock: aws.String("10.0.0.0/16"), + } + + result, err := svc.CreateVpc(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a customer gateway +// +// This example deletes the specified customer gateway. +func ExampleEC2_DeleteCustomerGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteCustomerGatewayInput{ + CustomerGatewayId: aws.String("cgw-0e11f167"), + } + + result, err := svc.DeleteCustomerGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a DHCP options set +// +// This example deletes the specified DHCP options set. +func ExampleEC2_DeleteDhcpOptions_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteDhcpOptionsInput{ + DhcpOptionsId: aws.String("dopt-d9070ebb"), + } + + result, err := svc.DeleteDhcpOptions(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete an Internet gateway +// +// This example deletes the specified Internet gateway. +func ExampleEC2_DeleteInternetGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteInternetGatewayInput{ + InternetGatewayId: aws.String("igw-c0a643a9"), + } + + result, err := svc.DeleteInternetGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a key pair +// +// This example deletes the specified key pair. +func ExampleEC2_DeleteKeyPair_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteKeyPairInput{ + KeyName: aws.String("my-key-pair"), + } + + result, err := svc.DeleteKeyPair(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a NAT gateway +// +// This example deletes the specified NAT gateway. +func ExampleEC2_DeleteNatGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteNatGatewayInput{ + NatGatewayId: aws.String("nat-04ae55e711cec5680"), + } + + result, err := svc.DeleteNatGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a network ACL +// +// This example deletes the specified network ACL. +func ExampleEC2_DeleteNetworkAcl_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteNetworkAclInput{ + NetworkAclId: aws.String("acl-5fb85d36"), + } + + result, err := svc.DeleteNetworkAcl(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a network ACL entry +// +// This example deletes ingress rule number 100 from the specified network ACL. +func ExampleEC2_DeleteNetworkAclEntry_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteNetworkAclEntryInput{ + Egress: aws.Bool(true), + NetworkAclId: aws.String("acl-5fb85d36"), + RuleNumber: aws.Int64(100), + } + + result, err := svc.DeleteNetworkAclEntry(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a network interface +// +// This example deletes the specified network interface. +func ExampleEC2_DeleteNetworkInterface_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteNetworkInterfaceInput{ + NetworkInterfaceId: aws.String("eni-e5aa89a3"), + } + + result, err := svc.DeleteNetworkInterface(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a placement group +// +// This example deletes the specified placement group. +// +func ExampleEC2_DeletePlacementGroup_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeletePlacementGroupInput{ + GroupName: aws.String("my-cluster"), + } + + result, err := svc.DeletePlacementGroup(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a route +// +// This example deletes the specified route from the specified route table. +func ExampleEC2_DeleteRoute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteRouteInput{ + DestinationCidrBlock: aws.String("0.0.0.0/0"), + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.DeleteRoute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a route table +// +// This example deletes the specified route table. +func ExampleEC2_DeleteRouteTable_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteRouteTableInput{ + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.DeleteRouteTable(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a snapshot +// +// This example deletes a snapshot with the snapshot ID of ``snap-1234567890abcdef0``. +// If the command succeeds, no output is returned. +func ExampleEC2_DeleteSnapshot_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteSnapshotInput{ + SnapshotId: aws.String("snap-1234567890abcdef0"), + } + + result, err := svc.DeleteSnapshot(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To cancel a Spot Instance data feed subscription +// +// This example deletes a Spot data feed subscription for the account. +func ExampleEC2_DeleteSpotDatafeedSubscription_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteSpotDatafeedSubscriptionInput{} + + result, err := svc.DeleteSpotDatafeedSubscription(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a subnet +// +// This example deletes the specified subnet. +func ExampleEC2_DeleteSubnet_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteSubnetInput{ + SubnetId: aws.String("subnet-9d4a7b6c"), + } + + result, err := svc.DeleteSubnet(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a tag from a resource +// +// This example deletes the tag Stack=test from the specified image. +func ExampleEC2_DeleteTags_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteTagsInput{ + Resources: []*string{ + aws.String("ami-78a54011"), + }, + Tags: []*ec2.Tag{ + { + Key: aws.String("Stack"), + Value: aws.String("test"), + }, + }, + } + + result, err := svc.DeleteTags(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a volume +// +// This example deletes an available volume with the volume ID of ``vol-049df61146c4d7901``. +// If the command succeeds, no output is returned. +func ExampleEC2_DeleteVolume_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteVolumeInput{ + VolumeId: aws.String("vol-049df61146c4d7901"), + } + + result, err := svc.DeleteVolume(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To delete a VPC +// +// This example deletes the specified VPC. +func ExampleEC2_DeleteVpc_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DeleteVpcInput{ + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.DeleteVpc(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a single attribute for your AWS account +// +// This example describes the supported-platforms attribute for your AWS account. +func ExampleEC2_DescribeAccountAttributes_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeAccountAttributesInput{ + AttributeNames: []*string{ + aws.String("supported-platforms"), + }, + } + + result, err := svc.DescribeAccountAttributes(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe all attributes for your AWS account +// +// This example describes the attributes for your AWS account. +func ExampleEC2_DescribeAccountAttributes_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeAccountAttributesInput{} + + result, err := svc.DescribeAccountAttributes(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your Elastic IP addresses +// +// This example describes your Elastic IP addresses. +func ExampleEC2_DescribeAddresses_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeAddressesInput{} + + result, err := svc.DescribeAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your Elastic IP addresses for EC2-VPC +// +// This example describes your Elastic IP addresses for use with instances in a VPC. +func ExampleEC2_DescribeAddresses_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeAddressesInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("domain"), + Values: []*string{ + aws.String("vpc"), + }, + }, + }, + } + + result, err := svc.DescribeAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your Elastic IP addresses for EC2-Classic +// +// This example describes your Elastic IP addresses for use with instances in EC2-Classic. +func ExampleEC2_DescribeAddresses_shared02() { + svc := ec2.New(session.New()) + input := &ec2.DescribeAddressesInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("domain"), + Values: []*string{ + aws.String("standard"), + }, + }, + }, + } + + result, err := svc.DescribeAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your Availability Zones +// +// This example describes the Availability Zones that are available to you. The response +// includes Availability Zones only for the current region. +func ExampleEC2_DescribeAvailabilityZones_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeAvailabilityZonesInput{} + + result, err := svc.DescribeAvailabilityZones(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a customer gateway +// +// This example describes the specified customer gateway. +func ExampleEC2_DescribeCustomerGateways_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeCustomerGatewaysInput{ + CustomerGatewayIds: []*string{ + aws.String("cgw-0e11f167"), + }, + } + + result, err := svc.DescribeCustomerGateways(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a DHCP options set +// +// This example describes the specified DHCP options set. +func ExampleEC2_DescribeDhcpOptions_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeDhcpOptionsInput{ + DhcpOptionsIds: []*string{ + aws.String("dopt-d9070ebb"), + }, + } + + result, err := svc.DescribeDhcpOptions(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the instance type +// +// This example describes the instance type of the specified instance. +// +func ExampleEC2_DescribeInstanceAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeInstanceAttributeInput{ + Attribute: aws.String("instanceType"), + InstanceId: aws.String("i-1234567890abcdef0"), + } + + result, err := svc.DescribeInstanceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the disableApiTermination attribute +// +// This example describes the ``disableApiTermination`` attribute of the specified instance. +// +func ExampleEC2_DescribeInstanceAttribute_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeInstanceAttributeInput{ + Attribute: aws.String("disableApiTermination"), + InstanceId: aws.String("i-1234567890abcdef0"), + } + + result, err := svc.DescribeInstanceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the block device mapping for an instance +// +// This example describes the ``blockDeviceMapping`` attribute of the specified instance. +// +func ExampleEC2_DescribeInstanceAttribute_shared02() { + svc := ec2.New(session.New()) + input := &ec2.DescribeInstanceAttributeInput{ + Attribute: aws.String("blockDeviceMapping"), + InstanceId: aws.String("i-1234567890abcdef0"), + } + + result, err := svc.DescribeInstanceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the Internet gateway for a VPC +// +// This example describes the Internet gateway for the specified VPC. +func ExampleEC2_DescribeInternetGateways_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeInternetGatewaysInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("attachment.vpc-id"), + Values: []*string{ + aws.String("vpc-a01106c2"), + }, + }, + }, + } + + result, err := svc.DescribeInternetGateways(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To display a key pair +// +// This example displays the fingerprint for the specified key. +func ExampleEC2_DescribeKeyPairs_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeKeyPairsInput{ + KeyNames: []*string{ + aws.String("my-key-pair"), + }, + } + + result, err := svc.DescribeKeyPairs(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your moving addresses +// +// This example describes all of your moving Elastic IP addresses. +func ExampleEC2_DescribeMovingAddresses_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeMovingAddressesInput{} + + result, err := svc.DescribeMovingAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a NAT gateway +// +// This example describes the NAT gateway for the specified VPC. +func ExampleEC2_DescribeNatGateways_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNatGatewaysInput{ + Filter: []*ec2.Filter{ + { + Name: aws.String("vpc-id"), + Values: []*string{ + aws.String("vpc-1a2b3c4d"), + }, + }, + }, + } + + result, err := svc.DescribeNatGateways(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a network ACL +// +// This example describes the specified network ACL. +func ExampleEC2_DescribeNetworkAcls_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNetworkAclsInput{ + NetworkAclIds: []*string{ + aws.String("acl-5fb85d36"), + }, + } + + result, err := svc.DescribeNetworkAcls(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the attachment attribute of a network interface +// +// This example describes the attachment attribute of the specified network interface. +func ExampleEC2_DescribeNetworkInterfaceAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNetworkInterfaceAttributeInput{ + Attribute: aws.String("attachment"), + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.DescribeNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the description attribute of a network interface +// +// This example describes the description attribute of the specified network interface. +func ExampleEC2_DescribeNetworkInterfaceAttribute_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNetworkInterfaceAttributeInput{ + Attribute: aws.String("description"), + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.DescribeNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the groupSet attribute of a network interface +// +// This example describes the groupSet attribute of the specified network interface. +func ExampleEC2_DescribeNetworkInterfaceAttribute_shared02() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNetworkInterfaceAttributeInput{ + Attribute: aws.String("groupSet"), + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.DescribeNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the sourceDestCheck attribute of a network interface +// +// This example describes the sourceDestCheck attribute of the specified network interface. +func ExampleEC2_DescribeNetworkInterfaceAttribute_shared03() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNetworkInterfaceAttributeInput{ + Attribute: aws.String("sourceDestCheck"), + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.DescribeNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a network interface +// + +func ExampleEC2_DescribeNetworkInterfaces_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []*string{ + aws.String("eni-e5aa89a3"), + }, + } + + result, err := svc.DescribeNetworkInterfaces(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your regions +// +// This example describes all the regions that are available to you. +func ExampleEC2_DescribeRegions_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeRegionsInput{} + + result, err := svc.DescribeRegions(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a route table +// +// This example describes the specified route table. +func ExampleEC2_DescribeRouteTables_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeRouteTablesInput{ + RouteTableIds: []*string{ + aws.String("rtb-1f382e7d"), + }, + } + + result, err := svc.DescribeRouteTables(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe an available schedule +// +// This example describes a schedule that occurs every week on Sunday, starting on the +// specified date. Note that the output contains a single schedule as an example. +func ExampleEC2_DescribeScheduledInstanceAvailability_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeScheduledInstanceAvailabilityInput{ + FirstSlotStartTimeRange: &ec2.SlotDateTimeRangeRequest{ + EarliestTime: parseTime("2006-01-02T15:04:05Z", "2016-01-31T00:00:00Z"), + LatestTime: parseTime("2006-01-02T15:04:05Z", "2016-01-31T04:00:00Z"), + }, + Recurrence: &ec2.ScheduledInstanceRecurrenceRequest{ + Frequency: aws.String("Weekly"), + Interval: aws.Int64(1), + OccurrenceDays: []*int64{ + aws.Int64(1), + }, + }, + } + + result, err := svc.DescribeScheduledInstanceAvailability(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe your Scheduled Instances +// +// This example describes the specified Scheduled Instance. +func ExampleEC2_DescribeScheduledInstances_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeScheduledInstancesInput{ + ScheduledInstanceIds: []*string{ + aws.String("sci-1234-1234-1234-1234-123456789012"), + }, + } + + result, err := svc.DescribeScheduledInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe snapshot attributes +// +// This example describes the ``createVolumePermission`` attribute on a snapshot with +// the snapshot ID of ``snap-066877671789bd71b``. +func ExampleEC2_DescribeSnapshotAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSnapshotAttributeInput{ + Attribute: aws.String("createVolumePermission"), + SnapshotId: aws.String("snap-066877671789bd71b"), + } + + result, err := svc.DescribeSnapshotAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a snapshot +// +// This example describes a snapshot with the snapshot ID of ``snap-1234567890abcdef0``. +func ExampleEC2_DescribeSnapshots_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSnapshotsInput{ + SnapshotIds: []*string{ + aws.String("snap-1234567890abcdef0"), + }, + } + + result, err := svc.DescribeSnapshots(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe snapshots using filters +// +// This example describes all snapshots owned by the ID 012345678910 that are in the +// ``pending`` status. +func ExampleEC2_DescribeSnapshots_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSnapshotsInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("status"), + Values: []*string{ + aws.String("pending"), + }, + }, + }, + OwnerIds: []*string{ + aws.String("012345678910"), + }, + } + + result, err := svc.DescribeSnapshots(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the datafeed for your AWS account +// +// This example describes the Spot Instance datafeed subscription for your AWS account. +func ExampleEC2_DescribeSpotDatafeedSubscription_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSpotDatafeedSubscriptionInput{} + + result, err := svc.DescribeSpotDatafeedSubscription(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the Spot Instances associated with a Spot fleet +// +// This example lists the Spot Instances associated with the specified Spot fleet. +func ExampleEC2_DescribeSpotFleetInstances_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSpotFleetInstancesInput{ + SpotFleetRequestId: aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + } + + result, err := svc.DescribeSpotFleetInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe Spot fleet history +// +// This example returns the history for the specified Spot fleet starting at the specified +// time. +func ExampleEC2_DescribeSpotFleetRequestHistory_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSpotFleetRequestHistoryInput{ + SpotFleetRequestId: aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + StartTime: parseTime("2006-01-02T15:04:05Z", "2015-05-26T00:00:00Z"), + } + + result, err := svc.DescribeSpotFleetRequestHistory(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a Spot fleet request +// +// This example describes the specified Spot fleet request. +func ExampleEC2_DescribeSpotFleetRequests_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSpotFleetRequestsInput{ + SpotFleetRequestIds: []*string{ + aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + }, + } + + result, err := svc.DescribeSpotFleetRequests(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a Spot Instance request +// +// This example describes the specified Spot Instance request. +func ExampleEC2_DescribeSpotInstanceRequests_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSpotInstanceRequestsInput{ + SpotInstanceRequestIds: []*string{ + aws.String("sir-08b93456"), + }, + } + + result, err := svc.DescribeSpotInstanceRequests(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe Spot price history for Linux/UNIX (Amazon VPC) +// +// This example returns the Spot Price history for m1.xlarge, Linux/UNIX (Amazon VPC) +// instances for a particular day in January. +func ExampleEC2_DescribeSpotPriceHistory_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSpotPriceHistoryInput{ + EndTime: parseTime("2006-01-02T15:04:05Z", "2014-01-06T08:09:10"), + InstanceTypes: []*string{ + aws.String("m1.xlarge"), + }, + ProductDescriptions: []*string{ + aws.String("Linux/UNIX (Amazon VPC)"), + }, + StartTime: parseTime("2006-01-02T15:04:05Z", "2014-01-06T07:08:09"), + } + + result, err := svc.DescribeSpotPriceHistory(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the subnets for a VPC +// +// This example describes the subnets for the specified VPC. +func ExampleEC2_DescribeSubnets_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeSubnetsInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("vpc-id"), + Values: []*string{ + aws.String("vpc-a01106c2"), + }, + }, + }, + } + + result, err := svc.DescribeSubnets(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the tags for a single resource +// +// This example describes the tags for the specified instance. +func ExampleEC2_DescribeTags_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeTagsInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("resource-id"), + Values: []*string{ + aws.String("i-1234567890abcdef8"), + }, + }, + }, + } + + result, err := svc.DescribeTags(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a volume attribute +// +// This example describes the ``autoEnableIo`` attribute of the volume with the ID ``vol-049df61146c4d7901``. +func ExampleEC2_DescribeVolumeAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVolumeAttributeInput{ + Attribute: aws.String("autoEnableIO"), + VolumeId: aws.String("vol-049df61146c4d7901"), + } + + result, err := svc.DescribeVolumeAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the status of a single volume +// +// This example describes the status for the volume ``vol-1234567890abcdef0``. +func ExampleEC2_DescribeVolumeStatus_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVolumeStatusInput{ + VolumeIds: []*string{ + aws.String("vol-1234567890abcdef0"), + }, + } + + result, err := svc.DescribeVolumeStatus(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the status of impaired volumes +// +// This example describes the status for all volumes that are impaired. In this example +// output, there are no impaired volumes. +func ExampleEC2_DescribeVolumeStatus_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVolumeStatusInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("volume-status.status"), + Values: []*string{ + aws.String("impaired"), + }, + }, + }, + } + + result, err := svc.DescribeVolumeStatus(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe all volumes +// +// This example describes all of your volumes in the default region. +func ExampleEC2_DescribeVolumes_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVolumesInput{} + + result, err := svc.DescribeVolumes(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe volumes that are attached to a specific instance +// +// This example describes all volumes that are both attached to the instance with the +// ID i-1234567890abcdef0 and set to delete when the instance terminates. +func ExampleEC2_DescribeVolumes_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVolumesInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("attachment.instance-id"), + Values: []*string{ + aws.String("i-1234567890abcdef0"), + }, + }, + { + Name: aws.String("attachment.delete-on-termination"), + Values: []*string{ + aws.String("true"), + }, + }, + }, + } + + result, err := svc.DescribeVolumes(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the enableDnsSupport attribute +// +// This example describes the enableDnsSupport attribute. This attribute indicates whether +// DNS resolution is enabled for the VPC. If this attribute is true, the Amazon DNS +// server resolves DNS hostnames for your instances to their corresponding IP addresses; +// otherwise, it does not. +func ExampleEC2_DescribeVpcAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVpcAttributeInput{ + Attribute: aws.String("enableDnsSupport"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.DescribeVpcAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe the enableDnsHostnames attribute +// +// This example describes the enableDnsHostnames attribute. This attribute indicates +// whether the instances launched in the VPC get DNS hostnames. If this attribute is +// true, instances in the VPC get DNS hostnames; otherwise, they do not. +func ExampleEC2_DescribeVpcAttribute_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVpcAttributeInput{ + Attribute: aws.String("enableDnsHostnames"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.DescribeVpcAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To describe a VPC +// +// This example describes the specified VPC. +func ExampleEC2_DescribeVpcs_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DescribeVpcsInput{ + VpcIds: []*string{ + aws.String("vpc-a01106c2"), + }, + } + + result, err := svc.DescribeVpcs(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To detach an Internet gateway from a VPC +// +// This example detaches the specified Internet gateway from the specified VPC. +func ExampleEC2_DetachInternetGateway_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DetachInternetGatewayInput{ + InternetGatewayId: aws.String("igw-c0a643a9"), + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.DetachInternetGateway(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To detach a network interface from an instance +// +// This example detaches the specified network interface from its attached instance. +func ExampleEC2_DetachNetworkInterface_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DetachNetworkInterfaceInput{ + AttachmentId: aws.String("eni-attach-66c4350a"), + } + + result, err := svc.DetachNetworkInterface(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To detach a volume from an instance +// +// This example detaches the volume (``vol-049df61146c4d7901``) from the instance it +// is attached to. +func ExampleEC2_DetachVolume_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DetachVolumeInput{ + VolumeId: aws.String("vol-1234567890abcdef0"), + } + + result, err := svc.DetachVolume(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To disable route propagation +// +// This example disables the specified virtual private gateway from propagating static +// routes to the specified route table. +func ExampleEC2_DisableVgwRoutePropagation_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DisableVgwRoutePropagationInput{ + GatewayId: aws.String("vgw-9a4cacf3"), + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.DisableVgwRoutePropagation(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To disassociate an Elastic IP address in EC2-VPC +// +// This example disassociates an Elastic IP address from an instance in a VPC. +func ExampleEC2_DisassociateAddress_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DisassociateAddressInput{ + AssociationId: aws.String("eipassoc-2bebb745"), + } + + result, err := svc.DisassociateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To disassociate an Elastic IP addresses in EC2-Classic +// +// This example disassociates an Elastic IP address from an instance in EC2-Classic. +func ExampleEC2_DisassociateAddress_shared01() { + svc := ec2.New(session.New()) + input := &ec2.DisassociateAddressInput{ + PublicIp: aws.String("198.51.100.0"), + } + + result, err := svc.DisassociateAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To disassociate a route table +// +// This example disassociates the specified route table from its associated subnet. +func ExampleEC2_DisassociateRouteTable_shared00() { + svc := ec2.New(session.New()) + input := &ec2.DisassociateRouteTableInput{ + AssociationId: aws.String("rtbassoc-781d0d1a"), + } + + result, err := svc.DisassociateRouteTable(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To enable route propagation +// +// This example enables the specified virtual private gateway to propagate static routes +// to the specified route table. +func ExampleEC2_EnableVgwRoutePropagation_shared00() { + svc := ec2.New(session.New()) + input := &ec2.EnableVgwRoutePropagationInput{ + GatewayId: aws.String("vgw-9a4cacf3"), + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.EnableVgwRoutePropagation(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To enable I/O for a volume +// +// This example enables I/O on volume ``vol-1234567890abcdef0``. +func ExampleEC2_EnableVolumeIO_shared00() { + svc := ec2.New(session.New()) + input := &ec2.EnableVolumeIOInput{ + VolumeId: aws.String("vol-1234567890abcdef0"), + } + + result, err := svc.EnableVolumeIO(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify the attachment attribute of a network interface +// +// This example modifies the attachment attribute of the specified network interface. +func ExampleEC2_ModifyNetworkInterfaceAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ModifyNetworkInterfaceAttributeInput{ + Attachment: &ec2.NetworkInterfaceAttachmentChanges{ + AttachmentId: aws.String("eni-attach-43348162"), + DeleteOnTermination: aws.Bool(false), + }, + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.ModifyNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify the description attribute of a network interface +// +// This example modifies the description attribute of the specified network interface. +func ExampleEC2_ModifyNetworkInterfaceAttribute_shared01() { + svc := ec2.New(session.New()) + input := &ec2.ModifyNetworkInterfaceAttributeInput{ + Description: &ec2.AttributeValue{ + Value: aws.String("My description"), + }, + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.ModifyNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify the groupSet attribute of a network interface +// +// This example command modifies the groupSet attribute of the specified network interface. +func ExampleEC2_ModifyNetworkInterfaceAttribute_shared02() { + svc := ec2.New(session.New()) + input := &ec2.ModifyNetworkInterfaceAttributeInput{ + Groups: []*string{ + aws.String("sg-903004f8"), + aws.String("sg-1a2b3c4d"), + }, + NetworkInterfaceId: aws.String("eni-686ea200"), + } + + result, err := svc.ModifyNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify the sourceDestCheck attribute of a network interface +// +// This example command modifies the sourceDestCheck attribute of the specified network +// interface. +func ExampleEC2_ModifyNetworkInterfaceAttribute_shared03() { + svc := ec2.New(session.New()) + input := &ec2.ModifyNetworkInterfaceAttributeInput{ + NetworkInterfaceId: aws.String("eni-686ea200"), + SourceDestCheck: &ec2.AttributeBooleanValue{ + Value: aws.Bool(false), + }, + } + + result, err := svc.ModifyNetworkInterfaceAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify a snapshot attribute +// +// This example modifies snapshot ``snap-1234567890abcdef0`` to remove the create volume +// permission for a user with the account ID ``123456789012``. If the command succeeds, +// no output is returned. +func ExampleEC2_ModifySnapshotAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ModifySnapshotAttributeInput{ + Attribute: aws.String("createVolumePermission"), + OperationType: aws.String("remove"), + SnapshotId: aws.String("snap-1234567890abcdef0"), + UserIds: []*string{ + aws.String("123456789012"), + }, + } + + result, err := svc.ModifySnapshotAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To make a snapshot public +// +// This example makes the snapshot ``snap-1234567890abcdef0`` public. +func ExampleEC2_ModifySnapshotAttribute_shared01() { + svc := ec2.New(session.New()) + input := &ec2.ModifySnapshotAttributeInput{ + Attribute: aws.String("createVolumePermission"), + GroupNames: []*string{ + aws.String("all"), + }, + OperationType: aws.String("add"), + SnapshotId: aws.String("snap-1234567890abcdef0"), + } + + result, err := svc.ModifySnapshotAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To increase the target capacity of a Spot fleet request +// +// This example increases the target capacity of the specified Spot fleet request. +func ExampleEC2_ModifySpotFleetRequest_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ModifySpotFleetRequestInput{ + SpotFleetRequestId: aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + TargetCapacity: aws.Int64(20), + } + + result, err := svc.ModifySpotFleetRequest(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To decrease the target capacity of a Spot fleet request +// +// This example decreases the target capacity of the specified Spot fleet request without +// terminating any Spot Instances as a result. +func ExampleEC2_ModifySpotFleetRequest_shared01() { + svc := ec2.New(session.New()) + input := &ec2.ModifySpotFleetRequestInput{ + ExcessCapacityTerminationPolicy: aws.String("NoTermination "), + SpotFleetRequestId: aws.String("sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE"), + TargetCapacity: aws.Int64(10), + } + + result, err := svc.ModifySpotFleetRequest(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To change a subnet's public IP addressing behavior +// +// This example modifies the specified subnet so that all instances launched into this +// subnet are assigned a public IP address. +func ExampleEC2_ModifySubnetAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ModifySubnetAttributeInput{ + MapPublicIpOnLaunch: &ec2.AttributeBooleanValue{ + Value: aws.Bool(true), + }, + SubnetId: aws.String("subnet-1a2b3c4d"), + } + + result, err := svc.ModifySubnetAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify a volume attribute +// +// This example sets the ``autoEnableIo`` attribute of the volume with the ID ``vol-1234567890abcdef0`` +// to ``true``. If the command succeeds, no output is returned. +func ExampleEC2_ModifyVolumeAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ModifyVolumeAttributeInput{ + AutoEnableIO: &ec2.AttributeBooleanValue{ + Value: aws.Bool(true), + }, + DryRun: aws.Bool(true), + VolumeId: aws.String("vol-1234567890abcdef0"), + } + + result, err := svc.ModifyVolumeAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify the enableDnsSupport attribute +// +// This example modifies the enableDnsSupport attribute. This attribute indicates whether +// DNS resolution is enabled for the VPC. If this attribute is true, the Amazon DNS +// server resolves DNS hostnames for instances in the VPC to their corresponding IP +// addresses; otherwise, it does not. +func ExampleEC2_ModifyVpcAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ModifyVpcAttributeInput{ + EnableDnsSupport: &ec2.AttributeBooleanValue{ + Value: aws.Bool(false), + }, + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.ModifyVpcAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To modify the enableDnsHostnames attribute +// +// This example modifies the enableDnsHostnames attribute. This attribute indicates +// whether instances launched in the VPC get DNS hostnames. If this attribute is true, +// instances in the VPC get DNS hostnames; otherwise, they do not. +func ExampleEC2_ModifyVpcAttribute_shared01() { + svc := ec2.New(session.New()) + input := &ec2.ModifyVpcAttributeInput{ + EnableDnsHostnames: &ec2.AttributeBooleanValue{ + Value: aws.Bool(false), + }, + VpcId: aws.String("vpc-a01106c2"), + } + + result, err := svc.ModifyVpcAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To move an address to EC2-VPC +// +// This example moves the specified Elastic IP address to the EC2-VPC platform. +func ExampleEC2_MoveAddressToVpc_shared00() { + svc := ec2.New(session.New()) + input := &ec2.MoveAddressToVpcInput{ + PublicIp: aws.String("54.123.4.56"), + } + + result, err := svc.MoveAddressToVpc(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To purchase a Scheduled Instance +// +// This example purchases a Scheduled Instance. +func ExampleEC2_PurchaseScheduledInstances_shared00() { + svc := ec2.New(session.New()) + input := &ec2.PurchaseScheduledInstancesInput{ + PurchaseRequests: []*ec2.PurchaseRequest{ + { + InstanceCount: aws.Int64(1), + PurchaseToken: aws.String("eyJ2IjoiMSIsInMiOjEsImMiOi..."), + }, + }, + } + + result, err := svc.PurchaseScheduledInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To release an Elastic IP address for EC2-VPC +// +// This example releases an Elastic IP address for use with instances in a VPC. +func ExampleEC2_ReleaseAddress_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ReleaseAddressInput{ + AllocationId: aws.String("eipalloc-64d5890a"), + } + + result, err := svc.ReleaseAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To release an Elastic IP addresses for EC2-Classic +// +// This example releases an Elastic IP address for use with instances in EC2-Classic. +func ExampleEC2_ReleaseAddress_shared01() { + svc := ec2.New(session.New()) + input := &ec2.ReleaseAddressInput{ + PublicIp: aws.String("198.51.100.0"), + } + + result, err := svc.ReleaseAddress(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To replace the network ACL associated with a subnet +// +// This example associates the specified network ACL with the subnet for the specified +// network ACL association. +func ExampleEC2_ReplaceNetworkAclAssociation_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ReplaceNetworkAclAssociationInput{ + AssociationId: aws.String("aclassoc-e5b95c8c"), + NetworkAclId: aws.String("acl-5fb85d36"), + } + + result, err := svc.ReplaceNetworkAclAssociation(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To replace a network ACL entry +// +// This example replaces an entry for the specified network ACL. The new rule 100 allows +// ingress traffic from 203.0.113.12/24 on UDP port 53 (DNS) into any associated subnet. +func ExampleEC2_ReplaceNetworkAclEntry_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ReplaceNetworkAclEntryInput{ + CidrBlock: aws.String("203.0.113.12/24"), + Egress: aws.Bool(false), + NetworkAclId: aws.String("acl-5fb85d36"), + PortRange: &ec2.PortRange{ + From: aws.Int64(53), + To: aws.Int64(53), + }, + Protocol: aws.String("udp"), + RuleAction: aws.String("allow"), + RuleNumber: aws.Int64(100), + } + + result, err := svc.ReplaceNetworkAclEntry(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To replace a route +// +// This example replaces the specified route in the specified table table. The new route +// matches the specified CIDR and sends the traffic to the specified virtual private +// gateway. +func ExampleEC2_ReplaceRoute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ReplaceRouteInput{ + DestinationCidrBlock: aws.String("10.0.0.0/16"), + GatewayId: aws.String("vgw-9a4cacf3"), + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.ReplaceRoute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To replace the route table associated with a subnet +// +// This example associates the specified route table with the subnet for the specified +// route table association. +func ExampleEC2_ReplaceRouteTableAssociation_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ReplaceRouteTableAssociationInput{ + AssociationId: aws.String("rtbassoc-781d0d1a"), + RouteTableId: aws.String("rtb-22574640"), + } + + result, err := svc.ReplaceRouteTableAssociation(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To request a Spot fleet in the subnet with the lowest price +// +// This example creates a Spot fleet request with two launch specifications that differ +// only by subnet. The Spot fleet launches the instances in the specified subnet with +// the lowest price. If the instances are launched in a default VPC, they receive a +// public IP address by default. If the instances are launched in a nondefault VPC, +// they do not receive a public IP address by default. Note that you can't specify different +// subnets from the same Availability Zone in a Spot fleet request. +func ExampleEC2_RequestSpotFleet_shared00() { + svc := ec2.New(session.New()) + input := &ec2.RequestSpotFleetInput{ + SpotFleetRequestConfig: &ec2.SpotFleetRequestConfigData{ + IamFleetRole: aws.String("arn:aws:iam::123456789012:role/my-spot-fleet-role"), + LaunchSpecifications: []*ec2.SpotFleetLaunchSpecification{ + { + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Arn: aws.String("arn:aws:iam::123456789012:instance-profile/my-iam-role"), + }, + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("m3.medium"), + KeyName: aws.String("my-key-pair"), + SecurityGroups: []*ec2.GroupIdentifier{ + { + GroupId: aws.String("sg-1a2b3c4d"), + }, + }, + SubnetId: aws.String("subnet-1a2b3c4d, subnet-3c4d5e6f"), + }, + }, + SpotPrice: aws.String("0.04"), + TargetCapacity: aws.Int64(2), + }, + } + + result, err := svc.RequestSpotFleet(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To request a Spot fleet in the Availability Zone with the lowest price +// +// This example creates a Spot fleet request with two launch specifications that differ +// only by Availability Zone. The Spot fleet launches the instances in the specified +// Availability Zone with the lowest price. If your account supports EC2-VPC only, Amazon +// EC2 launches the Spot instances in the default subnet of the Availability Zone. If +// your account supports EC2-Classic, Amazon EC2 launches the instances in EC2-Classic +// in the Availability Zone. +func ExampleEC2_RequestSpotFleet_shared01() { + svc := ec2.New(session.New()) + input := &ec2.RequestSpotFleetInput{ + SpotFleetRequestConfig: &ec2.SpotFleetRequestConfigData{ + IamFleetRole: aws.String("arn:aws:iam::123456789012:role/my-spot-fleet-role"), + LaunchSpecifications: []*ec2.SpotFleetLaunchSpecification{ + { + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Arn: aws.String("arn:aws:iam::123456789012:instance-profile/my-iam-role"), + }, + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("m3.medium"), + KeyName: aws.String("my-key-pair"), + Placement: &ec2.SpotPlacement{ + AvailabilityZone: aws.String("us-west-2a, us-west-2b"), + }, + SecurityGroups: []*ec2.GroupIdentifier{ + { + GroupId: aws.String("sg-1a2b3c4d"), + }, + }, + }, + }, + SpotPrice: aws.String("0.04"), + TargetCapacity: aws.Int64(2), + }, + } + + result, err := svc.RequestSpotFleet(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To launch Spot instances in a subnet and assign them public IP addresses +// +// This example assigns public addresses to instances launched in a nondefault VPC. +// Note that when you specify a network interface, you must include the subnet ID and +// security group ID using the network interface. +func ExampleEC2_RequestSpotFleet_shared02() { + svc := ec2.New(session.New()) + input := &ec2.RequestSpotFleetInput{ + SpotFleetRequestConfig: &ec2.SpotFleetRequestConfigData{ + IamFleetRole: aws.String("arn:aws:iam::123456789012:role/my-spot-fleet-role"), + LaunchSpecifications: []*ec2.SpotFleetLaunchSpecification{ + { + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Arn: aws.String("arn:aws:iam::880185128111:instance-profile/my-iam-role"), + }, + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("m3.medium"), + KeyName: aws.String("my-key-pair"), + NetworkInterfaces: []*ec2.InstanceNetworkInterfaceSpecification{ + { + AssociatePublicIpAddress: aws.Bool(true), + DeviceIndex: aws.Int64(0), + Groups: []*string{ + aws.String("sg-1a2b3c4d"), + }, + SubnetId: aws.String("subnet-1a2b3c4d"), + }, + }, + }, + }, + SpotPrice: aws.String("0.04"), + TargetCapacity: aws.Int64(2), + }, + } + + result, err := svc.RequestSpotFleet(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To request a Spot fleet using the diversified allocation strategy +// +// This example creates a Spot fleet request that launches 30 instances using the diversified +// allocation strategy. The launch specifications differ by instance type. The Spot +// fleet distributes the instances across the launch specifications such that there +// are 10 instances of each type. +func ExampleEC2_RequestSpotFleet_shared03() { + svc := ec2.New(session.New()) + input := &ec2.RequestSpotFleetInput{ + SpotFleetRequestConfig: &ec2.SpotFleetRequestConfigData{ + AllocationStrategy: aws.String("diversified"), + IamFleetRole: aws.String("arn:aws:iam::123456789012:role/my-spot-fleet-role"), + LaunchSpecifications: []*ec2.SpotFleetLaunchSpecification{ + { + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("c4.2xlarge"), + SubnetId: aws.String("subnet-1a2b3c4d"), + }, + { + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("m3.2xlarge"), + SubnetId: aws.String("subnet-1a2b3c4d"), + }, + { + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("r3.2xlarge"), + SubnetId: aws.String("subnet-1a2b3c4d"), + }, + }, + SpotPrice: aws.String("0.70"), + TargetCapacity: aws.Int64(30), + }, + } + + result, err := svc.RequestSpotFleet(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a one-time Spot Instance request +// +// This example creates a one-time Spot Instance request for five instances in the specified +// Availability Zone. If your account supports EC2-VPC only, Amazon EC2 launches the +// instances in the default subnet of the specified Availability Zone. If your account +// supports EC2-Classic, Amazon EC2 launches the instances in EC2-Classic in the specified +// Availability Zone. +func ExampleEC2_RequestSpotInstances_shared00() { + svc := ec2.New(session.New()) + input := &ec2.RequestSpotInstancesInput{ + InstanceCount: aws.Int64(5), + LaunchSpecification: &ec2.RequestSpotLaunchSpecification{ + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Arn: aws.String("arn:aws:iam::123456789012:instance-profile/my-iam-role"), + }, + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("m3.medium"), + KeyName: aws.String("my-key-pair"), + Placement: &ec2.SpotPlacement{ + AvailabilityZone: aws.String("us-west-2a"), + }, + SecurityGroupIds: []*string{ + aws.String("sg-1a2b3c4d"), + }, + }, + SpotPrice: aws.String("0.03"), + Type: aws.String("one-time"), + } + + result, err := svc.RequestSpotInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To create a one-time Spot Instance request +// +// This example command creates a one-time Spot Instance request for five instances +// in the specified subnet. Amazon EC2 launches the instances in the specified subnet. +// If the VPC is a nondefault VPC, the instances do not receive a public IP address +// by default. +func ExampleEC2_RequestSpotInstances_shared01() { + svc := ec2.New(session.New()) + input := &ec2.RequestSpotInstancesInput{ + InstanceCount: aws.Int64(5), + LaunchSpecification: &ec2.RequestSpotLaunchSpecification{ + IamInstanceProfile: &ec2.IamInstanceProfileSpecification{ + Arn: aws.String("arn:aws:iam::123456789012:instance-profile/my-iam-role"), + }, + ImageId: aws.String("ami-1a2b3c4d"), + InstanceType: aws.String("m3.medium"), + SecurityGroupIds: []*string{ + aws.String("sg-1a2b3c4d"), + }, + SubnetId: aws.String("subnet-1a2b3c4d"), + }, + SpotPrice: aws.String("0.050"), + Type: aws.String("one-time"), + } + + result, err := svc.RequestSpotInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To reset a snapshot attribute +// +// This example resets the create volume permissions for snapshot ``snap-1234567890abcdef0``. +// If the command succeeds, no output is returned. +func ExampleEC2_ResetSnapshotAttribute_shared00() { + svc := ec2.New(session.New()) + input := &ec2.ResetSnapshotAttributeInput{ + Attribute: aws.String("createVolumePermission"), + SnapshotId: aws.String("snap-1234567890abcdef0"), + } + + result, err := svc.ResetSnapshotAttribute(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To restore an address to EC2-Classic +// +// This example restores the specified Elastic IP address to the EC2-Classic platform. +func ExampleEC2_RestoreAddressToClassic_shared00() { + svc := ec2.New(session.New()) + input := &ec2.RestoreAddressToClassicInput{ + PublicIp: aws.String("198.51.100.0"), + } + + result, err := svc.RestoreAddressToClassic(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To launch a Scheduled Instance in a VPC +// +// This example launches the specified Scheduled Instance in a VPC. +func ExampleEC2_RunScheduledInstances_shared00() { + svc := ec2.New(session.New()) + input := &ec2.RunScheduledInstancesInput{ + InstanceCount: aws.Int64(1), + LaunchSpecification: &ec2.ScheduledInstancesLaunchSpecification{ + IamInstanceProfile: &ec2.ScheduledInstancesIamInstanceProfile{ + Name: aws.String("my-iam-role"), + }, + ImageId: aws.String("ami-12345678"), + InstanceType: aws.String("c4.large"), + KeyName: aws.String("my-key-pair"), + NetworkInterfaces: []*ec2.ScheduledInstancesNetworkInterface{ + { + AssociatePublicIpAddress: aws.Bool(true), + DeviceIndex: aws.Int64(0), + Groups: []*string{ + aws.String("sg-12345678"), + }, + SubnetId: aws.String("subnet-12345678"), + }, + }, + }, + ScheduledInstanceId: aws.String("sci-1234-1234-1234-1234-123456789012"), + } + + result, err := svc.RunScheduledInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To launch a Scheduled Instance in EC2-Classic +// +// This example launches the specified Scheduled Instance in EC2-Classic. +func ExampleEC2_RunScheduledInstances_shared01() { + svc := ec2.New(session.New()) + input := &ec2.RunScheduledInstancesInput{ + InstanceCount: aws.Int64(1), + LaunchSpecification: &ec2.ScheduledInstancesLaunchSpecification{ + IamInstanceProfile: &ec2.ScheduledInstancesIamInstanceProfile{ + Name: aws.String("my-iam-role"), + }, + ImageId: aws.String("ami-12345678"), + InstanceType: aws.String("c4.large"), + KeyName: aws.String("my-key-pair"), + Placement: &ec2.ScheduledInstancesPlacement{ + AvailabilityZone: aws.String("us-west-2b"), + }, + SecurityGroupIds: []*string{ + aws.String("sg-12345678"), + }, + }, + ScheduledInstanceId: aws.String("sci-1234-1234-1234-1234-123456789012"), + } + + result, err := svc.RunScheduledInstances(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To unassign a secondary private IP address from a network interface +// +// This example unassigns the specified private IP address from the specified network +// interface. +func ExampleEC2_UnassignPrivateIpAddresses_shared00() { + svc := ec2.New(session.New()) + input := &ec2.UnassignPrivateIpAddressesInput{ + NetworkInterfaceId: aws.String("eni-e5aa89a3"), + PrivateIpAddresses: []*string{ + aws.String("10.0.0.82"), + }, + } + + result, err := svc.UnassignPrivateIpAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/retryer_test.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/retryer_test.go new file mode 100644 index 000000000..5c955a0d5 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/retryer_test.go @@ -0,0 +1,37 @@ +package ec2 + +import ( + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/awstesting/unit" +) + +func TestCustomRetryer(t *testing.T) { + svc := New(unit.Session, &aws.Config{Region: aws.String("us-west-2")}) + if _, ok := svc.Client.Retryer.(retryer); !ok { + t.Error("expected custom retryer, but received otherwise") + } + + req, _ := svc.ModifyNetworkInterfaceAttributeRequest(&ModifyNetworkInterfaceAttributeInput{ + NetworkInterfaceId: aws.String("foo"), + }) + + duration := svc.Client.Retryer.RetryRules(req) + if duration < time.Second*1 || duration > time.Second*2 { + t.Errorf("expected duration to be between 1 and 2, but received %v", duration) + } + + req.RetryCount = 15 + duration = svc.Client.Retryer.RetryRules(req) + if duration < time.Second*5 || duration > time.Second*10 { + t.Errorf("expected duration to be between 1 and 2, but received %v", duration) + } + + svc = New(unit.Session, &aws.Config{Region: aws.String("us-west-2"), Retryer: client.DefaultRetryer{}}) + if _, ok := svc.Client.Retryer.(client.DefaultRetryer); !ok { + t.Error("expected default retryer, but received otherwise") + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/generate.go b/vendor/github.com/aws/aws-sdk-go/service/generate.go new file mode 100644 index 000000000..3ffc9fcc5 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/generate.go @@ -0,0 +1,5 @@ +// Package service contains automatically generated AWS clients. +package service + +//go:generate go run -tags codegen ../private/model/cli/gen-api/main.go -path=../service ../models/apis/*/*/api-2.json +//go:generate gofmt -s -w ../service diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/customizations_test.go b/vendor/github.com/aws/aws-sdk-go/service/sts/customizations_test.go new file mode 100644 index 000000000..18972b1f5 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/sts/customizations_test.go @@ -0,0 +1,45 @@ +package sts_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/awstesting/unit" + "github.com/aws/aws-sdk-go/service/sts" +) + +var svc = sts.New(unit.Session, &aws.Config{ + Region: aws.String("mock-region"), +}) + +func TestUnsignedRequest_AssumeRoleWithSAML(t *testing.T) { + req, _ := svc.AssumeRoleWithSAMLRequest(&sts.AssumeRoleWithSAMLInput{ + PrincipalArn: aws.String("ARN01234567890123456789"), + RoleArn: aws.String("ARN01234567890123456789"), + SAMLAssertion: aws.String("ASSERT"), + }) + + err := req.Sign() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := "", req.HTTPRequest.Header.Get("Authorization"); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} + +func TestUnsignedRequest_AssumeRoleWithWebIdentity(t *testing.T) { + req, _ := svc.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{ + RoleArn: aws.String("ARN01234567890123456789"), + RoleSessionName: aws.String("SESSION"), + WebIdentityToken: aws.String("TOKEN"), + }) + + err := req.Sign() + if err != nil { + t.Errorf("expect no error, got %v", err) + } + if e, a := "", req.HTTPRequest.Header.Get("Authorization"); e != a { + t.Errorf("expect %v, got %v", e, a) + } +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/sts/examples_test.go b/vendor/github.com/aws/aws-sdk-go/service/sts/examples_test.go new file mode 100644 index 000000000..d61a9932b --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/sts/examples_test.go @@ -0,0 +1,282 @@ +// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. + +package sts_test + +import ( + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/sts" +) + +var _ time.Duration +var _ strings.Reader +var _ aws.Config + +func parseTime(layout, value string) *time.Time { + t, err := time.Parse(layout, value) + if err != nil { + panic(err) + } + return &t +} + +// To assume a role +// + +func ExampleSTS_AssumeRole_shared00() { + svc := sts.New(session.New()) + input := &sts.AssumeRoleInput{ + DurationSeconds: aws.Int64(3600), + ExternalId: aws.String("123ABC"), + Policy: aws.String("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":\"s3:*\",\"Resource\":\"*\"}]}"), + RoleArn: aws.String("arn:aws:iam::123456789012:role/demo"), + RoleSessionName: aws.String("Bob"), + } + + result, err := svc.AssumeRole(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case sts.ErrCodeMalformedPolicyDocumentException: + fmt.Println(sts.ErrCodeMalformedPolicyDocumentException, aerr.Error()) + case sts.ErrCodePackedPolicyTooLargeException: + fmt.Println(sts.ErrCodePackedPolicyTooLargeException, aerr.Error()) + case sts.ErrCodeRegionDisabledException: + fmt.Println(sts.ErrCodeRegionDisabledException, aerr.Error()) + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To assume a role as an OpenID Connect-federated user +// + +func ExampleSTS_AssumeRoleWithWebIdentity_shared00() { + svc := sts.New(session.New()) + input := &sts.AssumeRoleWithWebIdentityInput{ + DurationSeconds: aws.Int64(3600), + ProviderId: aws.String("www.amazon.com"), + RoleArn: aws.String("arn:aws:iam::123456789012:role/FederatedWebIdentityRole"), + RoleSessionName: aws.String("app1"), + WebIdentityToken: aws.String("Atza%7CIQEBLjAsAhRFiXuWpUXuRvQ9PZL3GMFcYevydwIUFAHZwXZXXXXXXXXJnrulxKDHwy87oGKPznh0D6bEQZTSCzyoCtL_8S07pLpr0zMbn6w1lfVZKNTBdDansFBmtGnIsIapjI6xKR02Yc_2bQ8LZbUXSGm6Ry6_BG7PrtLZtj_dfCTj92xNGed-CrKqjG7nPBjNIL016GGvuS5gSvPRUxWES3VYfm1wl7WTI7jn-Pcb6M-buCgHhFOzTQxod27L9CqnOLio7N3gZAGpsp6n1-AJBOCJckcyXe2c6uD0srOJeZlKUm2eTDVMf8IehDVI0r1QOnTV6KzzAI3OY87Vd_cVMQ"), + } + + result, err := svc.AssumeRoleWithWebIdentity(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case sts.ErrCodeMalformedPolicyDocumentException: + fmt.Println(sts.ErrCodeMalformedPolicyDocumentException, aerr.Error()) + case sts.ErrCodePackedPolicyTooLargeException: + fmt.Println(sts.ErrCodePackedPolicyTooLargeException, aerr.Error()) + case sts.ErrCodeIDPRejectedClaimException: + fmt.Println(sts.ErrCodeIDPRejectedClaimException, aerr.Error()) + case sts.ErrCodeIDPCommunicationErrorException: + fmt.Println(sts.ErrCodeIDPCommunicationErrorException, aerr.Error()) + case sts.ErrCodeInvalidIdentityTokenException: + fmt.Println(sts.ErrCodeInvalidIdentityTokenException, aerr.Error()) + case sts.ErrCodeExpiredTokenException: + fmt.Println(sts.ErrCodeExpiredTokenException, aerr.Error()) + case sts.ErrCodeRegionDisabledException: + fmt.Println(sts.ErrCodeRegionDisabledException, aerr.Error()) + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To decode information about an authorization status of a request +// + +func ExampleSTS_DecodeAuthorizationMessage_shared00() { + svc := sts.New(session.New()) + input := &sts.DecodeAuthorizationMessageInput{ + EncodedMessage: aws.String(""), + } + + result, err := svc.DecodeAuthorizationMessage(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case sts.ErrCodeInvalidAuthorizationMessageException: + fmt.Println(sts.ErrCodeInvalidAuthorizationMessageException, aerr.Error()) + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To get details about a calling IAM user +// +// This example shows a request and response made with the credentials for a user named +// Alice in the AWS account 123456789012. +func ExampleSTS_GetCallerIdentity_shared00() { + svc := sts.New(session.New()) + input := &sts.GetCallerIdentityInput{} + + result, err := svc.GetCallerIdentity(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To get details about a calling user federated with AssumeRole +// +// This example shows a request and response made with temporary credentials created +// by AssumeRole. The name of the assumed role is my-role-name, and the RoleSessionName +// is set to my-role-session-name. +func ExampleSTS_GetCallerIdentity_shared01() { + svc := sts.New(session.New()) + input := &sts.GetCallerIdentityInput{} + + result, err := svc.GetCallerIdentity(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To get details about a calling user federated with GetFederationToken +// +// This example shows a request and response made with temporary credentials created +// by using GetFederationToken. The Name parameter is set to my-federated-user-name. +func ExampleSTS_GetCallerIdentity_shared02() { + svc := sts.New(session.New()) + input := &sts.GetCallerIdentityInput{} + + result, err := svc.GetCallerIdentity(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To get temporary credentials for a role by using GetFederationToken +// + +func ExampleSTS_GetFederationToken_shared00() { + svc := sts.New(session.New()) + input := &sts.GetFederationTokenInput{ + DurationSeconds: aws.Int64(3600), + Name: aws.String("Bob"), + Policy: aws.String("{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":\"s3:*\",\"Resource\":\"*\"}]}"), + } + + result, err := svc.GetFederationToken(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case sts.ErrCodeMalformedPolicyDocumentException: + fmt.Println(sts.ErrCodeMalformedPolicyDocumentException, aerr.Error()) + case sts.ErrCodePackedPolicyTooLargeException: + fmt.Println(sts.ErrCodePackedPolicyTooLargeException, aerr.Error()) + case sts.ErrCodeRegionDisabledException: + fmt.Println(sts.ErrCodeRegionDisabledException, aerr.Error()) + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} + +// To get temporary credentials for an IAM user or an AWS account +// + +func ExampleSTS_GetSessionToken_shared00() { + svc := sts.New(session.New()) + input := &sts.GetSessionTokenInput{ + DurationSeconds: aws.Int64(3600), + SerialNumber: aws.String("YourMFASerialNumber"), + TokenCode: aws.String("123456"), + } + + result, err := svc.GetSessionToken(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case sts.ErrCodeRegionDisabledException: + fmt.Println(sts.ErrCodeRegionDisabledException, aerr.Error()) + default: + fmt.Println(aerr.Error()) + } + } else { + // Print the error, cast err to awserr.Error to get the Code and + // Message from an error. + fmt.Println(err.Error()) + } + return + } + + fmt.Println(result) +} diff --git a/vendor/github.com/beorn7/perks/.gitignore b/vendor/github.com/beorn7/perks/.gitignore new file mode 100644 index 000000000..1bd9209aa --- /dev/null +++ b/vendor/github.com/beorn7/perks/.gitignore @@ -0,0 +1,2 @@ +*.test +*.prof diff --git a/vendor/github.com/beorn7/perks/README.md b/vendor/github.com/beorn7/perks/README.md new file mode 100644 index 000000000..fc0577770 --- /dev/null +++ b/vendor/github.com/beorn7/perks/README.md @@ -0,0 +1,31 @@ +# Perks for Go (golang.org) + +Perks contains the Go package quantile that computes approximate quantiles over +an unbounded data stream within low memory and CPU bounds. + +For more information and examples, see: +http://godoc.org/github.com/bmizerany/perks + +A very special thank you and shout out to Graham Cormode (Rutgers University), +Flip Korn (AT&T Labs–Research), S. Muthukrishnan (Rutgers University), and +Divesh Srivastava (AT&T Labs–Research) for their research and publication of +[Effective Computation of Biased Quantiles over Data Streams](http://www.cs.rutgers.edu/~muthu/bquant.pdf) + +Thank you, also: +* Armon Dadgar (@armon) +* Andrew Gerrand (@nf) +* Brad Fitzpatrick (@bradfitz) +* Keith Rarick (@kr) + +FAQ: + +Q: Why not move the quantile package into the project root? +A: I want to add more packages to perks later. + +Copyright (C) 2013 Blake Mizerany + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/beorn7/perks/quantile/bench_test.go b/vendor/github.com/beorn7/perks/quantile/bench_test.go new file mode 100644 index 000000000..0bd0e4e77 --- /dev/null +++ b/vendor/github.com/beorn7/perks/quantile/bench_test.go @@ -0,0 +1,63 @@ +package quantile + +import ( + "testing" +) + +func BenchmarkInsertTargeted(b *testing.B) { + b.ReportAllocs() + + s := NewTargeted(Targets) + b.ResetTimer() + for i := float64(0); i < float64(b.N); i++ { + s.Insert(i) + } +} + +func BenchmarkInsertTargetedSmallEpsilon(b *testing.B) { + s := NewTargeted(TargetsSmallEpsilon) + b.ResetTimer() + for i := float64(0); i < float64(b.N); i++ { + s.Insert(i) + } +} + +func BenchmarkInsertBiased(b *testing.B) { + s := NewLowBiased(0.01) + b.ResetTimer() + for i := float64(0); i < float64(b.N); i++ { + s.Insert(i) + } +} + +func BenchmarkInsertBiasedSmallEpsilon(b *testing.B) { + s := NewLowBiased(0.0001) + b.ResetTimer() + for i := float64(0); i < float64(b.N); i++ { + s.Insert(i) + } +} + +func BenchmarkQuery(b *testing.B) { + s := NewTargeted(Targets) + for i := float64(0); i < 1e6; i++ { + s.Insert(i) + } + b.ResetTimer() + n := float64(b.N) + for i := float64(0); i < n; i++ { + s.Query(i / n) + } +} + +func BenchmarkQuerySmallEpsilon(b *testing.B) { + s := NewTargeted(TargetsSmallEpsilon) + for i := float64(0); i < 1e6; i++ { + s.Insert(i) + } + b.ResetTimer() + n := float64(b.N) + for i := float64(0); i < n; i++ { + s.Query(i / n) + } +} diff --git a/vendor/github.com/beorn7/perks/quantile/example_test.go b/vendor/github.com/beorn7/perks/quantile/example_test.go new file mode 100644 index 000000000..ab3293aaf --- /dev/null +++ b/vendor/github.com/beorn7/perks/quantile/example_test.go @@ -0,0 +1,121 @@ +// +build go1.1 + +package quantile_test + +import ( + "bufio" + "fmt" + "log" + "os" + "strconv" + "time" + + "github.com/beorn7/perks/quantile" +) + +func Example_simple() { + ch := make(chan float64) + go sendFloats(ch) + + // Compute the 50th, 90th, and 99th percentile. + q := quantile.NewTargeted(map[float64]float64{ + 0.50: 0.005, + 0.90: 0.001, + 0.99: 0.0001, + }) + for v := range ch { + q.Insert(v) + } + + fmt.Println("perc50:", q.Query(0.50)) + fmt.Println("perc90:", q.Query(0.90)) + fmt.Println("perc99:", q.Query(0.99)) + fmt.Println("count:", q.Count()) + // Output: + // perc50: 5 + // perc90: 16 + // perc99: 223 + // count: 2388 +} + +func Example_mergeMultipleStreams() { + // Scenario: + // We have multiple database shards. On each shard, there is a process + // collecting query response times from the database logs and inserting + // them into a Stream (created via NewTargeted(0.90)), much like the + // Simple example. These processes expose a network interface for us to + // ask them to serialize and send us the results of their + // Stream.Samples so we may Merge and Query them. + // + // NOTES: + // * These sample sets are small, allowing us to get them + // across the network much faster than sending the entire list of data + // points. + // + // * For this to work correctly, we must supply the same quantiles + // a priori the process collecting the samples supplied to NewTargeted, + // even if we do not plan to query them all here. + ch := make(chan quantile.Samples) + getDBQuerySamples(ch) + q := quantile.NewTargeted(map[float64]float64{0.90: 0.001}) + for samples := range ch { + q.Merge(samples) + } + fmt.Println("perc90:", q.Query(0.90)) +} + +func Example_window() { + // Scenario: We want the 90th, 95th, and 99th percentiles for each + // minute. + + ch := make(chan float64) + go sendStreamValues(ch) + + tick := time.NewTicker(1 * time.Minute) + q := quantile.NewTargeted(map[float64]float64{ + 0.90: 0.001, + 0.95: 0.0005, + 0.99: 0.0001, + }) + for { + select { + case t := <-tick.C: + flushToDB(t, q.Samples()) + q.Reset() + case v := <-ch: + q.Insert(v) + } + } +} + +func sendStreamValues(ch chan float64) { + // Use your imagination +} + +func flushToDB(t time.Time, samples quantile.Samples) { + // Use your imagination +} + +// This is a stub for the above example. In reality this would hit the remote +// servers via http or something like it. +func getDBQuerySamples(ch chan quantile.Samples) {} + +func sendFloats(ch chan<- float64) { + f, err := os.Open("exampledata.txt") + if err != nil { + log.Fatal(err) + } + sc := bufio.NewScanner(f) + for sc.Scan() { + b := sc.Bytes() + v, err := strconv.ParseFloat(string(b), 64) + if err != nil { + log.Fatal(err) + } + ch <- v + } + if sc.Err() != nil { + log.Fatal(sc.Err()) + } + close(ch) +} diff --git a/vendor/github.com/beorn7/perks/quantile/exampledata.txt b/vendor/github.com/beorn7/perks/quantile/exampledata.txt new file mode 100644 index 000000000..1602287d7 --- /dev/null +++ b/vendor/github.com/beorn7/perks/quantile/exampledata.txt @@ -0,0 +1,2388 @@ +8 +5 +26 +12 +5 +235 +13 +6 +28 +30 +3 +3 +3 +3 +5 +2 +33 +7 +2 +4 +7 +12 +14 +5 +8 +3 +10 +4 +5 +3 +6 +6 +209 +20 +3 +10 +14 +3 +4 +6 +8 +5 +11 +7 +3 +2 +3 +3 +212 +5 +222 +4 +10 +10 +5 +6 +3 +8 +3 +10 +254 +220 +2 +3 +5 +24 +5 +4 +222 +7 +3 +3 +223 +8 +15 +12 +14 +14 +3 +2 +2 +3 +13 +3 +11 +4 +4 +6 +5 +7 +13 +5 +3 +5 +2 +5 +3 +5 +2 +7 +15 +17 +14 +3 +6 +6 +3 +17 +5 +4 +7 +6 +4 +4 +8 +6 +8 +3 +9 +3 +6 +3 +4 +5 +3 +3 +660 +4 +6 +10 +3 +6 +3 +2 +5 +13 +2 +4 +4 +10 +4 +8 +4 +3 +7 +9 +9 +3 +10 +37 +3 +13 +4 +12 +3 +6 +10 +8 +5 +21 +2 +3 +8 +3 +2 +3 +3 +4 +12 +2 +4 +8 +8 +4 +3 +2 +20 +1 +6 +32 +2 +11 +6 +18 +3 +8 +11 +3 +212 +3 +4 +2 +6 +7 +12 +11 +3 +2 +16 +10 +6 +4 +6 +3 +2 +7 +3 +2 +2 +2 +2 +5 +6 +4 +3 +10 +3 +4 +6 +5 +3 +4 +4 +5 +6 +4 +3 +4 +4 +5 +7 +5 +5 +3 +2 +7 +2 +4 +12 +4 +5 +6 +2 +4 +4 +8 +4 +15 +13 +7 +16 +5 +3 +23 +5 +5 +7 +3 +2 +9 +8 +7 +5 +8 +11 +4 +10 +76 +4 +47 +4 +3 +2 +7 +4 +2 +3 +37 +10 +4 +2 +20 +5 +4 +4 +10 +10 +4 +3 +7 +23 +240 +7 +13 +5 +5 +3 +3 +2 +5 +4 +2 +8 +7 +19 +2 +23 +8 +7 +2 +5 +3 +8 +3 +8 +13 +5 +5 +5 +2 +3 +23 +4 +9 +8 +4 +3 +3 +5 +220 +2 +3 +4 +6 +14 +3 +53 +6 +2 +5 +18 +6 +3 +219 +6 +5 +2 +5 +3 +6 +5 +15 +4 +3 +17 +3 +2 +4 +7 +2 +3 +3 +4 +4 +3 +2 +664 +6 +3 +23 +5 +5 +16 +5 +8 +2 +4 +2 +24 +12 +3 +2 +3 +5 +8 +3 +5 +4 +3 +14 +3 +5 +8 +2 +3 +7 +9 +4 +2 +3 +6 +8 +4 +3 +4 +6 +5 +3 +3 +6 +3 +19 +4 +4 +6 +3 +6 +3 +5 +22 +5 +4 +4 +3 +8 +11 +4 +9 +7 +6 +13 +4 +4 +4 +6 +17 +9 +3 +3 +3 +4 +3 +221 +5 +11 +3 +4 +2 +12 +6 +3 +5 +7 +5 +7 +4 +9 +7 +14 +37 +19 +217 +16 +3 +5 +2 +2 +7 +19 +7 +6 +7 +4 +24 +5 +11 +4 +7 +7 +9 +13 +3 +4 +3 +6 +28 +4 +4 +5 +5 +2 +5 +6 +4 +4 +6 +10 +5 +4 +3 +2 +3 +3 +6 +5 +5 +4 +3 +2 +3 +7 +4 +6 +18 +16 +8 +16 +4 +5 +8 +6 +9 +13 +1545 +6 +215 +6 +5 +6 +3 +45 +31 +5 +2 +2 +4 +3 +3 +2 +5 +4 +3 +5 +7 +7 +4 +5 +8 +5 +4 +749 +2 +31 +9 +11 +2 +11 +5 +4 +4 +7 +9 +11 +4 +5 +4 +7 +3 +4 +6 +2 +15 +3 +4 +3 +4 +3 +5 +2 +13 +5 +5 +3 +3 +23 +4 +4 +5 +7 +4 +13 +2 +4 +3 +4 +2 +6 +2 +7 +3 +5 +5 +3 +29 +5 +4 +4 +3 +10 +2 +3 +79 +16 +6 +6 +7 +7 +3 +5 +5 +7 +4 +3 +7 +9 +5 +6 +5 +9 +6 +3 +6 +4 +17 +2 +10 +9 +3 +6 +2 +3 +21 +22 +5 +11 +4 +2 +17 +2 +224 +2 +14 +3 +4 +4 +2 +4 +4 +4 +4 +5 +3 +4 +4 +10 +2 +6 +3 +3 +5 +7 +2 +7 +5 +6 +3 +218 +2 +2 +5 +2 +6 +3 +5 +222 +14 +6 +33 +3 +2 +5 +3 +3 +3 +9 +5 +3 +3 +2 +7 +4 +3 +4 +3 +5 +6 +5 +26 +4 +13 +9 +7 +3 +221 +3 +3 +4 +4 +4 +4 +2 +18 +5 +3 +7 +9 +6 +8 +3 +10 +3 +11 +9 +5 +4 +17 +5 +5 +6 +6 +3 +2 +4 +12 +17 +6 +7 +218 +4 +2 +4 +10 +3 +5 +15 +3 +9 +4 +3 +3 +6 +29 +3 +3 +4 +5 +5 +3 +8 +5 +6 +6 +7 +5 +3 +5 +3 +29 +2 +31 +5 +15 +24 +16 +5 +207 +4 +3 +3 +2 +15 +4 +4 +13 +5 +5 +4 +6 +10 +2 +7 +8 +4 +6 +20 +5 +3 +4 +3 +12 +12 +5 +17 +7 +3 +3 +3 +6 +10 +3 +5 +25 +80 +4 +9 +3 +2 +11 +3 +3 +2 +3 +8 +7 +5 +5 +19 +5 +3 +3 +12 +11 +2 +6 +5 +5 +5 +3 +3 +3 +4 +209 +14 +3 +2 +5 +19 +4 +4 +3 +4 +14 +5 +6 +4 +13 +9 +7 +4 +7 +10 +2 +9 +5 +7 +2 +8 +4 +6 +5 +5 +222 +8 +7 +12 +5 +216 +3 +4 +4 +6 +3 +14 +8 +7 +13 +4 +3 +3 +3 +3 +17 +5 +4 +3 +33 +6 +6 +33 +7 +5 +3 +8 +7 +5 +2 +9 +4 +2 +233 +24 +7 +4 +8 +10 +3 +4 +15 +2 +16 +3 +3 +13 +12 +7 +5 +4 +207 +4 +2 +4 +27 +15 +2 +5 +2 +25 +6 +5 +5 +6 +13 +6 +18 +6 +4 +12 +225 +10 +7 +5 +2 +2 +11 +4 +14 +21 +8 +10 +3 +5 +4 +232 +2 +5 +5 +3 +7 +17 +11 +6 +6 +23 +4 +6 +3 +5 +4 +2 +17 +3 +6 +5 +8 +3 +2 +2 +14 +9 +4 +4 +2 +5 +5 +3 +7 +6 +12 +6 +10 +3 +6 +2 +2 +19 +5 +4 +4 +9 +2 +4 +13 +3 +5 +6 +3 +6 +5 +4 +9 +6 +3 +5 +7 +3 +6 +6 +4 +3 +10 +6 +3 +221 +3 +5 +3 +6 +4 +8 +5 +3 +6 +4 +4 +2 +54 +5 +6 +11 +3 +3 +4 +4 +4 +3 +7 +3 +11 +11 +7 +10 +6 +13 +223 +213 +15 +231 +7 +3 +7 +228 +2 +3 +4 +4 +5 +6 +7 +4 +13 +3 +4 +5 +3 +6 +4 +6 +7 +2 +4 +3 +4 +3 +3 +6 +3 +7 +3 +5 +18 +5 +6 +8 +10 +3 +3 +3 +2 +4 +2 +4 +4 +5 +6 +6 +4 +10 +13 +3 +12 +5 +12 +16 +8 +4 +19 +11 +2 +4 +5 +6 +8 +5 +6 +4 +18 +10 +4 +2 +216 +6 +6 +6 +2 +4 +12 +8 +3 +11 +5 +6 +14 +5 +3 +13 +4 +5 +4 +5 +3 +28 +6 +3 +7 +219 +3 +9 +7 +3 +10 +6 +3 +4 +19 +5 +7 +11 +6 +15 +19 +4 +13 +11 +3 +7 +5 +10 +2 +8 +11 +2 +6 +4 +6 +24 +6 +3 +3 +3 +3 +6 +18 +4 +11 +4 +2 +5 +10 +8 +3 +9 +5 +3 +4 +5 +6 +2 +5 +7 +4 +4 +14 +6 +4 +4 +5 +5 +7 +2 +4 +3 +7 +3 +3 +6 +4 +5 +4 +4 +4 +3 +3 +3 +3 +8 +14 +2 +3 +5 +3 +2 +4 +5 +3 +7 +3 +3 +18 +3 +4 +4 +5 +7 +3 +3 +3 +13 +5 +4 +8 +211 +5 +5 +3 +5 +2 +5 +4 +2 +655 +6 +3 +5 +11 +2 +5 +3 +12 +9 +15 +11 +5 +12 +217 +2 +6 +17 +3 +3 +207 +5 +5 +4 +5 +9 +3 +2 +8 +5 +4 +3 +2 +5 +12 +4 +14 +5 +4 +2 +13 +5 +8 +4 +225 +4 +3 +4 +5 +4 +3 +3 +6 +23 +9 +2 +6 +7 +233 +4 +4 +6 +18 +3 +4 +6 +3 +4 +4 +2 +3 +7 +4 +13 +227 +4 +3 +5 +4 +2 +12 +9 +17 +3 +7 +14 +6 +4 +5 +21 +4 +8 +9 +2 +9 +25 +16 +3 +6 +4 +7 +8 +5 +2 +3 +5 +4 +3 +3 +5 +3 +3 +3 +2 +3 +19 +2 +4 +3 +4 +2 +3 +4 +4 +2 +4 +3 +3 +3 +2 +6 +3 +17 +5 +6 +4 +3 +13 +5 +3 +3 +3 +4 +9 +4 +2 +14 +12 +4 +5 +24 +4 +3 +37 +12 +11 +21 +3 +4 +3 +13 +4 +2 +3 +15 +4 +11 +4 +4 +3 +8 +3 +4 +4 +12 +8 +5 +3 +3 +4 +2 +220 +3 +5 +223 +3 +3 +3 +10 +3 +15 +4 +241 +9 +7 +3 +6 +6 +23 +4 +13 +7 +3 +4 +7 +4 +9 +3 +3 +4 +10 +5 +5 +1 +5 +24 +2 +4 +5 +5 +6 +14 +3 +8 +2 +3 +5 +13 +13 +3 +5 +2 +3 +15 +3 +4 +2 +10 +4 +4 +4 +5 +5 +3 +5 +3 +4 +7 +4 +27 +3 +6 +4 +15 +3 +5 +6 +6 +5 +4 +8 +3 +9 +2 +6 +3 +4 +3 +7 +4 +18 +3 +11 +3 +3 +8 +9 +7 +24 +3 +219 +7 +10 +4 +5 +9 +12 +2 +5 +4 +4 +4 +3 +3 +19 +5 +8 +16 +8 +6 +22 +3 +23 +3 +242 +9 +4 +3 +3 +5 +7 +3 +3 +5 +8 +3 +7 +5 +14 +8 +10 +3 +4 +3 +7 +4 +6 +7 +4 +10 +4 +3 +11 +3 +7 +10 +3 +13 +6 +8 +12 +10 +5 +7 +9 +3 +4 +7 +7 +10 +8 +30 +9 +19 +4 +3 +19 +15 +4 +13 +3 +215 +223 +4 +7 +4 +8 +17 +16 +3 +7 +6 +5 +5 +4 +12 +3 +7 +4 +4 +13 +4 +5 +2 +5 +6 +5 +6 +6 +7 +10 +18 +23 +9 +3 +3 +6 +5 +2 +4 +2 +7 +3 +3 +2 +5 +5 +14 +10 +224 +6 +3 +4 +3 +7 +5 +9 +3 +6 +4 +2 +5 +11 +4 +3 +3 +2 +8 +4 +7 +4 +10 +7 +3 +3 +18 +18 +17 +3 +3 +3 +4 +5 +3 +3 +4 +12 +7 +3 +11 +13 +5 +4 +7 +13 +5 +4 +11 +3 +12 +3 +6 +4 +4 +21 +4 +6 +9 +5 +3 +10 +8 +4 +6 +4 +4 +6 +5 +4 +8 +6 +4 +6 +4 +4 +5 +9 +6 +3 +4 +2 +9 +3 +18 +2 +4 +3 +13 +3 +6 +6 +8 +7 +9 +3 +2 +16 +3 +4 +6 +3 +2 +33 +22 +14 +4 +9 +12 +4 +5 +6 +3 +23 +9 +4 +3 +5 +5 +3 +4 +5 +3 +5 +3 +10 +4 +5 +5 +8 +4 +4 +6 +8 +5 +4 +3 +4 +6 +3 +3 +3 +5 +9 +12 +6 +5 +9 +3 +5 +3 +2 +2 +2 +18 +3 +2 +21 +2 +5 +4 +6 +4 +5 +10 +3 +9 +3 +2 +10 +7 +3 +6 +6 +4 +4 +8 +12 +7 +3 +7 +3 +3 +9 +3 +4 +5 +4 +4 +5 +5 +10 +15 +4 +4 +14 +6 +227 +3 +14 +5 +216 +22 +5 +4 +2 +2 +6 +3 +4 +2 +9 +9 +4 +3 +28 +13 +11 +4 +5 +3 +3 +2 +3 +3 +5 +3 +4 +3 +5 +23 +26 +3 +4 +5 +6 +4 +6 +3 +5 +5 +3 +4 +3 +2 +2 +2 +7 +14 +3 +6 +7 +17 +2 +2 +15 +14 +16 +4 +6 +7 +13 +6 +4 +5 +6 +16 +3 +3 +28 +3 +6 +15 +3 +9 +2 +4 +6 +3 +3 +22 +4 +12 +6 +7 +2 +5 +4 +10 +3 +16 +6 +9 +2 +5 +12 +7 +5 +5 +5 +5 +2 +11 +9 +17 +4 +3 +11 +7 +3 +5 +15 +4 +3 +4 +211 +8 +7 +5 +4 +7 +6 +7 +6 +3 +6 +5 +6 +5 +3 +4 +4 +26 +4 +6 +10 +4 +4 +3 +2 +3 +3 +4 +5 +9 +3 +9 +4 +4 +5 +5 +8 +2 +4 +2 +3 +8 +4 +11 +19 +5 +8 +6 +3 +5 +6 +12 +3 +2 +4 +16 +12 +3 +4 +4 +8 +6 +5 +6 +6 +219 +8 +222 +6 +16 +3 +13 +19 +5 +4 +3 +11 +6 +10 +4 +7 +7 +12 +5 +3 +3 +5 +6 +10 +3 +8 +2 +5 +4 +7 +2 +4 +4 +2 +12 +9 +6 +4 +2 +40 +2 +4 +10 +4 +223 +4 +2 +20 +6 +7 +24 +5 +4 +5 +2 +20 +16 +6 +5 +13 +2 +3 +3 +19 +3 +2 +4 +5 +6 +7 +11 +12 +5 +6 +7 +7 +3 +5 +3 +5 +3 +14 +3 +4 +4 +2 +11 +1 +7 +3 +9 +6 +11 +12 +5 +8 +6 +221 +4 +2 +12 +4 +3 +15 +4 +5 +226 +7 +218 +7 +5 +4 +5 +18 +4 +5 +9 +4 +4 +2 +9 +18 +18 +9 +5 +6 +6 +3 +3 +7 +3 +5 +4 +4 +4 +12 +3 +6 +31 +5 +4 +7 +3 +6 +5 +6 +5 +11 +2 +2 +11 +11 +6 +7 +5 +8 +7 +10 +5 +23 +7 +4 +3 +5 +34 +2 +5 +23 +7 +3 +6 +8 +4 +4 +4 +2 +5 +3 +8 +5 +4 +8 +25 +2 +3 +17 +8 +3 +4 +8 +7 +3 +15 +6 +5 +7 +21 +9 +5 +6 +6 +5 +3 +2 +3 +10 +3 +6 +3 +14 +7 +4 +4 +8 +7 +8 +2 +6 +12 +4 +213 +6 +5 +21 +8 +2 +5 +23 +3 +11 +2 +3 +6 +25 +2 +3 +6 +7 +6 +6 +4 +4 +6 +3 +17 +9 +7 +6 +4 +3 +10 +7 +2 +3 +3 +3 +11 +8 +3 +7 +6 +4 +14 +36 +3 +4 +3 +3 +22 +13 +21 +4 +2 +7 +4 +4 +17 +15 +3 +7 +11 +2 +4 +7 +6 +209 +6 +3 +2 +2 +24 +4 +9 +4 +3 +3 +3 +29 +2 +2 +4 +3 +3 +5 +4 +6 +3 +3 +2 +4 diff --git a/vendor/github.com/beorn7/perks/quantile/stream_test.go b/vendor/github.com/beorn7/perks/quantile/stream_test.go new file mode 100644 index 000000000..855195097 --- /dev/null +++ b/vendor/github.com/beorn7/perks/quantile/stream_test.go @@ -0,0 +1,215 @@ +package quantile + +import ( + "math" + "math/rand" + "sort" + "testing" +) + +var ( + Targets = map[float64]float64{ + 0.01: 0.001, + 0.10: 0.01, + 0.50: 0.05, + 0.90: 0.01, + 0.99: 0.001, + } + TargetsSmallEpsilon = map[float64]float64{ + 0.01: 0.0001, + 0.10: 0.001, + 0.50: 0.005, + 0.90: 0.001, + 0.99: 0.0001, + } + LowQuantiles = []float64{0.01, 0.1, 0.5} + HighQuantiles = []float64{0.99, 0.9, 0.5} +) + +const RelativeEpsilon = 0.01 + +func verifyPercsWithAbsoluteEpsilon(t *testing.T, a []float64, s *Stream) { + sort.Float64s(a) + for quantile, epsilon := range Targets { + n := float64(len(a)) + k := int(quantile * n) + if k < 1 { + k = 1 + } + lower := int((quantile - epsilon) * n) + if lower < 1 { + lower = 1 + } + upper := int(math.Ceil((quantile + epsilon) * n)) + if upper > len(a) { + upper = len(a) + } + w, min, max := a[k-1], a[lower-1], a[upper-1] + if g := s.Query(quantile); g < min || g > max { + t.Errorf("q=%f: want %v [%f,%f], got %v", quantile, w, min, max, g) + } + } +} + +func verifyLowPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) { + sort.Float64s(a) + for _, qu := range LowQuantiles { + n := float64(len(a)) + k := int(qu * n) + + lowerRank := int((1 - RelativeEpsilon) * qu * n) + upperRank := int(math.Ceil((1 + RelativeEpsilon) * qu * n)) + w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1] + if g := s.Query(qu); g < min || g > max { + t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g) + } + } +} + +func verifyHighPercsWithRelativeEpsilon(t *testing.T, a []float64, s *Stream) { + sort.Float64s(a) + for _, qu := range HighQuantiles { + n := float64(len(a)) + k := int(qu * n) + + lowerRank := int((1 - (1+RelativeEpsilon)*(1-qu)) * n) + upperRank := int(math.Ceil((1 - (1-RelativeEpsilon)*(1-qu)) * n)) + w, min, max := a[k-1], a[lowerRank-1], a[upperRank-1] + if g := s.Query(qu); g < min || g > max { + t.Errorf("q=%f: want %v [%f,%f], got %v", qu, w, min, max, g) + } + } +} + +func populateStream(s *Stream) []float64 { + a := make([]float64, 0, 1e5+100) + for i := 0; i < cap(a); i++ { + v := rand.NormFloat64() + // Add 5% asymmetric outliers. + if i%20 == 0 { + v = v*v + 1 + } + s.Insert(v) + a = append(a, v) + } + return a +} + +func TestTargetedQuery(t *testing.T) { + rand.Seed(42) + s := NewTargeted(Targets) + a := populateStream(s) + verifyPercsWithAbsoluteEpsilon(t, a, s) +} + +func TestTargetedQuerySmallSampleSize(t *testing.T) { + rand.Seed(42) + s := NewTargeted(TargetsSmallEpsilon) + a := []float64{1, 2, 3, 4, 5} + for _, v := range a { + s.Insert(v) + } + verifyPercsWithAbsoluteEpsilon(t, a, s) + // If not yet flushed, results should be precise: + if !s.flushed() { + for φ, want := range map[float64]float64{ + 0.01: 1, + 0.10: 1, + 0.50: 3, + 0.90: 5, + 0.99: 5, + } { + if got := s.Query(φ); got != want { + t.Errorf("want %f for φ=%f, got %f", want, φ, got) + } + } + } +} + +func TestLowBiasedQuery(t *testing.T) { + rand.Seed(42) + s := NewLowBiased(RelativeEpsilon) + a := populateStream(s) + verifyLowPercsWithRelativeEpsilon(t, a, s) +} + +func TestHighBiasedQuery(t *testing.T) { + rand.Seed(42) + s := NewHighBiased(RelativeEpsilon) + a := populateStream(s) + verifyHighPercsWithRelativeEpsilon(t, a, s) +} + +// BrokenTestTargetedMerge is broken, see Merge doc comment. +func BrokenTestTargetedMerge(t *testing.T) { + rand.Seed(42) + s1 := NewTargeted(Targets) + s2 := NewTargeted(Targets) + a := populateStream(s1) + a = append(a, populateStream(s2)...) + s1.Merge(s2.Samples()) + verifyPercsWithAbsoluteEpsilon(t, a, s1) +} + +// BrokenTestLowBiasedMerge is broken, see Merge doc comment. +func BrokenTestLowBiasedMerge(t *testing.T) { + rand.Seed(42) + s1 := NewLowBiased(RelativeEpsilon) + s2 := NewLowBiased(RelativeEpsilon) + a := populateStream(s1) + a = append(a, populateStream(s2)...) + s1.Merge(s2.Samples()) + verifyLowPercsWithRelativeEpsilon(t, a, s2) +} + +// BrokenTestHighBiasedMerge is broken, see Merge doc comment. +func BrokenTestHighBiasedMerge(t *testing.T) { + rand.Seed(42) + s1 := NewHighBiased(RelativeEpsilon) + s2 := NewHighBiased(RelativeEpsilon) + a := populateStream(s1) + a = append(a, populateStream(s2)...) + s1.Merge(s2.Samples()) + verifyHighPercsWithRelativeEpsilon(t, a, s2) +} + +func TestUncompressed(t *testing.T) { + q := NewTargeted(Targets) + for i := 100; i > 0; i-- { + q.Insert(float64(i)) + } + if g := q.Count(); g != 100 { + t.Errorf("want count 100, got %d", g) + } + // Before compression, Query should have 100% accuracy. + for quantile := range Targets { + w := quantile * 100 + if g := q.Query(quantile); g != w { + t.Errorf("want %f, got %f", w, g) + } + } +} + +func TestUncompressedSamples(t *testing.T) { + q := NewTargeted(map[float64]float64{0.99: 0.001}) + for i := 1; i <= 100; i++ { + q.Insert(float64(i)) + } + if g := q.Samples().Len(); g != 100 { + t.Errorf("want count 100, got %d", g) + } +} + +func TestUncompressedOne(t *testing.T) { + q := NewTargeted(map[float64]float64{0.99: 0.01}) + q.Insert(3.14) + if g := q.Query(0.90); g != 3.14 { + t.Error("want PI, got", g) + } +} + +func TestDefaults(t *testing.T) { + if g := NewTargeted(map[float64]float64{0.99: 0.001}).Query(0.99); g != 0 { + t.Errorf("want 0, got %f", g) + } +} diff --git a/vendor/github.com/davecgh/go-spew/.gitignore b/vendor/github.com/davecgh/go-spew/.gitignore new file mode 100644 index 000000000..00268614f --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/davecgh/go-spew/.travis.yml new file mode 100644 index 000000000..984e0736e --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: + - 1.5.4 + - 1.6.3 + - 1.7 +install: + - go get -v golang.org/x/tools/cmd/cover +script: + - go test -v -tags=safe ./spew + - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov +after_success: + - go get -v github.com/mattn/goveralls + - export PATH=$PATH:$HOME/gopath/bin + - goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md new file mode 100644 index 000000000..262430449 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/README.md @@ -0,0 +1,205 @@ +go-spew +======= + +[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)] +(https://travis-ci.org/davecgh/go-spew) [![ISC License] +(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status] +(https://img.shields.io/coveralls/davecgh/go-spew.svg)] +(https://coveralls.io/r/davecgh/go-spew?branch=master) + + +Go-spew implements a deep pretty printer for Go data structures to aid in +debugging. A comprehensive suite of tests with 100% test coverage is provided +to ensure proper functionality. See `test_coverage.txt` for the gocov coverage +report. Go-spew is licensed under the liberal ISC license, so it may be used in +open source or commercial projects. + +If you're interested in reading about how this package came to life and some +of the challenges involved in providing a deep pretty printer, there is a blog +post about it +[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/). + +## Documentation + +[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] +(http://godoc.org/github.com/davecgh/go-spew/spew) + +Full `go doc` style documentation for the project can be viewed online without +installing this package by using the excellent GoDoc site here: +http://godoc.org/github.com/davecgh/go-spew/spew + +You can also view the documentation locally once the package is installed with +the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to +http://localhost:6060/pkg/github.com/davecgh/go-spew/spew + +## Installation + +```bash +$ go get -u github.com/davecgh/go-spew/spew +``` + +## Quick Start + +Add this import line to the file you're working in: + +```Go +import "github.com/davecgh/go-spew/spew" +``` + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + +```Go +spew.Dump(myVar1, myVar2, ...) +spew.Fdump(someWriter, myVar1, myVar2, ...) +str := spew.Sdump(myVar1, myVar2, ...) +``` + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most +compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types +and pointer addresses): + +```Go +spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) +spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) +spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) +spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) +``` + +## Debugging a Web Application Example + +Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production. + +```Go +package main + +import ( + "fmt" + "html" + "net/http" + + "github.com/davecgh/go-spew/spew" +) + +func handler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html") + fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:]) + fmt.Fprintf(w, "") +} + +func main() { + http.HandleFunc("/", handler) + http.ListenAndServe(":8080", nil) +} +``` + +## Sample Dump Output + +``` +(main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) { + (string) "one": (bool) true + } +} +([]uint8) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| +} +``` + +## Sample Formatter Output + +Double pointer to a uint8: +``` + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 +``` + +Pointer to circular struct with a uint8 field and a pointer to itself: +``` + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} +``` + +## Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available via the +spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +``` +* Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + +* MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + +* DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + +* DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. This option + relies on access to the unsafe package, so it will not have any effect when + running in environments without access to the unsafe package such as Google + App Engine or with the "safe" build tag specified. + Pointer method invocation is enabled by default. + +* DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + +* DisableCapacities + DisableCapacities specifies whether to disable the printing of capacities + for arrays, slices, maps and channels. This is useful when diffing data + structures in tests. + +* ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + +* SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are supported, + with other types sorted according to the reflect.Value.String() output + which guarantees display stability. Natural map order is used by + default. + +* SpewKeys + SpewKeys specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only considered + if SortKeys is true. + +``` + +## Unsafe Package Dependency + +This package relies on the unsafe package to perform some of the more advanced +features, however it also supports a "limited" mode which allows it to work in +environments where the unsafe package is not available. By default, it will +operate in this mode on Google App Engine and when compiled with GopherJS. The +"safe" build tag may also be specified to force the package to build without +using the unsafe package. + +## License + +Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/vendor/github.com/davecgh/go-spew/cov_report.sh b/vendor/github.com/davecgh/go-spew/cov_report.sh new file mode 100644 index 000000000..9579497e4 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/cov_report.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# This script uses gocov to generate a test coverage report. +# The gocov tool my be obtained with the following command: +# go get github.com/axw/gocov/gocov +# +# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. + +# Check for gocov. +if ! type gocov >/dev/null 2>&1; then + echo >&2 "This script requires the gocov tool." + echo >&2 "You may obtain it with the following command:" + echo >&2 "go get github.com/axw/gocov/gocov" + exit 1 +fi + +# Only run the cgo tests if gcc is installed. +if type gcc >/dev/null 2>&1; then + (cd spew && gocov test -tags testcgo | gocov report) +else + (cd spew && gocov test | gocov report) +fi diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go new file mode 100644 index 000000000..0f5ce47dc --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/common_test.go @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "fmt" + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" +) + +// custom type to test Stinger interface on non-pointer receiver. +type stringer string + +// String implements the Stringer interface for testing invocation of custom +// stringers on types with non-pointer receivers. +func (s stringer) String() string { + return "stringer " + string(s) +} + +// custom type to test Stinger interface on pointer receiver. +type pstringer string + +// String implements the Stringer interface for testing invocation of custom +// stringers on types with only pointer receivers. +func (s *pstringer) String() string { + return "stringer " + string(*s) +} + +// xref1 and xref2 are cross referencing structs for testing circular reference +// detection. +type xref1 struct { + ps2 *xref2 +} +type xref2 struct { + ps1 *xref1 +} + +// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular +// reference for testing detection. +type indirCir1 struct { + ps2 *indirCir2 +} +type indirCir2 struct { + ps3 *indirCir3 +} +type indirCir3 struct { + ps1 *indirCir1 +} + +// embed is used to test embedded structures. +type embed struct { + a string +} + +// embedwrap is used to test embedded structures. +type embedwrap struct { + *embed + e *embed +} + +// panicer is used to intentionally cause a panic for testing spew properly +// handles them +type panicer int + +func (p panicer) String() string { + panic("test panic") +} + +// customError is used to test custom error interface invocation. +type customError int + +func (e customError) Error() string { + return fmt.Sprintf("error: %d", int(e)) +} + +// stringizeWants converts a slice of wanted test output into a format suitable +// for a test error message. +func stringizeWants(wants []string) string { + s := "" + for i, want := range wants { + if i > 0 { + s += fmt.Sprintf("want%d: %s", i+1, want) + } else { + s += "want: " + want + } + } + return s +} + +// testFailed returns whether or not a test failed by checking if the result +// of the test is in the slice of wanted strings. +func testFailed(result string, wants []string) bool { + for _, want := range wants { + if result == want { + return false + } + } + return true +} + +type sortableStruct struct { + x int +} + +func (ss sortableStruct) String() string { + return fmt.Sprintf("ss.%d", ss.x) +} + +type unsortableStruct struct { + x int +} + +type sortTestCase struct { + input []reflect.Value + expected []reflect.Value +} + +func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) { + getInterfaces := func(values []reflect.Value) []interface{} { + interfaces := []interface{}{} + for _, v := range values { + interfaces = append(interfaces, v.Interface()) + } + return interfaces + } + + for _, test := range tests { + spew.SortValues(test.input, cs) + // reflect.DeepEqual cannot really make sense of reflect.Value, + // probably because of all the pointer tricks. For instance, + // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{} + // instead. + input := getInterfaces(test.input) + expected := getInterfaces(test.expected) + if !reflect.DeepEqual(input, expected) { + t.Errorf("Sort mismatch:\n %v != %v", input, expected) + } + } +} + +// TestSortValues ensures the sort functionality for relect.Value based sorting +// works as intended. +func TestSortValues(t *testing.T) { + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + embedA := v(embed{"a"}) + embedB := v(embed{"b"}) + embedC := v(embed{"c"}) + tests := []sortTestCase{ + // No values. + { + []reflect.Value{}, + []reflect.Value{}, + }, + // Bools. + { + []reflect.Value{v(false), v(true), v(false)}, + []reflect.Value{v(false), v(false), v(true)}, + }, + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Uints. + { + []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))}, + []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))}, + }, + // Floats. + { + []reflect.Value{v(2.0), v(1.0), v(3.0)}, + []reflect.Value{v(1.0), v(2.0), v(3.0)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // Array + { + []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})}, + []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})}, + }, + // Uintptrs. + { + []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))}, + []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))}, + }, + // SortableStructs. + { + // Note: not sorted - DisableMethods is set. + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + }, + // UnsortableStructs. + { + // Note: not sorted - SpewKeys is false. + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + }, + // Invalid. + { + []reflect.Value{embedB, embedA, embedC}, + []reflect.Value{embedB, embedA, embedC}, + }, + } + cs := spew.ConfigState{DisableMethods: true, SpewKeys: false} + helpTestSortValues(tests, &cs, t) +} + +// TestSortValuesWithMethods ensures the sort functionality for relect.Value +// based sorting works as intended when using string methods. +func TestSortValuesWithMethods(t *testing.T) { + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + tests := []sortTestCase{ + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // SortableStructs. + { + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, + }, + // UnsortableStructs. + { + // Note: not sorted - SpewKeys is false. + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + }, + } + cs := spew.ConfigState{DisableMethods: false, SpewKeys: false} + helpTestSortValues(tests, &cs, t) +} + +// TestSortValuesWithSpew ensures the sort functionality for relect.Value +// based sorting works as intended when using spew to stringify keys. +func TestSortValuesWithSpew(t *testing.T) { + v := reflect.ValueOf + + a := v("a") + b := v("b") + c := v("c") + tests := []sortTestCase{ + // Ints. + { + []reflect.Value{v(2), v(1), v(3)}, + []reflect.Value{v(1), v(2), v(3)}, + }, + // Strings. + { + []reflect.Value{b, a, c}, + []reflect.Value{a, b, c}, + }, + // SortableStructs. + { + []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})}, + []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})}, + }, + // UnsortableStructs. + { + []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})}, + []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})}, + }, + } + cs := spew.ConfigState{DisableMethods: true, SpewKeys: true} + helpTestSortValues(tests, &cs, t) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go new file mode 100644 index 000000000..5aad9c7af --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/dump_test.go @@ -0,0 +1,1042 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Test Summary: +NOTE: For each test, a nil pointer, a single pointer and double pointer to the +base test element are also tested to ensure proper indirection across all types. + +- Max int8, int16, int32, int64, int +- Max uint8, uint16, uint32, uint64, uint +- Boolean true and false +- Standard complex64 and complex128 +- Array containing standard ints +- Array containing type with custom formatter on pointer receiver only +- Array containing interfaces +- Array containing bytes +- Slice containing standard float32 values +- Slice containing type with custom formatter on pointer receiver only +- Slice containing interfaces +- Slice containing bytes +- Nil slice +- Standard string +- Nil interface +- Sub-interface +- Map with string keys and int vals +- Map with custom formatter type on pointer receiver only keys and vals +- Map with interface keys and values +- Map with nil interface value +- Struct with primitives +- Struct that contains another struct +- Struct that contains custom type with Stringer pointer interface via both + exported and unexported fields +- Struct that contains embedded struct and field to same struct +- Uintptr to 0 (null pointer) +- Uintptr address of real variable +- Unsafe.Pointer to 0 (null pointer) +- Unsafe.Pointer to address of real variable +- Nil channel +- Standard int channel +- Function with no params and no returns +- Function with param and no returns +- Function with multiple params and multiple returns +- Struct that is circular through self referencing +- Structs that are circular through cross referencing +- Structs that are indirectly circular +- Type that panics in its Stringer interface +*/ + +package spew_test + +import ( + "bytes" + "fmt" + "testing" + "unsafe" + + "github.com/davecgh/go-spew/spew" +) + +// dumpTest is used to describe a test to be performed against the Dump method. +type dumpTest struct { + in interface{} + wants []string +} + +// dumpTests houses all of the tests to be performed against the Dump method. +var dumpTests = make([]dumpTest, 0) + +// addDumpTest is a helper method to append the passed input and desired result +// to dumpTests +func addDumpTest(in interface{}, wants ...string) { + test := dumpTest{in, wants} + dumpTests = append(dumpTests, test) +} + +func addIntDumpTests() { + // Max int8. + v := int8(127) + nv := (*int8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int8" + vs := "127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Max int16. + v2 := int16(32767) + nv2 := (*int16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "int16" + v2s := "32767" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Max int32. + v3 := int32(2147483647) + nv3 := (*int32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "int32" + v3s := "2147483647" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Max int64. + v4 := int64(9223372036854775807) + nv4 := (*int64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "int64" + v4s := "9223372036854775807" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Max int. + v5 := int(2147483647) + nv5 := (*int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "int" + v5s := "2147483647" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addUintDumpTests() { + // Max uint8. + v := uint8(255) + nv := (*uint8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uint8" + vs := "255" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Max uint16. + v2 := uint16(65535) + nv2 := (*uint16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Max uint32. + v3 := uint32(4294967295) + nv3 := (*uint32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "uint32" + v3s := "4294967295" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Max uint64. + v4 := uint64(18446744073709551615) + nv4 := (*uint64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "uint64" + v4s := "18446744073709551615" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Max uint. + v5 := uint(4294967295) + nv5 := (*uint)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "uint" + v5s := "4294967295" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addBoolDumpTests() { + // Boolean true. + v := bool(true) + nv := (*bool)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "bool" + vs := "true" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Boolean false. + v2 := bool(false) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "bool" + v2s := "false" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addFloatDumpTests() { + // Standard float32. + v := float32(3.1415) + nv := (*float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "3.1415" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Standard float64. + v2 := float64(3.1415926) + nv2 := (*float64)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "float64" + v2s := "3.1415926" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addComplexDumpTests() { + // Standard complex64. + v := complex(float32(6), -2) + nv := (*complex64)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "complex64" + vs := "(6-2i)" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Standard complex128. + v2 := complex(float64(-6), 2) + nv2 := (*complex128)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "complex128" + v2s := "(-6+2i)" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addArrayDumpTests() { + // Array containing standard ints. + v := [3]int{1, 2, 3} + vLen := fmt.Sprintf("%d", len(v)) + vCap := fmt.Sprintf("%d", cap(v)) + nv := (*[3]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int" + vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" + + vt + ") 2,\n (" + vt + ") 3\n}" + addDumpTest(v, "([3]"+vt+") "+vs+"\n") + addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*[3]"+vt+")()\n") + + // Array containing type with custom formatter on pointer receiver only. + v2i0 := pstringer("1") + v2i1 := pstringer("2") + v2i2 := pstringer("3") + v2 := [3]pstringer{v2i0, v2i1, v2i2} + v2i0Len := fmt.Sprintf("%d", len(v2i0)) + v2i1Len := fmt.Sprintf("%d", len(v2i1)) + v2i2Len := fmt.Sprintf("%d", len(v2i2)) + v2Len := fmt.Sprintf("%d", len(v2)) + v2Cap := fmt.Sprintf("%d", cap(v2)) + nv2 := (*[3]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.pstringer" + v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + + ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t + + ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t + + ") (len=" + v2i2Len + ") " + "stringer 3\n}" + v2s := v2sp + if spew.UnsafeDisabled { + v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + + ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" + + v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len + + ") " + "\"3\"\n}" + } + addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n") + addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n") + addDumpTest(nv2, "(*[3]"+v2t+")()\n") + + // Array containing interfaces. + v3i0 := "one" + v3 := [3]interface{}{v3i0, int(2), uint(3)} + v3i0Len := fmt.Sprintf("%d", len(v3i0)) + v3Len := fmt.Sprintf("%d", len(v3)) + v3Cap := fmt.Sprintf("%d", cap(v3)) + nv3 := (*[3]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[3]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Array containing bytes. + v4 := [34]byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + v4Len := fmt.Sprintf("%d", len(v4)) + v4Cap := fmt.Sprintf("%d", cap(v4)) + nv4 := (*[34]byte)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[34]uint8" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + + " |............... |\n" + + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + + " |!\"#$%&'()*+,-./0|\n" + + " 00000020 31 32 " + + " |12|\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") +} + +func addSliceDumpTests() { + // Slice containing standard float32 values. + v := []float32{3.14, 6.28, 12.56} + vLen := fmt.Sprintf("%d", len(v)) + vCap := fmt.Sprintf("%d", cap(v)) + nv := (*[]float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" + + vt + ") 6.28,\n (" + vt + ") 12.56\n}" + addDumpTest(v, "([]"+vt+") "+vs+"\n") + addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*[]"+vt+")()\n") + + // Slice containing type with custom formatter on pointer receiver only. + v2i0 := pstringer("1") + v2i1 := pstringer("2") + v2i2 := pstringer("3") + v2 := []pstringer{v2i0, v2i1, v2i2} + v2i0Len := fmt.Sprintf("%d", len(v2i0)) + v2i1Len := fmt.Sprintf("%d", len(v2i1)) + v2i2Len := fmt.Sprintf("%d", len(v2i2)) + v2Len := fmt.Sprintf("%d", len(v2)) + v2Cap := fmt.Sprintf("%d", cap(v2)) + nv2 := (*[]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.pstringer" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" + + v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len + + ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " + + "stringer 3\n}" + addDumpTest(v2, "([]"+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*[]"+v2t+")()\n") + + // Slice containing interfaces. + v3i0 := "one" + v3 := []interface{}{v3i0, int(2), uint(3), nil} + v3i0Len := fmt.Sprintf("%d", len(v3i0)) + v3Len := fmt.Sprintf("%d", len(v3)) + v3Cap := fmt.Sprintf("%d", cap(v3)) + nv3 := (*[]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3t5 := "interface {}" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " + + "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" + + v3t4 + ") 3,\n (" + v3t5 + ") \n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Slice containing bytes. + v4 := []byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + v4Len := fmt.Sprintf("%d", len(v4)) + v4Cap := fmt.Sprintf("%d", cap(v4)) + nv4 := (*[]byte)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[]uint8" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" + + " |............... |\n" + + " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" + + " |!\"#$%&'()*+,-./0|\n" + + " 00000020 31 32 " + + " |12|\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") + + // Nil slice. + v5 := []int(nil) + nv5 := (*[]int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "[]int" + v5s := "" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n") + addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n") + addDumpTest(nv5, "(*"+v5t+")()\n") +} + +func addStringDumpTests() { + // Standard string. + v := "test" + vLen := fmt.Sprintf("%d", len(v)) + nv := (*string)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "string" + vs := "(len=" + vLen + ") \"test\"" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addInterfaceDumpTests() { + // Nil interface. + var v interface{} + nv := (*interface{})(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "interface {}" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Sub-interface. + v2 := interface{}(uint16(65535)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addMapDumpTests() { + // Map with string keys and int vals. + k := "one" + kk := "two" + m := map[string]int{k: 1, kk: 2} + klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up + kkLen := fmt.Sprintf("%d", len(kk)) + mLen := fmt.Sprintf("%d", len(m)) + nilMap := map[string]int(nil) + nm := (*map[string]int)(nil) + pm := &m + mAddr := fmt.Sprintf("%p", pm) + pmAddr := fmt.Sprintf("%p", &pm) + mt := "map[string]int" + mt1 := "string" + mt2 := "int" + ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " + + "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen + + ") \"two\": (" + mt2 + ") 2\n}" + ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " + + "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen + + ") \"one\": (" + mt2 + ") 1\n}" + addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n") + addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n", + "(*"+mt+")("+mAddr+")("+ms2+")\n") + addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n", + "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n") + addDumpTest(nm, "(*"+mt+")()\n") + addDumpTest(nilMap, "("+mt+") \n") + + // Map with custom formatter type on pointer receiver only keys and vals. + k2 := pstringer("one") + v2 := pstringer("1") + m2 := map[pstringer]pstringer{k2: v2} + k2Len := fmt.Sprintf("%d", len(k2)) + v2Len := fmt.Sprintf("%d", len(v2)) + m2Len := fmt.Sprintf("%d", len(m2)) + nilMap2 := map[pstringer]pstringer(nil) + nm2 := (*map[pstringer]pstringer)(nil) + pm2 := &m2 + m2Addr := fmt.Sprintf("%p", pm2) + pm2Addr := fmt.Sprintf("%p", &pm2) + m2t := "map[spew_test.pstringer]spew_test.pstringer" + m2t1 := "spew_test.pstringer" + m2t2 := "spew_test.pstringer" + m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " + + "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}" + if spew.UnsafeDisabled { + m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + + ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len + + ") \"1\"\n}" + } + addDumpTest(m2, "("+m2t+") "+m2s+"\n") + addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n") + addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n") + addDumpTest(nm2, "(*"+m2t+")()\n") + addDumpTest(nilMap2, "("+m2t+") \n") + + // Map with interface keys and values. + k3 := "one" + k3Len := fmt.Sprintf("%d", len(k3)) + m3 := map[interface{}]interface{}{k3: 1} + m3Len := fmt.Sprintf("%d", len(m3)) + nilMap3 := map[interface{}]interface{}(nil) + nm3 := (*map[interface{}]interface{})(nil) + pm3 := &m3 + m3Addr := fmt.Sprintf("%p", pm3) + pm3Addr := fmt.Sprintf("%p", &pm3) + m3t := "map[interface {}]interface {}" + m3t1 := "string" + m3t2 := "int" + m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " + + "\"one\": (" + m3t2 + ") 1\n}" + addDumpTest(m3, "("+m3t+") "+m3s+"\n") + addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n") + addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n") + addDumpTest(nm3, "(*"+m3t+")()\n") + addDumpTest(nilMap3, "("+m3t+") \n") + + // Map with nil interface value. + k4 := "nil" + k4Len := fmt.Sprintf("%d", len(k4)) + m4 := map[string]interface{}{k4: nil} + m4Len := fmt.Sprintf("%d", len(m4)) + nilMap4 := map[string]interface{}(nil) + nm4 := (*map[string]interface{})(nil) + pm4 := &m4 + m4Addr := fmt.Sprintf("%p", pm4) + pm4Addr := fmt.Sprintf("%p", &pm4) + m4t := "map[string]interface {}" + m4t1 := "string" + m4t2 := "interface {}" + m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" + + " \"nil\": (" + m4t2 + ") \n}" + addDumpTest(m4, "("+m4t+") "+m4s+"\n") + addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n") + addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n") + addDumpTest(nm4, "(*"+m4t+")()\n") + addDumpTest(nilMap4, "("+m4t+") \n") +} + +func addStructDumpTests() { + // Struct with primitives. + type s1 struct { + a int8 + b uint8 + } + v := s1{127, 255} + nv := (*s1)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.s1" + vt2 := "int8" + vt3 := "uint8" + vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Struct that contains another struct. + type s2 struct { + s1 s1 + b bool + } + v2 := s2{s1{127, 255}, true} + nv2 := (*s2)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.s2" + v2t2 := "spew_test.s1" + v2t3 := "int8" + v2t4 := "uint8" + v2t5 := "bool" + v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" + + v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Struct that contains custom type with Stringer pointer interface via both + // exported and unexported fields. + type s3 struct { + s pstringer + S pstringer + } + v3 := s3{"test", "test2"} + nv3 := (*s3)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.s3" + v3t2 := "spew_test.pstringer" + v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 + + ") (len=5) stringer test2\n}" + v3sp := v3s + if spew.UnsafeDisabled { + v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + + v3t2 + ") (len=5) \"test2\"\n}" + v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" + + v3t2 + ") (len=5) stringer test2\n}" + } + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") + + // Struct that contains embedded struct and field to same struct. + e := embed{"embedstr"} + eLen := fmt.Sprintf("%d", len("embedstr")) + v4 := embedwrap{embed: &e, e: &e} + nv4 := (*embedwrap)(nil) + pv4 := &v4 + eAddr := fmt.Sprintf("%p", &e) + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "spew_test.embedwrap" + v4t2 := "spew_test.embed" + v4t3 := "string" + v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 + + ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 + + ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" + + " \"embedstr\"\n })\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n") + addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n") + addDumpTest(nv4, "(*"+v4t+")()\n") +} + +func addUintptrDumpTests() { + // Null pointer. + v := uintptr(0) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uintptr" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + + // Address of real variable. + i := 1 + v2 := uintptr(unsafe.Pointer(&i)) + nv2 := (*uintptr)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uintptr" + v2s := fmt.Sprintf("%p", &i) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") +} + +func addUnsafePointerDumpTests() { + // Null pointer. + v := unsafe.Pointer(uintptr(0)) + nv := (*unsafe.Pointer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "unsafe.Pointer" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Address of real variable. + i := 1 + v2 := unsafe.Pointer(&i) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "unsafe.Pointer" + v2s := fmt.Sprintf("%p", &i) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addChanDumpTests() { + // Nil channel. + var v chan int + pv := &v + nv := (*chan int)(nil) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "chan int" + vs := "" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Real channel. + v2 := make(chan int) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "chan int" + v2s := fmt.Sprintf("%p", v2) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") +} + +func addFuncDumpTests() { + // Function with no params and no returns. + v := addIntDumpTests + nv := (*func())(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "func()" + vs := fmt.Sprintf("%p", v) + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") + + // Function with param and no returns. + v2 := TestDump + nv2 := (*func(*testing.T))(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "func(*testing.T)" + v2s := fmt.Sprintf("%p", v2) + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n") + addDumpTest(nv2, "(*"+v2t+")()\n") + + // Function with multiple params and multiple returns. + var v3 = func(i int, s string) (b bool, err error) { + return true, nil + } + nv3 := (*func(int, string) (bool, error))(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "func(int, string) (bool, error)" + v3s := fmt.Sprintf("%p", v3) + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n") + addDumpTest(nv3, "(*"+v3t+")()\n") +} + +func addCircularDumpTests() { + // Struct that is circular through self referencing. + type circular struct { + c *circular + } + v := circular{nil} + v.c = &v + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.circular" + vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" + + vAddr + ")()\n })\n}" + vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n") + + // Structs that are circular through cross referencing. + v2 := xref1{nil} + ts2 := xref2{&v2} + v2.ps2 = &ts2 + pv2 := &v2 + ts2Addr := fmt.Sprintf("%p", &ts2) + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.xref1" + v2t2 := "spew_test.xref2" + v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + + ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr + + ")()\n })\n })\n}" + v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t + + ")(" + v2Addr + ")()\n })\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n") + addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n") + + // Structs that are indirectly circular. + v3 := indirCir1{nil} + tic2 := indirCir2{nil} + tic3 := indirCir3{&v3} + tic2.ps3 = &tic3 + v3.ps2 = &tic2 + pv3 := &v3 + tic2Addr := fmt.Sprintf("%p", &tic2) + tic3Addr := fmt.Sprintf("%p", &tic3) + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.indirCir1" + v3t2 := "spew_test.indirCir2" + v3t3 := "spew_test.indirCir3" + v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + + ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr + + ")()\n })\n })\n })\n}" + v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 + + ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr + + ")()\n })\n })\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n") + addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n") + addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n") +} + +func addPanicDumpTests() { + // Type that panics in its Stringer interface. + v := panicer(127) + nv := (*panicer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.panicer" + vs := "(PANIC=test panic)127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +func addErrorDumpTests() { + // Type that has a custom Error interface. + v := customError(127) + nv := (*customError)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.customError" + vs := "error: 127" + addDumpTest(v, "("+vt+") "+vs+"\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n") + addDumpTest(nv, "(*"+vt+")()\n") +} + +// TestDump executes all of the tests described by dumpTests. +func TestDump(t *testing.T) { + // Setup tests. + addIntDumpTests() + addUintDumpTests() + addBoolDumpTests() + addFloatDumpTests() + addComplexDumpTests() + addArrayDumpTests() + addSliceDumpTests() + addStringDumpTests() + addInterfaceDumpTests() + addMapDumpTests() + addStructDumpTests() + addUintptrDumpTests() + addUnsafePointerDumpTests() + addChanDumpTests() + addFuncDumpTests() + addCircularDumpTests() + addPanicDumpTests() + addErrorDumpTests() + addCgoDumpTests() + + t.Logf("Running %d tests", len(dumpTests)) + for i, test := range dumpTests { + buf := new(bytes.Buffer) + spew.Fdump(buf, test.in) + s := buf.String() + if testFailed(s, test.wants) { + t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants)) + continue + } + } +} + +func TestDumpSortedKeys(t *testing.T) { + cfg := spew.ConfigState{SortKeys: true} + s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"}) + expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " + + "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " + + "(len=1) \"3\"\n" + + "}\n" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2}) + expected = "(map[spew_test.stringer]int) (len=3) {\n" + + "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" + + "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" + + "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" + + "}\n" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) + expected = "(map[spew_test.pstringer]int) (len=3) {\n" + + "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" + + "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" + + "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" + + "}\n" + if spew.UnsafeDisabled { + expected = "(map[spew_test.pstringer]int) (len=3) {\n" + + "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" + + "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" + + "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" + + "}\n" + } + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + + s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) + expected = "(map[spew_test.customError]int) (len=3) {\n" + + "(spew_test.customError) error: 1: (int) 1,\n" + + "(spew_test.customError) error: 2: (int) 2,\n" + + "(spew_test.customError) error: 3: (int) 3\n" + + "}\n" + if s != expected { + t.Errorf("Sorted keys mismatch:\n %v %v", s, expected) + } + +} diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go new file mode 100644 index 000000000..6ab180809 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go @@ -0,0 +1,99 @@ +// Copyright (c) 2013-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when both cgo is supported and "-tags testcgo" is added to the go test +// command line. This means the cgo tests are only added (and hence run) when +// specifially requested. This configuration is used because spew itself +// does not require cgo to run even though it does handle certain cgo types +// specially. Rather than forcing all clients to require cgo and an external +// C compiler just to run the tests, this scheme makes them optional. +// +build cgo,testcgo + +package spew_test + +import ( + "fmt" + + "github.com/davecgh/go-spew/spew/testdata" +) + +func addCgoDumpTests() { + // C char pointer. + v := testdata.GetCgoCharPointer() + nv := testdata.GetCgoNullCharPointer() + pv := &v + vcAddr := fmt.Sprintf("%p", v) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "*testdata._Ctype_char" + vs := "116" + addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n") + addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n") + addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n") + addDumpTest(nv, "("+vt+")()\n") + + // C char array. + v2, v2l, v2c := testdata.GetCgoCharArray() + v2Len := fmt.Sprintf("%d", v2l) + v2Cap := fmt.Sprintf("%d", v2c) + v2t := "[6]testdata._Ctype_char" + v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " + + "{\n 00000000 74 65 73 74 32 00 " + + " |test2.|\n}" + addDumpTest(v2, "("+v2t+") "+v2s+"\n") + + // C unsigned char array. + v3, v3l, v3c := testdata.GetCgoUnsignedCharArray() + v3Len := fmt.Sprintf("%d", v3l) + v3Cap := fmt.Sprintf("%d", v3c) + v3t := "[6]testdata._Ctype_unsignedchar" + v3t2 := "[6]testdata._Ctype_uchar" + v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " + + "{\n 00000000 74 65 73 74 33 00 " + + " |test3.|\n}" + addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n") + + // C signed char array. + v4, v4l, v4c := testdata.GetCgoSignedCharArray() + v4Len := fmt.Sprintf("%d", v4l) + v4Cap := fmt.Sprintf("%d", v4c) + v4t := "[6]testdata._Ctype_schar" + v4t2 := "testdata._Ctype_schar" + v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " + + "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 + + ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 + + ") 0\n}" + addDumpTest(v4, "("+v4t+") "+v4s+"\n") + + // C uint8_t array. + v5, v5l, v5c := testdata.GetCgoUint8tArray() + v5Len := fmt.Sprintf("%d", v5l) + v5Cap := fmt.Sprintf("%d", v5c) + v5t := "[6]testdata._Ctype_uint8_t" + v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + + "{\n 00000000 74 65 73 74 35 00 " + + " |test5.|\n}" + addDumpTest(v5, "("+v5t+") "+v5s+"\n") + + // C typedefed unsigned char array. + v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() + v6Len := fmt.Sprintf("%d", v6l) + v6Cap := fmt.Sprintf("%d", v6c) + v6t := "[6]testdata._Ctype_custom_uchar_t" + v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + + "{\n 00000000 74 65 73 74 36 00 " + + " |test6.|\n}" + addDumpTest(v6, "("+v6t+") "+v6s+"\n") +} diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go new file mode 100644 index 000000000..52a0971fb --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go @@ -0,0 +1,26 @@ +// Copyright (c) 2013 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when either cgo is not supported or "-tags testcgo" is not added to the go +// test command line. This file intentionally does not setup any cgo tests in +// this scenario. +// +build !cgo !testcgo + +package spew_test + +func addCgoDumpTests() { + // Don't add any tests for cgo since this file is only compiled when + // there should not be any cgo tests. +} diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go new file mode 100644 index 000000000..c6ec8c6d5 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/example_test.go @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "fmt" + + "github.com/davecgh/go-spew/spew" +) + +type Flag int + +const ( + flagOne Flag = iota + flagTwo +) + +var flagStrings = map[Flag]string{ + flagOne: "flagOne", + flagTwo: "flagTwo", +} + +func (f Flag) String() string { + if s, ok := flagStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown flag (%d)", int(f)) +} + +type Bar struct { + data uintptr +} + +type Foo struct { + unexportedField Bar + ExportedField map[interface{}]interface{} +} + +// This example demonstrates how to use Dump to dump variables to stdout. +func ExampleDump() { + // The following package level declarations are assumed for this example: + /* + type Flag int + + const ( + flagOne Flag = iota + flagTwo + ) + + var flagStrings = map[Flag]string{ + flagOne: "flagOne", + flagTwo: "flagTwo", + } + + func (f Flag) String() string { + if s, ok := flagStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown flag (%d)", int(f)) + } + + type Bar struct { + data uintptr + } + + type Foo struct { + unexportedField Bar + ExportedField map[interface{}]interface{} + } + */ + + // Setup some sample data structures for the example. + bar := Bar{uintptr(0)} + s1 := Foo{bar, map[interface{}]interface{}{"one": true}} + f := Flag(5) + b := []byte{ + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, + } + + // Dump! + spew.Dump(s1, f, b) + + // Output: + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // (spew_test.Flag) Unknown flag (5) + // ([]uint8) (len=34 cap=34) { + // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + // 00000020 31 32 |12| + // } + // +} + +// This example demonstrates how to use Printf to display a variable with a +// format string and inline formatting. +func ExamplePrintf() { + // Create a double pointer to a uint 8. + ui8 := uint8(5) + pui8 := &ui8 + ppui8 := &pui8 + + // Create a circular data type. + type circular struct { + ui8 uint8 + c *circular + } + c := circular{ui8: 1} + c.c = &c + + // Print! + spew.Printf("ppui8: %v\n", ppui8) + spew.Printf("circular: %v\n", c) + + // Output: + // ppui8: <**>5 + // circular: {1 <*>{1 <*>}} +} + +// This example demonstrates how to use a ConfigState. +func ExampleConfigState() { + // Modify the indent level of the ConfigState only. The global + // configuration is not modified. + scs := spew.ConfigState{Indent: "\t"} + + // Output using the ConfigState instance. + v := map[string]int{"one": 1} + scs.Printf("v: %v\n", v) + scs.Dump(v) + + // Output: + // v: map[one:1] + // (map[string]int) (len=1) { + // (string) (len=3) "one": (int) 1 + // } +} + +// This example demonstrates how to use ConfigState.Dump to dump variables to +// stdout +func ExampleConfigState_Dump() { + // See the top-level Dump example for details on the types used in this + // example. + + // Create two ConfigState instances with different indentation. + scs := spew.ConfigState{Indent: "\t"} + scs2 := spew.ConfigState{Indent: " "} + + // Setup some sample data structures for the example. + bar := Bar{uintptr(0)} + s1 := Foo{bar, map[interface{}]interface{}{"one": true}} + + // Dump using the ConfigState instances. + scs.Dump(s1) + scs2.Dump(s1) + + // Output: + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // (spew_test.Foo) { + // unexportedField: (spew_test.Bar) { + // data: (uintptr) + // }, + // ExportedField: (map[interface {}]interface {}) (len=1) { + // (string) (len=3) "one": (bool) true + // } + // } + // +} + +// This example demonstrates how to use ConfigState.Printf to display a variable +// with a format string and inline formatting. +func ExampleConfigState_Printf() { + // See the top-level Dump example for details on the types used in this + // example. + + // Create two ConfigState instances and modify the method handling of the + // first ConfigState only. + scs := spew.NewDefaultConfig() + scs2 := spew.NewDefaultConfig() + scs.DisableMethods = true + + // Alternatively + // scs := spew.ConfigState{Indent: " ", DisableMethods: true} + // scs2 := spew.ConfigState{Indent: " "} + + // This is of type Flag which implements a Stringer and has raw value 1. + f := flagTwo + + // Dump using the ConfigState instances. + scs.Printf("f: %v\n", f) + scs2.Printf("f: %v\n", f) + + // Output: + // f: 1 + // f: flagTwo +} diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go new file mode 100644 index 000000000..f9b93abe8 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/format_test.go @@ -0,0 +1,1558 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Test Summary: +NOTE: For each test, a nil pointer, a single pointer and double pointer to the +base test element are also tested to ensure proper indirection across all types. + +- Max int8, int16, int32, int64, int +- Max uint8, uint16, uint32, uint64, uint +- Boolean true and false +- Standard complex64 and complex128 +- Array containing standard ints +- Array containing type with custom formatter on pointer receiver only +- Array containing interfaces +- Slice containing standard float32 values +- Slice containing type with custom formatter on pointer receiver only +- Slice containing interfaces +- Nil slice +- Standard string +- Nil interface +- Sub-interface +- Map with string keys and int vals +- Map with custom formatter type on pointer receiver only keys and vals +- Map with interface keys and values +- Map with nil interface value +- Struct with primitives +- Struct that contains another struct +- Struct that contains custom type with Stringer pointer interface via both + exported and unexported fields +- Struct that contains embedded struct and field to same struct +- Uintptr to 0 (null pointer) +- Uintptr address of real variable +- Unsafe.Pointer to 0 (null pointer) +- Unsafe.Pointer to address of real variable +- Nil channel +- Standard int channel +- Function with no params and no returns +- Function with param and no returns +- Function with multiple params and multiple returns +- Struct that is circular through self referencing +- Structs that are circular through cross referencing +- Structs that are indirectly circular +- Type that panics in its Stringer interface +- Type that has a custom Error interface +- %x passthrough with uint +- %#x passthrough with uint +- %f passthrough with precision +- %f passthrough with width and precision +- %d passthrough with width +- %q passthrough with string +*/ + +package spew_test + +import ( + "bytes" + "fmt" + "testing" + "unsafe" + + "github.com/davecgh/go-spew/spew" +) + +// formatterTest is used to describe a test to be performed against NewFormatter. +type formatterTest struct { + format string + in interface{} + wants []string +} + +// formatterTests houses all of the tests to be performed against NewFormatter. +var formatterTests = make([]formatterTest, 0) + +// addFormatterTest is a helper method to append the passed input and desired +// result to formatterTests. +func addFormatterTest(format string, in interface{}, wants ...string) { + test := formatterTest{format, in, wants} + formatterTests = append(formatterTests, test) +} + +func addIntFormatterTests() { + // Max int8. + v := int8(127) + nv := (*int8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "int8" + vs := "127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Max int16. + v2 := int16(32767) + nv2 := (*int16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "int16" + v2s := "32767" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Max int32. + v3 := int32(2147483647) + nv3 := (*int32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "int32" + v3s := "2147483647" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + + // Max int64. + v4 := int64(9223372036854775807) + nv4 := (*int64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "int64" + v4s := "9223372036854775807" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") + + // Max int. + v5 := int(2147483647) + nv5 := (*int)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "int" + v5s := "2147483647" + addFormatterTest("%v", v5, v5s) + addFormatterTest("%v", pv5, "<*>"+v5s) + addFormatterTest("%v", &pv5, "<**>"+v5s) + addFormatterTest("%v", nv5, "") + addFormatterTest("%+v", v5, v5s) + addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) + addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%+v", nv5, "") + addFormatterTest("%#v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) + addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") + addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) + addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"") +} + +func addUintFormatterTests() { + // Max uint8. + v := uint8(255) + nv := (*uint8)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uint8" + vs := "255" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Max uint16. + v2 := uint16(65535) + nv2 := (*uint16)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Max uint32. + v3 := uint32(4294967295) + nv3 := (*uint32)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "uint32" + v3s := "4294967295" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + + // Max uint64. + v4 := uint64(18446744073709551615) + nv4 := (*uint64)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "uint64" + v4s := "18446744073709551615" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") + + // Max uint. + v5 := uint(4294967295) + nv5 := (*uint)(nil) + pv5 := &v5 + v5Addr := fmt.Sprintf("%p", pv5) + pv5Addr := fmt.Sprintf("%p", &pv5) + v5t := "uint" + v5s := "4294967295" + addFormatterTest("%v", v5, v5s) + addFormatterTest("%v", pv5, "<*>"+v5s) + addFormatterTest("%v", &pv5, "<**>"+v5s) + addFormatterTest("%v", nv5, "") + addFormatterTest("%+v", v5, v5s) + addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s) + addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%+v", nv5, "") + addFormatterTest("%#v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s) + addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") + addFormatterTest("%#+v", v5, "("+v5t+")"+v5s) + addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s) + addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s) + addFormatterTest("%#v", nv5, "(*"+v5t+")"+"") +} + +func addBoolFormatterTests() { + // Boolean true. + v := bool(true) + nv := (*bool)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "bool" + vs := "true" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Boolean false. + v2 := bool(false) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "bool" + v2s := "false" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addFloatFormatterTests() { + // Standard float32. + v := float32(3.1415) + nv := (*float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "float32" + vs := "3.1415" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Standard float64. + v2 := float64(3.1415926) + nv2 := (*float64)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "float64" + v2s := "3.1415926" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") +} + +func addComplexFormatterTests() { + // Standard complex64. + v := complex(float32(6), -2) + nv := (*complex64)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "complex64" + vs := "(6-2i)" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Standard complex128. + v2 := complex(float64(-6), 2) + nv2 := (*complex128)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "complex128" + v2s := "(-6+2i)" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") +} + +func addArrayFormatterTests() { + // Array containing standard ints. + v := [3]int{1, 2, 3} + nv := (*[3]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "[3]int" + vs := "[1 2 3]" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Array containing type with custom formatter on pointer receiver only. + v2 := [3]pstringer{"1", "2", "3"} + nv2 := (*[3]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "[3]spew_test.pstringer" + v2sp := "[stringer 1 stringer 2 stringer 3]" + v2s := v2sp + if spew.UnsafeDisabled { + v2s = "[1 2 3]" + } + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2sp) + addFormatterTest("%v", &pv2, "<**>"+v2sp) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Array containing interfaces. + v3 := [3]interface{}{"one", int(2), uint(3)} + nv3 := (*[3]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[3]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3s := "[one 2 3]" + v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") +} + +func addSliceFormatterTests() { + // Slice containing standard float32 values. + v := []float32{3.14, 6.28, 12.56} + nv := (*[]float32)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "[]float32" + vs := "[3.14 6.28 12.56]" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Slice containing type with custom formatter on pointer receiver only. + v2 := []pstringer{"1", "2", "3"} + nv2 := (*[]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "[]spew_test.pstringer" + v2s := "[stringer 1 stringer 2 stringer 3]" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Slice containing interfaces. + v3 := []interface{}{"one", int(2), uint(3), nil} + nv3 := (*[]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "[]interface {}" + v3t2 := "string" + v3t3 := "int" + v3t4 := "uint" + v3t5 := "interface {}" + v3s := "[one 2 3 ]" + v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 + + ")]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Nil slice. + var v4 []int + nv4 := (*[]int)(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "[]int" + v4s := "" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addStringFormatterTests() { + // Standard string. + v := "test" + nv := (*string)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "string" + vs := "test" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addInterfaceFormatterTests() { + // Nil interface. + var v interface{} + nv := (*interface{})(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "interface {}" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Sub-interface. + v2 := interface{}(uint16(65535)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uint16" + v2s := "65535" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addMapFormatterTests() { + // Map with string keys and int vals. + v := map[string]int{"one": 1, "two": 2} + nilMap := map[string]int(nil) + nv := (*map[string]int)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "map[string]int" + vs := "map[one:1 two:2]" + vs2 := "map[two:2 one:1]" + addFormatterTest("%v", v, vs, vs2) + addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2) + addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2) + addFormatterTest("%+v", nilMap, "") + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs, vs2) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs, + "<**>("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%+v", nilMap, "") + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2) + addFormatterTest("%#v", nilMap, "("+vt+")"+"") + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs, + "(*"+vt+")("+vAddr+")"+vs2) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs, + "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%#+v", nilMap, "("+vt+")"+"") + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Map with custom formatter type on pointer receiver only keys and vals. + v2 := map[pstringer]pstringer{"one": "1"} + nv2 := (*map[pstringer]pstringer)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "map[spew_test.pstringer]spew_test.pstringer" + v2s := "map[stringer one:stringer 1]" + if spew.UnsafeDisabled { + v2s = "map[one:1]" + } + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Map with interface keys and values. + v3 := map[interface{}]interface{}{"one": 1} + nv3 := (*map[interface{}]interface{})(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "map[interface {}]interface {}" + v3t1 := "string" + v3t2 := "int" + v3s := "map[one:1]" + v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Map with nil interface value + v4 := map[string]interface{}{"nil": nil} + nv4 := (*map[string]interface{})(nil) + pv4 := &v4 + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "map[string]interface {}" + v4t1 := "interface {}" + v4s := "map[nil:]" + v4s2 := "map[nil:(" + v4t1 + ")]" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s2) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addStructFormatterTests() { + // Struct with primitives. + type s1 struct { + a int8 + b uint8 + } + v := s1{127, 255} + nv := (*s1)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.s1" + vt2 := "int8" + vt3 := "uint8" + vs := "{127 255}" + vs2 := "{a:127 b:255}" + vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs2) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs3) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs3) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs3) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Struct that contains another struct. + type s2 struct { + s1 s1 + b bool + } + v2 := s2{s1{127, 255}, true} + nv2 := (*s2)(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.s2" + v2t2 := "spew_test.s1" + v2t3 := "int8" + v2t4 := "uint8" + v2t5 := "bool" + v2s := "{{127 255} true}" + v2s2 := "{s1:{a:127 b:255} b:true}" + v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" + + v2t5 + ")true}" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s2) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s3) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Struct that contains custom type with Stringer pointer interface via both + // exported and unexported fields. + type s3 struct { + s pstringer + S pstringer + } + v3 := s3{"test", "test2"} + nv3 := (*s3)(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.s3" + v3t2 := "spew_test.pstringer" + v3s := "{stringer test stringer test2}" + v3sp := v3s + v3s2 := "{s:stringer test S:stringer test2}" + v3s2p := v3s2 + v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}" + v3s3p := v3s3 + if spew.UnsafeDisabled { + v3s = "{test test2}" + v3sp = "{test stringer test2}" + v3s2 = "{s:test S:test2}" + v3s2p = "{s:test S:stringer test2}" + v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}" + v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}" + } + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3sp) + addFormatterTest("%v", &pv3, "<**>"+v3sp) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s2) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s3) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") + + // Struct that contains embedded struct and field to same struct. + e := embed{"embedstr"} + v4 := embedwrap{embed: &e, e: &e} + nv4 := (*embedwrap)(nil) + pv4 := &v4 + eAddr := fmt.Sprintf("%p", &e) + v4Addr := fmt.Sprintf("%p", pv4) + pv4Addr := fmt.Sprintf("%p", &pv4) + v4t := "spew_test.embedwrap" + v4t2 := "spew_test.embed" + v4t3 := "string" + v4s := "{<*>{embedstr} <*>{embedstr}}" + v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr + + "){a:embedstr}}" + v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 + + "){a:(" + v4t3 + ")embedstr}}" + v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + + ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}" + addFormatterTest("%v", v4, v4s) + addFormatterTest("%v", pv4, "<*>"+v4s) + addFormatterTest("%v", &pv4, "<**>"+v4s) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%+v", v4, v4s2) + addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2) + addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2) + addFormatterTest("%+v", nv4, "") + addFormatterTest("%#v", v4, "("+v4t+")"+v4s3) + addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3) + addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3) + addFormatterTest("%#v", nv4, "(*"+v4t+")"+"") + addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4) + addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4) + addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4) + addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"") +} + +func addUintptrFormatterTests() { + // Null pointer. + v := uintptr(0) + nv := (*uintptr)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "uintptr" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Address of real variable. + i := 1 + v2 := uintptr(unsafe.Pointer(&i)) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "uintptr" + v2s := fmt.Sprintf("%p", &i) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addUnsafePointerFormatterTests() { + // Null pointer. + v := unsafe.Pointer(uintptr(0)) + nv := (*unsafe.Pointer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "unsafe.Pointer" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Address of real variable. + i := 1 + v2 := unsafe.Pointer(&i) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "unsafe.Pointer" + v2s := fmt.Sprintf("%p", &i) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addChanFormatterTests() { + // Nil channel. + var v chan int + pv := &v + nv := (*chan int)(nil) + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "chan int" + vs := "" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Real channel. + v2 := make(chan int) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "chan int" + v2s := fmt.Sprintf("%p", v2) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) +} + +func addFuncFormatterTests() { + // Function with no params and no returns. + v := addIntFormatterTests + nv := (*func())(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "func()" + vs := fmt.Sprintf("%p", v) + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") + + // Function with param and no returns. + v2 := TestFormatter + nv2 := (*func(*testing.T))(nil) + pv2 := &v2 + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "func(*testing.T)" + v2s := fmt.Sprintf("%p", v2) + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s) + addFormatterTest("%v", &pv2, "<**>"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%+v", v2, v2s) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%+v", nv2, "") + addFormatterTest("%#v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s) + addFormatterTest("%#v", nv2, "(*"+v2t+")"+"") + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s) + addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"") + + // Function with multiple params and multiple returns. + var v3 = func(i int, s string) (b bool, err error) { + return true, nil + } + nv3 := (*func(int, string) (bool, error))(nil) + pv3 := &v3 + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "func(int, string) (bool, error)" + v3s := fmt.Sprintf("%p", v3) + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s) + addFormatterTest("%v", &pv3, "<**>"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%+v", v3, v3s) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%+v", nv3, "") + addFormatterTest("%#v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s) + addFormatterTest("%#v", nv3, "(*"+v3t+")"+"") + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s) + addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"") +} + +func addCircularFormatterTests() { + // Struct that is circular through self referencing. + type circular struct { + c *circular + } + v := circular{nil} + v.c = &v + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.circular" + vs := "{<*>{<*>}}" + vs2 := "{<*>}" + vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}" + vs4 := "{c:<*>(" + vAddr + ")}" + vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}" + vs6 := "{c:(*" + vt + ")}" + vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr + + ")}}" + vs8 := "{c:(*" + vt + ")(" + vAddr + ")}" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs2) + addFormatterTest("%v", &pv, "<**>"+vs2) + addFormatterTest("%+v", v, vs3) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4) + addFormatterTest("%#v", v, "("+vt+")"+vs5) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs6) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6) + addFormatterTest("%#+v", v, "("+vt+")"+vs7) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8) + + // Structs that are circular through cross referencing. + v2 := xref1{nil} + ts2 := xref2{&v2} + v2.ps2 = &ts2 + pv2 := &v2 + ts2Addr := fmt.Sprintf("%p", &ts2) + v2Addr := fmt.Sprintf("%p", pv2) + pv2Addr := fmt.Sprintf("%p", &pv2) + v2t := "spew_test.xref1" + v2t2 := "spew_test.xref2" + v2s := "{<*>{<*>{<*>}}}" + v2s2 := "{<*>{<*>}}" + v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" + + ts2Addr + ")}}}" + v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")}}" + v2s5 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + "){ps2:(*" + v2t2 + + ")}}}" + v2s6 := "{ps2:(*" + v2t2 + "){ps1:(*" + v2t + ")}}" + v2s7 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + + ")(" + v2Addr + "){ps2:(*" + v2t2 + ")(" + ts2Addr + + ")}}}" + v2s8 := "{ps2:(*" + v2t2 + ")(" + ts2Addr + "){ps1:(*" + v2t + + ")(" + v2Addr + ")}}" + addFormatterTest("%v", v2, v2s) + addFormatterTest("%v", pv2, "<*>"+v2s2) + addFormatterTest("%v", &pv2, "<**>"+v2s2) + addFormatterTest("%+v", v2, v2s3) + addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s4) + addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s4) + addFormatterTest("%#v", v2, "("+v2t+")"+v2s5) + addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s6) + addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s6) + addFormatterTest("%#+v", v2, "("+v2t+")"+v2s7) + addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s8) + addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s8) + + // Structs that are indirectly circular. + v3 := indirCir1{nil} + tic2 := indirCir2{nil} + tic3 := indirCir3{&v3} + tic2.ps3 = &tic3 + v3.ps2 = &tic2 + pv3 := &v3 + tic2Addr := fmt.Sprintf("%p", &tic2) + tic3Addr := fmt.Sprintf("%p", &tic3) + v3Addr := fmt.Sprintf("%p", pv3) + pv3Addr := fmt.Sprintf("%p", &pv3) + v3t := "spew_test.indirCir1" + v3t2 := "spew_test.indirCir2" + v3t3 := "spew_test.indirCir3" + v3s := "{<*>{<*>{<*>{<*>}}}}" + v3s2 := "{<*>{<*>{<*>}}}" + v3s3 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + + v3Addr + "){ps2:<*>(" + tic2Addr + ")}}}}" + v3s4 := "{ps2:<*>(" + tic2Addr + "){ps3:<*>(" + tic3Addr + "){ps1:<*>(" + + v3Addr + ")}}}" + v3s5 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + + "){ps2:(*" + v3t2 + ")}}}}" + v3s6 := "{ps2:(*" + v3t2 + "){ps3:(*" + v3t3 + "){ps1:(*" + v3t + + ")}}}" + v3s7 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + "){ps2:(*" + v3t2 + + ")(" + tic2Addr + ")}}}}" + v3s8 := "{ps2:(*" + v3t2 + ")(" + tic2Addr + "){ps3:(*" + v3t3 + ")(" + + tic3Addr + "){ps1:(*" + v3t + ")(" + v3Addr + ")}}}" + addFormatterTest("%v", v3, v3s) + addFormatterTest("%v", pv3, "<*>"+v3s2) + addFormatterTest("%v", &pv3, "<**>"+v3s2) + addFormatterTest("%+v", v3, v3s3) + addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s4) + addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s4) + addFormatterTest("%#v", v3, "("+v3t+")"+v3s5) + addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s6) + addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s6) + addFormatterTest("%#+v", v3, "("+v3t+")"+v3s7) + addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s8) + addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s8) +} + +func addPanicFormatterTests() { + // Type that panics in its Stringer interface. + v := panicer(127) + nv := (*panicer)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.panicer" + vs := "(PANIC=test panic)127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addErrorFormatterTests() { + // Type that has a custom Error interface. + v := customError(127) + nv := (*customError)(nil) + pv := &v + vAddr := fmt.Sprintf("%p", pv) + pvAddr := fmt.Sprintf("%p", &pv) + vt := "spew_test.customError" + vs := "error: 127" + addFormatterTest("%v", v, vs) + addFormatterTest("%v", pv, "<*>"+vs) + addFormatterTest("%v", &pv, "<**>"+vs) + addFormatterTest("%v", nv, "") + addFormatterTest("%+v", v, vs) + addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs) + addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%+v", nv, "") + addFormatterTest("%#v", v, "("+vt+")"+vs) + addFormatterTest("%#v", pv, "(*"+vt+")"+vs) + addFormatterTest("%#v", &pv, "(**"+vt+")"+vs) + addFormatterTest("%#v", nv, "(*"+vt+")"+"") + addFormatterTest("%#+v", v, "("+vt+")"+vs) + addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs) + addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs) + addFormatterTest("%#+v", nv, "(*"+vt+")"+"") +} + +func addPassthroughFormatterTests() { + // %x passthrough with uint. + v := uint(4294967295) + pv := &v + vAddr := fmt.Sprintf("%x", pv) + pvAddr := fmt.Sprintf("%x", &pv) + vs := "ffffffff" + addFormatterTest("%x", v, vs) + addFormatterTest("%x", pv, vAddr) + addFormatterTest("%x", &pv, pvAddr) + + // %#x passthrough with uint. + v2 := int(2147483647) + pv2 := &v2 + v2Addr := fmt.Sprintf("%#x", pv2) + pv2Addr := fmt.Sprintf("%#x", &pv2) + v2s := "0x7fffffff" + addFormatterTest("%#x", v2, v2s) + addFormatterTest("%#x", pv2, v2Addr) + addFormatterTest("%#x", &pv2, pv2Addr) + + // %f passthrough with precision. + addFormatterTest("%.2f", 3.1415, "3.14") + addFormatterTest("%.3f", 3.1415, "3.142") + addFormatterTest("%.4f", 3.1415, "3.1415") + + // %f passthrough with width and precision. + addFormatterTest("%5.2f", 3.1415, " 3.14") + addFormatterTest("%6.3f", 3.1415, " 3.142") + addFormatterTest("%7.4f", 3.1415, " 3.1415") + + // %d passthrough with width. + addFormatterTest("%3d", 127, "127") + addFormatterTest("%4d", 127, " 127") + addFormatterTest("%5d", 127, " 127") + + // %q passthrough with string. + addFormatterTest("%q", "test", "\"test\"") +} + +// TestFormatter executes all of the tests described by formatterTests. +func TestFormatter(t *testing.T) { + // Setup tests. + addIntFormatterTests() + addUintFormatterTests() + addBoolFormatterTests() + addFloatFormatterTests() + addComplexFormatterTests() + addArrayFormatterTests() + addSliceFormatterTests() + addStringFormatterTests() + addInterfaceFormatterTests() + addMapFormatterTests() + addStructFormatterTests() + addUintptrFormatterTests() + addUnsafePointerFormatterTests() + addChanFormatterTests() + addFuncFormatterTests() + addCircularFormatterTests() + addPanicFormatterTests() + addErrorFormatterTests() + addPassthroughFormatterTests() + + t.Logf("Running %d tests", len(formatterTests)) + for i, test := range formatterTests { + buf := new(bytes.Buffer) + spew.Fprintf(buf, test.format, test.in) + s := buf.String() + if testFailed(s, test.wants) { + t.Errorf("Formatter #%d format: %s got: %s %s", i, test.format, s, + stringizeWants(test.wants)) + continue + } + } +} + +type testStruct struct { + x int +} + +func (ts testStruct) String() string { + return fmt.Sprintf("ts.%d", ts.x) +} + +type testStructP struct { + x int +} + +func (ts *testStructP) String() string { + return fmt.Sprintf("ts.%d", ts.x) +} + +func TestPrintSortedKeys(t *testing.T) { + cfg := spew.ConfigState{SortKeys: true} + s := cfg.Sprint(map[int]string{1: "1", 3: "3", 2: "2"}) + expected := "map[1:1 2:2 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch 1:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[stringer]int{"1": 1, "3": 3, "2": 2}) + expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch 2:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2}) + expected = "map[stringer 1:1 stringer 2:2 stringer 3:3]" + if spew.UnsafeDisabled { + expected = "map[1:1 2:2 3:3]" + } + if s != expected { + t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) + } + + s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) + expected = "map[ts.1:1 ts.2:2 ts.3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) + } + + if !spew.UnsafeDisabled { + s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) + expected = "map[ts.1:1 ts.2:2 ts.3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) + } + } + + s = cfg.Sprint(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2}) + expected = "map[error: 1:1 error: 2:2 error: 3:3]" + if s != expected { + t.Errorf("Sorted keys mismatch 6:\n %v %v", s, expected) + } +} diff --git a/vendor/github.com/davecgh/go-spew/spew/internal_test.go b/vendor/github.com/davecgh/go-spew/spew/internal_test.go new file mode 100644 index 000000000..20a9cfefc --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/internal_test.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +This test file is part of the spew package rather than than the spew_test +package because it needs access to internals to properly test certain cases +which are not possible via the public interface since they should never happen. +*/ + +package spew + +import ( + "bytes" + "reflect" + "testing" +) + +// dummyFmtState implements a fake fmt.State to use for testing invalid +// reflect.Value handling. This is necessary because the fmt package catches +// invalid values before invoking the formatter on them. +type dummyFmtState struct { + bytes.Buffer +} + +func (dfs *dummyFmtState) Flag(f int) bool { + if f == int('+') { + return true + } + return false +} + +func (dfs *dummyFmtState) Precision() (int, bool) { + return 0, false +} + +func (dfs *dummyFmtState) Width() (int, bool) { + return 0, false +} + +// TestInvalidReflectValue ensures the dump and formatter code handles an +// invalid reflect value properly. This needs access to internal state since it +// should never happen in real code and therefore can't be tested via the public +// API. +func TestInvalidReflectValue(t *testing.T) { + i := 1 + + // Dump invalid reflect value. + v := new(reflect.Value) + buf := new(bytes.Buffer) + d := dumpState{w: buf, cs: &Config} + d.dump(*v) + s := buf.String() + want := "" + if s != want { + t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want) + } + i++ + + // Formatter invalid reflect value. + buf2 := new(dummyFmtState) + f := formatState{value: *v, cs: &Config, fs: buf2} + f.format(*v) + s = buf2.String() + want = "" + if s != want { + t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want) + } +} + +// SortValues makes the internal sortValues function available to the test +// package. +func SortValues(values []reflect.Value, cs *ConfigState) { + sortValues(values, cs) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go b/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go new file mode 100644 index 000000000..a0c612ec3 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go @@ -0,0 +1,102 @@ +// Copyright (c) 2013-2016 Dave Collins + +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. + +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is not running on Google App Engine, compiled by GopherJS, and +// "-tags safe" is not added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// +build !js,!appengine,!safe,!disableunsafe + +/* +This test file is part of the spew package rather than than the spew_test +package because it needs access to internals to properly test certain cases +which are not possible via the public interface since they should never happen. +*/ + +package spew + +import ( + "bytes" + "reflect" + "testing" + "unsafe" +) + +// changeKind uses unsafe to intentionally change the kind of a reflect.Value to +// the maximum kind value which does not exist. This is needed to test the +// fallback code which punts to the standard fmt library for new types that +// might get added to the language. +func changeKind(v *reflect.Value, readOnly bool) { + rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) + *rvf = *rvf | ((1< + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/davecgh/go-spew/spew" +) + +// spewFunc is used to identify which public function of the spew package or +// ConfigState a test applies to. +type spewFunc int + +const ( + fCSFdump spewFunc = iota + fCSFprint + fCSFprintf + fCSFprintln + fCSPrint + fCSPrintln + fCSSdump + fCSSprint + fCSSprintf + fCSSprintln + fCSErrorf + fCSNewFormatter + fErrorf + fFprint + fFprintln + fPrint + fPrintln + fSdump + fSprint + fSprintf + fSprintln +) + +// Map of spewFunc values to names for pretty printing. +var spewFuncStrings = map[spewFunc]string{ + fCSFdump: "ConfigState.Fdump", + fCSFprint: "ConfigState.Fprint", + fCSFprintf: "ConfigState.Fprintf", + fCSFprintln: "ConfigState.Fprintln", + fCSSdump: "ConfigState.Sdump", + fCSPrint: "ConfigState.Print", + fCSPrintln: "ConfigState.Println", + fCSSprint: "ConfigState.Sprint", + fCSSprintf: "ConfigState.Sprintf", + fCSSprintln: "ConfigState.Sprintln", + fCSErrorf: "ConfigState.Errorf", + fCSNewFormatter: "ConfigState.NewFormatter", + fErrorf: "spew.Errorf", + fFprint: "spew.Fprint", + fFprintln: "spew.Fprintln", + fPrint: "spew.Print", + fPrintln: "spew.Println", + fSdump: "spew.Sdump", + fSprint: "spew.Sprint", + fSprintf: "spew.Sprintf", + fSprintln: "spew.Sprintln", +} + +func (f spewFunc) String() string { + if s, ok := spewFuncStrings[f]; ok { + return s + } + return fmt.Sprintf("Unknown spewFunc (%d)", int(f)) +} + +// spewTest is used to describe a test to be performed against the public +// functions of the spew package or ConfigState. +type spewTest struct { + cs *spew.ConfigState + f spewFunc + format string + in interface{} + want string +} + +// spewTests houses the tests to be performed against the public functions of +// the spew package and ConfigState. +// +// These tests are only intended to ensure the public functions are exercised +// and are intentionally not exhaustive of types. The exhaustive type +// tests are handled in the dump and format tests. +var spewTests []spewTest + +// redirStdout is a helper function to return the standard output from f as a +// byte slice. +func redirStdout(f func()) ([]byte, error) { + tempFile, err := ioutil.TempFile("", "ss-test") + if err != nil { + return nil, err + } + fileName := tempFile.Name() + defer os.Remove(fileName) // Ignore error + + origStdout := os.Stdout + os.Stdout = tempFile + f() + os.Stdout = origStdout + tempFile.Close() + + return ioutil.ReadFile(fileName) +} + +func initSpewTests() { + // Config states with various settings. + scsDefault := spew.NewDefaultConfig() + scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true} + scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} + scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} + scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} + scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true} + scsNoCap := &spew.ConfigState{DisableCapacities: true} + + // Variables for tests on types which implement Stringer interface with and + // without a pointer receiver. + ts := stringer("test") + tps := pstringer("test") + + type ptrTester struct { + s *struct{} + } + tptr := &ptrTester{s: &struct{}{}} + + // depthTester is used to test max depth handling for structs, array, slices + // and maps. + type depthTester struct { + ic indirCir1 + arr [1]string + slice []string + m map[string]int + } + dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"}, + map[string]int{"one": 1}} + + // Variable for tests on types which implement error interface. + te := customError(10) + + spewTests = []spewTest{ + {scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"}, + {scsDefault, fCSFprint, "", int16(32767), "32767"}, + {scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"}, + {scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"}, + {scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"}, + {scsDefault, fCSPrintln, "", uint8(255), "255\n"}, + {scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"}, + {scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"}, + {scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"}, + {scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"}, + {scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"}, + {scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"}, + {scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"}, + {scsDefault, fFprint, "", float32(3.14), "3.14"}, + {scsDefault, fFprintln, "", float64(6.28), "6.28\n"}, + {scsDefault, fPrint, "", true, "true"}, + {scsDefault, fPrintln, "", false, "false\n"}, + {scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"}, + {scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"}, + {scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"}, + {scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"}, + {scsNoMethods, fCSFprint, "", ts, "test"}, + {scsNoMethods, fCSFprint, "", &ts, "<*>test"}, + {scsNoMethods, fCSFprint, "", tps, "test"}, + {scsNoMethods, fCSFprint, "", &tps, "<*>test"}, + {scsNoPmethods, fCSFprint, "", ts, "stringer test"}, + {scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"}, + {scsNoPmethods, fCSFprint, "", tps, "test"}, + {scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"}, + {scsMaxDepth, fCSFprint, "", dt, "{{} [] [] map[]}"}, + {scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" + + " ic: (spew_test.indirCir1) {\n \n },\n" + + " arr: ([1]string) (len=1 cap=1) {\n \n },\n" + + " slice: ([]string) (len=1 cap=1) {\n \n },\n" + + " m: (map[string]int) (len=1) {\n \n }\n}\n"}, + {scsContinue, fCSFprint, "", ts, "(stringer test) test"}, + {scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " + + "(len=4) (stringer test) \"test\"\n"}, + {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, + {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + + "(error: 10) 10\n"}, + {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"}, + {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"}, + {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"}, + {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"}, + } +} + +// TestSpew executes all of the tests described by spewTests. +func TestSpew(t *testing.T) { + initSpewTests() + + t.Logf("Running %d tests", len(spewTests)) + for i, test := range spewTests { + buf := new(bytes.Buffer) + switch test.f { + case fCSFdump: + test.cs.Fdump(buf, test.in) + + case fCSFprint: + test.cs.Fprint(buf, test.in) + + case fCSFprintf: + test.cs.Fprintf(buf, test.format, test.in) + + case fCSFprintln: + test.cs.Fprintln(buf, test.in) + + case fCSPrint: + b, err := redirStdout(func() { test.cs.Print(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fCSPrintln: + b, err := redirStdout(func() { test.cs.Println(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fCSSdump: + str := test.cs.Sdump(test.in) + buf.WriteString(str) + + case fCSSprint: + str := test.cs.Sprint(test.in) + buf.WriteString(str) + + case fCSSprintf: + str := test.cs.Sprintf(test.format, test.in) + buf.WriteString(str) + + case fCSSprintln: + str := test.cs.Sprintln(test.in) + buf.WriteString(str) + + case fCSErrorf: + err := test.cs.Errorf(test.format, test.in) + buf.WriteString(err.Error()) + + case fCSNewFormatter: + fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in)) + + case fErrorf: + err := spew.Errorf(test.format, test.in) + buf.WriteString(err.Error()) + + case fFprint: + spew.Fprint(buf, test.in) + + case fFprintln: + spew.Fprintln(buf, test.in) + + case fPrint: + b, err := redirStdout(func() { spew.Print(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fPrintln: + b, err := redirStdout(func() { spew.Println(test.in) }) + if err != nil { + t.Errorf("%v #%d %v", test.f, i, err) + continue + } + buf.Write(b) + + case fSdump: + str := spew.Sdump(test.in) + buf.WriteString(str) + + case fSprint: + str := spew.Sprint(test.in) + buf.WriteString(str) + + case fSprintf: + str := spew.Sprintf(test.format, test.in) + buf.WriteString(str) + + case fSprintln: + str := spew.Sprintln(test.in) + buf.WriteString(str) + + default: + t.Errorf("%v #%d unrecognized function", test.f, i) + continue + } + s := buf.String() + if test.want != s { + t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want) + continue + } + } +} diff --git a/vendor/github.com/davecgh/go-spew/test_coverage.txt b/vendor/github.com/davecgh/go-spew/test_coverage.txt new file mode 100644 index 000000000..2cd087a2a --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/test_coverage.txt @@ -0,0 +1,61 @@ + +github.com/davecgh/go-spew/spew/dump.go dumpState.dump 100.00% (88/88) +github.com/davecgh/go-spew/spew/format.go formatState.format 100.00% (82/82) +github.com/davecgh/go-spew/spew/format.go formatState.formatPtr 100.00% (52/52) +github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44) +github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39) +github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30) +github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18) +github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13) +github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12) +github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11) +github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11) +github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10) +github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9) +github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8) +github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7) +github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5) +github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4) +github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4) +github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4) +github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4) +github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3) +github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3) +github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3) +github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3) +github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3) +github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3) +github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Sprint 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1) +github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1) +github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1) +github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1) +github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505) + diff --git a/vendor/github.com/dgrijalva/jwt-go/.gitignore b/vendor/github.com/dgrijalva/jwt-go/.gitignore new file mode 100644 index 000000000..80bed650e --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +bin + + diff --git a/vendor/github.com/dgrijalva/jwt-go/.travis.yml b/vendor/github.com/dgrijalva/jwt-go/.travis.yml new file mode 100644 index 000000000..1027f56cd --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/.travis.yml @@ -0,0 +1,13 @@ +language: go + +script: + - go vet ./... + - go test -v ./... + +go: + - 1.3 + - 1.4 + - 1.5 + - 1.6 + - 1.7 + - tip diff --git a/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md b/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md new file mode 100644 index 000000000..7fc1f793c --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/MIGRATION_GUIDE.md @@ -0,0 +1,97 @@ +## Migration Guide from v2 -> v3 + +Version 3 adds several new, frequently requested features. To do so, it introduces a few breaking changes. We've worked to keep these as minimal as possible. This guide explains the breaking changes and how you can quickly update your code. + +### `Token.Claims` is now an interface type + +The most requested feature from the 2.0 verison of this library was the ability to provide a custom type to the JSON parser for claims. This was implemented by introducing a new interface, `Claims`, to replace `map[string]interface{}`. We also included two concrete implementations of `Claims`: `MapClaims` and `StandardClaims`. + +`MapClaims` is an alias for `map[string]interface{}` with built in validation behavior. It is the default claims type when using `Parse`. The usage is unchanged except you must type cast the claims property. + +The old example for parsing a token looked like this.. + +```go + if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil { + fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"]) + } +``` + +is now directly mapped to... + +```go + if token, err := jwt.Parse(tokenString, keyLookupFunc); err == nil { + claims := token.Claims.(jwt.MapClaims) + fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"]) + } +``` + +`StandardClaims` is designed to be embedded in your custom type. You can supply a custom claims type with the new `ParseWithClaims` function. Here's an example of using a custom claims type. + +```go + type MyCustomClaims struct { + User string + *StandardClaims + } + + if token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, keyLookupFunc); err == nil { + claims := token.Claims.(*MyCustomClaims) + fmt.Printf("Token for user %v expires %v", claims.User, claims.StandardClaims.ExpiresAt) + } +``` + +### `ParseFromRequest` has been moved + +To keep this library focused on the tokens without becoming overburdened with complex request processing logic, `ParseFromRequest` and its new companion `ParseFromRequestWithClaims` have been moved to a subpackage, `request`. The method signatues have also been augmented to receive a new argument: `Extractor`. + +`Extractors` do the work of picking the token string out of a request. The interface is simple and composable. + +This simple parsing example: + +```go + if token, err := jwt.ParseFromRequest(tokenString, req, keyLookupFunc); err == nil { + fmt.Printf("Token for user %v expires %v", token.Claims["user"], token.Claims["exp"]) + } +``` + +is directly mapped to: + +```go + if token, err := request.ParseFromRequest(req, request.OAuth2Extractor, keyLookupFunc); err == nil { + claims := token.Claims.(jwt.MapClaims) + fmt.Printf("Token for user %v expires %v", claims["user"], claims["exp"]) + } +``` + +There are several concrete `Extractor` types provided for your convenience: + +* `HeaderExtractor` will search a list of headers until one contains content. +* `ArgumentExtractor` will search a list of keys in request query and form arguments until one contains content. +* `MultiExtractor` will try a list of `Extractors` in order until one returns content. +* `AuthorizationHeaderExtractor` will look in the `Authorization` header for a `Bearer` token. +* `OAuth2Extractor` searches the places an OAuth2 token would be specified (per the spec): `Authorization` header and `access_token` argument +* `PostExtractionFilter` wraps an `Extractor`, allowing you to process the content before it's parsed. A simple example is stripping the `Bearer ` text from a header + + +### RSA signing methods no longer accept `[]byte` keys + +Due to a [critical vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/), we've decided the convenience of accepting `[]byte` instead of `rsa.PublicKey` or `rsa.PrivateKey` isn't worth the risk of misuse. + +To replace this behavior, we've added two helper methods: `ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error)` and `ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error)`. These are just simple helpers for unpacking PEM encoded PKCS1 and PKCS8 keys. If your keys are encoded any other way, all you need to do is convert them to the `crypto/rsa` package's types. + +```go + func keyLookupFunc(*Token) (interface{}, error) { + // Don't forget to validate the alg is what you expect: + if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + + // Look up key + key, err := lookupPublicKey(token.Header["kid"]) + if err != nil { + return nil, err + } + + // Unpack key from PEM encoded PKCS8 + return jwt.ParseRSAPublicKeyFromPEM(key) + } +``` diff --git a/vendor/github.com/dgrijalva/jwt-go/README.md b/vendor/github.com/dgrijalva/jwt-go/README.md new file mode 100644 index 000000000..d358d881b --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/README.md @@ -0,0 +1,100 @@ +# jwt-go + +[![Build Status](https://travis-ci.org/dgrijalva/jwt-go.svg?branch=master)](https://travis-ci.org/dgrijalva/jwt-go) +[![GoDoc](https://godoc.org/github.com/dgrijalva/jwt-go?status.svg)](https://godoc.org/github.com/dgrijalva/jwt-go) + +A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html) + +**NEW VERSION COMING:** There have been a lot of improvements suggested since the version 3.0.0 released in 2016. I'm working now on cutting two different releases: 3.2.0 will contain any non-breaking changes or enhancements. 4.0.0 will follow shortly which will include breaking changes. See the 4.0.0 milestone to get an idea of what's coming. If you have other ideas, or would like to participate in 4.0.0, now's the time. If you depend on this library and don't want to be interrupted, I recommend you use your dependency mangement tool to pin to version 3. + +**SECURITY NOTICE:** Some older versions of Go have a security issue in the cryotp/elliptic. Recommendation is to upgrade to at least 1.8.3. See issue #216 for more detail. + +**SECURITY NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage. See the examples provided. + +## What the heck is a JWT? + +JWT.io has [a great introduction](https://jwt.io/introduction) to JSON Web Tokens. + +In short, it's a signed JSON object that does something useful (for example, authentication). It's commonly used for `Bearer` tokens in Oauth 2. A token is made of three parts, separated by `.`'s. The first two parts are JSON objects, that have been [base64url](http://tools.ietf.org/html/rfc4648) encoded. The last part is the signature, encoded the same way. + +The first part is called the header. It contains the necessary information for verifying the last part, the signature. For example, which encryption method was used for signing and what key was used. + +The part in the middle is the interesting bit. It's called the Claims and contains the actual stuff you care about. Refer to [the RFC](http://self-issued.info/docs/draft-jones-json-web-token.html) for information about reserved keys and the proper way to add your own. + +## What's in the box? + +This library supports the parsing and verification as well as the generation and signing of JWTs. Current supported signing algorithms are HMAC SHA, RSA, RSA-PSS, and ECDSA, though hooks are present for adding your own. + +## Examples + +See [the project documentation](https://godoc.org/github.com/dgrijalva/jwt-go) for examples of usage: + +* [Simple example of parsing and validating a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac) +* [Simple example of building and signing a token](https://godoc.org/github.com/dgrijalva/jwt-go#example-New--Hmac) +* [Directory of Examples](https://godoc.org/github.com/dgrijalva/jwt-go#pkg-examples) + +## Extensions + +This library publishes all the necessary components for adding your own signing methods. Simply implement the `SigningMethod` interface and register a factory method using `RegisterSigningMethod`. + +Here's an example of an extension that integrates with the Google App Engine signing tools: https://github.com/someone1/gcp-jwt-go + +## Compliance + +This library was last reviewed to comply with [RTF 7519](http://www.rfc-editor.org/info/rfc7519) dated May 2015 with a few notable differences: + +* In order to protect against accidental use of [Unsecured JWTs](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#UnsecuredJWT), tokens using `alg=none` will only be accepted if the constant `jwt.UnsafeAllowNoneSignatureType` is provided as the key. + +## Project Status & Versioning + +This library is considered production ready. Feedback and feature requests are appreciated. The API should be considered stable. There should be very few backwards-incompatible changes outside of major version updates (and only with good reason). + +This project uses [Semantic Versioning 2.0.0](http://semver.org). Accepted pull requests will land on `master`. Periodically, versions will be tagged from `master`. You can find all the releases on [the project releases page](https://github.com/dgrijalva/jwt-go/releases). + +While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users. You may want to use this alternative package include: `gopkg.in/dgrijalva/jwt-go.v3`. It will do the right thing WRT semantic versioning. + +**BREAKING CHANGES:*** +* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API. We've tried to break as few things as possible, so there should just be a few type signature changes. A full list of breaking changes is available in `VERSION_HISTORY.md`. See `MIGRATION_GUIDE.md` for more information on updating your code. + +## Usage Tips + +### Signing vs Encryption + +A token is simply a JSON object that is signed by its author. this tells you exactly two things about the data: + +* The author of the token was in the possession of the signing secret +* The data has not been modified since it was signed + +It's important to know that JWT does not provide encryption, which means anyone who has access to the token can read its contents. If you need to protect (encrypt) the data, there is a companion spec, `JWE`, that provides this functionality. JWE is currently outside the scope of this library. + +### Choosing a Signing Method + +There are several signing methods available, and you should probably take the time to learn about the various options before choosing one. The principal design decision is most likely going to be symmetric vs asymmetric. + +Symmetric signing methods, such as HSA, use only a single secret. This is probably the simplest signing method to use since any `[]byte` can be used as a valid secret. They are also slightly computationally faster to use, though this rarely is enough to matter. Symmetric signing methods work the best when both producers and consumers of tokens are trusted, or even the same system. Since the same secret is used to both sign and validate tokens, you can't easily distribute the key for validation. + +Asymmetric signing methods, such as RSA, use different keys for signing and verifying tokens. This makes it possible to produce tokens with a private key, and allow any consumer to access the public key for verification. + +### Signing Methods and Key Types + +Each signing method expects a different object type for its signing keys. See the package documentation for details. Here are the most common ones: + +* The [HMAC signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodHMAC) (`HS256`,`HS384`,`HS512`) expect `[]byte` values for signing and validation +* The [RSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA) (`RS256`,`RS384`,`RS512`) expect `*rsa.PrivateKey` for signing and `*rsa.PublicKey` for validation +* The [ECDSA signing method](https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodECDSA) (`ES256`,`ES384`,`ES512`) expect `*ecdsa.PrivateKey` for signing and `*ecdsa.PublicKey` for validation + +### JWT and OAuth + +It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is simply a signed JSON object. It can be used anywhere such a thing is useful. There is some confusion, though, as JWT is the most common type of bearer token used in OAuth2 authentication. + +Without going too far down the rabbit hole, here's a description of the interaction of these technologies: + +* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth. +* OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token. +* Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL. + +## More + +Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go). + +The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation. diff --git a/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md b/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md new file mode 100644 index 000000000..637029831 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md @@ -0,0 +1,118 @@ +## `jwt-go` Version History + +#### 3.2.0 + +* Added method `ParseUnverified` to allow users to split up the tasks of parsing and validation +* HMAC signing method returns `ErrInvalidKeyType` instead of `ErrInvalidKey` where appropriate +* Added options to `request.ParseFromRequest`, which allows for an arbitrary list of modifiers to parsing behavior. Initial set include `WithClaims` and `WithParser`. Existing usage of this function will continue to work as before. +* Deprecated `ParseFromRequestWithClaims` to simplify API in the future. + +#### 3.1.0 + +* Improvements to `jwt` command line tool +* Added `SkipClaimsValidation` option to `Parser` +* Documentation updates + +#### 3.0.0 + +* **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code + * Dropped support for `[]byte` keys when using RSA signing methods. This convenience feature could contribute to security vulnerabilities involving mismatched key types with signing methods. + * `ParseFromRequest` has been moved to `request` subpackage and usage has changed + * The `Claims` property on `Token` is now type `Claims` instead of `map[string]interface{}`. The default value is type `MapClaims`, which is an alias to `map[string]interface{}`. This makes it possible to use a custom type when decoding claims. +* Other Additions and Changes + * Added `Claims` interface type to allow users to decode the claims into a custom type + * Added `ParseWithClaims`, which takes a third argument of type `Claims`. Use this function instead of `Parse` if you have a custom type you'd like to decode into. + * Dramatically improved the functionality and flexibility of `ParseFromRequest`, which is now in the `request` subpackage + * Added `ParseFromRequestWithClaims` which is the `FromRequest` equivalent of `ParseWithClaims` + * Added new interface type `Extractor`, which is used for extracting JWT strings from http requests. Used with `ParseFromRequest` and `ParseFromRequestWithClaims`. + * Added several new, more specific, validation errors to error type bitmask + * Moved examples from README to executable example files + * Signing method registry is now thread safe + * Added new property to `ValidationError`, which contains the raw error returned by calls made by parse/verify (such as those returned by keyfunc or json parser) + +#### 2.7.0 + +This will likely be the last backwards compatible release before 3.0.0, excluding essential bug fixes. + +* Added new option `-show` to the `jwt` command that will just output the decoded token without verifying +* Error text for expired tokens includes how long it's been expired +* Fixed incorrect error returned from `ParseRSAPublicKeyFromPEM` +* Documentation updates + +#### 2.6.0 + +* Exposed inner error within ValidationError +* Fixed validation errors when using UseJSONNumber flag +* Added several unit tests + +#### 2.5.0 + +* Added support for signing method none. You shouldn't use this. The API tries to make this clear. +* Updated/fixed some documentation +* Added more helpful error message when trying to parse tokens that begin with `BEARER ` + +#### 2.4.0 + +* Added new type, Parser, to allow for configuration of various parsing parameters + * You can now specify a list of valid signing methods. Anything outside this set will be rejected. + * You can now opt to use the `json.Number` type instead of `float64` when parsing token JSON +* Added support for [Travis CI](https://travis-ci.org/dgrijalva/jwt-go) +* Fixed some bugs with ECDSA parsing + +#### 2.3.0 + +* Added support for ECDSA signing methods +* Added support for RSA PSS signing methods (requires go v1.4) + +#### 2.2.0 + +* Gracefully handle a `nil` `Keyfunc` being passed to `Parse`. Result will now be the parsed token and an error, instead of a panic. + +#### 2.1.0 + +Backwards compatible API change that was missed in 2.0.0. + +* The `SignedString` method on `Token` now takes `interface{}` instead of `[]byte` + +#### 2.0.0 + +There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change. + +The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`. + +It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`. + +* **Compatibility Breaking Changes** + * `SigningMethodHS256` is now `*SigningMethodHMAC` instead of `type struct` + * `SigningMethodRS256` is now `*SigningMethodRSA` instead of `type struct` + * `KeyFunc` now returns `interface{}` instead of `[]byte` + * `SigningMethod.Sign` now takes `interface{}` instead of `[]byte` for the key + * `SigningMethod.Verify` now takes `interface{}` instead of `[]byte` for the key +* Renamed type `SigningMethodHS256` to `SigningMethodHMAC`. Specific sizes are now just instances of this type. + * Added public package global `SigningMethodHS256` + * Added public package global `SigningMethodHS384` + * Added public package global `SigningMethodHS512` +* Renamed type `SigningMethodRS256` to `SigningMethodRSA`. Specific sizes are now just instances of this type. + * Added public package global `SigningMethodRS256` + * Added public package global `SigningMethodRS384` + * Added public package global `SigningMethodRS512` +* Moved sample private key for HMAC tests from an inline value to a file on disk. Value is unchanged. +* Refactored the RSA implementation to be easier to read +* Exposed helper methods `ParseRSAPrivateKeyFromPEM` and `ParseRSAPublicKeyFromPEM` + +#### 1.0.2 + +* Fixed bug in parsing public keys from certificates +* Added more tests around the parsing of keys for RS256 +* Code refactoring in RS256 implementation. No functional changes + +#### 1.0.1 + +* Fixed panic if RS256 signing method was passed an invalid key + +#### 1.0.0 + +* First versioned release +* API stabilized +* Supports creating, signing, parsing, and validating JWT tokens +* Supports RS256 and HS256 signing methods \ No newline at end of file diff --git a/vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go b/vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go new file mode 100644 index 000000000..753047b1e --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/ecdsa_test.go @@ -0,0 +1,100 @@ +package jwt_test + +import ( + "crypto/ecdsa" + "io/ioutil" + "strings" + "testing" + + "github.com/dgrijalva/jwt-go" +) + +var ecdsaTestData = []struct { + name string + keys map[string]string + tokenString string + alg string + claims map[string]interface{} + valid bool +}{ + { + "Basic ES256", + map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"}, + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJmb28iOiJiYXIifQ.feG39E-bn8HXAKhzDZq7yEAPWYDhZlwTn3sePJnU9VrGMmwdXAIEyoOnrjreYlVM_Z4N13eK9-TmMTWyfKJtHQ", + "ES256", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic ES384", + map[string]string{"private": "test/ec384-private.pem", "public": "test/ec384-public.pem"}, + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJmb28iOiJiYXIifQ.ngAfKMbJUh0WWubSIYe5GMsA-aHNKwFbJk_wq3lq23aPp8H2anb1rRILIzVR0gUf4a8WzDtrzmiikuPWyCS6CN4-PwdgTk-5nehC7JXqlaBZU05p3toM3nWCwm_LXcld", + "ES384", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic ES512", + map[string]string{"private": "test/ec512-private.pem", "public": "test/ec512-public.pem"}, + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJmb28iOiJiYXIifQ.AAU0TvGQOcdg2OvrwY73NHKgfk26UDekh9Prz-L_iWuTBIBqOFCWwwLsRiHB1JOddfKAls5do1W0jR_F30JpVd-6AJeTjGKA4C1A1H6gIKwRY0o_tFDIydZCl_lMBMeG5VNFAjO86-WCSKwc3hqaGkq1MugPRq_qrF9AVbuEB4JPLyL5", + "ES512", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "basic ES256 invalid: foo => bar", + map[string]string{"private": "test/ec256-private.pem", "public": "test/ec256-public.pem"}, + "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.MEQCIHoSJnmGlPaVQDqacx_2XlXEhhqtWceVopjomc2PJLtdAiAUTeGPoNYxZw0z8mgOnnIcjoxRuNDVZvybRZF3wR1l8W", + "ES256", + map[string]interface{}{"foo": "bar"}, + false, + }, +} + +func TestECDSAVerify(t *testing.T) { + for _, data := range ecdsaTestData { + var err error + + key, _ := ioutil.ReadFile(data.keys["public"]) + + var ecdsaKey *ecdsa.PublicKey + if ecdsaKey, err = jwt.ParseECPublicKeyFromPEM(key); err != nil { + t.Errorf("Unable to parse ECDSA public key: %v", err) + } + + parts := strings.Split(data.tokenString, ".") + + method := jwt.GetSigningMethod(data.alg) + err = method.Verify(strings.Join(parts[0:2], "."), parts[2], ecdsaKey) + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying key: %v", data.name, err) + } + if !data.valid && err == nil { + t.Errorf("[%v] Invalid key passed validation", data.name) + } + } +} + +func TestECDSASign(t *testing.T) { + for _, data := range ecdsaTestData { + var err error + key, _ := ioutil.ReadFile(data.keys["private"]) + + var ecdsaKey *ecdsa.PrivateKey + if ecdsaKey, err = jwt.ParseECPrivateKeyFromPEM(key); err != nil { + t.Errorf("Unable to parse ECDSA private key: %v", err) + } + + if data.valid { + parts := strings.Split(data.tokenString, ".") + method := jwt.GetSigningMethod(data.alg) + sig, err := method.Sign(strings.Join(parts[0:2], "."), ecdsaKey) + if err != nil { + t.Errorf("[%v] Error signing token: %v", data.name, err) + } + if sig == parts[2] { + t.Errorf("[%v] Identical signatures\nbefore:\n%v\nafter:\n%v", data.name, parts[2], sig) + } + } + } +} diff --git a/vendor/github.com/dgrijalva/jwt-go/example_test.go b/vendor/github.com/dgrijalva/jwt-go/example_test.go new file mode 100644 index 000000000..ae8b788a0 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/example_test.go @@ -0,0 +1,114 @@ +package jwt_test + +import ( + "fmt" + "github.com/dgrijalva/jwt-go" + "time" +) + +// Example (atypical) using the StandardClaims type by itself to parse a token. +// The StandardClaims type is designed to be embedded into your custom types +// to provide standard validation features. You can use it alone, but there's +// no way to retrieve other fields after parsing. +// See the CustomClaimsType example for intended usage. +func ExampleNewWithClaims_standardClaims() { + mySigningKey := []byte("AllYourBase") + + // Create the Claims + claims := &jwt.StandardClaims{ + ExpiresAt: 15000, + Issuer: "test", + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err := token.SignedString(mySigningKey) + fmt.Printf("%v %v", ss, err) + //Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.QsODzZu3lUZMVdhbO76u3Jv02iYCvEHcYVUI1kOWEU0 +} + +// Example creating a token using a custom claims type. The StandardClaim is embedded +// in the custom type to allow for easy encoding, parsing and validation of standard claims. +func ExampleNewWithClaims_customClaimsType() { + mySigningKey := []byte("AllYourBase") + + type MyCustomClaims struct { + Foo string `json:"foo"` + jwt.StandardClaims + } + + // Create the Claims + claims := MyCustomClaims{ + "bar", + jwt.StandardClaims{ + ExpiresAt: 15000, + Issuer: "test", + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err := token.SignedString(mySigningKey) + fmt.Printf("%v %v", ss, err) + //Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c +} + +// Example creating a token using a custom claims type. The StandardClaim is embedded +// in the custom type to allow for easy encoding, parsing and validation of standard claims. +func ExampleParseWithClaims_customClaimsType() { + tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c" + + type MyCustomClaims struct { + Foo string `json:"foo"` + jwt.StandardClaims + } + + // sample token is expired. override time so it parses as valid + at(time.Unix(0, 0), func() { + token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) { + return []byte("AllYourBase"), nil + }) + + if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid { + fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt) + } else { + fmt.Println(err) + } + }) + + // Output: bar 15000 +} + +// Override time value for tests. Restore default value after. +func at(t time.Time, f func()) { + jwt.TimeFunc = func() time.Time { + return t + } + f() + jwt.TimeFunc = time.Now +} + +// An example of parsing the error types using bitfield checks +func ExampleParse_errorChecking() { + // Token from another example. This token is expired + var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c" + + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return []byte("AllYourBase"), nil + }) + + if token.Valid { + fmt.Println("You look nice today") + } else if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + fmt.Println("That's not even a token") + } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { + // Token is either expired or not active yet + fmt.Println("Timing is everything") + } else { + fmt.Println("Couldn't handle this token:", err) + } + } else { + fmt.Println("Couldn't handle this token:", err) + } + + // Output: Timing is everything +} diff --git a/vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go b/vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go new file mode 100644 index 000000000..002783147 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/hmac_example_test.go @@ -0,0 +1,66 @@ +package jwt_test + +import ( + "fmt" + "github.com/dgrijalva/jwt-go" + "io/ioutil" + "time" +) + +// For HMAC signing method, the key can be any []byte. It is recommended to generate +// a key using crypto/rand or something equivalent. You need the same key for signing +// and validating. +var hmacSampleSecret []byte + +func init() { + // Load sample key data + if keyData, e := ioutil.ReadFile("test/hmacTestKey"); e == nil { + hmacSampleSecret = keyData + } else { + panic(e) + } +} + +// Example creating, signing, and encoding a JWT token using the HMAC signing method +func ExampleNew_hmac() { + // Create a new token object, specifying signing method and the claims + // you would like it to contain. + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "foo": "bar", + "nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(), + }) + + // Sign and get the complete encoded token as a string using the secret + tokenString, err := token.SignedString(hmacSampleSecret) + + fmt.Println(tokenString, err) + // Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU +} + +// Example parsing and validating a token using the HMAC signing method +func ExampleParse_hmac() { + // sample token string taken from the New example + tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.u1riaD1rW97opCoAuRCTy4w58Br-Zk-bh7vLiRIsrpU" + + // Parse takes the token string and a function for looking up the key. The latter is especially + // useful if you use multiple keys for your application. The standard is to use 'kid' in the + // head of the token to identify which key to use, but the parsed token (head and claims) is provided + // to the callback, providing flexibility. + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + // Don't forget to validate the alg is what you expect: + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) + } + + // hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key") + return hmacSampleSecret, nil + }) + + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + fmt.Println(claims["foo"], claims["nbf"]) + } else { + fmt.Println(err) + } + + // Output: bar 1.4444784e+09 +} diff --git a/vendor/github.com/dgrijalva/jwt-go/hmac_test.go b/vendor/github.com/dgrijalva/jwt-go/hmac_test.go new file mode 100644 index 000000000..c7e114f4f --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/hmac_test.go @@ -0,0 +1,91 @@ +package jwt_test + +import ( + "github.com/dgrijalva/jwt-go" + "io/ioutil" + "strings" + "testing" +) + +var hmacTestData = []struct { + name string + tokenString string + alg string + claims map[string]interface{} + valid bool +}{ + { + "web sample", + "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", + "HS256", + map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, + true, + }, + { + "HS384", + "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.KWZEuOD5lbBxZ34g7F-SlVLAQ_r5KApWNWlZIIMyQVz5Zs58a7XdNzj5_0EcNoOy", + "HS384", + map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, + true, + }, + { + "HS512", + "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuMzAwODE5MzhlKzA5LCJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZSwiaXNzIjoiam9lIn0.CN7YijRX6Aw1n2jyI2Id1w90ja-DEMYiWixhYCyHnrZ1VfJRaFQz1bEbjjA5Fn4CLYaUG432dEYmSbS4Saokmw", + "HS512", + map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, + true, + }, + { + "web sample: invalid", + "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXo", + "HS256", + map[string]interface{}{"iss": "joe", "exp": 1300819380, "http://example.com/is_root": true}, + false, + }, +} + +// Sample data from http://tools.ietf.org/html/draft-jones-json-web-signature-04#appendix-A.1 +var hmacTestKey, _ = ioutil.ReadFile("test/hmacTestKey") + +func TestHMACVerify(t *testing.T) { + for _, data := range hmacTestData { + parts := strings.Split(data.tokenString, ".") + + method := jwt.GetSigningMethod(data.alg) + err := method.Verify(strings.Join(parts[0:2], "."), parts[2], hmacTestKey) + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying key: %v", data.name, err) + } + if !data.valid && err == nil { + t.Errorf("[%v] Invalid key passed validation", data.name) + } + } +} + +func TestHMACSign(t *testing.T) { + for _, data := range hmacTestData { + if data.valid { + parts := strings.Split(data.tokenString, ".") + method := jwt.GetSigningMethod(data.alg) + sig, err := method.Sign(strings.Join(parts[0:2], "."), hmacTestKey) + if err != nil { + t.Errorf("[%v] Error signing token: %v", data.name, err) + } + if sig != parts[2] { + t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2]) + } + } + } +} + +func BenchmarkHS256Signing(b *testing.B) { + benchmarkSigning(b, jwt.SigningMethodHS256, hmacTestKey) +} + +func BenchmarkHS384Signing(b *testing.B) { + benchmarkSigning(b, jwt.SigningMethodHS384, hmacTestKey) +} + +func BenchmarkHS512Signing(b *testing.B) { + benchmarkSigning(b, jwt.SigningMethodHS512, hmacTestKey) +} diff --git a/vendor/github.com/dgrijalva/jwt-go/http_example_test.go b/vendor/github.com/dgrijalva/jwt-go/http_example_test.go new file mode 100644 index 000000000..82e9c50a4 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/http_example_test.go @@ -0,0 +1,216 @@ +package jwt_test + +// Example HTTP auth using asymmetric crypto/RSA keys +// This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b + +import ( + "bytes" + "crypto/rsa" + "fmt" + "github.com/dgrijalva/jwt-go" + "github.com/dgrijalva/jwt-go/request" + "io" + "io/ioutil" + "log" + "net" + "net/http" + "net/url" + "strings" + "time" +) + +// location of the files used for signing and verification +const ( + privKeyPath = "test/sample_key" // openssl genrsa -out app.rsa keysize + pubKeyPath = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub +) + +var ( + verifyKey *rsa.PublicKey + signKey *rsa.PrivateKey + serverPort int + // storing sample username/password pairs + // don't do this on a real server + users = map[string]string{ + "test": "known", + } +) + +// read the key files before starting http handlers +func init() { + signBytes, err := ioutil.ReadFile(privKeyPath) + fatal(err) + + signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes) + fatal(err) + + verifyBytes, err := ioutil.ReadFile(pubKeyPath) + fatal(err) + + verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes) + fatal(err) + + http.HandleFunc("/authenticate", authHandler) + http.HandleFunc("/restricted", restrictedHandler) + + // Setup listener + listener, err := net.ListenTCP("tcp", &net.TCPAddr{}) + serverPort = listener.Addr().(*net.TCPAddr).Port + + log.Println("Listening...") + go func() { + fatal(http.Serve(listener, nil)) + }() +} + +var start func() + +func fatal(err error) { + if err != nil { + log.Fatal(err) + } +} + +// Define some custom types were going to use within our tokens +type CustomerInfo struct { + Name string + Kind string +} + +type CustomClaimsExample struct { + *jwt.StandardClaims + TokenType string + CustomerInfo +} + +func Example_getTokenViaHTTP() { + // See func authHandler for an example auth handler that produces a token + res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{ + "user": {"test"}, + "pass": {"known"}, + }) + if err != nil { + fatal(err) + } + + if res.StatusCode != 200 { + fmt.Println("Unexpected status code", res.StatusCode) + } + + // Read the token out of the response body + buf := new(bytes.Buffer) + io.Copy(buf, res.Body) + res.Body.Close() + tokenString := strings.TrimSpace(buf.String()) + + // Parse the token + token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) { + // since we only use the one private key to sign the tokens, + // we also only use its public counter part to verify + return verifyKey, nil + }) + fatal(err) + + claims := token.Claims.(*CustomClaimsExample) + fmt.Println(claims.CustomerInfo.Name) + + //Output: test +} + +func Example_useTokenViaHTTP() { + + // Make a sample token + // In a real world situation, this token will have been acquired from + // some other API call (see Example_getTokenViaHTTP) + token, err := createToken("foo") + fatal(err) + + // Make request. See func restrictedHandler for example request processor + req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil) + fatal(err) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token)) + res, err := http.DefaultClient.Do(req) + fatal(err) + + // Read the response body + buf := new(bytes.Buffer) + io.Copy(buf, res.Body) + res.Body.Close() + fmt.Println(buf.String()) + + // Output: Welcome, foo +} + +func createToken(user string) (string, error) { + // create a signer for rsa 256 + t := jwt.New(jwt.GetSigningMethod("RS256")) + + // set our claims + t.Claims = &CustomClaimsExample{ + &jwt.StandardClaims{ + // set the expire time + // see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4 + ExpiresAt: time.Now().Add(time.Minute * 1).Unix(), + }, + "level1", + CustomerInfo{user, "human"}, + } + + // Creat token string + return t.SignedString(signKey) +} + +// reads the form values, checks them and creates the token +func authHandler(w http.ResponseWriter, r *http.Request) { + // make sure its post + if r.Method != "POST" { + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintln(w, "No POST", r.Method) + return + } + + user := r.FormValue("user") + pass := r.FormValue("pass") + + log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass) + + // check values + if user != "test" || pass != "known" { + w.WriteHeader(http.StatusForbidden) + fmt.Fprintln(w, "Wrong info") + return + } + + tokenString, err := createToken(user) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintln(w, "Sorry, error while Signing Token!") + log.Printf("Token Signing error: %v\n", err) + return + } + + w.Header().Set("Content-Type", "application/jwt") + w.WriteHeader(http.StatusOK) + fmt.Fprintln(w, tokenString) +} + +// only accessible with a valid token +func restrictedHandler(w http.ResponseWriter, r *http.Request) { + // Get token from request + token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) { + // since we only use the one private key to sign the tokens, + // we also only use its public counter part to verify + return verifyKey, nil + }) + + // If the token is missing or invalid, return error + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + fmt.Fprintln(w, "Invalid token:", err) + return + } + + // Token is valid + fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name) + return +} diff --git a/vendor/github.com/dgrijalva/jwt-go/none_test.go b/vendor/github.com/dgrijalva/jwt-go/none_test.go new file mode 100644 index 000000000..29a69efef --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/none_test.go @@ -0,0 +1,72 @@ +package jwt_test + +import ( + "github.com/dgrijalva/jwt-go" + "strings" + "testing" +) + +var noneTestData = []struct { + name string + tokenString string + alg string + key interface{} + claims map[string]interface{} + valid bool +}{ + { + "Basic", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.", + "none", + jwt.UnsafeAllowNoneSignatureType, + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic - no key", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.", + "none", + nil, + map[string]interface{}{"foo": "bar"}, + false, + }, + { + "Signed", + "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw", + "none", + jwt.UnsafeAllowNoneSignatureType, + map[string]interface{}{"foo": "bar"}, + false, + }, +} + +func TestNoneVerify(t *testing.T) { + for _, data := range noneTestData { + parts := strings.Split(data.tokenString, ".") + + method := jwt.GetSigningMethod(data.alg) + err := method.Verify(strings.Join(parts[0:2], "."), parts[2], data.key) + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying key: %v", data.name, err) + } + if !data.valid && err == nil { + t.Errorf("[%v] Invalid key passed validation", data.name) + } + } +} + +func TestNoneSign(t *testing.T) { + for _, data := range noneTestData { + if data.valid { + parts := strings.Split(data.tokenString, ".") + method := jwt.GetSigningMethod(data.alg) + sig, err := method.Sign(strings.Join(parts[0:2], "."), data.key) + if err != nil { + t.Errorf("[%v] Error signing token: %v", data.name, err) + } + if sig != parts[2] { + t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2]) + } + } + } +} diff --git a/vendor/github.com/dgrijalva/jwt-go/parser_test.go b/vendor/github.com/dgrijalva/jwt-go/parser_test.go new file mode 100644 index 000000000..390779785 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/parser_test.go @@ -0,0 +1,301 @@ +package jwt_test + +import ( + "crypto/rsa" + "encoding/json" + "fmt" + "reflect" + "testing" + "time" + + "github.com/dgrijalva/jwt-go" + "github.com/dgrijalva/jwt-go/test" +) + +var keyFuncError error = fmt.Errorf("error loading key") + +var ( + jwtTestDefaultKey *rsa.PublicKey + defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil } + emptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil } + errorKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, keyFuncError } + nilKeyFunc jwt.Keyfunc = nil +) + +func init() { + jwtTestDefaultKey = test.LoadRSAPublicKeyFromDisk("test/sample_key.pub") +} + +var jwtTestData = []struct { + name string + tokenString string + keyfunc jwt.Keyfunc + claims jwt.Claims + valid bool + errors uint32 + parser *jwt.Parser +}{ + { + "basic", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + defaultKeyFunc, + jwt.MapClaims{"foo": "bar"}, + true, + 0, + nil, + }, + { + "basic expired", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "exp": float64(time.Now().Unix() - 100)}, + false, + jwt.ValidationErrorExpired, + nil, + }, + { + "basic nbf", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100)}, + false, + jwt.ValidationErrorNotValidYet, + nil, + }, + { + "expired and nbf", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "nbf": float64(time.Now().Unix() + 100), "exp": float64(time.Now().Unix() - 100)}, + false, + jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired, + nil, + }, + { + "basic invalid", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + defaultKeyFunc, + jwt.MapClaims{"foo": "bar"}, + false, + jwt.ValidationErrorSignatureInvalid, + nil, + }, + { + "basic nokeyfunc", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + nilKeyFunc, + jwt.MapClaims{"foo": "bar"}, + false, + jwt.ValidationErrorUnverifiable, + nil, + }, + { + "basic nokey", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + emptyKeyFunc, + jwt.MapClaims{"foo": "bar"}, + false, + jwt.ValidationErrorSignatureInvalid, + nil, + }, + { + "basic errorkey", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + errorKeyFunc, + jwt.MapClaims{"foo": "bar"}, + false, + jwt.ValidationErrorUnverifiable, + nil, + }, + { + "invalid signing method", + "", + defaultKeyFunc, + jwt.MapClaims{"foo": "bar"}, + false, + jwt.ValidationErrorSignatureInvalid, + &jwt.Parser{ValidMethods: []string{"HS256"}}, + }, + { + "valid signing method", + "", + defaultKeyFunc, + jwt.MapClaims{"foo": "bar"}, + true, + 0, + &jwt.Parser{ValidMethods: []string{"RS256", "HS256"}}, + }, + { + "JSON Number", + "", + defaultKeyFunc, + jwt.MapClaims{"foo": json.Number("123.4")}, + true, + 0, + &jwt.Parser{UseJSONNumber: true}, + }, + { + "Standard Claims", + "", + defaultKeyFunc, + &jwt.StandardClaims{ + ExpiresAt: time.Now().Add(time.Second * 10).Unix(), + }, + true, + 0, + &jwt.Parser{UseJSONNumber: true}, + }, + { + "JSON Number - basic expired", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))}, + false, + jwt.ValidationErrorExpired, + &jwt.Parser{UseJSONNumber: true}, + }, + { + "JSON Number - basic nbf", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))}, + false, + jwt.ValidationErrorNotValidYet, + &jwt.Parser{UseJSONNumber: true}, + }, + { + "JSON Number - expired and nbf", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100)), "exp": json.Number(fmt.Sprintf("%v", time.Now().Unix()-100))}, + false, + jwt.ValidationErrorNotValidYet | jwt.ValidationErrorExpired, + &jwt.Parser{UseJSONNumber: true}, + }, + { + "SkipClaimsValidation during token parsing", + "", // autogen + defaultKeyFunc, + jwt.MapClaims{"foo": "bar", "nbf": json.Number(fmt.Sprintf("%v", time.Now().Unix()+100))}, + true, + 0, + &jwt.Parser{UseJSONNumber: true, SkipClaimsValidation: true}, + }, +} + +func TestParser_Parse(t *testing.T) { + privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key") + + // Iterate over test data set and run tests + for _, data := range jwtTestData { + // If the token string is blank, use helper function to generate string + if data.tokenString == "" { + data.tokenString = test.MakeSampleToken(data.claims, privateKey) + } + + // Parse the token + var token *jwt.Token + var err error + var parser = data.parser + if parser == nil { + parser = new(jwt.Parser) + } + // Figure out correct claims type + switch data.claims.(type) { + case jwt.MapClaims: + token, err = parser.ParseWithClaims(data.tokenString, jwt.MapClaims{}, data.keyfunc) + case *jwt.StandardClaims: + token, err = parser.ParseWithClaims(data.tokenString, &jwt.StandardClaims{}, data.keyfunc) + } + + // Verify result matches expectation + if !reflect.DeepEqual(data.claims, token.Claims) { + t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims) + } + + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err) + } + + if !data.valid && err == nil { + t.Errorf("[%v] Invalid token passed validation", data.name) + } + + if (err == nil && !token.Valid) || (err != nil && token.Valid) { + t.Errorf("[%v] Inconsistent behavior between returned error and token.Valid", data.name) + } + + if data.errors != 0 { + if err == nil { + t.Errorf("[%v] Expecting error. Didn't get one.", data.name) + } else { + + ve := err.(*jwt.ValidationError) + // compare the bitfield part of the error + if e := ve.Errors; e != data.errors { + t.Errorf("[%v] Errors don't match expectation. %v != %v", data.name, e, data.errors) + } + + if err.Error() == keyFuncError.Error() && ve.Inner != keyFuncError { + t.Errorf("[%v] Inner error does not match expectation. %v != %v", data.name, ve.Inner, keyFuncError) + } + } + } + if data.valid && token.Signature == "" { + t.Errorf("[%v] Signature is left unpopulated after parsing", data.name) + } + } +} + +func TestParser_ParseUnverified(t *testing.T) { + privateKey := test.LoadRSAPrivateKeyFromDisk("test/sample_key") + + // Iterate over test data set and run tests + for _, data := range jwtTestData { + // If the token string is blank, use helper function to generate string + if data.tokenString == "" { + data.tokenString = test.MakeSampleToken(data.claims, privateKey) + } + + // Parse the token + var token *jwt.Token + var err error + var parser = data.parser + if parser == nil { + parser = new(jwt.Parser) + } + // Figure out correct claims type + switch data.claims.(type) { + case jwt.MapClaims: + token, _, err = parser.ParseUnverified(data.tokenString, jwt.MapClaims{}) + case *jwt.StandardClaims: + token, _, err = parser.ParseUnverified(data.tokenString, &jwt.StandardClaims{}) + } + + if err != nil { + t.Errorf("[%v] Invalid token", data.name) + } + + // Verify result matches expectation + if !reflect.DeepEqual(data.claims, token.Claims) { + t.Errorf("[%v] Claims mismatch. Expecting: %v Got: %v", data.name, data.claims, token.Claims) + } + + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying token: %T:%v", data.name, err, err) + } + } +} + +// Helper method for benchmarking various methods +func benchmarkSigning(b *testing.B, method jwt.SigningMethod, key interface{}) { + t := jwt.New(method) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + if _, err := t.SignedString(key); err != nil { + b.Fatal(err) + } + } + }) + +} diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go b/vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go new file mode 100644 index 000000000..9045aaf34 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/rsa_pss_test.go @@ -0,0 +1,96 @@ +// +build go1.4 + +package jwt_test + +import ( + "crypto/rsa" + "io/ioutil" + "strings" + "testing" + + "github.com/dgrijalva/jwt-go" +) + +var rsaPSSTestData = []struct { + name string + tokenString string + alg string + claims map[string]interface{} + valid bool +}{ + { + "Basic PS256", + "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9w", + "PS256", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic PS384", + "eyJhbGciOiJQUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.w7-qqgj97gK4fJsq_DCqdYQiylJjzWONvD0qWWWhqEOFk2P1eDULPnqHRnjgTXoO4HAw4YIWCsZPet7nR3Xxq4ZhMqvKW8b7KlfRTb9cH8zqFvzMmybQ4jv2hKc3bXYqVow3AoR7hN_CWXI3Dv6Kd2X5xhtxRHI6IL39oTVDUQ74LACe-9t4c3QRPuj6Pq1H4FAT2E2kW_0KOc6EQhCLWEhm2Z2__OZskDC8AiPpP8Kv4k2vB7l0IKQu8Pr4RcNBlqJdq8dA5D3hk5TLxP8V5nG1Ib80MOMMqoS3FQvSLyolFX-R_jZ3-zfq6Ebsqr0yEb0AH2CfsECF7935Pa0FKQ", + "PS384", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic PS512", + "eyJhbGciOiJQUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.GX1HWGzFaJevuSLavqqFYaW8_TpvcjQ8KfC5fXiSDzSiT9UD9nB_ikSmDNyDILNdtjZLSvVKfXxZJqCfefxAtiozEDDdJthZ-F0uO4SPFHlGiXszvKeodh7BuTWRI2wL9-ZO4mFa8nq3GMeQAfo9cx11i7nfN8n2YNQ9SHGovG7_T_AvaMZB_jT6jkDHpwGR9mz7x1sycckEo6teLdHRnH_ZdlHlxqknmyTu8Odr5Xh0sJFOL8BepWbbvIIn-P161rRHHiDWFv6nhlHwZnVzjx7HQrWSGb6-s2cdLie9QL_8XaMcUpjLkfOMKkDOfHo6AvpL7Jbwi83Z2ZTHjJWB-A", + "PS512", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "basic PS256 invalid: foo => bar", + "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9W", + "PS256", + map[string]interface{}{"foo": "bar"}, + false, + }, +} + +func TestRSAPSSVerify(t *testing.T) { + var err error + + key, _ := ioutil.ReadFile("test/sample_key.pub") + var rsaPSSKey *rsa.PublicKey + if rsaPSSKey, err = jwt.ParseRSAPublicKeyFromPEM(key); err != nil { + t.Errorf("Unable to parse RSA public key: %v", err) + } + + for _, data := range rsaPSSTestData { + parts := strings.Split(data.tokenString, ".") + + method := jwt.GetSigningMethod(data.alg) + err := method.Verify(strings.Join(parts[0:2], "."), parts[2], rsaPSSKey) + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying key: %v", data.name, err) + } + if !data.valid && err == nil { + t.Errorf("[%v] Invalid key passed validation", data.name) + } + } +} + +func TestRSAPSSSign(t *testing.T) { + var err error + + key, _ := ioutil.ReadFile("test/sample_key") + var rsaPSSKey *rsa.PrivateKey + if rsaPSSKey, err = jwt.ParseRSAPrivateKeyFromPEM(key); err != nil { + t.Errorf("Unable to parse RSA private key: %v", err) + } + + for _, data := range rsaPSSTestData { + if data.valid { + parts := strings.Split(data.tokenString, ".") + method := jwt.GetSigningMethod(data.alg) + sig, err := method.Sign(strings.Join(parts[0:2], "."), rsaPSSKey) + if err != nil { + t.Errorf("[%v] Error signing token: %v", data.name, err) + } + if sig == parts[2] { + t.Errorf("[%v] Signatures shouldn't match\nnew:\n%v\noriginal:\n%v", data.name, sig, parts[2]) + } + } + } +} diff --git a/vendor/github.com/dgrijalva/jwt-go/rsa_test.go b/vendor/github.com/dgrijalva/jwt-go/rsa_test.go new file mode 100644 index 000000000..7f67c5db1 --- /dev/null +++ b/vendor/github.com/dgrijalva/jwt-go/rsa_test.go @@ -0,0 +1,185 @@ +package jwt_test + +import ( + "github.com/dgrijalva/jwt-go" + "io/ioutil" + "strings" + "testing" +) + +var rsaTestData = []struct { + name string + tokenString string + alg string + claims map[string]interface{} + valid bool +}{ + { + "Basic RS256", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + "RS256", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic RS384", + "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.W-jEzRfBigtCWsinvVVuldiuilzVdU5ty0MvpLaSaqK9PlAWWlDQ1VIQ_qSKzwL5IXaZkvZFJXT3yL3n7OUVu7zCNJzdwznbC8Z-b0z2lYvcklJYi2VOFRcGbJtXUqgjk2oGsiqUMUMOLP70TTefkpsgqDxbRh9CDUfpOJgW-dU7cmgaoswe3wjUAUi6B6G2YEaiuXC0XScQYSYVKIzgKXJV8Zw-7AN_DBUI4GkTpsvQ9fVVjZM9csQiEXhYekyrKu1nu_POpQonGd8yqkIyXPECNmmqH5jH4sFiF67XhD7_JpkvLziBpI-uh86evBUadmHhb9Otqw3uV3NTaXLzJw", + "RS384", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "Basic RS512", + "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.zBlLlmRrUxx4SJPUbV37Q1joRcI9EW13grnKduK3wtYKmDXbgDpF1cZ6B-2Jsm5RB8REmMiLpGms-EjXhgnyh2TSHE-9W2gA_jvshegLWtwRVDX40ODSkTb7OVuaWgiy9y7llvcknFBTIg-FnVPVpXMmeV_pvwQyhaz1SSwSPrDyxEmksz1hq7YONXhXPpGaNbMMeDTNP_1oj8DZaqTIL9TwV8_1wb2Odt_Fy58Ke2RVFijsOLdnyEAjt2n9Mxihu9i3PhNBkkxa2GbnXBfq3kzvZ_xxGGopLdHhJjcGWXO-NiwI9_tiu14NRv4L2xC0ItD9Yz68v2ZIZEp_DuzwRQ", + "RS512", + map[string]interface{}{"foo": "bar"}, + true, + }, + { + "basic invalid: foo => bar", + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.EhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg", + "RS256", + map[string]interface{}{"foo": "bar"}, + false, + }, +} + +func TestRSAVerify(t *testing.T) { + keyData, _ := ioutil.ReadFile("test/sample_key.pub") + key, _ := jwt.ParseRSAPublicKeyFromPEM(keyData) + + for _, data := range rsaTestData { + parts := strings.Split(data.tokenString, ".") + + method := jwt.GetSigningMethod(data.alg) + err := method.Verify(strings.Join(parts[0:2], "."), parts[2], key) + if data.valid && err != nil { + t.Errorf("[%v] Error while verifying key: %v", data.name, err) + } + if !data.valid && err == nil { + t.Errorf("[%v] Invalid key passed validation", data.name) + } + } +} + +func TestRSASign(t *testing.T) { + keyData, _ := ioutil.ReadFile("test/sample_key") + key, _ := jwt.ParseRSAPrivateKeyFromPEM(keyData) + + for _, data := range rsaTestData { + if data.valid { + parts := strings.Split(data.tokenString, ".") + method := jwt.GetSigningMethod(data.alg) + sig, err := method.Sign(strings.Join(parts[0:2], "."), key) + if err != nil { + t.Errorf("[%v] Error signing token: %v", data.name, err) + } + if sig != parts[2] { + t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", data.name, sig, parts[2]) + } + } + } +} + +func TestRSAVerifyWithPreParsedPrivateKey(t *testing.T) { + key, _ := ioutil.ReadFile("test/sample_key.pub") + parsedKey, err := jwt.ParseRSAPublicKeyFromPEM(key) + if err != nil { + t.Fatal(err) + } + testData := rsaTestData[0] + parts := strings.Split(testData.tokenString, ".") + err = jwt.SigningMethodRS256.Verify(strings.Join(parts[0:2], "."), parts[2], parsedKey) + if err != nil { + t.Errorf("[%v] Error while verifying key: %v", testData.name, err) + } +} + +func TestRSAWithPreParsedPrivateKey(t *testing.T) { + key, _ := ioutil.ReadFile("test/sample_key") + parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key) + if err != nil { + t.Fatal(err) + } + testData := rsaTestData[0] + parts := strings.Split(testData.tokenString, ".") + sig, err := jwt.SigningMethodRS256.Sign(strings.Join(parts[0:2], "."), parsedKey) + if err != nil { + t.Errorf("[%v] Error signing token: %v", testData.name, err) + } + if sig != parts[2] { + t.Errorf("[%v] Incorrect signature.\nwas:\n%v\nexpecting:\n%v", testData.name, sig, parts[2]) + } +} + +func TestRSAKeyParsing(t *testing.T) { + key, _ := ioutil.ReadFile("test/sample_key") + secureKey, _ := ioutil.ReadFile("test/privateSecure.pem") + pubKey, _ := ioutil.ReadFile("test/sample_key.pub") + badKey := []byte("All your base are belong to key") + + // Test parsePrivateKey + if _, e := jwt.ParseRSAPrivateKeyFromPEM(key); e != nil { + t.Errorf("Failed to parse valid private key: %v", e) + } + + if k, e := jwt.ParseRSAPrivateKeyFromPEM(pubKey); e == nil { + t.Errorf("Parsed public key as valid private key: %v", k) + } + + if k, e := jwt.ParseRSAPrivateKeyFromPEM(badKey); e == nil { + t.Errorf("Parsed invalid key as valid private key: %v", k) + } + + if _, e := jwt.ParseRSAPrivateKeyFromPEMWithPassword(secureKey, "password"); e != nil { + t.Errorf("Failed to parse valid private key with password: %v", e) + } + + if k, e := jwt.ParseRSAPrivateKeyFromPEMWithPassword(secureKey, "123132"); e == nil { + t.Errorf("Parsed private key with invalid password %v", k) + } + + // Test parsePublicKey + if _, e := jwt.ParseRSAPublicKeyFromPEM(pubKey); e != nil { + t.Errorf("Failed to parse valid public key: %v", e) + } + + if k, e := jwt.ParseRSAPublicKeyFromPEM(key); e == nil { + t.Errorf("Parsed private key as valid public key: %v", k) + } + + if k, e := jwt.ParseRSAPublicKeyFromPEM(badKey); e == nil { + t.Errorf("Parsed invalid key as valid private key: %v", k) + } + +} + +func BenchmarkRS256Signing(b *testing.B) { + key, _ := ioutil.ReadFile("test/sample_key") + parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key) + if err != nil { + b.Fatal(err) + } + + benchmarkSigning(b, jwt.SigningMethodRS256, parsedKey) +} + +func BenchmarkRS384Signing(b *testing.B) { + key, _ := ioutil.ReadFile("test/sample_key") + parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key) + if err != nil { + b.Fatal(err) + } + + benchmarkSigning(b, jwt.SigningMethodRS384, parsedKey) +} + +func BenchmarkRS512Signing(b *testing.B) { + key, _ := ioutil.ReadFile("test/sample_key") + parsedKey, err := jwt.ParseRSAPrivateKeyFromPEM(key) + if err != nil { + b.Fatal(err) + } + + benchmarkSigning(b, jwt.SigningMethodRS512, parsedKey) +} diff --git a/vendor/github.com/docker/docker/.dockerignore b/vendor/github.com/docker/docker/.dockerignore new file mode 100644 index 000000000..082cac922 --- /dev/null +++ b/vendor/github.com/docker/docker/.dockerignore @@ -0,0 +1,4 @@ +bundles +.gopath +vendor/pkg +.go-pkg-cache diff --git a/vendor/github.com/docker/docker/.gitignore b/vendor/github.com/docker/docker/.gitignore new file mode 100644 index 000000000..be8b03d17 --- /dev/null +++ b/vendor/github.com/docker/docker/.gitignore @@ -0,0 +1,33 @@ +# Docker project generated files to ignore +# if you want to ignore files created by your editor/tools, +# please consider a global .gitignore https://help.github.com/articles/ignoring-files +*.exe +*.exe~ +*.orig +*.test +.*.swp +.DS_Store +# a .bashrc may be added to customize the build environment +.bashrc +.editorconfig +.gopath/ +.go-pkg-cache/ +autogen/ +bundles/ +cmd/dockerd/dockerd +cmd/docker/docker +dockerversion/version_autogen.go +dockerversion/version_autogen_unix.go +docs/AWS_S3_BUCKET +docs/GITCOMMIT +docs/GIT_BRANCH +docs/VERSION +docs/_build +docs/_static +docs/_templates +docs/changed-files +# generated by man/md2man-all.sh +man/man1 +man/man5 +man/man8 +vendor/pkg/ diff --git a/vendor/github.com/docker/docker/.mailmap b/vendor/github.com/docker/docker/.mailmap new file mode 100644 index 000000000..fe99e2086 --- /dev/null +++ b/vendor/github.com/docker/docker/.mailmap @@ -0,0 +1,275 @@ +# Generate AUTHORS: hack/generate-authors.sh + +# Tip for finding duplicates (besides scanning the output of AUTHORS for name +# duplicates that aren't also email duplicates): scan the output of: +# git log --format='%aE - %aN' | sort -uf +# +# For explanation on this file format: man git-shortlog + +Patrick Stapleton +Shishir Mahajan +Erwin van der Koogh +Ahmed Kamal +Tejesh Mehta +Cristian Staretu +Cristian Staretu +Cristian Staretu +Marcus Linke +Aleksandrs Fadins +Christopher Latham +Hu Keping +Wayne Chang +Chen Chao +Daehyeok Mun + + + + + + +Guillaume J. Charmes + + + + + +Thatcher Peskens +Thatcher Peskens +Thatcher Peskens dhrp +Jérôme Petazzoni jpetazzo +Jérôme Petazzoni +Joffrey F +Joffrey F +Joffrey F +Tim Terhorst +Andy Smith + + + + + + + + + +Walter Stanish + +Roberto Hashioka +Konstantin Pelykh +David Sissitka +Nolan Darilek + +Benoit Chesneau +Jordan Arentsen +Daniel Garcia +Miguel Angel Fernández +Bhiraj Butala +Faiz Khan +Victor Lyuboslavsky +Jean-Baptiste Barth +Matthew Mueller + +Shih-Yuan Lee +Daniel Mizyrycki root +Jean-Baptiste Dalido + + + + + + + + + + + + + + +Sven Dowideit +Sven Dowideit +Sven Dowideit +Sven Dowideit <¨SvenDowideit@home.org.au¨> +Sven Dowideit +Sven Dowideit +Sven Dowideit + +Alexander Morozov +Alexander Morozov + +O.S. Tezer + +Roberto G. Hashioka + + + + + +Sridhar Ratnakumar +Sridhar Ratnakumar +Liang-Chi Hsieh +Aleksa Sarai +Aleksa Sarai +Aleksa Sarai +Will Weaver +Timothy Hobbs +Nathan LeClaire +Nathan LeClaire + + + + +Matthew Heon + + + + +Francisco Carriedo + + + + +Brian Goff + + + +Hollie Teal + + + +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle + + + + +Thomas LEVEIL Thomas LÉVEIL + + +Antonio Murdaca +Antonio Murdaca +Antonio Murdaca +Antonio Murdaca +Antonio Murdaca +Darren Shepherd +Deshi Xiao +Deshi Xiao +Doug Davis +Jacob Atzen +Jeff Nickoloff +John Howard (VM) +John Howard (VM) +John Howard (VM) +John Howard (VM) +Madhu Venugopal +Mary Anthony +Mary Anthony moxiegirl +Mary Anthony +mattyw +resouer +AJ Bowen soulshake +AJ Bowen soulshake +Tibor Vass +Tibor Vass +Vincent Bernat +Yestin Sun +bin liu +John Howard (VM) jhowardmsft +Ankush Agarwal +Tangi COLIN tangicolin +Allen Sun +Adrien Gallouët + +Anuj Bahuguna +Anusha Ragunathan +Avi Miller +Brent Salisbury +Chander G +Chun Chen +Ying Li +Daehyeok Mun + +Daniel, Dao Quang Minh +Daniel Nephin +Dave Tucker +Doug Tangren +Frederick F. Kautz IV +Ben Golub +Harold Cooper +hsinko <21551195@zju.edu.cn> +Josh Hawn +Justin Cormack + + +Kamil Domański +Lei Jitang + +Linus Heckemann + +Lynda O'Leary + +Marianna Tessel +Michael Huettermann +Moysés Borges + +Nigel Poulton +Qiang Huang + +Boaz Shuster +Shuwei Hao + +Soshi Katsuta + +Stefan Berger + +Stephen Day + +Toli Kuznets +Tristan Carel + +Vincent Demeester + +Vishnu Kannan +xlgao-zju xlgao +yuchangchun y00277921 + + + + +Hao Shu Wei + + + + + + + +Shengbo Song mYmNeo +Shengbo Song + +Sylvain Bellemare + + + +Arnaud Porterie + +David M. Karr + + + +Kenfe-Mickaël Laventure + + + + + +Runshen Zhu +Tom Barlow +Xianlu Bird +Dan Feldman +Harry Zhang diff --git a/vendor/github.com/docker/docker/CHANGELOG.md b/vendor/github.com/docker/docker/CHANGELOG.md new file mode 100644 index 000000000..36bb88063 --- /dev/null +++ b/vendor/github.com/docker/docker/CHANGELOG.md @@ -0,0 +1,3337 @@ +# Changelog + +Items starting with `DEPRECATE` are important deprecation notices. For more +information on the list of deprecated flags and APIs please have a look at +https://docs.docker.com/engine/deprecated/ where target removal dates can also +be found. + +## 1.13.1 (2017-02-08) + +**IMPORTANT**: On Linux distributions where `devicemapper` was the default storage driver, +the `overlay2`, or `overlay` is now used by default (if the kernel supports it). +To use devicemapper, you can manually configure the storage driver to use through +the `--storage-driver` daemon option, or by setting "storage-driver" in the `daemon.json` +configuration file. + +**IMPORTANT**: In Docker 1.13, the managed plugin api changed, as compared to the experimental +version introduced in Docker 1.12. You must **uninstall** plugins which you installed with Docker 1.12 +_before_ upgrading to Docker 1.13. You can uninstall plugins using the `docker plugin rm` command. + +If you have already upgraded to Docker 1.13 without uninstalling +previously-installed plugins, you may see this message when the Docker daemon +starts: + + Error starting daemon: json: cannot unmarshal string into Go value of type types.PluginEnv + +To manually remove all plugins and resolve this problem, take the following steps: + +1. Remove plugins.json from: `/var/lib/docker/plugins/`. +2. Restart Docker. Verify that the Docker daemon starts with no errors. +3. Reinstall your plugins. + +### Contrib + +* Do not require a custom build of tini [#28454](https://github.com/docker/docker/pull/28454) +* Upgrade to Go 1.7.5 [#30489](https://github.com/docker/docker/pull/30489) + +### Remote API (v1.26) & Client + ++ Support secrets in docker stack deploy with compose file [#30144](https://github.com/docker/docker/pull/30144) + +### Runtime + +* Fix size issue in `docker system df` [#30378](https://github.com/docker/docker/pull/30378) +* Fix error on `docker inspect` when Swarm certificates were expired. [#29246](https://github.com/docker/docker/pull/29246) +* Fix deadlock on v1 plugin with activate error [#30408](https://github.com/docker/docker/pull/30408) +* Fix SELinux regression [#30649](https://github.com/docker/docker/pull/30649) + +### Plugins + +* Support global scoped network plugins (v2) in swarm mode [#30332](https://github.com/docker/docker/pull/30332) ++ Add `docker plugin upgrade` [#29414](https://github.com/docker/docker/pull/29414) + +### Windows + +* Fix small regression with old plugins in Windows [#30150](https://github.com/docker/docker/pull/30150) +* Fix warning on Windows [#30730](https://github.com/docker/docker/pull/30730) + +## 1.13.0 (2017-01-18) + +**IMPORTANT**: On Linux distributions where `devicemapper` was the default storage driver, +the `overlay2`, or `overlay` is now used by default (if the kernel supports it). +To use devicemapper, you can manually configure the storage driver to use through +the `--storage-driver` daemon option, or by setting "storage-driver" in the `daemon.json` +configuration file. + +**IMPORTANT**: In Docker 1.13, the managed plugin api changed, as compared to the experimental +version introduced in Docker 1.12. You must **uninstall** plugins which you installed with Docker 1.12 +_before_ upgrading to Docker 1.13. You can uninstall plugins using the `docker plugin rm` command. + +If you have already upgraded to Docker 1.13 without uninstalling +previously-installed plugins, you may see this message when the Docker daemon +starts: + + Error starting daemon: json: cannot unmarshal string into Go value of type types.PluginEnv + +To manually remove all plugins and resolve this problem, take the following steps: + +1. Remove plugins.json from: `/var/lib/docker/plugins/`. +2. Restart Docker. Verify that the Docker daemon starts with no errors. +3. Reinstall your plugins. + +### Builder + ++ Add capability to specify images used as a cache source on build. These images do not need to have local parent chain and can be pulled from other registries [#26839](https://github.com/docker/docker/pull/26839) ++ (experimental) Add option to squash image layers to the FROM image after successful builds [#22641](https://github.com/docker/docker/pull/22641) +* Fix dockerfile parser with empty line after escape [#24725](https://github.com/docker/docker/pull/24725) +- Add step number on `docker build` [#24978](https://github.com/docker/docker/pull/24978) ++ Add support for compressing build context during image build [#25837](https://github.com/docker/docker/pull/25837) ++ add `--network` to `docker build` [#27702](https://github.com/docker/docker/pull/27702) +- Fix inconsistent behavior between `--label` flag on `docker build` and `docker run` [#26027](https://github.com/docker/docker/issues/26027) +- Fix image layer inconsistencies when using the overlay storage driver [#27209](https://github.com/docker/docker/pull/27209) +* Unused build-args are now allowed. A warning is presented instead of an error and failed build [#27412](https://github.com/docker/docker/pull/27412) +- Fix builder cache issue on Windows [#27805](https://github.com/docker/docker/pull/27805) ++ Allow `USER` in builder on Windows [#28415](https://github.com/docker/docker/pull/28415) ++ Handle env case-insensitive on Windows [#28725](https://github.com/docker/docker/pull/28725) + +### Contrib + ++ Add support for building docker debs for Ubuntu 16.04 Xenial on PPC64LE [#23438](https://github.com/docker/docker/pull/23438) ++ Add support for building docker debs for Ubuntu 16.04 Xenial on s390x [#26104](https://github.com/docker/docker/pull/26104) ++ Add support for building docker debs for Ubuntu 16.10 Yakkety Yak on PPC64LE [#28046](https://github.com/docker/docker/pull/28046) +- Add RPM builder for VMWare Photon OS [#24116](https://github.com/docker/docker/pull/24116) ++ Add shell completions to tgz [#27735](https://github.com/docker/docker/pull/27735) +* Update the install script to allow using the mirror in China [#27005](https://github.com/docker/docker/pull/27005) ++ Add DEB builder for Ubuntu 16.10 Yakkety Yak [#27993](https://github.com/docker/docker/pull/27993) ++ Add RPM builder for Fedora 25 [#28222](https://github.com/docker/docker/pull/28222) ++ Add `make deb` support for aarch64 [#27625](https://github.com/docker/docker/pull/27625) + +### Distribution + +* Update notary dependency to 0.4.2 (full changelogs [here](https://github.com/docker/notary/releases/tag/v0.4.2)) [#27074](https://github.com/docker/docker/pull/27074) + - Support for compilation on windows [docker/notary#970](https://github.com/docker/notary/pull/970) + - Improved error messages for client authentication errors [docker/notary#972](https://github.com/docker/notary/pull/972) + - Support for finding keys that are anywhere in the `~/.docker/trust/private` directory, not just under `~/.docker/trust/private/root_keys` or `~/.docker/trust/private/tuf_keys` [docker/notary#981](https://github.com/docker/notary/pull/981) + - Previously, on any error updating, the client would fall back on the cache. Now we only do so if there is a network error or if the server is unavailable or missing the TUF data. Invalid TUF data will cause the update to fail - for example if there was an invalid root rotation. [docker/notary#982](https://github.com/docker/notary/pull/982) + - Improve root validation and yubikey debug logging [docker/notary#858](https://github.com/docker/notary/pull/858) [docker/notary#891](https://github.com/docker/notary/pull/891) + - Warn if certificates for root or delegations are near expiry [docker/notary#802](https://github.com/docker/notary/pull/802) + - Warn if role metadata is near expiry [docker/notary#786](https://github.com/docker/notary/pull/786) + - Fix passphrase retrieval attempt counting and terminal detection [docker/notary#906](https://github.com/docker/notary/pull/906) +- Avoid unnecessary blob uploads when different users push same layers to authenticated registry [#26564](https://github.com/docker/docker/pull/26564) +* Allow external storage for registry credentials [#26354](https://github.com/docker/docker/pull/26354) + +### Logging + +* Standardize the default logging tag value in all logging drivers [#22911](https://github.com/docker/docker/pull/22911) +- Improve performance and memory use when logging of long log lines [#22982](https://github.com/docker/docker/pull/22982) ++ Enable syslog driver for windows [#25736](https://github.com/docker/docker/pull/25736) ++ Add Logentries Driver [#27471](https://github.com/docker/docker/pull/27471) ++ Update of AWS log driver to support tags [#27707](https://github.com/docker/docker/pull/27707) ++ Unix socket support for fluentd [#26088](https://github.com/docker/docker/pull/26088) +* Enable fluentd logging driver on Windows [#28189](https://github.com/docker/docker/pull/28189) +- Sanitize docker labels when used as journald field names [#23725](https://github.com/docker/docker/pull/23725) +- Fix an issue where `docker logs --tail` returned less lines than expected [#28203](https://github.com/docker/docker/pull/28203) +- Splunk Logging Driver: performance and reliability improvements [#26207](https://github.com/docker/docker/pull/26207) +- Splunk Logging Driver: configurable formats and skip for verifying connection [#25786](https://github.com/docker/docker/pull/25786) + +### Networking + ++ Add `--attachable` network support to enable `docker run` to work in swarm-mode overlay network [#25962](https://github.com/docker/docker/pull/25962) ++ Add support for host port PublishMode in services using the `--publish` option in `docker service create` [#27917](https://github.com/docker/docker/pull/27917) and [#28943](https://github.com/docker/docker/pull/28943) ++ Add support for Windows server 2016 overlay network driver (requires upcoming ws2016 update) [#28182](https://github.com/docker/docker/pull/28182) +* Change the default `FORWARD` policy to `DROP` [#28257](https://github.com/docker/docker/pull/28257) ++ Add support for specifying static IP addresses for predefined network on windows [#22208](https://github.com/docker/docker/pull/22208) +- Fix `--publish` flag on `docker run` not working with IPv6 addresses [#27860](https://github.com/docker/docker/pull/27860) +- Fix inspect network show gateway with mask [#25564](https://github.com/docker/docker/pull/25564) +- Fix an issue where multiple addresses in a bridge may cause `--fixed-cidr` to not have the correct addresses [#26659](https://github.com/docker/docker/pull/26659) ++ Add creation timestamp to `docker network inspect` [#26130](https://github.com/docker/docker/pull/26130) +- Show peer nodes in `docker network inspect` for swarm overlay networks [#28078](https://github.com/docker/docker/pull/28078) +- Enable ping for service VIP address [#28019](https://github.com/docker/docker/pull/28019) + +### Plugins + +- Move plugins out of experimental [#28226](https://github.com/docker/docker/pull/28226) +- Add `--force` on `docker plugin remove` [#25096](https://github.com/docker/docker/pull/25096) +* Add support for dynamically reloading authorization plugins [#22770](https://github.com/docker/docker/pull/22770) ++ Add description in `docker plugin ls` [#25556](https://github.com/docker/docker/pull/25556) ++ Add `-f`/`--format` to `docker plugin inspect` [#25990](https://github.com/docker/docker/pull/25990) ++ Add `docker plugin create` command [#28164](https://github.com/docker/docker/pull/28164) +* Send request's TLS peer certificates to authorization plugins [#27383](https://github.com/docker/docker/pull/27383) +* Support for global-scoped network and ipam plugins in swarm-mode [#27287](https://github.com/docker/docker/pull/27287) +* Split `docker plugin install` into two API call `/privileges` and `/pull` [#28963](https://github.com/docker/docker/pull/28963) + +### Remote API (v1.25) & Client + ++ Support `docker stack deploy` from a Compose file [#27998](https://github.com/docker/docker/pull/27998) ++ (experimental) Implement checkpoint and restore [#22049](https://github.com/docker/docker/pull/22049) ++ Add `--format` flag to `docker info` [#23808](https://github.com/docker/docker/pull/23808) +* Remove `--name` from `docker volume create` [#23830](https://github.com/docker/docker/pull/23830) ++ Add `docker stack ls` [#23886](https://github.com/docker/docker/pull/23886) ++ Add a new `is-task` ps filter [#24411](https://github.com/docker/docker/pull/24411) ++ Add `--env-file` flag to `docker service create` [#24844](https://github.com/docker/docker/pull/24844) ++ Add `--format` on `docker stats` [#24987](https://github.com/docker/docker/pull/24987) ++ Make `docker node ps` default to `self` in swarm node [#25214](https://github.com/docker/docker/pull/25214) ++ Add `--group` in `docker service create` [#25317](https://github.com/docker/docker/pull/25317) ++ Add `--no-trunc` to service/node/stack ps output [#25337](https://github.com/docker/docker/pull/25337) ++ Add Logs to `ContainerAttachOptions` so go clients can request to retrieve container logs as part of the attach process [#26718](https://github.com/docker/docker/pull/26718) ++ Allow client to talk to an older server [#27745](https://github.com/docker/docker/pull/27745) +* Inform user client-side that a container removal is in progress [#26074](https://github.com/docker/docker/pull/26074) ++ Add `Isolation` to the /info endpoint [#26255](https://github.com/docker/docker/pull/26255) ++ Add `userns` to the /info endpoint [#27840](https://github.com/docker/docker/pull/27840) +- Do not allow more than one mode be requested at once in the services endpoint [#26643](https://github.com/docker/docker/pull/26643) ++ Add capability to /containers/create API to specify mounts in a more granular and safer way [#22373](https://github.com/docker/docker/pull/22373) ++ Add `--format` flag to `network ls` and `volume ls` [#23475](https://github.com/docker/docker/pull/23475) +* Allow the top-level `docker inspect` command to inspect any kind of resource [#23614](https://github.com/docker/docker/pull/23614) ++ Add --cpus flag to control cpu resources for `docker run` and `docker create`, and add `NanoCPUs` to `HostConfig` [#27958](https://github.com/docker/docker/pull/27958) +- Allow unsetting the `--entrypoint` in `docker run` or `docker create` [#23718](https://github.com/docker/docker/pull/23718) +* Restructure CLI commands by adding `docker image` and `docker container` commands for more consistency [#26025](https://github.com/docker/docker/pull/26025) +- Remove `COMMAND` column from `service ls` output [#28029](https://github.com/docker/docker/pull/28029) ++ Add `--format` to `docker events` [#26268](https://github.com/docker/docker/pull/26268) +* Allow specifying multiple nodes on `docker node ps` [#26299](https://github.com/docker/docker/pull/26299) +* Restrict fractional digits to 2 decimals in `docker images` output [#26303](https://github.com/docker/docker/pull/26303) ++ Add `--dns-option` to `docker run` [#28186](https://github.com/docker/docker/pull/28186) ++ Add Image ID to container commit event [#28128](https://github.com/docker/docker/pull/28128) ++ Add external binaries version to docker info [#27955](https://github.com/docker/docker/pull/27955) ++ Add information for `Manager Addresses` in the output of `docker info` [#28042](https://github.com/docker/docker/pull/28042) ++ Add a new reference filter for `docker images` [#27872](https://github.com/docker/docker/pull/27872) + +### Runtime + ++ Add `--experimental` daemon flag to enable experimental features, instead of shipping them in a separate build [#27223](https://github.com/docker/docker/pull/27223) ++ Add a `--shutdown-timeout` daemon flag to specify the default timeout (in seconds) to stop containers gracefully before daemon exit [#23036](https://github.com/docker/docker/pull/23036) ++ Add `--stop-timeout` to specify the timeout value (in seconds) for individual containers to stop [#22566](https://github.com/docker/docker/pull/22566) ++ Add a new daemon flag `--userland-proxy-path` to allow configuring the userland proxy instead of using the hardcoded `docker-proxy` from `$PATH` [#26882](https://github.com/docker/docker/pull/26882) ++ Add boolean flag `--init` on `dockerd` and on `docker run` to use [tini](https://github.com/krallin/tini) a zombie-reaping init process as PID 1 [#26061](https://github.com/docker/docker/pull/26061) [#28037](https://github.com/docker/docker/pull/28037) ++ Add a new daemon flag `--init-path` to allow configuring the path to the `docker-init` binary [#26941](https://github.com/docker/docker/pull/26941) ++ Add support for live reloading insecure registry in configuration [#22337](https://github.com/docker/docker/pull/22337) ++ Add support for storage-opt size on Windows daemons [#23391](https://github.com/docker/docker/pull/23391) +* Improve reliability of `docker run --rm` by moving it from the client to the daemon [#20848](https://github.com/docker/docker/pull/20848) ++ Add support for `--cpu-rt-period` and `--cpu-rt-runtime` flags, allowing containers to run real-time threads when `CONFIG_RT_GROUP_SCHED` is enabled in the kernel [#23430](https://github.com/docker/docker/pull/23430) +* Allow parallel stop, pause, unpause [#24761](https://github.com/docker/docker/pull/24761) / [#26778](https://github.com/docker/docker/pull/26778) +* Implement XFS quota for overlay2 [#24771](https://github.com/docker/docker/pull/24771) +- Fix partial/full filter issue in `service tasks --filter` [#24850](https://github.com/docker/docker/pull/24850) +- Allow engine to run inside a user namespace [#25672](https://github.com/docker/docker/pull/25672) +- Fix a race condition between device deferred removal and resume device, when using the devicemapper graphdriver [#23497](https://github.com/docker/docker/pull/23497) +- Add `docker stats` support in Windows [#25737](https://github.com/docker/docker/pull/25737) +- Allow using `--pid=host` and `--net=host` when `--userns=host` [#25771](https://github.com/docker/docker/pull/25771) ++ (experimental) Add metrics (Prometheus) output for basic `container`, `image`, and `daemon` operations [#25820](https://github.com/docker/docker/pull/25820) +- Fix issue in `docker stats` with `NetworkDisabled=true` [#25905](https://github.com/docker/docker/pull/25905) ++ Add `docker top` support in Windows [#25891](https://github.com/docker/docker/pull/25891) ++ Record pid of exec'd process [#27470](https://github.com/docker/docker/pull/27470) ++ Add support for looking up user/groups via `getent` [#27599](https://github.com/docker/docker/pull/27599) ++ Add new `docker system` command with `df` and `prune` subcommands for system resource management, as well as `docker {container,image,volume,network} prune` subcommands [#26108](https://github.com/docker/docker/pull/26108) [#27525](https://github.com/docker/docker/pull/27525) / [#27525](https://github.com/docker/docker/pull/27525) +- Fix an issue where containers could not be stopped or killed by setting xfs max_retries to 0 upon ENOSPC with devicemapper [#26212](https://github.com/docker/docker/pull/26212) +- Fix `docker cp` failing to copy to a container's volume dir on CentOS with devicemapper [#28047](https://github.com/docker/docker/pull/28047) +* Promote overlay(2) graphdriver [#27932](https://github.com/docker/docker/pull/27932) ++ Add `--seccomp-profile` daemon flag to specify a path to a seccomp profile that overrides the default [#26276](https://github.com/docker/docker/pull/26276) +- Fix ulimits in `docker inspect` when `--default-ulimit` is set on daemon [#26405](https://github.com/docker/docker/pull/26405) +- Add workaround for overlay issues during build in older kernels [#28138](https://github.com/docker/docker/pull/28138) ++ Add `TERM` environment variable on `docker exec -t` [#26461](https://github.com/docker/docker/pull/26461) +* Honor a container’s `--stop-signal` setting upon `docker kill` [#26464](https://github.com/docker/docker/pull/26464) + +### Swarm Mode + ++ Add secret management [#27794](https://github.com/docker/docker/pull/27794) ++ Add support for templating service options (hostname, mounts, and environment variables) [#28025](https://github.com/docker/docker/pull/28025) +* Display the endpoint mode in the output of `docker service inspect --pretty` [#26906](https://github.com/docker/docker/pull/26906) +* Make `docker service ps` output more bearable by shortening service IDs in task names [#28088](https://github.com/docker/docker/pull/28088) +* Make `docker node ps` default to the current node [#25214](https://github.com/docker/docker/pull/25214) ++ Add `--dns`, -`-dns-opt`, and `--dns-search` to service create. [#27567](https://github.com/docker/docker/pull/27567) ++ Add `--force` to `docker service update` [#27596](https://github.com/docker/docker/pull/27596) ++ Add `--health-*` and `--no-healthcheck` flags to `docker service create` and `docker service update` [#27369](https://github.com/docker/docker/pull/27369) ++ Add `-q` to `docker service ps` [#27654](https://github.com/docker/docker/pull/27654) +* Display number of global services in `docker service ls` [#27710](https://github.com/docker/docker/pull/27710) +- Remove `--name` flag from `docker service update`. This flag is only functional on `docker service create`, so was removed from the `update` command [#26988](https://github.com/docker/docker/pull/26988) +- Fix worker nodes failing to recover because of transient networking issues [#26646](https://github.com/docker/docker/issues/26646) +* Add support for health aware load balancing and DNS records [#27279](https://github.com/docker/docker/pull/27279) ++ Add `--hostname` to `docker service create` [#27857](https://github.com/docker/docker/pull/27857) ++ Add `--host` to `docker service create`, and `--host-add`, `--host-rm` to `docker service update` [#28031](https://github.com/docker/docker/pull/28031) ++ Add `--tty` flag to `docker service create`/`update` [#28076](https://github.com/docker/docker/pull/28076) +* Autodetect, store, and expose node IP address as seen by the manager [#27910](https://github.com/docker/docker/pull/27910) +* Encryption at rest of manager keys and raft data [#27967](https://github.com/docker/docker/pull/27967) ++ Add `--update-max-failure-ratio`, `--update-monitor` and `--rollback` flags to `docker service update` [#26421](https://github.com/docker/docker/pull/26421) +- Fix an issue with address autodiscovery on `docker swarm init` running inside a container [#26457](https://github.com/docker/docker/pull/26457) ++ (experimental) Add `docker service logs` command to view logs for a service [#28089](https://github.com/docker/docker/pull/28089) ++ Pin images by digest for `docker service create` and `update` [#28173](https://github.com/docker/docker/pull/28173) +* Add short (`-f`) flag for `docker node rm --force` and `docker swarm leave --force` [#28196](https://github.com/docker/docker/pull/28196) ++ Add options to customize Raft snapshots (`--max-snapshots`, `--snapshot-interval`) [#27997](https://github.com/docker/docker/pull/27997) +- Don't repull image if pinned by digest [#28265](https://github.com/docker/docker/pull/28265) ++ Swarm-mode support for Windows [#27838](https://github.com/docker/docker/pull/27838) ++ Allow hostname to be updated on service [#28771](https://github.com/docker/docker/pull/28771) ++ Support v2 plugins [#29433](https://github.com/docker/docker/pull/29433) ++ Add content trust for services [#29469](https://github.com/docker/docker/pull/29469) + +### Volume + ++ Add support for labels on volumes [#21270](https://github.com/docker/docker/pull/21270) ++ Add support for filtering volumes by label [#25628](https://github.com/docker/docker/pull/25628) +* Add a `--force` flag in `docker volume rm` to forcefully purge the data of the volume that has already been deleted [#23436](https://github.com/docker/docker/pull/23436) +* Enhance `docker volume inspect` to show all options used when creating the volume [#26671](https://github.com/docker/docker/pull/26671) +* Add support for local NFS volumes to resolve hostnames [#27329](https://github.com/docker/docker/pull/27329) + +### Security + +- Fix selinux labeling of volumes shared in a container [#23024](https://github.com/docker/docker/pull/23024) +- Prohibit `/sys/firmware/**` from being accessed with apparmor [#26618](https://github.com/docker/docker/pull/26618) + +### DEPRECATION + +- Marked the `docker daemon` command as deprecated. The daemon is moved to a separate binary (`dockerd`), and should be used instead [#26834](https://github.com/docker/docker/pull/26834) +- Deprecate unversioned API endpoints [#28208](https://github.com/docker/docker/pull/28208) +- Remove Ubuntu 15.10 (Wily Werewolf) as supported platform. Ubuntu 15.10 is EOL, and no longer receives updates [#27042](https://github.com/docker/docker/pull/27042) +- Remove Fedora 22 as supported platform. Fedora 22 is EOL, and no longer receives updates [#27432](https://github.com/docker/docker/pull/27432) +- Remove Fedora 23 as supported platform. Fedora 23 is EOL, and no longer receives updates [#29455](https://github.com/docker/docker/pull/29455) +- Deprecate the `repo:shortid` syntax on `docker pull` [#27207](https://github.com/docker/docker/pull/27207) +- Deprecate backing filesystem without `d_type` for overlay and overlay2 storage drivers [#27433](https://github.com/docker/docker/pull/27433) +- Deprecate `MAINTAINER` in Dockerfile [#25466](https://github.com/docker/docker/pull/25466) +- Deprecate `filter` param for endpoint `/images/json` [#27872](https://github.com/docker/docker/pull/27872) +- Deprecate setting duplicate engine labels [#24533](https://github.com/docker/docker/pull/24533) +- Deprecate "top-level" network information in `NetworkSettings` [#28437](https://github.com/docker/docker/pull/28437) + +## 1.12.6 (2017-01-10) + +**IMPORTANT**: Docker 1.12 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + +**NOTE**: Docker 1.12.5 will correctly validate that either an IPv6 subnet is provided or +that the IPAM driver can provide one when you specify the `--ipv6` option. + +If you are currently using the `--ipv6` option _without_ specifying the +`--fixed-cidr-v6` option, the Docker daemon will refuse to start with the +following message: + +```none +Error starting daemon: Error initializing network controller: Error creating + default "bridge" network: failed to parse pool request + for address space "LocalDefault" pool " subpool ": + could not find an available, non-overlapping IPv6 address + pool among the defaults to assign to the network +``` + +To resolve this error, either remove the `--ipv6` flag (to preserve the same +behavior as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the +value of the `--fixed-cidr-v6` flag. + +In a similar way, if you specify the `--ipv6` flag when creating a network +with the default IPAM driver, without providing an IPv6 `--subnet`, network +creation will fail with the following message: + +```none +Error response from daemon: failed to parse pool request for address space + "LocalDefault" pool "" subpool "": could not find an + available, non-overlapping IPv6 address pool among + the defaults to assign to the network +``` + +To resolve this, either remove the `--ipv6` flag (to preserve the same behavior +as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the value of the +`--subnet` flag. + +The network network creation will instead succeed if you use an external IPAM driver +which supports automatic allocation of IPv6 subnets. + +### Runtime + +- Fix runC privilege escalation (CVE-2016-9962) + +## 1.12.5 (2016-12-15) + +**IMPORTANT**: Docker 1.12 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + +**NOTE**: Docker 1.12.5 will correctly validate that either an IPv6 subnet is provided or +that the IPAM driver can provide one when you specify the `--ipv6` option. + +If you are currently using the `--ipv6` option _without_ specifying the +`--fixed-cidr-v6` option, the Docker daemon will refuse to start with the +following message: + +```none +Error starting daemon: Error initializing network controller: Error creating + default "bridge" network: failed to parse pool request + for address space "LocalDefault" pool " subpool ": + could not find an available, non-overlapping IPv6 address + pool among the defaults to assign to the network +``` + +To resolve this error, either remove the `--ipv6` flag (to preserve the same +behavior as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the +value of the `--fixed-cidr-v6` flag. + +In a similar way, if you specify the `--ipv6` flag when creating a network +with the default IPAM driver, without providing an IPv6 `--subnet`, network +creation will fail with the following message: + +```none +Error response from daemon: failed to parse pool request for address space + "LocalDefault" pool "" subpool "": could not find an + available, non-overlapping IPv6 address pool among + the defaults to assign to the network +``` + +To resolve this, either remove the `--ipv6` flag (to preserve the same behavior +as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the value of the +`--subnet` flag. + +The network network creation will instead succeed if you use an external IPAM driver +which supports automatic allocation of IPv6 subnets. + +### Runtime + +- Fix race on sending stdin close event [#29424](https://github.com/docker/docker/pull/29424) + +### Networking + +- Fix panic in docker network ls when a network was created with `--ipv6` and no ipv6 `--subnet` in older docker versions [#29416](https://github.com/docker/docker/pull/29416) + +### Contrib + +- Fix compilation on Darwin [#29370](https://github.com/docker/docker/pull/29370) + +## 1.12.4 (2016-12-12) + +**IMPORTANT**: Docker 1.12 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + + +### Runtime + +- Fix issue where volume metadata was not removed [#29083](https://github.com/docker/docker/pull/29083) +- Asynchronously close streams to prevent holding container lock [#29050](https://github.com/docker/docker/pull/29050) +- Fix selinux labels for newly created container volumes [#29050](https://github.com/docker/docker/pull/29050) +- Remove hostname validation [#28990](https://github.com/docker/docker/pull/28990) +- Fix deadlocks caused by IO races [#29095](https://github.com/docker/docker/pull/29095) [#29141](https://github.com/docker/docker/pull/29141) +- Return an empty stats if the container is restarting [#29150](https://github.com/docker/docker/pull/29150) +- Fix volume store locking [#29151](https://github.com/docker/docker/pull/29151) +- Ensure consistent status code in API [#29150](https://github.com/docker/docker/pull/29150) +- Fix incorrect opaque directory permission in overlay2 [#29093](https://github.com/docker/docker/pull/29093) +- Detect plugin content and error out on `docker pull` [#29297](https://github.com/docker/docker/pull/29297) + +### Swarm Mode + +* Update Swarmkit [#29047](https://github.com/docker/docker/pull/29047) + - orchestrator/global: Fix deadlock on updates [docker/swarmkit#1760](https://github.com/docker/swarmkit/pull/1760) + - on leader switchover preserve the vxlan id for existing networks [docker/swarmkit#1773](https://github.com/docker/swarmkit/pull/1773) +- Refuse swarm spec not named "default" [#29152](https://github.com/docker/docker/pull/29152) + +### Networking + +* Update libnetwork [#29004](https://github.com/docker/docker/pull/29004) [#29146](https://github.com/docker/docker/pull/29146) + - Fix panic in embedded DNS [docker/libnetwork#1561](https://github.com/docker/libnetwork/pull/1561) + - Fix unmarhalling panic when passing --link-local-ip on global scope network [docker/libnetwork#1564](https://github.com/docker/libnetwork/pull/1564) + - Fix panic when network plugin returns nil StaticRoutes [docker/libnetwork#1563](https://github.com/docker/libnetwork/pull/1563) + - Fix panic in osl.(*networkNamespace).DeleteNeighbor [docker/libnetwork#1555](https://github.com/docker/libnetwork/pull/1555) + - Fix panic in swarm networking concurrent map read/write [docker/libnetwork#1570](https://github.com/docker/libnetwork/pull/1570) + * Allow encrypted networks when running docker inside a container [docker/libnetwork#1502](https://github.com/docker/libnetwork/pull/1502) + - Do not block autoallocation of IPv6 pool [docker/libnetwork#1538](https://github.com/docker/libnetwork/pull/1538) + - Set timeout for netlink calls [docker/libnetwork#1557](https://github.com/docker/libnetwork/pull/1557) + - Increase networking local store timeout to one minute [docker/libkv#140](https://github.com/docker/libkv/pull/140) + - Fix a panic in libnetwork.(*sandbox).execFunc [docker/libnetwork#1556](https://github.com/docker/libnetwork/pull/1556) + - Honor icc=false for internal networks [docker/libnetwork#1525](https://github.com/docker/libnetwork/pull/1525) + +### Logging + +* Update syslog log driver [#29150](https://github.com/docker/docker/pull/29150) + +### Contrib + +- Run "dnf upgrade" before installing in fedora [#29150](https://github.com/docker/docker/pull/29150) +- Add build-date back to RPM packages [#29150](https://github.com/docker/docker/pull/29150) +- deb package filename changed to include distro to distinguish between distro code names [#27829](https://github.com/docker/docker/pull/27829) + +## 1.12.3 (2016-10-26) + +**IMPORTANT**: Docker 1.12 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + + +### Runtime + +- Fix ambient capability usage in containers (CVE-2016-8867) [#27610](https://github.com/docker/docker/pull/27610) +- Prevent a deadlock in libcontainerd for Windows [#27136](https://github.com/docker/docker/pull/27136) +- Fix error reporting in CopyFileWithTar [#27075](https://github.com/docker/docker/pull/27075) +* Reset health status to starting when a container is restarted [#27387](https://github.com/docker/docker/pull/27387) +* Properly handle shared mount propagation in storage directory [#27609](https://github.com/docker/docker/pull/27609) +- Fix docker exec [#27610](https://github.com/docker/docker/pull/27610) +- Fix backward compatibility with containerd’s events log [#27693](https://github.com/docker/docker/pull/27693) + +### Swarm Mode + +- Fix conversion of restart-policy [#27062](https://github.com/docker/docker/pull/27062) +* Update Swarmkit [#27554](https://github.com/docker/docker/pull/27554) + * Avoid restarting a task that has already been restarted [docker/swarmkit#1305](https://github.com/docker/swarmkit/pull/1305) + * Allow duplicate published ports when they use different protocols [docker/swarmkit#1632](https://github.com/docker/swarmkit/pull/1632) + * Allow multiple randomly assigned published ports on service [docker/swarmkit#1657](https://github.com/docker/swarmkit/pull/1657) + - Fix panic when allocations happen at init time [docker/swarmkit#1651](https://github.com/docker/swarmkit/pull/1651) + +### Networking + +* Update libnetwork [#27559](https://github.com/docker/docker/pull/27559) + - Fix race in serializing sandbox to string [docker/libnetwork#1495](https://github.com/docker/libnetwork/pull/1495) + - Fix race during deletion [docker/libnetwork#1503](https://github.com/docker/libnetwork/pull/1503) + * Reset endpoint port info on connectivity revoke in bridge driver [docker/libnetwork#1504](https://github.com/docker/libnetwork/pull/1504) + - Fix a deadlock in networking code [docker/libnetwork#1507](https://github.com/docker/libnetwork/pull/1507) + - Fix a race in load balancer state [docker/libnetwork#1512](https://github.com/docker/libnetwork/pull/1512) + +### Logging + +* Update fluent-logger-golang to v1.2.1 [#27474](https://github.com/docker/docker/pull/27474) + +### Contrib + +* Update buildtags for armhf ubuntu-trusty [#27327](https://github.com/docker/docker/pull/27327) +* Add AppArmor to runc buildtags for armhf [#27421](https://github.com/docker/docker/pull/27421) + +## 1.12.2 (2016-10-11) + +**IMPORTANT**: Docker 1.12 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + + +### Runtime + +- Fix a panic due to a race condition filtering `docker ps` [#26049](https://github.com/docker/docker/pull/26049) +* Implement retry logic to prevent "Unable to remove filesystem" errors when using the aufs storage driver [#26536](https://github.com/docker/docker/pull/26536) +* Prevent devicemapper from removing device symlinks if `dm.use_deferred_removal` is enabled [#24740](https://github.com/docker/docker/pull/24740) +- Fix an issue where the CLI did not return correct exit codes if a command was run with invalid options [#26777](https://github.com/docker/docker/pull/26777) +- Fix a panic due to a bug in stdout / stderr processing in health checks [#26507](https://github.com/docker/docker/pull/26507) +- Fix exec's children handling [#26874](https://github.com/docker/docker/pull/26874) +- Fix exec form of HEALTHCHECK CMD [#26208](https://github.com/docker/docker/pull/26208) + +### Networking + +- Fix a daemon start panic on armv5 [#24315](https://github.com/docker/docker/issues/24315) +* Vendor libnetwork [#26879](https://github.com/docker/docker/pull/26879) [#26953](https://github.com/docker/docker/pull/26953) + * Avoid returning early on agent join failures [docker/libnetwork#1473](https://github.com/docker/libnetwork/pull/1473) + - Fix service published port cleanup issues [docker/libetwork#1432](https://github.com/docker/libnetwork/pull/1432) [docker/libnetwork#1433](https://github.com/docker/libnetwork/pull/1433) + * Recover properly from transient gossip failures [docker/libnetwork#1446](https://github.com/docker/libnetwork/pull/1446) + * Disambiguate node names known to gossip cluster to avoid node name collision [docker/libnetwork#1451](https://github.com/docker/libnetwork/pull/1451) + * Honor user provided listen address for gossip [docker/libnetwork#1460](https://github.com/docker/libnetwork/pull/1460) + * Allow reachability via published port across services on the same host [docker/libnetwork#1398](https://github.com/docker/libnetwork/pull/1398) + * Change the ingress sandbox name from random id to just `ingress_sbox` [docker/libnetwork#1449](https://github.com/docker/libnetwork/pull/1449) + - Disable service discovery in ingress network [docker/libnetwork#1489](https://github.com/docker/libnetwork/pull/1489) + +### Swarm Mode + +* Fix remote detection of a node's address when it joins the cluster [#26211](https://github.com/docker/docker/pull/26211) +* Vendor SwarmKit [#26765](https://github.com/docker/docker/pull/26765) + * Bounce session after failed status update [docker/swarmkit#1539](https://github.com/docker/swarmkit/pull/1539) + - Fix possible raft deadlocks [docker/swarmkit#1537](https://github.com/docker/swarmkit/pull/1537) + - Fix panic and endpoint leak when a service is updated with no endpoints [docker/swarmkit#1481](https://github.com/docker/swarmkit/pull/1481) + * Produce an error if the same port is published twice on `service create` or `service update` [docker/swarmkit#1495](https://github.com/docker/swarmkit/pull/1495) + - Fix an issue where changes to a service were not detected, resulting in the service not being updated [docker/swarmkit#1497](https://github.com/docker/swarmkit/pull/1497) + - Do not allow service creation on ingress network [docker/swarmkit#1600](https://github.com/docker/swarmkit/pull/1600) + +### Contrib + +* Update the debian sysv-init script to use `dockerd` instead of `docker daemon` [#25869](https://github.com/docker/docker/pull/25869) +* Improve stability when running the docker client on MacOS Sierra [#26875](https://github.com/docker/docker/pull/26875) +- Fix installation on debian stretch [#27184](https://github.com/docker/docker/pull/27184) + +### Windows + +- Fix an issue where arrow-navigation did not work when running the docker client in ConEmu [#25578](https://github.com/docker/docker/pull/25578) + +## 1.12.1 (2016-08-18) + +**IMPORTANT**: Docker 1.12 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + + +### Client + +* Add `Joined at` information in `node inspect --pretty` [#25512](https://github.com/docker/docker/pull/25512) +- Fix a crash on `service inspect` [#25454](https://github.com/docker/docker/pull/25454) +- Fix issue preventing `service update --env-add` to work as intended [#25427](https://github.com/docker/docker/pull/25427) +- Fix issue preventing `service update --publish-add` to work as intended [#25428](https://github.com/docker/docker/pull/25428) +- Remove `service update --network-add` and `service update --network-rm` flags + because this feature is not yet implemented in 1.12, but was inadvertently added + to the client in 1.12.0 [#25646](https://github.com/docker/docker/pull/25646) + +### Contrib + ++ Official ARM installation for Debian Jessie, Ubuntu Trusty, and Raspbian Jessie [#24815](https://github.com/docker/docker/pull/24815) [#25591](https://github.com/docker/docker/pull/25637) +- Add selinux policy per distro/version, fixing issue preventing successful installation on Fedora 24, and Oracle Linux [#25334](https://github.com/docker/docker/pull/25334) [#25593](https://github.com/docker/docker/pull/25593) + +### Networking + +- Fix issue that prevented containers to be accessed by hostname with Docker overlay driver in Swarm Mode [#25603](https://github.com/docker/docker/pull/25603) [#25648](https://github.com/docker/docker/pull/25648) +- Fix random network issues on service with published port [#25603](https://github.com/docker/docker/pull/25603) +- Fix unreliable inter-service communication after scaling down and up [#25603](https://github.com/docker/docker/pull/25603) +- Fix issue where removing all tasks on a node and adding them back breaks connectivity with other services [#25603](https://github.com/docker/docker/pull/25603) +- Fix issue where a task that fails to start results in a race, causing a `network xxx not found` error that masks the actual error [#25550](https://github.com/docker/docker/pull/25550) +- Relax validation of SRV records for external services that use SRV records not formatted according to RFC 2782 [#25739](https://github.com/docker/docker/pull/25739) + +### Plugins (experimental) + +* Make daemon events listen for plugin lifecycle events [#24760](https://github.com/docker/docker/pull/24760) +* Check for plugin state before enabling plugin [#25033](https://github.com/docker/docker/pull/25033) +- Remove plugin root from filesystem on `plugin rm` [#25187](https://github.com/docker/docker/pull/25187) +- Prevent deadlock when more than one plugin is installed [#25384](https://github.com/docker/docker/pull/25384) + +### Runtime + +* Mask join tokens in daemon logs [#25346](https://github.com/docker/docker/pull/25346) +- Fix `docker ps --filter` causing the results to no longer be sorted by creation time [#25387](https://github.com/docker/docker/pull/25387) +- Fix various crashes [#25053](https://github.com/docker/docker/pull/25053) + +### Security + +* Add `/proc/timer_list` to the masked paths list to prevent information leak from the host [#25630](https://github.com/docker/docker/pull/25630) +* Allow systemd to run with only `--cap-add SYS_ADMIN` rather than having to also add `--cap-add DAC_READ_SEARCH` or disabling seccomp filtering [#25567](https://github.com/docker/docker/pull/25567) + +### Swarm + +- Fix an issue where the swarm can get stuck electing a new leader after quorum is lost [#25055](https://github.com/docker/docker/issues/25055) +- Fix unwanted rescheduling of containers after a leader failover [#25017](https://github.com/docker/docker/issues/25017) +- Change swarm root CA key to P256 curve [swarmkit#1376](https://github.com/docker/swarmkit/pull/1376) +- Allow forced removal of a node from a swarm [#25159](https://github.com/docker/docker/pull/25159) +- Fix connection leak when a node leaves a swarm [swarmkit/#1277](https://github.com/docker/swarmkit/pull/1277) +- Backdate swarm certificates by one hour to tolerate more clock skew [swarmkit/#1243](https://github.com/docker/swarmkit/pull/1243) +- Avoid high CPU use with many unschedulable tasks [swarmkit/#1287](https://github.com/docker/swarmkit/pull/1287) +- Fix issue with global tasks not starting up [swarmkit/#1295](https://github.com/docker/swarmkit/pull/1295) +- Garbage collect raft logs [swarmkit/#1327](https://github.com/docker/swarmkit/pull/1327) + +### Volume + +- Persist local volume options after a daemon restart [#25316](https://github.com/docker/docker/pull/25316) +- Fix an issue where the mount ID was not returned on volume unmount [#25333](https://github.com/docker/docker/pull/25333) +- Fix an issue where a volume mount could inadvertently create a bind mount [#25309](https://github.com/docker/docker/pull/25309) +- `docker service create --mount type=bind,...` now correctly validates if the source path exists, instead of creating it [#25494](https://github.com/docker/docker/pull/25494) + +## 1.12.0 (2016-07-28) + + +**IMPORTANT**: Docker 1.12.0 ships with an updated systemd unit file for rpm +based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When +upgrading from an older version of docker, the upgrade process may not +automatically install the updated version of the unit file, or fail to start +the docker service if; + +- the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or +- a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive + +Starting the docker service will produce an error: + + Failed to start docker.service: Unit docker.socket failed to load: No such file or directory. + +or + + no sockets found via socket activation: make sure the service was started by systemd. + +To resolve this: + +- Backup the current version of the unit file, and replace the file with the + [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm) +- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present +- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present). + +After making those changes, run `sudo systemctl daemon-reload`, and `sudo +systemctl restart docker` to reload changes and (re)start the docker daemon. + +**IMPORTANT**: With Docker 1.12, a Linux docker installation now has two +additional binaries; `dockerd`, and `docker-proxy`. If you have scripts for +installing docker, please make sure to update them accordingly. + +### Builder + ++ New `HEALTHCHECK` Dockerfile instruction to support user-defined healthchecks [#23218](https://github.com/docker/docker/pull/23218) ++ New `SHELL` Dockerfile instruction to specify the default shell when using the shell form for commands in a Dockerfile [#22489](https://github.com/docker/docker/pull/22489) ++ Add `#escape=` Dockerfile directive to support platform-specific parsing of file paths in Dockerfile [#22268](https://github.com/docker/docker/pull/22268) ++ Add support for comments in `.dockerignore` [#23111](https://github.com/docker/docker/pull/23111) +* Support for UTF-8 in Dockerfiles [#23372](https://github.com/docker/docker/pull/23372) +* Skip UTF-8 BOM bytes from `Dockerfile` and `.dockerignore` if exist [#23234](https://github.com/docker/docker/pull/23234) +* Windows: support for `ARG` to match Linux [#22508](https://github.com/docker/docker/pull/22508) +- Fix error message when building using a daemon with the bridge network disabled [#22932](https://github.com/docker/docker/pull/22932) + +### Contrib + +* Enable seccomp for Centos 7 and Oracle Linux 7 [#22344](https://github.com/docker/docker/pull/22344) +- Remove MountFlags in systemd unit to allow shared mount propagation [#22806](https://github.com/docker/docker/pull/22806) + +### Distribution + ++ Add `--max-concurrent-downloads` and `--max-concurrent-uploads` daemon flags useful for situations where network connections don't support multiple downloads/uploads [#22445](https://github.com/docker/docker/pull/22445) +* Registry operations now honor the `ALL_PROXY` environment variable [#22316](https://github.com/docker/docker/pull/22316) +* Provide more information to the user on `docker load` [#23377](https://github.com/docker/docker/pull/23377) +* Always save registry digest metadata about images pushed and pulled [#23996](https://github.com/docker/docker/pull/23996) + +### Logging + ++ Syslog logging driver now supports DGRAM sockets [#21613](https://github.com/docker/docker/pull/21613) ++ Add `--details` option to `docker logs` to also display log tags [#21889](https://github.com/docker/docker/pull/21889) ++ Enable syslog logger to have access to env and labels [#21724](https://github.com/docker/docker/pull/21724) ++ An additional syslog-format option `rfc5424micro` to allow microsecond resolution in syslog timestamp [#21844](https://github.com/docker/docker/pull/21844) +* Inherit the daemon log options when creating containers [#21153](https://github.com/docker/docker/pull/21153) +* Remove `docker/` prefix from log messages tag and replace it with `{{.DaemonName}}` so that users have the option of changing the prefix [#22384](https://github.com/docker/docker/pull/22384) + +### Networking + ++ Built-in Virtual-IP based internal and ingress load-balancing using IPVS [#23361](https://github.com/docker/docker/pull/23361) ++ Routing Mesh using ingress overlay network [#23361](https://github.com/docker/docker/pull/23361) ++ Secured multi-host overlay networking using encrypted control-plane and Data-plane [#23361](https://github.com/docker/docker/pull/23361) ++ MacVlan driver is out of experimental [#23524](https://github.com/docker/docker/pull/23524) ++ Add `driver` filter to `network ls` [#22319](https://github.com/docker/docker/pull/22319) ++ Adding `network` filter to `docker ps --filter` [#23300](https://github.com/docker/docker/pull/23300) ++ Add `--link-local-ip` flag to `create`, `run` and `network connect` to specify a container's link-local address [#23415](https://github.com/docker/docker/pull/23415) ++ Add network label filter support [#21495](https://github.com/docker/docker/pull/21495) +* Removed dependency on external KV-Store for Overlay networking in Swarm-Mode [#23361](https://github.com/docker/docker/pull/23361) +* Add container's short-id as default network alias [#21901](https://github.com/docker/docker/pull/21901) +* `run` options `--dns` and `--net=host` are no longer mutually exclusive [#22408](https://github.com/docker/docker/pull/22408) +- Fix DNS issue when renaming containers with generated names [#22716](https://github.com/docker/docker/pull/22716) +- Allow both `network inspect -f {{.Id}}` and `network inspect -f {{.ID}}` to address inconsistency with inspect output [#23226](https://github.com/docker/docker/pull/23226) + +### Plugins (experimental) + ++ New `plugin` command to manager plugins with `install`, `enable`, `disable`, `rm`, `inspect`, `set` subcommands [#23446](https://github.com/docker/docker/pull/23446) + +### Remote API (v1.24) & Client + ++ Split the binary into two: `docker` (client) and `dockerd` (daemon) [#20639](https://github.com/docker/docker/pull/20639) ++ Add `before` and `since` filters to `docker images --filter` [#22908](https://github.com/docker/docker/pull/22908) ++ Add `--limit` option to `docker search` [#23107](https://github.com/docker/docker/pull/23107) ++ Add `--filter` option to `docker search` [#22369](https://github.com/docker/docker/pull/22369) ++ Add security options to `docker info` output [#21172](https://github.com/docker/docker/pull/21172) [#23520](https://github.com/docker/docker/pull/23520) ++ Add insecure registries to `docker info` output [#20410](https://github.com/docker/docker/pull/20410) ++ Extend Docker authorization with TLS user information [#21556](https://github.com/docker/docker/pull/21556) ++ devicemapper: expose Mininum Thin Pool Free Space through `docker info` [#21945](https://github.com/docker/docker/pull/21945) +* API now returns a JSON object when an error occurs making it more consistent [#22880](https://github.com/docker/docker/pull/22880) +- Prevent `docker run -i --restart` from hanging on exit [#22777](https://github.com/docker/docker/pull/22777) +- Fix API/CLI discrepancy on hostname validation [#21641](https://github.com/docker/docker/pull/21641) +- Fix discrepancy in the format of sizes in `stats` from HumanSize to BytesSize [#21773](https://github.com/docker/docker/pull/21773) +- authz: when request is denied return forbbiden exit code (403) [#22448](https://github.com/docker/docker/pull/22448) +- Windows: fix tty-related displaying issues [#23878](https://github.com/docker/docker/pull/23878) + +### Runtime + ++ Split the userland proxy to a separate binary (`docker-proxy`) [#23312](https://github.com/docker/docker/pull/23312) ++ Add `--live-restore` daemon flag to keep containers running when daemon shuts down, and regain control on startup [#23213](https://github.com/docker/docker/pull/23213) ++ Ability to add OCI-compatible runtimes (via `--add-runtime` daemon flag) and select one with `--runtime` on `create` and `run` [#22983](https://github.com/docker/docker/pull/22983) ++ New `overlay2` graphdriver for Linux 4.0+ with multiple lower directory support [#22126](https://github.com/docker/docker/pull/22126) ++ New load/save image events [#22137](https://github.com/docker/docker/pull/22137) ++ Add support for reloading daemon configuration through systemd [#22446](https://github.com/docker/docker/pull/22446) ++ Add disk quota support for btrfs [#19651](https://github.com/docker/docker/pull/19651) ++ Add disk quota support for zfs [#21946](https://github.com/docker/docker/pull/21946) ++ Add support for `docker run --pid=container:` [#22481](https://github.com/docker/docker/pull/22481) ++ Align default seccomp profile with selected capabilities [#22554](https://github.com/docker/docker/pull/22554) ++ Add a `daemon reload` event when the daemon reloads its configuration [#22590](https://github.com/docker/docker/pull/22590) ++ Add `trace` capability in the pprof profiler to show execution traces in binary form [#22715](https://github.com/docker/docker/pull/22715) ++ Add a `detach` event [#22898](https://github.com/docker/docker/pull/22898) ++ Add support for setting sysctls with `--sysctl` [#19265](https://github.com/docker/docker/pull/19265) ++ Add `--storage-opt` flag to `create` and `run` allowing to set `size` on devicemapper [#19367](https://github.com/docker/docker/pull/19367) ++ Add `--oom-score-adjust` daemon flag with a default value of `-500` making the daemon less likely to be killed before containers [#24516](https://github.com/docker/docker/pull/24516) +* Undeprecate the `-c` short alias of `--cpu-shares` on `run`, `build`, `create`, `update` [#22621](https://github.com/docker/docker/pull/22621) +* Prevent from using aufs and overlay graphdrivers on an eCryptfs mount [#23121](https://github.com/docker/docker/pull/23121) +- Fix issues with tmpfs mount ordering [#22329](https://github.com/docker/docker/pull/22329) +- Created containers are no longer listed on `docker ps -a -f exited=0` [#21947](https://github.com/docker/docker/pull/21947) +- Fix an issue where containers are stuck in a "Removal In Progress" state [#22423](https://github.com/docker/docker/pull/22423) +- Fix bug that was returning an HTTP 500 instead of a 400 when not specifying a command on run/create [#22762](https://github.com/docker/docker/pull/22762) +- Fix bug with `--detach-keys` whereby input matching a prefix of the detach key was not preserved [#22943](https://github.com/docker/docker/pull/22943) +- SELinux labeling is now disabled when using `--privileged` mode [#22993](https://github.com/docker/docker/pull/22993) +- If volume-mounted into a container, `/etc/hosts`, `/etc/resolv.conf`, `/etc/hostname` are no longer SELinux-relabeled [#22993](https://github.com/docker/docker/pull/22993) +- Fix inconsistency in `--tmpfs` behavior regarding mount options [#22438](https://github.com/docker/docker/pull/22438) +- Fix an issue where daemon hangs at startup [#23148](https://github.com/docker/docker/pull/23148) +- Ignore SIGPIPE events to prevent journald restarts to crash docker in some cases [#22460](https://github.com/docker/docker/pull/22460) +- Containers are not removed from stats list on error [#20835](https://github.com/docker/docker/pull/20835) +- Fix `on-failure` restart policy when daemon restarts [#20853](https://github.com/docker/docker/pull/20853) +- Fix an issue with `stats` when a container is using another container's network [#21904](https://github.com/docker/docker/pull/21904) + +### Swarm Mode + ++ New `swarm` command to manage swarms with `init`, `join`, `join-token`, `leave`, `update` subcommands [#23361](https://github.com/docker/docker/pull/23361) [#24823](https://github.com/docker/docker/pull/24823) ++ New `service` command to manage swarm-wide services with `create`, `inspect`, `update`, `rm`, `ps` subcommands [#23361](https://github.com/docker/docker/pull/23361) [#25140](https://github.com/docker/docker/pull/25140) ++ New `node` command to manage nodes with `accept`, `promote`, `demote`, `inspect`, `update`, `ps`, `ls` and `rm` subcommands [#23361](https://github.com/docker/docker/pull/23361) [#25140](https://github.com/docker/docker/pull/25140) ++ (experimental) New `stack` and `deploy` commands to manage and deploy multi-service applications [#23522](https://github.com/docker/docker/pull/23522) [#25140](https://github.com/docker/docker/pull/25140) + +### Volume + ++ Add support for local and global volume scopes (analogous to network scopes) [#22077](https://github.com/docker/docker/pull/22077) ++ Allow volume drivers to provide a `Status` field [#21006](https://github.com/docker/docker/pull/21006) ++ Add name/driver filter support for volume [#21361](https://github.com/docker/docker/pull/21361) +* Mount/Unmount operations now receives an opaque ID to allow volume drivers to differentiate between two callers [#21015](https://github.com/docker/docker/pull/21015) +- Fix issue preventing to remove a volume in a corner case [#22103](https://github.com/docker/docker/pull/22103) +- Windows: Enable auto-creation of host-path to match Linux [#22094](https://github.com/docker/docker/pull/22094) + + +### DEPRECATION +* Environment variables `DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and `DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` have been renamed + to `DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE` and `DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE` respectively [#22574](https://github.com/docker/docker/pull/22574) +* Remove deprecated `syslog-tag`, `gelf-tag`, `fluentd-tag` log option in favor of the more generic `tag` one [#22620](https://github.com/docker/docker/pull/22620) +* Remove deprecated feature of passing HostConfig at API container start [#22570](https://github.com/docker/docker/pull/22570) +* Remove deprecated `-f`/`--force` flag on docker tag [#23090](https://github.com/docker/docker/pull/23090) +* Remove deprecated `/containers//copy` endpoint [#22149](https://github.com/docker/docker/pull/22149) +* Remove deprecated `docker ps` flags `--since` and `--before` [#22138](https://github.com/docker/docker/pull/22138) +* Deprecate the old 3-args form of `docker import` [#23273](https://github.com/docker/docker/pull/23273) + +## 1.11.2 (2016-05-31) + +### Networking + +- Fix a stale endpoint issue on overlay networks during ungraceful restart ([#23015](https://github.com/docker/docker/pull/23015)) +- Fix an issue where the wrong port could be reported by `docker inspect/ps/port` ([#22997](https://github.com/docker/docker/pull/22997)) + +### Runtime + +- Fix a potential panic when running `docker build` ([#23032](https://github.com/docker/docker/pull/23032)) +- Fix interpretation of `--user` parameter ([#22998](https://github.com/docker/docker/pull/22998)) +- Fix a bug preventing container statistics to be correctly reported ([#22955](https://github.com/docker/docker/pull/22955)) +- Fix an issue preventing container to be restarted after daemon restart ([#22947](https://github.com/docker/docker/pull/22947)) +- Fix issues when running 32 bit binaries on Ubuntu 16.04 ([#22922](https://github.com/docker/docker/pull/22922)) +- Fix a possible deadlock on image deletion and container attach ([#22918](https://github.com/docker/docker/pull/22918)) +- Fix an issue where containers fail to start after a daemon restart if they depend on a containerized cluster store ([#22561](https://github.com/docker/docker/pull/22561)) +- Fix an issue causing `docker ps` to hang on CentOS when using devicemapper ([#22168](https://github.com/docker/docker/pull/22168), [#23067](https://github.com/docker/docker/pull/23067)) +- Fix a bug preventing to `docker exec` into a container when using devicemapper ([#22168](https://github.com/docker/docker/pull/22168), [#23067](https://github.com/docker/docker/pull/23067)) + + +## 1.11.1 (2016-04-26) + +### Distribution + +- Fix schema2 manifest media type to be of type `application/vnd.docker.container.image.v1+json` ([#21949](https://github.com/docker/docker/pull/21949)) + +### Documentation + ++ Add missing API documentation for changes introduced with 1.11.0 ([#22048](https://github.com/docker/docker/pull/22048)) + +### Builder + +* Append label passed to `docker build` as arguments as an implicit `LABEL` command at the end of the processed `Dockerfile` ([#22184](https://github.com/docker/docker/pull/22184)) + +### Networking + +- Fix a panic that would occur when forwarding DNS query ([#22261](https://github.com/docker/docker/pull/22261)) +- Fix an issue where OS threads could end up within an incorrect network namespace when using user defined networks ([#22261](https://github.com/docker/docker/pull/22261)) + +### Runtime + +- Fix a bug preventing labels configuration to be reloaded via the config file ([#22299](https://github.com/docker/docker/pull/22299)) +- Fix a regression where container mounting `/var/run` would prevent other containers from being removed ([#22256](https://github.com/docker/docker/pull/22256)) +- Fix an issue where it would be impossible to update both `memory-swap` and `memory` value together ([#22255](https://github.com/docker/docker/pull/22255)) +- Fix a regression from 1.11.0 where the `/auth` endpoint would not initialize `serveraddress` if it is not provided ([#22254](https://github.com/docker/docker/pull/22254)) +- Add missing cleanup of container temporary files when cancelling a schedule restart ([#22237](https://github.com/docker/docker/pull/22237)) +- Remove scary error message when no restart policy is specified ([#21993](https://github.com/docker/docker/pull/21993)) +- Fix a panic that would occur when the plugins were activated via the json spec ([#22191](https://github.com/docker/docker/pull/22191)) +- Fix restart backoff logic to correctly reset delay if container ran for at least 10secs ([#22125](https://github.com/docker/docker/pull/22125)) +- Remove error message when a container restart get cancelled ([#22123](https://github.com/docker/docker/pull/22123)) +- Fix an issue where `docker` would not correctly clean up after `docker exec` ([#22121](https://github.com/docker/docker/pull/22121)) +- Fix a panic that could occur when serving concurrent `docker stats` commands ([#22120](https://github.com/docker/docker/pull/22120))` +- Revert deprecation of non-existent host directories auto-creation ([#22065](https://github.com/docker/docker/pull/22065)) +- Hide misleading rpc error on daemon shutdown ([#22058](https://github.com/docker/docker/pull/22058)) + +## 1.11.0 (2016-04-13) + +**IMPORTANT**: With Docker 1.11, a Linux docker installation is now made of 4 binaries (`docker`, [`docker-containerd`](https://github.com/docker/containerd), [`docker-containerd-shim`](https://github.com/docker/containerd) and [`docker-runc`](https://github.com/opencontainers/runc)). If you have scripts relying on docker being a single static binaries, please make sure to update them. Interaction with the daemon stay the same otherwise, the usage of the other binaries should be transparent. A Windows docker installation remains a single binary, `docker.exe`. + +### Builder + +- Fix a bug where Docker would not use the correct uid/gid when processing the `WORKDIR` command ([#21033](https://github.com/docker/docker/pull/21033)) +- Fix a bug where copy operations with userns would not use the proper uid/gid ([#20782](https://github.com/docker/docker/pull/20782), [#21162](https://github.com/docker/docker/pull/21162)) + +### Client + +* Usage of the `:` separator for security option has been deprecated. `=` should be used instead ([#21232](https://github.com/docker/docker/pull/21232)) ++ The client user agent is now passed to the registry on `pull`, `build`, `push`, `login` and `search` operations ([#21306](https://github.com/docker/docker/pull/21306), [#21373](https://github.com/docker/docker/pull/21373)) +* Allow setting the Domainname and Hostname separately through the API ([#20200](https://github.com/docker/docker/pull/20200)) +* Docker info will now warn users if it can not detect the kernel version or the operating system ([#21128](https://github.com/docker/docker/pull/21128)) +- Fix an issue where `docker stats --no-stream` output could be all 0s ([#20803](https://github.com/docker/docker/pull/20803)) +- Fix a bug where some newly started container would not appear in a running `docker stats` command ([#20792](https://github.com/docker/docker/pull/20792)) +* Post processing is no longer enabled for linux-cgo terminals ([#20587](https://github.com/docker/docker/pull/20587)) +- Values to `--hostname` are now refused if they do not comply with [RFC1123](https://tools.ietf.org/html/rfc1123) ([#20566](https://github.com/docker/docker/pull/20566)) ++ Docker learned how to use a SOCKS proxy ([#20366](https://github.com/docker/docker/pull/20366), [#18373](https://github.com/docker/docker/pull/18373)) ++ Docker now supports external credential stores ([#20107](https://github.com/docker/docker/pull/20107)) +* `docker ps` now supports displaying the list of volumes mounted inside a container ([#20017](https://github.com/docker/docker/pull/20017)) +* `docker info` now also reports Docker's root directory location ([#19986](https://github.com/docker/docker/pull/19986)) +- Docker now prohibits login in with an empty username (spaces are trimmed) ([#19806](https://github.com/docker/docker/pull/19806)) +* Docker events attributes are now sorted by key ([#19761](https://github.com/docker/docker/pull/19761)) +* `docker ps` no longer shows exported port for stopped containers ([#19483](https://github.com/docker/docker/pull/19483)) +- Docker now cleans after itself if a save/export command fails ([#17849](https://github.com/docker/docker/pull/17849)) +* Docker load learned how to display a progress bar ([#17329](https://github.com/docker/docker/pull/17329), [#120078](https://github.com/docker/docker/pull/20078)) + +### Distribution + +- Fix a panic that occurred when pulling an image with 0 layers ([#21222](https://github.com/docker/docker/pull/21222)) +- Fix a panic that could occur on error while pushing to a registry with a misconfigured token service ([#21212](https://github.com/docker/docker/pull/21212)) ++ All first-level delegation roles are now signed when doing a trusted push ([#21046](https://github.com/docker/docker/pull/21046)) ++ OAuth support for registries was added ([#20970](https://github.com/docker/docker/pull/20970)) +* `docker login` now handles token using the implementation found in [docker/distribution](https://github.com/docker/distribution) ([#20832](https://github.com/docker/docker/pull/20832)) +* `docker login` will no longer prompt for an email ([#20565](https://github.com/docker/docker/pull/20565)) +* Docker will now fallback to registry V1 if no basic auth credentials are available ([#20241](https://github.com/docker/docker/pull/20241)) +* Docker will now try to resume layer download where it left off after a network error/timeout ([#19840](https://github.com/docker/docker/pull/19840)) +- Fix generated manifest mediaType when pushing cross-repository ([#19509](https://github.com/docker/docker/pull/19509)) +- Fix docker requesting additional push credentials when pulling an image if Content Trust is enabled ([#20382](https://github.com/docker/docker/pull/20382)) + +### Logging + +- Fix a race in the journald log driver ([#21311](https://github.com/docker/docker/pull/21311)) +* Docker syslog driver now uses the RFC-5424 format when emitting logs ([#20121](https://github.com/docker/docker/pull/20121)) +* Docker GELF log driver now allows to specify the compression algorithm and level via the `gelf-compression-type` and `gelf-compression-level` options ([#19831](https://github.com/docker/docker/pull/19831)) +* Docker daemon learned to output uncolorized logs via the `--raw-logs` options ([#19794](https://github.com/docker/docker/pull/19794)) ++ Docker, on Windows platform, now includes an ETW (Event Tracing in Windows) logging driver named `etwlogs` ([#19689](https://github.com/docker/docker/pull/19689)) +* Journald log driver learned how to handle tags ([#19564](https://github.com/docker/docker/pull/19564)) ++ The fluentd log driver learned the following options: `fluentd-address`, `fluentd-buffer-limit`, `fluentd-retry-wait`, `fluentd-max-retries` and `fluentd-async-connect` ([#19439](https://github.com/docker/docker/pull/19439)) ++ Docker learned to send log to Google Cloud via the new `gcplogs` logging driver. ([#18766](https://github.com/docker/docker/pull/18766)) + + +### Misc + ++ When saving linked images together with `docker save` a subsequent `docker load` will correctly restore their parent/child relationship ([#21385](https://github.com/docker/docker/pull/21385)) ++ Support for building the Docker cli for OpenBSD was added ([#21325](https://github.com/docker/docker/pull/21325)) ++ Labels can now be applied at network, volume and image creation ([#21270](https://github.com/docker/docker/pull/21270)) +* The `dockremap` is now created as a system user ([#21266](https://github.com/docker/docker/pull/21266)) +- Fix a few response body leaks ([#21258](https://github.com/docker/docker/pull/21258)) +- Docker, when run as a service with systemd, will now properly manage its processes cgroups ([#20633](https://github.com/docker/docker/pull/20633)) +* `docker info` now reports the value of cgroup KernelMemory or emits a warning if it is not supported ([#20863](https://github.com/docker/docker/pull/20863)) +* `docker info` now also reports the cgroup driver in use ([#20388](https://github.com/docker/docker/pull/20388)) +* Docker completion is now available on PowerShell ([#19894](https://github.com/docker/docker/pull/19894)) +* `dockerinit` is no more ([#19490](https://github.com/docker/docker/pull/19490),[#19851](https://github.com/docker/docker/pull/19851)) ++ Support for building Docker on arm64 was added ([#19013](https://github.com/docker/docker/pull/19013)) ++ Experimental support for building docker.exe in a native Windows Docker installation ([#18348](https://github.com/docker/docker/pull/18348)) + +### Networking + +- Fix panic if a node is forcibly removed from the cluster ([#21671](https://github.com/docker/docker/pull/21671)) +- Fix "error creating vxlan interface" when starting a container in a Swarm cluster ([#21671](https://github.com/docker/docker/pull/21671)) +* `docker network inspect` will now report all endpoints whether they have an active container or not ([#21160](https://github.com/docker/docker/pull/21160)) ++ Experimental support for the MacVlan and IPVlan network drivers has been added ([#21122](https://github.com/docker/docker/pull/21122)) +* Output of `docker network ls` is now sorted by network name ([#20383](https://github.com/docker/docker/pull/20383)) +- Fix a bug where Docker would allow a network to be created with the reserved `default` name ([#19431](https://github.com/docker/docker/pull/19431)) +* `docker network inspect` returns whether a network is internal or not ([#19357](https://github.com/docker/docker/pull/19357)) ++ Control IPv6 via explicit option when creating a network (`docker network create --ipv6`). This shows up as a new `EnableIPv6` field in `docker network inspect` ([#17513](https://github.com/docker/docker/pull/17513)) +* Support for AAAA Records (aka IPv6 Service Discovery) in embedded DNS Server ([#21396](https://github.com/docker/docker/pull/21396)) +- Fix to not forward docker domain IPv6 queries to external servers ([#21396](https://github.com/docker/docker/pull/21396)) +* Multiple A/AAAA records from embedded DNS Server for DNS Round robin ([#21019](https://github.com/docker/docker/pull/21019)) +- Fix endpoint count inconsistency after an ungraceful dameon restart ([#21261](https://github.com/docker/docker/pull/21261)) +- Move the ownership of exposed ports and port-mapping options from Endpoint to Sandbox ([#21019](https://github.com/docker/docker/pull/21019)) +- Fixed a bug which prevents docker reload when host is configured with ipv6.disable=1 ([#21019](https://github.com/docker/docker/pull/21019)) +- Added inbuilt nil IPAM driver ([#21019](https://github.com/docker/docker/pull/21019)) +- Fixed bug in iptables.Exists() logic [#21019](https://github.com/docker/docker/pull/21019) +- Fixed a Veth interface leak when using overlay network ([#21019](https://github.com/docker/docker/pull/21019)) +- Fixed a bug which prevents docker reload after a network delete during shutdown ([#20214](https://github.com/docker/docker/pull/20214)) +- Make sure iptables chains are recreated on firewalld reload ([#20419](https://github.com/docker/docker/pull/20419)) +- Allow to pass global datastore during config reload ([#20419](https://github.com/docker/docker/pull/20419)) +- For anonymous containers use the alias name for IP to name mapping, ie:DNS PTR record ([#21019](https://github.com/docker/docker/pull/21019)) +- Fix a panic when deleting an entry from /etc/hosts file ([#21019](https://github.com/docker/docker/pull/21019)) +- Source the forwarded DNS queries from the container net namespace ([#21019](https://github.com/docker/docker/pull/21019)) +- Fix to retain the network internal mode config for bridge networks on daemon reload ([#21780] (https://github.com/docker/docker/pull/21780)) +- Fix to retain IPAM driver option configs on daemon reload ([#21914] (https://github.com/docker/docker/pull/21914)) + +### Plugins + +- Fix a file descriptor leak that would occur every time plugins were enumerated ([#20686](https://github.com/docker/docker/pull/20686)) +- Fix an issue where Authz plugin would corrupt the payload body when faced with a large amount of data ([#20602](https://github.com/docker/docker/pull/20602)) + +### Runtime + +- Fix a panic that could occur when cleanup after a container started with invalid parameters ([#21716](https://github.com/docker/docker/pull/21716)) +- Fix a race with event timers stopping early ([#21692](https://github.com/docker/docker/pull/21692)) +- Fix race conditions in the layer store, potentially corrupting the map and crashing the process ([#21677](https://github.com/docker/docker/pull/21677)) +- Un-deprecate auto-creation of host directories for mounts. This feature was marked deprecated in ([#21666](https://github.com/docker/docker/pull/21666)) + Docker 1.9, but was decided to be too much of a backward-incompatible change, so it was decided to keep the feature. ++ It is now possible for containers to share the NET and IPC namespaces when `userns` is enabled ([#21383](https://github.com/docker/docker/pull/21383)) ++ `docker inspect ` will now expose the rootfs layers ([#21370](https://github.com/docker/docker/pull/21370)) ++ Docker Windows gained a minimal `top` implementation ([#21354](https://github.com/docker/docker/pull/21354)) +* Docker learned to report the faulty exe when a container cannot be started due to its condition ([#21345](https://github.com/docker/docker/pull/21345)) +* Docker with device mapper will now refuse to run if `udev sync` is not available ([#21097](https://github.com/docker/docker/pull/21097)) +- Fix a bug where Docker would not validate the config file upon configuration reload ([#21089](https://github.com/docker/docker/pull/21089)) +- Fix a hang that would happen on attach if initial start was to fail ([#21048](https://github.com/docker/docker/pull/21048)) +- Fix an issue where registry service options in the daemon configuration file were not properly taken into account ([#21045](https://github.com/docker/docker/pull/21045)) +- Fix a race between the exec and resize operations ([#21022](https://github.com/docker/docker/pull/21022)) +- Fix an issue where nanoseconds were not correctly taken in account when filtering Docker events ([#21013](https://github.com/docker/docker/pull/21013)) +- Fix the handling of Docker command when passed a 64 bytes id ([#21002](https://github.com/docker/docker/pull/21002)) +* Docker will now return a `204` (i.e http.StatusNoContent) code when it successfully deleted a network ([#20977](https://github.com/docker/docker/pull/20977)) +- Fix a bug where the daemon would wait indefinitely in case the process it was about to killed had already exited on its own ([#20967](https://github.com/docker/docker/pull/20967) +* The devmapper driver learned the `dm.min_free_space` option. If the mapped device free space reaches the passed value, new device creation will be prohibited. ([#20786](https://github.com/docker/docker/pull/20786)) ++ Docker can now prevent processes in container to gain new privileges via the `--security-opt=no-new-privileges` flag ([#20727](https://github.com/docker/docker/pull/20727)) +- Starting a container with the `--device` option will now correctly resolves symlinks ([#20684](https://github.com/docker/docker/pull/20684)) ++ Docker now relies on [`containerd`](https://github.com/docker/containerd) and [`runc`](https://github.com/opencontainers/runc) to spawn containers. ([#20662](https://github.com/docker/docker/pull/20662)) +- Fix docker configuration reloading to only alter value present in the given config file ([#20604](https://github.com/docker/docker/pull/20604)) ++ Docker now allows setting a container hostname via the `--hostname` flag when `--net=host` ([#20177](https://github.com/docker/docker/pull/20177)) ++ Docker now allows executing privileged container while running with `--userns-remap` if both `--privileged` and the new `--userns=host` flag are specified ([#20111](https://github.com/docker/docker/pull/20111)) +- Fix Docker not cleaning up correctly old containers upon restarting after a crash ([#19679](https://github.com/docker/docker/pull/19679)) +* Docker will now error out if it doesn't recognize a configuration key within the config file ([#19517](https://github.com/docker/docker/pull/19517)) +- Fix container loading, on daemon startup, when they depends on a plugin running within a container ([#19500](https://github.com/docker/docker/pull/19500)) +* `docker update` learned how to change a container restart policy ([#19116](https://github.com/docker/docker/pull/19116)) +* `docker inspect` now also returns a new `State` field containing the container state in a human readable way (i.e. one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`)([#18966](https://github.com/docker/docker/pull/18966)) ++ Docker learned to limit the number of active pids (i.e. processes) within the container via the `pids-limit` flags. NOTE: This requires `CGROUP_PIDS=y` to be in the kernel configuration. ([#18697](https://github.com/docker/docker/pull/18697)) +- `docker load` now has a `--quiet` option to suppress the load output ([#20078](https://github.com/docker/docker/pull/20078)) +- Fix a bug in neighbor discovery for IPv6 peers ([#20842](https://github.com/docker/docker/pull/20842)) +- Fix a panic during cleanup if a container was started with invalid options ([#21802](https://github.com/docker/docker/pull/21802)) +- Fix a situation where a container cannot be stopped if the terminal is closed ([#21840](https://github.com/docker/docker/pull/21840)) + +### Security + +* Object with the `pcp_pmcd_t` selinux type were given management access to `/var/lib/docker(/.*)?` ([#21370](https://github.com/docker/docker/pull/21370)) +* `restart_syscall`, `copy_file_range`, `mlock2` joined the list of allowed calls in the default seccomp profile ([#21117](https://github.com/docker/docker/pull/21117), [#21262](https://github.com/docker/docker/pull/21262)) +* `send`, `recv` and `x32` were added to the list of allowed syscalls and arch in the default seccomp profile ([#19432](https://github.com/docker/docker/pull/19432)) +* Docker Content Trust now requests the server to perform snapshot signing ([#21046](https://github.com/docker/docker/pull/21046)) +* Support for using YubiKeys for Content Trust signing has been moved out of experimental ([#21591](https://github.com/docker/docker/pull/21591)) + +### Volumes + +* Output of `docker volume ls` is now sorted by volume name ([#20389](https://github.com/docker/docker/pull/20389)) +* Local volumes can now accept options similar to the unix `mount` tool ([#20262](https://github.com/docker/docker/pull/20262)) +- Fix an issue where one letter directory name could not be used as source for volumes ([#21106](https://github.com/docker/docker/pull/21106)) ++ `docker run -v` now accepts a new flag `nocopy`. This tells the runtime not to copy the container path content into the volume (which is the default behavior) ([#21223](https://github.com/docker/docker/pull/21223)) + +## 1.10.3 (2016-03-10) + +### Runtime + +- Fix Docker client exiting with an "Unrecognized input header" error [#20706](https://github.com/docker/docker/pull/20706) +- Fix Docker exiting if Exec is started with both `AttachStdin` and `Detach` [#20647](https://github.com/docker/docker/pull/20647) + +### Distribution + +- Fix a crash when pushing multiple images sharing the same layers to the same repository in parallel [#20831](https://github.com/docker/docker/pull/20831) +- Fix a panic when pushing images to a registry which uses a misconfigured token service [#21030](https://github.com/docker/docker/pull/21030) + +### Plugin system + +- Fix issue preventing volume plugins to start when SELinux is enabled [#20834](https://github.com/docker/docker/pull/20834) +- Prevent Docker from exiting if a volume plugin returns a null response for Get requests [#20682](https://github.com/docker/docker/pull/20682) +- Fix plugin system leaking file descriptors if a plugin has an error [#20680](https://github.com/docker/docker/pull/20680) + +### Security + +- Fix linux32 emulation to fail during docker build [#20672](https://github.com/docker/docker/pull/20672) + It was due to the `personality` syscall being blocked by the default seccomp profile. +- Fix Oracle XE 10g failing to start in a container [#20981](https://github.com/docker/docker/pull/20981) + It was due to the `ipc` syscall being blocked by the default seccomp profile. +- Fix user namespaces not working on Linux From Scratch [#20685](https://github.com/docker/docker/pull/20685) +- Fix issue preventing daemon to start if userns is enabled and the `subuid` or `subgid` files contain comments [#20725](https://github.com/docker/docker/pull/20725) + +## 1.10.2 (2016-02-22) + +### Runtime + +- Prevent systemd from deleting containers' cgroups when its configuration is reloaded [#20518](https://github.com/docker/docker/pull/20518) +- Fix SELinux issues by disregarding `--read-only` when mounting `/dev/mqueue` [#20333](https://github.com/docker/docker/pull/20333) +- Fix chown permissions used during `docker cp` when userns is used [#20446](https://github.com/docker/docker/pull/20446) +- Fix configuration loading issue with all booleans defaulting to `true` [#20471](https://github.com/docker/docker/pull/20471) +- Fix occasional panic with `docker logs -f` [#20522](https://github.com/docker/docker/pull/20522) + +### Distribution + +- Keep layer reference if deletion failed to avoid a badly inconsistent state [#20513](https://github.com/docker/docker/pull/20513) +- Handle gracefully a corner case when canceling migration [#20372](https://github.com/docker/docker/pull/20372) +- Fix docker import on compressed data [#20367](https://github.com/docker/docker/pull/20367) +- Fix tar-split files corruption during migration that later cause docker push and docker save to fail [#20458](https://github.com/docker/docker/pull/20458) + +### Networking + +- Fix daemon crash if embedded DNS is sent garbage [#20510](https://github.com/docker/docker/pull/20510) + +### Volumes + +- Fix issue with multiple volume references with same name [#20381](https://github.com/docker/docker/pull/20381) + +### Security + +- Fix potential cache corruption and delegation conflict issues [#20523](https://github.com/docker/docker/pull/20523) + +## 1.10.1 (2016-02-11) + +### Runtime + +* Do not stop daemon on migration hard failure [#20156](https://github.com/docker/docker/pull/20156) +- Fix various issues with migration to content-addressable images [#20058](https://github.com/docker/docker/pull/20058) +- Fix ZFS permission bug with user namespaces [#20045](https://github.com/docker/docker/pull/20045) +- Do not leak /dev/mqueue from the host to all containers, keep it container-specific [#19876](https://github.com/docker/docker/pull/19876) [#20133](https://github.com/docker/docker/pull/20133) +- Fix `docker ps --filter before=...` to not show stopped containers without providing `-a` flag [#20135](https://github.com/docker/docker/pull/20135) + +### Security + +- Fix issue preventing docker events to work properly with authorization plugin [#20002](https://github.com/docker/docker/pull/20002) + +### Distribution + +* Add additional verifications and prevent from uploading invalid data to registries [#20164](https://github.com/docker/docker/pull/20164) +- Fix regression preventing uppercase characters in image reference hostname [#20175](https://github.com/docker/docker/pull/20175) + +### Networking + +- Fix embedded DNS for user-defined networks in the presence of firewalld [#20060](https://github.com/docker/docker/pull/20060) +- Fix issue where removing a network during shutdown left Docker inoperable [#20181](https://github.com/docker/docker/issues/20181) [#20235](https://github.com/docker/docker/issues/20235) +- Embedded DNS is now able to return compressed results [#20181](https://github.com/docker/docker/issues/20181) +- Fix port-mapping issue with `userland-proxy=false` [#20181](https://github.com/docker/docker/issues/20181) + +### Logging + +- Fix bug where tcp+tls protocol would be rejected [#20109](https://github.com/docker/docker/pull/20109) + +### Volumes + +- Fix issue whereby older volume drivers would not receive volume options [#19983](https://github.com/docker/docker/pull/19983) + +### Misc + +- Remove TasksMax from Docker systemd service [#20167](https://github.com/docker/docker/pull/20167) + +## 1.10.0 (2016-02-04) + +**IMPORTANT**: Docker 1.10 uses a new content-addressable storage for images and layers. +A migration is performed the first time docker is run, and can take a significant amount of time depending on the number of images present. +Refer to this page on the wiki for more information: https://github.com/docker/docker/wiki/Engine-v1.10.0-content-addressability-migration +We also released a cool migration utility that enables you to perform the migration before updating to reduce downtime. +Engine 1.10 migrator can be found on Docker Hub: https://hub.docker.com/r/docker/v1.10-migrator/ + +### Runtime + ++ New `docker update` command that allows updating resource constraints on running containers [#15078](https://github.com/docker/docker/pull/15078) ++ Add `--tmpfs` flag to `docker run` to create a tmpfs mount in a container [#13587](https://github.com/docker/docker/pull/13587) ++ Add `--format` flag to `docker images` command [#17692](https://github.com/docker/docker/pull/17692) ++ Allow to set daemon configuration in a file and hot-reload it with the `SIGHUP` signal [#18587](https://github.com/docker/docker/pull/18587) ++ Updated docker events to include more meta-data and event types [#18888](https://github.com/docker/docker/pull/18888) + This change is backward compatible in the API, but not on the CLI. ++ Add `--blkio-weight-device` flag to `docker run` [#13959](https://github.com/docker/docker/pull/13959) ++ Add `--device-read-bps` and `--device-write-bps` flags to `docker run` [#14466](https://github.com/docker/docker/pull/14466) ++ Add `--device-read-iops` and `--device-write-iops` flags to `docker run` [#15879](https://github.com/docker/docker/pull/15879) ++ Add `--oom-score-adj` flag to `docker run` [#16277](https://github.com/docker/docker/pull/16277) ++ Add `--detach-keys` flag to `attach`, `run`, `start` and `exec` commands to override the default key sequence that detaches from a container [#15666](https://github.com/docker/docker/pull/15666) ++ Add `--shm-size` flag to `run`, `create` and `build` to set the size of `/dev/shm` [#16168](https://github.com/docker/docker/pull/16168) ++ Show the number of running, stopped, and paused containers in `docker info` [#19249](https://github.com/docker/docker/pull/19249) ++ Show the `OSType` and `Architecture` in `docker info` [#17478](https://github.com/docker/docker/pull/17478) ++ Add `--cgroup-parent` flag on `daemon` to set cgroup parent for all containers [#19062](https://github.com/docker/docker/pull/19062) ++ Add `-L` flag to docker cp to follow symlinks [#16613](https://github.com/docker/docker/pull/16613) ++ New `status=dead` filter for `docker ps` [#17908](https://github.com/docker/docker/pull/17908) +* Change `docker run` exit codes to distinguish between runtime and application errors [#14012](https://github.com/docker/docker/pull/14012) +* Enhance `docker events --since` and `--until` to support nanoseconds and timezones [#17495](https://github.com/docker/docker/pull/17495) +* Add `--all`/`-a` flag to `stats` to include both running and stopped containers [#16742](https://github.com/docker/docker/pull/16742) +* Change the default cgroup-driver to `cgroupfs` [#17704](https://github.com/docker/docker/pull/17704) +* Emit a "tag" event when tagging an image with `build -t` [#17115](https://github.com/docker/docker/pull/17115) +* Best effort for linked containers' start order when starting the daemon [#18208](https://github.com/docker/docker/pull/18208) +* Add ability to add multiple tags on `build` [#15780](https://github.com/docker/docker/pull/15780) +* Permit `OPTIONS` request against any url, thus fixing issue with CORS [#19569](https://github.com/docker/docker/pull/19569) +- Fix the `--quiet` flag on `docker build` to actually be quiet [#17428](https://github.com/docker/docker/pull/17428) +- Fix `docker images --filter dangling=false` to now show all non-dangling images [#19326](https://github.com/docker/docker/pull/19326) +- Fix race condition causing autorestart turning off on restart [#17629](https://github.com/docker/docker/pull/17629) +- Recognize GPFS filesystems [#19216](https://github.com/docker/docker/pull/19216) +- Fix obscure bug preventing to start containers [#19751](https://github.com/docker/docker/pull/19751) +- Forbid `exec` during container restart [#19722](https://github.com/docker/docker/pull/19722) +- devicemapper: Increasing `--storage-opt dm.basesize` will now increase the base device size on daemon restart [#19123](https://github.com/docker/docker/pull/19123) + +### Security + ++ Add `--userns-remap` flag to `daemon` to support user namespaces (previously in experimental) [#19187](https://github.com/docker/docker/pull/19187) ++ Add support for custom seccomp profiles in `--security-opt` [#17989](https://github.com/docker/docker/pull/17989) ++ Add default seccomp profile [#18780](https://github.com/docker/docker/pull/18780) ++ Add `--authorization-plugin` flag to `daemon` to customize ACLs [#15365](https://github.com/docker/docker/pull/15365) ++ Docker Content Trust now supports the ability to read and write user delegations [#18887](https://github.com/docker/docker/pull/18887) + This is an optional, opt-in feature that requires the explicit use of the Notary command-line utility in order to be enabled. + Enabling delegation support in a specific repository will break the ability of Docker 1.9 and 1.8 to pull from that repository, if content trust is enabled. +* Allow SELinux to run in a container when using the BTRFS storage driver [#16452](https://github.com/docker/docker/pull/16452) + +### Distribution + +* Use content-addressable storage for images and layers [#17924](https://github.com/docker/docker/pull/17924) + Note that a migration is performed the first time docker is run; it can take a significant amount of time depending on the number of images and containers present. + Images no longer depend on the parent chain but contain a list of layer references. + `docker load`/`docker save` tarballs now also contain content-addressable image configurations. + For more information: https://github.com/docker/docker/wiki/Engine-v1.10.0-content-addressability-migration +* Add support for the new [manifest format ("schema2")](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md) [#18785](https://github.com/docker/docker/pull/18785) +* Lots of improvements for push and pull: performance++, retries on failed downloads, cancelling on client disconnect [#18353](https://github.com/docker/docker/pull/18353), [#18418](https://github.com/docker/docker/pull/18418), [#19109](https://github.com/docker/docker/pull/19109), [#18353](https://github.com/docker/docker/pull/18353) +* Limit v1 protocol fallbacks [#18590](https://github.com/docker/docker/pull/18590) +- Fix issue where docker could hang indefinitely waiting for a nonexistent process to pull an image [#19743](https://github.com/docker/docker/pull/19743) + +### Networking + ++ Use DNS-based discovery instead of `/etc/hosts` [#19198](https://github.com/docker/docker/pull/19198) ++ Support for network-scoped alias using `--net-alias` on `run` and `--alias` on `network connect` [#19242](https://github.com/docker/docker/pull/19242) ++ Add `--ip` and `--ip6` on `run` and `network connect` to support custom IP addresses for a container in a network [#19001](https://github.com/docker/docker/pull/19001) ++ Add `--ipam-opt` to `network create` for passing custom IPAM options [#17316](https://github.com/docker/docker/pull/17316) ++ Add `--internal` flag to `network create` to restrict external access to and from the network [#19276](https://github.com/docker/docker/pull/19276) ++ Add `kv.path` option to `--cluster-store-opt` [#19167](https://github.com/docker/docker/pull/19167) ++ Add `discovery.heartbeat` and `discovery.ttl` options to `--cluster-store-opt` to configure discovery TTL and heartbeat timer [#18204](https://github.com/docker/docker/pull/18204) ++ Add `--format` flag to `network inspect` [#17481](https://github.com/docker/docker/pull/17481) ++ Add `--link` to `network connect` to provide a container-local alias [#19229](https://github.com/docker/docker/pull/19229) ++ Support for Capability exchange with remote IPAM plugins [#18775](https://github.com/docker/docker/pull/18775) ++ Add `--force` to `network disconnect` to force container to be disconnected from network [#19317](https://github.com/docker/docker/pull/19317) +* Support for multi-host networking using built-in overlay driver for all engine supported kernels: 3.10+ [#18775](https://github.com/docker/docker/pull/18775) +* `--link` is now supported on `docker run` for containers in user-defined network [#19229](https://github.com/docker/docker/pull/19229) +* Enhance `docker network rm` to allow removing multiple networks [#17489](https://github.com/docker/docker/pull/17489) +* Include container names in `network inspect` [#17615](https://github.com/docker/docker/pull/17615) +* Include auto-generated subnets for user-defined networks in `network inspect` [#17316](https://github.com/docker/docker/pull/17316) +* Add `--filter` flag to `network ls` to hide predefined networks [#17782](https://github.com/docker/docker/pull/17782) +* Add support for network connect/disconnect to stopped containers [#18906](https://github.com/docker/docker/pull/18906) +* Add network ID to container inspect [#19323](https://github.com/docker/docker/pull/19323) +- Fix MTU issue where Docker would not start with two or more default routes [#18108](https://github.com/docker/docker/pull/18108) +- Fix duplicate IP address for containers [#18106](https://github.com/docker/docker/pull/18106) +- Fix issue preventing sometimes docker from creating the bridge network [#19338](https://github.com/docker/docker/pull/19338) +- Do not substitute 127.0.0.1 name server when using `--net=host` [#19573](https://github.com/docker/docker/pull/19573) + +### Logging + ++ New logging driver for Splunk [#16488](https://github.com/docker/docker/pull/16488) ++ Add support for syslog over TCP+TLS [#18998](https://github.com/docker/docker/pull/18998) +* Enhance `docker logs --since` and `--until` to support nanoseconds and time [#17495](https://github.com/docker/docker/pull/17495) +* Enhance AWS logs to auto-detect region [#16640](https://github.com/docker/docker/pull/16640) + +### Volumes + ++ Add support to set the mount propagation mode for a volume [#17034](https://github.com/docker/docker/pull/17034) +* Add `ls` and `inspect` endpoints to volume plugin API [#16534](https://github.com/docker/docker/pull/16534) + Existing plugins need to make use of these new APIs to satisfy users' expectation + For that, please use the new MIME type `application/vnd.docker.plugins.v1.2+json` [#19549](https://github.com/docker/docker/pull/19549) +- Fix data not being copied to named volumes [#19175](https://github.com/docker/docker/pull/19175) +- Fix issues preventing volume drivers from being containerized [#19500](https://github.com/docker/docker/pull/19500) +- Fix `docker volumes ls --dangling=false` to now show all non-dangling volumes [#19671](https://github.com/docker/docker/pull/19671) +- Do not remove named volumes on container removal [#19568](https://github.com/docker/docker/pull/19568) +- Allow external volume drivers to host anonymous volumes [#19190](https://github.com/docker/docker/pull/19190) + +### Builder + ++ Add support for `**` in `.dockerignore` to wildcard multiple levels of directories [#17090](https://github.com/docker/docker/pull/17090) +- Fix handling of UTF-8 characters in Dockerfiles [#17055](https://github.com/docker/docker/pull/17055) +- Fix permissions problem when reading from STDIN [#19283](https://github.com/docker/docker/pull/19283) + +### Client + ++ Add support for overriding the API version to use via an `DOCKER_API_VERSION` environment-variable [#15964](https://github.com/docker/docker/pull/15964) +- Fix a bug preventing Windows clients to log in to Docker Hub [#19891](https://github.com/docker/docker/pull/19891) + +### Misc + +* systemd: Set TasksMax in addition to LimitNPROC in systemd service file [#19391](https://github.com/docker/docker/pull/19391) + +### Deprecations + +* Remove LXC support. The LXC driver was deprecated in Docker 1.8, and has now been removed [#17700](https://github.com/docker/docker/pull/17700) +* Remove `--exec-driver` daemon flag, because it is no longer in use [#17700](https://github.com/docker/docker/pull/17700) +* Remove old deprecated single-dashed long CLI flags (such as `-rm`; use `--rm` instead) [#17724](https://github.com/docker/docker/pull/17724) +* Deprecate HostConfig at API container start [#17799](https://github.com/docker/docker/pull/17799) +* Deprecate docker packages for newly EOL'd Linux distributions: Fedora 21 and Ubuntu 15.04 (Vivid) [#18794](https://github.com/docker/docker/pull/18794), [#18809](https://github.com/docker/docker/pull/18809) +* Deprecate `-f` flag for docker tag [#18350](https://github.com/docker/docker/pull/18350) + +## 1.9.1 (2015-11-21) + +### Runtime + +- Do not prevent daemon from booting if images could not be restored (#17695) +- Force IPC mount to unmount on daemon shutdown/init (#17539) +- Turn IPC unmount errors into warnings (#17554) +- Fix `docker stats` performance regression (#17638) +- Clarify cryptic error message upon `docker logs` if `--log-driver=none` (#17767) +- Fix seldom panics (#17639, #17634, #17703) +- Fix opq whiteouts problems for files with dot prefix (#17819) +- devicemapper: try defaulting to xfs instead of ext4 for performance reasons (#17903, #17918) +- devicemapper: fix displayed fs in docker info (#17974) +- selinux: only relabel if user requested so with the `z` option (#17450, #17834) +- Do not make network calls when normalizing names (#18014) + +### Client + +- Fix `docker login` on windows (#17738) +- Fix bug with `docker inspect` output when not connected to daemon (#17715) +- Fix `docker inspect -f {{.HostConfig.Dns}} somecontainer` (#17680) + +### Builder + +- Fix regression with symlink behavior in ADD/COPY (#17710) + +### Networking + +- Allow passing a network ID as an argument for `--net` (#17558) +- Fix connect to host and prevent disconnect from host for `host` network (#17476) +- Fix `--fixed-cidr` issue when gateway ip falls in ip-range and ip-range is + not the first block in the network (#17853) +- Restore deterministic `IPv6` generation from `MAC` address on default `bridge` network (#17890) +- Allow port-mapping only for endpoints created on docker run (#17858) +- Fixed an endpoint delete issue with a possible stale sbox (#18102) + +### Distribution + +- Correct parent chain in v2 push when v1Compatibility files on the disk are inconsistent (#18047) + +## 1.9.0 (2015-11-03) + +### Runtime + ++ `docker stats` now returns block IO metrics (#15005) ++ `docker stats` now details network stats per interface (#15786) ++ Add `ancestor=` filter to `docker ps --filter` flag to filter +containers based on their ancestor images (#14570) ++ Add `label=` filter to `docker ps --filter` to filter containers +based on label (#16530) ++ Add `--kernel-memory` flag to `docker run` (#14006) ++ Add `--message` flag to `docker import` allowing to specify an optional +message (#15711) ++ Add `--privileged` flag to `docker exec` (#14113) ++ Add `--stop-signal` flag to `docker run` allowing to replace the container +process stopping signal (#15307) ++ Add a new `unless-stopped` restart policy (#15348) ++ Inspecting an image now returns tags (#13185) ++ Add container size information to `docker inspect` (#15796) ++ Add `RepoTags` and `RepoDigests` field to `/images/{name:.*}/json` (#17275) +- Remove the deprecated `/container/ps` endpoint from the API (#15972) +- Send and document correct HTTP codes for `/exec//start` (#16250) +- Share shm and mqueue between containers sharing IPC namespace (#15862) +- Event stream now shows OOM status when `--oom-kill-disable` is set (#16235) +- Ensure special network files (/etc/hosts etc.) are read-only if bind-mounted +with `ro` option (#14965) +- Improve `rmi` performance (#16890) +- Do not update /etc/hosts for the default bridge network, except for links (#17325) +- Fix conflict with duplicate container names (#17389) +- Fix an issue with incorrect template execution in `docker inspect` (#17284) +- DEPRECATE `-c` short flag variant for `--cpu-shares` in docker run (#16271) + +### Client + ++ Allow `docker import` to import from local files (#11907) + +### Builder + ++ Add a `STOPSIGNAL` Dockerfile instruction allowing to set a different +stop-signal for the container process (#15307) ++ Add an `ARG` Dockerfile instruction and a `--build-arg` flag to `docker build` +that allows to add build-time environment variables (#15182) +- Improve cache miss performance (#16890) + +### Storage + +- devicemapper: Implement deferred deletion capability (#16381) + +## Networking + ++ `docker network` exits experimental and is part of standard release (#16645) ++ New network top-level concept, with associated subcommands and API (#16645) + WARNING: the API is different from the experimental API ++ Support for multiple isolated/micro-segmented networks (#16645) ++ Built-in multihost networking using VXLAN based overlay driver (#14071) ++ Support for third-party network plugins (#13424) ++ Ability to dynamically connect containers to multiple networks (#16645) ++ Support for user-defined IP address management via pluggable IPAM drivers (#16910) ++ Add daemon flags `--cluster-store` and `--cluster-advertise` for built-in nodes discovery (#16229) ++ Add `--cluster-store-opt` for setting up TLS settings (#16644) ++ Add `--dns-opt` to the daemon (#16031) +- DEPRECATE following container `NetworkSettings` fields in API v1.21: `EndpointID`, `Gateway`, + `GlobalIPv6Address`, `GlobalIPv6PrefixLen`, `IPAddress`, `IPPrefixLen`, `IPv6Gateway` and `MacAddress`. + Those are now specific to the `bridge` network. Use `NetworkSettings.Networks` to inspect + the networking settings of a container per network. + +### Volumes + ++ New top-level `volume` subcommand and API (#14242) +- Move API volume driver settings to host-specific config (#15798) +- Print an error message if volume name is not unique (#16009) +- Ensure volumes created from Dockerfiles always use the local volume driver +(#15507) +- DEPRECATE auto-creating missing host paths for bind mounts (#16349) + +### Logging + ++ Add `awslogs` logging driver for Amazon CloudWatch (#15495) ++ Add generic `tag` log option to allow customizing container/image +information passed to driver (e.g. show container names) (#15384) +- Implement the `docker logs` endpoint for the journald driver (#13707) +- DEPRECATE driver-specific log tags (e.g. `syslog-tag`, etc.) (#15384) + +### Distribution + ++ `docker search` now works with partial names (#16509) +- Push optimization: avoid buffering to file (#15493) +- The daemon will display progress for images that were already being pulled +by another client (#15489) +- Only permissions required for the current action being performed are requested (#) ++ Renaming trust keys (and respective environment variables) from `offline` to +`root` and `tagging` to `repository` (#16894) +- DEPRECATE trust key environment variables +`DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and +`DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` (#16894) + +### Security + ++ Add SELinux profiles to the rpm package (#15832) +- Fix various issues with AppArmor profiles provided in the deb package +(#14609) +- Add AppArmor policy that prevents writing to /proc (#15571) + +## 1.8.3 (2015-10-12) + +### Distribution + +- Fix layer IDs lead to local graph poisoning (CVE-2014-8178) +- Fix manifest validation and parsing logic errors allow pull-by-digest validation bypass (CVE-2014-8179) ++ Add `--disable-legacy-registry` to prevent a daemon from using a v1 registry + +## 1.8.2 (2015-09-10) + +### Distribution + +- Fixes rare edge case of handling GNU LongLink and LongName entries. +- Fix ^C on docker pull. +- Fix docker pull issues on client disconnection. +- Fix issue that caused the daemon to panic when loggers weren't configured properly. +- Fix goroutine leak pulling images from registry V2. + +### Runtime + +- Fix a bug mounting cgroups for docker daemons running inside docker containers. +- Initialize log configuration properly. + +### Client: + +- Handle `-q` flag in `docker ps` properly when there is a default format. + +### Networking + +- Fix several corner cases with netlink. + +### Contrib + +- Fix several issues with bash completion. + +## 1.8.1 (2015-08-12) + +### Distribution + +* Fix a bug where pushing multiple tags would result in invalid images + +## 1.8.0 (2015-08-11) + +### Distribution + ++ Trusted pull, push and build, disabled by default +* Make tar layers deterministic between registries +* Don't allow deleting the image of running containers +* Check if a tag name to load is a valid digest +* Allow one character repository names +* Add a more accurate error description for invalid tag name +* Make build cache ignore mtime + +### Cli + ++ Add support for DOCKER_CONFIG/--config to specify config file dir ++ Add --type flag for docker inspect command ++ Add formatting options to `docker ps` with `--format` ++ Replace `docker -d` with new subcommand `docker daemon` +* Zsh completion updates and improvements +* Add some missing events to bash completion +* Support daemon urls with base paths in `docker -H` +* Validate status= filter to docker ps +* Display when a container is in --net=host in docker ps +* Extend docker inspect to export image metadata related to graph driver +* Restore --default-gateway{,-v6} daemon options +* Add missing unpublished ports in docker ps +* Allow duration strings in `docker events` as --since/--until +* Expose more mounts information in `docker inspect` + +### Runtime + ++ Add new Fluentd logging driver ++ Allow `docker import` to load from local files ++ Add logging driver for GELF via UDP ++ Allow to copy files from host to containers with `docker cp` ++ Promote volume drivers from experimental to master ++ Add rollover options to json-file log driver, and --log-driver-opts flag ++ Add memory swappiness tuning options +* Remove cgroup read-only flag when privileged +* Make /proc, /sys, & /dev readonly for readonly containers +* Add cgroup bind mount by default +* Overlay: Export metadata for container and image in `docker inspect` +* Devicemapper: external device activation +* Devicemapper: Compare uuid of base device on startup +* Remove RC4 from the list of registry cipher suites +* Add syslog-facility option +* LXC execdriver compatibility with recent LXC versions +* Mark LXC execriver as deprecated (to be removed with the migration to runc) + +### Plugins + +* Separate plugin sockets and specs locations +* Allow TLS connections to plugins + +### Bug fixes + +- Add missing 'Names' field to /containers/json API output +- Make `docker rmi` of dangling images safe while pulling +- Devicemapper: Change default basesize to 100G +- Go Scheduler issue with sync.Mutex and gcc +- Fix issue where Search API endpoint would panic due to empty AuthConfig +- Set image canonical names correctly +- Check dockerinit only if lxc driver is used +- Fix ulimit usage of nproc +- Always attach STDIN if -i,--interactive is specified +- Show error messages when saving container state fails +- Fixed incorrect assumption on --bridge=none treated as disable network +- Check for invalid port specifications in host configuration +- Fix endpoint leave failure for --net=host mode +- Fix goroutine leak in the stats API if the container is not running +- Check for apparmor file before reading it +- Fix DOCKER_TLS_VERIFY being ignored +- Set umask to the default on startup +- Correct the message of pause and unpause a non-running container +- Adjust disallowed CpuShares in container creation +- ZFS: correctly apply selinux context +- Display empty string instead of when IP opt is nil +- `docker kill` returns error when container is not running +- Fix COPY/ADD quoted/json form +- Fix goroutine leak on logs -f with no output +- Remove panic in nat package on invalid hostport +- Fix container linking in Fedora 22 +- Fix error caused using default gateways outside of the allocated range +- Format times in inspect command with a template as RFC3339Nano +- Make registry client to accept 2xx and 3xx http status responses as successful +- Fix race issue that caused the daemon to crash with certain layer downloads failed in a specific order. +- Fix error when the docker ps format was not valid. +- Remove redundant ip forward check. +- Fix issue trying to push images to repository mirrors. +- Fix error cleaning up network entrypoints when there is an initialization issue. + +## 1.7.1 (2015-07-14) + +#### Runtime + +- Fix default user spawning exec process with `docker exec` +- Make `--bridge=none` not to configure the network bridge +- Publish networking stats properly +- Fix implicit devicemapper selection with static binaries +- Fix socket connections that hung intermittently +- Fix bridge interface creation on CentOS/RHEL 6.6 +- Fix local dns lookups added to resolv.conf +- Fix copy command mounting volumes +- Fix read/write privileges in volumes mounted with --volumes-from + +#### Remote API + +- Fix unmarshalling of Command and Entrypoint +- Set limit for minimum client version supported +- Validate port specification +- Return proper errors when attach/reattach fail + +#### Distribution + +- Fix pulling private images +- Fix fallback between registry V2 and V1 + +## 1.7.0 (2015-06-16) + +#### Runtime ++ Experimental feature: support for out-of-process volume plugins +* The userland proxy can be disabled in favor of hairpin NAT using the daemon’s `--userland-proxy=false` flag +* The `exec` command supports the `-u|--user` flag to specify the new process owner ++ Default gateway for containers can be specified daemon-wide using the `--default-gateway` and `--default-gateway-v6` flags ++ The CPU CFS (Completely Fair Scheduler) quota can be set in `docker run` using `--cpu-quota` ++ Container block IO can be controlled in `docker run` using`--blkio-weight` ++ ZFS support ++ The `docker logs` command supports a `--since` argument ++ UTS namespace can be shared with the host with `docker run --uts=host` + +#### Quality +* Networking stack was entirely rewritten as part of the libnetwork effort +* Engine internals refactoring +* Volumes code was entirely rewritten to support the plugins effort ++ Sending SIGUSR1 to a daemon will dump all goroutines stacks without exiting + +#### Build ++ Support ${variable:-value} and ${variable:+value} syntax for environment variables ++ Support resource management flags `--cgroup-parent`, `--cpu-period`, `--cpu-quota`, `--cpuset-cpus`, `--cpuset-mems` ++ git context changes with branches and directories +* The .dockerignore file support exclusion rules + +#### Distribution ++ Client support for v2 mirroring support for the official registry + +#### Bugfixes +* Firewalld is now supported and will automatically be used when available +* mounting --device recursively + +## 1.6.2 (2015-05-13) + +#### Runtime +- Revert change prohibiting mounting into /sys + +## 1.6.1 (2015-05-07) + +#### Security +- Fix read/write /proc paths (CVE-2015-3630) +- Prohibit VOLUME /proc and VOLUME / (CVE-2015-3631) +- Fix opening of file-descriptor 1 (CVE-2015-3627) +- Fix symlink traversal on container respawn allowing local privilege escalation (CVE-2015-3629) +- Prohibit mount of /sys + +#### Runtime +- Update AppArmor policy to not allow mounts + +## 1.6.0 (2015-04-07) + +#### Builder ++ Building images from an image ID ++ Build containers with resource constraints, ie `docker build --cpu-shares=100 --memory=1024m...` ++ `commit --change` to apply specified Dockerfile instructions while committing the image ++ `import --change` to apply specified Dockerfile instructions while importing the image ++ Builds no longer continue in the background when canceled with CTRL-C + +#### Client ++ Windows Support + +#### Runtime ++ Container and image Labels ++ `--cgroup-parent` for specifying a parent cgroup to place container cgroup within ++ Logging drivers, `json-file`, `syslog`, or `none` ++ Pulling images by ID ++ `--ulimit` to set the ulimit on a container ++ `--default-ulimit` option on the daemon which applies to all created containers (and overwritten by `--ulimit` on run) + +## 1.5.0 (2015-02-10) + +#### Builder ++ Dockerfile to use for a given `docker build` can be specified with the `-f` flag +* Dockerfile and .dockerignore files can be themselves excluded as part of the .dockerignore file, thus preventing modifications to these files invalidating ADD or COPY instructions cache +* ADD and COPY instructions accept relative paths +* Dockerfile `FROM scratch` instruction is now interpreted as a no-base specifier +* Improve performance when exposing a large number of ports + +#### Hack ++ Allow client-side only integration tests for Windows +* Include docker-py integration tests against Docker daemon as part of our test suites + +#### Packaging ++ Support for the new version of the registry HTTP API +* Speed up `docker push` for images with a majority of already existing layers +- Fixed contacting a private registry through a proxy + +#### Remote API ++ A new endpoint will stream live container resource metrics and can be accessed with the `docker stats` command ++ Containers can be renamed using the new `rename` endpoint and the associated `docker rename` command +* Container `inspect` endpoint show the ID of `exec` commands running in this container +* Container `inspect` endpoint show the number of times Docker auto-restarted the container +* New types of event can be streamed by the `events` endpoint: ‘OOM’ (container died with out of memory), ‘exec_create’, and ‘exec_start' +- Fixed returned string fields which hold numeric characters incorrectly omitting surrounding double quotes + +#### Runtime ++ Docker daemon has full IPv6 support ++ The `docker run` command can take the `--pid=host` flag to use the host PID namespace, which makes it possible for example to debug host processes using containerized debugging tools ++ The `docker run` command can take the `--read-only` flag to make the container’s root filesystem mounted as readonly, which can be used in combination with volumes to force a container’s processes to only write to locations that will be persisted ++ Container total memory usage can be limited for `docker run` using the `--memory-swap` flag +* Major stability improvements for devicemapper storage driver +* Better integration with host system: containers will reflect changes to the host's `/etc/resolv.conf` file when restarted +* Better integration with host system: per-container iptable rules are moved to the DOCKER chain +- Fixed container exiting on out of memory to return an invalid exit code + +#### Other +* The HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables are properly taken into account by the client when connecting to the Docker daemon + +## 1.4.1 (2014-12-15) + +#### Runtime +- Fix issue with volumes-from and bind mounts not being honored after create + +## 1.4.0 (2014-12-11) + +#### Notable Features since 1.3.0 ++ Set key=value labels to the daemon (displayed in `docker info`), applied with + new `-label` daemon flag ++ Add support for `ENV` in Dockerfile of the form: + `ENV name=value name2=value2...` ++ New Overlayfs Storage Driver ++ `docker info` now returns an `ID` and `Name` field ++ Filter events by event name, container, or image ++ `docker cp` now supports copying from container volumes +- Fixed `docker tag`, so it honors `--force` when overriding a tag for existing + image. + +## 1.3.3 (2014-12-11) + +#### Security +- Fix path traversal vulnerability in processing of absolute symbolic links (CVE-2014-9356) +- Fix decompression of xz image archives, preventing privilege escalation (CVE-2014-9357) +- Validate image IDs (CVE-2014-9358) + +#### Runtime +- Fix an issue when image archives are being read slowly + +#### Client +- Fix a regression related to stdin redirection +- Fix a regression with `docker cp` when destination is the current directory + +## 1.3.2 (2014-11-20) + +#### Security +- Fix tar breakout vulnerability +* Extractions are now sandboxed chroot +- Security options are no longer committed to images + +#### Runtime +- Fix deadlock in `docker ps -f exited=1` +- Fix a bug when `--volumes-from` references a container that failed to start + +#### Registry ++ `--insecure-registry` now accepts CIDR notation such as 10.1.0.0/16 +* Private registries whose IPs fall in the 127.0.0.0/8 range do no need the `--insecure-registry` flag +- Skip the experimental registry v2 API when mirroring is enabled + +## 1.3.1 (2014-10-28) + +#### Security +* Prevent fallback to SSL protocols < TLS 1.0 for client, daemon and registry ++ Secure HTTPS connection to registries with certificate verification and without HTTP fallback unless `--insecure-registry` is specified + +#### Runtime +- Fix issue where volumes would not be shared + +#### Client +- Fix issue with `--iptables=false` not automatically setting `--ip-masq=false` +- Fix docker run output to non-TTY stdout + +#### Builder +- Fix escaping `$` for environment variables +- Fix issue with lowercase `onbuild` Dockerfile instruction +- Restrict environment variable expansion to `ENV`, `ADD`, `COPY`, `WORKDIR`, `EXPOSE`, `VOLUME` and `USER` + +## 1.3.0 (2014-10-14) + +#### Notable features since 1.2.0 ++ Docker `exec` allows you to run additional processes inside existing containers ++ Docker `create` gives you the ability to create a container via the CLI without executing a process ++ `--security-opts` options to allow user to customize container labels and apparmor profiles ++ Docker `ps` filters +- Wildcard support to COPY/ADD ++ Move production URLs to get.docker.com from get.docker.io ++ Allocate IP address on the bridge inside a valid CIDR ++ Use drone.io for PR and CI testing ++ Ability to setup an official registry mirror ++ Ability to save multiple images with docker `save` + +## 1.2.0 (2014-08-20) + +#### Runtime ++ Make /etc/hosts /etc/resolv.conf and /etc/hostname editable at runtime ++ Auto-restart containers using policies ++ Use /var/lib/docker/tmp for large temporary files ++ `--cap-add` and `--cap-drop` to tweak what linux capability you want ++ `--device` to use devices in containers + +#### Client ++ `docker search` on private registries ++ Add `exited` filter to `docker ps --filter` +* `docker rm -f` now kills instead of stop ++ Support for IPv6 addresses in `--dns` flag + +#### Proxy ++ Proxy instances in separate processes +* Small bug fix on UDP proxy + +## 1.1.2 (2014-07-23) + +#### Runtime ++ Fix port allocation for existing containers ++ Fix containers restart on daemon restart + +#### Packaging ++ Fix /etc/init.d/docker issue on Debian + +## 1.1.1 (2014-07-09) + +#### Builder +* Fix issue with ADD + +## 1.1.0 (2014-07-03) + +#### Notable features since 1.0.1 ++ Add `.dockerignore` support ++ Pause containers during `docker commit` ++ Add `--tail` to `docker logs` + +#### Builder ++ Allow a tar file as context for `docker build` +* Fix issue with white-spaces and multi-lines in `Dockerfiles` + +#### Runtime +* Overall performance improvements +* Allow `/` as source of `docker run -v` +* Fix port allocation +* Fix bug in `docker save` +* Add links information to `docker inspect` + +#### Client +* Improve command line parsing for `docker commit` + +#### Remote API +* Improve status code for the `start` and `stop` endpoints + +## 1.0.1 (2014-06-19) + +#### Notable features since 1.0.0 +* Enhance security for the LXC driver + +#### Builder +* Fix `ONBUILD` instruction passed to grandchildren + +#### Runtime +* Fix events subscription +* Fix /etc/hostname file with host networking +* Allow `-h` and `--net=none` +* Fix issue with hotplug devices in `--privileged` + +#### Client +* Fix artifacts with events +* Fix a panic with empty flags +* Fix `docker cp` on Mac OS X + +#### Miscellaneous +* Fix compilation on Mac OS X +* Fix several races + +## 1.0.0 (2014-06-09) + +#### Notable features since 0.12.0 +* Production support + +## 0.12.0 (2014-06-05) + +#### Notable features since 0.11.0 +* 40+ various improvements to stability, performance and usability +* New `COPY` Dockerfile instruction to allow copying a local file from the context into the container without ever extracting if the file is a tar file +* Inherit file permissions from the host on `ADD` +* New `pause` and `unpause` commands to allow pausing and unpausing of containers using cgroup freezer +* The `images` command has a `-f`/`--filter` option to filter the list of images +* Add `--force-rm` to clean up after a failed build +* Standardize JSON keys in Remote API to CamelCase +* Pull from a docker run now assumes `latest` tag if not specified +* Enhance security on Linux capabilities and device nodes + +## 0.11.1 (2014-05-07) + +#### Registry +- Fix push and pull to private registry + +## 0.11.0 (2014-05-07) + +#### Notable features since 0.10.0 + +* SELinux support for mount and process labels +* Linked containers can be accessed by hostname +* Use the net `--net` flag to allow advanced network configuration such as host networking so that containers can use the host's network interfaces +* Add a ping endpoint to the Remote API to do healthchecks of your docker daemon +* Logs can now be returned with an optional timestamp +* Docker now works with registries that support SHA-512 +* Multiple registry endpoints are supported to allow registry mirrors + +## 0.10.0 (2014-04-08) + +#### Builder +- Fix printing multiple messages on a single line. Fixes broken output during builds. +- Follow symlinks inside container's root for ADD build instructions. +- Fix EXPOSE caching. + +#### Documentation +- Add the new options of `docker ps` to the documentation. +- Add the options of `docker restart` to the documentation. +- Update daemon docs and help messages for --iptables and --ip-forward. +- Updated apt-cacher-ng docs example. +- Remove duplicate description of --mtu from docs. +- Add missing -t and -v for `docker images` to the docs. +- Add fixes to the cli docs. +- Update libcontainer docs. +- Update images in docs to remove references to AUFS and LXC. +- Update the nodejs_web_app in the docs to use the new epel RPM address. +- Fix external link on security of containers. +- Update remote API docs. +- Add image size to history docs. +- Be explicit about binding to all interfaces in redis example. +- Document DisableNetwork flag in the 1.10 remote api. +- Document that `--lxc-conf` is lxc only. +- Add chef usage documentation. +- Add example for an image with multiple for `docker load`. +- Explain what `docker run -a` does in the docs. + +#### Contrib +- Add variable for DOCKER_LOGFILE to sysvinit and use append instead of overwrite in opening the logfile. +- Fix init script cgroup mounting workarounds to be more similar to cgroupfs-mount and thus work properly. +- Remove inotifywait hack from the upstart host-integration example because it's not necessary any more. +- Add check-config script to contrib. +- Fix fish shell completion. + +#### Hack +* Clean up "go test" output from "make test" to be much more readable/scannable. +* Exclude more "definitely not unit tested Go source code" directories from hack/make/test. ++ Generate md5 and sha256 hashes when building, and upload them via hack/release.sh. +- Include contributed completions in Ubuntu PPA. ++ Add cli integration tests. +* Add tweaks to the hack scripts to make them simpler. + +#### Remote API ++ Add TLS auth support for API. +* Move git clone from daemon to client. +- Fix content-type detection in docker cp. +* Split API into 2 go packages. + +#### Runtime +* Support hairpin NAT without going through Docker server. +- devicemapper: succeed immediately when removing non-existent devices. +- devicemapper: improve handling of devicemapper devices (add per device lock, increase sleep time and unlock while sleeping). +- devicemapper: increase timeout in waitClose to 10 seconds. +- devicemapper: ensure we shut down thin pool cleanly. +- devicemapper: pass info, rather than hash to activateDeviceIfNeeded, deactivateDevice, setInitialized, deleteDevice. +- devicemapper: avoid AB-BA deadlock. +- devicemapper: make shutdown better/faster. +- improve alpha sorting in mflag. +- Remove manual http cookie management because the cookiejar is being used. +- Use BSD raw mode on Darwin. Fixes nano, tmux and others. +- Add FreeBSD support for the client. +- Merge auth package into registry. +- Add deprecation warning for -t on `docker pull`. +- Remove goroutine leak on error. +- Update parseLxcInfo to comply with new lxc1.0 format. +- Fix attach exit on darwin. +- Improve deprecation message. +- Retry to retrieve the layer metadata up to 5 times for `docker pull`. +- Only unshare the mount namespace for execin. +- Merge existing config when committing. +- Disable daemon startup timeout. +- Fix issue #4681: add loopback interface when networking is disabled. +- Add failing test case for issue #4681. +- Send SIGTERM to child, instead of SIGKILL. +- Show the driver and the kernel version in `docker info` even when not in debug mode. +- Always symlink /dev/ptmx for libcontainer. This fixes console related problems. +- Fix issue caused by the absence of /etc/apparmor.d. +- Don't leave empty cidFile behind when failing to create the container. +- Mount cgroups automatically if they're not mounted already. +- Use mock for search tests. +- Update to double-dash everywhere. +- Move .dockerenv parsing to lxc driver. +- Move all bind-mounts in the container inside the namespace. +- Don't use separate bind mount for container. +- Always symlink /dev/ptmx for libcontainer. +- Don't kill by pid for other drivers. +- Add initial logging to libcontainer. +* Sort by port in `docker ps`. +- Move networking drivers into runtime top level package. ++ Add --no-prune to `docker rmi`. ++ Add time since exit in `docker ps`. +- graphdriver: add build tags. +- Prevent allocation of previously allocated ports & prevent improve port allocation. +* Add support for --since/--before in `docker ps`. +- Clean up container stop. ++ Add support for configurable dns search domains. +- Add support for relative WORKDIR instructions. +- Add --output flag for docker save. +- Remove duplication of DNS entries in config merging. +- Add cpuset.cpus to cgroups and native driver options. +- Remove docker-ci. +- Promote btrfs. btrfs is no longer considered experimental. +- Add --input flag to `docker load`. +- Return error when existing bridge doesn't match IP address. +- Strip comments before parsing line continuations to avoid interpreting instructions as comments. +- Fix TestOnlyLoopbackExistsWhenUsingDisableNetworkOption to ignore "DOWN" interfaces. +- Add systemd implementation of cgroups and make containers show up as systemd units. +- Fix commit and import when no repository is specified. +- Remount /var/lib/docker as --private to fix scaling issue. +- Use the environment's proxy when pinging the remote registry. +- Reduce error level from harmless errors. +* Allow --volumes-from to be individual files. +- Fix expanding buffer in StdCopy. +- Set error regardless of attach or stdin. This fixes #3364. +- Add support for --env-file to load environment variables from files. +- Symlink /etc/mtab and /proc/mounts. +- Allow pushing a single tag. +- Shut down containers cleanly at shutdown and wait forever for the containers to shut down. This makes container shutdown on daemon shutdown work properly via SIGTERM. +- Don't throw error when starting an already running container. +- Fix dynamic port allocation limit. +- remove setupDev from libcontainer. +- Add API version to `docker version`. +- Return correct exit code when receiving signal and make SIGQUIT quit without cleanup. +- Fix --volumes-from mount failure. +- Allow non-privileged containers to create device nodes. +- Skip login tests because of external dependency on a hosted service. +- Deprecate `docker images --tree` and `docker images --viz`. +- Deprecate `docker insert`. +- Include base abstraction for apparmor. This fixes some apparmor related problems on Ubuntu 14.04. +- Add specific error message when hitting 401 over HTTP on push. +- Fix absolute volume check. +- Remove volumes-from from the config. +- Move DNS options to hostconfig. +- Update the apparmor profile for libcontainer. +- Add deprecation notice for `docker commit -run`. + +## 0.9.1 (2014-03-24) + +#### Builder +- Fix printing multiple messages on a single line. Fixes broken output during builds. + +#### Documentation +- Fix external link on security of containers. + +#### Contrib +- Fix init script cgroup mounting workarounds to be more similar to cgroupfs-mount and thus work properly. +- Add variable for DOCKER_LOGFILE to sysvinit and use append instead of overwrite in opening the logfile. + +#### Hack +- Generate md5 and sha256 hashes when building, and upload them via hack/release.sh. + +#### Remote API +- Fix content-type detection in `docker cp`. + +#### Runtime +- Use BSD raw mode on Darwin. Fixes nano, tmux and others. +- Only unshare the mount namespace for execin. +- Retry to retrieve the layer metadata up to 5 times for `docker pull`. +- Merge existing config when committing. +- Fix panic in monitor. +- Disable daemon startup timeout. +- Fix issue #4681: add loopback interface when networking is disabled. +- Add failing test case for issue #4681. +- Send SIGTERM to child, instead of SIGKILL. +- Show the driver and the kernel version in `docker info` even when not in debug mode. +- Always symlink /dev/ptmx for libcontainer. This fixes console related problems. +- Fix issue caused by the absence of /etc/apparmor.d. +- Don't leave empty cidFile behind when failing to create the container. +- Improve deprecation message. +- Fix attach exit on darwin. +- devicemapper: improve handling of devicemapper devices (add per device lock, increase sleep time, unlock while sleeping). +- devicemapper: succeed immediately when removing non-existent devices. +- devicemapper: increase timeout in waitClose to 10 seconds. +- Remove goroutine leak on error. +- Update parseLxcInfo to comply with new lxc1.0 format. + +## 0.9.0 (2014-03-10) + +#### Builder +- Avoid extra mount/unmount during build. This fixes mount/unmount related errors during build. +- Add error to docker build --rm. This adds missing error handling. +- Forbid chained onbuild, `onbuild from` and `onbuild maintainer` triggers. +- Make `--rm` the default for `docker build`. + +#### Documentation +- Download the docker client binary for Mac over https. +- Update the titles of the install instructions & descriptions. +* Add instructions for upgrading boot2docker. +* Add port forwarding example in OS X install docs. +- Attempt to disentangle repository and registry. +- Update docs to explain more about `docker ps`. +- Update sshd example to use a Dockerfile. +- Rework some examples, including the Python examples. +- Update docs to include instructions for a container's lifecycle. +- Update docs documentation to discuss the docs branch. +- Don't skip cert check for an example & use HTTPS. +- Bring back the memory and swap accounting section which was lost when the kernel page was removed. +- Explain DNS warnings and how to fix them on systems running and using a local nameserver. + +#### Contrib +- Add Tanglu support for mkimage-debootstrap. +- Add SteamOS support for mkimage-debootstrap. + +#### Hack +- Get package coverage when running integration tests. +- Remove the Vagrantfile. This is being replaced with boot2docker. +- Fix tests on systems where aufs isn't available. +- Update packaging instructions and remove the dependency on lxc. + +#### Remote API +* Move code specific to the API to the api package. +- Fix header content type for the API. Makes all endpoints use proper content type. +- Fix registry auth & remove ping calls from CmdPush and CmdPull. +- Add newlines to the JSON stream functions. + +#### Runtime +* Do not ping the registry from the CLI. All requests to registries flow through the daemon. +- Check for nil information return in the lxc driver. This fixes panics with older lxc versions. +- Devicemapper: cleanups and fix for unmount. Fixes two problems which were causing unmount to fail intermittently. +- Devicemapper: remove directory when removing device. Directories don't get left behind when removing the device. +* Devicemapper: enable skip_block_zeroing. Improves performance by not zeroing blocks. +- Devicemapper: fix shutdown warnings. Fixes shutdown warnings concerning pool device removal. +- Ensure docker cp stream is closed properly. Fixes problems with files not being copied by `docker cp`. +- Stop making `tcp://` default to `127.0.0.1:4243` and remove the default port for tcp. +- Fix `--run` in `docker commit`. This makes `docker commit --run` work again. +- Fix custom bridge related options. This makes custom bridges work again. ++ Mount-bind the PTY as container console. This allows tmux/screen to run. ++ Add the pure Go libcontainer library to make it possible to run containers using only features of the Linux kernel. ++ Add native exec driver which uses libcontainer and make it the default exec driver. +- Add support for handling extended attributes in archives. +* Set the container MTU to be the same as the host MTU. ++ Add simple sha256 checksums for layers to speed up `docker push`. +* Improve kernel version parsing. +* Allow flag grouping (`docker run -it`). +- Remove chroot exec driver. +- Fix divide by zero to fix panic. +- Rewrite `docker rmi`. +- Fix docker info with lxc 1.0.0. +- Fix fedora tty with apparmor. +* Don't always append env vars, replace defaults with vars from config. +* Fix a goroutine leak. +* Switch to Go 1.2.1. +- Fix unique constraint error checks. +* Handle symlinks for Docker's data directory and for TMPDIR. +- Add deprecation warnings for flags (-flag is deprecated in favor of --flag) +- Add apparmor profile for the native execution driver. +* Move system specific code from archive to pkg/system. +- Fix duplicate signal for `docker run -i -t` (issue #3336). +- Return correct process pid for lxc. +- Add a -G option to specify the group which unix sockets belong to. ++ Add `-f` flag to `docker rm` to force removal of running containers. ++ Kill ghost containers and restart all ghost containers when the docker daemon restarts. ++ Add `DOCKER_RAMDISK` environment variable to make Docker work when the root is on a ramdisk. + +## 0.8.1 (2014-02-18) + +#### Builder + +- Avoid extra mount/unmount during build. This removes an unneeded mount/unmount operation which was causing problems with devicemapper +- Fix regression with ADD of tar files. This stops Docker from decompressing tarballs added via ADD from the local file system +- Add error to `docker build --rm`. This adds a missing error check to ensure failures to remove containers are detected and reported + +#### Documentation + +* Update issue filing instructions +* Warn against the use of symlinks for Docker's storage folder +* Replace the Firefox example with an IceWeasel example +* Rewrite the PostgreSQL example using a Dockerfile and add more details to it +* Improve the OS X documentation + +#### Remote API + +- Fix broken images API for version less than 1.7 +- Use the right encoding for all API endpoints which return JSON +- Move remote api client to api/ +- Queue calls to the API using generic socket wait + +#### Runtime + +- Fix the use of custom settings for bridges and custom bridges +- Refactor the devicemapper code to avoid many mount/unmount race conditions and failures +- Remove two panics which could make Docker crash in some situations +- Don't ping registry from the CLI client +- Enable skip_block_zeroing for devicemapper. This stops devicemapper from always zeroing entire blocks +- Fix --run in `docker commit`. This makes docker commit store `--run` in the image configuration +- Remove directory when removing devicemapper device. This cleans up leftover mount directories +- Drop NET_ADMIN capability for non-privileged containers. Unprivileged containers can't change their network configuration +- Ensure `docker cp` stream is closed properly +- Avoid extra mount/unmount during container registration. This removes an unneeded mount/unmount operation which was causing problems with devicemapper +- Stop allowing tcp:// as a default tcp bin address which binds to 127.0.0.1:4243 and remove the default port ++ Mount-bind the PTY as container console. This allows tmux and screen to run in a container +- Clean up archive closing. This fixes and improves archive handling +- Fix engine tests on systems where temp directories are symlinked +- Add test methods for save and load +- Avoid temporarily unmounting the container when restarting it. This fixes a race for devicemapper during restart +- Support submodules when building from a GitHub repository +- Quote volume path to allow spaces +- Fix remote tar ADD behavior. This fixes a regression which was causing Docker to extract tarballs + +## 0.8.0 (2014-02-04) + +#### Notable features since 0.7.0 + +* Images and containers can be removed much faster +* Building an image from source with docker build is now much faster +* The Docker daemon starts and stops much faster +* The memory footprint of many common operations has been reduced, by streaming files instead of buffering them in memory, fixing memory leaks, and fixing various suboptimal memory allocations +* Several race conditions were fixed, making Docker more stable under very high concurrency load. This makes Docker more stable and less likely to crash and reduces the memory footprint of many common operations +* All packaging operations are now built on the Go language’s standard tar implementation, which is bundled with Docker itself. This makes packaging more portable across host distributions, and solves several issues caused by quirks and incompatibilities between different distributions of tar +* Docker can now create, remove and modify larger numbers of containers and images graciously thanks to more aggressive releasing of system resources. For example the storage driver API now allows Docker to do reference counting on mounts created by the drivers +With the ongoing changes to the networking and execution subsystems of docker testing these areas have been a focus of the refactoring. By moving these subsystems into separate packages we can test, analyze, and monitor coverage and quality of these packages +* Many components have been separated into smaller sub-packages, each with a dedicated test suite. As a result the code is better-tested, more readable and easier to change + +* The ADD instruction now supports caching, which avoids unnecessarily re-uploading the same source content again and again when it hasn’t changed +* The new ONBUILD instruction adds to your image a “trigger” instruction to be executed at a later time, when the image is used as the base for another build +* Docker now ships with an experimental storage driver which uses the BTRFS filesystem for copy-on-write +* Docker is officially supported on Mac OS X +* The Docker daemon supports systemd socket activation + +## 0.7.6 (2014-01-14) + +#### Builder + +* Do not follow symlink outside of build context + +#### Runtime + +- Remount bind mounts when ro is specified +* Use https for fetching docker version + +#### Other + +* Inline the test.docker.io fingerprint +* Add ca-certificates to packaging documentation + +## 0.7.5 (2014-01-09) + +#### Builder + +* Disable compression for build. More space usage but a much faster upload +- Fix ADD caching for certain paths +- Do not compress archive from git build + +#### Documentation + +- Fix error in GROUP add example +* Make sure the GPG fingerprint is inline in the documentation +* Give more specific advice on setting up signing of commits for DCO + +#### Runtime + +- Fix misspelled container names +- Do not add hostname when networking is disabled +* Return most recent image from the cache by date +- Return all errors from docker wait +* Add Content-Type Header "application/json" to GET /version and /info responses + +#### Other + +* Update DCO to version 1.1 ++ Update Makefile to use "docker:GIT_BRANCH" as the generated image name +* Update Travis to check for new 1.1 DCO version + +## 0.7.4 (2014-01-07) + +#### Builder + +- Fix ADD caching issue with . prefixed path +- Fix docker build on devicemapper by reverting sparse file tar option +- Fix issue with file caching and prevent wrong cache hit +* Use same error handling while unmarshalling CMD and ENTRYPOINT + +#### Documentation + +* Simplify and streamline Amazon Quickstart +* Install instructions use unprefixed Fedora image +* Update instructions for mtu flag for Docker on GCE ++ Add Ubuntu Saucy to installation +- Fix for wrong version warning on master instead of latest + +#### Runtime + +- Only get the image's rootfs when we need to calculate the image size +- Correctly handle unmapping UDP ports +* Make CopyFileWithTar use a pipe instead of a buffer to save memory on docker build +- Fix login message to say pull instead of push +- Fix "docker load" help by removing "SOURCE" prompt and mentioning STDIN +* Make blank -H option default to the same as no -H was sent +* Extract cgroups utilities to own submodule + +#### Other + ++ Add Travis CI configuration to validate DCO and gofmt requirements ++ Add Developer Certificate of Origin Text +* Upgrade VBox Guest Additions +* Check standalone header when pinging a registry server + +## 0.7.3 (2014-01-02) + +#### Builder + ++ Update ADD to use the image cache, based on a hash of the added content +* Add error message for empty Dockerfile + +#### Documentation + +- Fix outdated link to the "Introduction" on www.docker.io ++ Update the docs to get wider when the screen does +- Add information about needing to install LXC when using raw binaries +* Update Fedora documentation to disentangle the docker and docker.io conflict +* Add a note about using the new `-mtu` flag in several GCE zones ++ Add FrugalWare installation instructions ++ Add a more complete example of `docker run` +- Fix API documentation for creating and starting Privileged containers +- Add missing "name" parameter documentation on "/containers/create" +* Add a mention of `lxc-checkconfig` as a way to check for some of the necessary kernel configuration +- Update the 1.8 API documentation with some additions that were added to the docs for 1.7 + +#### Hack + +- Add missing libdevmapper dependency to the packagers documentation +* Update minimum Go requirement to a hard line at Go 1.2+ +* Many minor improvements to the Vagrantfile ++ Add ability to customize dockerinit search locations when compiling (to be used very sparingly only by packagers of platforms who require a nonstandard location) ++ Add coverprofile generation reporting +- Add `-a` to our Go build flags, removing the need for recompiling the stdlib manually +* Update Dockerfile to be more canonical and have less spurious warnings during build +- Fix some miscellaneous `docker pull` progress bar display issues +* Migrate more miscellaneous packages under the "pkg" folder +* Update TextMate highlighting to automatically be enabled for files named "Dockerfile" +* Reorganize syntax highlighting files under a common "contrib/syntax" directory +* Update install.sh script (https://get.docker.io/) to not fail if busybox fails to download or run at the end of the Ubuntu/Debian installation +* Add support for container names in bash completion + +#### Packaging + ++ Add an official Docker client binary for Darwin (Mac OS X) +* Remove empty "Vendor" string and added "License" on deb package ++ Add a stubbed version of "/etc/default/docker" in the deb package + +#### Runtime + +* Update layer application to extract tars in place, avoiding file churn while handling whiteouts +- Fix permissiveness of mtime comparisons in tar handling (since GNU tar and Go tar do not yet support sub-second mtime precision) +* Reimplement `docker top` in pure Go to work more consistently, and even inside Docker-in-Docker (thus removing the shell injection vulnerability present in some versions of `lxc-ps`) ++ Update `-H unix://` to work similarly to `-H tcp://` by inserting the default values for missing portions +- Fix more edge cases regarding dockerinit and deleted or replaced docker or dockerinit files +* Update container name validation to include '.' +- Fix use of a symlink or non-absolute path as the argument to `-g` to work as expected +* Update to handle external mounts outside of LXC, fixing many small mounting quirks and making future execution backends and other features simpler +* Update to use proper box-drawing characters everywhere in `docker images -tree` +* Move MTU setting from LXC configuration to directly use netlink +* Add `-S` option to external tar invocation for more efficient spare file handling ++ Add arch/os info to User-Agent string, especially for registry requests ++ Add `-mtu` option to Docker daemon for configuring MTU +- Fix `docker build` to exit with a non-zero exit code on error ++ Add `DOCKER_HOST` environment variable to configure the client `-H` flag without specifying it manually for every invocation + +## 0.7.2 (2013-12-16) + +#### Runtime + ++ Validate container names on creation with standard regex +* Increase maximum image depth to 127 from 42 +* Continue to move api endpoints to the job api ++ Add -bip flag to allow specification of dynamic bridge IP via CIDR +- Allow bridge creation when ipv6 is not enabled on certain systems +* Set hostname and IP address from within dockerinit +* Drop capabilities from within dockerinit +- Fix volumes on host when symlink is present the image +- Prevent deletion of image if ANY container is depending on it even if the container is not running +* Update docker push to use new progress display +* Use os.Lstat to allow mounting unix sockets when inspecting volumes +- Adjust handling of inactive user login +- Add missing defines in devicemapper for older kernels +- Allow untag operations with no container validation +- Add auth config to docker build + +#### Documentation + +* Add more information about Docker logging ++ Add RHEL documentation +* Add a direct example for changing the CMD that is run in a container +* Update Arch installation documentation ++ Add section on Trusted Builds ++ Add Network documentation page + +#### Other + ++ Add new cover bundle for providing code coverage reporting +* Separate integration tests in bundles +* Make Tianon the hack maintainer +* Update mkimage-debootstrap with more tweaks for keeping images small +* Use https to get the install script +* Remove vendored dotcloud/tar now that Go 1.2 has been released + +## 0.7.1 (2013-12-05) + +#### Documentation + ++ Add @SvenDowideit as documentation maintainer ++ Add links example ++ Add documentation regarding ambassador pattern ++ Add Google Cloud Platform docs ++ Add dockerfile best practices +* Update doc for RHEL +* Update doc for registry +* Update Postgres examples +* Update doc for Ubuntu install +* Improve remote api doc + +#### Runtime + ++ Add hostconfig to docker inspect ++ Implement `docker log -f` to stream logs ++ Add env variable to disable kernel version warning ++ Add -format to `docker inspect` ++ Support bind-mount for files +- Fix bridge creation on RHEL +- Fix image size calculation +- Make sure iptables are called even if the bridge already exists +- Fix issue with stderr only attach +- Remove init layer when destroying a container +- Fix same port binding on different interfaces +- `docker build` now returns the correct exit code +- Fix `docker port` to display correct port +- `docker build` now check that the dockerfile exists client side +- `docker attach` now returns the correct exit code +- Remove the name entry when the container does not exist + +#### Registry + +* Improve progress bars, add ETA for downloads +* Simultaneous pulls now waits for the first to finish instead of failing +- Tag only the top-layer image when pushing to registry +- Fix issue with offline image transfer +- Fix issue preventing using ':' in password for registry + +#### Other + ++ Add pprof handler for debug ++ Create a Makefile +* Use stdlib tar that now includes fix +* Improve make.sh test script +* Handle SIGQUIT on the daemon +* Disable verbose during tests +* Upgrade to go1.2 for official build +* Improve unit tests +* The test suite now runs all tests even if one fails +* Refactor C in Go (Devmapper) +- Fix OS X compilation + +## 0.7.0 (2013-11-25) + +#### Notable features since 0.6.0 + +* Storage drivers: choose from aufs, device-mapper, or vfs. +* Standard Linux support: docker now runs on unmodified Linux kernels and all major distributions. +* Links: compose complex software stacks by connecting containers to each other. +* Container naming: organize your containers by giving them memorable names. +* Advanced port redirects: specify port redirects per interface, or keep sensitive ports private. +* Offline transfer: push and pull images to the filesystem without losing information. +* Quality: numerous bugfixes and small usability improvements. Significant increase in test coverage. + +## 0.6.7 (2013-11-21) + +#### Runtime + +* Improve stability, fixes some race conditions +* Skip the volumes mounted when deleting the volumes of container. +* Fix layer size computation: handle hard links correctly +* Use the work Path for docker cp CONTAINER:PATH +* Fix tmp dir never cleanup +* Speedup docker ps +* More informative error message on name collisions +* Fix nameserver regex +* Always return long id's +* Fix container restart race condition +* Keep published ports on docker stop;docker start +* Fix container networking on Fedora +* Correctly express "any address" to iptables +* Fix network setup when reconnecting to ghost container +* Prevent deletion if image is used by a running container +* Lock around read operations in graph + +#### RemoteAPI + +* Return full ID on docker rmi + +#### Client + ++ Add -tree option to images ++ Offline image transfer +* Exit with status 2 on usage error and display usage on stderr +* Do not forward SIGCHLD to container +* Use string timestamp for docker events -since + +#### Other + +* Update to go 1.2rc5 ++ Add /etc/default/docker support to upstart + +## 0.6.6 (2013-11-06) + +#### Runtime + +* Ensure container name on register +* Fix regression in /etc/hosts ++ Add lock around write operations in graph +* Check if port is valid +* Fix restart runtime error with ghost container networking ++ Add some more colors and animals to increase the pool of generated names +* Fix issues in docker inspect ++ Escape apparmor confinement ++ Set environment variables using a file. +* Prevent docker insert to erase something ++ Prevent DNS server conflicts in CreateBridgeIface ++ Validate bind mounts on the server side ++ Use parent image config in docker build +* Fix regression in /etc/hosts + +#### Client + ++ Add -P flag to publish all exposed ports ++ Add -notrunc and -q flags to docker history +* Fix docker commit, tag and import usage ++ Add stars, trusted builds and library flags in docker search +* Fix docker logs with tty + +#### RemoteAPI + +* Make /events API send headers immediately +* Do not split last column docker top ++ Add size to history + +#### Other + ++ Contrib: Desktop integration. Firefox usecase. ++ Dockerfile: bump to go1.2rc3 + +## 0.6.5 (2013-10-29) + +#### Runtime + ++ Containers can now be named ++ Containers can now be linked together for service discovery ++ 'run -a', 'start -a' and 'attach' can forward signals to the container for better integration with process supervisors ++ Automatically start crashed containers after a reboot ++ Expose IP, port, and proto as separate environment vars for container links +* Allow ports to be published to specific ips +* Prohibit inter-container communication by default +- Ignore ErrClosedPipe for stdin in Container.Attach +- Remove unused field kernelVersion +* Fix issue when mounting subdirectories of /mnt in container +- Fix untag during removal of images +* Check return value of syscall.Chdir when changing working directory inside dockerinit + +#### Client + +- Only pass stdin to hijack when needed to avoid closed pipe errors +* Use less reflection in command-line method invocation +- Monitor the tty size after starting the container, not prior +- Remove useless os.Exit() calls after log.Fatal + +#### Hack + ++ Add initial init scripts library and a safer Ubuntu packaging script that works for Debian +* Add -p option to invoke debootstrap with http_proxy +- Update install.sh with $sh_c to get sudo/su for modprobe +* Update all the mkimage scripts to use --numeric-owner as a tar argument +* Update hack/release.sh process to automatically invoke hack/make.sh and bail on build and test issues + +#### Other + +* Documentation: Fix the flags for nc in example +* Testing: Remove warnings and prevent mount issues +- Testing: Change logic for tty resize to avoid warning in tests +- Builder: Fix race condition in docker build with verbose output +- Registry: Fix content-type for PushImageJSONIndex method +* Contrib: Improve helper tools to generate debian and Arch linux server images + +## 0.6.4 (2013-10-16) + +#### Runtime + +- Add cleanup of container when Start() fails +* Add better comments to utils/stdcopy.go +* Add utils.Errorf for error logging ++ Add -rm to docker run for removing a container on exit +- Remove error messages which are not actually errors +- Fix `docker rm` with volumes +- Fix some error cases where an HTTP body might not be closed +- Fix panic with wrong dockercfg file +- Fix the attach behavior with -i +* Record termination time in state. +- Use empty string so TempDir uses the OS's temp dir automatically +- Make sure to close the network allocators ++ Autorestart containers by default +* Bump vendor kr/pty to commit 3b1f6487b `(syscall.O_NOCTTY)` +* lxc: Allow set_file_cap capability in container +- Move run -rm to the cli only +* Split stdout stderr +* Always create a new session for the container + +#### Testing + +- Add aggregated docker-ci email report +- Add cleanup to remove leftover containers +* Add nightly release to docker-ci +* Add more tests around auth.ResolveAuthConfig +- Remove a few errors in tests +- Catch errClosing error when TCP and UDP proxies are terminated +* Only run certain tests with TESTFLAGS='-run TestName' make.sh +* Prevent docker-ci to test closing PRs +* Replace panic by log.Fatal in tests +- Increase TestRunDetach timeout + +#### Documentation + +* Add initial draft of the Docker infrastructure doc +* Add devenvironment link to CONTRIBUTING.md +* Add `apt-get install curl` to Ubuntu docs +* Add explanation for export restrictions +* Add .dockercfg doc +* Remove Gentoo install notes about #1422 workaround +* Fix help text for -v option +* Fix Ping endpoint documentation +- Fix parameter names in docs for ADD command +- Fix ironic typo in changelog +* Various command fixes in postgres example +* Document how to edit and release docs +- Minor updates to `postgresql_service.rst` +* Clarify LGTM process to contributors +- Corrected error in the package name +* Document what `vagrant up` is actually doing ++ improve doc search results +* Cleanup whitespace in API 1.5 docs +* use angle brackets in MAINTAINER example email +* Update archlinux.rst ++ Changes to a new style for the docs. Includes version switcher. +* Formatting, add information about multiline json +* Improve registry and index REST API documentation +- Replace deprecated upgrading reference to docker-latest.tgz, which hasn't been updated since 0.5.3 +* Update Gentoo installation documentation now that we're in the portage tree proper +* Cleanup and reorganize docs and tooling for contributors and maintainers +- Minor spelling correction of protocoll -> protocol + +#### Contrib + +* Add vim syntax highlighting for Dockerfiles from @honza +* Add mkimage-arch.sh +* Reorganize contributed completion scripts to add zsh completion + +#### Hack + +* Add vagrant user to the docker group +* Add proper bash completion for "docker push" +* Add xz utils as a runtime dep +* Add cleanup/refactor portion of #2010 for hack and Dockerfile updates ++ Add contrib/mkimage-centos.sh back (from #1621), and associated documentation link +* Add several of the small make.sh fixes from #1920, and make the output more consistent and contributor-friendly ++ Add @tianon to hack/MAINTAINERS +* Improve network performance for VirtualBox +* Revamp install.sh to be usable by more people, and to use official install methods whenever possible (apt repo, portage tree, etc.) +- Fix contrib/mkimage-debian.sh apt caching prevention ++ Add Dockerfile.tmLanguage to contrib +* Configured FPM to make /etc/init/docker.conf a config file +* Enable SSH Agent forwarding in Vagrant VM +* Several small tweaks/fixes for contrib/mkimage-debian.sh + +#### Other + +- Builder: Abort build if mergeConfig returns an error and fix duplicate error message +- Packaging: Remove deprecated packaging directory +- Registry: Use correct auth config when logging in. +- Registry: Fix the error message so it is the same as the regex + +## 0.6.3 (2013-09-23) + +#### Packaging + +* Add 'docker' group on install for ubuntu package +* Update tar vendor dependency +* Download apt key over HTTPS + +#### Runtime + +- Only copy and change permissions on non-bindmount volumes +* Allow multiple volumes-from +- Fix HTTP imports from STDIN + +#### Documentation + +* Update section on extracting the docker binary after build +* Update development environment docs for new build process +* Remove 'base' image from documentation + +#### Other + +- Client: Fix detach issue +- Registry: Update regular expression to match index + +## 0.6.2 (2013-09-17) + +#### Runtime + ++ Add domainname support ++ Implement image filtering with path.Match +* Remove unnecessary warnings +* Remove os/user dependency +* Only mount the hostname file when the config exists +* Handle signals within the `docker login` command +- UID and GID are now also applied to volumes +- `docker start` set error code upon error +- `docker run` set the same error code as the process started + +#### Builder + ++ Add -rm option in order to remove intermediate containers +* Allow multiline for the RUN instruction + +#### Registry + +* Implement login with private registry +- Fix push issues + +#### Other + ++ Hack: Vendor all dependencies +* Remote API: Bump to v1.5 +* Packaging: Break down hack/make.sh into small scripts, one per 'bundle': test, binary, ubuntu etc. +* Documentation: General improvements + +## 0.6.1 (2013-08-23) + +#### Registry + +* Pass "meta" headers in API calls to the registry + +#### Packaging + +- Use correct upstart script with new build tool +- Use libffi-dev, don`t build it from sources +- Remove duplicate mercurial install command + +## 0.6.0 (2013-08-22) + +#### Runtime + ++ Add lxc-conf flag to allow custom lxc options ++ Add an option to set the working directory +* Add Image name to LogEvent tests ++ Add -privileged flag and relevant tests, docs, and examples +* Add websocket support to /container//attach/ws +* Add warning when net.ipv4.ip_forwarding = 0 +* Add hostname to environment +* Add last stable version in `docker version` +- Fix race conditions in parallel pull +- Fix Graph ByParent() to generate list of child images per parent image. +- Fix typo: fmt.Sprint -> fmt.Sprintf +- Fix small \n error un docker build +* Fix to "Inject dockerinit at /.dockerinit" +* Fix #910. print user name to docker info output +* Use Go 1.1.2 for dockerbuilder +* Use ranged for loop on channels +- Use utils.ParseRepositoryTag instead of strings.Split(name, ":") in server.ImageDelete +- Improve CMD, ENTRYPOINT, and attach docs. +- Improve connect message with socket error +- Load authConfig only when needed and fix useless WARNING +- Show tag used when image is missing +* Apply volumes-from before creating volumes +- Make docker run handle SIGINT/SIGTERM +- Prevent crash when .dockercfg not readable +- Install script should be fetched over https, not http. +* API, issue 1471: Use groups for socket permissions +- Correctly detect IPv4 forwarding +* Mount /dev/shm as a tmpfs +- Switch from http to https for get.docker.io +* Let userland proxy handle container-bound traffic +* Update the Docker CLI to specify a value for the "Host" header. +- Change network range to avoid conflict with EC2 DNS +- Reduce connect and read timeout when pinging the registry +* Parallel pull +- Handle ip route showing mask-less IP addresses +* Allow ENTRYPOINT without CMD +- Always consider localhost as a domain name when parsing the FQN repos name +* Refactor checksum + +#### Documentation + +* Add MongoDB image example +* Add instructions for creating and using the docker group +* Add sudo to examples and installation to documentation +* Add ufw doc +* Add a reference to ps -a +* Add information about Docker`s high level tools over LXC. +* Fix typo in docs for docker run -dns +* Fix a typo in the ubuntu installation guide +* Fix to docs regarding adding docker groups +* Update default -H docs +* Update readme with dependencies for building +* Update amazon.rst to explain that Vagrant is not necessary for running Docker on ec2 +* PostgreSQL service example in documentation +* Suggest installing linux-headers by default. +* Change the twitter handle +* Clarify Amazon EC2 installation +* 'Base' image is deprecated and should no longer be referenced in the docs. +* Move note about officially supported kernel +- Solved the logo being squished in Safari + +#### Builder + ++ Add USER instruction do Dockerfile ++ Add workdir support for the Buildfile +* Add no cache for docker build +- Fix docker build and docker events output +- Only count known instructions as build steps +- Make sure ENV instruction within build perform a commit each time +- Forbid certain paths within docker build ADD +- Repository name (and optionally a tag) in build usage +- Make sure ADD will create everything in 0755 + +#### Remote API + +* Sort Images by most recent creation date. +* Reworking opaque requests in registry module +* Add image name in /events +* Use mime pkg to parse Content-Type +* 650 http utils and user agent field + +#### Hack + ++ Bash Completion: Limit commands to containers of a relevant state +* Add docker dependencies coverage testing into docker-ci + +#### Packaging + ++ Docker-brew 0.5.2 support and memory footprint reduction +* Add new docker dependencies into docker-ci +- Revert "docker.upstart: avoid spawning a `sh` process" ++ Docker-brew and Docker standard library ++ Release docker with docker +* Fix the upstart script generated by get.docker.io +* Enabled the docs to generate manpages. +* Revert Bind daemon to 0.0.0.0 in Vagrant. + +#### Register + +* Improve auth push +* Registry unit tests + mock registry + +#### Tests + +* Improve TestKillDifferentUser to prevent timeout on buildbot +- Fix typo in TestBindMounts (runContainer called without image) +* Improve TestGetContainersTop so it does not rely on sleep +* Relax the lo interface test to allow iface index != 1 +* Add registry functional test to docker-ci +* Add some tests in server and utils + +#### Other + +* Contrib: bash completion script +* Client: Add docker cp command and copy api endpoint to copy container files/folders to the host +* Don`t read from stdout when only attached to stdin + +## 0.5.3 (2013-08-13) + +#### Runtime + +* Use docker group for socket permissions +- Spawn shell within upstart script +- Handle ip route showing mask-less IP addresses +- Add hostname to environment + +#### Builder + +- Make sure ENV instruction within build perform a commit each time + +## 0.5.2 (2013-08-08) + +* Builder: Forbid certain paths within docker build ADD +- Runtime: Change network range to avoid conflict with EC2 DNS +* API: Change daemon to listen on unix socket by default + +## 0.5.1 (2013-07-30) + +#### Runtime + ++ Add `ps` args to `docker top` ++ Add support for container ID files (pidfile like) ++ Add container=lxc in default env ++ Support networkless containers with `docker run -n` and `docker -d -b=none` +* Stdout/stderr logs are now stored in the same file as JSON +* Allocate a /16 IP range by default, with fallback to /24. Try 12 ranges instead of 3. +* Change .dockercfg format to json and support multiple auth remote +- Do not override volumes from config +- Fix issue with EXPOSE override + +#### API + ++ Docker client now sets useragent (RFC 2616) ++ Add /events endpoint + +#### Builder + ++ ADD command now understands URLs ++ CmdAdd and CmdEnv now respect Dockerfile-set ENV variables +- Create directories with 755 instead of 700 within ADD instruction + +#### Hack + +* Simplify unit tests with helpers +* Improve docker.upstart event +* Add coverage testing into docker-ci + +## 0.5.0 (2013-07-17) + +#### Runtime + ++ List all processes running inside a container with 'docker top' ++ Host directories can be mounted as volumes with 'docker run -v' ++ Containers can expose public UDP ports (eg, '-p 123/udp') ++ Optionally specify an exact public port (eg. '-p 80:4500') +* 'docker login' supports additional options +- Don't save a container`s hostname when committing an image. + +#### Registry + ++ New image naming scheme inspired by Go packaging convention allows arbitrary combinations of registries +- Fix issues when uploading images to a private registry + +#### Builder + ++ ENTRYPOINT instruction sets a default binary entry point to a container ++ VOLUME instruction marks a part of the container as persistent data +* 'docker build' displays the full output of a build by default + +## 0.4.8 (2013-07-01) + ++ Builder: New build operation ENTRYPOINT adds an executable entry point to the container. - Runtime: Fix a bug which caused 'docker run -d' to no longer print the container ID. +- Tests: Fix issues in the test suite + +## 0.4.7 (2013-06-28) + +#### Remote API + +* The progress bar updates faster when downloading and uploading large files +- Fix a bug in the optional unix socket transport + +#### Runtime + +* Improve detection of kernel version ++ Host directories can be mounted as volumes with 'docker run -b' +- fix an issue when only attaching to stdin +* Use 'tar --numeric-owner' to avoid uid mismatch across multiple hosts + +#### Hack + +* Improve test suite and dev environment +* Remove dependency on unit tests on 'os/user' + +#### Other + +* Registry: easier push/pull to a custom registry ++ Documentation: add terminology section + +## 0.4.6 (2013-06-22) + +- Runtime: fix a bug which caused creation of empty images (and volumes) to crash. + +## 0.4.5 (2013-06-21) + ++ Builder: 'docker build git://URL' fetches and builds a remote git repository +* Runtime: 'docker ps -s' optionally prints container size +* Tests: improved and simplified +- Runtime: fix a regression introduced in 0.4.3 which caused the logs command to fail. +- Builder: fix a regression when using ADD with single regular file. + +## 0.4.4 (2013-06-19) + +- Builder: fix a regression introduced in 0.4.3 which caused builds to fail on new clients. + +## 0.4.3 (2013-06-19) + +#### Builder + ++ ADD of a local file will detect tar archives and unpack them +* ADD improvements: use tar for copy + automatically unpack local archives +* ADD uses tar/untar for copies instead of calling 'cp -ar' +* Fix the behavior of ADD to be (mostly) reverse-compatible, predictable and well-documented. +- Fix a bug which caused builds to fail if ADD was the first command +* Nicer output for 'docker build' + +#### Runtime + +* Remove bsdtar dependency +* Add unix socket and multiple -H support +* Prevent rm of running containers +* Use go1.1 cookiejar +- Fix issue detaching from running TTY container +- Forbid parallel push/pull for a single image/repo. Fixes #311 +- Fix race condition within Run command when attaching. + +#### Client + +* HumanReadable ProgressBar sizes in pull +* Fix docker version`s git commit output + +#### API + +* Send all tags on History API call +* Add tag lookup to history command. Fixes #882 + +#### Documentation + +- Fix missing command in irc bouncer example + +## 0.4.2 (2013-06-17) + +- Packaging: Bumped version to work around an Ubuntu bug + +## 0.4.1 (2013-06-17) + +#### Remote Api + ++ Add flag to enable cross domain requests ++ Add images and containers sizes in docker ps and docker images + +#### Runtime + ++ Configure dns configuration host-wide with 'docker -d -dns' ++ Detect faulty DNS configuration and replace it with a public default ++ Allow docker run : ++ You can now specify public port (ex: -p 80:4500) +* Improve image removal to garbage-collect unreferenced parents + +#### Client + +* Allow multiple params in inspect +* Print the container id before the hijack in `docker run` + +#### Registry + +* Add regexp check on repo`s name +* Move auth to the client +- Remove login check on pull + +#### Other + +* Vagrantfile: Add the rest api port to vagrantfile`s port_forward +* Upgrade to Go 1.1 +- Builder: don`t ignore last line in Dockerfile when it doesn`t end with \n + +## 0.4.0 (2013-06-03) + +#### Builder + ++ Introducing Builder ++ 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile + +#### Remote API + ++ Introducing Remote API ++ control Docker programmatically using a simple HTTP/json API + +#### Runtime + +* Various reliability and usability improvements + +## 0.3.4 (2013-05-30) + +#### Builder + ++ 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile ++ 'docker build -t FOO' applies the tag FOO to the newly built container. + +#### Runtime + ++ Interactive TTYs correctly handle window resize +* Fix how configuration is merged between layers + +#### Remote API + ++ Split stdout and stderr on 'docker run' ++ Optionally listen on a different IP and port (use at your own risk) + +#### Documentation + +* Improve install instructions. + +## 0.3.3 (2013-05-23) + +- Registry: Fix push regression +- Various bugfixes + +## 0.3.2 (2013-05-09) + +#### Registry + +* Improve the checksum process +* Use the size to have a good progress bar while pushing +* Use the actual archive if it exists in order to speed up the push +- Fix error 400 on push + +#### Runtime + +* Store the actual archive on commit + +## 0.3.1 (2013-05-08) + +#### Builder + ++ Implement the autorun capability within docker builder ++ Add caching to docker builder ++ Add support for docker builder with native API as top level command ++ Implement ENV within docker builder +- Check the command existence prior create and add Unit tests for the case +* use any whitespaces instead of tabs + +#### Runtime + ++ Add go version to debug infos +* Kernel version - don`t show the dash if flavor is empty + +#### Registry + ++ Add docker search top level command in order to search a repository +- Fix pull for official images with specific tag +- Fix issue when login in with a different user and trying to push +* Improve checksum - async calculation + +#### Images + ++ Output graph of images to dot (graphviz) +- Fix ByParent function + +#### Documentation + ++ New introduction and high-level overview ++ Add the documentation for docker builder +- CSS fix for docker documentation to make REST API docs look better. +- Fix CouchDB example page header mistake +- Fix README formatting +* Update www.docker.io website. + +#### Other + ++ Website: new high-level overview +- Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc +* Packaging: packaging ubuntu; issue #510: Use goland-stable PPA package to build docker + +## 0.3.0 (2013-05-06) + +#### Runtime + +- Fix the command existence check +- strings.Split may return an empty string on no match +- Fix an index out of range crash if cgroup memory is not + +#### Documentation + +* Various improvements ++ New example: sharing data between 2 couchdb databases + +#### Other + +* Vagrant: Use only one deb line in /etc/apt ++ Registry: Implement the new registry + +## 0.2.2 (2013-05-03) + ++ Support for data volumes ('docker run -v=PATH') ++ Share data volumes between containers ('docker run -volumes-from') ++ Improve documentation +* Upgrade to Go 1.0.3 +* Various upgrades to the dev environment for contributors + +## 0.2.1 (2013-05-01) + ++ 'docker commit -run' bundles a layer with default runtime options: command, ports etc. +* Improve install process on Vagrant ++ New Dockerfile operation: "maintainer" ++ New Dockerfile operation: "expose" ++ New Dockerfile operation: "cmd" ++ Contrib script to build a Debian base layer ++ 'docker -d -r': restart crashed containers at daemon startup +* Runtime: improve test coverage + +## 0.2.0 (2013-04-23) + +- Runtime: ghost containers can be killed and waited for +* Documentation: update install instructions +- Packaging: fix Vagrantfile +- Development: automate releasing binaries and ubuntu packages ++ Add a changelog +- Various bugfixes + +## 0.1.8 (2013-04-22) + +- Dynamically detect cgroup capabilities +- Issue stability warning on kernels <3.8 +- 'docker push' buffers on disk instead of memory +- Fix 'docker diff' for removed files +- Fix 'docker stop' for ghost containers +- Fix handling of pidfile +- Various bugfixes and stability improvements + +## 0.1.7 (2013-04-18) + +- Container ports are available on localhost +- 'docker ps' shows allocated TCP ports +- Contributors can run 'make hack' to start a continuous integration VM +- Streamline ubuntu packaging & uploading +- Various bugfixes and stability improvements + +## 0.1.6 (2013-04-17) + +- Record the author an image with 'docker commit -author' + +## 0.1.5 (2013-04-17) + +- Disable standalone mode +- Use a custom DNS resolver with 'docker -d -dns' +- Detect ghost containers +- Improve diagnosis of missing system capabilities +- Allow disabling memory limits at compile time +- Add debian packaging +- Documentation: installing on Arch Linux +- Documentation: running Redis on docker +- Fix lxc 0.9 compatibility +- Automatically load aufs module +- Various bugfixes and stability improvements + +## 0.1.4 (2013-04-09) + +- Full support for TTY emulation +- Detach from a TTY session with the escape sequence `C-p C-q` +- Various bugfixes and stability improvements +- Minor UI improvements +- Automatically create our own bridge interface 'docker0' + +## 0.1.3 (2013-04-04) + +- Choose TCP frontend port with '-p :PORT' +- Layer format is versioned +- Major reliability improvements to the process manager +- Various bugfixes and stability improvements + +## 0.1.2 (2013-04-03) + +- Set container hostname with 'docker run -h' +- Selective attach at run with 'docker run -a [stdin[,stdout[,stderr]]]' +- Various bugfixes and stability improvements +- UI polish +- Progress bar on push/pull +- Use XZ compression by default +- Make IP allocator lazy + +## 0.1.1 (2013-03-31) + +- Display shorthand IDs for convenience +- Stabilize process management +- Layers can include a commit message +- Simplified 'docker attach' +- Fix support for re-attaching +- Various bugfixes and stability improvements +- Auto-download at run +- Auto-login on push +- Beefed up documentation + +## 0.1.0 (2013-03-23) + +Initial public release + +- Implement registry in order to push/pull images +- TCP port allocation +- Fix termcaps on Linux +- Add documentation +- Add Vagrant support with Vagrantfile +- Add unit tests +- Add repository/tags to ease image management +- Improve the layer implementation diff --git a/vendor/github.com/docker/docker/CONTRIBUTING.md b/vendor/github.com/docker/docker/CONTRIBUTING.md new file mode 100644 index 000000000..eb5f8ab0e --- /dev/null +++ b/vendor/github.com/docker/docker/CONTRIBUTING.md @@ -0,0 +1,401 @@ +# Contributing to Docker + +Want to hack on Docker? Awesome! We have a contributor's guide that explains +[setting up a Docker development environment and the contribution +process](https://docs.docker.com/opensource/project/who-written-for/). + +[![Contributors guide](docs/static_files/contributors.png)](https://docs.docker.com/opensource/project/who-written-for/) + +This page contains information about reporting issues as well as some tips and +guidelines useful to experienced open source contributors. Finally, make sure +you read our [community guidelines](#docker-community-guidelines) before you +start participating. + +## Topics + +* [Reporting Security Issues](#reporting-security-issues) +* [Design and Cleanup Proposals](#design-and-cleanup-proposals) +* [Reporting Issues](#reporting-other-issues) +* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines) +* [Community Guidelines](#docker-community-guidelines) + +## Reporting security issues + +The Docker maintainers take security seriously. If you discover a security +issue, please bring it to their attention right away! + +Please **DO NOT** file a public issue, instead send your report privately to +[security@docker.com](mailto:security@docker.com). + +Security reports are greatly appreciated and we will publicly thank you for it. +We also like to send gifts—if you're into Docker schwag, make sure to let +us know. We currently do not offer a paid security bounty program, but are not +ruling it out in the future. + + +## Reporting other issues + +A great way to contribute to the project is to send a detailed report when you +encounter an issue. We always appreciate a well-written, thorough bug report, +and will thank you for it! + +Check that [our issue database](https://github.com/docker/docker/issues) +doesn't already include that problem or suggestion before submitting an issue. +If you find a match, you can use the "subscribe" button to get notified on +updates. Do *not* leave random "+1" or "I have this too" comments, as they +only clutter the discussion, and don't help resolving it. However, if you +have ways to reproduce the issue or have additional information that may help +resolving the issue, please leave a comment. + +When reporting issues, always include: + +* The output of `docker version`. +* The output of `docker info`. + +Also include the steps required to reproduce the problem if possible and +applicable. This information will help us review and fix your issue faster. +When sending lengthy log-files, consider posting them as a gist (https://gist.github.com). +Don't forget to remove sensitive data from your logfiles before posting (you can +replace those parts with "REDACTED"). + +## Quick contribution tips and guidelines + +This section gives the experienced contributor some tips and guidelines. + +### Pull requests are always welcome + +Not sure if that typo is worth a pull request? Found a bug and know how to fix +it? Do it! We will appreciate it. Any significant improvement should be +documented as [a GitHub issue](https://github.com/docker/docker/issues) before +anybody starts working on it. + +We are always thrilled to receive pull requests. We do our best to process them +quickly. If your pull request is not accepted on the first try, +don't get discouraged! Our contributor's guide explains [the review process we +use for simple changes](https://docs.docker.com/opensource/workflow/make-a-contribution/). + +### Design and cleanup proposals + +You can propose new designs for existing Docker features. You can also design +entirely new features. We really appreciate contributors who want to refactor or +otherwise cleanup our project. For information on making these types of +contributions, see [the advanced contribution +section](https://docs.docker.com/opensource/workflow/advanced-contributing/) in +the contributors guide. + +We try hard to keep Docker lean and focused. Docker can't do everything for +everybody. This means that we might decide against incorporating a new feature. +However, there might be a way to implement that feature *on top of* Docker. + +### Talking to other Docker users and contributors + + + + + + + + + + + + + + + + + + + + + + + + +
Forums + A public forum for users to discuss questions and explore current design patterns and + best practices about Docker and related projects in the Docker Ecosystem. To participate, + just log in with your Docker Hub account on https://forums.docker.com. +
Internet Relay Chat (IRC) +

+ IRC a direct line to our most knowledgeable Docker users; we have + both the #docker and #docker-dev group on + irc.freenode.net. + IRC is a rich chat protocol but it can overwhelm new users. You can search + our chat archives. +

+

+ Read our IRC quickstart guide + for an easy way to get started. +

+
Google Group + The docker-dev + group is for contributors and other people contributing to the Docker project. + You can join them without a google account by sending an email to + docker-dev+subscribe@googlegroups.com. + After receiving the join-request message, you can simply reply to that to confirm the subscription. +
Twitter + You can follow Docker's Twitter feed + to get updates on our products. You can also tweet us questions or just + share blogs or stories. +
Stack Overflow + Stack Overflow has over 17000 Docker questions listed. We regularly + monitor Docker questions + and so do many other knowledgeable Docker users. +
+ + +### Conventions + +Fork the repository and make changes on your fork in a feature branch: + +- If it's a bug fix branch, name it XXXX-something where XXXX is the number of + the issue. +- If it's a feature branch, create an enhancement issue to announce + your intentions, and name it XXXX-something where XXXX is the number of the + issue. + +Submit unit tests for your changes. Go has a great test framework built in; use +it! Take a look at existing tests for inspiration. [Run the full test +suite](https://docs.docker.com/opensource/project/test-and-docs/) on your branch before +submitting a pull request. + +Update the documentation when creating or modifying features. Test your +documentation changes for clarity, concision, and correctness, as well as a +clean documentation build. See our contributors guide for [our style +guide](https://docs.docker.com/opensource/doc-style) and instructions on [building +the documentation](https://docs.docker.com/opensource/project/test-and-docs/#build-and-test-the-documentation). + +Write clean code. Universally formatted code promotes ease of writing, reading, +and maintenance. Always run `gofmt -s -w file.go` on each changed file before +committing your changes. Most editors have plug-ins that do this automatically. + +Pull request descriptions should be as clear as possible and include a reference +to all the issues that they address. + +Commit messages must start with a capitalized and short summary (max. 50 chars) +written in the imperative, followed by an optional, more detailed explanatory +text which is separated from the summary by an empty line. + +Code review comments may be added to your pull request. Discuss, then make the +suggested modifications and push additional commits to your feature branch. Post +a comment after pushing. New commits show up in the pull request automatically, +but the reviewers are notified only when you comment. + +Pull requests must be cleanly rebased on top of master without multiple branches +mixed into the PR. + +**Git tip**: If your PR no longer merges cleanly, use `rebase master` in your +feature branch to update your pull request rather than `merge master`. + +Before you make a pull request, squash your commits into logical units of work +using `git rebase -i` and `git push -f`. A logical unit of work is a consistent +set of patches that should be reviewed together: for example, upgrading the +version of a vendored dependency and taking advantage of its now available new +feature constitute two separate units of work. Implementing a new function and +calling it in another file constitute a single logical unit of work. The very +high majority of submissions should have a single commit, so if in doubt: squash +down to one. + +After every commit, [make sure the test suite passes] +(https://docs.docker.com/opensource/project/test-and-docs/). Include documentation +changes in the same pull request so that a revert would remove all traces of +the feature or fix. + +Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that +close an issue. Including references automatically closes the issue on a merge. + +Please do not add yourself to the `AUTHORS` file, as it is regenerated regularly +from the Git history. + +Please see the [Coding Style](#coding-style) for further guidelines. + +### Merge approval + +Docker maintainers use LGTM (Looks Good To Me) in comments on the code review to +indicate acceptance. + +A change requires LGTMs from an absolute majority of the maintainers of each +component affected. For example, if a change affects `docs/` and `registry/`, it +needs an absolute majority from the maintainers of `docs/` AND, separately, an +absolute majority of the maintainers of `registry/`. + +For more details, see the [MAINTAINERS](MAINTAINERS) page. + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the patch. Your +signature certifies that you wrote the patch or otherwise have the right to pass +it on as an open-source patch. The rules are pretty simple: if you can certify +the below (from [developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +Then you just add a line to every git commit message: + + Signed-off-by: Joe Smith + +Use your real name (sorry, no pseudonyms or anonymous contributions.) + +If you set your `user.name` and `user.email` git configs, you can sign your +commit automatically with `git commit -s`. + +### How can I become a maintainer? + +The procedures for adding new maintainers are explained in the +global [MAINTAINERS](https://github.com/docker/opensource/blob/master/MAINTAINERS) +file in the [https://github.com/docker/opensource/](https://github.com/docker/opensource/) +repository. + +Don't forget: being a maintainer is a time investment. Make sure you +will have time to make yourself available. You don't have to be a +maintainer to make a difference on the project! + +## Docker community guidelines + +We want to keep the Docker community awesome, growing and collaborative. We need +your help to keep it that way. To help with this we've come up with some general +guidelines for the community as a whole: + +* Be nice: Be courteous, respectful and polite to fellow community members: + no regional, racial, gender, or other abuse will be tolerated. We like + nice people way better than mean ones! + +* Encourage diversity and participation: Make everyone in our community feel + welcome, regardless of their background and the extent of their + contributions, and do everything possible to encourage participation in + our community. + +* Keep it legal: Basically, don't get us in trouble. Share only content that + you own, do not share private or sensitive information, and don't break + the law. + +* Stay on topic: Make sure that you are posting to the correct channel and + avoid off-topic discussions. Remember when you update an issue or respond + to an email you are potentially sending to a large number of people. Please + consider this before you update. Also remember that nobody likes spam. + +* Don't send email to the maintainers: There's no need to send email to the + maintainers to ask them to investigate an issue or to take a look at a + pull request. Instead of sending an email, GitHub mentions should be + used to ping maintainers to review a pull request, a proposal or an + issue. + +### Guideline violations — 3 strikes method + +The point of this section is not to find opportunities to punish people, but we +do need a fair way to deal with people who are making our community suck. + +1. First occurrence: We'll give you a friendly, but public reminder that the + behavior is inappropriate according to our guidelines. + +2. Second occurrence: We will send you a private message with a warning that + any additional violations will result in removal from the community. + +3. Third occurrence: Depending on the violation, we may need to delete or ban + your account. + +**Notes:** + +* Obvious spammers are banned on first occurrence. If we don't do this, we'll + have spam all over the place. + +* Violations are forgiven after 6 months of good behavior, and we won't hold a + grudge. + +* People who commit minor infractions will get some education, rather than + hammering them in the 3 strikes process. + +* The rules apply equally to everyone in the community, no matter how much + you've contributed. + +* Extreme violations of a threatening, abusive, destructive or illegal nature + will be addressed immediately and are not subject to 3 strikes or forgiveness. + +* Contact abuse@docker.com to report abuse or appeal violations. In the case of + appeals, we know that mistakes happen, and we'll work with you to come up with a + fair solution if there has been a misunderstanding. + +## Coding Style + +Unless explicitly stated, we follow all coding guidelines from the Go +community. While some of these standards may seem arbitrary, they somehow seem +to result in a solid, consistent codebase. + +It is possible that the code base does not currently comply with these +guidelines. We are not looking for a massive PR that fixes this, since that +goes against the spirit of the guidelines. All new contributions should make a +best effort to clean up and make the code base better than they left it. +Obviously, apply your best judgement. Remember, the goal here is to make the +code base easier for humans to navigate and understand. Always keep that in +mind when nudging others to comply. + +The rules: + +1. All code should be formatted with `gofmt -s`. +2. All code should pass the default levels of + [`golint`](https://github.com/golang/lint). +3. All code should follow the guidelines covered in [Effective + Go](http://golang.org/doc/effective_go.html) and [Go Code Review + Comments](https://github.com/golang/go/wiki/CodeReviewComments). +4. Comment the code. Tell us the why, the history and the context. +5. Document _all_ declarations and methods, even private ones. Declare + expectations, caveats and anything else that may be important. If a type + gets exported, having the comments already there will ensure it's ready. +6. Variable name length should be proportional to its context and no longer. + `noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`. + In practice, short methods will have short variable names and globals will + have longer names. +7. No underscores in package names. If you need a compound name, step back, + and re-examine why you need a compound name. If you still think you need a + compound name, lose the underscore. +8. No utils or helpers packages. If a function is not general enough to + warrant its own package, it has not been written generally enough to be a + part of a util package. Just leave it unexported and well-documented. +9. All tests should run with `go test` and outside tooling should not be + required. No, we don't need another unit testing framework. Assertion + packages are acceptable if they provide _real_ incremental value. +10. Even though we call these "rules" above, they are actually just + guidelines. Since you've read all the rules, you now know that. + +If you are having trouble getting into the mood of idiomatic Go, we recommend +reading through [Effective Go](https://golang.org/doc/effective_go.html). The +[Go Blog](https://blog.golang.org) is also a great resource. Drinking the +kool-aid is a lot easier than going thirsty. diff --git a/vendor/github.com/docker/docker/Dockerfile b/vendor/github.com/docker/docker/Dockerfile new file mode 100644 index 000000000..ce2d70280 --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile @@ -0,0 +1,246 @@ +# This file describes the standard way to build Docker, using docker +# +# Usage: +# +# # Assemble the full dev environment. This is slow the first time. +# docker build -t docker . +# +# # Mount your source in an interactive container for quick testing: +# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash +# +# # Run the test suite: +# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py +# +# # Publish a release: +# docker run --privileged \ +# -e AWS_S3_BUCKET=baz \ +# -e AWS_ACCESS_KEY=foo \ +# -e AWS_SECRET_KEY=bar \ +# -e GPG_PASSPHRASE=gloubiboulga \ +# docker hack/release.sh +# +# Note: AppArmor used to mess with privileged mode, but this is no longer +# the case. Therefore, you don't have to disable it anymore. +# + +FROM debian:jessie + +# allow replacing httpredir or deb mirror +ARG APT_MIRROR=deb.debian.org +RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list + +# Add zfs ppa +RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61 \ + || apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61 +RUN echo deb http://ppa.launchpad.net/zfs-native/stable/ubuntu trusty main > /etc/apt/sources.list.d/zfs.list + +# Packaged dependencies +RUN apt-get update && apt-get install -y \ + apparmor \ + apt-utils \ + aufs-tools \ + automake \ + bash-completion \ + binutils-mingw-w64 \ + bsdmainutils \ + btrfs-tools \ + build-essential \ + clang \ + cmake \ + createrepo \ + curl \ + dpkg-sig \ + gcc-mingw-w64 \ + git \ + iptables \ + jq \ + libapparmor-dev \ + libcap-dev \ + libltdl-dev \ + libnl-3-dev \ + libprotobuf-c0-dev \ + libprotobuf-dev \ + libsqlite3-dev \ + libsystemd-journal-dev \ + libtool \ + mercurial \ + net-tools \ + pkg-config \ + protobuf-compiler \ + protobuf-c-compiler \ + python-dev \ + python-mock \ + python-pip \ + python-websocket \ + ubuntu-zfs \ + xfsprogs \ + vim-common \ + libzfs-dev \ + tar \ + zip \ + --no-install-recommends \ + && pip install awscli==1.10.15 +# Get lvm2 source for compiling statically +ENV LVM2_VERSION 2.02.103 +RUN mkdir -p /usr/local/lvm2 \ + && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \ + | tar -xzC /usr/local/lvm2 --strip-components=1 +# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags + +# Compile and install lvm2 +RUN cd /usr/local/lvm2 \ + && ./configure \ + --build="$(gcc -print-multiarch)" \ + --enable-static_link \ + && make device-mapper \ + && make install_device-mapper +# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL + +# Configure the container for OSX cross compilation +ENV OSX_SDK MacOSX10.11.sdk +ENV OSX_CROSS_COMMIT a9317c18a3a457ca0a657f08cc4d0d43c6cf8953 +RUN set -x \ + && export OSXCROSS_PATH="/osxcross" \ + && git clone https://github.com/tpoechtrager/osxcross.git $OSXCROSS_PATH \ + && ( cd $OSXCROSS_PATH && git checkout -q $OSX_CROSS_COMMIT) \ + && curl -sSL https://s3.dockerproject.org/darwin/v2/${OSX_SDK}.tar.xz -o "${OSXCROSS_PATH}/tarballs/${OSX_SDK}.tar.xz" \ + && UNATTENDED=yes OSX_VERSION_MIN=10.6 ${OSXCROSS_PATH}/build.sh +ENV PATH /osxcross/target/bin:$PATH + +# Install seccomp: the version shipped in trusty is too old +ENV SECCOMP_VERSION 2.3.1 +RUN set -x \ + && export SECCOMP_PATH="$(mktemp -d)" \ + && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \ + | tar -xzC "$SECCOMP_PATH" --strip-components=1 \ + && ( \ + cd "$SECCOMP_PATH" \ + && ./configure --prefix=/usr/local \ + && make \ + && make install \ + && ldconfig \ + ) \ + && rm -rf "$SECCOMP_PATH" + +# Install Go +# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines +# will need updating, to avoid errors. Ping #docker-maintainers on IRC +# with a heads-up. +ENV GO_VERSION 1.7.5 +RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \ + | tar -xzC /usr/local + +ENV PATH /go/bin:/usr/local/go/bin:$PATH +ENV GOPATH /go + +# Compile Go for cross compilation +ENV DOCKER_CROSSPLATFORMS \ + linux/386 linux/arm \ + darwin/amd64 \ + freebsd/amd64 freebsd/386 freebsd/arm \ + windows/amd64 windows/386 \ + solaris/amd64 + +# Dependency for golint +ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3 +RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \ + && (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) + +# Grab Go's lint tool +ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456 +RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \ + && (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \ + && go install -v github.com/golang/lint/golint + +# Install CRIU for checkpoint/restore support +ENV CRIU_VERSION 2.2 +RUN mkdir -p /usr/src/criu \ + && curl -sSL https://github.com/xemul/criu/archive/v${CRIU_VERSION}.tar.gz | tar -v -C /usr/src/criu/ -xz --strip-components=1 \ + && cd /usr/src/criu \ + && make \ + && make install-criu + +# Install two versions of the registry. The first is an older version that +# only supports schema1 manifests. The second is a newer version that supports +# both. This allows integration-cli tests to cover push/pull with both schema1 +# and schema2 manifests. +ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd +ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \ + && rm -rf "$GOPATH" + +# Install notary and notary-server +ENV NOTARY_VERSION v0.4.2 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \ + && rm -rf "$GOPATH" + +# Get the "docker-py" source so we can run their integration tests +ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324 +RUN git clone https://github.com/docker/docker-py.git /docker-py \ + && cd /docker-py \ + && git checkout -q $DOCKER_PY_COMMIT \ + && pip install -r test-requirements.txt + +# Install yamllint for validating swagger.yaml +RUN pip install yamllint==1.5.0 + +# Install go-swagger for validating swagger.yaml +ENV GO_SWAGGER_COMMIT c28258affb0b6251755d92489ef685af8d4ff3eb +RUN git clone https://github.com/go-swagger/go-swagger.git /go/src/github.com/go-swagger/go-swagger \ + && (cd /go/src/github.com/go-swagger/go-swagger && git checkout -q $GO_SWAGGER_COMMIT) \ + && go install -v github.com/go-swagger/go-swagger/cmd/swagger + +# Set user.email so crosbymichael's in-container merge commits go smoothly +RUN git config --global user.email 'docker-dummy@example.com' + +# Add an unprivileged user to be used for tests which need it +RUN groupadd -r docker +RUN useradd --create-home --gid docker unprivilegeduser + +VOLUME /var/lib/docker +WORKDIR /go/src/github.com/docker/docker +ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux + +# Let us use a .bashrc file +RUN ln -sfv $PWD/.bashrc ~/.bashrc +# Add integration helps to bashrc +RUN echo "source $PWD/hack/make/.integration-test-helpers" >> /etc/bash.bashrc + +# Register Docker's bash completion. +RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker + +# Get useful and necessary Hub images so we can "docker load" locally instead of pulling +COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/ +RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ + buildpack-deps:jessie@sha256:25785f89240fbcdd8a74bdaf30dd5599a9523882c6dfc567f2e9ef7cf6f79db6 \ + busybox:latest@sha256:e4f93f6ed15a0cdd342f5aae387886fba0ab98af0a102da6276eaf24d6e6ade0 \ + debian:jessie@sha256:f968f10b4b523737e253a97eac59b0d1420b5c19b69928d35801a6373ffe330e \ + hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 +# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) + +# Install tomlv, vndr, runc, containerd, tini, docker-proxy +# Please edit hack/dockerfile/install-binaries.sh to update them. +COPY hack/dockerfile/binaries-commits /tmp/binaries-commits +COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh +RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy bindata + +# Wrap all commands in the "docker-in-docker" script to allow nested containers +ENTRYPOINT ["hack/dind"] + +# Upload docker source +COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.aarch64 b/vendor/github.com/docker/docker/Dockerfile.aarch64 new file mode 100644 index 000000000..6112f802f --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.aarch64 @@ -0,0 +1,175 @@ +# This file describes the standard way to build Docker on aarch64, using docker +# +# Usage: +# +# # Assemble the full dev environment. This is slow the first time. +# docker build -t docker -f Dockerfile.aarch64 . +# +# # Mount your source in an interactive container for quick testing: +# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash +# +# # Run the test suite: +# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py +# +# Note: AppArmor used to mess with privileged mode, but this is no longer +# the case. Therefore, you don't have to disable it anymore. +# + +FROM aarch64/ubuntu:wily + +# Packaged dependencies +RUN apt-get update && apt-get install -y \ + apparmor \ + aufs-tools \ + automake \ + bash-completion \ + btrfs-tools \ + build-essential \ + cmake \ + createrepo \ + curl \ + dpkg-sig \ + g++ \ + gcc \ + git \ + iptables \ + jq \ + libapparmor-dev \ + libc6-dev \ + libcap-dev \ + libltdl-dev \ + libsqlite3-dev \ + libsystemd-dev \ + mercurial \ + net-tools \ + parallel \ + pkg-config \ + python-dev \ + python-mock \ + python-pip \ + python-websocket \ + gccgo \ + iproute2 \ + iputils-ping \ + vim-common \ + --no-install-recommends + +# Get lvm2 source for compiling statically +ENV LVM2_VERSION 2.02.103 +RUN mkdir -p /usr/local/lvm2 \ + && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \ + | tar -xzC /usr/local/lvm2 --strip-components=1 +# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags + +# Fix platform enablement in lvm2 to support aarch64 properly +RUN set -e \ + && for f in config.guess config.sub; do \ + curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \ + done +# "arch.c:78:2: error: #error the arch code needs to know about your machine type" + +# Compile and install lvm2 +RUN cd /usr/local/lvm2 \ + && ./configure \ + --build="$(gcc -print-multiarch)" \ + --enable-static_link \ + && make device-mapper \ + && make install_device-mapper +# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL + +# Install seccomp: the version shipped in trusty is too old +ENV SECCOMP_VERSION 2.3.1 +RUN set -x \ + && export SECCOMP_PATH="$(mktemp -d)" \ + && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \ + | tar -xzC "$SECCOMP_PATH" --strip-components=1 \ + && ( \ + cd "$SECCOMP_PATH" \ + && ./configure --prefix=/usr/local \ + && make \ + && make install \ + && ldconfig \ + ) \ + && rm -rf "$SECCOMP_PATH" + +# Install Go +# We don't have official binary tarballs for ARM64, eigher for Go or bootstrap, +# so we use gccgo as bootstrap to build Go from source code. +# We don't use the official ARMv6 released binaries as a GOROOT_BOOTSTRAP, because +# not all ARM64 platforms support 32-bit mode. 32-bit mode is optional for ARMv8. +ENV GO_VERSION 1.7.5 +RUN mkdir /usr/src/go && curl -fsSL https://golang.org/dl/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \ + && cd /usr/src/go/src \ + && GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP="$(go env GOROOT)" ./make.bash + +ENV PATH /usr/src/go/bin:$PATH +ENV GOPATH /go + +# Only install one version of the registry, because old version which support +# schema1 manifests is not working on ARM64, we should skip integration-cli +# tests for schema1 manifests on ARM64. +ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \ + && rm -rf "$GOPATH" + +# Install notary and notary-server +ENV NOTARY_VERSION v0.4.2 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \ + && rm -rf "$GOPATH" + +# Get the "docker-py" source so we can run their integration tests +ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324 +RUN git clone https://github.com/docker/docker-py.git /docker-py \ + && cd /docker-py \ + && git checkout -q $DOCKER_PY_COMMIT \ + && pip install -r test-requirements.txt + +# Set user.email so crosbymichael's in-container merge commits go smoothly +RUN git config --global user.email 'docker-dummy@example.com' + +# Add an unprivileged user to be used for tests which need it +RUN groupadd -r docker +RUN useradd --create-home --gid docker unprivilegeduser + +VOLUME /var/lib/docker +WORKDIR /go/src/github.com/docker/docker +ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux + +# Let us use a .bashrc file +RUN ln -sfv $PWD/.bashrc ~/.bashrc + +# Register Docker's bash completion. +RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker + +# Get useful and necessary Hub images so we can "docker load" locally instead of pulling +COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/ +RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ + aarch64/buildpack-deps:jessie@sha256:6aa1d6910791b7ac78265fd0798e5abd6cb3f27ae992f6f960f6c303ec9535f2 \ + aarch64/busybox:latest@sha256:b23a6a37cf269dff6e46d2473b6e227afa42b037e6d23435f1d2bc40fc8c2828 \ + aarch64/debian:jessie@sha256:4be74a41a7c70ebe887b634b11ffe516cf4fcd56864a54941e56bb49883c3170 \ + aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda +# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) + +# Install tomlv, vndr, runc, containerd, tini, docker-proxy +# Please edit hack/dockerfile/install-binaries.sh to update them. +COPY hack/dockerfile/binaries-commits /tmp/binaries-commits +COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh +RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy + +# Wrap all commands in the "docker-in-docker" script to allow nested containers +ENTRYPOINT ["hack/dind"] + +# Upload docker source +COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.armhf b/vendor/github.com/docker/docker/Dockerfile.armhf new file mode 100644 index 000000000..1aebc166b --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.armhf @@ -0,0 +1,182 @@ +# This file describes the standard way to build Docker on ARMv7, using docker +# +# Usage: +# +# # Assemble the full dev environment. This is slow the first time. +# docker build -t docker -f Dockerfile.armhf . +# +# # Mount your source in an interactive container for quick testing: +# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash +# +# # Run the test suite: +# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py +# +# Note: AppArmor used to mess with privileged mode, but this is no longer +# the case. Therefore, you don't have to disable it anymore. +# + +FROM armhf/debian:jessie + +# allow replacing httpredir or deb mirror +ARG APT_MIRROR=deb.debian.org +RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list + +# Packaged dependencies +RUN apt-get update && apt-get install -y \ + apparmor \ + aufs-tools \ + automake \ + bash-completion \ + btrfs-tools \ + build-essential \ + createrepo \ + curl \ + cmake \ + dpkg-sig \ + git \ + iptables \ + jq \ + net-tools \ + libapparmor-dev \ + libcap-dev \ + libltdl-dev \ + libsqlite3-dev \ + libsystemd-journal-dev \ + libtool \ + mercurial \ + pkg-config \ + python-dev \ + python-mock \ + python-pip \ + python-websocket \ + xfsprogs \ + tar \ + vim-common \ + --no-install-recommends \ + && pip install awscli==1.10.15 + +# Get lvm2 source for compiling statically +ENV LVM2_VERSION 2.02.103 +RUN mkdir -p /usr/local/lvm2 \ + && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \ + | tar -xzC /usr/local/lvm2 --strip-components=1 +# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags + +# Compile and install lvm2 +RUN cd /usr/local/lvm2 \ + && ./configure \ + --build="$(gcc -print-multiarch)" \ + --enable-static_link \ + && make device-mapper \ + && make install_device-mapper +# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL + +# Install Go +ENV GO_VERSION 1.7.5 +RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-armv6l.tar.gz" \ + | tar -xzC /usr/local +ENV PATH /go/bin:/usr/local/go/bin:$PATH +ENV GOPATH /go + +# We're building for armhf, which is ARMv7, so let's be explicit about that +ENV GOARCH arm +ENV GOARM 7 + +# Dependency for golint +ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3 +RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \ + && (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) + +# Grab Go's lint tool +ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456 +RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \ + && (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \ + && go install -v github.com/golang/lint/golint + +# Install seccomp: the version shipped in trusty is too old +ENV SECCOMP_VERSION 2.3.1 +RUN set -x \ + && export SECCOMP_PATH="$(mktemp -d)" \ + && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \ + | tar -xzC "$SECCOMP_PATH" --strip-components=1 \ + && ( \ + cd "$SECCOMP_PATH" \ + && ./configure --prefix=/usr/local \ + && make \ + && make install \ + && ldconfig \ + ) \ + && rm -rf "$SECCOMP_PATH" + +# Install two versions of the registry. The first is an older version that +# only supports schema1 manifests. The second is a newer version that supports +# both. This allows integration-cli tests to cover push/pull with both schema1 +# and schema2 manifests. +ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd +ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \ + && rm -rf "$GOPATH" + +# Install notary and notary-server +ENV NOTARY_VERSION v0.4.2 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \ + && rm -rf "$GOPATH" + +# Get the "docker-py" source so we can run their integration tests +ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324 +RUN git clone https://github.com/docker/docker-py.git /docker-py \ + && cd /docker-py \ + && git checkout -q $DOCKER_PY_COMMIT \ + && pip install -r test-requirements.txt + +# Set user.email so crosbymichael's in-container merge commits go smoothly +RUN git config --global user.email 'docker-dummy@example.com' + +# Add an unprivileged user to be used for tests which need it +RUN groupadd -r docker +RUN useradd --create-home --gid docker unprivilegeduser + +VOLUME /var/lib/docker +WORKDIR /go/src/github.com/docker/docker +ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux + +# Let us use a .bashrc file +RUN ln -sfv $PWD/.bashrc ~/.bashrc + +# Register Docker's bash completion. +RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker + +# Get useful and necessary Hub images so we can "docker load" locally instead of pulling +COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/ +RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ + armhf/buildpack-deps:jessie@sha256:ca6cce8e5bf5c952129889b5cc15cd6aa8d995d77e55e3749bbaadae50e476cb \ + armhf/busybox:latest@sha256:d98a7343ac750ffe387e3d514f8521ba69846c216778919b01414b8617cfb3d4 \ + armhf/debian:jessie@sha256:4a2187483f04a84f9830910fe3581d69b3c985cc045d9f01d8e2f3795b28107b \ + armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791 +# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) + +# Install tomlv, vndr, runc, containerd, tini, docker-proxy +# Please edit hack/dockerfile/install-binaries.sh to update them. +COPY hack/dockerfile/binaries-commits /tmp/binaries-commits +COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh +RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy + +ENTRYPOINT ["hack/dind"] + +# Upload docker source +COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.ppc64le b/vendor/github.com/docker/docker/Dockerfile.ppc64le new file mode 100644 index 000000000..1f9f5006f --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.ppc64le @@ -0,0 +1,188 @@ +# This file describes the standard way to build Docker on ppc64le, using docker +# +# Usage: +# +# # Assemble the full dev environment. This is slow the first time. +# docker build -t docker -f Dockerfile.ppc64le . +# +# # Mount your source in an interactive container for quick testing: +# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash +# +# # Run the test suite: +# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py +# +# Note: AppArmor used to mess with privileged mode, but this is no longer +# the case. Therefore, you don't have to disable it anymore. +# + +FROM ppc64le/debian:jessie + +# allow replacing httpredir or deb mirror +ARG APT_MIRROR=deb.debian.org +RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list + +# Packaged dependencies +RUN apt-get update && apt-get install -y \ + apparmor \ + aufs-tools \ + automake \ + bash-completion \ + btrfs-tools \ + build-essential \ + cmake \ + createrepo \ + curl \ + dpkg-sig \ + git \ + iptables \ + jq \ + net-tools \ + libapparmor-dev \ + libcap-dev \ + libltdl-dev \ + libsqlite3-dev \ + libsystemd-journal-dev \ + libtool \ + mercurial \ + pkg-config \ + python-dev \ + python-mock \ + python-pip \ + python-websocket \ + xfsprogs \ + tar \ + vim-common \ + --no-install-recommends + +# Get lvm2 source for compiling statically +ENV LVM2_VERSION 2.02.103 +RUN mkdir -p /usr/local/lvm2 \ + && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \ + | tar -xzC /usr/local/lvm2 --strip-components=1 +# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags + +# Fix platform enablement in lvm2 to support ppc64le properly +RUN set -e \ + && for f in config.guess config.sub; do \ + curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \ + done +# "arch.c:78:2: error: #error the arch code needs to know about your machine type" + +# Compile and install lvm2 +RUN cd /usr/local/lvm2 \ + && ./configure \ + --build="$(gcc -print-multiarch)" \ + --enable-static_link \ + && make device-mapper \ + && make install_device-mapper +# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL + +# Install seccomp: the version shipped in jessie is too old +ENV SECCOMP_VERSION 2.3.1 +RUN set -x \ + && export SECCOMP_PATH="$(mktemp -d)" \ + && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \ + | tar -xzC "$SECCOMP_PATH" --strip-components=1 \ + && ( \ + cd "$SECCOMP_PATH" \ + && ./configure --prefix=/usr/local \ + && make \ + && make install \ + && ldconfig \ + ) \ + && rm -rf "$SECCOMP_PATH" + + +# Install Go +# NOTE: official ppc64le go binaries weren't available until go 1.6.4 and 1.7.4 +ENV GO_VERSION 1.7.5 +RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" \ + | tar -xzC /usr/local + +ENV PATH /go/bin:/usr/local/go/bin:$PATH +ENV GOPATH /go + +# Dependency for golint +ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3 +RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \ + && (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) + +# Grab Go's lint tool +ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456 +RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \ + && (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \ + && go install -v github.com/golang/lint/golint + +# Install two versions of the registry. The first is an older version that +# only supports schema1 manifests. The second is a newer version that supports +# both. This allows integration-cli tests to cover push/pull with both schema1 +# and schema2 manifests. +ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd +ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \ + && rm -rf "$GOPATH" + +# Install notary and notary-server +ENV NOTARY_VERSION v0.4.2 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ + && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ + && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \ + && rm -rf "$GOPATH" + +# Get the "docker-py" source so we can run their integration tests +ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324 +RUN git clone https://github.com/docker/docker-py.git /docker-py \ + && cd /docker-py \ + && git checkout -q $DOCKER_PY_COMMIT \ + && pip install -r test-requirements.txt + +# Set user.email so crosbymichael's in-container merge commits go smoothly +RUN git config --global user.email 'docker-dummy@example.com' + +# Add an unprivileged user to be used for tests which need it +RUN groupadd -r docker +RUN useradd --create-home --gid docker unprivilegeduser + +VOLUME /var/lib/docker +WORKDIR /go/src/github.com/docker/docker +ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux + +# Let us use a .bashrc file +RUN ln -sfv $PWD/.bashrc ~/.bashrc + +# Register Docker's bash completion. +RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker + +# Get useful and necessary Hub images so we can "docker load" locally instead of pulling +COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/ +RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ + ppc64le/buildpack-deps:jessie@sha256:902bfe4ef1389f94d143d64516dd50a2de75bca2e66d4a44b1d73f63ddf05dda \ + ppc64le/busybox:latest@sha256:38bb82085248d5a3c24bd7a5dc146f2f2c191e189da0441f1c2ca560e3fc6f1b \ + ppc64le/debian:jessie@sha256:412845f51b6ab662afba71bc7a716e20fdb9b84f185d180d4c7504f8a75c4f91 \ + ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974 +# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) + +# Install tomlv, vndr, runc, containerd, tini, docker-proxy +# Please edit hack/dockerfile/install-binaries.sh to update them. +COPY hack/dockerfile/binaries-commits /tmp/binaries-commits +COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh +RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy + +# Wrap all commands in the "docker-in-docker" script to allow nested containers +ENTRYPOINT ["hack/dind"] + +# Upload docker source +COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.s390x b/vendor/github.com/docker/docker/Dockerfile.s390x new file mode 100644 index 000000000..ba94bc70a --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.s390x @@ -0,0 +1,190 @@ +# This file describes the standard way to build Docker on s390x, using docker +# +# Usage: +# +# # Assemble the full dev environment. This is slow the first time. +# docker build -t docker -f Dockerfile.s390x . +# +# # Mount your source in an interactive container for quick testing: +# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash +# +# # Run the test suite: +# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py +# +# Note: AppArmor used to mess with privileged mode, but this is no longer +# the case. Therefore, you don't have to disable it anymore. +# + +FROM s390x/gcc:6.1 + +# Packaged dependencies +RUN apt-get update && apt-get install -y \ + apparmor \ + aufs-tools \ + automake \ + bash-completion \ + btrfs-tools \ + build-essential \ + cmake \ + createrepo \ + curl \ + dpkg-sig \ + git \ + iptables \ + jq \ + net-tools \ + libapparmor-dev \ + libcap-dev \ + libltdl-dev \ + libsqlite3-dev \ + libsystemd-journal-dev \ + libtool \ + mercurial \ + pkg-config \ + python-dev \ + python-mock \ + python-pip \ + python-websocket \ + xfsprogs \ + tar \ + vim-common \ + --no-install-recommends + +# glibc in Debian has a bug specific to s390x that won't be fixed until Debian 8.6 is released +# - https://github.com/docker/docker/issues/24748 +# - https://sourceware.org/git/?p=glibc.git;a=commit;h=890b7a4b33d482b5c768ab47d70758b80227e9bc +# - https://sourceware.org/git/?p=glibc.git;a=commit;h=2e807f29595eb5b1e5d0decc6e356a3562ecc58e +RUN echo 'deb http://httpredir.debian.org/debian jessie-proposed-updates main' >> /etc/apt/sources.list.d/pu.list \ + && apt-get update \ + && apt-get install -y libc6 \ + && rm -rf /var/lib/apt/lists/* + +# Install seccomp: the version shipped in jessie is too old +ENV SECCOMP_VERSION 2.3.1 +RUN set -x \ + && export SECCOMP_PATH="$(mktemp -d)" \ + && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \ + | tar -xzC "$SECCOMP_PATH" --strip-components=1 \ + && ( \ + cd "$SECCOMP_PATH" \ + && ./configure --prefix=/usr/local \ + && make \ + && make install \ + && ldconfig \ + ) \ + && rm -rf "$SECCOMP_PATH" + +# Get lvm2 source for compiling statically +ENV LVM2_VERSION 2.02.103 +RUN mkdir -p /usr/local/lvm2 \ + && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \ + | tar -xzC /usr/local/lvm2 --strip-components=1 +# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags + +# Fix platform enablement in lvm2 to support s390x properly +RUN set -e \ + && for f in config.guess config.sub; do \ + curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \ + done +# "arch.c:78:2: error: #error the arch code needs to know about your machine type" + +# Compile and install lvm2 +RUN cd /usr/local/lvm2 \ + && ./configure \ + --build="$(gcc -print-multiarch)" \ + --enable-static_link \ + && make device-mapper \ + && make install_device-mapper +# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL + +ENV GO_VERSION 1.7.5 +RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-s390x.tar.gz" \ + | tar -xzC /usr/local + +ENV PATH /go/bin:/usr/local/go/bin:$PATH +ENV GOPATH /go + +# Dependency for golint +ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3 +RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \ + && (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) + +# Grab Go's lint tool +ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456 +RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \ + && (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \ + && go install -v github.com/golang/lint/golint + +# Install two versions of the registry. The first is an older version that +# only supports schema1 manifests. The second is a newer version that supports +# both. This allows integration-cli tests to cover push/pull with both schema1 +# and schema2 manifests. +ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd +ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \ + && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \ + && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ + go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \ + && rm -rf "$GOPATH" + +# Install notary and notary-server +ENV NOTARY_VERSION v0.4.2 +RUN set -x \ + && export GOPATH="$(mktemp -d)" \ + && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ + && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ + go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \ + && rm -rf "$GOPATH" + +# Get the "docker-py" source so we can run their integration tests +ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324 +RUN git clone https://github.com/docker/docker-py.git /docker-py \ + && cd /docker-py \ + && git checkout -q $DOCKER_PY_COMMIT \ + && pip install -r test-requirements.txt + +# Set user.email so crosbymichael's in-container merge commits go smoothly +RUN git config --global user.email 'docker-dummy@example.com' + +# Add an unprivileged user to be used for tests which need it +RUN groupadd -r docker +RUN useradd --create-home --gid docker unprivilegeduser + +VOLUME /var/lib/docker +WORKDIR /go/src/github.com/docker/docker +ENV DOCKER_BUILDTAGS apparmor selinux seccomp + +# Let us use a .bashrc file +RUN ln -sfv $PWD/.bashrc ~/.bashrc + +# Register Docker's bash completion. +RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker + +# Get useful and necessary Hub images so we can "docker load" locally instead of pulling +COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/ +RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ + s390x/buildpack-deps:jessie@sha256:4d1381224acaca6c4bfe3604de3af6972083a8558a99672cb6989c7541780099 \ + s390x/busybox:latest@sha256:dd61522c983884a66ed72d60301925889028c6d2d5e0220a8fe1d9b4c6a4f01b \ + s390x/debian:jessie@sha256:b74c863400909eff3c5e196cac9bfd1f6333ce47aae6a38398d87d5875da170a \ + s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699 +# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) + +# Install tomlv, vndr, runc, containerd, tini, docker-proxy +# Please edit hack/dockerfile/install-binaries.sh to update them. +COPY hack/dockerfile/binaries-commits /tmp/binaries-commits +COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh +RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy + +# Wrap all commands in the "docker-in-docker" script to allow nested containers +ENTRYPOINT ["hack/dind"] + +# Upload docker source +COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.simple b/vendor/github.com/docker/docker/Dockerfile.simple new file mode 100644 index 000000000..8eeb3d96b --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.simple @@ -0,0 +1,73 @@ +# docker build -t docker:simple -f Dockerfile.simple . +# docker run --rm docker:simple hack/make.sh dynbinary +# docker run --rm --privileged docker:simple hack/dind hack/make.sh test-unit +# docker run --rm --privileged -v /var/lib/docker docker:simple hack/dind hack/make.sh dynbinary test-integration-cli + +# This represents the bare minimum required to build and test Docker. + +FROM debian:jessie + +# allow replacing httpredir or deb mirror +ARG APT_MIRROR=deb.debian.org +RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list + +# Compile and runtime deps +# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#build-dependencies +# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#runtime-dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + btrfs-tools \ + build-essential \ + curl \ + cmake \ + gcc \ + git \ + libapparmor-dev \ + libdevmapper-dev \ + libsqlite3-dev \ + \ + ca-certificates \ + e2fsprogs \ + iptables \ + procps \ + xfsprogs \ + xz-utils \ + \ + aufs-tools \ + vim-common \ + && rm -rf /var/lib/apt/lists/* + +# Install seccomp: the version shipped in trusty is too old +ENV SECCOMP_VERSION 2.3.1 +RUN set -x \ + && export SECCOMP_PATH="$(mktemp -d)" \ + && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \ + | tar -xzC "$SECCOMP_PATH" --strip-components=1 \ + && ( \ + cd "$SECCOMP_PATH" \ + && ./configure --prefix=/usr/local \ + && make \ + && make install \ + && ldconfig \ + ) \ + && rm -rf "$SECCOMP_PATH" + +# Install Go +# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines +# will need updating, to avoid errors. Ping #docker-maintainers on IRC +# with a heads-up. +ENV GO_VERSION 1.7.5 +RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \ + | tar -xzC /usr/local +ENV PATH /go/bin:/usr/local/go/bin:$PATH +ENV GOPATH /go +ENV CGO_LDFLAGS -L/lib + +# Install runc, containerd, tini and docker-proxy +# Please edit hack/dockerfile/install-binaries.sh to update them. +COPY hack/dockerfile/binaries-commits /tmp/binaries-commits +COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh +RUN /tmp/install-binaries.sh runc containerd tini proxy + +ENV AUTO_GOPATH 1 +WORKDIR /usr/src/docker +COPY . /usr/src/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.solaris b/vendor/github.com/docker/docker/Dockerfile.solaris new file mode 100644 index 000000000..bb342e5e6 --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.solaris @@ -0,0 +1,20 @@ +# Defines an image that hosts a native Docker build environment for Solaris +# TODO: Improve stub + +FROM solaris:latest + +# compile and runtime deps +RUN pkg install --accept \ + git \ + gnu-coreutils \ + gnu-make \ + gnu-tar \ + diagnostic/top \ + golang \ + library/golang/* \ + developer/gcc-* + +ENV GOPATH /go/:/usr/lib/gocode/1.5/ +ENV DOCKER_CROSSPLATFORMS solaris/amd64 +WORKDIR /go/src/github.com/docker/docker +COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.windows b/vendor/github.com/docker/docker/Dockerfile.windows new file mode 100644 index 000000000..652d07275 --- /dev/null +++ b/vendor/github.com/docker/docker/Dockerfile.windows @@ -0,0 +1,267 @@ +# escape=` + +# ----------------------------------------------------------------------------------------- +# This file describes the standard way to build Docker in a container on Windows +# Server 2016 or Windows 10. +# +# Maintainer: @jhowardmsft +# ----------------------------------------------------------------------------------------- + + +# Prerequisites: +# -------------- +# +# 1. Windows Server 2016 or Windows 10 with all Windows updates applied. The major +# build number must be at least 14393. This can be confirmed, for example, by +# running the following from an elevated PowerShell prompt - this sample output +# is from a fully up to date machine as at mid-November 2016: +# +# >> PS C:\> $(gin).WindowsBuildLabEx +# >> 14393.447.amd64fre.rs1_release_inmarket.161102-0100 +# +# 2. Git for Windows (or another git client) must be installed. https://git-scm.com/download/win. +# +# 3. The machine must be configured to run containers. For example, by following +# the quick start guidance at https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start or +# https://github.com/docker/labs/blob/master/windows/windows-containers/Setup.md +# +# 4. If building in a Hyper-V VM: For Windows Server 2016 using Windows Server +# containers as the default option, it is recommended you have at least 1GB +# of memory assigned; For Windows 10 where Hyper-V Containers are employed, you +# should have at least 4GB of memory assigned. Note also, to run Hyper-V +# containers in a VM, it is necessary to configure the VM for nested virtualization. + +# ----------------------------------------------------------------------------------------- + + +# Usage: +# ----- +# +# The following steps should be run from an (elevated*) Windows PowerShell prompt. +# +# (*In a default installation of containers on Windows following the quick-start guidance at +# https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start, +# the docker.exe client must run elevated to be able to connect to the daemon). +# +# 1. Clone the sources from github.com: +# +# >> git clone https://github.com/docker/docker.git C:\go\src\github.com\docker\docker +# >> Cloning into 'C:\go\src\github.com\docker\docker'... +# >> remote: Counting objects: 186216, done. +# >> remote: Compressing objects: 100% (21/21), done. +# >> remote: Total 186216 (delta 5), reused 0 (delta 0), pack-reused 186195 +# >> Receiving objects: 100% (186216/186216), 104.32 MiB | 8.18 MiB/s, done. +# >> Resolving deltas: 100% (123139/123139), done. +# >> Checking connectivity... done. +# >> Checking out files: 100% (3912/3912), done. +# >> PS C:\> +# +# +# 2. Change directory to the cloned docker sources: +# +# >> cd C:\go\src\github.com\docker\docker +# +# +# 3. Build a docker image with the components required to build the docker binaries from source +# by running one of the following: +# +# >> docker build -t nativebuildimage -f Dockerfile.windows . +# >> docker build -t nativebuildimage -f Dockerfile.windows -m 2GB . (if using Hyper-V containers) +# +# +# 4. Build the docker executable binaries by running one of the following: +# +# >> docker run --name binaries nativebuildimage hack\make.ps1 -Binary +# >> docker run --name binaries -m 2GB nativebuildimage hack\make.ps1 -Binary (if using Hyper-V containers) +# +# +# 5. Copy the binaries out of the container, replacing HostPath with an appropriate destination +# folder on the host system where you want the binaries to be located. +# +# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\docker.exe C:\HostPath\docker.exe +# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\dockerd.exe C:\HostPath\dockerd.exe +# +# +# 6. (Optional) Remove the interim container holding the built executable binaries: +# +# >> docker rm binaries +# +# +# 7. (Optional) Remove the image used for the container in which the executable +# binaries are build. Tip - it may be useful to keep this image around if you need to +# build multiple times. Then you can take advantage of the builder cache to have an +# image which has all the components required to build the binaries already installed. +# +# >> docker rmi nativebuildimage +# + +# ----------------------------------------------------------------------------------------- + + +# The validation tests can either run in a container, or directly on the host. To run in a +# container, ensure you have created the nativebuildimage above. Then run one of the +# following from an (elevated) Windows PowerShell prompt: +# +# >> docker run --rm nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat +# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat (if using Hyper-V containers) + +# To run the validation tests on the host, from the root of the repository, run the +# following from a Windows PowerShell prompt (elevation is not required): (Note Go +# must be installed to run these tests) +# +# >> hack\make.ps1 -DCO -PkgImports -GoFormat + +# ----------------------------------------------------------------------------------------- + + +# To run unit tests, ensure you have created the nativebuildimage above. Then run one of +# the following from an (elevated) Windows PowerShell prompt: +# +# >> docker run --rm nativebuildimage hack\make.ps1 -TestUnit +# >> docker run --rm -m 2GB nativebuildimage hack\make.ps1 -TestUnit (if using Hyper-V containers) + + +# ----------------------------------------------------------------------------------------- + + +# To run all tests and binary build, ensure you have created the nativebuildimage above. Then +# run one of the following from an (elevated) Windows PowerShell prompt: +# +# >> docker run nativebuildimage hack\make.ps1 -All +# >> docker run -m 2GB nativebuildimage hack\make.ps1 -All (if using Hyper-V containers) + +# ----------------------------------------------------------------------------------------- + + +# Important notes: +# --------------- +# +# Don't attempt to use a bind-mount to pass a local directory as the bundles target +# directory. It does not work (golang attempts for follow a mapped folder incorrectly). +# Instead, use docker cp as per the example. +# +# go.zip is not removed from the image as it is used by the Windows CI servers +# to ensure the host and image are running consistent versions of go. +# +# Nanoserver support is a work in progress. Although the image will build if the +# FROM statement is updated, it will not work when running autogen through hack\make.ps1. +# It is suspected that the required GCC utilities (eg gcc, windres, windmc) silently +# quit due to the use of console hooks which are not available. +# +# The docker integration tests do not currently run in a container on Windows, predominantly +# due to Windows not supporting privileged mode, so anything using a volume would fail. +# They (along with the rest of the docker CI suite) can be run using +# https://github.com/jhowardmsft/docker-w2wCIScripts/blob/master/runCI/Invoke-DockerCI.ps1. +# +# ----------------------------------------------------------------------------------------- + + +# The number of build steps below are explicitly minimised to improve performance. +FROM microsoft/windowsservercore + +# Use PowerShell as the default shell +SHELL ["powershell", "-command"] + +# Environment variable notes: +# - GO_VERSION must be consistent with 'Dockerfile' used by Linux. +# - FROM_DOCKERFILE is used for detection of building within a container. +ENV GO_VERSION=1.7.5 ` + GIT_VERSION=2.11.0 ` + GOPATH=C:\go ` + FROM_DOCKERFILE=1 + +RUN ` + $ErrorActionPreference = 'Stop'; ` + $ProgressPreference = 'SilentlyContinue'; ` + ` + Function Test-Nano() { ` + $EditionId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'EditionID').EditionId; ` + return (($EditionId -eq 'ServerStandardNano') -or ($EditionId -eq 'ServerDataCenterNano') -or ($EditionId -eq 'NanoServer')); ` + }` + ` + Function Download-File([string] $source, [string] $target) { ` + if (Test-Nano) { ` + $handler = New-Object System.Net.Http.HttpClientHandler; ` + $client = New-Object System.Net.Http.HttpClient($handler); ` + $client.Timeout = New-Object System.TimeSpan(0, 30, 0); ` + $cancelTokenSource = [System.Threading.CancellationTokenSource]::new(); ` + $responseMsg = $client.GetAsync([System.Uri]::new($source), $cancelTokenSource.Token); ` + $responseMsg.Wait(); ` + if (!$responseMsg.IsCanceled) { ` + $response = $responseMsg.Result; ` + if ($response.IsSuccessStatusCode) { ` + $downloadedFileStream = [System.IO.FileStream]::new($target, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write); ` + $copyStreamOp = $response.Content.CopyToAsync($downloadedFileStream); ` + $copyStreamOp.Wait(); ` + $downloadedFileStream.Close(); ` + if ($copyStreamOp.Exception -ne $null) { throw $copyStreamOp.Exception } ` + } ` + } else { ` + Throw ("Failed to download " + $source) ` + }` + } else { ` + $webClient = New-Object System.Net.WebClient; ` + $webClient.DownloadFile($source, $target); ` + } ` + } ` + ` + setx /M PATH $('C:\git\bin;C:\git\usr\bin;'+$Env:PATH+';C:\gcc\bin;C:\go\bin'); ` + ` + Write-Host INFO: Downloading git...; ` + $location='https://github.com/git-for-windows/git/releases/download/v'+$env:GIT_VERSION+'.windows.1/PortableGit-'+$env:GIT_VERSION+'-64-bit.7z.exe'; ` + Download-File $location C:\gitsetup.7z.exe; ` + ` + Write-Host INFO: Downloading go...; ` + Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; ` + ` + Write-Host INFO: Downloading compiler 1 of 3...; ` + Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip C:\gcc.zip; ` + ` + Write-Host INFO: Downloading compiler 2 of 3...; ` + Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip C:\runtime.zip; ` + ` + Write-Host INFO: Downloading compiler 3 of 3...; ` + Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip C:\binutils.zip; ` + ` + Write-Host INFO: Installing PS7Zip package...; ` + Install-Package PS7Zip -Force | Out-Null; ` + Write-Host INFO: Importing PS7Zip...; ` + Import-Module PS7Zip -Force; ` + New-Item C:\git -ItemType Directory | Out-Null ; ` + cd C:\git; ` + Write-Host INFO: Extracting git...; ` + Expand-7Zip C:\gitsetup.7z.exe | Out-Null; ` + cd C:\; ` + ` + Write-Host INFO: Expanding go...; ` + Expand-Archive C:\go.zip -DestinationPath C:\; ` + ` + Write-Host INFO: Expanding compiler 1 of 3...; ` + Expand-Archive C:\gcc.zip -DestinationPath C:\gcc -Force; ` + Write-Host INFO: Expanding compiler 2 of 3...; ` + Expand-Archive C:\runtime.zip -DestinationPath C:\gcc -Force; ` + Write-Host INFO: Expanding compiler 3 of 3...; ` + Expand-Archive C:\binutils.zip -DestinationPath C:\gcc -Force; ` + ` + Write-Host INFO: Removing downloaded files...; ` + Remove-Item C:\gcc.zip; ` + Remove-Item C:\runtime.zip; ` + Remove-Item C:\binutils.zip; ` + Remove-Item C:\gitsetup.7z.exe; ` + ` + Write-Host INFO: Creating source directory...; ` + New-Item -ItemType Directory -Path C:\go\src\github.com\docker\docker | Out-Null; ` + ` + Write-Host INFO: Configuring git core.autocrlf...; ` + C:\git\bin\git config --global core.autocrlf true; ` + ` + Write-Host INFO: Completed + +# Make PowerShell the default entrypoint +ENTRYPOINT ["powershell.exe"] + +# Set the working directory to the location of the sources +WORKDIR C:\go\src\github.com\docker\docker + +# Copy the sources into the container +COPY . . diff --git a/vendor/github.com/docker/docker/MAINTAINERS b/vendor/github.com/docker/docker/MAINTAINERS new file mode 100644 index 000000000..39bb8c130 --- /dev/null +++ b/vendor/github.com/docker/docker/MAINTAINERS @@ -0,0 +1,376 @@ +# Docker maintainers file +# +# This file describes who runs the docker/docker project and how. +# This is a living document - if you see something out of date or missing, speak up! +# +# It is structured to be consumable by both humans and programs. +# To extract its contents programmatically, use any TOML-compliant +# parser. +# +# This file is compiled into the MAINTAINERS file in docker/opensource. +# +[Org] + + [Org."Core maintainers"] + + # The Core maintainers are the ghostbusters of the project: when there's a problem others + # can't solve, they show up and fix it with bizarre devices and weaponry. + # They have final say on technical implementation and coding style. + # They are ultimately responsible for quality in all its forms: usability polish, + # bugfixes, performance, stability, etc. When ownership can cleanly be passed to + # a subsystem, they are responsible for doing so and holding the + # subsystem maintainers accountable. If ownership is unclear, they are the de facto owners. + + # For each release (including minor releases), a "release captain" is assigned from the + # pool of core maintainers. Rotation is encouraged across all maintainers, to ensure + # the release process is clear and up-to-date. + + people = [ + "aaronlehmann", + "akihirosuda", + "aluzzardi", + "anusha", + "coolljt0725", + "cpuguy83", + "crosbymichael", + "dnephin", + "duglin", + "estesp", + "icecrime", + "jhowardmsft", + "justincormack", + "lk4d4", + "mavenugo", + "mhbauer", + "mlaventure", + "mrjana", + "runcom", + "stevvooe", + "tianon", + "tibor", + "tonistiigi", + "unclejack", + "vdemeester", + "vieux" + ] + + [Org."Docs maintainers"] + + # TODO Describe the docs maintainers role. + + people = [ + "jamtur01", + "misty", + "sven", + "thajeztah" + ] + + [Org.Curators] + + # The curators help ensure that incoming issues and pull requests are properly triaged and + # that our various contribution and reviewing processes are respected. With their knowledge of + # the repository activity, they can also guide contributors to relevant material or + # discussions. + # + # They are neither code nor docs reviewers, so they are never expected to merge. They can + # however: + # - close an issue or pull request when it's an exact duplicate + # - close an issue or pull request when it's inappropriate or off-topic + + people = [ + "aboch", + "andrewhsu", + "ehazlett", + "mgoelzer", + "programmerq", + "thajeztah" + ] + + [Org.Alumni] + + # This list contains maintainers that are no longer active on the project. + # It is thanks to these people that the project has become what it is today. + # Thank you! + + people = [ + # David Calavera contributed many features to Docker, such as an improved + # event system, dynamic configuration reloading, volume plugins, fancy + # new templating options, and an external client credential store. As a + # maintainer, David was release captain for Docker 1.8, and competing + # with Jess Frazelle to be "top dream killer". + # David is now doing amazing stuff as CTO for https://www.netlify.com, + # and tweets as @calavera. + "calavera", + + # As a maintainer, Erik was responsible for the "builder", and + # started the first designs for the new networking model in + # Docker. Erik is now working on all kinds of plugins for Docker + # (https://github.com/contiv) and various open source projects + # in his own repository https://github.com/erikh. You may + # still stumble into him in our issue tracker, or on IRC. + "erikh", + + # Jessica Frazelle, also known as the "Keyser Söze of containers", + # runs *everything* in containers. She started contributing to + # Docker with a (fun fun) change involving both iptables and regular + # expressions (coz, YOLO!) on July 10, 2014 + # https://github.com/docker/docker/pull/6950/commits/f3a68ffa390fb851115c77783fa4031f1d3b2995. + # Jess was Release Captain for Docker 1.4, 1.6 and 1.7, and contributed + # many features and improvement, among which "seccomp profiles" (making + # containers a lot more secure). Besides being a maintainer, she + # set up the CI infrastructure for the project, giving everyone + # something to shout at if a PR failed ("noooo Janky!"). + # Jess is currently working on the DCOS security team at Mesosphere, + # and contributing to various open source projects. + # Be sure you don't miss her talks at a conference near you (a must-see), + # read her blog at https://blog.jessfraz.com (a must-read), and + # check out her open source projects on GitHub https://github.com/jessfraz (a must-try). + "jessfraz", + + # As a docs maintainer, Mary Anthony contributed greatly to the Docker + # docs. She wrote the Docker Contributor Guide and Getting Started + # Guides. She helped create a doc build system independent of + # docker/docker project, and implemented a new docs.docker.com theme and + # nav for 2015 Dockercon. Fun fact: the most inherited layer in DockerHub + # public repositories was originally referenced in + # maryatdocker/docker-whale back in May 2015. + "moxiegirl", + + # Vincent "vbatts!" Batts made his first contribution to the project + # in November 2013, to become a maintainer a few months later, on + # May 10, 2014 (https://github.com/docker/docker/commit/d6e666a87a01a5634c250358a94c814bf26cb778). + # As a maintainer, Vincent made important contributions to core elements + # of Docker, such as "distribution" (tarsum) and graphdrivers (btrfs, devicemapper). + # He also contributed the "tar-split" library, an important element + # for the content-addressable store. + # Vincent is currently a member of the Open Containers Initiative + # Technical Oversight Board (TOB), besides his work at Red Hat and + # Project Atomic. You can still find him regularly hanging out in + # our repository and the #docker-dev and #docker-maintainers IRC channels + # for a chat, as he's always a lot of fun. + "vbatts", + + # Vishnu became a maintainer to help out on the daemon codebase and + # libcontainer integration. He's currently involved in the + # Open Containers Initiative, working on the specifications, + # besides his work on cAdvisor and Kubernetes for Google. + "vishh" + ] + +[people] + +# A reference list of all people associated with the project. +# All other sections should refer to people by their canonical key +# in the people section. + + # ADD YOURSELF HERE IN ALPHABETICAL ORDER + + [people.aaronlehmann] + Name = "Aaron Lehmann" + Email = "aaron.lehmann@docker.com" + GitHub = "aaronlehmann" + + [people.aboch] + Name = "Alessandro Boch" + Email = "aboch@docker.com" + GitHub = "aboch" + + [people.akihirosuda] + Name = "Akihiro Suda" + Email = "suda.akihiro@lab.ntt.co.jp" + GitHub = "AkihiroSuda" + + [people.aluzzardi] + Name = "Andrea Luzzardi" + Email = "al@docker.com" + GitHub = "aluzzardi" + + [people.andrewhsu] + Name = "Andrew Hsu" + Email = "andrewhsu@docker.com" + GitHub = "andrewhsu" + + [people.anusha] + Name = "Anusha Ragunathan" + Email = "anusha@docker.com" + GitHub = "anusha-ragunathan" + + [people.calavera] + Name = "David Calavera" + Email = "david.calavera@gmail.com" + GitHub = "calavera" + + [people.coolljt0725] + Name = "Lei Jitang" + Email = "leijitang@huawei.com" + GitHub = "coolljt0725" + + [people.cpuguy83] + Name = "Brian Goff" + Email = "cpuguy83@gmail.com" + Github = "cpuguy83" + + [people.crosbymichael] + Name = "Michael Crosby" + Email = "crosbymichael@gmail.com" + GitHub = "crosbymichael" + + [people.dnephin] + Name = "Daniel Nephin" + Email = "dnephin@gmail.com" + GitHub = "dnephin" + + [people.duglin] + Name = "Doug Davis" + Email = "dug@us.ibm.com" + GitHub = "duglin" + + [people.ehazlett] + Name = "Evan Hazlett" + Email = "ejhazlett@gmail.com" + GitHub = "ehazlett" + + [people.erikh] + Name = "Erik Hollensbe" + Email = "erik@docker.com" + GitHub = "erikh" + + [people.estesp] + Name = "Phil Estes" + Email = "estesp@linux.vnet.ibm.com" + GitHub = "estesp" + + [people.icecrime] + Name = "Arnaud Porterie" + Email = "arnaud@docker.com" + GitHub = "icecrime" + + [people.jamtur01] + Name = "James Turnbull" + Email = "james@lovedthanlost.net" + GitHub = "jamtur01" + + [people.jhowardmsft] + Name = "John Howard" + Email = "jhoward@microsoft.com" + GitHub = "jhowardmsft" + + [people.jessfraz] + Name = "Jessie Frazelle" + Email = "jess@linux.com" + GitHub = "jessfraz" + + [people.justincormack] + Name = "Justin Cormack" + Email = "justin.cormack@docker.com" + GitHub = "justincormack" + + [people.lk4d4] + Name = "Alexander Morozov" + Email = "lk4d4@docker.com" + GitHub = "lk4d4" + + [people.mavenugo] + Name = "Madhu Venugopal" + Email = "madhu@docker.com" + GitHub = "mavenugo" + + [people.mgoelzer] + Name = "Mike Goelzer" + Email = "mike.goelzer@docker.com" + GitHub = "mgoelzer" + + [people.mhbauer] + Name = "Morgan Bauer" + Email = "mbauer@us.ibm.com" + GitHub = "mhbauer" + + [people.misty] + Name = "Misty Stanley-Jones" + Email = "misty@docker.com" + GitHub = "mstanleyjones" + + [people.mlaventure] + Name = "Kenfe-Mickaël Laventure" + Email = "mickael.laventure@docker.com" + GitHub = "mlaventure" + + [people.moxiegirl] + Name = "Mary Anthony" + Email = "mary.anthony@docker.com" + GitHub = "moxiegirl" + + [people.mrjana] + Name = "Jana Radhakrishnan" + Email = "mrjana@docker.com" + GitHub = "mrjana" + + [people.programmerq] + Name = "Jeff Anderson" + Email = "jeff@docker.com" + GitHub = "programmerq" + + [people.runcom] + Name = "Antonio Murdaca" + Email = "runcom@redhat.com" + GitHub = "runcom" + + [people.shykes] + Name = "Solomon Hykes" + Email = "solomon@docker.com" + GitHub = "shykes" + + [people.stevvooe] + Name = "Stephen Day" + Email = "stephen.day@docker.com" + GitHub = "stevvooe" + + [people.sven] + Name = "Sven Dowideit" + Email = "SvenDowideit@home.org.au" + GitHub = "SvenDowideit" + + [people.thajeztah] + Name = "Sebastiaan van Stijn" + Email = "github@gone.nl" + GitHub = "thaJeztah" + + [people.tianon] + Name = "Tianon Gravi" + Email = "admwiggin@gmail.com" + GitHub = "tianon" + + [people.tibor] + Name = "Tibor Vass" + Email = "tibor@docker.com" + GitHub = "tiborvass" + + [people.tonistiigi] + Name = "Tõnis Tiigi" + Email = "tonis@docker.com" + GitHub = "tonistiigi" + + [people.unclejack] + Name = "Cristian Staretu" + Email = "cristian.staretu@gmail.com" + GitHub = "unclejack" + + [people.vbatts] + Name = "Vincent Batts" + Email = "vbatts@redhat.com" + GitHub = "vbatts" + + [people.vdemeester] + Name = "Vincent Demeester" + Email = "vincent@sbr.pm" + GitHub = "vdemeester" + + [people.vieux] + Name = "Victor Vieux" + Email = "vieux@docker.com" + GitHub = "vieux" + + [people.vishh] + Name = "Vishnu Kannan" + Email = "vishnuk@google.com" + GitHub = "vishh" diff --git a/vendor/github.com/docker/docker/Makefile b/vendor/github.com/docker/docker/Makefile new file mode 100644 index 000000000..81bde6b4f --- /dev/null +++ b/vendor/github.com/docker/docker/Makefile @@ -0,0 +1,147 @@ +.PHONY: all binary build cross deb help init-go-pkg-cache install manpages rpm run shell test test-docker-py test-integration-cli test-unit tgz validate win + +# set the graph driver as the current graphdriver if not set +DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //')) + +# get OS/Arch of docker engine +DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH:-$$DOCKER_CLIENT_OSARCH}') +DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKERFILE}') + +# env vars passed through directly to Docker's build scripts +# to allow things like `make KEEPBUNDLE=1 binary` easily +# `project/PACKAGERS.md` have some limited documentation of some of these +DOCKER_ENVS := \ + -e BUILD_APT_MIRROR \ + -e BUILDFLAGS \ + -e KEEPBUNDLE \ + -e DOCKER_BUILD_ARGS \ + -e DOCKER_BUILD_GOGC \ + -e DOCKER_BUILD_PKGS \ + -e DOCKER_DEBUG \ + -e DOCKER_EXPERIMENTAL \ + -e DOCKER_GITCOMMIT \ + -e DOCKER_GRAPHDRIVER=$(DOCKER_GRAPHDRIVER) \ + -e DOCKER_INCREMENTAL_BINARY \ + -e DOCKER_PORT \ + -e DOCKER_REMAP_ROOT \ + -e DOCKER_STORAGE_OPTS \ + -e DOCKER_USERLANDPROXY \ + -e TESTDIRS \ + -e TESTFLAGS \ + -e TIMEOUT \ + -e HTTP_PROXY \ + -e HTTPS_PROXY \ + -e NO_PROXY \ + -e http_proxy \ + -e https_proxy \ + -e no_proxy +# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds + +# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test` +# (default to no bind mount if DOCKER_HOST is set) +# note: BINDDIR is supported for backwards-compatibility here +BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles)) +DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)") + +# This allows the test suite to be able to run without worrying about the underlying fs used by the container running the daemon (e.g. aufs-on-aufs), so long as the host running the container is running a supported fs. +# The volume will be cleaned up when the container is removed due to `--rm`. +# Note that `BIND_DIR` will already be set to `bundles` if `DOCKER_HOST` is not set (see above BIND_DIR line), in such case this will do nothing since `DOCKER_MOUNT` will already be set. +DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docker/docker/bundles) + +# enable .go-pkg-cache if DOCKER_INCREMENTAL_BINARY and DOCKER_MOUNT (i.e.DOCKER_HOST) are set +PKGCACHE_DIR := $(if $(PKGCACHE_DIR),$(PKGCACHE_DIR),.go-pkg-cache) +PKGCACHE_MAP := gopath:/go/pkg goroot-linux_amd64_netgo:/usr/local/go/pkg/linux_amd64_netgo +DOCKER_MOUNT := $(if $(DOCKER_INCREMENTAL_BINARY),$(DOCKER_MOUNT) $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^ ]*)@-v "$(CURDIR)/$(PKGCACHE_DIR)/\1"@g'),$(DOCKER_MOUNT)) + +GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) +GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g") +DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN)) +DOCKER_PORT_FORWARD := $(if $(DOCKER_PORT),-p "$(DOCKER_PORT)",) + +DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) +BUILD_APT_MIRROR := $(if $(DOCKER_BUILD_APT_MIRROR),--build-arg APT_MIRROR=$(DOCKER_BUILD_APT_MIRROR)) +export BUILD_APT_MIRROR + +# if this session isn't interactive, then we don't want to allocate a +# TTY, which would fail, but if it is interactive, we do want to attach +# so that the user can send e.g. ^C through. +INTERACTIVE := $(shell [ -t 0 ] && echo 1 || echo 0) +ifeq ($(INTERACTIVE), 1) + DOCKER_FLAGS += -t +endif + +DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)" + +default: binary + +all: build ## validate all checks, build linux binaries, run all tests\ncross build non-linux binaries and generate archives + $(DOCKER_RUN_DOCKER) bash -c 'hack/validate/default && hack/make.sh' + +binary: build ## build the linux binaries + $(DOCKER_RUN_DOCKER) hack/make.sh binary + +build: bundles init-go-pkg-cache + docker build ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} -t "$(DOCKER_IMAGE)" -f "$(DOCKERFILE)" . + +bundles: + mkdir bundles + +cross: build ## cross build the binaries for darwin, freebsd and\nwindows + $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross + +deb: build ## build the deb packages + $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-deb + + +help: ## this help + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +init-go-pkg-cache: + mkdir -p $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^: ]*):[^ ]*@$(PKGCACHE_DIR)/\1@g') + +install: ## install the linux binaries + KEEPBUNDLE=1 hack/make.sh install-binary + +manpages: ## Generate man pages from go source and markdown + docker build -t docker-manpage-dev -f "man/$(DOCKERFILE)" ./man + docker run --rm \ + -v $(PWD):/go/src/github.com/docker/docker/ \ + docker-manpage-dev + +rpm: build ## build the rpm packages + $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-rpm + +run: build ## run the docker daemon in a container + $(DOCKER_RUN_DOCKER) sh -c "KEEPBUNDLE=1 hack/make.sh install-binary run" + +shell: build ## start a shell inside the build env + $(DOCKER_RUN_DOCKER) bash + +test: build ## run the unit, integration and docker-py tests + $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary cross test-unit test-integration-cli test-docker-py + +test-docker-py: build ## run the docker-py tests + $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-docker-py + +test-integration-cli: build ## run the integration tests + $(DOCKER_RUN_DOCKER) hack/make.sh build-integration-test-binary dynbinary test-integration-cli + +test-unit: build ## run the unit tests + $(DOCKER_RUN_DOCKER) hack/make.sh test-unit + +tgz: build ## build the archives (.zip on windows and .tgz\notherwise) containing the binaries + $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross tgz + +validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isolation, golint, tests, tomls, go vet and vendor + $(DOCKER_RUN_DOCKER) hack/validate/all + +win: build ## cross build the binary for windows + $(DOCKER_RUN_DOCKER) hack/make.sh win + +.PHONY: swagger-gen +swagger-gen: + docker run --rm -v $(PWD):/go/src/github.com/docker/docker \ + -w /go/src/github.com/docker/docker \ + --entrypoint hack/generate-swagger-api.sh \ + -e GOPATH=/go \ + quay.io/goswagger/swagger:0.7.4 diff --git a/vendor/github.com/docker/docker/README.md b/vendor/github.com/docker/docker/README.md new file mode 100644 index 000000000..0b33bdca0 --- /dev/null +++ b/vendor/github.com/docker/docker/README.md @@ -0,0 +1,304 @@ +Docker: the container engine [![Release](https://img.shields.io/github/release/docker/docker.svg)](https://github.com/docker/docker/releases/latest) +============================ + +Docker is an open source project to pack, ship and run any application +as a lightweight container. + +Docker containers are both *hardware-agnostic* and *platform-agnostic*. +This means they can run anywhere, from your laptop to the largest +cloud compute instance and everything in between - and they don't require +you to use a particular language, framework or packaging system. That +makes them great building blocks for deploying and scaling web apps, +databases, and backend services without depending on a particular stack +or provider. + +Docker began as an open-source implementation of the deployment engine which +powered [dotCloud](http://web.archive.org/web/20130530031104/https://www.dotcloud.com/), +a popular Platform-as-a-Service. It benefits directly from the experience +accumulated over several years of large-scale operation and support of hundreds +of thousands of applications and databases. + +![Docker logo](docs/static_files/docker-logo-compressed.png "Docker") + +## Security Disclosure + +Security is very important to us. If you have any issue regarding security, +please disclose the information responsibly by sending an email to +security@docker.com and not by creating a GitHub issue. + +## Better than VMs + +A common method for distributing applications and sandboxing their +execution is to use virtual machines, or VMs. Typical VM formats are +VMware's vmdk, Oracle VirtualBox's vdi, and Amazon EC2's ami. In theory +these formats should allow every developer to automatically package +their application into a "machine" for easy distribution and deployment. +In practice, that almost never happens, for a few reasons: + + * *Size*: VMs are very large which makes them impractical to store + and transfer. + * *Performance*: running VMs consumes significant CPU and memory, + which makes them impractical in many scenarios, for example local + development of multi-tier applications, and large-scale deployment + of cpu and memory-intensive applications on large numbers of + machines. + * *Portability*: competing VM environments don't play well with each + other. Although conversion tools do exist, they are limited and + add even more overhead. + * *Hardware-centric*: VMs were designed with machine operators in + mind, not software developers. As a result, they offer very + limited tooling for what developers need most: building, testing + and running their software. For example, VMs offer no facilities + for application versioning, monitoring, configuration, logging or + service discovery. + +By contrast, Docker relies on a different sandboxing method known as +*containerization*. Unlike traditional virtualization, containerization +takes place at the kernel level. Most modern operating system kernels +now support the primitives necessary for containerization, including +Linux with [openvz](https://openvz.org), +[vserver](http://linux-vserver.org) and more recently +[lxc](https://linuxcontainers.org/), Solaris with +[zones](https://docs.oracle.com/cd/E26502_01/html/E29024/preface-1.html#scrolltoc), +and FreeBSD with +[Jails](https://www.freebsd.org/doc/handbook/jails.html). + +Docker builds on top of these low-level primitives to offer developers a +portable format and runtime environment that solves all four problems. +Docker containers are small (and their transfer can be optimized with +layers), they have basically zero memory and cpu overhead, they are +completely portable, and are designed from the ground up with an +application-centric design. + +Perhaps best of all, because Docker operates at the OS level, it can still be +run inside a VM! + +## Plays well with others + +Docker does not require you to buy into a particular programming +language, framework, packaging system, or configuration language. + +Is your application a Unix process? Does it use files, tcp connections, +environment variables, standard Unix streams and command-line arguments +as inputs and outputs? Then Docker can run it. + +Can your application's build be expressed as a sequence of such +commands? Then Docker can build it. + +## Escape dependency hell + +A common problem for developers is the difficulty of managing all +their application's dependencies in a simple and automated way. + +This is usually difficult for several reasons: + + * *Cross-platform dependencies*. Modern applications often depend on + a combination of system libraries and binaries, language-specific + packages, framework-specific modules, internal components + developed for another project, etc. These dependencies live in + different "worlds" and require different tools - these tools + typically don't work well with each other, requiring awkward + custom integrations. + + * *Conflicting dependencies*. Different applications may depend on + different versions of the same dependency. Packaging tools handle + these situations with various degrees of ease - but they all + handle them in different and incompatible ways, which again forces + the developer to do extra work. + + * *Custom dependencies*. A developer may need to prepare a custom + version of their application's dependency. Some packaging systems + can handle custom versions of a dependency, others can't - and all + of them handle it differently. + + +Docker solves the problem of dependency hell by giving the developer a simple +way to express *all* their application's dependencies in one place, while +streamlining the process of assembling them. If this makes you think of +[XKCD 927](https://xkcd.com/927/), don't worry. Docker doesn't +*replace* your favorite packaging systems. It simply orchestrates +their use in a simple and repeatable way. How does it do that? With +layers. + +Docker defines a build as running a sequence of Unix commands, one +after the other, in the same container. Build commands modify the +contents of the container (usually by installing new files on the +filesystem), the next command modifies it some more, etc. Since each +build command inherits the result of the previous commands, the +*order* in which the commands are executed expresses *dependencies*. + +Here's a typical Docker build process: + +```bash +FROM ubuntu:12.04 +RUN apt-get update && apt-get install -y python python-pip curl +RUN curl -sSL https://github.com/shykes/helloflask/archive/master.tar.gz | tar -xzv +RUN cd helloflask-master && pip install -r requirements.txt +``` + +Note that Docker doesn't care *how* dependencies are built - as long +as they can be built by running a Unix command in a container. + + +Getting started +=============== + +Docker can be installed either on your computer for building applications or +on servers for running them. To get started, [check out the installation +instructions in the +documentation](https://docs.docker.com/engine/installation/). + +Usage examples +============== + +Docker can be used to run short-lived commands, long-running daemons +(app servers, databases, etc.), interactive shell sessions, etc. + +You can find a [list of real-world +examples](https://docs.docker.com/engine/examples/) in the +documentation. + +Under the hood +-------------- + +Under the hood, Docker is built on the following components: + +* The + [cgroups](https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt) + and + [namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) + capabilities of the Linux kernel +* The [Go](https://golang.org) programming language +* The [Docker Image Specification](https://github.com/docker/docker/blob/master/image/spec/v1.md) +* The [Libcontainer Specification](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md) + +Contributing to Docker [![GoDoc](https://godoc.org/github.com/docker/docker?status.svg)](https://godoc.org/github.com/docker/docker) +====================== + +| **Master** (Linux) | **Experimental** (Linux) | **Windows** | **FreeBSD** | +|------------------|----------------------|---------|---------| +| [![Jenkins Build Status](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/) | [![Jenkins Build Status](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/badge/icon)](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/) | [![Build Status](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/) | [![Build Status](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/) | + +Want to hack on Docker? Awesome! We have [instructions to help you get +started contributing code or documentation](https://docs.docker.com/opensource/project/who-written-for/). + +These instructions are probably not perfect, please let us know if anything +feels wrong or incomplete. Better yet, submit a PR and improve them yourself. + +Getting the development builds +============================== + +Want to run Docker from a master build? You can download +master builds at [master.dockerproject.org](https://master.dockerproject.org). +They are updated with each commit merged into the master branch. + +Don't know how to use that super cool new feature in the master build? Check +out the master docs at +[docs.master.dockerproject.org](http://docs.master.dockerproject.org). + +How the project is run +====================== + +Docker is a very, very active project. If you want to learn more about how it is run, +or want to get more involved, the best place to start is [the project directory](https://github.com/docker/docker/tree/master/project). + +We are always open to suggestions on process improvements, and are always looking for more maintainers. + +### Talking to other Docker users and contributors + + + + + + + + + + + + + + + + + + + + + + + + +
Internet Relay Chat (IRC) +

+ IRC is a direct line to our most knowledgeable Docker users; we have + both the #docker and #docker-dev group on + irc.freenode.net. + IRC is a rich chat protocol but it can overwhelm new users. You can search + our chat archives. +

+ Read our IRC quickstart guide for an easy way to get started. +
Docker Community Forums + The Docker Engine + group is for users of the Docker Engine project. +
Google Groups + The docker-dev group is for contributors and other people + contributing to the Docker project. You can join this group without a + Google account by sending an email to docker-dev+subscribe@googlegroups.com. + You'll receive a join-request message; simply reply to the message to + confirm your subscription. +
Twitter + You can follow Docker's Twitter feed + to get updates on our products. You can also tweet us questions or just + share blogs or stories. +
Stack Overflow + Stack Overflow has over 7000 Docker questions listed. We regularly + monitor Docker questions + and so do many other knowledgeable Docker users. +
+ +### Legal + +*Brought to you courtesy of our legal counsel. For more context, +please see the [NOTICE](https://github.com/docker/docker/blob/master/NOTICE) document in this repo.* + +Use and transfer of Docker may be subject to certain restrictions by the +United States and other governments. + +It is your responsibility to ensure that your use and/or transfer does not +violate applicable laws. + +For more information, please see https://www.bis.doc.gov + + +Licensing +========= +Docker is licensed under the Apache License, Version 2.0. See +[LICENSE](https://github.com/docker/docker/blob/master/LICENSE) for the full +license text. + +Other Docker Related Projects +============================= +There are a number of projects under development that are based on Docker's +core technology. These projects expand the tooling built around the +Docker platform to broaden its application and utility. + +* [Docker Registry](https://github.com/docker/distribution): Registry +server for Docker (hosting/delivery of repositories and images) +* [Docker Machine](https://github.com/docker/machine): Machine management +for a container-centric world +* [Docker Swarm](https://github.com/docker/swarm): A Docker-native clustering +system +* [Docker Compose](https://github.com/docker/compose) (formerly Fig): +Define and run multi-container apps +* [Kitematic](https://github.com/docker/kitematic): The easiest way to use +Docker on Mac and Windows + +If you know of another project underway that should be listed here, please help +us keep this list up-to-date by submitting a PR. + +Awesome-Docker +============== +You can find more projects, tools and articles related to Docker on the [awesome-docker list](https://github.com/veggiemonk/awesome-docker). Add your project there. diff --git a/vendor/github.com/docker/docker/ROADMAP.md b/vendor/github.com/docker/docker/ROADMAP.md new file mode 100644 index 000000000..21fe06dba --- /dev/null +++ b/vendor/github.com/docker/docker/ROADMAP.md @@ -0,0 +1,118 @@ +Docker Engine Roadmap +===================== + +### How should I use this document? + +This document provides description of items that the project decided to prioritize. This should +serve as a reference point for Docker contributors to understand where the project is going, and +help determine if a contribution could be conflicting with some longer terms plans. + +The fact that a feature isn't listed here doesn't mean that a patch for it will automatically be +refused (except for those mentioned as "frozen features" below)! We are always happy to receive +patches for new cool features we haven't thought about, or didn't judge priority. Please however +understand that such patches might take longer for us to review. + +### How can I help? + +Short term objectives are listed in the [wiki](https://github.com/docker/docker/wiki) and described +in [Issues](https://github.com/docker/docker/issues?q=is%3Aopen+is%3Aissue+label%3Aroadmap). Our +goal is to split down the workload in such way that anybody can jump in and help. Please comment on +issues if you want to take it to avoid duplicating effort! Similarly, if a maintainer is already +assigned on an issue you'd like to participate in, pinging him on IRC or GitHub to offer your help is +the best way to go. + +### How can I add something to the roadmap? + +The roadmap process is new to the Docker Engine: we are only beginning to structure and document the +project objectives. Our immediate goal is to be more transparent, and work with our community to +focus our efforts on fewer prioritized topics. + +We hope to offer in the near future a process allowing anyone to propose a topic to the roadmap, but +we are not quite there yet. For the time being, the BDFL remains the keeper of the roadmap, and we +won't be accepting pull requests adding or removing items from this file. + +# 1. Features and refactoring + +## 1.1 Runtime improvements + +We recently introduced [`runC`](https://runc.io) as a standalone low-level tool for container +execution. The initial goal was to integrate runC as a replacement in the Engine for the traditional +default libcontainer `execdriver`, but the Engine internals were not ready for this. + +As runC continued evolving, and the OCI specification along with it, we created +[`containerd`](https://containerd.tools/), a daemon to control and monitor multiple `runC`. This is +the new target for Engine integration, as it can entirely replace the whole `execdriver` +architecture, and container monitoring along with it. + +Docker Engine will rely on a long-running `containerd` companion daemon for all container execution +related operations. This could open the door in the future for Engine restarts without interrupting +running containers. + +## 1.2 Plugins improvements + +Docker Engine 1.7.0 introduced plugin support, initially for the use cases of volumes and networks +extensions. The plugin infrastructure was kept minimal as we were collecting use cases and real +world feedback before optimizing for any particular workflow. + +In the future, we'd like plugins to become first class citizens, and encourage an ecosystem of +plugins. This implies in particular making it trivially easy to distribute plugins as containers +through any Registry instance, as well as solving the commonly heard pain points of plugins needing +to be treated as somewhat special (being active at all time, started before any other user +containers, and not as easily dismissed). + +## 1.3 Internal decoupling + +A lot of work has been done in trying to decouple the Docker Engine's internals. In particular, the +API implementation has been refactored, and the Builder side of the daemon is now +[fully independent](https://github.com/docker/docker/tree/master/builder) while still residing in +the same repository. + +We are exploring ways to go further with that decoupling, capitalizing on the work introduced by the +runtime renovation and plugins improvement efforts. Indeed, the combination of `containerd` support +with the concept of "special" containers opens the door for bootstrapping more Engine internals +using the same facilities. + +## 1.4 Cluster capable Engine + +The community has been pushing for a more cluster capable Docker Engine, and a huge effort was spent +adding features such as multihost networking, and node discovery down at the Engine level. Yet, the +Engine is currently incapable of taking scheduling decisions alone, and continues relying on Swarm +for that. + +We plan to complete this effort and make Engine fully cluster capable. Multiple instances of the +Docker Engine being already capable of discovering each other and establish overlay networking for +their container to communicate, the next step is for a given Engine to gain ability to dispatch work +to another node in the cluster. This will be introduced in a backward compatible way, such that a +`docker run` invocation on a particular node remains fully deterministic. + +# 2 Frozen features + +## 2.1 Docker exec + +We won't accept patches expanding the surface of `docker exec`, which we intend to keep as a +*debugging* feature, as well as being strongly dependent on the Runtime ingredient effort. + +## 2.2 Remote Registry Operations + +A large amount of work is ongoing in the area of image distribution and provenance. This includes +moving to the V2 Registry API and heavily refactoring the code that powers these features. The +desired result is more secure, reliable and easier to use image distribution. + +Part of the problem with this part of the code base is the lack of a stable and flexible interface. +If new features are added that access the registry without solidifying these interfaces, achieving +feature parity will continue to be elusive. While we get a handle on this situation, we are imposing +a moratorium on new code that accesses the Registry API in commands that don't already make remote +calls. + +Currently, only the following commands cause interaction with a remote registry: + + - push + - pull + - run + - build + - search + - login + +In the interest of stabilizing the registry access model during this ongoing work, we are not +accepting additions to other commands that will cause remote interaction with the Registry API. This +moratorium will lift when the goals of the distribution project have been met. diff --git a/vendor/github.com/docker/docker/VENDORING.md b/vendor/github.com/docker/docker/VENDORING.md new file mode 100644 index 000000000..3086f9d17 --- /dev/null +++ b/vendor/github.com/docker/docker/VENDORING.md @@ -0,0 +1,45 @@ +# Vendoring policies + +This document outlines recommended Vendoring policies for Docker repositories. +(Example, libnetwork is a Docker repo and logrus is not.) + +## Vendoring using tags + +Commit ID based vendoring provides little/no information about the updates +vendored. To fix this, vendors will now require that repositories use annotated +tags along with commit ids to snapshot commits. Annotated tags by themselves +are not sufficient, since the same tag can be force updated to reference +different commits. + +Each tag should: +- Follow Semantic Versioning rules (refer to section on "Semantic Versioning") +- Have a corresponding entry in the change tracking document. + +Each repo should: +- Have a change tracking document between tags/releases. Ex: CHANGELOG.md, +github releases file. + +The goal here is for consuming repos to be able to use the tag version and +changelog updates to determine whether the vendoring will cause any breaking or +backward incompatible changes. This also means that repos can specify having +dependency on a package of a specific version or greater up to the next major +release, without encountering breaking changes. + +## Semantic Versioning +Annotated version tags should follow Schema Versioning policies. +According to http://semver.org: + +"Given a version number MAJOR.MINOR.PATCH, increment the: + MAJOR version when you make incompatible API changes, + MINOR version when you add functionality in a backwards-compatible manner, and + PATCH version when you make backwards-compatible bug fixes. +Additional labels for pre-release and build metadata are available as extensions +to the MAJOR.MINOR.PATCH format." + +## Vendoring cadence +In order to avoid huge vendoring changes, it is recommended to have a regular +cadence for vendoring updates. e.g. monthly. + +## Pre-merge vendoring tests +All related repos will be vendored into docker/docker. +CI on docker/docker should catch any breaking changes involving multiple repos. diff --git a/vendor/github.com/docker/docker/VERSION b/vendor/github.com/docker/docker/VERSION new file mode 100644 index 000000000..b50dd27dd --- /dev/null +++ b/vendor/github.com/docker/docker/VERSION @@ -0,0 +1 @@ +1.13.1 diff --git a/vendor/github.com/docker/docker/contrib/selinux-fedora-24/docker-engine-selinux/LICENSE b/vendor/github.com/docker/docker/contrib/selinux-fedora-24/docker-engine-selinux/LICENSE deleted file mode 100644 index d511905c1..000000000 --- a/vendor/github.com/docker/docker/contrib/selinux-fedora-24/docker-engine-selinux/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/vendor/github.com/docker/docker/contrib/selinux-oraclelinux-7/docker-engine-selinux/LICENSE b/vendor/github.com/docker/docker/contrib/selinux-oraclelinux-7/docker-engine-selinux/LICENSE deleted file mode 100644 index d511905c1..000000000 --- a/vendor/github.com/docker/docker/contrib/selinux-oraclelinux-7/docker-engine-selinux/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/vendor/github.com/docker/docker/contrib/selinux/docker-engine-selinux/LICENSE b/vendor/github.com/docker/docker/contrib/selinux/docker-engine-selinux/LICENSE deleted file mode 100644 index 5b6e7c66c..000000000 --- a/vendor/github.com/docker/docker/contrib/selinux/docker-engine-selinux/LICENSE +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE b/vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE deleted file mode 100644 index e67cdabd2..000000000 --- a/vendor/github.com/docker/docker/contrib/syntax/vim/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Honza Pokorny -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/docker/docker/docs/static_files/contributors.png b/vendor/github.com/docker/docker/docs/static_files/contributors.png deleted file mode 100644 index 63c0a0c09b58bce2e1ade867760a937612934202..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23100 zcmb@OV{j(E_x888ZEbB^Tbp;=t!>=3ZQHint!;a2+qU)J@BCgqZ=W|wCYelTGH1?Q z`J8JKt|%{o0E-Lzo_Y4dhY>#tUQd@oOt3`hoOL|BKcJqN3Vxy$AhV?ax|X zwP7_xdmcs=u4=&I4-7>PVT51Et0V?6adF`Fly>RguBKa_?u?$lQ0phh>{!;bJF?oY zC)U*RkjI zsZ{9ymFQPP=Ffni?-C9P+OC9;+m(1`#sifR2o?cG#SMq<7^FFga@MBPTZc}}8{OtP z!CXnufoQzjhXU6pDu?FO?q?N~x)gG+s5_)nwFPTwBYb7~CibK72sE%1)SrJd^${!^ zEHw&Dtkf^i4vaU^uU^}gy=)4@H#0a?oWg*dF~t!rx~8uPt`)MO;*-1xScpDwk8Yd6 zV|oWAE&v<#MZbeL_k~-u+`8|Wmvs+s;S27t7f}( zmXlHcCaBX3IF<@+Er8_&TT#hEUm$9AWJhM+a2DG>$2af5AN|C9xfYFRFuLL?G1+^h z)!T!@8{JnMuGS?na}ca1a>7RB3N7|6Ju30;Ef@hw{DK01K4-F7z?2a1d z6xYB&;G|Ie<*=I5*<4$#T&O(X^Lx-a9hgg%5-@!cNcW>GOGntHUgUcesfkwoDU2}( zp^XvJc&>8m=-3u88Wgay@j*@{{4f45)4=9Jiy38dDa1naT<3nu?&eE&0d1Rn`W{JW z+U8LtqZPyYp%!)zg2B{3Lbkcu{ZEP<^T>cg)(%UgkghgLTC7~CpI^-|9klpVyAWH7 zHV%sv1WpJwWSw3XfkAq0r09b)a@xX9bKHO9xrn_r-#E&xkbhxq3~^b?MMfTMrD`?h zS1|01CL;=KT9+@O+wU!YZtx6RE#mF=ft=3IwPZU@AV(b-C>&!>dN-kzGwftdTF&rd zV2HwHnX$g0Btk=EJ0UuWB9?h;sVo?F6sphY7i^nLaqx;0#|-1_NIN znQ=;!ID#{lTECe0DwM(&vRwJD*)Gz$_3@es`+CpqM7Q%IYfT1VZ34@S>|}^$zHlkX zqF8IhE*z}@E5)`|)vYmMV8Fuuwl#g)M;dnrznCsx^)FDd&2BGw3%jIv9)+lZGfX0) zYXR{+(nD1^wvq>61Pi@=cYUqu1fPu({)DXZT}E*gsEJb65~g}4&2#wpn~EreB`Aiq zg7Pbi@B7eVz2$nQVzSKlXewM|_q0II6N#6^m%zv+)CQ#e{aek6h^j*oSezfg@@ES8MT#Kt;stNsM)7<|y0gZ}3|BfisAPKfpssv+PnM%1VQY)$rhkVcvBn)CNqo=Dw6JxNoo5 z+?S)IhN;I!PR9W}TV0%Cg%P|=Rwc*vuJcWXX}&i%Q7k8eY_YQNJh(%Oe)&`@<6og9 zh)NBcA`1moGJ-+ovIx@i7-yFFK0~yQnAM8Sr9^6XuoX!AbC?P$q2~6iiAfl=nAEpt ztl<$HhP=f;xkH2R(?;rl($kw#&`v9rb%-xrT#kQOtTDMAWxbBS4HQeav)Z{pn`{*f zNzch%el?n$o;f}o{1b;5TUzc)DubRG z_P6s%V$>GskUzg(#JC12ZBkjI>s2sl+{Py{-jh`1@wQ-7m7=K;DQA=*epw=LFrIgt zbYj&O@gA1R^a2EOt0z3ZbP);;o)nTj2r^hI#QW~6(^`bRt$iy zl()J$C_Q(fa_hBYvjNUJAg)_uN(5Yc^KwcJf^P4KI#lO(yt;Dt%5_C^SN+!I$*8R( z9M?!Cjh>#_`&aK}=msRvaedcGO2XFZhr>Gl8X2nHL0P#*@kV6UApxH+v_8;{N_M0Pl$r%yaDSqn6uqqIJBFa=5ojh-~A-^ zPmeoEHRJI_JUY^dNhY?vAL@v^rHqsPz1_@V2OKVYs(b?9_I#N5q3U0Chzi|5KU0n> zRmfWd!I0N3rM@IH1c^x0U4q4o!Kk0L38x(yTR!)X$*8xmmY-}#7eIVJZkfXzV88`x z!$Al&+Ttx~wK}v8dyHMT_ubr=!e}@<74}62y?&~OkaF>|qt=A81dXQ63s+)pM>@<@++StGdv_h{M{^*6(4wSA?L&`h(vdvy=jjQhB$s3~ob z3Y`hzC%|P0cDQR_1}PGC$1c0J>5p^z_2l~T?oQ@{K_oKU9b&I1Oyd<(gP?o$^i(oi z9e5d7eY~#v%EB)Gf-*+X+6%$qZ+Vc+9vrd(yTQ-(`=Y7~>G&eQq3jTPK z?+SNz?L*%+JQaLZ}9TlRVYrGKEHC-veo<>48F+QB1OX_b-y1 ziFZCun;tAP&7Y0IJMx=&mUN}<`z*`t?N2aY?vk(MCdW=@(=uNkl~T80k&p~)NiMJI z_V}mOu+X9?basLL{_S~lM#kyDMHEU41?1ZZYu1zXWaw)kUC>@9r_yDtAL81{(T__n zc9AR&U8ZH_zL$h_w_(L9u3!zbOuU;*atF*!Dy$yc+6jHptGZq~HnX z=%6U+11T1-&TdgZrFtxrFlCioFmWS8XF@Re;1RY?ajff%ePKRjy6$9|i_b(x*Us2^ z%v;$!7$sR!p8U~Ig?=`jzhrjarKGU>D6stp{3uUyIHUa{YK?X8$H#H%cXf^v!fhH` zd1;q$Ji0XkZSz3MoDGoRY4HrVPP`SD6+hx8B*&} z^G~lwg9($F&bIPYuHK!?;+*1Yn|Z8zXgMP~u^^s+)+BZTyV`i5c+jAnK$g?Dnzz)l z!Lp;k+7bS(+$`DHlDO2k6A{&JPK_#sC_IJ<_YZn9bCeXD@>Dj*oU~^Oipd|a)1j@@ zd9c!{Z-pq$UXCd0r8J=tRefM@qn=`aPczYp}J#$p75w76m2L2&@gGH$xJ5 zEeP7RUtVAh)Jbl6Yn%30+Y`!kdZ6Ddopj|r8m7J_48skVI%iLci*%x^Cd%eekU|aJ za?ga`snZG8h>&sMx#noLwhE~?*DOd#a%inn;Nbr3K6u?*D6_Fo4*LmTtgal6xQ1MT z1fvmX5TVixN1@_b0Lk-qCbFQ0`YXFK?N{fmK3&ch^rVcuNO^sxWLHOilBqsU-jY06u2G0xa-3$+X*yVJf zI~UKD!|JODG?=z?b#@%R)2H;3->;EB5UGT%k572IJ9H)t2rW?e7n=(GlVKcew~ zam>#q{bbEX(IZg%qh}Cl4};R|cEX^#^}ujEn3WWj-=VjnVqeB)6cZ?-M$xdb)@29m z_ufV#^-1gmtJ^Qw-f{Jt@Nxv>aC+H%~G^2VgIo?1)MnmtZ} zMI}6!Tkm&Pk-rA1eY&y+84IJ4bhZc&$fWF6YB3!}hD{c%cKVSh;!zxj<{8y5_Os6v6lFp|HsipZZq#_}(K94RQ%wcq;|?*27TE1D)R4-6exbOcEBS z%I}n{D!QE7d_+oy%BWK3SY(;`3NWvBI}f5(w<3~H%jY>PW<++|`1Y_EEYv@E>|FBc zEpBxzGto3zWkt7uWI}nDJG+c}F8AQ~ug--Ojkl2wf@lG&9pol}ZWNM?@aV(v^eFokThdqjox%^trPxl$6CuYbl8lGynbl3QZ z3|b^N@NV8<$P)TW_=*|bTF4X13gK%)i)@oNh%DHS4h4+3@JM!lRU%NkrgpAinJg%p z+qa_h@kz1s%DxKPs!HgY*4N}qhE0iueK!OWx3xwKQP`Z4B4pdmju_3Md8|mk`Cc%- zYa;n2#lX}yK|c7mT#8@1TY&NeK9!hbYV>XS@%g{uU4GEo&kVQS{-E-?Vm3JG^W~1w zC!8Ud-`K}PlWHPN#=i|nsxXIDk8;#r*=#3GY<<$9w%{2$LIH#tu`su(9oJAnqrfw4 z2B31CsqvQR1`u!wcRiVFFJY2QTH7mv&p0FCxRvc&4P`=p7FV06-O#rf*;`riR2Hen z1j%}T=s42*hZN=hN?|AJ&QSw(pTM;uW#)&wuva7y%?`2+T|(M%dx79#Xr6Tf5EQZneX5 z2P@~l%{-;BRK%8)Gnu9s`b?a}EZWeWB*{-=kM>CA7vs}9+IoD&2L|&IVri>A zKNu&oqw$OineM{b%a(ZL!=TMLe44hW;ClSgZtfDu-Ckdh>m0UO)UTQ@Xl*Q$Va9=y zYRJ(y&SXiWT>*wDSF&~!19j1SQE(K74up4it=ZE9J4HVybMXTlaII>#b~^2i^B{4k}n@Vpf23Wh$D#Ya#JXJ1Q_4S^<1( zeBvx#7Lt$S{5mY>4LYSNp-JyPj)f8Nl!!>RiM{r~r><3RNmkoOaBJhV5071mB<0&6 zMBRb=79(1t*sG{m`7#2S)9&iuYS}3(U$hq&`iCd6TSvwqW)3;&U7gCY ztZY44JH#hvo7gqS=3590X!A|b)PoxmJw%j>qRjFM0gpSCK0d`;XEr16jPQ51fx8Pg zHE3**?VgN+8{s;Q_Xwq`q**R6L}YvGV~&d%YEcmsHyvkY zEt;G0xi+_(@Rs;=y-^647=v$D^kx7XO*I#*?Q74^vu1pOSVT&eYe;;Oxm&_%3dS__ zs%gcJ3XFwo2WK^pr~YD5*6G0vbu;}Ccv>sPJ%&hyooMt)Hz$~RQ-kBPU~E=(0nT5- z*v}0Xo%~=(jxL#S-!KUQrk*}dD_O^@{9r2LkwH7E;&WcsY42>R@ErHV8^YC=r?d?y z>*o$s3jBT#2Z3Rk{rANUiw|L$fsL+2%4DGOYUPpKZ!Xq)d}v0d+p#`1{nQz1MVmSn zXbTQX-;S(NfK1E?Wl2z>fVl6y?utRE&}W| zt>AS>Z!PKGCJRwLEs}cqL*YqtkljsW9JNFS#gM8=6{@E6@B^8@6B!9?`;jdeM`S%w z7^M2f#)~)POPrKF@TOaEl^(IqRJ8k?(rQ(%;~Q(pZdR4HzkM*}5A8#O!n%~$3ozAv zSp+E~WuP?AMQIp{h5@4#!J%U9=W6_vmk|rQ*8a)Yg=UXWtl=)X*R))nDbE0{>1sC} zi3b}oQ_gy-p*=7y;~8;*Vsg&o!(K(Tg(5S?F_9x;(dWg+nze~%qYVG1ZQCQ>BVrWm zCgbrp@g}&O_i-eAkQAAU>aoZZ^LGi8+fz|Crw@SDpfkc0VWK?f3xG zVYb*wPj2A$79(=&ksP?KY>3_)MNsFbgoZp(U=hmM+Z-J>}%+69htY7X}bKOmOd1r0d^CYh6 zkBQB&5v1?nR$AD6KH2T(`_;hnHFoIV`AQ~JMXr4&^(BNg4G;8KIVsUIrMGCEUo`x6 zDBTiM=|!;Z|H;4kAs?mR1Cv}yX6P#{-a6G)-w7F}HTsHYE0zx6AZ z!wcPqXUs@YxXSGgBgcMApzWYs{(4;phk|>E#G{#kPjnc&jp8P5dRd#Io%cSDlzlng z{AhE_^Fcf0^47L~W|bhx1W`NADQjZ9_^#>JJqLWyI}W-hkq0E6s__<1CfV(B6ozE( zJLr?-k4))TjV@qH#IO}MH-XI7y14#Ng$jaCb!7|lCfvK)J|dCKLT$lWu_UI}E7S<=H?DX4tYo#>yf;}>4-2VQy4ce1x&>fn_cLn3eO&nO+_?;#i zw3i(aEh-z&FG}jNXpcJU;%eNMLpxwuqSNXSh&yA&BCXUfAl5O1-lUi4G)SO^1AvJ8{+@GSRJ8mE(5q3!94h^DUc zsr=a9_gw?$ad2Y1Y@1POPgkp0oBiG1WTnHx5?6|LX2{D)66f>f*Q3Vti0qrNAay}C zh%T%?SuzH>n4f<2JNj@Wjs3myLa?dyJSMgBp~-2zxiruG5HA*A9SyZ3o746ncVyUB zr9Z2*CPH_g{xc5N=Ya$YwsAI4P-77_@D(ND{awAZNzpRC! z(eUTAy7E#f%{`!3lImU=oT5I-2KlcfRe)kvr*)18JO{+_enyGJRD_@R}L2D0L**u?*Y(60`!x z*<2sS(;}Aop9kT~WKM610cm6BTlwk|U+)g{D~&%Fsa_7j)V9 zo?I!D6`cW;n~ebDKfE{sc?|SEs}5vlp#k}p-i);>Y43kCC8f86fgaowdl#(exa?0o zh;mM=3V@aE?LPTY5VR5d?CZ)Y&I{J5cCqeX&g?_gF^wg&Z)$WD;jO{K9ui@~Hdj^rxlpf z9Eu+P3O8*wP{yh~-`VZhB!;)-!?ezM{Pkr_BHBZ{w@-!UOb)n_)TB0L@!R$q4^>Yg zt;>bDoi{a{o7x`XuVpZjHDA2aLprmWWd^cfhex7inNuk%{;BKUkSPNRtEc zza-iT|4qj1;R2f=m{ty%pat4qAxH1<*`I~r`uXQf{F}ZnzBbL?E6KIDEzbw}X@C#N zQdK%vM`uA8FrT_Nivxp=Zrj&C^?O=byJN0h$xdf%M@MQoomvB}W=kX66ddBUe9fwD zG=Zxh2c-bo4V|&ZKIM9n_)`^Ty5q0Y{YN~TufSD@@_r;b!8MEl1C}aHRpBKE{wkSQ zIh=c10;>R|62RCSfNm0Bdl_HBR>{wi|HTtoJr1wc^QO{l4I2ukOO*7H?i;kX4S{t< zenI9Nbr@Ll1HLM7Ht4ReF#qL6cnM%m2(C;Tv5ykO#EznYgno$G%mvhivr%s5|O;3m_Q=d@j9rT zYC=+-J@Z!C9qD2FHh!8p1Mia)oXnOOdd*t6GCNqwGR4HrC_&H^oZRR-sZgWwTbj=O z!=0~J4*m{FBDybv(RiiULJ8M5fNf!2g8v?bZ9ywSvj^E(?KyeU8p$Pv#OBihHeBq) zWMM6C$^-$WkbF$@6WfF0YWOJteJ?Pwzx{^{VYtxXU5*=%0mBuQ8=O4~|H7anp)cZ$ z0uTYL;eR|;CVIz(@DOTo^{H01+nVI=hAs;DwN^=jbnIcgOo&L};!2Nk`s%D$iVPGF z-3Nh!pIPV&RqHb0$qkHq*0WJgKe|9$%vAx#?8&{GBxOOgn+v9$!DyXFq{9_l3}j&$ z&d&dVqCWKwqHlHG7)>D3`5}eCDySn zn1R>NqJ45w@Wb40!u`1rM)>4RKIuutkTs+!SVgUV+BCcRHQkN{FkVj|Q}5MC3Mh6w zHq@8pA&j~X?ks$7ZG;V$W1NkFy?v_E--yMa(qO^BJ-f7K&pn(Rd3$uAJfnvwb0_wR zLyuKILd9@=@GNM{qZd7Sk-u-9 z8hnG?8;2d;wu~z9aAgbkitRNa%9#yBeR4pCVMhb62fI@{!@pA3E5W?00%W?<-hTeb zXnt3)qF=5{c=xt{7abojDU8~F!9~(O9G!-mPYuQUT>M+?0c<7J0kkeW8M@=vQEew( z3Jk^Ooge`<)yUQmpGz!H$q;p`ONP!rxNL_Lq)f4PIn;yqOnsv6LK4(;LvT2{K9frj zqBc@E=fP>%qJ!Ts7{?Yn?EUC@MxFf87{&VU`;e1_+JXkqJ#_^!$Jz`(KuMcL7A4(R7Tr8loR1EJ1ZJcFSzl1rW%)Y)3T?Hh{Y+D`UZ25Hre|mZ)23 z=Wl5F(bAXYjh_;At^ar)a3P$^*^YQ8^b!ts(*uO9x=(M)8B;j6A{hr~G$o&V`S#Kobn}9sHW#ioMclp98a; z?N6i`F2enDfUyLe6XgzLH1mmH#vs;j-`sffR8soP>rSG!VK=v_O&gI zgI&!CbG+2p&(uogt>UHN#12YvdgE`X)nNc)o6V6+TIQMP3UKQ_JVt1>(J>iPqSw5o z?+EY5cELRrOysYfHWjLEr&{U_Et9 zBS;@k^qwEsaQFI1*C6-l@EV>-A%_bjq|Z;LYt~#;s@{mcg|Mx#-^9i-?KpktZel32 z(5-QS4&VA|)h3GOf{tlZf08is>8S8^?q&-79$^JC!wYKoe{aLtf*jup$hXJNT-thq z)(Dq%Ph&1*{?k|6?SDPU3g3AawK-cX`OAEK_h_JWx)3@`8E8TcN3;gtaqd>)I9R%=94AHMg1-R3lq_ItzhtX zs@2XwqrcU50Cld9()E{=98uN>?4*<3$=&Jt*=I#M{O7hq(}lm5;4h6OgNF|nI1l_6 zSOZEV!`>JL)jmp#pdugA2g`hftMd`HHl+U?F9Zo-Bgz|7Zx>ARx1!(~lYC(WLQmOR zz40Ifkwe8u8-W_PQj1`Y8+I%pQA%r z*ERO#JtRSRZ22YC1jO9e%2sC4vfi;DCsdJw%r=DyR^Cn<`&m`Fj3*l7`Td4y?-+Zs z6UgzNDDO6sj5vhRNUj5?(K9LWv)2Dk({U7ftADVd{InqJrfH}Qm@Mu(yiXBL8bbyw z?__zMDR%Js2D(_v{yv!2Se(Trd>3>SAXH9Jird_GG0ln#^TSz6Tr+5>(N( zG*L>oEKNiITf^bYBsXMoHrI>vMap2IWREM7f_v5aP7n-1SP}|c-T68l-{5b6oZQUb zf#rC0JH@iUu0yFsgt_gUYcWz{k;3Q_5t z>1{sQXG^SX|G3ENOGAg!obXnMX3JO`P61J)J7U5ziV0`Dt9m&jYaHDMJ)zX3JP%2_W^a*-9oD`JjAwe1U9A|N? zw4O7fOfeGURurS}SI&HQ6@p0Qie-4a*@)Vu-C`r>u5{_b4h<+M4v+{Q?{-OAgmi}~ zLkWK=o68b1DM-A};8tm0s9JlmoRkb`vccCm@+a`?|p2m6%3tek1)wAv zSa1w+Vpxe}Ss~B-lFPh#DiUB|{D@SNZW_^wTL~l*mbv>~>f>l!pxaULpKEw=)qg$Nk9XOZYa0G2t^x+V<4bVRsZwaH)l>g+ zt9F(fdeUuY&9`#q67O4N#lp&p4o0I`h;h~8nD%Y!VOXH11nFhZNF(N2!gf2Ki@*^O zc!w+}zr?24dgV{{jW4j06!46QsxD8>kiKy|T2coVzKR{z8^&;gdKBv?RI~VNRYNda zd)o=b)fVYba=_)__Zg#v!mI%ov5u1dFhn?K3pV+x7}eJWa{bmy%>Hz*yG125JBl{T z0y4rsW1Dfw12$(}+o64>v&Oimt))6>O{WYr!WT){=t?B(hyAnkc2uIh(QKd<&(RY> zNdREH$S)4bcXCL_llWl)#TbELpD;y}%(Hwz)JO`&y7M}*jp$IMR>^)-x~3y?#kQP^ z$c3J+)0Pssgf7!`$Mk$@d8#qM*4rFvy%N+&Q#yiMv#F4d3BQkf4N_@4!((sVyXLA8@w)$&@DoMIpDvLKu>k@E ze2;ItOR)VYr@!35`h2SzmE0*5wMysn z(fd+?#wH#rw-_Quw!}dztCp^KPa$TXl$x4!!8kdyIb`7Z2);G;*s!$k2hB1wRa_VD zLZO*yZb{h|?l-ZkHYx|6%csKFL<>S$eM`b+@*Jo~=DBkS9<~utwZeQN3_>#6ibDBh z(U32@O#U79W_03WUP`mW$8Esvj7=er+iRY;>&r?58Ko#pD>E$Xr?&r1Z|5L|iPvYrRTT=WVsg(!euCvC6uvh>(|SH7tMKxFw@ro?p4Rw4=%LsS5< zKo~laFV)s)e+gu{CqsplvDW8X*XChM5EU@t+mm^5Mbh>6UhEIpQ@A*wiD+`Q2-z|S zONfxkB1I4RrBaaeZI2lJ_M0eo*GU!qV(*VJ--mKto&X2g;VD%+EyP{L0Ndhm$N2)@ zI2@>&i&&htvvfk*6q63hz`!xspc-rkJaSlUroULnDQqaKjpBd8hZ zR&>)cMb4Y$Q`5jmi$wFrQsskEI_XfX4Xx1V<-l=$%PRg$K4YQfca@`wZ)KY>t#7zR z+qI!!jbr65+(blavJ|Iuo~_|TQP%kzq7aBXNAJ5cK&)j8siLY`$SR6)f!VbX*~3f7 zgeWP*E|Kk$?fP}XXAkqwHuDeL?c^1`pF;^{`8XPaB8pTIkc0U}??2l2Bms?ki);ul zl+iT($hNQ_uns6rS6qT_rQA|Kd&plh=u(JbTSX8?r4{BJ@R4^ZGQEt&TElM&IPxvc zkK3^PDYTe5Q}q)cqDlYxq$6|)$m+}`AT1@t19>p$o)BBro?_d&5We2LJ-m z3@9|Sp!rdJ9C~I0qG!sA;JC0Td3JRPAT4QnsQAxrb}m34BH@SEleq0|Q$%CIP!sU3 zP#yg1_u(w9Ltmqy4wK$@Uqw>)w<#I+xkOlR!}9dv#%P{}Jajf$ zkjF|z9$Y*37$OMF1;1AeSQL|b z{1V`=?F*gk=fXn$>uMDvErrzMnKEm?^LAahMRhGzZCQ8hwx4=sR`(T+vBZ?-iA{bD zooqvt>;Tiq+6$u+d4@ZInI{80A}?rz9l?SIH)2ny_-7Sb2N~U`OGzqP5EL2a$287qs^)Tk6Pign6p&L3r?iPUgx7>h)9v&@~SOPb{-r0MD2 zyi1~1dG5c=A9oFa%E9hJ70O*dh8>=<$eQZ(@rIlIk5gqD!2G7gPh(pDfc$s%E14!j zV=q|=9U8IYXHRl&Ag0+-iN5C8$E@NSq{tLxNJ_<*klrU z&%PYkh3%PX1`%*lkJcfa5`eA}6IbuGE-`j(HS+d7-4CME>zu-=Bf{J9nw-Xky*a6+ z-frjGlhPmUkSBxmT#Sok?0-t%QxZDoQM=9^OyybOEH4oiFT4OH}G0 zW|fi!1Wk&~2xn~VaLdqPMJ?(fEWE$L?kDvIsTWv#@5l^M_l13M1coUO8J@WrFF*~} ziWP<YSL&H4` zY;+h5Gz`J+{xMb=EQhZz_Nld(z-{WyIlD$S0l&)lKc*NqmOL7K1?5WYv8|>t9-$2= zJSyqL(K!0PS#loR(<@e?JoqmVW@TEi@ijcYp51_dv68EwV)x>l$dUP*?=p_#C(-dW zW+6n1D`{nI?efj${n?}ZpfoCE?WM0VN2rHoo zV)$feiB2O2&55bEm%i#rGIgC#SvLxp-(x z(3rn7h*CL3`eXe-UqPYb^2!CO5rTs1ngpv)ZC{2OtC{TZK2))j1}aZYcxM9MHEA%K znw;~j%t#WRT1`xK#63Kg5+qu&^^o(Lq=QnMqC@D3FwkIbT}m7BtA|k{l~^238-{nC z=D&w9>hz&h!ZS{Z$_X^B$r_F)%_V&?ieS&O5WDPzusU4FPymx4-j~B8MHCIcTDlmz zoE=L#@gS+g|I2{Yb0 z!!*+l7rs=i@5=Pb6HNiYR!zvcW`HybsPvPvBw~s*iF=);Qj+Z(r!?TV8&2LNKQj*v}$m(Blk*sx4?U4jJAG*7c;0tZh4+Nkv>KUs_#>M zynwKqsv`Tq+2zi*hGv)l(_+g0Kc<=GpV)*!aet}vAnFHugLstX!B10$$U^O)DOW1ntiSk|P0Jp4= zbq5lPxLxa^BWU*>Dc+GIETYL?}JzTo0TzpJGW^&JuRyKiPM=MQjNOf8|6KC3uevYbXv{B+CJ&+%ab}zG91B`AQ z@m-9XDp>rrXCw4OAZR))ggBjWiSLSdj`2ib=-tl@f8R})F>Dxr2;#wkaEDXEx%lmOH z5&H8~CAtDG>y?w&BRTH%0~Nc1^>O2MmDhKjhXPO07YMAE@;o~DQ2hk2FIIiE!00KF zR(yU@MZ(QtWlU)QWkn$Y0ZfN<$h1>>8fSnQRp?Bh`yKYCS<)gt@K3XM6Nom=&cS`@lrzBt3}9YIYsUE(7NkU)jgc#&y+gs)5*$D(>e#e;A$DbNj?Mc68a=3y{JMEPkYd(+8Zt;6>Uq zd_3>Bf9v^Qtd^V}{Y-MP`=!yB7RX-R-R`Cmx0Qg!dex|^!u;T%p=xr|Gp8}5{Ta+*?937 z;X{&jYf)|;yR*&}=#6`$?Fw3VuSCir4w_}pM9c1<68VFYJJml5rZAE zx}^{)x&s6Z0UhN@-Rk8i(9Te86PiarGUl>G?}sO@j4~}qx-`G=-tB$#mYbGV-jkue z{0|4qOsIj+#}y`c2odKwRfZ2oC$aVBPS)feYRr%j@1LPP<-V~m*ROxnXqtqF!Y&iO zlCKrt0TR|5+qfMR&&LQJt?6h8zf&EHX?9*P&Imdf-s>Z$w#%@GJr7V!8a0;Md8zsw z4|TIErPwz{FO;Hu%t;@f_qk_widh?WO1VD!yngw2yx8|RC_W!w3N5DNhn2@4h9>1o^SqS8rFL|ybgPDlmv$-+SFM& zFXM%s^oT-tGNSa0vC#wK_GL1`E0YdrhI)DPm%nlIZa-Ni-hKw*~C4QMvrB z4Xxs*%gvPiM=(<)qX^f=1Gd%^7aZTu%>*_zhHTIcS^&fNWqoXEtuO)i42qf61dG%FEM z5(B^EX(RN)*ElYUhn+=tlsP4JwX}U&$I}^FoDy%j&Cxe;%v>I=I)D7pls9=Bo1gH7 z1p%ppm7S^wKOy5Y?EM3kV6f=uYD<^9q`mE!lsK!@-?&b+ttmB?4nJ&zYLVLHqYCyI(&J5ZU6o;|9a7$ z&@|e$4lCH-fzy%~OFxh<=&P&FU)UEh5wZJyIO4E4wKl#xjb1tddULA0$%DeZjDSqnXc64h?IR+l<+AFuT@!0~16jU$1qnVNJ2l{~?cc=rf@m$ZR)Q z&W?54av*}TKOti+XOH)^SQ9h6A^CizHG#%VulD zqL|#9^9|Ih;!__MpH}{6d3T?j)*Jjf^m0xi-dXaUHxx`6_`5w{dTCdcI`s%GZEf1= zVU3MRKoFuFDti~Ezuywgx>m6c6`YoSMQCV;_KbukvKWPmsTLYNmCcQ0{lOG|bfnPP zqU*`wFg6J8?94pFmNR1T8wyax(N^;EVv?I%cN1mEGU8rR{=Bj~iX^S$HJ6Gs7ZbV=hF7N#Z_rv`I z=j`+BbM}7rTI(z_G^G}9L9;*Jzt1rru~U!RxDK_@Xi8E(;R$+#Omq&uWbT0`x)B)SDNFZobE(jGY{I3MbVf z3G29FiUEJuwGf84-wtMc>-;KJ(h;<3R2gJVl2Xt{Sp8A(9mr*R@0dtZFUZ2m*UIjj z?}Q)FAA3#md$;dtp~u8_P(7TJJEx|Q>mv!U9<;8hRBVyOK-ruqTM{|U`4dkG?j6U$ zk>#qNoM(d%I46G8F1RYSYNMu#bs!4!uR&m9PsPb8`hHM@{P|NcjJToy-v57 z;+sDM*dk_9-1d!HkDnZFoEMUPVM!oOsMlwiwh7wDT`iV zijIsZE9C85w0gZ2;uMCJqo_k9dc_vDf=ysEc0QA}ac5K4{b3`JKf(+DQuOa=LrS+e z%#i;!R8`z$JN^er)%Rs(6o%+Va{Z}HbKIskJ}u^RK|KSq208c(K(G(X&?Ya~{Pn=E z)qp=%k%(6W!Y_Bc;_lmPYg`9MY7>O(a^6J0|8o6Tb>ENSRe0Zr{>{@4ZMN^dRP6AP z)r0yvtM7tw3wI|>+*NnwdF`L%)m64L5SSR?1{VCW8@z1yWT{NVIp8)GmJVsVYFkS% z|HH2xi%-T?O=@rC0^&Y@gwlVUz3A$ zX~`Yu%gPuE`EoMfD02@jLmoFu(}l037@tv}YoZU$o^?Eur*@^$1_`8YJE^g|(H$5< zV%)+26)W1>0OpsXIWmwZRh00zB!NL$_DKzjxN+WO4R>xLIfzr7WA3lBo{S_|{Nh8> zo?oVuRnTWrV@Uw~c*zY!wyx7RL-SjO`?B2ju&L(LBVj_%^NbSSTHsvutI^&P0MQG2 zQljb0aC>4`d_gHB9S)1s7$eSVYXq@cXl&Ir>`Z9xo*;Csw+Tu5cf6$4rR*vvy|Ih? zdq;7+#{{RV2{A?&?-t`eHg6h9$=F(AKJO)!lcy zfJH3h5^qeo&=UPCFO3DIZo-;Z8%227>ML$sO$gmM*u^~Q!oJVi_3wrAReC}Bnl|)$ zX1umAhXIWp6O5v?l@xE0l91=1iYe7cQE!v8ecoQiEY3LQ>$W$O5(4Q>i@Ky5Ic`PI znx#QANYX#|++L$uv=q*GLTNiOI#Kj{!e^(1VbM~}HC;37r{39z-;d`k(a0M*GmU_? z49%Q4son3B$QS~n1(mX-@LgAJqRf>1Fq+TA$sf&5gi*=-U?j{;#02>f?-f>^Su1y> z>je&+`|_`*N$c3A<9@$mY*w=?->DJf83vBd`q7n3MjUsIj?q1M2aJ3Rj;nf>y^)qP zfcqC3Hy7qB_ANG)78E46T4-KYU|DrIn`qxEU2>*9d7;nJeDMeWV~nq65Bp$`$>5## ziJVgM1xtQxnxPb9f?AJu(_1PkYIpMJKV=fN@xqumf=|cqpb@8fL1G%^S=q^Eph#0f z_E(8mc2(p94+THv9GYtK->qC7;gM*|g#vf$(s?~Q>1VXjF=BzwToizePd@VJ2BXnd z9ilh0j-boqjOCw}nQ+Fxi)s>l#n5cIPK*If3LSR0IQ@~BDa#f7<2}VO?lPat3HeoQ zsZ7;Lc!gj172^aDhc!^Xq$E=wwdU0pKSb1MrZy+1;UHS){nx7LTmLd76UFAf0wi$1-K1I3gsV;TzFQe2CaZBl}}= zhK@#=6eAId{*&4KGmia@S0h~W&}Ygt2QfbKgR~kp?M6SqF|JokTcOHa7+U5i2Aiir`qDu869rQnf61M?>DJ^O_2p&hX^B%KX zVk>65tGT;wUg>IadPCWw~=kd0n2Pyw|DVoJ$5byVld5W5^R;Z^0wIDK+e*pe79w z5{Hq-^5>eO<1Wq?G%b3ppF|ZChA*g9@I(JFcZEi`6D&wi2ZS1^*AwE z45YB^7D*Mk=4w-0E8uG=3J-zm5!XUfCo=v{m21{Bl$qt|CWrEgyAuROdvMoVh07dL5ACs{Q02qj_n`z60qB|aqz1~#3v|tRFPJBqD7(l z3k&JyxAoe($X%8_3#-HpYmzrYY$or}pR?|O7yxsI?OBzUnTlSC%J6J^fijDc?PEcG z&d*#GHFY?TNaT-Mo^3FTYJt+UkpZJ1md}fTo>yso3m%)obrXnrE#)@Y7x z&l_KAwbdJX60TsN>R08OOCdU5%04+eQ3I(xEiOc^@O#*VUl>s`*12b#X>egL-t9m> zB-S({5^R5;h#PAzdm;LpPs)sI_Lv%k<`}pb=0C9{#kFF}f++3@P`nA~2z`Nit^y^> zwCZW{bhKfAb{WKGQ?y*|FgI9&MLzed-csc=+;7j$oH@8b#(~c+2gHDkztPsVJ8vJ} z9SC@SV1gM6N08W<{vn^Y)Vo=XFp8cG-MO(fJa|GS;i0>)F}edknqTxCIi~le&z` zQd8cF*5b=}v6?JYAT6MmJSMF7rhC$MF1b()YU5eg`3O#1Y@iyW-+n{ZT0=m^iQqij zIyw1jMCXdpmF*C|fZrv{EpGp`3{i8QF&&6oXx*AV?2p1En;hwdmxfu|7S<3Mu4yC7 z=IYc`4RazPpoKay#hHmUBWWatU*rAEqI|V>=T8!B^z7|RkdeKOu7ksNMN2a}Kc|C6 z)PQ8vez!Q-kcRD6;rGE=hus}7kwN5he1QOfkx6IvGW-^NM&EsE_R9O75A)RiNgJv$ z9XYYIp$kjdn@HQ0z^hF=Kl}0+KfXe{(AFVuW-j!3m6td*?B7N}F;2$z*`Xmkwr>Kf z4$=u64v0-I#=daLpagTMe)HM7B!>>WL zRZHz>*mNF=mF|%&YUR#EbSt8b!#mgDKoo%-w5mSJbQ&+#g!J_EnMudomZ%g|MrN7dfqjJdaV@VbqH=KJ1 z7b+O(6B4*H#^u{C1A<$IGR}ea5Bt9~O+f$s!dB}FDxz}Y&Tn)txOw%qGVaFv6(WC? zz9bYYa>~YTl53*t1N>AsDVm3z&Cf%uL*)UJ3fV;CQe~*jfNTBn4Phx3xCO_gz?^Of zmIuLuqoS>lU{!8d>kcOk5V~sDurFtf&hBbcM0Z8apPYGtyPP_dRc3h;B%YynF@RAz zTB>}f-`xhR#eNT7SP{HW^g;gQ2Y0^Y(0e8U-_cK4Rb`y3R|OSZ@p986A1O|g`UM0o z?jfe#c_A>u4b3()*LWHWW-*Ud^{n?#9~&^g*tm2Ek^n)vJDp5N@nF< z>2L?b4R@?vtbe@@Wrh)NyR!%3qGx#}0UBxx;>_qy{_~t)_Rpg0K9Jy?K~# zT3?=yiHVujuA}-*D5+k&7l@7o^S7QptbGk$X@`-S5i(cXEo;s|(GSbwM@knTDZWkr zZh$*Ui|pd#=O zE|@5YMVWRJYsFUH6vpSd%GmKf3c1v%-R&P__1&R2s@^F2CRpqRU@~G~v0H+MK3y6hTq3hWN>s2!-|q%| zU$!1=64}({#O2x&XY1~ti>rowsSFZd?$AkH^rt4|xBMNvg!`dT@*%RV*d6_biqQls zxvO~VZym74+@nY*Ng6(hCWjjzO)u~`5K2%lN>GoD!U}GA`{nY3H_X4U`+kPcYn>s& z?nmApS0bPl3XU*Xp?WOXYn74gACB$QMV8ZM3rCCS86I`EXdC zU9QycN3MwLTbXKF1GlRDAA^U-O+_^Fl`m9HEr>aVh^#TWYxan~t_?NtcN(zC9fQtz zFS{H}hlMDU9~#Sz?hH8$6nQlEq!UHPi_n*=*>rtn+0U_0=7iPkD%<^ti5*+xhS%Au zy&dZ%4Q;ML^p<(Lm7L@!a(OJnA_Ileo`F25&A~}wbrrET>#0__=XDjV89f8hKFV(d zVYbEsy#GwXmr|1khD!t<#_gVVhiqT}n{=#MtJ?|zYUrCze|>Jm4g_y@Z`atlT22}d zOrj9ONF{oY3etI2BmshHgN1CcpoWb15_YJx?-~H%PVV3Gjtt&`QGK;=5)i$d)yomt z8amgd{-W@)ZCiHK(2yjR7;Zn;kJY>`2!?off#A!TS<7Pnuc3Sz@M70oB5G?_RE?;a*~61G(Z;T@m*MdZH$snsAp4L{~4&3w<;PFiA7crzYB19cr z@;Y8_r+lcnl_lw}`D77jNudxik=@Nif=+DGslF_}ZE8F*J1zXj{b50k@ZkoQqxKM) zYFyfFuQ{J{i7aZIle?xoptdFl*cw<;{`HM6YTZ3;^GUa7;X}Vk3_hMf<2?xi@G=B< zIE}uu_#>bb%{N(GS^Ybl)@ek#Qg69!fFW58OfqCx)YI$2q=fPln?uhm5>V~El3be3 zF^{@nNS-hra8`^pQb487yra7;r5JG`%)xV@BnDVy1x$Z;G_JhI_gEI_G=GCkm1WUC zw4wXmS5X%bmU&OeSb<>^;7@^cQY#W`nF#I$e=AqN#y*yVH$E4n(v)X~^HM;^T?i11 zqdaje=HB2BP&+?O-fh>c< zc*UoO^hPodZ@zNStNQ*66Y?Y^HX`~`qHa5h7_^LhGSQP#@!F zO|Nh2GxrP5M@|}KsDn|rww{nCVaXpJ{?Mcq8Kbc1`jSnl<;6R37R8f%Dh%VMk(K%< zF9kh^yb+)9L@cVsFIU&4N7NQ1Az2)#LgD+_ z;F6z0MW8{6xN4(r513cm`pFEXYUT6~io>~nTTfx6B}6h%T-k~JdarMdSmb4OVHIx z?_;)Mc)dNOujjiEO12~_ARFtj)4IDEo%3}psBt97ooyYA_v`JKA;0(4FE87_9vMl0 z51PI#TJL*HH1oR#Y?INdDP<6h0m+f2H<4bXyh{e<`t%87Ng1mfZyj@Y6h59TRM1wu zbFjOaJt}a`WfmQ;eAdVxz*;+ce z7p)tTw3YS&(`0OJe~^A=p+~XuO{P8V{wYn4q>R*Q4D~)Q>e$U?-!gRVHAC-X)>N3T z*XZywk~H@k&&>YF^6|mq!`zF1knO@A^S*NA$x_{X<`Td13QKR1txaA_Kau}E-N;UF z}_Nd@KmPd)J@GAAJyW1HH|?$Muvj@6BexRYo5)cd~F`_-spS9-Q)8GVMN1)L*T=voe>uY0Uw~F(xk?{pI&ZfN1;Q6M*|@;*?k38mE43V=eHCWpfwx_C#r znAllw?Q*~E6z81p{_Bque~HKLaDi1Q*3|XZtP#Ea-Ut0w_7PG`VGJklvgd1dIu%@Ub#a?BJX7Q2*Nx2x$mJ1*^ja}|1R)=J4Vtiv8$kotL2sflbO>$xT?hsO zuY+Alx)(6`Z%|>0ptQfJN+lq2Q~l089zy4B)UX4LKEKP>ou21e(zDC+-0;~l@Bh{E j`2XOe{3aXi30VC`rN0&MDDi9u{X#`SL%vehEckx_MeJN* diff --git a/vendor/github.com/docker/docker/hack/generate-authors.sh b/vendor/github.com/docker/docker/hack/generate-authors.sh deleted file mode 100755 index e78a97f96..000000000 --- a/vendor/github.com/docker/docker/hack/generate-authors.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -set -e - -cd "$(dirname "$(readlink -f "$BASH_SOURCE")")/.." - -# see also ".mailmap" for how email addresses and names are deduplicated - -{ - cat <<-'EOH' - # This file lists all individuals having contributed content to the repository. - # For how it is generated, see `hack/generate-authors.sh`. - EOH - echo - git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf -} > AUTHORS diff --git a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default b/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default deleted file mode 120000 index 4278533d6..000000000 --- a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.default +++ /dev/null @@ -1 +0,0 @@ -../../../contrib/init/sysvinit-debian/docker.default \ No newline at end of file diff --git a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.init b/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.init deleted file mode 120000 index 8cb89d30d..000000000 --- a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.init +++ /dev/null @@ -1 +0,0 @@ -../../../contrib/init/sysvinit-debian/docker \ No newline at end of file diff --git a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.upstart b/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.upstart deleted file mode 120000 index 7e1b64a3e..000000000 --- a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.docker.upstart +++ /dev/null @@ -1 +0,0 @@ -../../../contrib/init/upstart/docker.conf \ No newline at end of file diff --git a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.udev b/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.udev deleted file mode 120000 index 914a36195..000000000 --- a/vendor/github.com/docker/docker/hack/make/.build-deb/docker-engine.udev +++ /dev/null @@ -1 +0,0 @@ -../../../contrib/udev/80-docker.rules \ No newline at end of file diff --git a/vendor/github.com/docker/docker/pkg/README.md b/vendor/github.com/docker/docker/pkg/README.md new file mode 100644 index 000000000..c4b78a8ad --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/README.md @@ -0,0 +1,11 @@ +pkg/ is a collection of utility packages used by the Docker project without being specific to its internals. + +Utility packages are kept separate from the docker core codebase to keep it as small and concise as possible. +If some utilities grow larger and their APIs stabilize, they may be moved to their own repository under the +Docker organization, to facilitate re-use by other projects. However that is not the priority. + +The directory `pkg` is named after the same directory in the camlistore project. Since Brad is a core +Go maintainer, we thought it made sense to copy his methods for organizing Go code :) Thanks Brad! + +Because utility packages are small and neatly separated from the rest of the codebase, they are a good +place to start for aspiring maintainers and contributors. Get in touch if you want to help maintain them! diff --git a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE deleted file mode 100644 index 34c4ea7c5..000000000 --- a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE +++ /dev/null @@ -1,191 +0,0 @@ - - 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 - - Copyright 2014-2016 Docker, 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. diff --git a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD deleted file mode 100644 index 9b4f4a294..000000000 --- a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014-2016 The Docker & Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/docker/docker/pkg/term/ascii_test.go b/vendor/github.com/docker/docker/pkg/term/ascii_test.go new file mode 100644 index 000000000..4a1e7f302 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/term/ascii_test.go @@ -0,0 +1,43 @@ +package term + +import "testing" + +func TestToBytes(t *testing.T) { + codes, err := ToBytes("ctrl-a,a") + if err != nil { + t.Fatal(err) + } + if len(codes) != 2 { + t.Fatalf("Expected 2 codes, got %d", len(codes)) + } + if codes[0] != 1 || codes[1] != 97 { + t.Fatalf("Expected '1' '97', got '%d' '%d'", codes[0], codes[1]) + } + + codes, err = ToBytes("shift-z") + if err == nil { + t.Fatalf("Expected error, got none") + } + + codes, err = ToBytes("ctrl-@,ctrl-[,~,ctrl-o") + if err != nil { + t.Fatal(err) + } + if len(codes) != 4 { + t.Fatalf("Expected 4 codes, got %d", len(codes)) + } + if codes[0] != 0 || codes[1] != 27 || codes[2] != 126 || codes[3] != 15 { + t.Fatalf("Expected '0' '27' '126', '15', got '%d' '%d' '%d' '%d'", codes[0], codes[1], codes[2], codes[3]) + } + + codes, err = ToBytes("DEL,+") + if err != nil { + t.Fatal(err) + } + if len(codes) != 2 { + t.Fatalf("Expected 2 codes, got %d", len(codes)) + } + if codes[0] != 127 || codes[1] != 43 { + t.Fatalf("Expected '127 '43'', got '%d' '%d'", codes[0], codes[1]) + } +} diff --git a/vendor/github.com/docker/docker/pkg/term/windows/windows_test.go b/vendor/github.com/docker/docker/pkg/term/windows/windows_test.go new file mode 100644 index 000000000..52aeab54e --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/term/windows/windows_test.go @@ -0,0 +1,3 @@ +// This file is necessary to pass the Docker tests. + +package windows diff --git a/vendor/github.com/docker/docker/poule.yml b/vendor/github.com/docker/docker/poule.yml new file mode 100644 index 000000000..61aab4551 --- /dev/null +++ b/vendor/github.com/docker/docker/poule.yml @@ -0,0 +1,88 @@ +# Add a "status/0-triage" to every newly opened pull request. +- triggers: + pull_request: [ opened ] + operations: + - type: label + settings: { + patterns: { + status/0-triage: [ ".*" ], + } + } + +# For every newly created or modified issue, assign label based on matching regexp using the `label` +# operation, as well as an Engine-specific version label using `version-label`. +- triggers: + issues: [ edited, opened, reopened ] + operations: + - type: label + settings: { + patterns: { + area/builder: [ "dockerfile", "docker build" ], + area/distribution: [ "docker login", "docker logout", "docker pull", "docker push", "docker search" ], + area/plugins: [ "docker plugin" ], + area/networking: [ "docker network", "ipvs", "vxlan" ], + area/runtime: [ "oci runtime error" ], + area/security/trust: [ "docker_content_trust" ], + area/swarm: [ "docker node", "docker service", "docker swarm" ], + platform/desktop: [ "docker for mac", "docker for windows" ], + platform/freebsd: [ "freebsd" ], + platform/windows: [ "nanoserver", "windowsservercore", "windows server" ], + } + } + - type: version-label + +# When a pull request is closed, attach it to the currently active milestone. +- triggers: + pull_request: [ closed ] + operations: + - type: version-milestone + +# Labeling a PR with `rebuild/` triggers a rebuild job for the associated +# configuration. The label is automatically removed after the rebuild is initiated. There's no such +# thing as "templating" in this configuration, so we need one operation for each type of +# configuration that can be triggered. +- triggers: + pull_request: [ labeled ] + operations: + - type: rebuild + settings: { + # When configurations are empty, the `rebuild` operation rebuilds all the currently + # known statuses for that pull request. + configurations: [], + label: "rebuild/*", + } + - type: rebuild + settings: { + configurations: [ arm ], + label: "rebuild/arm", + } + - type: rebuild + settings: { + configurations: [ experimental ], + label: "rebuild/experimental", + } + - type: rebuild + settings: { + configurations: [ janky ], + label: "rebuild/janky", + } + - type: rebuild + settings: { + configurations: [ userns ], + label: "rebuild/userns", + } + - type: rebuild + settings: { + configurations: [ vendor ], + label: "rebuild/vendor", + } + - type: rebuild + settings: { + configurations: [ win2lin ], + label: "rebuild/win2lin", + } + - type: rebuild + settings: { + configurations: [ windowsRS1 ], + label: "rebuild/windowsRS1", + } diff --git a/vendor/github.com/docker/docker/project/CONTRIBUTORS.md b/vendor/github.com/docker/docker/project/CONTRIBUTORS.md deleted file mode 120000 index 44fcc6343..000000000 --- a/vendor/github.com/docker/docker/project/CONTRIBUTORS.md +++ /dev/null @@ -1 +0,0 @@ -../CONTRIBUTING.md \ No newline at end of file diff --git a/vendor/github.com/docker/docker/vendor.conf b/vendor/github.com/docker/docker/vendor.conf new file mode 100644 index 000000000..bb7718bc4 --- /dev/null +++ b/vendor/github.com/docker/docker/vendor.conf @@ -0,0 +1,140 @@ +# the following lines are in sorted order, FYI +github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62 +github.com/Microsoft/hcsshim v0.5.9 +github.com/Microsoft/go-winio v0.3.8 +github.com/Sirupsen/logrus v0.11.0 +github.com/davecgh/go-spew 6d212800a42e8ab5c146b8ace3490ee17e5225f9 +github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a +github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git +github.com/gorilla/context v1.1 +github.com/gorilla/mux v1.1 +github.com/kr/pty 5cf931ef8f +github.com/mattn/go-shellwords v1.0.0 +github.com/mattn/go-sqlite3 v1.1.0 +github.com/tchap/go-patricia v2.2.6 +github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 +# forked golang.org/x/net package includes a patch for lazy loading trace templates +golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://github.com/tonistiigi/net.git +golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9 +github.com/docker/go-units 8a7beacffa3009a9ac66bad506b18ffdd110cf97 +github.com/docker/go-connections ecb4cb2dd420ada7df7f2593d6c25441f65f69f2 + +github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 +github.com/imdario/mergo 0.2.1 + +#get libnetwork packages +github.com/docker/libnetwork 45b40861e677e37cf27bc184eca5af92f8cdd32d +github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894 +github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 +github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec +github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b +github.com/hashicorp/memberlist 88ac4de0d1a0ca6def284b571342db3b777a4c37 +github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e +github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 +github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef +github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 +github.com/vishvananda/netlink 482f7a52b758233521878cb6c5904b6bd63f3457 +github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060 +github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 +github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d +github.com/coreos/etcd 3a49cbb769ebd8d1dd25abb1e83386e9883a5707 +github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065 +github.com/hashicorp/consul v0.5.2 +github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904 +github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 + +# get graph and distribution packages +github.com/docker/distribution 28602af35aceda2f8d571bad7ca37a54cf0250bc +github.com/vbatts/tar-split v0.10.1 + +# get go-zfs packages +github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa +github.com/pborman/uuid v1.0 + +# get desired notary commit, might also need to be updated in Dockerfile +github.com/docker/notary v0.4.2 + +google.golang.org/grpc v1.0.2 +github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f +github.com/docker/go v1.5.1-1-1-gbaf439e +github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c + +# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly +github.com/opencontainers/runc 9df8b306d01f59d3a8029be411de015b7304dd8f https://github.com/docker/runc.git # libcontainer +github.com/opencontainers/runtime-spec 1c7c27d043c2a5e513a44084d2b10d77d1402b8c # specs +github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 +# libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json) +github.com/coreos/go-systemd v4 +github.com/godbus/dbus v4.0.0 +github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 +github.com/golang/protobuf 1f49d83d9aa00e6ce4fc8258c71cc7786aec968a + +# gelf logging driver deps +github.com/Graylog2/go-gelf aab2f594e4585d43468ac57287b0dece9d806883 + +github.com/fluent/fluent-logger-golang v1.2.1 +# fluent-logger-golang deps +github.com/philhofer/fwd 899e4efba8eaa1fea74175308f3fae18ff3319fa +github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c + +# fsnotify +github.com/fsnotify/fsnotify v1.2.11 + +# awslogs deps +github.com/aws/aws-sdk-go v1.4.22 +github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0 +github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74 + +# logentries +github.com/bsphere/le_go d3308aafe090956bc89a65f0769f58251a1b4f03 + +# gcplogs deps +golang.org/x/oauth2 2baa8a1b9338cf13d9eeb27696d761155fa480be +google.golang.org/api dc6d2353af16e2a2b0ff6986af051d473a4ed468 +google.golang.org/cloud dae7e3d993bc3812a2185af60552bb6b847e52a0 + +# native credentials +github.com/docker/docker-credential-helpers f72c04f1d8e71959a6d103f808c50ccbad79b9fd + +# containerd +github.com/docker/containerd aa8187dbd3b7ad67d8e5e3a15115d3eef43a7ed1 +github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4 + +# cluster +github.com/docker/swarmkit 1c7f003d75f091d5f7051ed982594420e4515f77 +github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9 +github.com/gogo/protobuf v0.3 +github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a +github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e +golang.org/x/crypto 3fbbcd23f1cb824e69491a5930cfeff09b12f4d2 +golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb +github.com/mreiferson/go-httpclient 63fe23f7434723dc904c901043af07931f293c47 +github.com/hashicorp/go-memdb 608dda3b1410a73eaf3ac8b517c9ae7ebab6aa87 +github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990 +github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 +github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 +github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0 +github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e +github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 +github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 +github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8 +github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 +bitbucket.org/ww/goautoneg 75cd24fc2f2c2a2088577d12123ddee5f54e0675 +github.com/matttproud/golang_protobuf_extensions fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a +github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 + +# cli +github.com/spf13/cobra v1.5 https://github.com/dnephin/cobra.git +github.com/spf13/pflag dabebe21bf790f782ea4c7bbd2efc430de182afd +github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 +github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff + +# metrics +github.com/docker/go-metrics 86138d05f285fd9737a99bee2d9be30866b59d72 + +# composefile +github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715 +github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a +github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45 +github.com/xeipuuv/gojsonschema 93e72a773fade158921402d6a24c819b48aba29d +gopkg.in/yaml.v2 a83829b6f1293c91addabc89d0571c246397bbf4 diff --git a/vendor/github.com/emicklei/go-restful/.gitignore b/vendor/github.com/emicklei/go-restful/.gitignore new file mode 100644 index 000000000..cece7be66 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/.gitignore @@ -0,0 +1,70 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +restful.html + +*.out + +tmp.prof + +go-restful.test + +examples/restful-basic-authentication + +examples/restful-encoding-filter + +examples/restful-filters + +examples/restful-hello-world + +examples/restful-resource-functions + +examples/restful-serve-static + +examples/restful-user-service + +*.DS_Store +examples/restful-user-resource + +examples/restful-multi-containers + +examples/restful-form-handling + +examples/restful-CORS-filter + +examples/restful-options-filter + +examples/restful-curly-router + +examples/restful-cpuprofiler-service + +examples/restful-pre-post-filters + +curly.prof + +examples/restful-NCSA-logging + +examples/restful-html-template + +s.html +restful-path-tail diff --git a/vendor/github.com/emicklei/go-restful/.travis.yml b/vendor/github.com/emicklei/go-restful/.travis.yml new file mode 100644 index 000000000..b22f8f547 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.x + +script: go test -v \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/CHANGES.md b/vendor/github.com/emicklei/go-restful/CHANGES.md new file mode 100644 index 000000000..7294637cd --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/CHANGES.md @@ -0,0 +1,234 @@ +Change history of go-restful += +v2.6.1 +- add JSONNewDecoderFunc to allow custom JSON Decoder usage (go 1.10+) + +v2.6.0 +- Make JSR 311 routing and path param processing consistent +- Adding description to RouteBuilder.Reads() +- Update example for Swagger12 and OpenAPI + +2017-09-13 +- added route condition functions using `.If(func)` in route building. + +2017-02-16 +- solved issue #304, make operation names unique + +2017-01-30 + + [IMPORTANT] For swagger users, change your import statement to: + swagger "github.com/emicklei/go-restful-swagger12" + +- moved swagger 1.2 code to go-restful-swagger12 +- created TAG 2.0.0 + +2017-01-27 + +- remove defer request body close +- expose Dispatch for testing filters and Routefunctions +- swagger response model cannot be array +- created TAG 1.0.0 + +2016-12-22 + +- (API change) Remove code related to caching request content. Removes SetCacheReadEntity(doCache bool) + +2016-11-26 + +- Default change! now use CurlyRouter (was RouterJSR311) +- Default change! no more caching of request content +- Default change! do not recover from panics + +2016-09-22 + +- fix the DefaultRequestContentType feature + +2016-02-14 + +- take the qualify factor of the Accept header mediatype into account when deciding the contentype of the response +- add constructors for custom entity accessors for xml and json + +2015-09-27 + +- rename new WriteStatusAnd... to WriteHeaderAnd... for consistency + +2015-09-25 + +- fixed problem with changing Header after WriteHeader (issue 235) + +2015-09-14 + +- changed behavior of WriteHeader (immediate write) and WriteEntity (no status write) +- added support for custom EntityReaderWriters. + +2015-08-06 + +- add support for reading entities from compressed request content +- use sync.Pool for compressors of http response and request body +- add Description to Parameter for documentation in Swagger UI + +2015-03-20 + +- add configurable logging + +2015-03-18 + +- if not specified, the Operation is derived from the Route function + +2015-03-17 + +- expose Parameter creation functions +- make trace logger an interface +- fix OPTIONSFilter +- customize rendering of ServiceError +- JSR311 router now handles wildcards +- add Notes to Route + +2014-11-27 + +- (api add) PrettyPrint per response. (as proposed in #167) + +2014-11-12 + +- (api add) ApiVersion(.) for documentation in Swagger UI + +2014-11-10 + +- (api change) struct fields tagged with "description" show up in Swagger UI + +2014-10-31 + +- (api change) ReturnsError -> Returns +- (api add) RouteBuilder.Do(aBuilder) for DRY use of RouteBuilder +- fix swagger nested structs +- sort Swagger response messages by code + +2014-10-23 + +- (api add) ReturnsError allows you to document Http codes in swagger +- fixed problem with greedy CurlyRouter +- (api add) Access-Control-Max-Age in CORS +- add tracing functionality (injectable) for debugging purposes +- support JSON parse 64bit int +- fix empty parameters for swagger +- WebServicesUrl is now optional for swagger +- fixed duplicate AccessControlAllowOrigin in CORS +- (api change) expose ServeMux in container +- (api add) added AllowedDomains in CORS +- (api add) ParameterNamed for detailed documentation + +2014-04-16 + +- (api add) expose constructor of Request for testing. + +2014-06-27 + +- (api add) ParameterNamed gives access to a Parameter definition and its data (for further specification). +- (api add) SetCacheReadEntity allow scontrol over whether or not the request body is being cached (default true for compatibility reasons). + +2014-07-03 + +- (api add) CORS can be configured with a list of allowed domains + +2014-03-12 + +- (api add) Route path parameters can use wildcard or regular expressions. (requires CurlyRouter) + +2014-02-26 + +- (api add) Request now provides information about the matched Route, see method SelectedRoutePath + +2014-02-17 + +- (api change) renamed parameter constants (go-lint checks) + +2014-01-10 + +- (api add) support for CloseNotify, see http://golang.org/pkg/net/http/#CloseNotifier + +2014-01-07 + +- (api change) Write* methods in Response now return the error or nil. +- added example of serving HTML from a Go template. +- fixed comparing Allowed headers in CORS (is now case-insensitive) + +2013-11-13 + +- (api add) Response knows how many bytes are written to the response body. + +2013-10-29 + +- (api add) RecoverHandler(handler RecoverHandleFunction) to change how panic recovery is handled. Default behavior is to log and return a stacktrace. This may be a security issue as it exposes sourcecode information. + +2013-10-04 + +- (api add) Response knows what HTTP status has been written +- (api add) Request can have attributes (map of string->interface, also called request-scoped variables + +2013-09-12 + +- (api change) Router interface simplified +- Implemented CurlyRouter, a Router that does not use|allow regular expressions in paths + +2013-08-05 + - add OPTIONS support + - add CORS support + +2013-08-27 + +- fixed some reported issues (see github) +- (api change) deprecated use of WriteError; use WriteErrorString instead + +2014-04-15 + +- (fix) v1.0.1 tag: fix Issue 111: WriteErrorString + +2013-08-08 + +- (api add) Added implementation Container: a WebServices collection with its own http.ServeMux allowing multiple endpoints per program. Existing uses of go-restful will register their services to the DefaultContainer. +- (api add) the swagger package has be extended to have a UI per container. +- if panic is detected then a small stack trace is printed (thanks to runner-mei) +- (api add) WriteErrorString to Response + +Important API changes: + +- (api remove) package variable DoNotRecover no longer works ; use restful.DefaultContainer.DoNotRecover(true) instead. +- (api remove) package variable EnableContentEncoding no longer works ; use restful.DefaultContainer.EnableContentEncoding(true) instead. + + +2013-07-06 + +- (api add) Added support for response encoding (gzip and deflate(zlib)). This feature is disabled on default (for backwards compatibility). Use restful.EnableContentEncoding = true in your initialization to enable this feature. + +2013-06-19 + +- (improve) DoNotRecover option, moved request body closer, improved ReadEntity + +2013-06-03 + +- (api change) removed Dispatcher interface, hide PathExpression +- changed receiver names of type functions to be more idiomatic Go + +2013-06-02 + +- (optimize) Cache the RegExp compilation of Paths. + +2013-05-22 + +- (api add) Added support for request/response filter functions + +2013-05-18 + + +- (api add) Added feature to change the default Http Request Dispatch function (travis cline) +- (api change) Moved Swagger Webservice to swagger package (see example restful-user) + +[2012-11-14 .. 2013-05-18> + +- See https://github.com/emicklei/go-restful/commits + +2012-11-14 + +- Initial commit + + diff --git a/vendor/github.com/emicklei/go-restful/Makefile b/vendor/github.com/emicklei/go-restful/Makefile new file mode 100644 index 000000000..b40081cc0 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/Makefile @@ -0,0 +1,7 @@ +all: test + +test: + go test -v . + +ex: + cd examples && ls *.go | xargs go build -o /tmp/ignore \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/README.md b/vendor/github.com/emicklei/go-restful/README.md new file mode 100644 index 000000000..65c3d4f9d --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/README.md @@ -0,0 +1,87 @@ +go-restful +========== +package for building REST-style Web Services using Google Go + +[![Build Status](https://travis-ci.org/emicklei/go-restful.png)](https://travis-ci.org/emicklei/go-restful) +[![Go Report Card](https://goreportcard.com/badge/github.com/emicklei/go-restful)](https://goreportcard.com/report/github.com/emicklei/go-restful) +[![GoDoc](https://godoc.org/github.com/emicklei/go-restful?status.svg)](https://godoc.org/github.com/emicklei/go-restful) + +- [Code examples](https://github.com/emicklei/go-restful/tree/master/examples) + +REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping: + +- GET = Retrieve a representation of a resource +- POST = Create if you are sending content to the server to create a subordinate of the specified resource collection, using some server-side algorithm. +- PUT = Create if you are sending the full content of the specified resource (URI). +- PUT = Update if you are updating the full content of the specified resource. +- DELETE = Delete if you are requesting the server to delete the resource +- PATCH = Update partial content of a resource +- OPTIONS = Get information about the communication options for the request URI + +### Example + +```Go +ws := new(restful.WebService) +ws. + Path("/users"). + Consumes(restful.MIME_XML, restful.MIME_JSON). + Produces(restful.MIME_JSON, restful.MIME_XML) + +ws.Route(ws.GET("/{user-id}").To(u.findUser). + Doc("get a user"). + Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")). + Writes(User{})) +... + +func (u UserResource) findUser(request *restful.Request, response *restful.Response) { + id := request.PathParameter("user-id") + ... +} +``` + +[Full API of a UserResource](https://github.com/emicklei/go-restful/tree/master/examples/restful-user-resource.go) + +### Features + +- Routes for request → function mapping with path parameter (e.g. {id}) support +- Configurable router: + - (default) Fast routing algorithm that allows static elements, regular expressions and dynamic parameters in the URL path (e.g. /meetings/{id} or /static/{subpath:*} + - Routing algorithm after [JSR311](http://jsr311.java.net/nonav/releases/1.1/spec/spec.html) that is implemented using (but does **not** accept) regular expressions +- Request API for reading structs from JSON/XML and accesing parameters (path,query,header) +- Response API for writing structs to JSON/XML and setting headers +- Customizable encoding using EntityReaderWriter registration +- Filters for intercepting the request → response flow on Service or Route level +- Request-scoped variables using attributes +- Containers for WebServices on different HTTP endpoints +- Content encoding (gzip,deflate) of request and response payloads +- Automatic responses on OPTIONS (using a filter) +- Automatic CORS request handling (using a filter) +- API declaration for Swagger UI ([go-restful-openapi](https://github.com/emicklei/go-restful-openapi), see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12)) +- Panic recovery to produce HTTP 500, customizable using RecoverHandler(...) +- Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...) +- Configurable (trace) logging +- Customizable gzip/deflate readers and writers using CompressorProvider registration + +## How to customize +There are several hooks to customize the behavior of the go-restful package. + +- Router algorithm +- Panic recovery +- JSON decoder +- Trace logging +- Compression +- Encoders for other serializers + +TODO: write examples of these. + +## Resources + +- [Example posted on blog](http://ernestmicklei.com/2012/11/go-restful-first-working-example/) +- [Design explained on blog](http://ernestmicklei.com/2012/11/go-restful-api-design/) +- [sourcegraph](https://sourcegraph.com/github.com/emicklei/go-restful) +- [showcase: Zazkia - tcp proxy for testing resiliency](https://github.com/emicklei/zazkia) +- [showcase: Mora - MongoDB REST Api server](https://github.com/emicklei/mora) + +Type ```git shortlog -s``` for a full list of contributors. + +© 2012 - 2018, http://ernestmicklei.com. MIT License. Contributions are welcome. diff --git a/vendor/github.com/emicklei/go-restful/Srcfile b/vendor/github.com/emicklei/go-restful/Srcfile new file mode 100644 index 000000000..16fd18689 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/Srcfile @@ -0,0 +1 @@ +{"SkipDirs": ["examples"]} diff --git a/vendor/github.com/emicklei/go-restful/bench_curly_test.go b/vendor/github.com/emicklei/go-restful/bench_curly_test.go new file mode 100644 index 000000000..db6a1a752 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/bench_curly_test.go @@ -0,0 +1,51 @@ +package restful + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" +) + +func setupCurly(container *Container) []string { + wsCount := 26 + rtCount := 26 + urisCurly := []string{} + + container.Router(CurlyRouter{}) + for i := 0; i < wsCount; i++ { + root := fmt.Sprintf("/%s/{%s}/", string(i+97), string(i+97)) + ws := new(WebService).Path(root) + for j := 0; j < rtCount; j++ { + sub := fmt.Sprintf("/%s2/{%s2}", string(j+97), string(j+97)) + ws.Route(ws.GET(sub).Consumes("application/xml").Produces("application/xml").To(echoCurly)) + } + container.Add(ws) + for _, each := range ws.Routes() { + urisCurly = append(urisCurly, "http://bench.com"+each.Path) + } + } + return urisCurly +} + +func echoCurly(req *Request, resp *Response) {} + +func BenchmarkManyCurly(b *testing.B) { + container := NewContainer() + urisCurly := setupCurly(container) + b.ResetTimer() + for t := 0; t < b.N; t++ { + for r := 0; r < 1000; r++ { + for _, each := range urisCurly { + sendNoReturnTo(each, container, t) + } + } + } +} + +func sendNoReturnTo(address string, container *Container, t int) { + httpRequest, _ := http.NewRequest("GET", address, nil) + httpRequest.Header.Set("Accept", "application/xml") + httpWriter := httptest.NewRecorder() + container.dispatch(httpWriter, httpRequest) +} diff --git a/vendor/github.com/emicklei/go-restful/bench_test.go b/vendor/github.com/emicklei/go-restful/bench_test.go new file mode 100644 index 000000000..3e77c2d29 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/bench_test.go @@ -0,0 +1,43 @@ +package restful + +import ( + "fmt" + "io" + "testing" +) + +var uris = []string{} + +func setup(container *Container) { + wsCount := 26 + rtCount := 26 + + for i := 0; i < wsCount; i++ { + root := fmt.Sprintf("/%s/{%s}/", string(i+97), string(i+97)) + ws := new(WebService).Path(root) + for j := 0; j < rtCount; j++ { + sub := fmt.Sprintf("/%s2/{%s2}", string(j+97), string(j+97)) + ws.Route(ws.GET(sub).To(echo)) + } + container.Add(ws) + for _, each := range ws.Routes() { + uris = append(uris, "http://bench.com"+each.Path) + } + } +} + +func echo(req *Request, resp *Response) { + io.WriteString(resp.ResponseWriter, "echo") +} + +func BenchmarkMany(b *testing.B) { + container := NewContainer() + setup(container) + b.ResetTimer() + for t := 0; t < b.N; t++ { + for _, each := range uris { + // println(each) + sendItTo(each, container) + } + } +} diff --git a/vendor/github.com/emicklei/go-restful/bench_test.sh b/vendor/github.com/emicklei/go-restful/bench_test.sh new file mode 100644 index 000000000..47ffbe4ac --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/bench_test.sh @@ -0,0 +1,10 @@ +#go test -run=none -file bench_test.go -test.bench . -cpuprofile=bench_test.out + +go test -c +./go-restful.test -test.run=none -test.cpuprofile=tmp.prof -test.bench=BenchmarkMany +./go-restful.test -test.run=none -test.cpuprofile=curly.prof -test.bench=BenchmarkManyCurly + +#go tool pprof go-restful.test tmp.prof +go tool pprof go-restful.test curly.prof + + diff --git a/vendor/github.com/emicklei/go-restful/compress_test.go b/vendor/github.com/emicklei/go-restful/compress_test.go new file mode 100644 index 000000000..cc3e93d54 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/compress_test.go @@ -0,0 +1,125 @@ +package restful + +import ( + "bytes" + "compress/gzip" + "compress/zlib" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" +) + +// go test -v -test.run TestGzip ...restful +func TestGzip(t *testing.T) { + EnableContentEncoding = true + httpRequest, _ := http.NewRequest("GET", "/test", nil) + httpRequest.Header.Set("Accept-Encoding", "gzip,deflate") + httpWriter := httptest.NewRecorder() + wanted, encoding := wantsCompressedResponse(httpRequest) + if !wanted { + t.Fatal("should accept gzip") + } + if encoding != "gzip" { + t.Fatal("expected gzip") + } + c, err := NewCompressingResponseWriter(httpWriter, encoding) + if err != nil { + t.Fatal(err.Error()) + } + c.Write([]byte("Hello World")) + c.Close() + if httpWriter.Header().Get("Content-Encoding") != "gzip" { + t.Fatal("Missing gzip header") + } + reader, err := gzip.NewReader(httpWriter.Body) + if err != nil { + t.Fatal(err.Error()) + } + data, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err.Error()) + } + if got, want := string(data), "Hello World"; got != want { + t.Errorf("got %v want %v", got, want) + } +} + +func TestDeflate(t *testing.T) { + EnableContentEncoding = true + httpRequest, _ := http.NewRequest("GET", "/test", nil) + httpRequest.Header.Set("Accept-Encoding", "deflate,gzip") + httpWriter := httptest.NewRecorder() + wanted, encoding := wantsCompressedResponse(httpRequest) + if !wanted { + t.Fatal("should accept deflate") + } + if encoding != "deflate" { + t.Fatal("expected deflate") + } + c, err := NewCompressingResponseWriter(httpWriter, encoding) + if err != nil { + t.Fatal(err.Error()) + } + c.Write([]byte("Hello World")) + c.Close() + if httpWriter.Header().Get("Content-Encoding") != "deflate" { + t.Fatal("Missing deflate header") + } + reader, err := zlib.NewReader(httpWriter.Body) + if err != nil { + t.Fatal(err.Error()) + } + data, err := ioutil.ReadAll(reader) + if err != nil { + t.Fatal(err.Error()) + } + if got, want := string(data), "Hello World"; got != want { + t.Errorf("got %v want %v", got, want) + } +} + +func TestGzipDecompressRequestBody(t *testing.T) { + b := new(bytes.Buffer) + w := newGzipWriter() + w.Reset(b) + io.WriteString(w, `{"msg":"hi"}`) + w.Flush() + w.Close() + + req := new(Request) + httpRequest, _ := http.NewRequest("GET", "/", bytes.NewReader(b.Bytes())) + httpRequest.Header.Set("Content-Type", "application/json") + httpRequest.Header.Set("Content-Encoding", "gzip") + req.Request = httpRequest + + doc := make(map[string]interface{}) + req.ReadEntity(&doc) + + if got, want := doc["msg"], "hi"; got != want { + t.Errorf("got %v want %v", got, want) + } +} + +func TestZlibDecompressRequestBody(t *testing.T) { + b := new(bytes.Buffer) + w := newZlibWriter() + w.Reset(b) + io.WriteString(w, `{"msg":"hi"}`) + w.Flush() + w.Close() + + req := new(Request) + httpRequest, _ := http.NewRequest("GET", "/", bytes.NewReader(b.Bytes())) + httpRequest.Header.Set("Content-Type", "application/json") + httpRequest.Header.Set("Content-Encoding", "deflate") + req.Request = httpRequest + + doc := make(map[string]interface{}) + req.ReadEntity(&doc) + + if got, want := doc["msg"], "hi"; got != want { + t.Errorf("got %v want %v", got, want) + } +} diff --git a/vendor/github.com/emicklei/go-restful/container_test.go b/vendor/github.com/emicklei/go-restful/container_test.go new file mode 100644 index 000000000..491c793ab --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/container_test.go @@ -0,0 +1,83 @@ +package restful + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +// go test -v -test.run TestContainer_computeAllowedMethods ...restful +func TestContainer_computeAllowedMethods(t *testing.T) { + wc := NewContainer() + ws1 := new(WebService).Path("/users") + ws1.Route(ws1.GET("{i}").To(dummy)) + ws1.Route(ws1.POST("{i}").To(dummy)) + wc.Add(ws1) + httpRequest, _ := http.NewRequest("GET", "http://api.his.com/users/1", nil) + rreq := Request{Request: httpRequest} + m := wc.computeAllowedMethods(&rreq) + if len(m) != 2 { + t.Errorf("got %d expected 2 methods, %v", len(m), m) + } +} + +func TestContainer_HandleWithFilter(t *testing.T) { + prefilterCalled := false + postfilterCalled := false + httpHandlerCalled := false + + wc := NewContainer() + wc.Filter(func(request *Request, response *Response, chain *FilterChain) { + prefilterCalled = true + chain.ProcessFilter(request, response) + }) + wc.HandleWithFilter("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + httpHandlerCalled = true + w.Write([]byte("ok")) + })) + wc.Filter(func(request *Request, response *Response, chain *FilterChain) { + postfilterCalled = true + chain.ProcessFilter(request, response) + }) + + recorder := httptest.NewRecorder() + request, _ := http.NewRequest("GET", "/", nil) + wc.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK { + t.Errorf("unexpected code %d", recorder.Code) + } + if recorder.Body.String() != "ok" { + t.Errorf("unexpected body %s", recorder.Body.String()) + } + if !prefilterCalled { + t.Errorf("filter added before calling HandleWithFilter wasn't called") + } + if !postfilterCalled { + t.Errorf("filter added after calling HandleWithFilter wasn't called") + } + if !httpHandlerCalled { + t.Errorf("handler added by calling HandleWithFilter wasn't called") + } +} + +func TestContainerAddAndRemove(t *testing.T) { + ws1 := new(WebService).Path("/") + ws2 := new(WebService).Path("/users") + wc := NewContainer() + wc.Add(ws1) + wc.Add(ws2) + wc.Remove(ws2) + if len(wc.webServices) != 1 { + t.Errorf("expected one webservices") + } + if !wc.isRegisteredOnRoot { + t.Errorf("expected on root registered") + } + wc.Remove(ws1) + if len(wc.webServices) > 0 { + t.Errorf("expected zero webservices") + } + if wc.isRegisteredOnRoot { + t.Errorf("expected not on root registered") + } +} diff --git a/vendor/github.com/emicklei/go-restful/cors_filter_test.go b/vendor/github.com/emicklei/go-restful/cors_filter_test.go new file mode 100644 index 000000000..09c5d3300 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/cors_filter_test.go @@ -0,0 +1,129 @@ +package restful + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +// go test -v -test.run TestCORSFilter_Preflight ...restful +// http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request +func TestCORSFilter_Preflight(t *testing.T) { + tearDown() + ws := new(WebService) + ws.Route(ws.PUT("/cors").To(dummy)) + Add(ws) + + cors := CrossOriginResourceSharing{ + ExposeHeaders: []string{"X-Custom-Header"}, + AllowedHeaders: []string{"X-Custom-Header", "X-Additional-Header"}, + CookiesAllowed: true, + Container: DefaultContainer} + Filter(cors.Filter) + + // Preflight + httpRequest, _ := http.NewRequest("OPTIONS", "http://api.alice.com/cors", nil) + httpRequest.Method = "OPTIONS" + httpRequest.Header.Set(HEADER_Origin, "http://api.bob.com") + httpRequest.Header.Set(HEADER_AccessControlRequestMethod, "PUT") + httpRequest.Header.Set(HEADER_AccessControlRequestHeaders, "X-Custom-Header, X-Additional-Header") + + httpWriter := httptest.NewRecorder() + DefaultContainer.Dispatch(httpWriter, httpRequest) + + actual := httpWriter.Header().Get(HEADER_AccessControlAllowOrigin) + if "http://api.bob.com" != actual { + t.Fatal("expected: http://api.bob.com but got:" + actual) + } + actual = httpWriter.Header().Get(HEADER_AccessControlAllowMethods) + if "PUT" != actual { + t.Fatal("expected: PUT but got:" + actual) + } + actual = httpWriter.Header().Get(HEADER_AccessControlAllowHeaders) + if "X-Custom-Header, X-Additional-Header" != actual { + t.Fatal("expected: X-Custom-Header, X-Additional-Header but got:" + actual) + } + + if !cors.isOriginAllowed("somewhere") { + t.Fatal("origin expected to be allowed") + } + cors.AllowedDomains = []string{"overthere.com"} + if cors.isOriginAllowed("somewhere") { + t.Fatal("origin [somewhere] expected NOT to be allowed") + } + if !cors.isOriginAllowed("overthere.com") { + t.Fatal("origin [overthere] expected to be allowed") + } + +} + +// go test -v -test.run TestCORSFilter_Actual ...restful +// http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request +func TestCORSFilter_Actual(t *testing.T) { + tearDown() + ws := new(WebService) + ws.Route(ws.PUT("/cors").To(dummy)) + Add(ws) + + cors := CrossOriginResourceSharing{ + ExposeHeaders: []string{"X-Custom-Header"}, + AllowedHeaders: []string{"X-Custom-Header", "X-Additional-Header"}, + CookiesAllowed: true, + Container: DefaultContainer} + Filter(cors.Filter) + + // Actual + httpRequest, _ := http.NewRequest("PUT", "http://api.alice.com/cors", nil) + httpRequest.Header.Set(HEADER_Origin, "http://api.bob.com") + httpRequest.Header.Set("X-Custom-Header", "value") + + httpWriter := httptest.NewRecorder() + DefaultContainer.Dispatch(httpWriter, httpRequest) + actual := httpWriter.Header().Get(HEADER_AccessControlAllowOrigin) + if "http://api.bob.com" != actual { + t.Fatal("expected: http://api.bob.com but got:" + actual) + } + if httpWriter.Body.String() != "dummy" { + t.Fatal("expected: dummy but got:" + httpWriter.Body.String()) + } +} + +var allowedDomainInput = []struct { + domains []string + origin string + allowed bool +}{ + {[]string{}, "http://anything.com", true}, + {[]string{"example.com"}, "example.com", true}, + {[]string{"example.com"}, "not-allowed", false}, + {[]string{"not-matching.com", "example.com"}, "example.com", true}, + {[]string{".*"}, "example.com", true}, +} + +// go test -v -test.run TestCORSFilter_AllowedDomains ...restful +func TestCORSFilter_AllowedDomains(t *testing.T) { + for _, each := range allowedDomainInput { + tearDown() + ws := new(WebService) + ws.Route(ws.PUT("/cors").To(dummy)) + Add(ws) + + cors := CrossOriginResourceSharing{ + AllowedDomains: each.domains, + CookiesAllowed: true, + Container: DefaultContainer} + Filter(cors.Filter) + + httpRequest, _ := http.NewRequest("PUT", "http://api.his.com/cors", nil) + httpRequest.Header.Set(HEADER_Origin, each.origin) + httpWriter := httptest.NewRecorder() + DefaultContainer.Dispatch(httpWriter, httpRequest) + actual := httpWriter.Header().Get(HEADER_AccessControlAllowOrigin) + if actual != each.origin && each.allowed { + t.Fatal("expected to be accepted") + } + if actual == each.origin && !each.allowed { + t.Fatal("did not expect to be accepted") + } + } +} diff --git a/vendor/github.com/emicklei/go-restful/coverage.sh b/vendor/github.com/emicklei/go-restful/coverage.sh new file mode 100644 index 000000000..e27dbf1a9 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/coverage.sh @@ -0,0 +1,2 @@ +go test -coverprofile=coverage.out +go tool cover -html=coverage.out \ No newline at end of file diff --git a/vendor/github.com/emicklei/go-restful/curly_test.go b/vendor/github.com/emicklei/go-restful/curly_test.go new file mode 100644 index 000000000..0568dfac1 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/curly_test.go @@ -0,0 +1,238 @@ +package restful + +import ( + "io" + "net/http" + "testing" +) + +var requestPaths = []struct { + // url with path (1) is handled by service with root (2) and remainder has value final (3) + path, root string +}{ + {"/", "/"}, + {"/p", "/p"}, + {"/p/x", "/p/{q}"}, + {"/q/x", "/q"}, + {"/p/x/", "/p/{q}"}, + {"/p/x/y", "/p/{q}"}, + {"/q/x/y", "/q"}, + {"/z/q", "/{p}/q"}, + {"/a/b/c/q", "/"}, +} + +// go test -v -test.run TestCurlyDetectWebService ...restful +func TestCurlyDetectWebService(t *testing.T) { + ws1 := new(WebService).Path("/") + ws2 := new(WebService).Path("/p") + ws3 := new(WebService).Path("/q") + ws4 := new(WebService).Path("/p/q") + ws5 := new(WebService).Path("/p/{q}") + ws7 := new(WebService).Path("/{p}/q") + var wss = []*WebService{ws1, ws2, ws3, ws4, ws5, ws7} + + for _, each := range wss { + t.Logf("path=%s,toks=%v\n", each.pathExpr.Source, each.pathExpr.tokens) + } + + router := CurlyRouter{} + + ok := true + for i, fixture := range requestPaths { + requestTokens := tokenizePath(fixture.path) + who := router.detectWebService(requestTokens, wss) + if who != nil && who.RootPath() != fixture.root { + t.Logf("[line:%v] Unexpected dispatcher, expected:%v, actual:%v", i, fixture.root, who.RootPath()) + ok = false + } + } + if !ok { + t.Fail() + } +} + +var serviceDetects = []struct { + path string + found bool + root string +}{ + {"/a/b", true, "/{p}/{q}/{r}"}, + {"/p/q", true, "/p/q"}, + {"/q/p", true, "/q"}, + {"/", true, "/"}, + {"/p/q/r", true, "/p/q"}, +} + +// go test -v -test.run Test_detectWebService ...restful +func Test_detectWebService(t *testing.T) { + router := CurlyRouter{} + ws1 := new(WebService).Path("/") + ws2 := new(WebService).Path("/p") + ws3 := new(WebService).Path("/q") + ws4 := new(WebService).Path("/p/q") + ws5 := new(WebService).Path("/p/{q}") + ws6 := new(WebService).Path("/p/{q}/") + ws7 := new(WebService).Path("/{p}/q") + ws8 := new(WebService).Path("/{p}/{q}/{r}") + var wss = []*WebService{ws8, ws7, ws6, ws5, ws4, ws3, ws2, ws1} + for _, fix := range serviceDetects { + requestPath := fix.path + requestTokens := tokenizePath(requestPath) + for _, ws := range wss { + serviceTokens := ws.pathExpr.tokens + matches, score := router.computeWebserviceScore(requestTokens, serviceTokens) + t.Logf("req=%s,toks:%v,ws=%s,toks:%v,score=%d,matches=%v", requestPath, requestTokens, ws.RootPath(), serviceTokens, score, matches) + } + best := router.detectWebService(requestTokens, wss) + if best != nil { + if fix.found { + t.Logf("best=%s", best.RootPath()) + } else { + t.Fatalf("should have found:%s", fix.root) + } + } + } +} + +var routeMatchers = []struct { + route string + path string + matches bool + paramCount int + staticCount int +}{ + // route, request-path + {"/a", "/a", true, 0, 1}, + {"/a", "/b", false, 0, 0}, + {"/a", "/b", false, 0, 0}, + {"/a/{b}/c/", "/a/2/c", true, 1, 2}, + {"/{a}/{b}/{c}/", "/a/b", false, 0, 0}, + {"/{x:*}", "/", false, 0, 0}, + {"/{x:*}", "/a", true, 1, 0}, + {"/{x:*}", "/a/b", true, 1, 0}, + {"/a/{x:*}", "/a/b", true, 1, 1}, + {"/a/{x:[A-Z][A-Z]}", "/a/ZX", true, 1, 1}, + {"/basepath/{resource:*}", "/basepath/some/other/location/test.xml", true, 1, 1}, +} + +// clear && go test -v -test.run Test_matchesRouteByPathTokens ...restful +func Test_matchesRouteByPathTokens(t *testing.T) { + router := CurlyRouter{} + for i, each := range routeMatchers { + routeToks := tokenizePath(each.route) + reqToks := tokenizePath(each.path) + matches, pCount, sCount := router.matchesRouteByPathTokens(routeToks, reqToks) + if matches != each.matches { + t.Fatalf("[%d] unexpected matches outcome route:%s, path:%s, matches:%v", i, each.route, each.path, matches) + } + if pCount != each.paramCount { + t.Fatalf("[%d] unexpected paramCount got:%d want:%d ", i, pCount, each.paramCount) + } + if sCount != each.staticCount { + t.Fatalf("[%d] unexpected staticCount got:%d want:%d ", i, sCount, each.staticCount) + } + } +} + +// clear && go test -v -test.run TestExtractParameters_Wildcard1 ...restful +func TestExtractParameters_Wildcard1(t *testing.T) { + params := doExtractParams("/fixed/{var:*}", 2, "/fixed/remainder", t) + if params["var"] != "remainder" { + t.Errorf("parameter mismatch var: %s", params["var"]) + } +} + +// clear && go test -v -test.run TestExtractParameters_Wildcard2 ...restful +func TestExtractParameters_Wildcard2(t *testing.T) { + params := doExtractParams("/fixed/{var:*}", 2, "/fixed/remain/der", t) + if params["var"] != "remain/der" { + t.Errorf("parameter mismatch var: %s", params["var"]) + } +} + +// clear && go test -v -test.run TestExtractParameters_Wildcard3 ...restful +func TestExtractParameters_Wildcard3(t *testing.T) { + params := doExtractParams("/static/{var:*}", 2, "/static/test/sub/hi.html", t) + if params["var"] != "test/sub/hi.html" { + t.Errorf("parameter mismatch var: %s", params["var"]) + } +} + +func TestExtractParameters_Wildcard4(t *testing.T) { + params := doExtractParams("/static/{var:*}/sub", 3, "/static/test/sub", t) + if params["var"] != "test/sub" { + t.Errorf("parameter mismatch var: %s", params["var"]) + } +} + +// clear && go test -v -test.run TestCurly_ISSUE_34 ...restful +func TestCurly_ISSUE_34(t *testing.T) { + ws1 := new(WebService).Path("/") + ws1.Route(ws1.GET("/{type}/{id}").To(curlyDummy)) + ws1.Route(ws1.GET("/network/{id}").To(curlyDummy)) + croutes := CurlyRouter{}.selectRoutes(ws1, tokenizePath("/network/12")) + if len(croutes) != 2 { + t.Fatal("expected 2 routes") + } + if got, want := croutes[0].route.Path, "/network/{id}"; got != want { + t.Errorf("got %v want %v", got, want) + } +} + +// clear && go test -v -test.run TestCurly_ISSUE_34_2 ...restful +func TestCurly_ISSUE_34_2(t *testing.T) { + ws1 := new(WebService) + ws1.Route(ws1.GET("/network/{id}").To(curlyDummy)) + ws1.Route(ws1.GET("/{type}/{id}").To(curlyDummy)) + croutes := CurlyRouter{}.selectRoutes(ws1, tokenizePath("/network/12")) + if len(croutes) != 2 { + t.Fatal("expected 2 routes") + } + if got, want := croutes[0].route.Path, "/network/{id}"; got != want { + t.Errorf("got %v want %v", got, want) + } +} + +// clear && go test -v -test.run TestCurly_JsonHtml ...restful +func TestCurly_JsonHtml(t *testing.T) { + ws1 := new(WebService) + ws1.Path("/") + ws1.Route(ws1.GET("/some.html").To(curlyDummy).Consumes("*/*").Produces("text/html")) + req, _ := http.NewRequest("GET", "/some.html", nil) + req.Header.Set("Accept", "application/json") + _, route, err := CurlyRouter{}.SelectRoute([]*WebService{ws1}, req) + if err == nil { + t.Error("error expected") + } + if route != nil { + t.Error("no route expected") + } +} + +// go test -v -test.run TestCurly_ISSUE_137 ...restful +func TestCurly_ISSUE_137(t *testing.T) { + ws1 := new(WebService) + ws1.Route(ws1.GET("/hello").To(curlyDummy)) + ws1.Path("/") + req, _ := http.NewRequest("GET", "/", nil) + _, route, _ := CurlyRouter{}.SelectRoute([]*WebService{ws1}, req) + t.Log(route) + if route != nil { + t.Error("no route expected") + } +} + +// go test -v -test.run TestCurly_ISSUE_137_2 ...restful +func TestCurly_ISSUE_137_2(t *testing.T) { + ws1 := new(WebService) + ws1.Route(ws1.GET("/hello").To(curlyDummy)) + ws1.Path("/") + req, _ := http.NewRequest("GET", "/hello/bob", nil) + _, route, _ := CurlyRouter{}.SelectRoute([]*WebService{ws1}, req) + t.Log(route) + if route != nil { + t.Errorf("no route expected, got %v", route) + } +} + +func curlyDummy(req *Request, resp *Response) { io.WriteString(resp.ResponseWriter, "curlyDummy") } diff --git a/vendor/github.com/emicklei/go-restful/doc_examples_test.go b/vendor/github.com/emicklei/go-restful/doc_examples_test.go new file mode 100644 index 000000000..0af636e55 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/doc_examples_test.go @@ -0,0 +1,41 @@ +package restful + +import "net/http" + +func ExampleOPTIONSFilter() { + // Install the OPTIONS filter on the default Container + Filter(OPTIONSFilter()) +} +func ExampleContainer_OPTIONSFilter() { + // Install the OPTIONS filter on a Container + myContainer := new(Container) + myContainer.Filter(myContainer.OPTIONSFilter) +} + +func ExampleContainer() { + // The Default container of go-restful uses the http.DefaultServeMux. + // You can create your own Container using restful.NewContainer() and create a new http.Server for that particular container + + ws := new(WebService) + wsContainer := NewContainer() + wsContainer.Add(ws) + server := &http.Server{Addr: ":8080", Handler: wsContainer} + server.ListenAndServe() +} + +func ExampleCrossOriginResourceSharing() { + // To install this filter on the Default Container use: + cors := CrossOriginResourceSharing{ExposeHeaders: []string{"X-My-Header"}, CookiesAllowed: false, Container: DefaultContainer} + Filter(cors.Filter) +} + +func ExampleServiceError() { + resp := new(Response) + resp.WriteEntity(NewError(http.StatusBadRequest, "Non-integer {id} path parameter")) +} + +func ExampleBoundedCachedCompressors() { + // Register a compressor provider (gzip/deflate read/write) that uses + // a bounded cache with a maximum of 20 writers and 20 readers. + SetCompressorProvider(NewBoundedCachedCompressors(20, 20)) +} diff --git a/vendor/github.com/emicklei/go-restful/entity_accessors_test.go b/vendor/github.com/emicklei/go-restful/entity_accessors_test.go new file mode 100644 index 000000000..d1c1e1585 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/entity_accessors_test.go @@ -0,0 +1,69 @@ +package restful + +import ( + "bytes" + "fmt" + "io" + "net/http" + "net/http/httptest" + "reflect" + "testing" +) + +type keyvalue struct { + readCalled bool + writeCalled bool +} + +func (kv *keyvalue) Read(req *Request, v interface{}) error { + //t := reflect.TypeOf(v) + //rv := reflect.ValueOf(v) + kv.readCalled = true + return nil +} + +func (kv *keyvalue) Write(resp *Response, status int, v interface{}) error { + t := reflect.TypeOf(v) + rv := reflect.ValueOf(v) + for ix := 0; ix < t.NumField(); ix++ { + sf := t.Field(ix) + io.WriteString(resp, sf.Name) + io.WriteString(resp, "=") + io.WriteString(resp, fmt.Sprintf("%v\n", rv.Field(ix).Interface())) + } + kv.writeCalled = true + return nil +} + +// go test -v -test.run TestKeyValueEncoding ...restful +func TestKeyValueEncoding(t *testing.T) { + type Book struct { + Title string + Author string + PublishedYear int + } + kv := new(keyvalue) + RegisterEntityAccessor("application/kv", kv) + b := Book{"Singing for Dummies", "john doe", 2015} + + // Write + httpWriter := httptest.NewRecorder() + // Accept Produces + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/kv,*/*;q=0.8", routeProduces: []string{"application/kv"}, prettyPrint: true} + resp.WriteEntity(b) + t.Log(string(httpWriter.Body.Bytes())) + if !kv.writeCalled { + t.Error("Write never called") + } + + // Read + bodyReader := bytes.NewReader(httpWriter.Body.Bytes()) + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/kv; charset=UTF-8") + request := NewRequest(httpRequest) + var bb Book + request.ReadEntity(&bb) + if !kv.readCalled { + t.Error("Read never called") + } +} diff --git a/vendor/github.com/emicklei/go-restful/filter_test.go b/vendor/github.com/emicklei/go-restful/filter_test.go new file mode 100644 index 000000000..fadfb570f --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/filter_test.go @@ -0,0 +1,141 @@ +package restful + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" +) + +func setupServices(addGlobalFilter bool, addServiceFilter bool, addRouteFilter bool) { + if addGlobalFilter { + Filter(globalFilter) + } + Add(newTestService(addServiceFilter, addRouteFilter)) +} + +func tearDown() { + DefaultContainer.webServices = []*WebService{} + DefaultContainer.isRegisteredOnRoot = true // this allows for setupServices multiple times + DefaultContainer.containerFilters = []FilterFunction{} +} + +func newTestService(addServiceFilter bool, addRouteFilter bool) *WebService { + ws := new(WebService).Path("") + if addServiceFilter { + ws.Filter(serviceFilter) + } + rb := ws.GET("/foo").To(foo) + if addRouteFilter { + rb.Filter(routeFilter) + } + ws.Route(rb) + ws.Route(ws.GET("/bar").To(bar)) + return ws +} + +func foo(req *Request, resp *Response) { + io.WriteString(resp.ResponseWriter, "foo") +} + +func bar(req *Request, resp *Response) { + io.WriteString(resp.ResponseWriter, "bar") +} + +func fail(req *Request, resp *Response) { + http.Error(resp.ResponseWriter, "something failed", http.StatusInternalServerError) +} + +func globalFilter(req *Request, resp *Response, chain *FilterChain) { + io.WriteString(resp.ResponseWriter, "global-") + chain.ProcessFilter(req, resp) +} + +func serviceFilter(req *Request, resp *Response, chain *FilterChain) { + io.WriteString(resp.ResponseWriter, "service-") + chain.ProcessFilter(req, resp) +} + +func routeFilter(req *Request, resp *Response, chain *FilterChain) { + io.WriteString(resp.ResponseWriter, "route-") + chain.ProcessFilter(req, resp) +} + +func TestNoFilter(t *testing.T) { + tearDown() + setupServices(false, false, false) + actual := sendIt("http://example.com/foo") + if "foo" != actual { + t.Fatal("expected: foo but got:" + actual) + } +} + +func TestGlobalFilter(t *testing.T) { + tearDown() + setupServices(true, false, false) + actual := sendIt("http://example.com/foo") + if "global-foo" != actual { + t.Fatal("expected: global-foo but got:" + actual) + } +} + +func TestWebServiceFilter(t *testing.T) { + tearDown() + setupServices(true, true, false) + actual := sendIt("http://example.com/foo") + if "global-service-foo" != actual { + t.Fatal("expected: global-service-foo but got:" + actual) + } +} + +func TestRouteFilter(t *testing.T) { + tearDown() + setupServices(true, true, true) + actual := sendIt("http://example.com/foo") + if "global-service-route-foo" != actual { + t.Fatal("expected: global-service-route-foo but got:" + actual) + } +} + +func TestRouteFilterOnly(t *testing.T) { + tearDown() + setupServices(false, false, true) + actual := sendIt("http://example.com/foo") + if "route-foo" != actual { + t.Fatal("expected: route-foo but got:" + actual) + } +} + +func TestBar(t *testing.T) { + tearDown() + setupServices(false, true, false) + actual := sendIt("http://example.com/bar") + if "service-bar" != actual { + t.Fatal("expected: service-bar but got:" + actual) + } +} + +func TestAllFiltersBar(t *testing.T) { + tearDown() + setupServices(true, true, true) + actual := sendIt("http://example.com/bar") + if "global-service-bar" != actual { + t.Fatal("expected: global-service-bar but got:" + actual) + } +} + +func sendIt(address string) string { + httpRequest, _ := http.NewRequest("GET", address, nil) + httpRequest.Header.Set("Accept", "*/*") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + return httpWriter.Body.String() +} + +func sendItTo(address string, container *Container) string { + httpRequest, _ := http.NewRequest("GET", address, nil) + httpRequest.Header.Set("Accept", "*/*") + httpWriter := httptest.NewRecorder() + container.dispatch(httpWriter, httpRequest) + return httpWriter.Body.String() +} diff --git a/vendor/github.com/emicklei/go-restful/jsr311_test.go b/vendor/github.com/emicklei/go-restful/jsr311_test.go new file mode 100644 index 000000000..15cb3333c --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/jsr311_test.go @@ -0,0 +1,332 @@ +package restful + +import ( + "io" + "net/http" + "reflect" + "sort" + "testing" +) + +// +// Step 1 tests +// +var paths = []struct { + // url with path (1) is handled by service with root (2) and last capturing group has value final (3) + path, root, final string + params map[string]string +}{ + {"/", "/", "/", map[string]string{}}, + {"/p", "/p", "", map[string]string{}}, + {"/p/x", "/p/{q}", "", map[string]string{"q": "x"}}, + {"/q/x", "/q", "/x", map[string]string{}}, + {"/p/x/", "/p/{q}", "/", map[string]string{"q": "x"}}, + {"/p/x/y", "/p/{q}", "/y", map[string]string{"q": "x"}}, + {"/q/x/y", "/q", "/x/y", map[string]string{}}, + {"/z/q", "/{p}/q", "", map[string]string{"p": "z"}}, + {"/a/b/c/q", "/", "/a/b/c/q", map[string]string{}}, +} + +func TestDetectDispatcher(t *testing.T) { + ws1 := new(WebService).Path("/") + ws2 := new(WebService).Path("/p") + ws3 := new(WebService).Path("/q") + ws4 := new(WebService).Path("/p/q") + ws5 := new(WebService).Path("/p/{q}") + ws6 := new(WebService).Path("/p/{q}/") + ws7 := new(WebService).Path("/{p}/q") + var dispatchers = []*WebService{ws1, ws2, ws3, ws4, ws5, ws6, ws7} + + wc := NewContainer() + for _, each := range dispatchers { + each.Route(each.GET("").To(dummy)) + wc.Add(each) + } + + router := RouterJSR311{} + + ok := true + for i, fixture := range paths { + who, final, err := router.detectDispatcher(fixture.path, dispatchers) + if err != nil { + t.Logf("error in detection:%v", err) + ok = false + } + if who.RootPath() != fixture.root { + t.Logf("[line:%v] Unexpected dispatcher, expected:%v, actual:%v", i, fixture.root, who.RootPath()) + ok = false + } + if final != fixture.final { + t.Logf("[line:%v] Unexpected final, expected:%v, actual:%v", i, fixture.final, final) + ok = false + } + params := router.ExtractParameters(&who.Routes()[0], who, fixture.path) + if !reflect.DeepEqual(params, fixture.params) { + t.Logf("[line:%v] Unexpected params, expected:%v, actual:%v", i, fixture.params, params) + ok = false + } + } + if !ok { + t.Fail() + } +} + +// +// Step 2 tests +// + +// go test -v -test.run TestISSUE_179 ...restful +func TestISSUE_179(t *testing.T) { + ws1 := new(WebService) + ws1.Route(ws1.GET("/v1/category/{param:*}").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/v1/category/sub/sub") + t.Logf("%v", routes) +} + +// go test -v -test.run TestISSUE_30 ...restful +func TestISSUE_30(t *testing.T) { + ws1 := new(WebService).Path("/users") + ws1.Route(ws1.GET("/{id}").To(dummy)) + ws1.Route(ws1.POST("/login").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/login") + if len(routes) != 2 { + t.Fatal("expected 2 routes") + } + if routes[0].Path != "/users/login" { + t.Error("first is", routes[0].Path) + t.Logf("routes:%v", routes) + } +} + +// go test -v -test.run TestISSUE_34 ...restful +func TestISSUE_34(t *testing.T) { + ws1 := new(WebService).Path("/") + ws1.Route(ws1.GET("/{type}/{id}").To(dummy)) + ws1.Route(ws1.GET("/network/{id}").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/network/12") + if len(routes) != 2 { + t.Fatal("expected 2 routes") + } + if routes[0].Path != "/network/{id}" { + t.Error("first is", routes[0].Path) + t.Logf("routes:%v", routes) + } +} + +// go test -v -test.run TestISSUE_34_2 ...restful +func TestISSUE_34_2(t *testing.T) { + ws1 := new(WebService).Path("/") + // change the registration order + ws1.Route(ws1.GET("/network/{id}").To(dummy)) + ws1.Route(ws1.GET("/{type}/{id}").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/network/12") + if len(routes) != 2 { + t.Fatal("expected 2 routes") + } + if routes[0].Path != "/network/{id}" { + t.Error("first is", routes[0].Path) + } +} + +// go test -v -test.run TestISSUE_137 ...restful +func TestISSUE_137(t *testing.T) { + ws1 := new(WebService) + ws1.Route(ws1.GET("/hello").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/") + t.Log(routes) + if len(routes) > 0 { + t.Error("no route expected") + } +} + +func TestSelectRoutesSlash(t *testing.T) { + ws1 := new(WebService).Path("/") + ws1.Route(ws1.GET("").To(dummy)) + ws1.Route(ws1.GET("/").To(dummy)) + ws1.Route(ws1.GET("/u").To(dummy)) + ws1.Route(ws1.POST("/u").To(dummy)) + ws1.Route(ws1.POST("/u/v").To(dummy)) + ws1.Route(ws1.POST("/u/{w}").To(dummy)) + ws1.Route(ws1.POST("/u/{w}/z").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/u") + checkRoutesContains(routes, "/u", t) + checkRoutesContainsNo(routes, "/u/v", t) + checkRoutesContainsNo(routes, "/", t) + checkRoutesContainsNo(routes, "/u/{w}/z", t) +} +func TestSelectRoutesU(t *testing.T) { + ws1 := new(WebService).Path("/u") + ws1.Route(ws1.GET("").To(dummy)) + ws1.Route(ws1.GET("/").To(dummy)) + ws1.Route(ws1.GET("/v").To(dummy)) + ws1.Route(ws1.POST("/{w}").To(dummy)) + ws1.Route(ws1.POST("/{w}/z").To(dummy)) // so full path = /u/{w}/z + routes := RouterJSR311{}.selectRoutes(ws1, "/v") // test against /u/v + checkRoutesContains(routes, "/u/{w}", t) +} + +func TestSelectRoutesUsers1(t *testing.T) { + ws1 := new(WebService).Path("/users") + ws1.Route(ws1.POST("").To(dummy)) + ws1.Route(ws1.POST("/").To(dummy)) + ws1.Route(ws1.PUT("/{id}").To(dummy)) + routes := RouterJSR311{}.selectRoutes(ws1, "/1") + checkRoutesContains(routes, "/users/{id}", t) +} +func checkRoutesContains(routes []Route, path string, t *testing.T) { + if !containsRoutePath(routes, path, t) { + for _, r := range routes { + t.Logf("route %v %v", r.Method, r.Path) + } + t.Fatalf("routes should include [%v]:", path) + } +} +func checkRoutesContainsNo(routes []Route, path string, t *testing.T) { + if containsRoutePath(routes, path, t) { + for _, r := range routes { + t.Logf("route %v %v", r.Method, r.Path) + } + t.Fatalf("routes should not include [%v]:", path) + } +} +func containsRoutePath(routes []Route, path string, t *testing.T) bool { + for _, each := range routes { + if each.Path == path { + return true + } + } + return false +} + +// go test -v -test.run TestSortableRouteCandidates ...restful +func TestSortableRouteCandidates(t *testing.T) { + fixture := &sortableRouteCandidates{} + r1 := routeCandidate{matchesCount: 0, literalCount: 0, nonDefaultCount: 0} + r2 := routeCandidate{matchesCount: 0, literalCount: 0, nonDefaultCount: 1} + r3 := routeCandidate{matchesCount: 0, literalCount: 1, nonDefaultCount: 1} + r4 := routeCandidate{matchesCount: 1, literalCount: 1, nonDefaultCount: 0} + r5 := routeCandidate{matchesCount: 1, literalCount: 0, nonDefaultCount: 0} + fixture.candidates = append(fixture.candidates, r5, r4, r3, r2, r1) + sort.Sort(sort.Reverse(fixture)) + first := fixture.candidates[0] + if first.matchesCount != 1 && first.literalCount != 1 && first.nonDefaultCount != 0 { + t.Fatal("expected r4") + } + last := fixture.candidates[len(fixture.candidates)-1] + if last.matchesCount != 0 && last.literalCount != 0 && last.nonDefaultCount != 0 { + t.Fatal("expected r1") + } +} + +func TestDetectRouteReturns404IfNoRoutePassesConditions(t *testing.T) { + called := false + shouldNotBeCalledButWas := false + + routes := []Route{ + new(RouteBuilder).To(dummy). + If(func(req *http.Request) bool { return false }). + Build(), + + // check that condition functions are called in order + new(RouteBuilder). + To(dummy). + If(func(req *http.Request) bool { return true }). + If(func(req *http.Request) bool { called = true; return false }). + Build(), + + // check that condition functions short circuit + new(RouteBuilder). + To(dummy). + If(func(req *http.Request) bool { return false }). + If(func(req *http.Request) bool { shouldNotBeCalledButWas = true; return false }). + Build(), + } + + _, err := RouterJSR311{}.detectRoute(routes, (*http.Request)(nil)) + if se := err.(ServiceError); se.Code != 404 { + t.Fatalf("expected 404, got %d", se.Code) + } + + if !called { + t.Fatal("expected condition function to get called, but it wasn't") + } + + if shouldNotBeCalledButWas { + t.Fatal("expected condition function to not be called, but it was") + } +} + +var extractParams = []struct { + name string + routePath string + urlPath string + expectedParams map[string]string +}{ + {"wildcardLastPart", "/fixed/{var:*}", "/fixed/remainder", map[string]string{"var": "remainder"}}, + {"wildcardMultipleParts", "/fixed/{var:*}", "/fixed/remain/der", map[string]string{"var": "remain/der"}}, + {"wildcardManyParts", "/fixed/{var:*}", "/fixed/test/sub/hi.html", map[string]string{"var": "test/sub/hi.html"}}, + {"wildcardInMiddle", "/fixed/{var:*}/morefixed", "/fixed/middle/stuff/morefixed", map[string]string{"var": "middle/stuff"}}, + {"wildcardFollowedByVar", "/fixed/{var:*}/morefixed/{otherVar}", "/fixed/middle/stuff/morefixed/end", map[string]string{"var": "middle/stuff", "otherVar": "end"}}, + {"singleParam", "/fixed/{var}", "/fixed/remainder", map[string]string{"var": "remainder"}}, + {"slash", "/", "/", map[string]string{}}, + {"NoVars", "/fixed", "/fixed", map[string]string{}}, + {"TwoVars", "/from/{source}/to/{destination}", "/from/LHR/to/AMS", map[string]string{"source": "LHR", "destination": "AMS"}}, + {"VarOnFront", "/{what}/from/{source}", "/who/from/SOS", map[string]string{"what": "who", "source": "SOS"}}, +} + +func TestExtractParams(t *testing.T) { + for _, testCase := range extractParams { + t.Run(testCase.name, func(t *testing.T) { + ws1 := new(WebService).Path("/") + ws1.Route(ws1.GET(testCase.routePath).To(dummy)) + router := RouterJSR311{} + req, _ := http.NewRequest(http.MethodGet, testCase.urlPath, nil) + params := router.ExtractParameters(&ws1.Routes()[0], ws1, req.URL.Path) + if len(params) != len(testCase.expectedParams) { + t.Fatalf("Wrong length of params on selected route, expected: %v, got: %v", testCase.expectedParams, params) + } + for expectedParamKey, expectedParamValue := range testCase.expectedParams { + if expectedParamValue != params[expectedParamKey] { + t.Errorf("Wrong parameter for key '%v', expected: %v, got: %v", expectedParamKey, expectedParamValue, params[expectedParamKey]) + } + } + }) + } +} + +func TestSelectRouteInvalidMethod(t *testing.T) { + ws1 := new(WebService).Path("/") + ws1.Route(ws1.GET("/simple").To(dummy)) + router := RouterJSR311{} + req, _ := http.NewRequest(http.MethodPost, "/simple", nil) + _, _, err := router.SelectRoute([]*WebService{ws1}, req) + if err == nil { + t.Fatal("Expected an error as the wrong method is used but was nil") + } +} + +func TestParameterInWebService(t *testing.T) { + for _, testCase := range extractParams { + t.Run(testCase.name, func(t *testing.T) { + ws1 := new(WebService).Path("/{wsParam}") + ws1.Route(ws1.GET(testCase.routePath).To(dummy)) + router := RouterJSR311{} + req, _ := http.NewRequest(http.MethodGet, "/wsValue"+testCase.urlPath, nil) + params := router.ExtractParameters(&ws1.Routes()[0], ws1, req.URL.Path) + expectedParams := map[string]string{"wsParam": "wsValue"} + for key, value := range testCase.expectedParams { + expectedParams[key] = value + } + if len(params) != len(expectedParams) { + t.Fatalf("Wrong length of params on selected route, expected: %v, got: %v", testCase.expectedParams, params) + } + for expectedParamKey, expectedParamValue := range testCase.expectedParams { + if expectedParamValue != params[expectedParamKey] { + t.Errorf("Wrong parameter for key '%v', expected: %v, got: %v", expectedParamKey, expectedParamValue, params[expectedParamKey]) + } + } + }) + } +} + +func dummy(req *Request, resp *Response) { io.WriteString(resp.ResponseWriter, "dummy") } diff --git a/vendor/github.com/emicklei/go-restful/mime_test.go b/vendor/github.com/emicklei/go-restful/mime_test.go new file mode 100644 index 000000000..a910bb100 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/mime_test.go @@ -0,0 +1,17 @@ +package restful + +import ( + "fmt" + "testing" +) + +// go test -v -test.run TestSortMimes ...restful +func TestSortMimes(t *testing.T) { + accept := "text/html; q=0.8, text/plain, image/gif, */*; q=0.01, image/jpeg" + result := sortedMimes(accept) + got := fmt.Sprintf("%v", result) + want := "[{text/plain 1} {image/gif 1} {image/jpeg 1} {text/html 0.8} {*/* 0.01}]" + if got != want { + t.Errorf("bad sort order of mime types:%s", got) + } +} diff --git a/vendor/github.com/emicklei/go-restful/options_filter_test.go b/vendor/github.com/emicklei/go-restful/options_filter_test.go new file mode 100644 index 000000000..f0fceb834 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/options_filter_test.go @@ -0,0 +1,34 @@ +package restful + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +// go test -v -test.run TestOptionsFilter ...restful +func TestOptionsFilter(t *testing.T) { + tearDown() + ws := new(WebService) + ws.Route(ws.GET("/candy/{kind}").To(dummy)) + ws.Route(ws.DELETE("/candy/{kind}").To(dummy)) + ws.Route(ws.POST("/candies").To(dummy)) + Add(ws) + Filter(OPTIONSFilter()) + + httpRequest, _ := http.NewRequest("OPTIONS", "http://here.io/candy/gum", nil) + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + actual := httpWriter.Header().Get(HEADER_Allow) + if "GET,DELETE" != actual { + t.Fatal("expected: GET,DELETE but got:" + actual) + } + + httpRequest, _ = http.NewRequest("OPTIONS", "http://here.io/candies", nil) + httpWriter = httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + actual = httpWriter.Header().Get(HEADER_Allow) + if "POST" != actual { + t.Fatal("expected: POST but got:" + actual) + } +} diff --git a/vendor/github.com/emicklei/go-restful/path_expression_test.go b/vendor/github.com/emicklei/go-restful/path_expression_test.go new file mode 100644 index 000000000..073f1989e --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/path_expression_test.go @@ -0,0 +1,45 @@ +package restful + +import ( + "reflect" + "testing" +) + +var tempregexs = []struct { + template, regex string + names []string + literalCount, varCount int +}{ + {"", "^(/.*)?$", nil, 0, 0}, + {"/a/{b}/c/", "^/a/([^/]+?)/c(/.*)?$", []string{"b"}, 2, 1}, + {"/{a}/{b}/{c-d-e}/", "^/([^/]+?)/([^/]+?)/([^/]+?)(/.*)?$", []string{"a", "b", "c-d-e"}, 0, 3}, + {"/{p}/abcde", "^/([^/]+?)/abcde(/.*)?$", []string{"p"}, 5, 1}, + {"/a/{b:*}", "^/a/(.*)(/.*)?$", []string{"b"}, 1, 1}, + {"/a/{b:[a-z]+}", "^/a/([a-z]+)(/.*)?$", []string{"b"}, 1, 1}, +} + +func TestTemplateToRegularExpression(t *testing.T) { + ok := true + for i, fixture := range tempregexs { + actual, lCount, varNames, vCount, _ := templateToRegularExpression(fixture.template) + if actual != fixture.regex { + t.Logf("regex mismatch, expected:%v , actual:%v, line:%v\n", fixture.regex, actual, i) // 11 = where the data starts + ok = false + } + if lCount != fixture.literalCount { + t.Logf("literal count mismatch, expected:%v , actual:%v, line:%v\n", fixture.literalCount, lCount, i) + ok = false + } + if vCount != fixture.varCount { + t.Logf("variable count mismatch, expected:%v , actual:%v, line:%v\n", fixture.varCount, vCount, i) + ok = false + } + if !reflect.DeepEqual(fixture.names, varNames) { + t.Logf("variable name mismatch, expected:%v , actual:%v, line:%v\n", fixture.names, varNames, i) + ok = false + } + } + if !ok { + t.Fatal("one or more expression did not match") + } +} diff --git a/vendor/github.com/emicklei/go-restful/path_processor_test.go b/vendor/github.com/emicklei/go-restful/path_processor_test.go new file mode 100644 index 000000000..fd1b07dd7 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/path_processor_test.go @@ -0,0 +1,55 @@ +package restful + +import "testing" + +func TestMatchesPath_OneParam(t *testing.T) { + params := doExtractParams("/from/{source}", 2, "/from/here", t) + if params["source"] != "here" { + t.Errorf("parameter mismatch here") + } +} + +func TestMatchesPath_Slash(t *testing.T) { + params := doExtractParams("/", 0, "/", t) + if len(params) != 0 { + t.Errorf("expected empty parameters") + } +} + +func TestMatchesPath_SlashNonVar(t *testing.T) { + params := doExtractParams("/any", 1, "/any", t) + if len(params) != 0 { + t.Errorf("expected empty parameters") + } +} + +func TestMatchesPath_TwoVars(t *testing.T) { + params := doExtractParams("/from/{source}/to/{destination}", 4, "/from/AMS/to/NY", t) + if params["source"] != "AMS" { + t.Errorf("parameter mismatch AMS") + } +} + +func TestMatchesPath_VarOnFront(t *testing.T) { + params := doExtractParams("{what}/from/{source}/", 3, "who/from/SOS/", t) + if params["source"] != "SOS" { + t.Errorf("parameter mismatch SOS") + } +} + +func TestExtractParameters_EmptyValue(t *testing.T) { + params := doExtractParams("/fixed/{var}", 2, "/fixed/", t) + if params["var"] != "" { + t.Errorf("parameter mismatch var") + } +} + +func doExtractParams(routePath string, size int, urlPath string, t *testing.T) map[string]string { + r := Route{Path: routePath} + r.postBuild() + if len(r.pathParts) != size { + t.Fatalf("len not %v %v, but %v", size, r.pathParts, len(r.pathParts)) + } + pathProcessor := defaultPathProcessor{} + return pathProcessor.ExtractParameters(&r, nil, urlPath) +} diff --git a/vendor/github.com/emicklei/go-restful/request_test.go b/vendor/github.com/emicklei/go-restful/request_test.go new file mode 100644 index 000000000..31f509659 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/request_test.go @@ -0,0 +1,141 @@ +package restful + +import ( + "encoding/json" + "net/http" + "net/url" + "strconv" + "strings" + "testing" +) + +func TestQueryParameter(t *testing.T) { + hreq := http.Request{Method: "GET"} + hreq.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar") + rreq := Request{Request: &hreq} + if rreq.QueryParameter("q") != "foo" { + t.Errorf("q!=foo %#v", rreq) + } +} + +type Anything map[string]interface{} + +type Number struct { + ValueFloat float64 + ValueInt int64 +} + +type Sample struct { + Value string +} + +func TestReadEntityJson(t *testing.T) { + bodyReader := strings.NewReader(`{"Value" : "42"}`) + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/json") + request := &Request{Request: httpRequest} + sam := new(Sample) + request.ReadEntity(sam) + if sam.Value != "42" { + t.Fatal("read failed") + } +} + +func TestReadEntityJsonCharset(t *testing.T) { + bodyReader := strings.NewReader(`{"Value" : "42"}`) + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/json; charset=UTF-8") + request := NewRequest(httpRequest) + sam := new(Sample) + request.ReadEntity(sam) + if sam.Value != "42" { + t.Fatal("read failed") + } +} + +func TestReadEntityJsonNumber(t *testing.T) { + bodyReader := strings.NewReader(`{"Value" : 4899710515899924123}`) + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/json") + request := &Request{Request: httpRequest} + any := make(Anything) + request.ReadEntity(&any) + number, ok := any["Value"].(json.Number) + if !ok { + t.Fatal("read failed") + } + vint, err := number.Int64() + if err != nil { + t.Fatal("convert failed") + } + if vint != 4899710515899924123 { + t.Fatal("read failed") + } + vfloat, err := number.Float64() + if err != nil { + t.Fatal("convert failed") + } + // match the default behaviour + vstring := strconv.FormatFloat(vfloat, 'e', 15, 64) + if vstring != "4.899710515899924e+18" { + t.Fatal("convert float64 failed") + } +} + +func TestReadEntityJsonLong(t *testing.T) { + bodyReader := strings.NewReader(`{"ValueFloat" : 4899710515899924123, "ValueInt": 4899710515899924123}`) + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/json") + request := &Request{Request: httpRequest} + number := new(Number) + request.ReadEntity(&number) + if number.ValueInt != 4899710515899924123 { + t.Fatal("read failed") + } + // match the default behaviour + vstring := strconv.FormatFloat(number.ValueFloat, 'e', 15, 64) + if vstring != "4.899710515899924e+18" { + t.Fatal("convert float64 failed") + } +} + +func TestBodyParameter(t *testing.T) { + bodyReader := strings.NewReader(`value1=42&value2=43`) + httpRequest, _ := http.NewRequest("POST", "/test?value1=44", bodyReader) // POST and PUT body parameters take precedence over URL query string + httpRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") + request := NewRequest(httpRequest) + v1, err := request.BodyParameter("value1") + if err != nil { + t.Error(err) + } + v2, err := request.BodyParameter("value2") + if err != nil { + t.Error(err) + } + if v1 != "42" || v2 != "43" { + t.Fatal("read failed") + } +} + +func TestReadEntityUnkown(t *testing.T) { + bodyReader := strings.NewReader("?") + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/rubbish") + request := NewRequest(httpRequest) + sam := new(Sample) + err := request.ReadEntity(sam) + if err == nil { + t.Fatal("read should be in error") + } +} + +func TestSetAttribute(t *testing.T) { + bodyReader := strings.NewReader("?") + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + request := NewRequest(httpRequest) + request.SetAttribute("go", "there") + there := request.Attribute("go") + if there != "there" { + t.Fatalf("missing request attribute:%v", there) + } +} diff --git a/vendor/github.com/emicklei/go-restful/response_test.go b/vendor/github.com/emicklei/go-restful/response_test.go new file mode 100644 index 000000000..0587c40b4 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/response_test.go @@ -0,0 +1,213 @@ +package restful + +import ( + "errors" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestWriteHeader(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}, prettyPrint: true} + resp.WriteHeader(123) + if resp.StatusCode() != 123 { + t.Errorf("Unexpected status code:%d", resp.StatusCode()) + } +} + +func TestNoWriteHeader(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}, prettyPrint: true} + if resp.StatusCode() != http.StatusOK { + t.Errorf("Unexpected status code:%d", resp.StatusCode()) + } +} + +type food struct { + Kind string +} + +// go test -v -test.run TestMeasureContentLengthXml ...restful +func TestMeasureContentLengthXml(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}, prettyPrint: true} + resp.WriteAsXml(food{"apple"}) + if resp.ContentLength() != 76 { + t.Errorf("Incorrect measured length:%d", resp.ContentLength()) + } +} + +// go test -v -test.run TestMeasureContentLengthJson ...restful +func TestMeasureContentLengthJson(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}, prettyPrint: true} + resp.WriteAsJson(food{"apple"}) + if resp.ContentLength() != 22 { + t.Errorf("Incorrect measured length:%d", resp.ContentLength()) + } +} + +// go test -v -test.run TestMeasureContentLengthJsonNotPretty ...restful +func TestMeasureContentLengthJsonNotPretty(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}} + resp.WriteAsJson(food{"apple"}) + if resp.ContentLength() != 17 { // 16+1 using the Encoder directly yields another /n + t.Errorf("Incorrect measured length:%d", resp.ContentLength()) + } +} + +// go test -v -test.run TestMeasureContentLengthWriteErrorString ...restful +func TestMeasureContentLengthWriteErrorString(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}, prettyPrint: true} + resp.WriteErrorString(404, "Invalid") + if resp.ContentLength() != len("Invalid") { + t.Errorf("Incorrect measured length:%d", resp.ContentLength()) + } +} + +// go test -v -test.run TestStatusIsPassedToResponse ...restful +func TestStatusIsPassedToResponse(t *testing.T) { + for _, each := range []struct { + write, read int + }{ + {write: 204, read: 204}, + {write: 304, read: 304}, + {write: 200, read: 200}, + {write: 400, read: 400}, + } { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "*/*", routeProduces: []string{"*/*"}, prettyPrint: true} + resp.WriteHeader(each.write) + if got, want := httpWriter.Code, each.read; got != want { + t.Errorf("got %v want %v", got, want) + } + } +} + +// go test -v -test.run TestStatusCreatedAndContentTypeJson_Issue54 ...restful +func TestStatusCreatedAndContentTypeJson_Issue54(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/json", routeProduces: []string{"application/json"}, prettyPrint: true} + resp.WriteHeader(201) + resp.WriteAsJson(food{"Juicy"}) + if httpWriter.HeaderMap.Get("Content-Type") != "application/json" { + t.Errorf("Expected content type json but got:%s", httpWriter.HeaderMap.Get("Content-Type")) + } + if httpWriter.Code != 201 { + t.Errorf("Expected status 201 but got:%d", httpWriter.Code) + } +} + +type errorOnWriteRecorder struct { + *httptest.ResponseRecorder +} + +func (e errorOnWriteRecorder) Write(bytes []byte) (int, error) { + return 0, errors.New("fail") +} + +// go test -v -test.run TestLastWriteErrorCaught ...restful +func TestLastWriteErrorCaught(t *testing.T) { + httpWriter := errorOnWriteRecorder{httptest.NewRecorder()} + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/json", routeProduces: []string{"application/json"}, prettyPrint: true} + err := resp.WriteAsJson(food{"Juicy"}) + if err.Error() != "fail" { + t.Errorf("Unexpected error message:%v", err) + } +} + +// go test -v -test.run TestAcceptStarStar_Issue83 ...restful +func TestAcceptStarStar_Issue83(t *testing.T) { + httpWriter := httptest.NewRecorder() + // Accept Produces + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/bogus,*/*;q=0.8", routeProduces: []string{"application/json"}, prettyPrint: true} + resp.WriteEntity(food{"Juicy"}) + ct := httpWriter.Header().Get("Content-Type") + if "application/json" != ct { + t.Errorf("Unexpected content type:%s", ct) + } +} + +// go test -v -test.run TestAcceptSkipStarStar_Issue83 ...restful +func TestAcceptSkipStarStar_Issue83(t *testing.T) { + httpWriter := httptest.NewRecorder() + // Accept Produces + resp := Response{ResponseWriter: httpWriter, requestAccept: " application/xml ,*/* ; q=0.8", routeProduces: []string{"application/json", "application/xml"}, prettyPrint: true} + resp.WriteEntity(food{"Juicy"}) + ct := httpWriter.Header().Get("Content-Type") + if "application/xml" != ct { + t.Errorf("Unexpected content type:%s", ct) + } +} + +// go test -v -test.run TestAcceptXmlBeforeStarStar_Issue83 ...restful +func TestAcceptXmlBeforeStarStar_Issue83(t *testing.T) { + httpWriter := httptest.NewRecorder() + // Accept Produces + resp := Response{ResponseWriter: httpWriter, requestAccept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", routeProduces: []string{"application/json"}, prettyPrint: true} + resp.WriteEntity(food{"Juicy"}) + ct := httpWriter.Header().Get("Content-Type") + if "application/json" != ct { + t.Errorf("Unexpected content type:%s", ct) + } +} + +// go test -v -test.run TestWriteHeaderNoContent_Issue124 ...restful +func TestWriteHeaderNoContent_Issue124(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "text/plain", routeProduces: []string{"text/plain"}, prettyPrint: true} + resp.WriteHeader(http.StatusNoContent) + if httpWriter.Code != http.StatusNoContent { + t.Errorf("got %d want %d", httpWriter.Code, http.StatusNoContent) + } +} + +// go test -v -test.run TestStatusCreatedAndContentTypeJson_Issue163 ...restful +func TestStatusCreatedAndContentTypeJson_Issue163(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/json", routeProduces: []string{"application/json"}, prettyPrint: true} + resp.WriteHeader(http.StatusNotModified) + if httpWriter.Code != http.StatusNotModified { + t.Errorf("Got %d want %d", httpWriter.Code, http.StatusNotModified) + } +} + +func TestWriteHeaderAndEntity_Issue235(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/json", routeProduces: []string{"application/json"}, prettyPrint: true} + var pong = struct { + Foo string `json:"foo"` + }{Foo: "123"} + resp.WriteHeaderAndEntity(404, pong) + if httpWriter.Code != http.StatusNotFound { + t.Errorf("got %d want %d", httpWriter.Code, http.StatusNoContent) + } + if got, want := httpWriter.Header().Get("Content-Type"), "application/json"; got != want { + t.Errorf("got %v want %v", got, want) + } + if !strings.HasPrefix(httpWriter.Body.String(), "{") { + t.Errorf("expected pong struct in json:%s", httpWriter.Body.String()) + } +} + +func TestWriteEntityNoAcceptMatchWithProduces(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/bogus", routeProduces: []string{"application/json"}, prettyPrint: true} + resp.WriteEntity("done") + if httpWriter.Code != http.StatusOK { + t.Errorf("got %d want %d", httpWriter.Code, http.StatusOK) + } +} + +func TestWriteEntityNoAcceptMatchNoProduces(t *testing.T) { + httpWriter := httptest.NewRecorder() + resp := Response{ResponseWriter: httpWriter, requestAccept: "application/bogus", routeProduces: []string{}, prettyPrint: true} + resp.WriteEntity("done") + if httpWriter.Code != http.StatusNotAcceptable { + t.Errorf("got %d want %d", httpWriter.Code, http.StatusNotAcceptable) + } +} diff --git a/vendor/github.com/emicklei/go-restful/route_builder_test.go b/vendor/github.com/emicklei/go-restful/route_builder_test.go new file mode 100644 index 000000000..25881d5eb --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/route_builder_test.go @@ -0,0 +1,76 @@ +package restful + +import ( + "testing" + "time" +) + +func TestRouteBuilder_PathParameter(t *testing.T) { + p := &Parameter{&ParameterData{Name: "name", Description: "desc"}} + p.AllowMultiple(true) + p.DataType("int") + p.Required(true) + values := map[string]string{"a": "b"} + p.AllowableValues(values) + p.bePath() + + b := new(RouteBuilder) + b.function = dummy + b.Param(p) + r := b.Build() + if !r.ParameterDocs[0].Data().AllowMultiple { + t.Error("AllowMultiple invalid") + } + if r.ParameterDocs[0].Data().DataType != "int" { + t.Error("dataType invalid") + } + if !r.ParameterDocs[0].Data().Required { + t.Error("required invalid") + } + if r.ParameterDocs[0].Data().Kind != PathParameterKind { + t.Error("kind invalid") + } + if r.ParameterDocs[0].Data().AllowableValues["a"] != "b" { + t.Error("allowableValues invalid") + } + if b.ParameterNamed("name") == nil { + t.Error("access to parameter failed") + } +} + +func TestRouteBuilder(t *testing.T) { + json := "application/json" + b := new(RouteBuilder) + b.To(dummy) + b.Path("/routes").Method("HEAD").Consumes(json).Produces(json).Metadata("test", "test-value").DefaultReturns("default", time.Now()) + r := b.Build() + if r.Path != "/routes" { + t.Error("path invalid") + } + if r.Produces[0] != json { + t.Error("produces invalid") + } + if r.Consumes[0] != json { + t.Error("consumes invalid") + } + if r.Operation != "dummy" { + t.Error("Operation not set") + } + if r.Metadata["test"] != "test-value" { + t.Errorf("Metadata not set") + } + if _, ok := r.ResponseErrors[0]; !ok { + t.Fatal("expected default response") + } +} + +func TestAnonymousFuncNaming(t *testing.T) { + f1 := func() {} + f2 := func() {} + if got, want := nameOfFunction(f1), "func1"; got != want { + t.Errorf("got %v want %v", got, want) + } + if got, want := nameOfFunction(f2), "func2"; got != want { + t.Errorf("got %v want %v", got, want) + } +} diff --git a/vendor/github.com/emicklei/go-restful/route_test.go b/vendor/github.com/emicklei/go-restful/route_test.go new file mode 100644 index 000000000..a687d8a4d --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/route_test.go @@ -0,0 +1,76 @@ +package restful + +import ( + "testing" +) + +// accept should match produces +func TestMatchesAcceptPlainTextWhenProducePlainTextAsLast(t *testing.T) { + r := Route{Produces: []string{"application/json", "text/plain"}} + if !r.matchesAccept("text/plain") { + t.Errorf("accept should match text/plain") + } +} + +// accept should match produces +func TestMatchesAcceptStar(t *testing.T) { + r := Route{Produces: []string{"application/xml"}} + if !r.matchesAccept("*/*") { + t.Errorf("accept should match star") + } +} + +// accept should match produces +func TestMatchesAcceptIE(t *testing.T) { + r := Route{Produces: []string{"application/xml"}} + if !r.matchesAccept("text/html, application/xhtml+xml, */*") { + t.Errorf("accept should match star") + } +} + +// accept should match produces +func TestMatchesAcceptXml(t *testing.T) { + r := Route{Produces: []string{"application/xml"}} + if r.matchesAccept("application/json") { + t.Errorf("accept should not match json") + } + if !r.matchesAccept("application/xml") { + t.Errorf("accept should match xml") + } +} + +// accept should match produces +func TestMatchesAcceptAny(t *testing.T) { + r := Route{Produces: []string{"*/*"}} + if !r.matchesAccept("application/json") { + t.Errorf("accept should match json") + } + if !r.matchesAccept("application/xml") { + t.Errorf("accept should match xml") + } +} + +// content type should match consumes +func TestMatchesContentTypeXml(t *testing.T) { + r := Route{Consumes: []string{"application/xml"}} + if r.matchesContentType("application/json") { + t.Errorf("accept should not match json") + } + if !r.matchesContentType("application/xml") { + t.Errorf("accept should match xml") + } +} + +// content type should match consumes +func TestMatchesContentTypeCharsetInformation(t *testing.T) { + r := Route{Consumes: []string{"application/json"}} + if !r.matchesContentType("application/json; charset=UTF-8") { + t.Errorf("matchesContentType should ignore charset information") + } +} + +func TestTokenizePath(t *testing.T) { + if len(tokenizePath("/")) != 0 { + t.Errorf("not empty path tokens") + } +} diff --git a/vendor/github.com/emicklei/go-restful/tracer_test.go b/vendor/github.com/emicklei/go-restful/tracer_test.go new file mode 100644 index 000000000..60c1e9fc0 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/tracer_test.go @@ -0,0 +1,18 @@ +package restful + +import "testing" + +// Use like this: +// +// TraceLogger(testLogger{t}) +type testLogger struct { + t *testing.T +} + +func (l testLogger) Print(v ...interface{}) { + l.t.Log(v...) +} + +func (l testLogger) Printf(format string, v ...interface{}) { + l.t.Logf(format, v...) +} diff --git a/vendor/github.com/emicklei/go-restful/web_service_test.go b/vendor/github.com/emicklei/go-restful/web_service_test.go new file mode 100644 index 000000000..c1b756a94 --- /dev/null +++ b/vendor/github.com/emicklei/go-restful/web_service_test.go @@ -0,0 +1,343 @@ +package restful + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +const ( + pathGetFriends = "/get/{userId}/friends" +) + +func TestParameter(t *testing.T) { + p := &Parameter{&ParameterData{Name: "name", Description: "desc"}} + p.AllowMultiple(true) + p.DataType("int") + p.Required(true) + values := map[string]string{"a": "b"} + p.AllowableValues(values) + p.bePath() + + ws := new(WebService) + ws.Param(p) + if ws.pathParameters[0].Data().Name != "name" { + t.Error("path parameter (or name) invalid") + } +} +func TestWebService_CanCreateParameterKinds(t *testing.T) { + ws := new(WebService) + if ws.BodyParameter("b", "b").Kind() != BodyParameterKind { + t.Error("body parameter expected") + } + if ws.PathParameter("p", "p").Kind() != PathParameterKind { + t.Error("path parameter expected") + } + if ws.QueryParameter("q", "q").Kind() != QueryParameterKind { + t.Error("query parameter expected") + } +} + +func TestCapturePanic(t *testing.T) { + tearDown() + Add(newPanicingService()) + httpRequest, _ := http.NewRequest("GET", "http://here.com/fire", nil) + httpRequest.Header.Set("Accept", "*/*") + httpWriter := httptest.NewRecorder() + // override the default here + DefaultContainer.DoNotRecover(false) + DefaultContainer.dispatch(httpWriter, httpRequest) + if 500 != httpWriter.Code { + t.Error("500 expected on fire") + } +} + +func TestCapturePanicWithEncoded(t *testing.T) { + tearDown() + Add(newPanicingService()) + DefaultContainer.EnableContentEncoding(true) + httpRequest, _ := http.NewRequest("GET", "http://here.com/fire", nil) + httpRequest.Header.Set("Accept", "*/*") + httpRequest.Header.Set("Accept-Encoding", "gzip") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 500 != httpWriter.Code { + t.Error("500 expected on fire, got", httpWriter.Code) + } +} + +func TestNotFound(t *testing.T) { + tearDown() + httpRequest, _ := http.NewRequest("GET", "http://here.com/missing", nil) + httpRequest.Header.Set("Accept", "*/*") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 404 != httpWriter.Code { + t.Error("404 expected on missing") + } +} + +func TestMethodNotAllowed(t *testing.T) { + tearDown() + Add(newGetOnlyService()) + httpRequest, _ := http.NewRequest("POST", "http://here.com/get", nil) + httpRequest.Header.Set("Accept", "*/*") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 405 != httpWriter.Code { + t.Error("405 expected method not allowed") + } +} + +func TestSelectedRoutePath_Issue100(t *testing.T) { + tearDown() + Add(newSelectedRouteTestingService()) + httpRequest, _ := http.NewRequest("GET", "http://here.com/get/232452/friends", nil) + httpRequest.Header.Set("Accept", "*/*") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if http.StatusOK != httpWriter.Code { + t.Error(http.StatusOK, "expected,", httpWriter.Code, "received.") + } +} + +func TestContentType415_Issue170(t *testing.T) { + tearDown() + Add(newGetOnlyJsonOnlyService()) + httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil) + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 200 != httpWriter.Code { + t.Errorf("Expected 200, got %d", httpWriter.Code) + } +} + +func TestNoContentTypePOST(t *testing.T) { + tearDown() + Add(newPostNoConsumesService()) + httpRequest, _ := http.NewRequest("POST", "http://here.com/post", nil) + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 204 != httpWriter.Code { + t.Errorf("Expected 204, got %d", httpWriter.Code) + } +} + +func TestContentType415_POST_Issue170(t *testing.T) { + tearDown() + Add(newPostOnlyJsonOnlyService()) + httpRequest, _ := http.NewRequest("POST", "http://here.com/post", nil) + httpRequest.Header.Set("Content-Type", "application/json") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 200 != httpWriter.Code { + t.Errorf("Expected 200, got %d", httpWriter.Code) + } +} + +// go test -v -test.run TestContentType406PlainJson ...restful +func TestContentType406PlainJson(t *testing.T) { + tearDown() + TraceLogger(testLogger{t}) + Add(newGetPlainTextOrJsonService()) + httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil) + httpRequest.Header.Set("Accept", "text/plain") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 200; got != want { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestRemoveRoute(t *testing.T) { + tearDown() + TraceLogger(testLogger{t}) + ws := newGetPlainTextOrJsonService() + Add(ws) + httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil) + httpRequest.Header.Set("Accept", "text/plain") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 200; got != want { + t.Errorf("got %v, want %v", got, want) + } + + // dynamic apis are disabled, should error and do nothing + if err := ws.RemoveRoute("/get", "GET"); err == nil { + t.Error("unexpected non-error") + } + + httpWriter = httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 200; got != want { + t.Errorf("got %v, want %v", got, want) + } + + ws.SetDynamicRoutes(true) + if err := ws.RemoveRoute("/get", "GET"); err != nil { + t.Errorf("unexpected error %v", err) + } + + httpWriter = httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 404; got != want { + t.Errorf("got %v, want %v", got, want) + } +} +func TestRemoveLastRoute(t *testing.T) { + tearDown() + TraceLogger(testLogger{t}) + ws := newGetPlainTextOrJsonServiceMultiRoute() + Add(ws) + httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil) + httpRequest.Header.Set("Accept", "text/plain") + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 200; got != want { + t.Errorf("got %v, want %v", got, want) + } + + // dynamic apis are disabled, should error and do nothing + if err := ws.RemoveRoute("/get", "GET"); err == nil { + t.Error("unexpected non-error") + } + + httpWriter = httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 200; got != want { + t.Errorf("got %v, want %v", got, want) + } + + ws.SetDynamicRoutes(true) + if err := ws.RemoveRoute("/get", "GET"); err != nil { + t.Errorf("unexpected error %v", err) + } + + httpWriter = httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if got, want := httpWriter.Code, 404; got != want { + t.Errorf("got %v, want %v", got, want) + } +} + +// go test -v -test.run TestContentTypeOctet_Issue170 ...restful +func TestContentTypeOctet_Issue170(t *testing.T) { + tearDown() + Add(newGetConsumingOctetStreamService()) + // with content-type + httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil) + httpRequest.Header.Set("Content-Type", MIME_OCTET) + httpWriter := httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 200 != httpWriter.Code { + t.Errorf("Expected 200, got %d", httpWriter.Code) + } + // without content-type + httpRequest, _ = http.NewRequest("GET", "http://here.com/get", nil) + httpWriter = httptest.NewRecorder() + DefaultContainer.dispatch(httpWriter, httpRequest) + if 200 != httpWriter.Code { + t.Errorf("Expected 200, got %d", httpWriter.Code) + } +} + +type exampleBody struct{} + +func TestParameterDataTypeDefaults(t *testing.T) { + tearDown() + ws := new(WebService) + route := ws.POST("/post").Reads(&exampleBody{}, "") + if route.parameters[0].data.DataType != "*restful.exampleBody" { + t.Errorf("body parameter incorrect name: %#v", route.parameters[0].data) + } +} + +func TestParameterDataTypeCustomization(t *testing.T) { + tearDown() + ws := new(WebService) + ws.TypeNameHandler(func(sample interface{}) string { + return "my.custom.type.name" + }) + route := ws.POST("/post").Reads(&exampleBody{}, "") + if route.parameters[0].data.DataType != "my.custom.type.name" { + t.Errorf("body parameter incorrect name: %#v", route.parameters[0].data) + } +} + +func newPanicingService() *WebService { + ws := new(WebService).Path("") + ws.Route(ws.GET("/fire").To(doPanic)) + return ws +} + +func newGetOnlyService() *WebService { + ws := new(WebService).Path("") + ws.Route(ws.GET("/get").To(doPanic)) + return ws +} + +func newPostOnlyJsonOnlyService() *WebService { + ws := new(WebService).Path("") + ws.Consumes("application/json") + ws.Route(ws.POST("/post").To(doNothing)) + return ws +} + +func newGetOnlyJsonOnlyService() *WebService { + ws := new(WebService).Path("") + ws.Consumes("application/json") + ws.Route(ws.GET("/get").To(doNothing)) + return ws +} + +func newGetPlainTextOrJsonService() *WebService { + ws := new(WebService).Path("") + ws.Produces("text/plain", "application/json") + ws.Route(ws.GET("/get").To(doNothing)) + return ws +} + +func newGetPlainTextOrJsonServiceMultiRoute() *WebService { + ws := new(WebService).Path("") + ws.Produces("text/plain", "application/json") + ws.Route(ws.GET("/get").To(doNothing)) + ws.Route(ws.GET("/status").To(doNothing)) + return ws +} + +func newGetConsumingOctetStreamService() *WebService { + ws := new(WebService).Path("") + ws.Consumes("application/octet-stream") + ws.Route(ws.GET("/get").To(doNothing)) + return ws +} + +func newPostNoConsumesService() *WebService { + ws := new(WebService).Path("") + ws.Route(ws.POST("/post").To(return204)) + return ws +} + +func newSelectedRouteTestingService() *WebService { + ws := new(WebService).Path("") + ws.Route(ws.GET(pathGetFriends).To(selectedRouteChecker)) + return ws +} + +func selectedRouteChecker(req *Request, resp *Response) { + if req.SelectedRoutePath() != pathGetFriends { + resp.InternalServerError() + } +} + +func doPanic(req *Request, resp *Response) { + println("lightning...") + panic("fire") +} + +func doNothing(req *Request, resp *Response) { +} + +func return204(req *Request, resp *Response) { + resp.WriteHeader(204) +} diff --git a/vendor/github.com/ghodss/yaml/.gitignore b/vendor/github.com/ghodss/yaml/.gitignore new file mode 100644 index 000000000..e256a31e0 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/.gitignore @@ -0,0 +1,20 @@ +# OSX leaves these everywhere on SMB shares +._* + +# Eclipse files +.classpath +.project +.settings/** + +# Emacs save files +*~ + +# Vim-related files +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +*.un~ +Session.vim +.netrwhist + +# Go test binaries +*.test diff --git a/vendor/github.com/ghodss/yaml/.travis.yml b/vendor/github.com/ghodss/yaml/.travis.yml new file mode 100644 index 000000000..0e9d6edc0 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: + - 1.3 + - 1.4 +script: + - go test + - go build diff --git a/vendor/github.com/ghodss/yaml/README.md b/vendor/github.com/ghodss/yaml/README.md new file mode 100644 index 000000000..0200f75b4 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/README.md @@ -0,0 +1,121 @@ +# YAML marshaling and unmarshaling support for Go + +[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml) + +## Introduction + +A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs. + +In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/). + +## Compatibility + +This package uses [go-yaml](https://github.com/go-yaml/yaml) and therefore supports [everything go-yaml supports](https://github.com/go-yaml/yaml#compatibility). + +## Caveats + +**Caveat #1:** When using `yaml.Marshal` and `yaml.Unmarshal`, binary data should NOT be preceded with the `!!binary` YAML tag. If you do, go-yaml will convert the binary data from base64 to native binary data, which is not compatible with JSON. You can still use binary in your YAML files though - just store them without the `!!binary` tag and decode the base64 in your code (e.g. in the custom JSON methods `MarshalJSON` and `UnmarshalJSON`). This also has the benefit that your YAML and your JSON binary data will be decoded exactly the same way. As an example: + +``` +BAD: + exampleKey: !!binary gIGC + +GOOD: + exampleKey: gIGC +... and decode the base64 data in your code. +``` + +**Caveat #2:** When using `YAMLToJSON` directly, maps with keys that are maps will result in an error since this is not supported by JSON. This error will occur in `Unmarshal` as well since you can't unmarshal map keys anyways since struct fields can't be keys. + +## Installation and usage + +To install, run: + +``` +$ go get github.com/ghodss/yaml +``` + +And import using: + +``` +import "github.com/ghodss/yaml" +``` + +Usage is very similar to the JSON library: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +type Person struct { + Name string `json:"name"` // Affects YAML field names too. + Age int `json:"age"` +} + +func main() { + // Marshal a Person struct to YAML. + p := Person{"John", 30} + y, err := yaml.Marshal(p) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + age: 30 + name: John + */ + + // Unmarshal the YAML back into a Person struct. + var p2 Person + err = yaml.Unmarshal(y, &p2) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(p2) + /* Output: + {John 30} + */ +} +``` + +`yaml.YAMLToJSON` and `yaml.JSONToYAML` methods are also available: + +```go +package main + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +func main() { + j := []byte(`{"name": "John", "age": 30}`) + y, err := yaml.JSONToYAML(j) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(y)) + /* Output: + name: John + age: 30 + */ + j2, err := yaml.YAMLToJSON(y) + if err != nil { + fmt.Printf("err: %v\n", err) + return + } + fmt.Println(string(j2)) + /* Output: + {"age":30,"name":"John"} + */ +} +``` diff --git a/vendor/github.com/ghodss/yaml/yaml_test.go b/vendor/github.com/ghodss/yaml/yaml_test.go new file mode 100644 index 000000000..505af4530 --- /dev/null +++ b/vendor/github.com/ghodss/yaml/yaml_test.go @@ -0,0 +1,287 @@ +package yaml + +import ( + "fmt" + "math" + "reflect" + "strconv" + "testing" +) + +type MarshalTest struct { + A string + B int64 + // Would like to test float64, but it's not supported in go-yaml. + // (See https://github.com/go-yaml/yaml/issues/83.) + C float32 +} + +func TestMarshal(t *testing.T) { + f32String := strconv.FormatFloat(math.MaxFloat32, 'g', -1, 32) + s := MarshalTest{"a", math.MaxInt64, math.MaxFloat32} + e := []byte(fmt.Sprintf("A: a\nB: %d\nC: %s\n", math.MaxInt64, f32String)) + + y, err := Marshal(s) + if err != nil { + t.Errorf("error marshaling YAML: %v", err) + } + + if !reflect.DeepEqual(y, e) { + t.Errorf("marshal YAML was unsuccessful, expected: %#v, got: %#v", + string(e), string(y)) + } +} + +type UnmarshalString struct { + A string + True string +} + +type UnmarshalStringMap struct { + A map[string]string +} + +type UnmarshalNestedString struct { + A NestedString +} + +type NestedString struct { + A string +} + +type UnmarshalSlice struct { + A []NestedSlice +} + +type NestedSlice struct { + B string + C *string +} + +func TestUnmarshal(t *testing.T) { + y := []byte("a: 1") + s1 := UnmarshalString{} + e1 := UnmarshalString{A: "1"} + unmarshal(t, y, &s1, &e1) + + y = []byte("a: true") + s1 = UnmarshalString{} + e1 = UnmarshalString{A: "true"} + unmarshal(t, y, &s1, &e1) + + y = []byte("true: 1") + s1 = UnmarshalString{} + e1 = UnmarshalString{True: "1"} + unmarshal(t, y, &s1, &e1) + + y = []byte("a:\n a: 1") + s2 := UnmarshalNestedString{} + e2 := UnmarshalNestedString{NestedString{"1"}} + unmarshal(t, y, &s2, &e2) + + y = []byte("a:\n - b: abc\n c: def\n - b: 123\n c: 456\n") + s3 := UnmarshalSlice{} + e3 := UnmarshalSlice{[]NestedSlice{NestedSlice{"abc", strPtr("def")}, NestedSlice{"123", strPtr("456")}}} + unmarshal(t, y, &s3, &e3) + + y = []byte("a:\n b: 1") + s4 := UnmarshalStringMap{} + e4 := UnmarshalStringMap{map[string]string{"b": "1"}} + unmarshal(t, y, &s4, &e4) + + y = []byte(` +a: + name: TestA +b: + name: TestB +`) + type NamedThing struct { + Name string `json:"name"` + } + s5 := map[string]*NamedThing{} + e5 := map[string]*NamedThing{ + "a": &NamedThing{Name: "TestA"}, + "b": &NamedThing{Name: "TestB"}, + } + unmarshal(t, y, &s5, &e5) +} + +func unmarshal(t *testing.T, y []byte, s, e interface{}) { + err := Unmarshal(y, s) + if err != nil { + t.Errorf("error unmarshaling YAML: %v", err) + } + + if !reflect.DeepEqual(s, e) { + t.Errorf("unmarshal YAML was unsuccessful, expected: %+#v, got: %+#v", + e, s) + } +} + +type Case struct { + input string + output string + // By default we test that reversing the output == input. But if there is a + // difference in the reversed output, you can optionally specify it here. + reverse *string +} + +type RunType int + +const ( + RunTypeJSONToYAML RunType = iota + RunTypeYAMLToJSON +) + +func TestJSONToYAML(t *testing.T) { + cases := []Case{ + { + `{"t":"a"}`, + "t: a\n", + nil, + }, { + `{"t":null}`, + "t: null\n", + nil, + }, + } + + runCases(t, RunTypeJSONToYAML, cases) +} + +func TestYAMLToJSON(t *testing.T) { + cases := []Case{ + { + "t: a\n", + `{"t":"a"}`, + nil, + }, { + "t: \n", + `{"t":null}`, + strPtr("t: null\n"), + }, { + "t: null\n", + `{"t":null}`, + nil, + }, { + "1: a\n", + `{"1":"a"}`, + strPtr("\"1\": a\n"), + }, { + "1000000000000000000000000000000000000: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "1e+36: a\n", + `{"1e+36":"a"}`, + strPtr("\"1e+36\": a\n"), + }, { + "\"1e+36\": a\n", + `{"1e+36":"a"}`, + nil, + }, { + "\"1.2\": a\n", + `{"1.2":"a"}`, + nil, + }, { + "- t: a\n", + `[{"t":"a"}]`, + nil, + }, { + "- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n", + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + nil, + }, { + `[{t: a}, {t: {b: 1, c: 2}}]`, + `[{"t":"a"},{"t":{"b":1,"c":2}}]`, + strPtr("- t: a\n" + + "- t:\n" + + " b: 1\n" + + " c: 2\n"), + }, { + "- t: \n", + `[{"t":null}]`, + strPtr("- t: null\n"), + }, { + "- t: null\n", + `[{"t":null}]`, + nil, + }, + } + + // Cases that should produce errors. + _ = []Case{ + { + "~: a", + `{"null":"a"}`, + nil, + }, { + "a: !!binary gIGC\n", + "{\"a\":\"\x80\x81\x82\"}", + nil, + }, + } + + runCases(t, RunTypeYAMLToJSON, cases) +} + +func runCases(t *testing.T, runType RunType, cases []Case) { + var f func([]byte) ([]byte, error) + var invF func([]byte) ([]byte, error) + var msg string + var invMsg string + if runType == RunTypeJSONToYAML { + f = JSONToYAML + invF = YAMLToJSON + msg = "JSON to YAML" + invMsg = "YAML back to JSON" + } else { + f = YAMLToJSON + invF = JSONToYAML + msg = "YAML to JSON" + invMsg = "JSON back to YAML" + } + + for _, c := range cases { + // Convert the string. + t.Logf("converting %s\n", c.input) + output, err := f([]byte(c.input)) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", msg, c.input, err) + } + + // Check it against the expected output. + if string(output) != c.output { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + msg, c.input, c.output, string(output)) + } + + // Set the string that we will compare the reversed output to. + reverse := c.input + // If a special reverse string was specified, use that instead. + if c.reverse != nil { + reverse = *c.reverse + } + + // Reverse the output. + input, err := invF(output) + if err != nil { + t.Errorf("Failed to convert %s, input: `%s`, err: %v", invMsg, string(output), err) + } + + // Check the reverse is equal to the input (or to *c.reverse). + if string(input) != reverse { + t.Errorf("Failed to convert %s, input: `%s`, expected `%s`, got `%s`", + invMsg, string(output), reverse, string(input)) + } + } + +} + +// To be able to easily fill in the *Case.reverse string above. +func strPtr(s string) *string { + return &s +} diff --git a/vendor/github.com/go-ini/ini/.gitignore b/vendor/github.com/go-ini/ini/.gitignore new file mode 100644 index 000000000..12411127b --- /dev/null +++ b/vendor/github.com/go-ini/ini/.gitignore @@ -0,0 +1,6 @@ +testdata/conf_out.ini +ini.sublime-project +ini.sublime-workspace +testdata/conf_reflect.ini +.idea +/.vscode diff --git a/vendor/github.com/go-ini/ini/.travis.yml b/vendor/github.com/go-ini/ini/.travis.yml new file mode 100644 index 000000000..75fe7b74b --- /dev/null +++ b/vendor/github.com/go-ini/ini/.travis.yml @@ -0,0 +1,16 @@ +sudo: false +language: go +go: + - 1.5.x + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + +script: + - go get golang.org/x/tools/cmd/cover + - go get github.com/smartystreets/goconvey + - mkdir -p $HOME/gopath/src/gopkg.in + - ln -s $HOME/gopath/src/github.com/go-ini/ini $HOME/gopath/src/gopkg.in/ini.v1 + - go test -v -cover -race diff --git a/vendor/github.com/go-ini/ini/Makefile b/vendor/github.com/go-ini/ini/Makefile new file mode 100644 index 000000000..af27ff076 --- /dev/null +++ b/vendor/github.com/go-ini/ini/Makefile @@ -0,0 +1,15 @@ +.PHONY: build test bench vet coverage + +build: vet bench + +test: + go test -v -cover -race + +bench: + go test -v -cover -race -test.bench=. -test.benchmem + +vet: + go vet + +coverage: + go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out diff --git a/vendor/github.com/go-ini/ini/README.md b/vendor/github.com/go-ini/ini/README.md new file mode 100644 index 000000000..95d920d6b --- /dev/null +++ b/vendor/github.com/go-ini/ini/README.md @@ -0,0 +1,44 @@ +INI [![Build Status](https://travis-ci.org/go-ini/ini.svg?branch=master)](https://travis-ci.org/go-ini/ini) [![Sourcegraph](https://sourcegraph.com/github.com/go-ini/ini/-/badge.svg)](https://sourcegraph.com/github.com/go-ini/ini?badge) +=== + +![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) + +Package ini provides INI file read and write functionality in Go. + +## Features + +- Load from multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites. +- Read with recursion values. +- Read with parent-child sections. +- Read with auto-increment key names. +- Read with multiple-line values. +- Read with tons of helper methods. +- Read and convert values to Go types. +- Read and **WRITE** comments of sections and keys. +- Manipulate sections, keys and comments with ease. +- Keep sections and keys in order as you parse and save. + +## Installation + +To use a tagged revision: + +```sh +$ go get gopkg.in/ini.v1 +``` + +To use with latest changes: + +```sh +$ go get github.com/go-ini/ini +``` + +Please add `-u` flag to update in the future. + +## Getting Help + +- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) +- [API Documentation](https://gowalker.org/gopkg.in/ini.v1) + +## License + +This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. diff --git a/vendor/github.com/go-ini/ini/bench_test.go b/vendor/github.com/go-ini/ini/bench_test.go new file mode 100644 index 000000000..fc1802469 --- /dev/null +++ b/vendor/github.com/go-ini/ini/bench_test.go @@ -0,0 +1,118 @@ +// Copyright 2017 Unknwon +// +// 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 ini_test + +import ( + "testing" + + "gopkg.in/ini.v1" +) + +func newTestFile(block bool) *ini.File { + c, _ := ini.Load([]byte(_CONF_DATA)) + c.BlockMode = block + return c +} + +func Benchmark_Key_Value(b *testing.B) { + c := newTestFile(true) + for i := 0; i < b.N; i++ { + c.Section("").Key("NAME").Value() + } +} + +func Benchmark_Key_Value_NonBlock(b *testing.B) { + c := newTestFile(false) + for i := 0; i < b.N; i++ { + c.Section("").Key("NAME").Value() + } +} + +func Benchmark_Key_Value_ViaSection(b *testing.B) { + c := newTestFile(true) + sec := c.Section("") + for i := 0; i < b.N; i++ { + sec.Key("NAME").Value() + } +} + +func Benchmark_Key_Value_ViaSection_NonBlock(b *testing.B) { + c := newTestFile(false) + sec := c.Section("") + for i := 0; i < b.N; i++ { + sec.Key("NAME").Value() + } +} + +func Benchmark_Key_Value_Direct(b *testing.B) { + c := newTestFile(true) + key := c.Section("").Key("NAME") + for i := 0; i < b.N; i++ { + key.Value() + } +} + +func Benchmark_Key_Value_Direct_NonBlock(b *testing.B) { + c := newTestFile(false) + key := c.Section("").Key("NAME") + for i := 0; i < b.N; i++ { + key.Value() + } +} + +func Benchmark_Key_String(b *testing.B) { + c := newTestFile(true) + for i := 0; i < b.N; i++ { + _ = c.Section("").Key("NAME").String() + } +} + +func Benchmark_Key_String_NonBlock(b *testing.B) { + c := newTestFile(false) + for i := 0; i < b.N; i++ { + _ = c.Section("").Key("NAME").String() + } +} + +func Benchmark_Key_String_ViaSection(b *testing.B) { + c := newTestFile(true) + sec := c.Section("") + for i := 0; i < b.N; i++ { + _ = sec.Key("NAME").String() + } +} + +func Benchmark_Key_String_ViaSection_NonBlock(b *testing.B) { + c := newTestFile(false) + sec := c.Section("") + for i := 0; i < b.N; i++ { + _ = sec.Key("NAME").String() + } +} + +func Benchmark_Key_SetValue(b *testing.B) { + c := newTestFile(true) + for i := 0; i < b.N; i++ { + c.Section("").Key("NAME").SetValue("10") + } +} + +func Benchmark_Key_SetValue_VisSection(b *testing.B) { + c := newTestFile(true) + sec := c.Section("") + for i := 0; i < b.N; i++ { + sec.Key("NAME").SetValue("10") + } +} diff --git a/vendor/github.com/go-ini/ini/file_test.go b/vendor/github.com/go-ini/ini/file_test.go new file mode 100644 index 000000000..2a0ca7c75 --- /dev/null +++ b/vendor/github.com/go-ini/ini/file_test.go @@ -0,0 +1,294 @@ +// Copyright 2017 Unknwon +// +// 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 ini_test + +import ( + "bytes" + "io/ioutil" + "testing" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/ini.v1" +) + +func TestEmpty(t *testing.T) { + Convey("Create an empty object", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + // Should only have the default section + So(len(f.Sections()), ShouldEqual, 1) + + // Default section should not contain any key + So(len(f.Section("").Keys()), ShouldBeZeroValue) + }) +} + +func TestFile_NewSection(t *testing.T) { + Convey("Create a new section", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + sec, err := f.NewSection("author") + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + So(sec.Name(), ShouldEqual, "author") + + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author"}) + + Convey("With duplicated name", func() { + sec, err := f.NewSection("author") + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + + // Does nothing if section already exists + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author"}) + }) + + Convey("With empty string", func() { + _, err := f.NewSection("") + So(err, ShouldNotBeNil) + }) + }) +} + +func TestFile_NewRawSection(t *testing.T) { + Convey("Create a new raw section", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000`) + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + So(sec.Name(), ShouldEqual, "comments") + + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "comments"}) + So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000`) + + Convey("With duplicated name", func() { + sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000`) + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "comments"}) + + // Overwrite previous existed section + So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000`) + }) + + Convey("With empty string", func() { + _, err := f.NewRawSection("", "") + So(err, ShouldNotBeNil) + }) + }) +} + +func TestFile_NewSections(t *testing.T) { + Convey("Create new sections", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + So(f.NewSections("package", "author"), ShouldBeNil) + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "package", "author"}) + + Convey("With duplicated name", func() { + So(f.NewSections("author", "features"), ShouldBeNil) + + // Ignore section already exists + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "package", "author", "features"}) + }) + + Convey("With empty string", func() { + So(f.NewSections("", ""), ShouldNotBeNil) + }) + }) +} + +func TestFile_GetSection(t *testing.T) { + Convey("Get a section", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + sec, err := f.GetSection("author") + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + So(sec.Name(), ShouldEqual, "author") + + Convey("Section not exists", func() { + _, err := f.GetSection("404") + So(err, ShouldNotBeNil) + }) + }) +} + +func TestFile_Section(t *testing.T) { + Convey("Get a section", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + sec := f.Section("author") + So(sec, ShouldNotBeNil) + So(sec.Name(), ShouldEqual, "author") + + Convey("Section not exists", func() { + sec := f.Section("404") + So(sec, ShouldNotBeNil) + So(sec.Name(), ShouldEqual, "404") + }) + }) + + Convey("Get default section in lower case with insensitive load", t, func() { + f, err := ini.InsensitiveLoad([]byte(` +[default] +NAME = ini +VERSION = v1`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("name").String(), ShouldEqual, "ini") + So(f.Section("").Key("version").String(), ShouldEqual, "v1") + }) +} + +func TestFile_Sections(t *testing.T) { + Convey("Get all sections", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + secs := f.Sections() + names := []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"} + So(len(secs), ShouldEqual, len(names)) + for i, name := range names { + So(secs[i].Name(), ShouldEqual, name) + } + }) +} + +func TestFile_ChildSections(t *testing.T) { + Convey("Get child sections by parent name", t, func() { + f, err := ini.Load([]byte(` +[node] +[node.biz1] +[node.biz2] +[node.biz3] +[node.bizN] +`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + children := f.ChildSections("node") + names := []string{"node.biz1", "node.biz2", "node.biz3", "node.bizN"} + So(len(children), ShouldEqual, len(names)) + for i, name := range names { + So(children[i].Name(), ShouldEqual, name) + } + }) +} + +func TestFile_SectionStrings(t *testing.T) { + Convey("Get all section names", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"}) + }) +} + +func TestFile_DeleteSection(t *testing.T) { + Convey("Delete a section", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + f.NewSections("author", "package", "features") + f.DeleteSection("features") + f.DeleteSection("") + So(f.SectionStrings(), ShouldResemble, []string{"author", "package"}) + }) +} + +func TestFile_Append(t *testing.T) { + Convey("Append a data source", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + So(f.Append(_MINIMAL_CONF, []byte(` +[author] +NAME = Unknwon`)), ShouldBeNil) + + Convey("With bad input", func() { + So(f.Append(123), ShouldNotBeNil) + So(f.Append(_MINIMAL_CONF, 123), ShouldNotBeNil) + }) + }) +} + +func TestFile_WriteTo(t *testing.T) { + Convey("Write content to somewhere", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + f.Section("author").Comment = `Information about package author +# Bio can be written in multiple lines.` + f.Section("author").Key("NAME").Comment = "This is author name" + f.Section("note").NewBooleanKey("boolean_key") + f.Section("note").NewKey("more", "notes") + + var buf bytes.Buffer + _, err = f.WriteTo(&buf) + So(err, ShouldBeNil) + + golden := "testdata/TestFile_WriteTo.golden" + if *update { + ioutil.WriteFile(golden, buf.Bytes(), 0644) + } + + expected, err := ioutil.ReadFile(golden) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, string(expected)) + }) + + Convey("Support multiline comments", t, func() { + f := ini.Empty() + f.Section("").Key("test").Comment = "Multiline\nComment" + + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + + So(buf.String(), ShouldEqual, `; Multiline +; Comment +test = + +`) + + }) +} + +func TestFile_SaveTo(t *testing.T) { + Convey("Write content to somewhere", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.SaveTo("testdata/conf_out.ini"), ShouldBeNil) + So(f.SaveToIndent("testdata/conf_out.ini", "\t"), ShouldBeNil) + }) +} diff --git a/vendor/github.com/go-ini/ini/ini_internal_test.go b/vendor/github.com/go-ini/ini/ini_internal_test.go new file mode 100644 index 000000000..257ef1ebb --- /dev/null +++ b/vendor/github.com/go-ini/ini/ini_internal_test.go @@ -0,0 +1,35 @@ +// Copyright 2017 Unknwon +// +// 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 ini + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func Test_Version(t *testing.T) { + Convey("Get version", t, func() { + So(Version(), ShouldEqual, _VERSION) + }) +} + +func Test_isSlice(t *testing.T) { + Convey("Check if a string is in the slice", t, func() { + ss := []string{"a", "b", "c"} + So(inSlice("a", ss), ShouldBeTrue) + So(inSlice("d", ss), ShouldBeFalse) + }) +} diff --git a/vendor/github.com/go-ini/ini/ini_test.go b/vendor/github.com/go-ini/ini/ini_test.go new file mode 100644 index 000000000..6b764018a --- /dev/null +++ b/vendor/github.com/go-ini/ini/ini_test.go @@ -0,0 +1,1114 @@ +// Copyright 2014 Unknwon +// +// 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 ini_test + +import ( + "bytes" + "flag" + "io/ioutil" + "testing" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/ini.v1" +) + +const ( + _CONF_DATA = ` + ; Package name + NAME = ini + ; Package version + VERSION = v1 + ; Package import path + IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s + + # Information about package author + # Bio can be written in multiple lines. + [author] + NAME = Unknwon ; Succeeding comment + E-MAIL = fake@localhost + GITHUB = https://github.com/%(NAME)s + BIO = """Gopher. + Coding addict. + Good man. + """ # Succeeding comment` + _MINIMAL_CONF = "testdata/minimal.ini" + _FULL_CONF = "testdata/full.ini" + _NOT_FOUND_CONF = "testdata/404.ini" +) + +var update = flag.Bool("update", false, "Update .golden files") + +func TestLoad(t *testing.T) { + Convey("Load from good data sources", t, func() { + f, err := ini.Load([]byte(` +NAME = ini +VERSION = v1 +IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s`), + "testdata/minimal.ini", + ioutil.NopCloser(bytes.NewReader([]byte(` +[author] +NAME = Unknwon +`))), + ) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + // Vaildate values make sure all sources are loaded correctly + sec := f.Section("") + So(sec.Key("NAME").String(), ShouldEqual, "ini") + So(sec.Key("VERSION").String(), ShouldEqual, "v1") + So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1") + + sec = f.Section("author") + So(sec.Key("NAME").String(), ShouldEqual, "Unknwon") + So(sec.Key("E-MAIL").String(), ShouldEqual, "u@gogs.io") + }) + + Convey("Load from bad data sources", t, func() { + Convey("Invalid input", func() { + _, err := ini.Load(_NOT_FOUND_CONF) + So(err, ShouldNotBeNil) + }) + + Convey("Unsupported type", func() { + _, err := ini.Load(123) + So(err, ShouldNotBeNil) + }) + }) + + Convey("Cant't parse small python-compatible INI files", t, func() { + f, err := ini.Load([]byte(` +[long] +long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- + foo + bar + foobar + barfoo + -----END RSA PRIVATE KEY----- +`)) + So(err, ShouldNotBeNil) + So(f, ShouldBeNil) + So(err.Error(), ShouldEqual, "key-value delimiter not found: foo\n") + }) + + Convey("Cant't parse big python-compatible INI files", t, func() { + f, err := ini.Load([]byte(` +[long] +long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- + 1foo + 2bar + 3foobar + 4barfoo + 5foo + 6bar + 7foobar + 8barfoo + 9foo + 10bar + 11foobar + 12barfoo + 13foo + 14bar + 15foobar + 16barfoo + 17foo + 18bar + 19foobar + 20barfoo + 21foo + 22bar + 23foobar + 24barfoo + 25foo + 26bar + 27foobar + 28barfoo + 29foo + 30bar + 31foobar + 32barfoo + 33foo + 34bar + 35foobar + 36barfoo + 37foo + 38bar + 39foobar + 40barfoo + 41foo + 42bar + 43foobar + 44barfoo + 45foo + 46bar + 47foobar + 48barfoo + 49foo + 50bar + 51foobar + 52barfoo + 53foo + 54bar + 55foobar + 56barfoo + 57foo + 58bar + 59foobar + 60barfoo + 61foo + 62bar + 63foobar + 64barfoo + 65foo + 66bar + 67foobar + 68barfoo + 69foo + 70bar + 71foobar + 72barfoo + 73foo + 74bar + 75foobar + 76barfoo + 77foo + 78bar + 79foobar + 80barfoo + 81foo + 82bar + 83foobar + 84barfoo + 85foo + 86bar + 87foobar + 88barfoo + 89foo + 90bar + 91foobar + 92barfoo + 93foo + 94bar + 95foobar + 96barfoo + -----END RSA PRIVATE KEY----- +`)) + So(err, ShouldNotBeNil) + So(f, ShouldBeNil) + So(err.Error(), ShouldEqual, "key-value delimiter not found: 1foo\n") + }) +} + +func TestLooseLoad(t *testing.T) { + Convey("Load from data sources with option `Loose` true", t, func() { + f, err := ini.LoadSources(ini.LoadOptions{Loose: true}, _NOT_FOUND_CONF, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + Convey("Inverse case", func() { + _, err = ini.Load(_NOT_FOUND_CONF) + So(err, ShouldNotBeNil) + }) + }) +} + +func TestInsensitiveLoad(t *testing.T) { + Convey("Insensitive to section and key names", t, func() { + f, err := ini.InsensitiveLoad(_MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io") + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `[author] +e-mail = u@gogs.io + +`) + }) + + Convey("Inverse case", func() { + f, err := ini.Load(_MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty) + }) + }) +} + +func TestLoadSources(t *testing.T) { + Convey("Load from data sources with options", t, func() { + Convey("with true `AllowPythonMultilineValues`", func() { + Convey("Ignore nonexistent files", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true, Loose: true}, _NOT_FOUND_CONF, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + Convey("Inverse case", func() { + _, err = ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, _NOT_FOUND_CONF) + So(err, ShouldNotBeNil) + }) + }) + + Convey("Insensitive to section and key names", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true, Insensitive: true}, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io") + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `[author] +e-mail = u@gogs.io + +`) + }) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty) + }) + }) + + Convey("Ignore continuation lines", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + IgnoreContinuation: true, + }, []byte(` +key1=a\b\ +key2=c\d\ +key3=value`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `a\b\`) + So(f.Section("").Key("key2").String(), ShouldEqual, `c\d\`) + So(f.Section("").Key("key3").String(), ShouldEqual, "value") + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(` +key1=a\b\ +key2=c\d\`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `a\bkey2=c\d`) + }) + }) + + Convey("Ignore inline comments", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + IgnoreInlineComment: true, + }, []byte(` +key1=value ;comment +key2=value2 #comment2`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `value ;comment`) + So(f.Section("").Key("key2").String(), ShouldEqual, `value2 #comment2`) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(` +key1=value ;comment +key2=value2 #comment2`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `value`) + So(f.Section("").Key("key1").Comment, ShouldEqual, `;comment`) + So(f.Section("").Key("key2").String(), ShouldEqual, `value2`) + So(f.Section("").Key("key2").Comment, ShouldEqual, `#comment2`) + }) + }) + + Convey("Allow boolean type keys", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + AllowBooleanKeys: true, + }, []byte(` +key1=hello +#key2 +key3`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").KeyStrings(), ShouldResemble, []string{"key1", "key3"}) + So(f.Section("").Key("key3").MustBool(false), ShouldBeTrue) + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `key1 = hello +# key2 +key3 +`) + }) + + Convey("Inverse case", func() { + _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(` +key1=hello +#key2 +key3`)) + So(err, ShouldNotBeNil) + }) + }) + + Convey("Allow shadow keys", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowShadows: true, AllowPythonMultilineValues: true}, []byte(` +[remote "origin"] +url = https://github.com/Antergone/test1.git +url = https://github.com/Antergone/test2.git +fetch = +refs/heads/*:refs/remotes/origin/*`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git") + So(f.Section(`remote "origin"`).Key("url").ValueWithShadows(), ShouldResemble, []string{ + "https://github.com/Antergone/test1.git", + "https://github.com/Antergone/test2.git", + }) + So(f.Section(`remote "origin"`).Key("fetch").String(), ShouldEqual, "+refs/heads/*:refs/remotes/origin/*") + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `[remote "origin"] +url = https://github.com/Antergone/test1.git +url = https://github.com/Antergone/test2.git +fetch = +refs/heads/*:refs/remotes/origin/* + +`) + }) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(` +[remote "origin"] +url = https://github.com/Antergone/test1.git +url = https://github.com/Antergone/test2.git`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git") + }) + }) + + Convey("Unescape double quotes inside value", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + UnescapeValueDoubleQuotes: true, + }, []byte(` +create_repo="创建了仓库 %s"`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("create_repo").String(), ShouldEqual, `创建了仓库 %s`) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(` +create_repo="创建了仓库 %s"`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("create_repo").String(), ShouldEqual, `"创建了仓库 %s"`) + }) + }) + + Convey("Unescape comment symbols inside value", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + IgnoreInlineComment: true, + UnescapeValueCommentSymbols: true, + }, []byte(` +key = test value more text +`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key").String(), ShouldEqual, `test value more text`) + }) + + Convey("Can parse small python-compatible INI files", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + Insensitive: true, + UnparseableSections: []string{"core_lesson", "comments"}, + }, []byte(` +[long] +long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- + foo + bar + foobar + barfoo + -----END RSA PRIVATE KEY----- +`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("long").Key("long_rsa_private_key").String(), ShouldEqual, "-----BEGIN RSA PRIVATE KEY-----\nfoo\nbar\nfoobar\nbarfoo\n-----END RSA PRIVATE KEY-----") + }) + + Convey("Can parse big python-compatible INI files", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + Insensitive: true, + UnparseableSections: []string{"core_lesson", "comments"}, + }, []byte(` +[long] +long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- + 1foo + 2bar + 3foobar + 4barfoo + 5foo + 6bar + 7foobar + 8barfoo + 9foo + 10bar + 11foobar + 12barfoo + 13foo + 14bar + 15foobar + 16barfoo + 17foo + 18bar + 19foobar + 20barfoo + 21foo + 22bar + 23foobar + 24barfoo + 25foo + 26bar + 27foobar + 28barfoo + 29foo + 30bar + 31foobar + 32barfoo + 33foo + 34bar + 35foobar + 36barfoo + 37foo + 38bar + 39foobar + 40barfoo + 41foo + 42bar + 43foobar + 44barfoo + 45foo + 46bar + 47foobar + 48barfoo + 49foo + 50bar + 51foobar + 52barfoo + 53foo + 54bar + 55foobar + 56barfoo + 57foo + 58bar + 59foobar + 60barfoo + 61foo + 62bar + 63foobar + 64barfoo + 65foo + 66bar + 67foobar + 68barfoo + 69foo + 70bar + 71foobar + 72barfoo + 73foo + 74bar + 75foobar + 76barfoo + 77foo + 78bar + 79foobar + 80barfoo + 81foo + 82bar + 83foobar + 84barfoo + 85foo + 86bar + 87foobar + 88barfoo + 89foo + 90bar + 91foobar + 92barfoo + 93foo + 94bar + 95foobar + 96barfoo + -----END RSA PRIVATE KEY----- +`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("long").Key("long_rsa_private_key").String(), ShouldEqual, `-----BEGIN RSA PRIVATE KEY----- +1foo +2bar +3foobar +4barfoo +5foo +6bar +7foobar +8barfoo +9foo +10bar +11foobar +12barfoo +13foo +14bar +15foobar +16barfoo +17foo +18bar +19foobar +20barfoo +21foo +22bar +23foobar +24barfoo +25foo +26bar +27foobar +28barfoo +29foo +30bar +31foobar +32barfoo +33foo +34bar +35foobar +36barfoo +37foo +38bar +39foobar +40barfoo +41foo +42bar +43foobar +44barfoo +45foo +46bar +47foobar +48barfoo +49foo +50bar +51foobar +52barfoo +53foo +54bar +55foobar +56barfoo +57foo +58bar +59foobar +60barfoo +61foo +62bar +63foobar +64barfoo +65foo +66bar +67foobar +68barfoo +69foo +70bar +71foobar +72barfoo +73foo +74bar +75foobar +76barfoo +77foo +78bar +79foobar +80barfoo +81foo +82bar +83foobar +84barfoo +85foo +86bar +87foobar +88barfoo +89foo +90bar +91foobar +92barfoo +93foo +94bar +95foobar +96barfoo +-----END RSA PRIVATE KEY-----`) + }) + + Convey("Allow unparsable sections", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: true, + Insensitive: true, + UnparseableSections: []string{"core_lesson", "comments"}, + }, []byte(` +Lesson_Location = 87 +Lesson_Status = C +Score = 3 +Time = 00:02:30 + +[CORE_LESSON] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data + +[COMMENTS] +<1> This slide has the fuel listed in the wrong units `)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("score").String(), ShouldEqual, "3") + So(f.Section("").Body(), ShouldBeEmpty) + So(f.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data`) + So(f.Section("comments").Body(), ShouldEqual, `<1> This slide has the fuel listed in the wrong units `) + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `lesson_location = 87 +lesson_status = C +score = 3 +time = 00:02:30 + +[core_lesson] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data + +[comments] +<1> This slide has the fuel listed in the wrong units +`) + }) + + Convey("Inverse case", func() { + _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(` +[CORE_LESSON] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data`)) + So(err, ShouldNotBeNil) + }) + }) + }) + + Convey("with false `AllowPythonMultilineValues`", func() { + Convey("Ignore nonexistent files", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false, Loose: true}, _NOT_FOUND_CONF, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + Convey("Inverse case", func() { + _, err = ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, _NOT_FOUND_CONF) + So(err, ShouldNotBeNil) + }) + }) + + Convey("Insensitive to section and key names", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false, Insensitive: true}, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io") + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `[author] +e-mail = u@gogs.io + +`) + }) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, _MINIMAL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty) + }) + }) + + Convey("Ignore continuation lines", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: false, + IgnoreContinuation: true, + }, []byte(` +key1=a\b\ +key2=c\d\ +key3=value`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `a\b\`) + So(f.Section("").Key("key2").String(), ShouldEqual, `c\d\`) + So(f.Section("").Key("key3").String(), ShouldEqual, "value") + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +key1=a\b\ +key2=c\d\`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `a\bkey2=c\d`) + }) + }) + + Convey("Ignore inline comments", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: false, + IgnoreInlineComment: true, + }, []byte(` +key1=value ;comment +key2=value2 #comment2`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `value ;comment`) + So(f.Section("").Key("key2").String(), ShouldEqual, `value2 #comment2`) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +key1=value ;comment +key2=value2 #comment2`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key1").String(), ShouldEqual, `value`) + So(f.Section("").Key("key1").Comment, ShouldEqual, `;comment`) + So(f.Section("").Key("key2").String(), ShouldEqual, `value2`) + So(f.Section("").Key("key2").Comment, ShouldEqual, `#comment2`) + }) + }) + + Convey("Allow boolean type keys", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: false, + AllowBooleanKeys: true, + }, []byte(` +key1=hello +#key2 +key3`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").KeyStrings(), ShouldResemble, []string{"key1", "key3"}) + So(f.Section("").Key("key3").MustBool(false), ShouldBeTrue) + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `key1 = hello +# key2 +key3 +`) + }) + + Convey("Inverse case", func() { + _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +key1=hello +#key2 +key3`)) + So(err, ShouldNotBeNil) + }) + }) + + Convey("Allow shadow keys", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false, AllowShadows: true}, []byte(` +[remote "origin"] +url = https://github.com/Antergone/test1.git +url = https://github.com/Antergone/test2.git +fetch = +refs/heads/*:refs/remotes/origin/*`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git") + So(f.Section(`remote "origin"`).Key("url").ValueWithShadows(), ShouldResemble, []string{ + "https://github.com/Antergone/test1.git", + "https://github.com/Antergone/test2.git", + }) + So(f.Section(`remote "origin"`).Key("fetch").String(), ShouldEqual, "+refs/heads/*:refs/remotes/origin/*") + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `[remote "origin"] +url = https://github.com/Antergone/test1.git +url = https://github.com/Antergone/test2.git +fetch = +refs/heads/*:refs/remotes/origin/* + +`) + }) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +[remote "origin"] +url = https://github.com/Antergone/test1.git +url = https://github.com/Antergone/test2.git`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git") + }) + }) + + Convey("Unescape double quotes inside value", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: false, + UnescapeValueDoubleQuotes: true, + }, []byte(` +create_repo="创建了仓库 %s"`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("create_repo").String(), ShouldEqual, `创建了仓库 %s`) + + Convey("Inverse case", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +create_repo="创建了仓库 %s"`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("create_repo").String(), ShouldEqual, `"创建了仓库 %s"`) + }) + }) + + Convey("Unescape comment symbols inside value", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: false, + IgnoreInlineComment: true, + UnescapeValueCommentSymbols: true, + }, []byte(` +key = test value more text +`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("key").String(), ShouldEqual, `test value more text`) + }) + + Convey("Cant't parse small python-compatible INI files", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +[long] +long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- + foo + bar + foobar + barfoo + -----END RSA PRIVATE KEY----- +`)) + So(err, ShouldNotBeNil) + So(f, ShouldBeNil) + So(err.Error(), ShouldEqual, "key-value delimiter not found: foo\n") + }) + + Convey("Cant't parse big python-compatible INI files", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +[long] +long_rsa_private_key = -----BEGIN RSA PRIVATE KEY----- + 1foo + 2bar + 3foobar + 4barfoo + 5foo + 6bar + 7foobar + 8barfoo + 9foo + 10bar + 11foobar + 12barfoo + 13foo + 14bar + 15foobar + 16barfoo + 17foo + 18bar + 19foobar + 20barfoo + 21foo + 22bar + 23foobar + 24barfoo + 25foo + 26bar + 27foobar + 28barfoo + 29foo + 30bar + 31foobar + 32barfoo + 33foo + 34bar + 35foobar + 36barfoo + 37foo + 38bar + 39foobar + 40barfoo + 41foo + 42bar + 43foobar + 44barfoo + 45foo + 46bar + 47foobar + 48barfoo + 49foo + 50bar + 51foobar + 52barfoo + 53foo + 54bar + 55foobar + 56barfoo + 57foo + 58bar + 59foobar + 60barfoo + 61foo + 62bar + 63foobar + 64barfoo + 65foo + 66bar + 67foobar + 68barfoo + 69foo + 70bar + 71foobar + 72barfoo + 73foo + 74bar + 75foobar + 76barfoo + 77foo + 78bar + 79foobar + 80barfoo + 81foo + 82bar + 83foobar + 84barfoo + 85foo + 86bar + 87foobar + 88barfoo + 89foo + 90bar + 91foobar + 92barfoo + 93foo + 94bar + 95foobar + 96barfoo + -----END RSA PRIVATE KEY----- +`)) + So(err, ShouldNotBeNil) + So(f, ShouldBeNil) + So(err.Error(), ShouldEqual, "key-value delimiter not found: 1foo\n") + }) + + Convey("Allow unparsable sections", func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowPythonMultilineValues: false, + Insensitive: true, + UnparseableSections: []string{"core_lesson", "comments"}, + }, []byte(` +Lesson_Location = 87 +Lesson_Status = C +Score = 3 +Time = 00:02:30 + +[CORE_LESSON] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data + +[COMMENTS] +<1> This slide has the fuel listed in the wrong units `)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("score").String(), ShouldEqual, "3") + So(f.Section("").Body(), ShouldBeEmpty) + So(f.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data`) + So(f.Section("comments").Body(), ShouldEqual, `<1> This slide has the fuel listed in the wrong units `) + + Convey("Write out", func() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `lesson_location = 87 +lesson_status = C +score = 3 +time = 00:02:30 + +[core_lesson] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data + +[comments] +<1> This slide has the fuel listed in the wrong units +`) + }) + + Convey("Inverse case", func() { + _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(` +[CORE_LESSON] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data`)) + So(err, ShouldNotBeNil) + }) + }) + }) + }) +} diff --git a/vendor/github.com/go-ini/ini/key_test.go b/vendor/github.com/go-ini/ini/key_test.go new file mode 100644 index 000000000..a13ad95fa --- /dev/null +++ b/vendor/github.com/go-ini/ini/key_test.go @@ -0,0 +1,523 @@ +// Copyright 2014 Unknwon +// +// 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 ini_test + +import ( + "bytes" + "fmt" + "strings" + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/ini.v1" +) + +func TestKey_AddShadow(t *testing.T) { + Convey("Add shadow to a key", t, func() { + f, err := ini.ShadowLoad([]byte(` +[notes] +-: note1`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(k.AddShadow("ini.v1"), ShouldBeNil) + So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"}) + + Convey("Add shadow to boolean key", func() { + k, err := f.Section("").NewBooleanKey("published") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + So(k.AddShadow("beta"), ShouldNotBeNil) + }) + + Convey("Add shadow to auto-increment key", func() { + So(f.Section("notes").Key("#1").AddShadow("beta"), ShouldNotBeNil) + }) + }) + + Convey("Shadow is not allowed", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(k.AddShadow("ini.v1"), ShouldNotBeNil) + }) +} + +// Helpers for slice tests. +func float64sEqual(values []float64, expected ...float64) { + So(values, ShouldHaveLength, len(expected)) + for i, v := range expected { + So(values[i], ShouldEqual, v) + } +} + +func intsEqual(values []int, expected ...int) { + So(values, ShouldHaveLength, len(expected)) + for i, v := range expected { + So(values[i], ShouldEqual, v) + } +} + +func int64sEqual(values []int64, expected ...int64) { + So(values, ShouldHaveLength, len(expected)) + for i, v := range expected { + So(values[i], ShouldEqual, v) + } +} + +func uintsEqual(values []uint, expected ...uint) { + So(values, ShouldHaveLength, len(expected)) + for i, v := range expected { + So(values[i], ShouldEqual, v) + } +} + +func uint64sEqual(values []uint64, expected ...uint64) { + So(values, ShouldHaveLength, len(expected)) + for i, v := range expected { + So(values[i], ShouldEqual, v) + } +} + +func timesEqual(values []time.Time, expected ...time.Time) { + So(values, ShouldHaveLength, len(expected)) + for i, v := range expected { + So(values[i].String(), ShouldEqual, v.String()) + } +} + +func TestKey_Helpers(t *testing.T) { + Convey("Getting and setting values", t, func() { + f, err := ini.Load(_FULL_CONF) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + Convey("Get string representation", func() { + sec := f.Section("") + So(sec, ShouldNotBeNil) + So(sec.Key("NAME").Value(), ShouldEqual, "ini") + So(sec.Key("NAME").String(), ShouldEqual, "ini") + So(sec.Key("NAME").Validate(func(in string) string { + return in + }), ShouldEqual, "ini") + So(sec.Key("NAME").Comment, ShouldEqual, "; Package name") + So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1") + + Convey("With ValueMapper", func() { + f.ValueMapper = func(in string) string { + if in == "gopkg.in/%(NAME)s.%(VERSION)s" { + return "github.com/go-ini/ini" + } + return in + } + So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "github.com/go-ini/ini") + }) + }) + + Convey("Get values in non-default section", func() { + sec := f.Section("author") + So(sec, ShouldNotBeNil) + So(sec.Key("NAME").String(), ShouldEqual, "Unknwon") + So(sec.Key("GITHUB").String(), ShouldEqual, "https://github.com/Unknwon") + + sec = f.Section("package") + So(sec, ShouldNotBeNil) + So(sec.Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1") + }) + + Convey("Get auto-increment key names", func() { + keys := f.Section("features").Keys() + for i, k := range keys { + So(k.Name(), ShouldEqual, fmt.Sprintf("#%d", i+1)) + } + }) + + Convey("Get parent-keys that are available to the child section", func() { + parentKeys := f.Section("package.sub").ParentKeys() + for _, k := range parentKeys { + So(k.Name(), ShouldEqual, "CLONE_URL") + } + }) + + Convey("Get overwrite value", func() { + So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io") + }) + + Convey("Get sections", func() { + sections := f.Sections() + for i, name := range []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"} { + So(sections[i].Name(), ShouldEqual, name) + } + }) + + Convey("Get parent section value", func() { + So(f.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1") + So(f.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1") + }) + + Convey("Get multiple line value", func() { + So(f.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n") + }) + + Convey("Get values with type", func() { + sec := f.Section("types") + v1, err := sec.Key("BOOL").Bool() + So(err, ShouldBeNil) + So(v1, ShouldBeTrue) + + v1, err = sec.Key("BOOL_FALSE").Bool() + So(err, ShouldBeNil) + So(v1, ShouldBeFalse) + + v2, err := sec.Key("FLOAT64").Float64() + So(err, ShouldBeNil) + So(v2, ShouldEqual, 1.25) + + v3, err := sec.Key("INT").Int() + So(err, ShouldBeNil) + So(v3, ShouldEqual, 10) + + v4, err := sec.Key("INT").Int64() + So(err, ShouldBeNil) + So(v4, ShouldEqual, 10) + + v5, err := sec.Key("UINT").Uint() + So(err, ShouldBeNil) + So(v5, ShouldEqual, 3) + + v6, err := sec.Key("UINT").Uint64() + So(err, ShouldBeNil) + So(v6, ShouldEqual, 3) + + t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z") + So(err, ShouldBeNil) + v7, err := sec.Key("TIME").Time() + So(err, ShouldBeNil) + So(v7.String(), ShouldEqual, t.String()) + + Convey("Must get values with type", func() { + So(sec.Key("STRING").MustString("404"), ShouldEqual, "str") + So(sec.Key("BOOL").MustBool(), ShouldBeTrue) + So(sec.Key("FLOAT64").MustFloat64(), ShouldEqual, 1.25) + So(sec.Key("INT").MustInt(), ShouldEqual, 10) + So(sec.Key("INT").MustInt64(), ShouldEqual, 10) + So(sec.Key("UINT").MustUint(), ShouldEqual, 3) + So(sec.Key("UINT").MustUint64(), ShouldEqual, 3) + So(sec.Key("TIME").MustTime().String(), ShouldEqual, t.String()) + + dur, err := time.ParseDuration("2h45m") + So(err, ShouldBeNil) + So(sec.Key("DURATION").MustDuration().Seconds(), ShouldEqual, dur.Seconds()) + + Convey("Must get values with default value", func() { + So(sec.Key("STRING_404").MustString("404"), ShouldEqual, "404") + So(sec.Key("BOOL_404").MustBool(true), ShouldBeTrue) + So(sec.Key("FLOAT64_404").MustFloat64(2.5), ShouldEqual, 2.5) + So(sec.Key("INT_404").MustInt(15), ShouldEqual, 15) + So(sec.Key("INT64_404").MustInt64(15), ShouldEqual, 15) + So(sec.Key("UINT_404").MustUint(6), ShouldEqual, 6) + So(sec.Key("UINT64_404").MustUint64(6), ShouldEqual, 6) + + t, err := time.Parse(time.RFC3339, "2014-01-01T20:17:05Z") + So(err, ShouldBeNil) + So(sec.Key("TIME_404").MustTime(t).String(), ShouldEqual, t.String()) + + So(sec.Key("DURATION_404").MustDuration(dur).Seconds(), ShouldEqual, dur.Seconds()) + + Convey("Must should set default as key value", func() { + So(sec.Key("STRING_404").String(), ShouldEqual, "404") + So(sec.Key("BOOL_404").String(), ShouldEqual, "true") + So(sec.Key("FLOAT64_404").String(), ShouldEqual, "2.5") + So(sec.Key("INT_404").String(), ShouldEqual, "15") + So(sec.Key("INT64_404").String(), ShouldEqual, "15") + So(sec.Key("UINT_404").String(), ShouldEqual, "6") + So(sec.Key("UINT64_404").String(), ShouldEqual, "6") + So(sec.Key("TIME_404").String(), ShouldEqual, "2014-01-01T20:17:05Z") + So(sec.Key("DURATION_404").String(), ShouldEqual, "2h45m0s") + }) + }) + }) + }) + + Convey("Get value with candidates", func() { + sec := f.Section("types") + So(sec.Key("STRING").In("", []string{"str", "arr", "types"}), ShouldEqual, "str") + So(sec.Key("FLOAT64").InFloat64(0, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25) + So(sec.Key("INT").InInt(0, []int{10, 20, 30}), ShouldEqual, 10) + So(sec.Key("INT").InInt64(0, []int64{10, 20, 30}), ShouldEqual, 10) + So(sec.Key("UINT").InUint(0, []uint{3, 6, 9}), ShouldEqual, 3) + So(sec.Key("UINT").InUint64(0, []uint64{3, 6, 9}), ShouldEqual, 3) + + zt, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z") + So(err, ShouldBeNil) + t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z") + So(err, ShouldBeNil) + So(sec.Key("TIME").InTime(zt, []time.Time{t, time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String()) + + Convey("Get value with candidates and default value", func() { + So(sec.Key("STRING_404").In("str", []string{"str", "arr", "types"}), ShouldEqual, "str") + So(sec.Key("FLOAT64_404").InFloat64(1.25, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25) + So(sec.Key("INT_404").InInt(10, []int{10, 20, 30}), ShouldEqual, 10) + So(sec.Key("INT64_404").InInt64(10, []int64{10, 20, 30}), ShouldEqual, 10) + So(sec.Key("UINT_404").InUint(3, []uint{3, 6, 9}), ShouldEqual, 3) + So(sec.Key("UINT_404").InUint64(3, []uint64{3, 6, 9}), ShouldEqual, 3) + So(sec.Key("TIME_404").InTime(t, []time.Time{time.Now(), time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String()) + }) + }) + + Convey("Get values in range", func() { + sec := f.Section("types") + So(sec.Key("FLOAT64").RangeFloat64(0, 1, 2), ShouldEqual, 1.25) + So(sec.Key("INT").RangeInt(0, 10, 20), ShouldEqual, 10) + So(sec.Key("INT").RangeInt64(0, 10, 20), ShouldEqual, 10) + + minT, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z") + So(err, ShouldBeNil) + midT, err := time.Parse(time.RFC3339, "2013-01-01T01:00:00Z") + So(err, ShouldBeNil) + maxT, err := time.Parse(time.RFC3339, "9999-01-01T01:00:00Z") + So(err, ShouldBeNil) + t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z") + So(err, ShouldBeNil) + So(sec.Key("TIME").RangeTime(t, minT, maxT).String(), ShouldEqual, t.String()) + + Convey("Get value in range with default value", func() { + So(sec.Key("FLOAT64").RangeFloat64(5, 0, 1), ShouldEqual, 5) + So(sec.Key("INT").RangeInt(7, 0, 5), ShouldEqual, 7) + So(sec.Key("INT").RangeInt64(7, 0, 5), ShouldEqual, 7) + So(sec.Key("TIME").RangeTime(t, minT, midT).String(), ShouldEqual, t.String()) + }) + }) + + Convey("Get values into slice", func() { + sec := f.Section("array") + So(strings.Join(sec.Key("STRINGS").Strings(","), ","), ShouldEqual, "en,zh,de") + So(len(sec.Key("STRINGS_404").Strings(",")), ShouldEqual, 0) + + vals1 := sec.Key("FLOAT64S").Float64s(",") + float64sEqual(vals1, 1.1, 2.2, 3.3) + + vals2 := sec.Key("INTS").Ints(",") + intsEqual(vals2, 1, 2, 3) + + vals3 := sec.Key("INTS").Int64s(",") + int64sEqual(vals3, 1, 2, 3) + + vals4 := sec.Key("UINTS").Uints(",") + uintsEqual(vals4, 1, 2, 3) + + vals5 := sec.Key("UINTS").Uint64s(",") + uint64sEqual(vals5, 1, 2, 3) + + t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z") + So(err, ShouldBeNil) + vals6 := sec.Key("TIMES").Times(",") + timesEqual(vals6, t, t, t) + }) + + Convey("Test string slice escapes", func() { + sec := f.Section("string escapes") + So(sec.Key("key1").Strings(","), ShouldResemble, []string{"value1", "value2", "value3"}) + So(sec.Key("key2").Strings(","), ShouldResemble, []string{"value1, value2"}) + So(sec.Key("key3").Strings(","), ShouldResemble, []string{`val\ue1`, "value2"}) + So(sec.Key("key4").Strings(","), ShouldResemble, []string{`value1\`, `value\\2`}) + So(sec.Key("key5").Strings(",,"), ShouldResemble, []string{"value1,, value2"}) + So(sec.Key("key6").Strings(" "), ShouldResemble, []string{"aaa", "bbb and space", "ccc"}) + }) + + Convey("Get valid values into slice", func() { + sec := f.Section("array") + vals1 := sec.Key("FLOAT64S").ValidFloat64s(",") + float64sEqual(vals1, 1.1, 2.2, 3.3) + + vals2 := sec.Key("INTS").ValidInts(",") + intsEqual(vals2, 1, 2, 3) + + vals3 := sec.Key("INTS").ValidInt64s(",") + int64sEqual(vals3, 1, 2, 3) + + vals4 := sec.Key("UINTS").ValidUints(",") + uintsEqual(vals4, 1, 2, 3) + + vals5 := sec.Key("UINTS").ValidUint64s(",") + uint64sEqual(vals5, 1, 2, 3) + + t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z") + So(err, ShouldBeNil) + vals6 := sec.Key("TIMES").ValidTimes(",") + timesEqual(vals6, t, t, t) + }) + + Convey("Get values one type into slice of another type", func() { + sec := f.Section("array") + vals1 := sec.Key("STRINGS").ValidFloat64s(",") + So(vals1, ShouldBeEmpty) + + vals2 := sec.Key("STRINGS").ValidInts(",") + So(vals2, ShouldBeEmpty) + + vals3 := sec.Key("STRINGS").ValidInt64s(",") + So(vals3, ShouldBeEmpty) + + vals4 := sec.Key("STRINGS").ValidUints(",") + So(vals4, ShouldBeEmpty) + + vals5 := sec.Key("STRINGS").ValidUint64s(",") + So(vals5, ShouldBeEmpty) + + vals6 := sec.Key("STRINGS").ValidTimes(",") + So(vals6, ShouldBeEmpty) + }) + + Convey("Get valid values into slice without errors", func() { + sec := f.Section("array") + vals1, err := sec.Key("FLOAT64S").StrictFloat64s(",") + So(err, ShouldBeNil) + float64sEqual(vals1, 1.1, 2.2, 3.3) + + vals2, err := sec.Key("INTS").StrictInts(",") + So(err, ShouldBeNil) + intsEqual(vals2, 1, 2, 3) + + vals3, err := sec.Key("INTS").StrictInt64s(",") + So(err, ShouldBeNil) + int64sEqual(vals3, 1, 2, 3) + + vals4, err := sec.Key("UINTS").StrictUints(",") + So(err, ShouldBeNil) + uintsEqual(vals4, 1, 2, 3) + + vals5, err := sec.Key("UINTS").StrictUint64s(",") + So(err, ShouldBeNil) + uint64sEqual(vals5, 1, 2, 3) + + t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z") + So(err, ShouldBeNil) + vals6, err := sec.Key("TIMES").StrictTimes(",") + So(err, ShouldBeNil) + timesEqual(vals6, t, t, t) + }) + + Convey("Get invalid values into slice", func() { + sec := f.Section("array") + vals1, err := sec.Key("STRINGS").StrictFloat64s(",") + So(vals1, ShouldBeEmpty) + So(err, ShouldNotBeNil) + + vals2, err := sec.Key("STRINGS").StrictInts(",") + So(vals2, ShouldBeEmpty) + So(err, ShouldNotBeNil) + + vals3, err := sec.Key("STRINGS").StrictInt64s(",") + So(vals3, ShouldBeEmpty) + So(err, ShouldNotBeNil) + + vals4, err := sec.Key("STRINGS").StrictUints(",") + So(vals4, ShouldBeEmpty) + So(err, ShouldNotBeNil) + + vals5, err := sec.Key("STRINGS").StrictUint64s(",") + So(vals5, ShouldBeEmpty) + So(err, ShouldNotBeNil) + + vals6, err := sec.Key("STRINGS").StrictTimes(",") + So(vals6, ShouldBeEmpty) + So(err, ShouldNotBeNil) + }) + }) +} + +func TestKey_StringsWithShadows(t *testing.T) { + Convey("Get strings of shadows of a key", t, func() { + f, err := ini.ShadowLoad([]byte("")) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NUMS", "1,2") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("NUMS", "4,5,6") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(k.StringsWithShadows(","), ShouldResemble, []string{"1", "2", "4", "5", "6"}) + }) +} + +func TestKey_SetValue(t *testing.T) { + Convey("Set value of key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + So(k.Value(), ShouldEqual, "ini") + + k.SetValue("ini.v1") + So(k.Value(), ShouldEqual, "ini.v1") + }) +} + +func TestKey_NestedValues(t *testing.T) { + Convey("Read and write nested values", t, func() { + f, err := ini.LoadSources(ini.LoadOptions{ + AllowNestedValues: true, + }, []byte(` +aws_access_key_id = foo +aws_secret_access_key = bar +region = us-west-2 +s3 = + max_concurrent_requests=10 + max_queue_size=1000`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("").Key("s3").NestedValues(), ShouldResemble, []string{"max_concurrent_requests=10", "max_queue_size=1000"}) + + var buf bytes.Buffer + _, err = f.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `aws_access_key_id = foo +aws_secret_access_key = bar +region = us-west-2 +s3 = + max_concurrent_requests=10 + max_queue_size=1000 + +`) + }) +} + +func TestRecursiveValues(t *testing.T) { + Convey("Recursive values should not reflect on same key", t, func() { + f, err := ini.Load([]byte(` +NAME = ini +[package] +NAME = %(NAME)s`)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + So(f.Section("package").Key("NAME").String(), ShouldEqual, "ini") + }) +} diff --git a/vendor/github.com/go-ini/ini/parser_test.go b/vendor/github.com/go-ini/ini/parser_test.go new file mode 100644 index 000000000..bb0f2665e --- /dev/null +++ b/vendor/github.com/go-ini/ini/parser_test.go @@ -0,0 +1,77 @@ +// Copyright 2016 Unknwon +// +// 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 ini_test + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/ini.v1" +) + +func TestBOM(t *testing.T) { + Convey("Test handling BOM", t, func() { + Convey("UTF-8-BOM", func() { + f, err := ini.Load("testdata/UTF-8-BOM.ini") + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io") + }) + + Convey("UTF-16-LE-BOM", func() { + f, err := ini.Load("testdata/UTF-16-LE-BOM.ini") + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + }) + + Convey("UTF-16-BE-BOM", func() { + }) + }) +} + +func TestBadLoad(t *testing.T) { + Convey("Load with bad data", t, func() { + Convey("Bad section name", func() { + _, err := ini.Load([]byte("[]")) + So(err, ShouldNotBeNil) + + _, err = ini.Load([]byte("[")) + So(err, ShouldNotBeNil) + }) + + Convey("Bad keys", func() { + _, err := ini.Load([]byte(`"""name`)) + So(err, ShouldNotBeNil) + + _, err = ini.Load([]byte(`"""name"""`)) + So(err, ShouldNotBeNil) + + _, err = ini.Load([]byte(`""=1`)) + So(err, ShouldNotBeNil) + + _, err = ini.Load([]byte(`=`)) + So(err, ShouldNotBeNil) + + _, err = ini.Load([]byte(`name`)) + So(err, ShouldNotBeNil) + }) + + Convey("Bad values", func() { + _, err := ini.Load([]byte(`name="""Unknwon`)) + So(err, ShouldNotBeNil) + }) + }) +} diff --git a/vendor/github.com/go-ini/ini/section_test.go b/vendor/github.com/go-ini/ini/section_test.go new file mode 100644 index 000000000..e9c347881 --- /dev/null +++ b/vendor/github.com/go-ini/ini/section_test.go @@ -0,0 +1,313 @@ +// Copyright 2014 Unknwon +// +// 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 ini_test + +import ( + "testing" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/ini.v1" +) + +func TestSection_SetBody(t *testing.T) { + Convey("Set body of raw section", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000`) + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + So(sec.Body(), ShouldEqual, `1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000`) + + sec.SetBody("1111111111111111111000000000000000001110000") + So(sec.Body(), ShouldEqual, `1111111111111111111000000000000000001110000`) + + Convey("Set for non-raw section", func() { + sec, err := f.NewSection("author") + So(err, ShouldBeNil) + So(sec, ShouldNotBeNil) + So(sec.Body(), ShouldBeEmpty) + + sec.SetBody("1111111111111111111000000000000000001110000") + So(sec.Body(), ShouldBeEmpty) + }) + }) +} + +func TestSection_NewKey(t *testing.T) { + Convey("Create a new key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + So(k.Name(), ShouldEqual, "NAME") + So(k.Value(), ShouldEqual, "ini") + + Convey("With duplicated name", func() { + k, err := f.Section("").NewKey("NAME", "ini.v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + // Overwrite previous existed key + So(k.Value(), ShouldEqual, "ini.v1") + }) + + Convey("With empty string", func() { + _, err := f.Section("").NewKey("", "") + So(err, ShouldNotBeNil) + }) + }) + + Convey("Create keys with same name and allow shadow", t, func() { + f, err := ini.ShadowLoad([]byte("")) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("NAME", "ini.v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"}) + }) +} + +func TestSection_NewBooleanKey(t *testing.T) { + Convey("Create a new boolean key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewBooleanKey("start-ssh-server") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + So(k.Name(), ShouldEqual, "start-ssh-server") + So(k.Value(), ShouldEqual, "true") + + Convey("With empty string", func() { + _, err := f.Section("").NewBooleanKey("") + So(err, ShouldNotBeNil) + }) + }) +} + +func TestSection_GetKey(t *testing.T) { + Convey("Get a key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + k, err = f.Section("").GetKey("NAME") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + So(k.Name(), ShouldEqual, "NAME") + So(k.Value(), ShouldEqual, "ini") + + Convey("Key not exists", func() { + _, err := f.Section("").GetKey("404") + So(err, ShouldNotBeNil) + }) + + Convey("Key exists in parent section", func() { + k, err := f.Section("parent").NewKey("AGE", "18") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + k, err = f.Section("parent.child.son").GetKey("AGE") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + So(k.Value(), ShouldEqual, "18") + }) + }) +} + +func TestSection_HasKey(t *testing.T) { + Convey("Check if a key exists", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(f.Section("").HasKey("NAME"), ShouldBeTrue) + So(f.Section("").Haskey("NAME"), ShouldBeTrue) + So(f.Section("").HasKey("404"), ShouldBeFalse) + So(f.Section("").Haskey("404"), ShouldBeFalse) + }) +} + +func TestSection_HasValue(t *testing.T) { + Convey("Check if contains a value in any key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(f.Section("").HasValue("ini"), ShouldBeTrue) + So(f.Section("").HasValue("404"), ShouldBeFalse) + }) +} + +func TestSection_Key(t *testing.T) { + Convey("Get a key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + k = f.Section("").Key("NAME") + So(k, ShouldNotBeNil) + So(k.Name(), ShouldEqual, "NAME") + So(k.Value(), ShouldEqual, "ini") + + Convey("Key not exists", func() { + k := f.Section("").Key("404") + So(k, ShouldNotBeNil) + So(k.Name(), ShouldEqual, "404") + }) + + Convey("Key exists in parent section", func() { + k, err := f.Section("parent").NewKey("AGE", "18") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + k = f.Section("parent.child.son").Key("AGE") + So(k, ShouldNotBeNil) + So(k.Value(), ShouldEqual, "18") + }) + }) +} + +func TestSection_Keys(t *testing.T) { + Convey("Get all keys in a section", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("VERSION", "v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + keys := f.Section("").Keys() + names := []string{"NAME", "VERSION", "IMPORT_PATH"} + So(len(keys), ShouldEqual, len(names)) + for i, name := range names { + So(keys[i].Name(), ShouldEqual, name) + } + }) +} + +func TestSection_ParentKeys(t *testing.T) { + Convey("Get all keys of parent sections", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("package").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("package").NewKey("VERSION", "v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("package").NewKey("IMPORT_PATH", "gopkg.in/ini.v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + keys := f.Section("package.sub.sub2").ParentKeys() + names := []string{"NAME", "VERSION", "IMPORT_PATH"} + So(len(keys), ShouldEqual, len(names)) + for i, name := range names { + So(keys[i].Name(), ShouldEqual, name) + } + }) +} + +func TestSection_KeyStrings(t *testing.T) { + Convey("Get all key names in a section", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("VERSION", "v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(f.Section("").KeyStrings(), ShouldResemble, []string{"NAME", "VERSION", "IMPORT_PATH"}) + }) +} + +func TestSection_KeyHash(t *testing.T) { + Convey("Get clone of key hash", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("VERSION", "v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + hash := f.Section("").KeysHash() + relation := map[string]string{ + "NAME": "ini", + "VERSION": "v1", + "IMPORT_PATH": "gopkg.in/ini.v1", + } + for k, v := range hash { + So(v, ShouldEqual, relation[k]) + } + }) +} + +func TestSection_DeleteKey(t *testing.T) { + Convey("Delete a key", t, func() { + f := ini.Empty() + So(f, ShouldNotBeNil) + + k, err := f.Section("").NewKey("NAME", "ini") + So(err, ShouldBeNil) + So(k, ShouldNotBeNil) + + So(f.Section("").HasKey("NAME"), ShouldBeTrue) + f.Section("").DeleteKey("NAME") + So(f.Section("").HasKey("NAME"), ShouldBeFalse) + }) +} diff --git a/vendor/github.com/go-ini/ini/struct_test.go b/vendor/github.com/go-ini/ini/struct_test.go new file mode 100644 index 000000000..0dbbef22d --- /dev/null +++ b/vendor/github.com/go-ini/ini/struct_test.go @@ -0,0 +1,387 @@ +// Copyright 2014 Unknwon +// +// 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 ini_test + +import ( + "bytes" + "fmt" + "strings" + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/ini.v1" +) + +type testNested struct { + Cities []string `delim:"|"` + Visits []time.Time + Years []int + Numbers []int64 + Ages []uint + Populations []uint64 + Coordinates []float64 + Note string + Unused int `ini:"-"` +} + +type TestEmbeded struct { + GPA float64 +} + +type testStruct struct { + Name string `ini:"NAME"` + Age int + Male bool + Money float64 + Born time.Time + Time time.Duration `ini:"Duration"` + Others testNested + *TestEmbeded `ini:"grade"` + Unused int `ini:"-"` + Unsigned uint + Omitted bool `ini:"omitthis,omitempty"` + Shadows []string `ini:",,allowshadow"` + ShadowInts []int `ini:"Shadows,,allowshadow"` +} + +const _CONF_DATA_STRUCT = ` +NAME = Unknwon +Age = 21 +Male = true +Money = 1.25 +Born = 1993-10-07T20:17:05Z +Duration = 2h45m +Unsigned = 3 +omitthis = true +Shadows = 1, 2 +Shadows = 3, 4 + +[Others] +Cities = HangZhou|Boston +Visits = 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z +Years = 1993,1994 +Numbers = 10010,10086 +Ages = 18,19 +Populations = 12345678,98765432 +Coordinates = 192.168,10.11 +Note = Hello world! + +[grade] +GPA = 2.8 + +[foo.bar] +Here = there +When = then +` + +type unsupport struct { + Byte byte +} + +type unsupport2 struct { + Others struct { + Cities byte + } +} + +type Unsupport3 struct { + Cities byte +} + +type unsupport4 struct { + *Unsupport3 `ini:"Others"` +} + +type defaultValue struct { + Name string + Age int + Male bool + Money float64 + Born time.Time + Cities []string +} + +type fooBar struct { + Here, When string +} + +const _INVALID_DATA_CONF_STRUCT = ` +Name = +Age = age +Male = 123 +Money = money +Born = nil +Cities = +` + +func Test_MapToStruct(t *testing.T) { + Convey("Map to struct", t, func() { + Convey("Map file to struct", func() { + ts := new(testStruct) + So(ini.MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil) + + So(ts.Name, ShouldEqual, "Unknwon") + So(ts.Age, ShouldEqual, 21) + So(ts.Male, ShouldBeTrue) + So(ts.Money, ShouldEqual, 1.25) + So(ts.Unsigned, ShouldEqual, 3) + + t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z") + So(err, ShouldBeNil) + So(ts.Born.String(), ShouldEqual, t.String()) + + dur, err := time.ParseDuration("2h45m") + So(err, ShouldBeNil) + So(ts.Time.Seconds(), ShouldEqual, dur.Seconds()) + + So(strings.Join(ts.Others.Cities, ","), ShouldEqual, "HangZhou,Boston") + So(ts.Others.Visits[0].String(), ShouldEqual, t.String()) + So(fmt.Sprint(ts.Others.Years), ShouldEqual, "[1993 1994]") + So(fmt.Sprint(ts.Others.Numbers), ShouldEqual, "[10010 10086]") + So(fmt.Sprint(ts.Others.Ages), ShouldEqual, "[18 19]") + So(fmt.Sprint(ts.Others.Populations), ShouldEqual, "[12345678 98765432]") + So(fmt.Sprint(ts.Others.Coordinates), ShouldEqual, "[192.168 10.11]") + So(ts.Others.Note, ShouldEqual, "Hello world!") + So(ts.TestEmbeded.GPA, ShouldEqual, 2.8) + }) + + Convey("Map section to struct", func() { + foobar := new(fooBar) + f, err := ini.Load([]byte(_CONF_DATA_STRUCT)) + So(err, ShouldBeNil) + + So(f.Section("foo.bar").MapTo(foobar), ShouldBeNil) + So(foobar.Here, ShouldEqual, "there") + So(foobar.When, ShouldEqual, "then") + }) + + Convey("Map to non-pointer struct", func() { + f, err := ini.Load([]byte(_CONF_DATA_STRUCT)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + So(f.MapTo(testStruct{}), ShouldNotBeNil) + }) + + Convey("Map to unsupported type", func() { + f, err := ini.Load([]byte(_CONF_DATA_STRUCT)) + So(err, ShouldBeNil) + So(f, ShouldNotBeNil) + + f.NameMapper = func(raw string) string { + if raw == "Byte" { + return "NAME" + } + return raw + } + So(f.MapTo(&unsupport{}), ShouldNotBeNil) + So(f.MapTo(&unsupport2{}), ShouldNotBeNil) + So(f.MapTo(&unsupport4{}), ShouldNotBeNil) + }) + + Convey("Map to omitempty field", func() { + ts := new(testStruct) + So(ini.MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil) + + So(ts.Omitted, ShouldEqual, true) + }) + + Convey("Map with shadows", func() { + f, err := ini.LoadSources(ini.LoadOptions{AllowShadows: true}, []byte(_CONF_DATA_STRUCT)) + So(err, ShouldBeNil) + ts := new(testStruct) + So(f.MapTo(ts), ShouldBeNil) + + So(strings.Join(ts.Shadows, " "), ShouldEqual, "1 2 3 4") + So(fmt.Sprintf("%v", ts.ShadowInts), ShouldEqual, "[1 2 3 4]") + }) + + Convey("Map from invalid data source", func() { + So(ini.MapTo(&testStruct{}, "hi"), ShouldNotBeNil) + }) + + Convey("Map to wrong types and gain default values", func() { + f, err := ini.Load([]byte(_INVALID_DATA_CONF_STRUCT)) + So(err, ShouldBeNil) + + t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z") + So(err, ShouldBeNil) + dv := &defaultValue{"Joe", 10, true, 1.25, t, []string{"HangZhou", "Boston"}} + So(f.MapTo(dv), ShouldBeNil) + So(dv.Name, ShouldEqual, "Joe") + So(dv.Age, ShouldEqual, 10) + So(dv.Male, ShouldBeTrue) + So(dv.Money, ShouldEqual, 1.25) + So(dv.Born.String(), ShouldEqual, t.String()) + So(strings.Join(dv.Cities, ","), ShouldEqual, "HangZhou,Boston") + }) + }) + + Convey("Map to struct in strict mode", t, func() { + f, err := ini.Load([]byte(` +name=bruce +age=a30`)) + So(err, ShouldBeNil) + + type Strict struct { + Name string `ini:"name"` + Age int `ini:"age"` + } + s := new(Strict) + + So(f.Section("").StrictMapTo(s), ShouldNotBeNil) + }) + + Convey("Map slice in strict mode", t, func() { + f, err := ini.Load([]byte(` +names=alice, bruce`)) + So(err, ShouldBeNil) + + type Strict struct { + Names []string `ini:"names"` + } + s := new(Strict) + + So(f.Section("").StrictMapTo(s), ShouldBeNil) + So(fmt.Sprint(s.Names), ShouldEqual, "[alice bruce]") + }) +} + +func Test_ReflectFromStruct(t *testing.T) { + Convey("Reflect from struct", t, func() { + type Embeded struct { + Dates []time.Time `delim:"|" comment:"Time data"` + Places []string + Years []int + Numbers []int64 + Ages []uint + Populations []uint64 + Coordinates []float64 + None []int + } + type Author struct { + Name string `ini:"NAME"` + Male bool + Age int `comment:"Author's age"` + Height uint + GPA float64 + Date time.Time + NeverMind string `ini:"-"` + *Embeded `ini:"infos" comment:"Embeded section"` + } + + t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z") + So(err, ShouldBeNil) + a := &Author{"Unknwon", true, 21, 100, 2.8, t, "", + &Embeded{ + []time.Time{t, t}, + []string{"HangZhou", "Boston"}, + []int{1993, 1994}, + []int64{10010, 10086}, + []uint{18, 19}, + []uint64{12345678, 98765432}, + []float64{192.168, 10.11}, + []int{}, + }} + cfg := ini.Empty() + So(ini.ReflectFrom(cfg, a), ShouldBeNil) + + var buf bytes.Buffer + _, err = cfg.WriteTo(&buf) + So(err, ShouldBeNil) + So(buf.String(), ShouldEqual, `NAME = Unknwon +Male = true +; Author's age +Age = 21 +Height = 100 +GPA = 2.8 +Date = 1993-10-07T20:17:05Z + +; Embeded section +[infos] +; Time data +Dates = 1993-10-07T20:17:05Z|1993-10-07T20:17:05Z +Places = HangZhou,Boston +Years = 1993,1994 +Numbers = 10010,10086 +Ages = 18,19 +Populations = 12345678,98765432 +Coordinates = 192.168,10.11 +None = + +`) + + Convey("Reflect from non-point struct", func() { + So(ini.ReflectFrom(cfg, Author{}), ShouldNotBeNil) + }) + + Convey("Reflect from struct with omitempty", func() { + cfg := ini.Empty() + type SpecialStruct struct { + FirstName string `ini:"first_name"` + LastName string `ini:"last_name"` + JustOmitMe string `ini:"omitempty"` + LastLogin time.Time `ini:"last_login,omitempty"` + LastLogin2 time.Time `ini:",omitempty"` + NotEmpty int `ini:"omitempty"` + } + + So(ini.ReflectFrom(cfg, &SpecialStruct{FirstName: "John", LastName: "Doe", NotEmpty: 9}), ShouldBeNil) + + var buf bytes.Buffer + _, err = cfg.WriteTo(&buf) + So(buf.String(), ShouldEqual, `first_name = John +last_name = Doe +omitempty = 9 + +`) + }) + }) +} + +type testMapper struct { + PackageName string +} + +func Test_NameGetter(t *testing.T) { + Convey("Test name mappers", t, func() { + So(ini.MapToWithMapper(&testMapper{}, ini.TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil) + + cfg, err := ini.Load([]byte("PACKAGE_NAME=ini")) + So(err, ShouldBeNil) + So(cfg, ShouldNotBeNil) + + cfg.NameMapper = ini.AllCapsUnderscore + tg := new(testMapper) + So(cfg.MapTo(tg), ShouldBeNil) + So(tg.PackageName, ShouldEqual, "ini") + }) +} + +type testDurationStruct struct { + Duration time.Duration `ini:"Duration"` +} + +func Test_Duration(t *testing.T) { + Convey("Duration less than 16m50s", t, func() { + ds := new(testDurationStruct) + So(ini.MapTo(ds, []byte("Duration=16m49s")), ShouldBeNil) + + dur, err := time.ParseDuration("16m49s") + So(err, ShouldBeNil) + So(ds.Duration.Seconds(), ShouldEqual, dur.Seconds()) + }) +} diff --git a/vendor/github.com/go-openapi/jsonpointer/.editorconfig b/vendor/github.com/go-openapi/jsonpointer/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/jsonpointer/.gitignore b/vendor/github.com/go-openapi/jsonpointer/.gitignore new file mode 100644 index 000000000..769c24400 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.gitignore @@ -0,0 +1 @@ +secrets.yml diff --git a/vendor/github.com/go-openapi/jsonpointer/.travis.yml b/vendor/github.com/go-openapi/jsonpointer/.travis.yml new file mode 100644 index 000000000..2ee3ab975 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/.travis.yml @@ -0,0 +1,15 @@ +language: go +go: +- "1.8" +- "1.9" +- "1.10" +install: +- go get -u github.com/stretchr/testify/assert +- go get -u github.com/go-openapi/swag +script: +- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... +after_success: +- bash <(curl -s https://codecov.io/bash) +notifications: + slack: + secure: a5VgoiwB1G/AZqzmephPZIhEB9avMlsWSlVnM1dSAtYAwdrQHGTQxAmpOxYIoSPDhWNN5bfZmjd29++UlTwLcHSR+e0kJhH6IfDlsHj/HplNCJ9tyI0zYc7XchtdKgeMxMzBKCzgwFXGSbQGydXTliDNBo0HOzmY3cou/daMFTP60K+offcjS+3LRAYb1EroSRXZqrk1nuF/xDL3792DZUdPMiFR/L/Df6y74D6/QP4sTkTDFQitz4Wy/7jbsfj8dG6qK2zivgV6/l+w4OVjFkxVpPXogDWY10vVXNVynqxfJ7to2d1I9lNCHE2ilBCkWMIPdyJF7hjF8pKW+82yP4EzRh0vu8Xn0HT5MZpQxdRY/YMxNrWaG7SxsoEaO4q5uhgdzAqLYY3TRa7MjIK+7Ur+aqOeTXn6OKwVi0CjvZ6mIU3WUKSwiwkFZMbjRAkSb5CYwMEfGFO/z964xz83qGt6WAtBXNotqCQpTIiKtDHQeLOMfksHImCg6JLhQcWBVxamVgu0G3Pdh8Y6DyPnxraXY95+QDavbjqv7TeYT9T/FNnrkXaTTK0s4iWE5H4ACU0Qvz0wUYgfQrZv0/Hp7V17+rabUwnzYySHCy9SWX/7OV9Cfh31iMp9ZIffr76xmmThtOEqs8TrTtU6BWI3rWwvA9cXQipZTVtL0oswrGw= diff --git a/vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md new file mode 100644 index 000000000..813788aff --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/README.md @@ -0,0 +1,15 @@ +# gojsonpointer [![Build Status](https://travis-ci.org/go-openapi/jsonpointer.svg?branch=master)](https://travis-ci.org/go-openapi/jsonpointer) [![codecov](https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonpointer) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonpointer?status.svg)](http://godoc.org/github.com/go-openapi/jsonpointer) +An implementation of JSON Pointer - Go language + +## Status +Completed YES + +Tested YES + +## References +http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 + +### Note +The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented. diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer_test.go b/vendor/github.com/go-openapi/jsonpointer/pointer_test.go new file mode 100644 index 000000000..eabd58603 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/pointer_test.go @@ -0,0 +1,573 @@ +// Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) +// +// 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. + +// author sigu-399 +// author-github https://github.com/sigu-399 +// author-mail sigu.399@gmail.com +// +// repository-name jsonpointer +// repository-desc An implementation of JSON Pointer - Go language +// +// description Automated tests on package. +// +// created 03-03-2013 + +package jsonpointer + +import ( + "encoding/json" + "fmt" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" +) + +const ( + TestDocumentNBItems = 11 + TestNodeObjNBItems = 4 + TestDocumentString = `{ +"foo": ["bar", "baz"], +"obj": { "a":1, "b":2, "c":[3,4], "d":[ {"e":9}, {"f":[50,51]} ] }, +"": 0, +"a/b": 1, +"c%d": 2, +"e^f": 3, +"g|h": 4, +"i\\j": 5, +"k\"l": 6, +" ": 7, +"m~n": 8 +}` +) + +var testDocumentJSON interface{} + +type testStructJSON struct { + Foo []string `json:"foo"` + Obj struct { + A int `json:"a"` + B int `json:"b"` + C []int `json:"c"` + D []struct { + E int `json:"e"` + F []int `json:"f"` + } `json:"d"` + } `json:"obj"` +} + +type aliasedMap map[string]interface{} + +var testStructJSONDoc testStructJSON +var testStructJSONPtr *testStructJSON + +func init() { + json.Unmarshal([]byte(TestDocumentString), &testDocumentJSON) + json.Unmarshal([]byte(TestDocumentString), &testStructJSONDoc) + testStructJSONPtr = &testStructJSONDoc +} + +func TestEscaping(t *testing.T) { + + ins := []string{`/`, `/`, `/a~1b`, `/a~1b`, `/c%d`, `/e^f`, `/g|h`, `/i\j`, `/k"l`, `/ `, `/m~0n`} + outs := []float64{0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8} + + for i := range ins { + p, err := New(ins[i]) + if assert.NoError(t, err, "input: %v", ins[i]) { + result, _, err := p.Get(testDocumentJSON) + if assert.NoError(t, err, "input: %v", ins[i]) { + assert.Equal(t, outs[i], result, "input: %v", ins[i]) + } + } + } + +} + +func TestFullDocument(t *testing.T) { + + in := `` + + p, err := New(in) + if err != nil { + t.Errorf("New(%v) error %v", in, err.Error()) + } + + result, _, err := p.Get(testDocumentJSON) + if err != nil { + t.Errorf("Get(%v) error %v", in, err.Error()) + } + + if len(result.(map[string]interface{})) != TestDocumentNBItems { + t.Errorf("Get(%v) = %v, expect full document", in, result) + } + + result, _, err = p.get(testDocumentJSON, nil) + if err != nil { + t.Errorf("Get(%v) error %v", in, err.Error()) + } + + if len(result.(map[string]interface{})) != TestDocumentNBItems { + t.Errorf("Get(%v) = %v, expect full document", in, result) + } +} + +func TestDecodedTokens(t *testing.T) { + p, err := New("/obj/a~1b") + assert.NoError(t, err) + assert.Equal(t, []string{"obj", "a/b"}, p.DecodedTokens()) +} + +func TestIsEmpty(t *testing.T) { + p, err := New("") + assert.NoError(t, err) + assert.True(t, p.IsEmpty()) + p, err = New("/obj") + assert.NoError(t, err) + assert.False(t, p.IsEmpty()) +} + +func TestGetSingle(t *testing.T) { + in := `/obj` + + _, err := New(in) + assert.NoError(t, err) + result, _, err := GetForToken(testDocumentJSON, "obj") + assert.NoError(t, err) + assert.Len(t, result, TestNodeObjNBItems) + + result, _, err = GetForToken(testStructJSONDoc, "Obj") + assert.Error(t, err) + assert.Nil(t, result) + + result, _, err = GetForToken(testStructJSONDoc, "Obj2") + assert.Error(t, err) + assert.Nil(t, result) +} + +type pointableImpl struct { + a string +} + +func (p pointableImpl) JSONLookup(token string) (interface{}, error) { + if token == "some" { + return p.a, nil + } + return nil, fmt.Errorf("object has no field %q", token) +} + +func TestPointableInterface(t *testing.T) { + p := &pointableImpl{"hello"} + + result, _, err := GetForToken(p, "some") + assert.NoError(t, err) + assert.Equal(t, p.a, result) + + result, _, err = GetForToken(p, "something") + assert.Error(t, err) + assert.Nil(t, result) +} + +func TestGetNode(t *testing.T) { + + in := `/obj` + + p, err := New(in) + assert.NoError(t, err) + result, _, err := p.Get(testDocumentJSON) + assert.NoError(t, err) + assert.Len(t, result, TestNodeObjNBItems) + + result, _, err = p.Get(aliasedMap(testDocumentJSON.(map[string]interface{}))) + assert.NoError(t, err) + assert.Len(t, result, TestNodeObjNBItems) + + result, _, err = p.Get(testStructJSONDoc) + assert.NoError(t, err) + assert.Equal(t, testStructJSONDoc.Obj, result) + + result, _, err = p.Get(testStructJSONPtr) + assert.NoError(t, err) + assert.Equal(t, testStructJSONDoc.Obj, result) +} + +func TestArray(t *testing.T) { + + ins := []string{`/foo/0`, `/foo/0`, `/foo/1`} + outs := []string{"bar", "bar", "baz"} + + for i := range ins { + p, err := New(ins[i]) + assert.NoError(t, err) + + result, _, err := p.Get(testStructJSONDoc) + assert.NoError(t, err) + assert.Equal(t, outs[i], result) + + result, _, err = p.Get(testStructJSONPtr) + assert.NoError(t, err) + assert.Equal(t, outs[i], result) + + result, _, err = p.Get(testDocumentJSON) + assert.NoError(t, err) + assert.Equal(t, outs[i], result) + } +} + +func TestOtherThings(t *testing.T) { + _, err := New("abc") + assert.Error(t, err) + + p, err := New("") + assert.NoError(t, err) + assert.Equal(t, "", p.String()) + + p, err = New("/obj/a") + assert.Equal(t, "/obj/a", p.String()) + + s := Escape("m~n") + assert.Equal(t, "m~0n", s) + s = Escape("m/n") + assert.Equal(t, "m~1n", s) + + p, err = New("/foo/3") + assert.NoError(t, err) + _, _, err = p.Get(testDocumentJSON) + assert.Error(t, err) + + p, err = New("/foo/a") + assert.NoError(t, err) + _, _, err = p.Get(testDocumentJSON) + assert.Error(t, err) + + p, err = New("/notthere") + assert.NoError(t, err) + _, _, err = p.Get(testDocumentJSON) + assert.Error(t, err) + + p, err = New("/invalid") + assert.NoError(t, err) + _, _, err = p.Get(1234) + assert.Error(t, err) + + p, err = New("/foo/1") + assert.NoError(t, err) + expected := "hello" + bbb := testDocumentJSON.(map[string]interface{})["foo"] + bbb.([]interface{})[1] = "hello" + + v, _, err := p.Get(testDocumentJSON) + assert.NoError(t, err) + assert.Equal(t, expected, v) + + esc := Escape("a/") + assert.Equal(t, "a~1", esc) + unesc := Unescape(esc) + assert.Equal(t, "a/", unesc) + + unesc = Unescape("~01") + assert.Equal(t, "~1", unesc) + assert.Equal(t, "~0~1", Escape("~/")) + assert.Equal(t, "~/", Unescape("~0~1")) +} + +func TestObject(t *testing.T) { + + ins := []string{`/obj/a`, `/obj/b`, `/obj/c/0`, `/obj/c/1`, `/obj/c/1`, `/obj/d/1/f/0`} + outs := []float64{1, 2, 3, 4, 4, 50} + + for i := range ins { + + p, err := New(ins[i]) + assert.NoError(t, err) + + result, _, err := p.Get(testDocumentJSON) + assert.NoError(t, err) + assert.Equal(t, outs[i], result) + + result, _, err = p.Get(testStructJSONDoc) + assert.NoError(t, err) + assert.EqualValues(t, outs[i], result) + + result, _, err = p.Get(testStructJSONPtr) + assert.NoError(t, err) + assert.EqualValues(t, outs[i], result) + } +} + +type setJsonDocEle struct { + B int `json:"b"` + C int `json:"c"` +} +type setJsonDoc struct { + A []struct { + B int `json:"b"` + C int `json:"c"` + } `json:"a"` + D int `json:"d"` +} + +type settableDoc struct { + Coll settableColl + Int settableInt +} + +func (s settableDoc) MarshalJSON() ([]byte, error) { + var res struct { + A settableColl `json:"a"` + D settableInt `json:"d"` + } + res.A = s.Coll + res.D = s.Int + return json.Marshal(res) +} +func (s *settableDoc) UnmarshalJSON(data []byte) error { + var res struct { + A settableColl `json:"a"` + D settableInt `json:"d"` + } + + if err := json.Unmarshal(data, &res); err != nil { + return err + } + s.Coll = res.A + s.Int = res.D + return nil +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s settableDoc) JSONLookup(token string) (interface{}, error) { + switch token { + case "a": + return &s.Coll, nil + case "d": + return &s.Int, nil + default: + return nil, fmt.Errorf("%s is not a known field", token) + } +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s *settableDoc) JSONSet(token string, data interface{}) error { + switch token { + case "a": + switch dt := data.(type) { + case settableColl: + s.Coll = dt + return nil + case *settableColl: + if dt != nil { + s.Coll = *dt + } else { + s.Coll = settableColl{} + } + return nil + case []settableCollItem: + s.Coll.Items = dt + return nil + } + case "d": + switch dt := data.(type) { + case settableInt: + s.Int = dt + return nil + case int: + s.Int.Value = dt + return nil + case int8: + s.Int.Value = int(dt) + return nil + case int16: + s.Int.Value = int(dt) + return nil + case int32: + s.Int.Value = int(dt) + return nil + case int64: + s.Int.Value = int(dt) + return nil + default: + return fmt.Errorf("invalid type %T for %s", data, token) + } + } + return fmt.Errorf("%s is not a known field", token) +} + +type settableColl struct { + Items []settableCollItem +} + +func (s settableColl) MarshalJSON() ([]byte, error) { + return json.Marshal(s.Items) +} +func (s *settableColl) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &s.Items) +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s settableColl) JSONLookup(token string) (interface{}, error) { + if tok, err := strconv.Atoi(token); err == nil { + return &s.Items[tok], nil + } + return nil, fmt.Errorf("%s is not a valid index", token) +} + +// JSONLookup implements an interface to customize json pointer lookup +func (s *settableColl) JSONSet(token string, data interface{}) error { + if _, err := strconv.Atoi(token); err == nil { + _, err := SetForToken(s.Items, token, data) + return err + } + return fmt.Errorf("%s is not a valid index", token) +} + +type settableCollItem struct { + B int `json:"b"` + C int `json:"c"` +} + +type settableInt struct { + Value int +} + +func (s settableInt) MarshalJSON() ([]byte, error) { + return json.Marshal(s.Value) +} +func (s *settableInt) UnmarshalJSON(data []byte) error { + return json.Unmarshal(data, &s.Value) +} + +func TestSetNode(t *testing.T) { + + jsonText := `{"a":[{"b": 1, "c": 2}], "d": 3}` + + var jsonDocument interface{} + if assert.NoError(t, json.Unmarshal([]byte(jsonText), &jsonDocument)) { + in := "/a/0/c" + p, err := New(in) + if assert.NoError(t, err) { + + _, err = p.Set(jsonDocument, 999) + assert.NoError(t, err) + + firstNode := jsonDocument.(map[string]interface{}) + assert.Len(t, firstNode, 2) + + sliceNode := firstNode["a"].([]interface{}) + assert.Len(t, sliceNode, 1) + + changedNode := sliceNode[0].(map[string]interface{}) + chNodeVI := changedNode["c"] + if assert.IsType(t, 0, chNodeVI) { + changedNodeValue := chNodeVI.(int) + if assert.Equal(t, 999, changedNodeValue) { + assert.Len(t, sliceNode, 1) + } + } + } + + v, err := New("/a/0") + if assert.NoError(t, err) { + _, err = v.Set(jsonDocument, map[string]interface{}{"b": 3, "c": 8}) + if assert.NoError(t, err) { + firstNode := jsonDocument.(map[string]interface{}) + assert.Len(t, firstNode, 2) + + sliceNode := firstNode["a"].([]interface{}) + assert.Len(t, sliceNode, 1) + changedNode := sliceNode[0].(map[string]interface{}) + assert.Equal(t, 3, changedNode["b"]) + assert.Equal(t, 8, changedNode["c"]) + } + } + } + + var structDoc setJsonDoc + if assert.NoError(t, json.Unmarshal([]byte(jsonText), &structDoc)) { + g, err := New("/a") + if assert.NoError(t, err) { + _, err = g.Set(&structDoc, []struct { + B int `json:"b"` + C int `json:"c"` + }{{B: 4, C: 7}}) + + if assert.NoError(t, err) { + assert.Len(t, structDoc.A, 1) + changedNode := structDoc.A[0] + assert.Equal(t, 4, changedNode.B) + assert.Equal(t, 7, changedNode.C) + } + } + + v, err := New("/a/0") + if assert.NoError(t, err) { + _, err = v.Set(structDoc, struct { + B int `json:"b"` + C int `json:"c"` + }{B: 3, C: 8}) + + if assert.NoError(t, err) { + assert.Len(t, structDoc.A, 1) + changedNode := structDoc.A[0] + assert.Equal(t, 3, changedNode.B) + assert.Equal(t, 8, changedNode.C) + } + } + + p, err := New("/a/0/c") + if assert.NoError(t, err) { + _, err = p.Set(&structDoc, 999) + assert.NoError(t, err) + if assert.Len(t, structDoc.A, 1) { + assert.Equal(t, 999, structDoc.A[0].C) + } + } + } + + var setDoc settableDoc + if assert.NoError(t, json.Unmarshal([]byte(jsonText), &setDoc)) { + g, err := New("/a") + if assert.NoError(t, err) { + _, err = g.Set(&setDoc, []settableCollItem{{B: 4, C: 7}}) + + if assert.NoError(t, err) { + assert.Len(t, setDoc.Coll.Items, 1) + changedNode := setDoc.Coll.Items[0] + assert.Equal(t, 4, changedNode.B) + assert.Equal(t, 7, changedNode.C) + } + } + + v, err := New("/a/0") + if assert.NoError(t, err) { + _, err = v.Set(setDoc, settableCollItem{B: 3, C: 8}) + + if assert.NoError(t, err) { + assert.Len(t, setDoc.Coll.Items, 1) + changedNode := setDoc.Coll.Items[0] + assert.Equal(t, 3, changedNode.B) + assert.Equal(t, 8, changedNode.C) + } + } + + p, err := New("/a/0/c") + if assert.NoError(t, err) { + _, err = p.Set(setDoc, 999) + assert.NoError(t, err) + if assert.Len(t, setDoc.Coll.Items, 1) { + assert.Equal(t, 999, setDoc.Coll.Items[0].C) + } + } + } +} diff --git a/vendor/github.com/go-openapi/jsonreference/.gitignore b/vendor/github.com/go-openapi/jsonreference/.gitignore new file mode 100644 index 000000000..769c24400 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/.gitignore @@ -0,0 +1 @@ +secrets.yml diff --git a/vendor/github.com/go-openapi/jsonreference/.travis.yml b/vendor/github.com/go-openapi/jsonreference/.travis.yml new file mode 100644 index 000000000..7a261a651 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/.travis.yml @@ -0,0 +1,16 @@ +language: go +go: +- "1.8" +- "1.9" +- "1.10" +install: +- go get -u github.com/stretchr/testify/assert +- go get -u github.com/PuerkitoBio/purell +- go get -u github.com/go-openapi/jsonpointer +script: +- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... +after_success: +- bash <(curl -s https://codecov.io/bash) +notifications: + slack: + secure: OpQG/36F7DSF00HLm9WZMhyqFCYYyYTsVDObW226cWiR8PWYiNfLZiSEvIzT1Gx4dDjhigKTIqcLhG34CkL5iNXDjm9Yyo2RYhQPlK8NErNqUEXuBqn4RqYHW48VGhEhOyDd4Ei0E2FN5ZbgpvHgtpkdZ6XDi64r3Ac89isP9aPHXQTuv2Jog6b4/OKKiUTftLcTIst0p4Cp3gqOJWf1wnoj+IadWiECNVQT6zb47IYjtyw6+uV8iUjTzdKcRB6Zc6b4Dq7JAg1Zd7Jfxkql3hlKp4PNlRf9Cy7y5iA3G7MLyg3FcPX5z2kmcyPt2jOTRMBWUJ5zIQpOxizAcN8WsT3WWBL5KbuYK6k0PzujrIDLqdxGpNmjkkMfDBT9cKmZpm2FdW+oZgPFJP+oKmAo4u4KJz/vjiPTXgQlN5bmrLuRMCp+AwC5wkIohTqWZVPE2TK6ZSnMYcg/W39s+RP/9mJoyryAvPSpBOLTI+biCgaUCTOAZxNTWpMFc3tPYntc41WWkdKcooZ9JA5DwfcaVFyTGQ3YXz+HvX6G1z/gW0Q/A4dBi9mj2iE1xm7tRTT+4VQ2AXFvSEI1HJpfPgYnwAtwOD1v3Qm2EUHk9sCdtEDR4wVGEPIVn44GnwFMnGKx9JWppMPYwFu3SVDdHt+E+LOlhZUply11Aa+IVrT2KUQ= diff --git a/vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/jsonreference/README.md b/vendor/github.com/go-openapi/jsonreference/README.md new file mode 100644 index 000000000..66345f4c6 --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/README.md @@ -0,0 +1,15 @@ +# gojsonreference [![Build Status](https://travis-ci.org/go-openapi/jsonreference.svg?branch=master)](https://travis-ci.org/go-openapi/jsonreference) [![codecov](https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/jsonreference) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/jsonreference?status.svg)](http://godoc.org/github.com/go-openapi/jsonreference) +An implementation of JSON Reference - Go language + +## Status +Work in progress ( 90% done ) + +## Dependencies +https://github.com/go-openapi/jsonpointer + +## References +http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07 + +http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03 diff --git a/vendor/github.com/go-openapi/jsonreference/reference_test.go b/vendor/github.com/go-openapi/jsonreference/reference_test.go new file mode 100644 index 000000000..2bfadcede --- /dev/null +++ b/vendor/github.com/go-openapi/jsonreference/reference_test.go @@ -0,0 +1,420 @@ +// Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) +// +// 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. + +// author sigu-399 +// author-github https://github.com/sigu-399 +// author-mail sigu.399@gmail.com +// +// repository-name jsonreference +// repository-desc An implementation of JSON Reference - Go language +// +// description Automated tests on package. +// +// created 03-03-2013 + +package jsonreference + +import ( + "testing" + + "github.com/go-openapi/jsonpointer" + "github.com/stretchr/testify/assert" +) + +func TestIsRoot(t *testing.T) { + in := "#" + r1, err := New(in) + assert.NoError(t, err) + assert.True(t, r1.IsRoot()) + + in = "#/ok" + r1 = MustCreateRef(in) + assert.False(t, r1.IsRoot()) + + assert.Panics(t, assert.PanicTestFunc(func() { + MustCreateRef("%2") + })) +} + +func TestFull(t *testing.T) { + + in := "http://host/path/a/b/c#/f/a/b" + + r1, err := New(in) + if err != nil { + t.Errorf("New(%v) error %s", in, err.Error()) + } + + if in != r1.String() { + t.Errorf("New(%v) = %v, expect %v", in, r1.String(), in) + } + + if r1.HasFragmentOnly != false { + t.Errorf("New(%v)::HasFragmentOnly %v expect %v", in, r1.HasFragmentOnly, false) + } + + if r1.HasFullURL != true { + t.Errorf("New(%v)::HasFullURL %v expect %v", in, r1.HasFullURL, true) + } + + if r1.HasURLPathOnly != false { + t.Errorf("New(%v)::HasURLPathOnly %v expect %v", in, r1.HasURLPathOnly, false) + } + + if r1.HasFileScheme != false { + t.Errorf("New(%v)::HasFileScheme %v expect %v", in, r1.HasFileScheme, false) + } + + if r1.GetPointer().String() != "/f/a/b" { + t.Errorf("New(%v)::GetPointer() %v expect %v", in, r1.GetPointer().String(), "/f/a/b") + } +} + +func TestFullURL(t *testing.T) { + + in := "http://host/path/a/b/c" + + r1, err := New(in) + if err != nil { + t.Errorf("New(%v) error %s", in, err.Error()) + } + + if in != r1.String() { + t.Errorf("New(%v) = %v, expect %v", in, r1.String(), in) + } + + if r1.HasFragmentOnly != false { + t.Errorf("New(%v)::HasFragmentOnly %v expect %v", in, r1.HasFragmentOnly, false) + } + + if r1.HasFullURL != true { + t.Errorf("New(%v)::HasFullURL %v expect %v", in, r1.HasFullURL, true) + } + + if r1.HasURLPathOnly != false { + t.Errorf("New(%v)::HasURLPathOnly %v expect %v", in, r1.HasURLPathOnly, false) + } + + if r1.HasFileScheme != false { + t.Errorf("New(%v)::HasFileScheme %v expect %v", in, r1.HasFileScheme, false) + } + + if r1.GetPointer().String() != "" { + t.Errorf("New(%v)::GetPointer() %v expect %v", in, r1.GetPointer().String(), "") + } +} + +func TestFragmentOnly(t *testing.T) { + + in := "#/fragment/only" + + r1, err := New(in) + if err != nil { + t.Errorf("New(%v) error %s", in, err.Error()) + } + + if in != r1.String() { + t.Errorf("New(%v) = %v, expect %v", in, r1.String(), in) + } + + if r1.HasFragmentOnly != true { + t.Errorf("New(%v)::HasFragmentOnly %v expect %v", in, r1.HasFragmentOnly, true) + } + + if r1.HasFullURL != false { + t.Errorf("New(%v)::HasFullURL %v expect %v", in, r1.HasFullURL, false) + } + + if r1.HasURLPathOnly != false { + t.Errorf("New(%v)::HasURLPathOnly %v expect %v", in, r1.HasURLPathOnly, false) + } + + if r1.HasFileScheme != false { + t.Errorf("New(%v)::HasFileScheme %v expect %v", in, r1.HasFileScheme, false) + } + + if r1.GetPointer().String() != "/fragment/only" { + t.Errorf("New(%v)::GetPointer() %v expect %v", in, r1.GetPointer().String(), "/fragment/only") + } + + p, _ := jsonpointer.New(r1.referenceURL.Fragment) + r2 := Ref{referencePointer: p, HasFragmentOnly: true} + assert.Equal(t, r2.String(), in) + + r3 := Ref{referencePointer: p, HasFragmentOnly: false} + assert.Equal(t, r3.String(), in[1:]) +} + +func TestURLPathOnly(t *testing.T) { + + in := "/documents/document.json" + + r1, err := New(in) + if err != nil { + t.Errorf("New(%v) error %s", in, err.Error()) + } + + if in != r1.String() { + t.Errorf("New(%v) = %v, expect %v", in, r1.String(), in) + } + + if r1.HasFragmentOnly != false { + t.Errorf("New(%v)::HasFragmentOnly %v expect %v", in, r1.HasFragmentOnly, false) + } + + if r1.HasFullURL != false { + t.Errorf("New(%v)::HasFullURL %v expect %v", in, r1.HasFullURL, false) + } + + if r1.HasURLPathOnly != true { + t.Errorf("New(%v)::HasURLPathOnly %v expect %v", in, r1.HasURLPathOnly, true) + } + + if r1.HasFileScheme != false { + t.Errorf("New(%v)::HasFileScheme %v expect %v", in, r1.HasFileScheme, false) + } + + if r1.GetPointer().String() != "" { + t.Errorf("New(%v)::GetPointer() %v expect %v", in, r1.GetPointer().String(), "") + } +} + +func TestURLRelativePathOnly(t *testing.T) { + + in := "document.json" + + r1, err := New(in) + if err != nil { + t.Errorf("New(%v) error %s", in, err.Error()) + } + + if in != r1.String() { + t.Errorf("New(%v) = %v, expect %v", in, r1.String(), in) + } + + if r1.HasFragmentOnly != false { + t.Errorf("New(%v)::HasFragmentOnly %v expect %v", in, r1.HasFragmentOnly, false) + } + + if r1.HasFullURL != false { + t.Errorf("New(%v)::HasFullURL %v expect %v", in, r1.HasFullURL, false) + } + + if r1.HasURLPathOnly != true { + t.Errorf("New(%v)::HasURLPathOnly %v expect %v", in, r1.HasURLPathOnly, true) + } + + if r1.HasFileScheme != false { + t.Errorf("New(%v)::HasFileScheme %v expect %v", in, r1.HasFileScheme, false) + } + + if r1.GetPointer().String() != "" { + t.Errorf("New(%v)::GetPointer() %v expect %v", in, r1.GetPointer().String(), "") + } +} + +func TestInheritsInValid(t *testing.T) { + in1 := "http://www.test.com/doc.json" + in2 := "#/a/b" + + r1, _ := New(in1) + r2 := Ref{} + result, err := r1.Inherits(r2) + assert.Error(t, err) + assert.Nil(t, result) + + r1 = Ref{} + r2, _ = New(in2) + result, err = r1.Inherits(r2) + assert.NoError(t, err) + assert.Equal(t, r2, *result) +} + +func TestInheritsValid(t *testing.T) { + + in1 := "http://www.test.com/doc.json" + in2 := "#/a/b" + out := in1 + in2 + + r1, _ := New(in1) + r2, _ := New(in2) + + result, err := r1.Inherits(r2) + if err != nil { + t.Errorf("Inherits(%s,%s) error %s", r1.String(), r2.String(), err.Error()) + } + + if result.String() != out { + t.Errorf("Inherits(%s,%s) = %s, expect %s", r1.String(), r2.String(), result.String(), out) + } + + if result.GetPointer().String() != "/a/b" { + t.Errorf("result(%v)::GetPointer() %v expect %v", result.String(), result.GetPointer().String(), "/a/b") + } +} + +func TestInheritsDifferentHost(t *testing.T) { + + in1 := "http://www.test.com/doc.json" + in2 := "http://www.test2.com/doc.json#bla" + + r1, _ := New(in1) + r2, _ := New(in2) + + result, err := r1.Inherits(r2) + + if err != nil { + t.Errorf("Inherits(%s,%s) should not fail. Error: %s", r1.String(), r2.String(), err.Error()) + } + + if result.String() != in2 { + t.Errorf("Inherits(%s,%s) should be %s but is %s", in1, in2, in2, result) + } + + if result.GetPointer().String() != "" { + t.Errorf("result(%v)::GetPointer() %v expect %v", result.String(), result.GetPointer().String(), "") + } +} + +func TestFileScheme(t *testing.T) { + + in1 := "file:///Users/mac/1.json#a" + in2 := "file:///Users/mac/2.json#b" + + r1, _ := New(in1) + r2, _ := New(in2) + + if r1.HasFragmentOnly != false { + t.Errorf("New(%v)::HasFragmentOnly %v expect %v", in1, r1.HasFragmentOnly, false) + } + + if r1.HasFileScheme != true { + t.Errorf("New(%v)::HasFileScheme %v expect %v", in1, r1.HasFileScheme, true) + } + + if r1.HasFullFilePath != true { + t.Errorf("New(%v)::HasFullFilePath %v expect %v", in1, r1.HasFullFilePath, true) + } + + if r1.IsCanonical() != true { + t.Errorf("New(%v)::IsCanonical %v expect %v", in1, r1.IsCanonical(), true) + } + + result, err := r1.Inherits(r2) + if err != nil { + t.Errorf("Inherits(%s,%s) should not fail. Error: %s", r1.String(), r2.String(), err.Error()) + } + if result.String() != in2 { + t.Errorf("Inherits(%s,%s) should be %s but is %s", in1, in2, in2, result) + } + + if result.GetPointer().String() != "" { + t.Errorf("result(%v)::GetPointer() %v expect %v", result.String(), result.GetPointer().String(), "") + } +} + +func TestReferenceResolution(t *testing.T) { + + // 5.4. Reference Resolution Examples + // http://tools.ietf.org/html/rfc3986#section-5.4 + + base := "http://a/b/c/d;p?q" + baseRef, err := New(base) + + if err != nil { + t.Errorf("New(%s) failed error: %s", base, err.Error()) + } + if baseRef.String() != base { + t.Errorf("New(%s) %s expected %s", base, baseRef.String(), base) + } + + checks := []string{ + // 5.4.1. Normal Examples + // http://tools.ietf.org/html/rfc3986#section-5.4.1 + + "g:h", "g:h", + "g", "http://a/b/c/g", + "./g", "http://a/b/c/g", + "g/", "http://a/b/c/g/", + "/g", "http://a/g", + "//g", "http://g", + "?y", "http://a/b/c/d;p?y", + "g?y", "http://a/b/c/g?y", + "#s", "http://a/b/c/d;p?q#s", + "g#s", "http://a/b/c/g#s", + "g?y#s", "http://a/b/c/g?y#s", + ";x", "http://a/b/c/;x", + "g;x", "http://a/b/c/g;x", + "g;x?y#s", "http://a/b/c/g;x?y#s", + "", "http://a/b/c/d;p?q", + ".", "http://a/b/c/", + "./", "http://a/b/c/", + "..", "http://a/b/", + "../", "http://a/b/", + "../g", "http://a/b/g", + "../..", "http://a/", + "../../", "http://a/", + "../../g", "http://a/g", + + // 5.4.2. Abnormal Examples + // http://tools.ietf.org/html/rfc3986#section-5.4.2 + + "../../../g", "http://a/g", + "../../../../g", "http://a/g", + + "/./g", "http://a/g", + "/../g", "http://a/g", + "g.", "http://a/b/c/g.", + ".g", "http://a/b/c/.g", + "g..", "http://a/b/c/g..", + "..g", "http://a/b/c/..g", + + "./../g", "http://a/b/g", + "./g/.", "http://a/b/c/g/", + "g/./h", "http://a/b/c/g/h", + "g/../h", "http://a/b/c/h", + "g;x=1/./y", "http://a/b/c/g;x=1/y", + "g;x=1/../y", "http://a/b/c/y", + + "g?y/./x", "http://a/b/c/g?y/./x", + "g?y/../x", "http://a/b/c/g?y/../x", + "g#s/./x", "http://a/b/c/g#s/./x", + "g#s/../x", "http://a/b/c/g#s/../x", + + "http:g", "http:g", // for strict parsers + //"http:g", "http://a/b/c/g", // for backward compatibility + + } + for i := 0; i < len(checks); i += 2 { + child := checks[i] + expected := checks[i+1] + // fmt.Printf("%d: %v -> %v\n", i/2, child, expected) + + childRef, e := New(child) + if e != nil { + t.Errorf("%d: New(%s) failed error: %s", i/2, child, e.Error()) + } + + res, e := baseRef.Inherits(childRef) + if res == nil { + t.Errorf("%d: Inherits(%s, %s) nil not expected", i/2, base, child) + } + if e != nil { + t.Errorf("%d: Inherits(%s) failed error: %s", i/2, child, e.Error()) + } + if res.String() != expected { + t.Errorf("%d: Inherits(%s, %s) %s expected %s", i/2, base, child, res.String(), expected) + } + } +} diff --git a/vendor/github.com/go-openapi/spec/.drone.sec b/vendor/github.com/go-openapi/spec/.drone.sec new file mode 100644 index 000000000..60c5ebe38 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.drone.sec @@ -0,0 +1 @@ +eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.Epk8dDFH8U1RPYIPDpajZO26L5zFJ1wnQNGWxVHHo5cXrWF148kENoZzh35FT9cAxxPS_4CeVVpf59EgvCc8bem1puuj0gBZptn-lYa7iXZdI-ESN2Te7nF5VbZfwbnI62nEikYGyxz-ozL_IFuMl-qWek4iLerF8Z_xh0MZOJ_w8Nog7qb2WQov72d997TJv5ZKjWcRYPbnsAy1q60-Cqxq3a6enhcSPXqpK46nYSXGKfHvognWBJ_pxwkEqIBPN6hE4EfNtJjMf2LFKEdYy02nbHz78d-2YZ8wIUSJ-IWIwn3GTzObdGqRed20Qf3JtWTsOespmexDrLSeo3HW6A.7XaHW-Y1jjRAWt_W.S1Adut62RLOYZc-lN02M0MGczEucch3zIr4J1UPBPnZooWzntiE5UaUz0UdhjHVszQE5hTfG-yocKD1rDQGER6qrLtnJVrCm9J3n4lHglM-xOz1eZln1XKrWcAgZnAKaKSzuAa5scPG4iTHW6RwbWi_PWm04tBJ1yazdjaVo3uvuhflwvU9if7uMPMtscrDesbBVvpG89xmeudiFjX-wjsV5oGBIjz6ukEBAMKzNDMqikNoG4SnGenpxUpjUjMkDXxiC3BC8oL2_myeIfFeEOF066DqEN3CLkqBVO25zdpWAF4Ou2jKv--mgGEb_E1aMgiSoAVBnybene0TKn2IJ8rtkyRdmWlLIRKZdDT3v775C1FPK6-tYzS7NVg9nnuvpta5PhzYNkqI1Ie74Sl0I-RFClhsdx9dLDhoFEKCx2etC4UDX9jhj2u0Y2MrL76dRGE9kEV1hL1fh6HMvS4ZAAWw3Qce4skCjcL-2YyIOHzKjgLGkZsR5cTUQwCJyacVkdHUOUKFdDGZaUzWkFyeZ1oyrlG2d52svaplpU5-vCOVbWkqUN9rOALGPTC51Ur0L7DFx29aDImhaxZqTe2t9mcdqY7VLcO3JgUiD3JKsEet7s2EDeN44MqITv9KBS8wqJW4.sRv4ov0wB0IxTHw90kJy-A \ No newline at end of file diff --git a/vendor/github.com/go-openapi/spec/.drone.yml b/vendor/github.com/go-openapi/spec/.drone.yml new file mode 100644 index 000000000..6d0442737 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.drone.yml @@ -0,0 +1,35 @@ +clone: + path: github.com/go-openapi/spec + +matrix: + GO_VERSION: + - "1.6" + +build: + integration: + image: golang:$$GO_VERSION + pull: true + commands: + - go get -u github.com/stretchr/testify/assert + - go get -u gopkg.in/yaml.v2 + - go get -u github.com/go-openapi/swag + - go get -u github.com/go-openapi/jsonpointer + - go get -u github.com/go-openapi/jsonreference + - go test -race + - go test -v -cover -coverprofile=coverage.out -covermode=count ./... + +notify: + slack: + channel: bots + webhook_url: $$SLACK_URL + username: drone + +publish: + coverage: + server: https://coverage.vmware.run + token: $$GITHUB_TOKEN + # threshold: 70 + # must_increase: true + when: + matrix: + GO_VERSION: "1.6" diff --git a/vendor/github.com/go-openapi/spec/.gitignore b/vendor/github.com/go-openapi/spec/.gitignore new file mode 100644 index 000000000..dd91ed6a0 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.gitignore @@ -0,0 +1,2 @@ +secrets.yml +coverage.out diff --git a/vendor/github.com/go-openapi/spec/.pullapprove.yml b/vendor/github.com/go-openapi/spec/.pullapprove.yml new file mode 100644 index 000000000..5ec183e22 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/.pullapprove.yml @@ -0,0 +1,13 @@ +approve_by_comment: true +approve_regex: '^(:shipit:|:\+1:|\+1|LGTM|lgtm|Approved)' +reject_regex: ^[Rr]ejected +reset_on_push: false +reviewers: + members: + - casualjim + - chancez + - frapposelli + - vburenin + - pytlesk4 + name: pullapprove + required: 1 diff --git a/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/spec/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/spec/README.md b/vendor/github.com/go-openapi/spec/README.md new file mode 100644 index 000000000..4b2af124a --- /dev/null +++ b/vendor/github.com/go-openapi/spec/README.md @@ -0,0 +1,5 @@ +# OAI object model [![Build Status](https://ci.vmware.run/api/badges/go-openapi/spec/status.svg)](https://ci.vmware.run/go-openapi/spec) [![Coverage](https://coverage.vmware.run/badges/go-openapi/spec/coverage.svg)](https://coverage.vmware.run/go-openapi/spec) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/spec/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/spec?status.svg)](http://godoc.org/github.com/go-openapi/spec) + +The object model for OpenAPI specification documents \ No newline at end of file diff --git a/vendor/github.com/go-openapi/spec/auth_test.go b/vendor/github.com/go-openapi/spec/auth_test.go new file mode 100644 index 000000000..5449fdec9 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/auth_test.go @@ -0,0 +1,128 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "testing" +) + +func TestSerialization_AuthSerialization(t *testing.T) { + assertSerializeJSON(t, BasicAuth(), `{"type":"basic"}`) + + assertSerializeJSON(t, APIKeyAuth("api-key", "header"), `{"type":"apiKey","name":"api-key","in":"header"}`) + + assertSerializeJSON( + t, + OAuth2Implicit("http://foo.com/authorization"), + `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization"}`) + + assertSerializeJSON( + t, + OAuth2Password("http://foo.com/token"), + `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/token"}`) + + assertSerializeJSON(t, + OAuth2Application("http://foo.com/token"), + `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token"}`) + + assertSerializeJSON( + t, + OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token"), + `{"type":"oauth2","flow":"accessCode","authorizationUrl":"http://foo.com/authorization","tokenUrl":"http://foo.com/token"}`) + + auth1 := OAuth2Implicit("http://foo.com/authorization") + auth1.AddScope("email", "read your email") + assertSerializeJSON( + t, + auth1, + `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization","scopes":{"email":"read your email"}}`) + + auth2 := OAuth2Password("http://foo.com/authorization") + auth2.AddScope("email", "read your email") + assertSerializeJSON( + t, + auth2, + `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/authorization","scopes":{"email":"read your email"}}`) + + auth3 := OAuth2Application("http://foo.com/token") + auth3.AddScope("email", "read your email") + assertSerializeJSON( + t, + auth3, + `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) + + auth4 := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") + auth4.AddScope("email", "read your email") + assertSerializeJSON( + t, + auth4, + `{"type":"oauth2","flow":"accessCode","authorizationUrl":"http://foo.com/authorization","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) +} + +func TestSerialization_AuthDeserialization(t *testing.T) { + + assertParsesJSON(t, `{"type":"basic"}`, BasicAuth()) + + assertParsesJSON( + t, + `{"in":"header","name":"api-key","type":"apiKey"}`, + APIKeyAuth("api-key", "header")) + + assertParsesJSON( + t, + `{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","type":"oauth2"}`, + OAuth2Implicit("http://foo.com/authorization")) + + assertParsesJSON( + t, + `{"flow":"password","tokenUrl":"http://foo.com/token","type":"oauth2"}`, + OAuth2Password("http://foo.com/token")) + + assertParsesJSON( + t, + `{"flow":"application","tokenUrl":"http://foo.com/token","type":"oauth2"}`, + OAuth2Application("http://foo.com/token")) + + assertParsesJSON( + t, + `{"authorizationUrl":"http://foo.com/authorization","flow":"accessCode","tokenUrl":"http://foo.com/token","type":"oauth2"}`, + OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token")) + + auth1 := OAuth2Implicit("http://foo.com/authorization") + auth1.AddScope("email", "read your email") + assertParsesJSON(t, + `{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","scopes":{"email":"read your email"},"type":"oauth2"}`, + auth1) + + auth2 := OAuth2Password("http://foo.com/token") + auth2.AddScope("email", "read your email") + assertParsesJSON(t, + `{"flow":"password","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, + auth2) + + auth3 := OAuth2Application("http://foo.com/token") + auth3.AddScope("email", "read your email") + assertParsesJSON(t, + `{"flow":"application","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, + auth3) + + auth4 := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") + auth4.AddScope("email", "read your email") + assertParsesJSON( + t, + `{"authorizationUrl":"http://foo.com/authorization","flow":"accessCode","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, + auth4) + +} diff --git a/vendor/github.com/go-openapi/spec/contact_info_test.go b/vendor/github.com/go-openapi/spec/contact_info_test.go new file mode 100644 index 000000000..5e644d0f0 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/contact_info_test.go @@ -0,0 +1,37 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "testing" +) + +var contactInfoJSON = `{"name":"wordnik api team","url":"http://developer.wordnik.com","email":"some@mailayada.dkdkd"}` +var contactInfoYAML = `name: wordnik api team +url: http://developer.wordnik.com +email: some@mailayada.dkdkd +` +var contactInfo = ContactInfo{ + Name: "wordnik api team", + URL: "http://developer.wordnik.com", + Email: "some@mailayada.dkdkd", +} + +func TestIntegrationContactInfo(t *testing.T) { + assertSerializeJSON(t, contactInfo, contactInfoJSON) + assertSerializeYAML(t, contactInfo, contactInfoYAML) + assertParsesJSON(t, contactInfoJSON, contactInfo) + assertParsesYAML(t, contactInfoYAML, contactInfo) +} diff --git a/vendor/github.com/go-openapi/spec/expander_test.go b/vendor/github.com/go-openapi/spec/expander_test.go new file mode 100644 index 000000000..bd6eb9e38 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/expander_test.go @@ -0,0 +1,1098 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-openapi/jsonpointer" + "github.com/go-openapi/swag" + "github.com/stretchr/testify/assert" +) + +func jsonDoc(path string) (json.RawMessage, error) { + data, err := swag.LoadFromFileOrHTTP(path) + if err != nil { + return nil, err + } + return json.RawMessage(data), nil +} + +func TestSpecExpansion(t *testing.T) { + spec := new(Swagger) + // resolver, err := defaultSchemaLoader(spec, nil, nil) + // assert.NoError(t, err) + + err := ExpandSpec(spec) + assert.NoError(t, err) + + specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") + assert.NoError(t, err) + + spec = new(Swagger) + err = json.Unmarshal(specDoc, spec) + assert.NoError(t, err) + + pet := spec.Definitions["pet"] + errorModel := spec.Definitions["errorModel"] + petResponse := spec.Responses["petResponse"] + petResponse.Schema = &pet + stringResponse := spec.Responses["stringResponse"] + tagParam := spec.Parameters["tag"] + idParam := spec.Parameters["idParam"] + + err = ExpandSpec(spec) + assert.NoError(t, err) + + assert.Equal(t, tagParam, spec.Parameters["query"]) + assert.Equal(t, petResponse, spec.Responses["petResponse"]) + assert.Equal(t, petResponse, spec.Responses["anotherPet"]) + assert.Equal(t, pet, *spec.Responses["petResponse"].Schema) + assert.Equal(t, stringResponse, *spec.Paths.Paths["/"].Get.Responses.Default) + assert.Equal(t, petResponse, spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200]) + assert.Equal(t, pet, *spec.Paths.Paths["/pets"].Get.Responses.StatusCodeResponses[200].Schema.Items.Schema) + assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Get.Responses.Default.Schema) + assert.Equal(t, pet, spec.Definitions["petInput"].AllOf[0]) + assert.Equal(t, spec.Definitions["petInput"], *spec.Paths.Paths["/pets"].Post.Parameters[0].Schema) + assert.Equal(t, petResponse, spec.Paths.Paths["/pets"].Post.Responses.StatusCodeResponses[200]) + assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Post.Responses.Default.Schema) + pi := spec.Paths.Paths["/pets/{id}"] + assert.Equal(t, idParam, pi.Get.Parameters[0]) + assert.Equal(t, petResponse, pi.Get.Responses.StatusCodeResponses[200]) + assert.Equal(t, errorModel, *pi.Get.Responses.Default.Schema) + assert.Equal(t, idParam, pi.Delete.Parameters[0]) + assert.Equal(t, errorModel, *pi.Delete.Responses.Default.Schema) +} + +func TestResponseExpansion(t *testing.T) { + specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(specDoc, spec) + assert.NoError(t, err) + + resolver, err := defaultSchemaLoader(spec, nil, nil) + assert.NoError(t, err) + + resp := spec.Responses["anotherPet"] + expected := spec.Responses["petResponse"] + + err = expandResponse(&resp, resolver) + assert.NoError(t, err) + assert.Equal(t, expected, resp) + + resp2 := spec.Paths.Paths["/"].Get.Responses.Default + expected = spec.Responses["stringResponse"] + + err = expandResponse(resp2, resolver) + assert.NoError(t, err) + assert.Equal(t, expected, *resp2) + + resp = spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200] + expected = spec.Responses["petResponse"] + + err = expandResponse(&resp, resolver) + assert.NoError(t, err) + // assert.Equal(t, expected, resp) +} + +func TestIssue3(t *testing.T) { + spec := new(Swagger) + specDoc, err := jsonDoc("fixtures/expansion/overflow.json") + assert.NoError(t, err) + + err = json.Unmarshal(specDoc, spec) + assert.NoError(t, err) + + assert.NotPanics(t, func() { + err = ExpandSpec(spec) + assert.NoError(t, err) + }, "Calling expand spec with circular refs, should not panic!") +} + +func TestParameterExpansion(t *testing.T) { + paramDoc, err := jsonDoc("fixtures/expansion/params.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(paramDoc, spec) + assert.NoError(t, err) + + resolver, err := defaultSchemaLoader(spec, nil, nil) + assert.NoError(t, err) + + param := spec.Parameters["query"] + expected := spec.Parameters["tag"] + + err = expandParameter(¶m, resolver) + assert.NoError(t, err) + assert.Equal(t, expected, param) + + param = spec.Paths.Paths["/cars/{id}"].Parameters[0] + expected = spec.Parameters["id"] + + err = expandParameter(¶m, resolver) + assert.NoError(t, err) + assert.Equal(t, expected, param) +} + +func TestCircularRefsExpansion(t *testing.T) { + carsDoc, err := jsonDoc("fixtures/expansion/circularRefs.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(carsDoc, spec) + assert.NoError(t, err) + + resolver, err := defaultSchemaLoader(spec, nil, nil) + assert.NoError(t, err) + schema := spec.Definitions["car"] + + assert.NotPanics(t, func() { + _, err = expandSchema(schema, []string{"#/definitions/car"}, resolver) + assert.NoError(t, err) + }, "Calling expand schema with circular refs, should not panic!") +} + +func TestIssue415(t *testing.T) { + doc, err := jsonDoc("fixtures/expansion/clickmeter.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(doc, spec) + assert.NoError(t, err) + + assert.NotPanics(t, func() { + err = ExpandSpec(spec) + assert.NoError(t, err) + }, "Calling expand spec with response schemas that have circular refs, should not panic!") +} + +func TestCircularSpecExpansion(t *testing.T) { + doc, err := jsonDoc("fixtures/expansion/circularSpec.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(doc, spec) + assert.NoError(t, err) + + assert.NotPanics(t, func() { + err = ExpandSpec(spec) + assert.NoError(t, err) + }, "Calling expand spec with circular refs, should not panic!") +} + +func TestItemsExpansion(t *testing.T) { + carsDoc, err := jsonDoc("fixtures/expansion/schemas2.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(carsDoc, spec) + assert.NoError(t, err) + + resolver, err := defaultSchemaLoader(spec, nil, nil) + assert.NoError(t, err) + + schema := spec.Definitions["car"] + oldBrand := schema.Properties["brand"] + assert.NotEmpty(t, oldBrand.Items.Schema.Ref.String()) + assert.NotEqual(t, spec.Definitions["brand"], oldBrand) + + _, err = expandSchema(schema, []string{"#/definitions/car"}, resolver) + assert.NoError(t, err) + + newBrand := schema.Properties["brand"] + assert.Empty(t, newBrand.Items.Schema.Ref.String()) + assert.Equal(t, spec.Definitions["brand"], *newBrand.Items.Schema) + + schema = spec.Definitions["truck"] + assert.NotEmpty(t, schema.Items.Schema.Ref.String()) + + s, err := expandSchema(schema, []string{"#/definitions/truck"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Items.Schema.Ref.String()) + assert.Equal(t, spec.Definitions["car"], *schema.Items.Schema) + + sch := new(Schema) + _, err = expandSchema(*sch, []string{""}, resolver) + assert.NoError(t, err) + + schema = spec.Definitions["batch"] + s, err = expandSchema(schema, []string{"#/definitions/batch"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Items.Schema.Items.Schema.Ref.String()) + assert.Equal(t, *schema.Items.Schema.Items.Schema, spec.Definitions["brand"]) + + schema = spec.Definitions["batch2"] + s, err = expandSchema(schema, []string{"#/definitions/batch2"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Items.Schemas[0].Items.Schema.Ref.String()) + assert.Empty(t, schema.Items.Schemas[1].Items.Schema.Ref.String()) + assert.Equal(t, *schema.Items.Schemas[0].Items.Schema, spec.Definitions["brand"]) + assert.Equal(t, *schema.Items.Schemas[1].Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["allofBoth"] + s, err = expandSchema(schema, []string{"#/definitions/allofBoth"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AllOf[0].Items.Schema.Ref.String()) + assert.Empty(t, schema.AllOf[1].Items.Schema.Ref.String()) + assert.Equal(t, *schema.AllOf[0].Items.Schema, spec.Definitions["brand"]) + assert.Equal(t, *schema.AllOf[1].Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["anyofBoth"] + s, err = expandSchema(schema, []string{"#/definitions/anyofBoth"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AnyOf[0].Items.Schema.Ref.String()) + assert.Empty(t, schema.AnyOf[1].Items.Schema.Ref.String()) + assert.Equal(t, *schema.AnyOf[0].Items.Schema, spec.Definitions["brand"]) + assert.Equal(t, *schema.AnyOf[1].Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["oneofBoth"] + s, err = expandSchema(schema, []string{"#/definitions/oneofBoth"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.OneOf[0].Items.Schema.Ref.String()) + assert.Empty(t, schema.OneOf[1].Items.Schema.Ref.String()) + assert.Equal(t, *schema.OneOf[0].Items.Schema, spec.Definitions["brand"]) + assert.Equal(t, *schema.OneOf[1].Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["notSomething"] + s, err = expandSchema(schema, []string{"#/definitions/notSomething"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Not.Items.Schema.Ref.String()) + assert.Equal(t, *schema.Not.Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["withAdditional"] + s, err = expandSchema(schema, []string{"#/definitions/withAdditional"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AdditionalProperties.Schema.Items.Schema.Ref.String()) + assert.Equal(t, *schema.AdditionalProperties.Schema.Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["withAdditionalItems"] + s, err = expandSchema(schema, []string{"#/definitions/withAdditionalItems"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AdditionalItems.Schema.Items.Schema.Ref.String()) + assert.Equal(t, *schema.AdditionalItems.Schema.Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["withPattern"] + s, err = expandSchema(schema, []string{"#/definitions/withPattern"}, resolver) + schema = *s + assert.NoError(t, err) + prop := schema.PatternProperties["^x-ab"] + assert.Empty(t, prop.Items.Schema.Ref.String()) + assert.Equal(t, *prop.Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["deps"] + s, err = expandSchema(schema, []string{"#/definitions/deps"}, resolver) + schema = *s + assert.NoError(t, err) + prop2 := schema.Dependencies["something"] + assert.Empty(t, prop2.Schema.Items.Schema.Ref.String()) + assert.Equal(t, *prop2.Schema.Items.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["defined"] + s, err = expandSchema(schema, []string{"#/definitions/defined"}, resolver) + schema = *s + assert.NoError(t, err) + prop = schema.Definitions["something"] + assert.Empty(t, prop.Items.Schema.Ref.String()) + assert.Equal(t, *prop.Items.Schema, spec.Definitions["tag"]) +} + +func TestSchemaExpansion(t *testing.T) { + carsDoc, err := jsonDoc("fixtures/expansion/schemas1.json") + assert.NoError(t, err) + + spec := new(Swagger) + err = json.Unmarshal(carsDoc, spec) + assert.NoError(t, err) + + resolver, err := defaultSchemaLoader(spec, nil, nil) + assert.NoError(t, err) + + schema := spec.Definitions["car"] + oldBrand := schema.Properties["brand"] + assert.NotEmpty(t, oldBrand.Ref.String()) + assert.NotEqual(t, spec.Definitions["brand"], oldBrand) + + s, err := expandSchema(schema, []string{"#/definitions/car"}, resolver) + schema = *s + assert.NoError(t, err) + + newBrand := schema.Properties["brand"] + assert.Empty(t, newBrand.Ref.String()) + assert.Equal(t, spec.Definitions["brand"], newBrand) + + schema = spec.Definitions["truck"] + assert.NotEmpty(t, schema.Ref.String()) + + s, err = expandSchema(schema, []string{"#/definitions/truck"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Ref.String()) + assert.Equal(t, spec.Definitions["car"], schema) + + sch := new(Schema) + _, err = expandSchema(*sch, []string{""}, resolver) + assert.NoError(t, err) + + schema = spec.Definitions["batch"] + s, err = expandSchema(schema, []string{"#/definitions/batch"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Items.Schema.Ref.String()) + assert.Equal(t, *schema.Items.Schema, spec.Definitions["brand"]) + + schema = spec.Definitions["batch2"] + s, err = expandSchema(schema, []string{"#/definitions/batch2"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Items.Schemas[0].Ref.String()) + assert.Empty(t, schema.Items.Schemas[1].Ref.String()) + assert.Equal(t, schema.Items.Schemas[0], spec.Definitions["brand"]) + assert.Equal(t, schema.Items.Schemas[1], spec.Definitions["tag"]) + + schema = spec.Definitions["allofBoth"] + s, err = expandSchema(schema, []string{"#/definitions/allofBoth"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AllOf[0].Ref.String()) + assert.Empty(t, schema.AllOf[1].Ref.String()) + assert.Equal(t, schema.AllOf[0], spec.Definitions["brand"]) + assert.Equal(t, schema.AllOf[1], spec.Definitions["tag"]) + + schema = spec.Definitions["anyofBoth"] + s, err = expandSchema(schema, []string{"#/definitions/anyofBoth"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AnyOf[0].Ref.String()) + assert.Empty(t, schema.AnyOf[1].Ref.String()) + assert.Equal(t, schema.AnyOf[0], spec.Definitions["brand"]) + assert.Equal(t, schema.AnyOf[1], spec.Definitions["tag"]) + + schema = spec.Definitions["oneofBoth"] + s, err = expandSchema(schema, []string{"#/definitions/oneofBoth"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.OneOf[0].Ref.String()) + assert.Empty(t, schema.OneOf[1].Ref.String()) + assert.Equal(t, schema.OneOf[0], spec.Definitions["brand"]) + assert.Equal(t, schema.OneOf[1], spec.Definitions["tag"]) + + schema = spec.Definitions["notSomething"] + s, err = expandSchema(schema, []string{"#/definitions/notSomething"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.Not.Ref.String()) + assert.Equal(t, *schema.Not, spec.Definitions["tag"]) + + schema = spec.Definitions["withAdditional"] + s, err = expandSchema(schema, []string{"#/definitions/withAdditional"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AdditionalProperties.Schema.Ref.String()) + assert.Equal(t, *schema.AdditionalProperties.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["withAdditionalItems"] + s, err = expandSchema(schema, []string{"#/definitions/withAdditionalItems"}, resolver) + schema = *s + assert.NoError(t, err) + assert.Empty(t, schema.AdditionalItems.Schema.Ref.String()) + assert.Equal(t, *schema.AdditionalItems.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["withPattern"] + s, err = expandSchema(schema, []string{"#/definitions/withPattern"}, resolver) + schema = *s + assert.NoError(t, err) + prop := schema.PatternProperties["^x-ab"] + assert.Empty(t, prop.Ref.String()) + assert.Equal(t, prop, spec.Definitions["tag"]) + + schema = spec.Definitions["deps"] + s, err = expandSchema(schema, []string{"#/definitions/deps"}, resolver) + schema = *s + assert.NoError(t, err) + prop2 := schema.Dependencies["something"] + assert.Empty(t, prop2.Schema.Ref.String()) + assert.Equal(t, *prop2.Schema, spec.Definitions["tag"]) + + schema = spec.Definitions["defined"] + s, err = expandSchema(schema, []string{"#/definitions/defined"}, resolver) + schema = *s + assert.NoError(t, err) + prop = schema.Definitions["something"] + assert.Empty(t, prop.Ref.String()) + assert.Equal(t, prop, spec.Definitions["tag"]) + +} + +func TestDefaultResolutionCache(t *testing.T) { + + cache := initResolutionCache() + + sch, ok := cache.Get("not there") + assert.False(t, ok) + assert.Nil(t, sch) + + sch, ok = cache.Get("http://swagger.io/v2/schema.json") + assert.True(t, ok) + assert.Equal(t, swaggerSchema, sch) + + sch, ok = cache.Get("http://json-schema.org/draft-04/schema") + assert.True(t, ok) + assert.Equal(t, jsonSchema, sch) + + cache.Set("something", "here") + sch, ok = cache.Get("something") + assert.True(t, ok) + assert.Equal(t, "here", sch) +} + +func resolutionContextServer() *httptest.Server { + var servedAt string + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + // fmt.Println("got a request for", req.URL.String()) + if req.URL.Path == "/resolution.json" { + + b, _ := ioutil.ReadFile("fixtures/specs/resolution.json") + var ctnt map[string]interface{} + json.Unmarshal(b, &ctnt) + ctnt["id"] = servedAt + + rw.Header().Set("Content-Type", "application/json") + rw.WriteHeader(200) + bb, _ := json.Marshal(ctnt) + rw.Write(bb) + return + } + if req.URL.Path == "/resolution2.json" { + b, _ := ioutil.ReadFile("fixtures/specs/resolution2.json") + var ctnt map[string]interface{} + json.Unmarshal(b, &ctnt) + ctnt["id"] = servedAt + + rw.Header().Set("Content-Type", "application/json") + rw.WriteHeader(200) + bb, _ := json.Marshal(ctnt) + rw.Write(bb) + return + } + + if req.URL.Path == "/boolProp.json" { + rw.Header().Set("Content-Type", "application/json") + rw.WriteHeader(200) + b, _ := json.Marshal(map[string]interface{}{ + "type": "boolean", + }) + rw.Write(b) + return + } + + if req.URL.Path == "/deeper/stringProp.json" { + rw.Header().Set("Content-Type", "application/json") + rw.WriteHeader(200) + b, _ := json.Marshal(map[string]interface{}{ + "type": "string", + }) + rw.Write(b) + return + } + + if req.URL.Path == "/deeper/arrayProp.json" { + rw.Header().Set("Content-Type", "application/json") + rw.WriteHeader(200) + b, _ := json.Marshal(map[string]interface{}{ + "type": "array", + "items": map[string]interface{}{ + "type": "file", + }, + }) + rw.Write(b) + return + } + + rw.WriteHeader(http.StatusNotFound) + })) + servedAt = server.URL + return server +} + +func TestResolveRemoteRef_RootSame(t *testing.T) { + specs := "fixtures/specs" + fileserver := http.FileServer(http.Dir(specs)) + server := httptest.NewServer(fileserver) + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var result Swagger + ref, _ := NewRef(server.URL + "/refed.json#") + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &result)) { + assertSpecs(t, result, *rootDoc) + } + } +} + +func TestResolveRemoteRef_FromFragment(t *testing.T) { + specs := "fixtures/specs" + fileserver := http.FileServer(http.Dir(specs)) + server := httptest.NewServer(fileserver) + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Schema + ref, err := NewRef(server.URL + "/refed.json#/definitions/pet") + if assert.NoError(t, err) { + resolver := &schemaLoader{root: rootDoc, cache: initResolutionCache(), loadDoc: jsonDoc} + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, []string{"id", "name"}, tgt.Required) + } + } + } +} + +func TestResolveRemoteRef_FromInvalidFragment(t *testing.T) { + specs := "fixtures/specs" + fileserver := http.FileServer(http.Dir(specs)) + server := httptest.NewServer(fileserver) + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Schema + ref, err := NewRef(server.URL + "/refed.json#/definitions/NotThere") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + assert.Error(t, resolver.Resolve(&ref, &tgt)) + } + } +} + +func TestResolveRemoteRef_WithResolutionContext(t *testing.T) { + server := resolutionContextServer() + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Schema + ref, err := NewRef(server.URL + "/resolution.json#/definitions/bool") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, StringOrArray([]string{"boolean"}), tgt.Type) + } + } + } +} + +func TestResolveRemoteRef_WithNestedResolutionContext(t *testing.T) { + server := resolutionContextServer() + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Schema + ref, err := NewRef(server.URL + "/resolution.json#/items/items") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, StringOrArray([]string{"string"}), tgt.Type) + } + } + } +} + +func TestResolveRemoteRef_WithNestedResolutionContextWithFragment(t *testing.T) { + server := resolutionContextServer() + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Schema + ref, err := NewRef(server.URL + "/resolution2.json#/items/items") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, StringOrArray([]string{"file"}), tgt.Type) + } + } + } +} + +func TestResolveRemoteRef_ToParameter(t *testing.T) { + specs := "fixtures/specs" + fileserver := http.FileServer(http.Dir(specs)) + server := httptest.NewServer(fileserver) + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Parameter + ref, err := NewRef(server.URL + "/refed.json#/parameters/idParam") + if assert.NoError(t, err) { + + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, "id", tgt.Name) + assert.Equal(t, "path", tgt.In) + assert.Equal(t, "ID of pet to fetch", tgt.Description) + assert.True(t, tgt.Required) + assert.Equal(t, "integer", tgt.Type) + assert.Equal(t, "int64", tgt.Format) + } + } + } +} + +func TestResolveRemoteRef_ToPathItem(t *testing.T) { + specs := "fixtures/specs" + fileserver := http.FileServer(http.Dir(specs)) + server := httptest.NewServer(fileserver) + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt PathItem + ref, err := NewRef(server.URL + "/refed.json#/paths/" + jsonpointer.Escape("/pets/{id}")) + if assert.NoError(t, err) { + + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) + } + } + } +} + +func TestResolveRemoteRef_ToResponse(t *testing.T) { + specs := "fixtures/specs" + fileserver := http.FileServer(http.Dir(specs)) + server := httptest.NewServer(fileserver) + defer server.Close() + + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Response + ref, err := NewRef(server.URL + "/refed.json#/responses/petResponse") + if assert.NoError(t, err) { + + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, rootDoc.Responses["petResponse"], tgt) + } + } + } +} + +func TestResolveLocalRef_SameRoot(t *testing.T) { + rootDoc := new(Swagger) + json.Unmarshal(PetStoreJSONMessage, rootDoc) + + result := new(Swagger) + ref, _ := NewRef("#") + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + err := resolver.Resolve(&ref, result) + if assert.NoError(t, err) { + assert.Equal(t, rootDoc, result) + } +} + +func TestResolveLocalRef_FromFragment(t *testing.T) { + rootDoc := new(Swagger) + json.Unmarshal(PetStoreJSONMessage, rootDoc) + + var tgt Schema + ref, err := NewRef("#/definitions/Category") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + err := resolver.Resolve(&ref, &tgt) + if assert.NoError(t, err) { + assert.Equal(t, "Category", tgt.ID) + } + } +} + +func TestResolveLocalRef_FromInvalidFragment(t *testing.T) { + rootDoc := new(Swagger) + json.Unmarshal(PetStoreJSONMessage, rootDoc) + + var tgt Schema + ref, err := NewRef("#/definitions/NotThere") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + err := resolver.Resolve(&ref, &tgt) + assert.Error(t, err) + } +} + +func TestResolveLocalRef_Parameter(t *testing.T) { + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Parameter + ref, err := NewRef("#/parameters/idParam") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, "id", tgt.Name) + assert.Equal(t, "path", tgt.In) + assert.Equal(t, "ID of pet to fetch", tgt.Description) + assert.True(t, tgt.Required) + assert.Equal(t, "integer", tgt.Type) + assert.Equal(t, "int64", tgt.Format) + } + } + } +} + +func TestResolveLocalRef_PathItem(t *testing.T) { + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt PathItem + ref, err := NewRef("#/paths/" + jsonpointer.Escape("/pets/{id}")) + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) + } + } + } +} + +func TestResolveLocalRef_Response(t *testing.T) { + rootDoc := new(Swagger) + b, err := ioutil.ReadFile("fixtures/specs/refed.json") + if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { + var tgt Response + ref, err := NewRef("#/responses/petResponse") + if assert.NoError(t, err) { + resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) + if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { + assert.Equal(t, rootDoc.Responses["petResponse"], tgt) + } + } + } +} + +// PetStoreJSONMessage json raw message for Petstore20 +var PetStoreJSONMessage = json.RawMessage([]byte(PetStore20)) + +// PetStore20 json doc for swagger 2.0 pet store +const PetStore20 = `{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "contact": { + "name": "Wordnik API Team", + "url": "http://developer.wordnik.com" + }, + "license": { + "name": "Creative Commons 4.0 International", + "url": "http://creativecommons.org/licenses/by/4.0/" + } + }, + "host": "petstore.swagger.wordnik.com", + "basePath": "/api", + "schemes": [ + "http" + ], + "paths": { + "/pets": { + "get": { + "security": [ + { + "basic": [] + } + ], + "tags": [ "Pet Operations" ], + "operationId": "getAllPets", + "parameters": [ + { + "name": "status", + "in": "query", + "description": "The status to filter by", + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "The maximum number of results to return", + "type": "integer", + "format": "int64" + } + ], + "summary": "Finds all pets in the system", + "responses": { + "200": { + "description": "Pet response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + }, + "default": { + "description": "Unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "post": { + "security": [ + { + "basic": [] + } + ], + "tags": [ "Pet Operations" ], + "operationId": "createPet", + "summary": "Creates a new pet", + "consumes": ["application/x-yaml"], + "produces": ["application/x-yaml"], + "parameters": [ + { + "name": "pet", + "in": "body", + "description": "The Pet to create", + "required": true, + "schema": { + "$ref": "#/definitions/newPet" + } + } + ], + "responses": { + "200": { + "description": "Created Pet response", + "schema": { + "$ref": "#/definitions/Pet" + } + }, + "default": { + "description": "Unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/pets/{id}": { + "delete": { + "security": [ + { + "apiKey": [] + } + ], + "description": "Deletes the Pet by id", + "operationId": "deletePet", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of pet to delete", + "required": true, + "type": "integer", + "format": "int64" + } + ], + "responses": { + "204": { + "description": "pet deleted" + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "get": { + "tags": [ "Pet Operations" ], + "operationId": "getPetById", + "summary": "Finds the pet by id", + "responses": { + "200": { + "description": "Pet response", + "schema": { + "$ref": "#/definitions/Pet" + } + }, + "default": { + "description": "Unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of pet", + "required": true, + "type": "integer", + "format": "int64" + } + ] + } + }, + "definitions": { + "Category": { + "id": "Category", + "properties": { + "id": { + "format": "int64", + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "Pet": { + "id": "Pet", + "properties": { + "category": { + "$ref": "#/definitions/Category" + }, + "id": { + "description": "unique identifier for the pet", + "format": "int64", + "maximum": 100.0, + "minimum": 0.0, + "type": "integer" + }, + "name": { + "type": "string" + }, + "photoUrls": { + "items": { + "type": "string" + }, + "type": "array" + }, + "status": { + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ], + "type": "string" + }, + "tags": { + "items": { + "$ref": "#/definitions/Tag" + }, + "type": "array" + } + }, + "required": [ + "id", + "name" + ] + }, + "newPet": { + "anyOf": [ + { + "$ref": "#/definitions/Pet" + }, + { + "required": [ + "name" + ] + } + ] + }, + "Tag": { + "id": "Tag", + "properties": { + "id": { + "format": "int64", + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "Error": { + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + } + }, + "consumes": [ + "application/json", + "application/xml" + ], + "produces": [ + "application/json", + "application/xml", + "text/plain", + "text/html" + ], + "securityDefinitions": { + "basic": { + "type": "basic" + }, + "apiKey": { + "type": "apiKey", + "in": "header", + "name": "X-API-KEY" + } + } +} +` diff --git a/vendor/github.com/go-openapi/spec/external_docs_test.go b/vendor/github.com/go-openapi/spec/external_docs_test.go new file mode 100644 index 000000000..14c5ef156 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/external_docs_test.go @@ -0,0 +1,29 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "testing" +) + +func TestIntegrationExternalDocs(t *testing.T) { + var extDocs = ExternalDocumentation{"the name", "the url"} + const extDocsYAML = "description: the name\nurl: the url\n" + const extDocsJSON = `{"description":"the name","url":"the url"}` + assertSerializeJSON(t, extDocs, extDocsJSON) + assertSerializeYAML(t, extDocs, extDocsYAML) + assertParsesJSON(t, extDocsJSON, extDocs) + assertParsesYAML(t, extDocsYAML, extDocs) +} diff --git a/vendor/github.com/go-openapi/spec/header_test.go b/vendor/github.com/go-openapi/spec/header_test.go new file mode 100644 index 000000000..e87ac0666 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/header_test.go @@ -0,0 +1,86 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func float64Ptr(f float64) *float64 { + return &f +} +func int64Ptr(f int64) *int64 { + return &f +} + +var header = Header{ + HeaderProps: HeaderProps{Description: "the description of this header"}, + SimpleSchema: SimpleSchema{ + Items: &Items{ + Refable: Refable{Ref: MustCreateRef("Cat")}, + }, + Type: "string", + Format: "date", + Default: "8", + }, + CommonValidations: CommonValidations{ + Maximum: float64Ptr(100), + ExclusiveMaximum: true, + ExclusiveMinimum: true, + Minimum: float64Ptr(5), + MaxLength: int64Ptr(100), + MinLength: int64Ptr(5), + Pattern: "\\w{1,5}\\w+", + MaxItems: int64Ptr(100), + MinItems: int64Ptr(5), + UniqueItems: true, + MultipleOf: float64Ptr(5), + Enum: []interface{}{"hello", "world"}, + }, +} + +var headerJSON = `{ + "items": { + "$ref": "Cat" + }, + "description": "the description of this header", + "maximum": 100, + "minimum": 5, + "exclusiveMaximum": true, + "exclusiveMinimum": true, + "maxLength": 100, + "minLength": 5, + "pattern": "\\w{1,5}\\w+", + "maxItems": 100, + "minItems": 5, + "uniqueItems": true, + "multipleOf": 5, + "enum": ["hello", "world"], + "type": "string", + "format": "date", + "default": "8" +}` + +func TestIntegrationHeader(t *testing.T) { + var actual Header + if assert.NoError(t, json.Unmarshal([]byte(headerJSON), &actual)) { + assert.EqualValues(t, actual, header) + } + + assertParsesJSON(t, headerJSON, header) +} diff --git a/vendor/github.com/go-openapi/spec/info_test.go b/vendor/github.com/go-openapi/spec/info_test.go new file mode 100644 index 000000000..fc40c1630 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/info_test.go @@ -0,0 +1,65 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var infoJSON = `{ + "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", + "title": "Swagger Sample API", + "termsOfService": "http://helloreverb.com/terms/", + "contact": { + "name": "wordnik api team", + "url": "http://developer.wordnik.com" + }, + "license": { + "name": "Creative Commons 4.0 International", + "url": "http://creativecommons.org/licenses/by/4.0/" + }, + "version": "1.0.9-abcd", + "x-framework": "go-swagger" +}` + +var info = Info{ + InfoProps: InfoProps{ + Version: "1.0.9-abcd", + Title: "Swagger Sample API", + Description: "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", + TermsOfService: "http://helloreverb.com/terms/", + Contact: &ContactInfo{Name: "wordnik api team", URL: "http://developer.wordnik.com"}, + License: &License{Name: "Creative Commons 4.0 International", URL: "http://creativecommons.org/licenses/by/4.0/"}, + }, + VendorExtensible: VendorExtensible{map[string]interface{}{"x-framework": "go-swagger"}}, +} + +func TestIntegrationInfo_Serialize(t *testing.T) { + b, err := json.MarshalIndent(info, "", "\t") + if assert.NoError(t, err) { + assert.Equal(t, infoJSON, string(b)) + } +} + +func TestIntegrationInfo_Deserialize(t *testing.T) { + actual := Info{} + err := json.Unmarshal([]byte(infoJSON), &actual) + if assert.NoError(t, err) { + assert.EqualValues(t, info, actual) + } +} diff --git a/vendor/github.com/go-openapi/spec/items_test.go b/vendor/github.com/go-openapi/spec/items_test.go new file mode 100644 index 000000000..2f9ac11b4 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/items_test.go @@ -0,0 +1,81 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var items = Items{ + Refable: Refable{Ref: MustCreateRef("Dog")}, + CommonValidations: CommonValidations{ + Maximum: float64Ptr(100), + ExclusiveMaximum: true, + ExclusiveMinimum: true, + Minimum: float64Ptr(5), + MaxLength: int64Ptr(100), + MinLength: int64Ptr(5), + Pattern: "\\w{1,5}\\w+", + MaxItems: int64Ptr(100), + MinItems: int64Ptr(5), + UniqueItems: true, + MultipleOf: float64Ptr(5), + Enum: []interface{}{"hello", "world"}, + }, + SimpleSchema: SimpleSchema{ + Type: "string", + Format: "date", + Items: &Items{ + Refable: Refable{Ref: MustCreateRef("Cat")}, + }, + CollectionFormat: "csv", + Default: "8", + }, +} + +var itemsJSON = `{ + "items": { + "$ref": "Cat" + }, + "$ref": "Dog", + "maximum": 100, + "minimum": 5, + "exclusiveMaximum": true, + "exclusiveMinimum": true, + "maxLength": 100, + "minLength": 5, + "pattern": "\\w{1,5}\\w+", + "maxItems": 100, + "minItems": 5, + "uniqueItems": true, + "multipleOf": 5, + "enum": ["hello", "world"], + "type": "string", + "format": "date", + "collectionFormat": "csv", + "default": "8" +}` + +func TestIntegrationItems(t *testing.T) { + var actual Items + if assert.NoError(t, json.Unmarshal([]byte(itemsJSON), &actual)) { + assert.EqualValues(t, actual, items) + } + + assertParsesJSON(t, itemsJSON, items) +} diff --git a/vendor/github.com/go-openapi/spec/license_test.go b/vendor/github.com/go-openapi/spec/license_test.go new file mode 100644 index 000000000..8ed51a352 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/license_test.go @@ -0,0 +1,28 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import "testing" + +func TestIntegrationLicense(t *testing.T) { + license := License{"the name", "the url"} + const licenseJSON = `{"name":"the name","url":"the url"}` + const licenseYAML = "name: the name\nurl: the url\n" + + assertSerializeJSON(t, license, licenseJSON) + assertSerializeYAML(t, license, licenseYAML) + assertParsesJSON(t, licenseJSON, license) + assertParsesYAML(t, licenseYAML, license) +} diff --git a/vendor/github.com/go-openapi/spec/operation_test.go b/vendor/github.com/go-openapi/spec/operation_test.go new file mode 100644 index 000000000..113bf6c06 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/operation_test.go @@ -0,0 +1,85 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var operation = Operation{ + VendorExtensible: VendorExtensible{ + Extensions: map[string]interface{}{ + "x-framework": "go-swagger", + }, + }, + OperationProps: OperationProps{ + Description: "operation description", + Consumes: []string{"application/json", "application/x-yaml"}, + Produces: []string{"application/json", "application/x-yaml"}, + Schemes: []string{"http", "https"}, + Tags: []string{"dogs"}, + Summary: "the summary of the operation", + ID: "sendCat", + Deprecated: true, + Security: []map[string][]string{ + map[string][]string{ + "apiKey": []string{}, + }, + }, + Parameters: []Parameter{ + Parameter{Refable: Refable{Ref: MustCreateRef("Cat")}}, + }, + Responses: &Responses{ + ResponsesProps: ResponsesProps{ + Default: &Response{ + ResponseProps: ResponseProps{ + Description: "void response", + }, + }, + }, + }, + }, +} + +var operationJSON = `{ + "description": "operation description", + "x-framework": "go-swagger", + "consumes": [ "application/json", "application/x-yaml" ], + "produces": [ "application/json", "application/x-yaml" ], + "schemes": ["http", "https"], + "tags": ["dogs"], + "summary": "the summary of the operation", + "operationId": "sendCat", + "deprecated": true, + "security": [ { "apiKey": [] } ], + "parameters": [{"$ref":"Cat"}], + "responses": { + "default": { + "description": "void response" + } + } +}` + +func TestIntegrationOperation(t *testing.T) { + var actual Operation + if assert.NoError(t, json.Unmarshal([]byte(operationJSON), &actual)) { + assert.EqualValues(t, actual, operation) + } + + assertParsesJSON(t, operationJSON, operation) +} diff --git a/vendor/github.com/go-openapi/spec/parameters_test.go b/vendor/github.com/go-openapi/spec/parameters_test.go new file mode 100644 index 000000000..424f66332 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/parameters_test.go @@ -0,0 +1,156 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var parameter = Parameter{ + VendorExtensible: VendorExtensible{Extensions: map[string]interface{}{ + "x-framework": "swagger-go", + }}, + Refable: Refable{Ref: MustCreateRef("Dog")}, + CommonValidations: CommonValidations{ + Maximum: float64Ptr(100), + ExclusiveMaximum: true, + ExclusiveMinimum: true, + Minimum: float64Ptr(5), + MaxLength: int64Ptr(100), + MinLength: int64Ptr(5), + Pattern: "\\w{1,5}\\w+", + MaxItems: int64Ptr(100), + MinItems: int64Ptr(5), + UniqueItems: true, + MultipleOf: float64Ptr(5), + Enum: []interface{}{"hello", "world"}, + }, + SimpleSchema: SimpleSchema{ + Type: "string", + Format: "date", + CollectionFormat: "csv", + Items: &Items{ + Refable: Refable{Ref: MustCreateRef("Cat")}, + }, + Default: "8", + }, + ParamProps: ParamProps{ + Name: "param-name", + In: "header", + Required: true, + Schema: &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + Description: "the description of this parameter", + }, +} + +var parameterJSON = `{ + "items": { + "$ref": "Cat" + }, + "x-framework": "swagger-go", + "$ref": "Dog", + "description": "the description of this parameter", + "maximum": 100, + "minimum": 5, + "exclusiveMaximum": true, + "exclusiveMinimum": true, + "maxLength": 100, + "minLength": 5, + "pattern": "\\w{1,5}\\w+", + "maxItems": 100, + "minItems": 5, + "uniqueItems": true, + "multipleOf": 5, + "enum": ["hello", "world"], + "type": "string", + "format": "date", + "name": "param-name", + "in": "header", + "required": true, + "schema": { + "type": "string" + }, + "collectionFormat": "csv", + "default": "8" +}` + +func TestIntegrationParameter(t *testing.T) { + var actual Parameter + if assert.NoError(t, json.Unmarshal([]byte(parameterJSON), &actual)) { + assert.EqualValues(t, actual, parameter) + } + + assertParsesJSON(t, parameterJSON, parameter) +} + +func TestParameterSerialization(t *testing.T) { + items := &Items{ + SimpleSchema: SimpleSchema{Type: "string"}, + } + + intItems := &Items{ + SimpleSchema: SimpleSchema{Type: "int", Format: "int32"}, + } + + assertSerializeJSON(t, QueryParam("").Typed("string", ""), `{"type":"string","in":"query"}`) + + assertSerializeJSON(t, + QueryParam("").CollectionOf(items, "multi"), + `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"query"}`) + + assertSerializeJSON(t, PathParam("").Typed("string", ""), `{"type":"string","in":"path","required":true}`) + + assertSerializeJSON(t, + PathParam("").CollectionOf(items, "multi"), + `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"path","required":true}`) + + assertSerializeJSON(t, + PathParam("").CollectionOf(intItems, "multi"), + `{"type":"array","items":{"type":"int","format":"int32"},"collectionFormat":"multi","in":"path","required":true}`) + + assertSerializeJSON(t, HeaderParam("").Typed("string", ""), `{"type":"string","in":"header","required":true}`) + + assertSerializeJSON(t, + HeaderParam("").CollectionOf(items, "multi"), + `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"header","required":true}`) + schema := &Schema{SchemaProps: SchemaProps{ + Properties: map[string]Schema{ + "name": Schema{SchemaProps: SchemaProps{ + Type: []string{"string"}, + }}, + }, + }} + + refSchema := &Schema{ + SchemaProps: SchemaProps{Ref: MustCreateRef("Cat")}, + } + + assertSerializeJSON(t, + BodyParam("", schema), + `{"type":"object","in":"body","schema":{"properties":{"name":{"type":"string"}}}}`) + + assertSerializeJSON(t, + BodyParam("", refSchema), + `{"type":"object","in":"body","schema":{"$ref":"Cat"}}`) + + // array body param + assertSerializeJSON(t, + BodyParam("", ArrayProperty(RefProperty("Cat"))), + `{"type":"object","in":"body","schema":{"type":"array","items":{"$ref":"Cat"}}}`) + +} diff --git a/vendor/github.com/go-openapi/spec/path_item_test.go b/vendor/github.com/go-openapi/spec/path_item_test.go new file mode 100644 index 000000000..ea77e6a9b --- /dev/null +++ b/vendor/github.com/go-openapi/spec/path_item_test.go @@ -0,0 +1,81 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var pathItem = PathItem{ + Refable: Refable{Ref: MustCreateRef("Dog")}, + VendorExtensible: VendorExtensible{ + Extensions: map[string]interface{}{ + "x-framework": "go-swagger", + }, + }, + PathItemProps: PathItemProps{ + Get: &Operation{ + OperationProps: OperationProps{Description: "get operation description"}, + }, + Put: &Operation{ + OperationProps: OperationProps{Description: "put operation description"}, + }, + Post: &Operation{ + OperationProps: OperationProps{Description: "post operation description"}, + }, + Delete: &Operation{ + OperationProps: OperationProps{Description: "delete operation description"}, + }, + Options: &Operation{ + OperationProps: OperationProps{Description: "options operation description"}, + }, + Head: &Operation{ + OperationProps: OperationProps{Description: "head operation description"}, + }, + Patch: &Operation{ + OperationProps: OperationProps{Description: "patch operation description"}, + }, + Parameters: []Parameter{ + Parameter{ + ParamProps: ParamProps{In: "path"}, + }, + }, + }, +} + +var pathItemJSON = `{ + "$ref": "Dog", + "x-framework": "go-swagger", + "get": { "description": "get operation description" }, + "put": { "description": "put operation description" }, + "post": { "description": "post operation description" }, + "delete": { "description": "delete operation description" }, + "options": { "description": "options operation description" }, + "head": { "description": "head operation description" }, + "patch": { "description": "patch operation description" }, + "parameters": [{"in":"path"}] +}` + +func TestIntegrationPathItem(t *testing.T) { + var actual PathItem + if assert.NoError(t, json.Unmarshal([]byte(pathItemJSON), &actual)) { + assert.EqualValues(t, actual, pathItem) + } + + assertParsesJSON(t, pathItemJSON, pathItem) +} diff --git a/vendor/github.com/go-openapi/spec/paths_test.go b/vendor/github.com/go-openapi/spec/paths_test.go new file mode 100644 index 000000000..5ccfd4a0a --- /dev/null +++ b/vendor/github.com/go-openapi/spec/paths_test.go @@ -0,0 +1,43 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var paths = Paths{ + VendorExtensible: VendorExtensible{Extensions: map[string]interface{}{"x-framework": "go-swagger"}}, + Paths: map[string]PathItem{ + "/": PathItem{ + Refable: Refable{Ref: MustCreateRef("cats")}, + }, + }, +} + +var pathsJSON = `{"x-framework":"go-swagger","/":{"$ref":"cats"}}` + +func TestIntegrationPaths(t *testing.T) { + var actual Paths + if assert.NoError(t, json.Unmarshal([]byte(pathsJSON), &actual)) { + assert.EqualValues(t, actual, paths) + } + + assertParsesJSON(t, pathsJSON, paths) + +} diff --git a/vendor/github.com/go-openapi/spec/properties_test.go b/vendor/github.com/go-openapi/spec/properties_test.go new file mode 100644 index 000000000..90bd32c9e --- /dev/null +++ b/vendor/github.com/go-openapi/spec/properties_test.go @@ -0,0 +1,58 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "testing" +) + +func TestPropertySerialization(t *testing.T) { + strProp := StringProperty() + strProp.Enum = append(strProp.Enum, "a", "b") + + prop := &Schema{SchemaProps: SchemaProps{ + Items: &SchemaOrArray{Schemas: []Schema{ + Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + }}, + }} + + var propSerData = []struct { + Schema *Schema + JSON string + }{ + {BooleanProperty(), `{"type":"boolean"}`}, + {DateProperty(), `{"type":"string","format":"date"}`}, + {DateTimeProperty(), `{"type":"string","format":"date-time"}`}, + {Float64Property(), `{"type":"number","format":"double"}`}, + {Float32Property(), `{"type":"number","format":"float"}`}, + {Int32Property(), `{"type":"integer","format":"int32"}`}, + {Int64Property(), `{"type":"integer","format":"int64"}`}, + {MapProperty(StringProperty()), `{"type":"object","additionalProperties":{"type":"string"}}`}, + {MapProperty(Int32Property()), `{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}`}, + {RefProperty("Dog"), `{"$ref":"Dog"}`}, + {StringProperty(), `{"type":"string"}`}, + {strProp, `{"type":"string","enum":["a","b"]}`}, + {ArrayProperty(StringProperty()), `{"type":"array","items":{"type":"string"}}`}, + {prop, `{"items":[{"type":"string"},{"type":"string"}]}`}, + } + + for _, v := range propSerData { + t.Log("roundtripping for", v.JSON) + assertSerializeJSON(t, v.Schema, v.JSON) + assertParsesJSON(t, v.JSON, v.Schema) + } + +} diff --git a/vendor/github.com/go-openapi/spec/schema_test.go b/vendor/github.com/go-openapi/spec/schema_test.go new file mode 100644 index 000000000..2e49fbc15 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/schema_test.go @@ -0,0 +1,205 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +var schema = Schema{ + VendorExtensible: VendorExtensible{Extensions: map[string]interface{}{"x-framework": "go-swagger"}}, + SchemaProps: SchemaProps{ + Ref: MustCreateRef("Cat"), + Type: []string{"string"}, + Format: "date", + Description: "the description of this schema", + Title: "the title", + Default: "blah", + Maximum: float64Ptr(100), + ExclusiveMaximum: true, + ExclusiveMinimum: true, + Minimum: float64Ptr(5), + MaxLength: int64Ptr(100), + MinLength: int64Ptr(5), + Pattern: "\\w{1,5}\\w+", + MaxItems: int64Ptr(100), + MinItems: int64Ptr(5), + UniqueItems: true, + MultipleOf: float64Ptr(5), + Enum: []interface{}{"hello", "world"}, + MaxProperties: int64Ptr(5), + MinProperties: int64Ptr(1), + Required: []string{"id", "name"}, + Items: &SchemaOrArray{Schema: &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}}, + AllOf: []Schema{Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}}, + Properties: map[string]Schema{ + "id": Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}, + "name": Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + }, + AdditionalProperties: &SchemaOrBool{Allows: true, Schema: &Schema{SchemaProps: SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }}}, + }, + SwaggerSchemaProps: SwaggerSchemaProps{ + Discriminator: "not this", + ReadOnly: true, + XML: &XMLObject{"sch", "io", "sw", true, true}, + ExternalDocs: &ExternalDocumentation{ + Description: "the documentation etc", + URL: "http://readthedocs.org/swagger", + }, + Example: []interface{}{ + map[string]interface{}{ + "id": 1, + "name": "a book", + }, + map[string]interface{}{ + "id": 2, + "name": "the thing", + }, + }, + }, +} + +var schemaJSON = `{ + "x-framework": "go-swagger", + "$ref": "Cat", + "description": "the description of this schema", + "maximum": 100, + "minimum": 5, + "exclusiveMaximum": true, + "exclusiveMinimum": true, + "maxLength": 100, + "minLength": 5, + "pattern": "\\w{1,5}\\w+", + "maxItems": 100, + "minItems": 5, + "uniqueItems": true, + "multipleOf": 5, + "enum": ["hello", "world"], + "type": "string", + "format": "date", + "title": "the title", + "default": "blah", + "maxProperties": 5, + "minProperties": 1, + "required": ["id", "name"], + "items": { + "type": "string" + }, + "allOf": [ + { + "type": "string" + } + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "discriminator": "not this", + "readOnly": true, + "xml": { + "name": "sch", + "namespace": "io", + "prefix": "sw", + "wrapped": true, + "attribute": true + }, + "externalDocs": { + "description": "the documentation etc", + "url": "http://readthedocs.org/swagger" + }, + "example": [ + { + "id": 1, + "name": "a book" + }, + { + "id": 2, + "name": "the thing" + } + ], + "additionalProperties": { + "type": "integer", + "format": "int32" + } +} +` + +func TestSchema(t *testing.T) { + + expected := map[string]interface{}{} + json.Unmarshal([]byte(schemaJSON), &expected) + b, err := json.Marshal(schema) + if assert.NoError(t, err) { + var actual map[string]interface{} + json.Unmarshal(b, &actual) + assert.Equal(t, expected, actual) + } + + actual2 := Schema{} + if assert.NoError(t, json.Unmarshal([]byte(schemaJSON), &actual2)) { + assert.Equal(t, schema.Ref, actual2.Ref) + assert.Equal(t, schema.Description, actual2.Description) + assert.Equal(t, schema.Maximum, actual2.Maximum) + assert.Equal(t, schema.Minimum, actual2.Minimum) + assert.Equal(t, schema.ExclusiveMinimum, actual2.ExclusiveMinimum) + assert.Equal(t, schema.ExclusiveMaximum, actual2.ExclusiveMaximum) + assert.Equal(t, schema.MaxLength, actual2.MaxLength) + assert.Equal(t, schema.MinLength, actual2.MinLength) + assert.Equal(t, schema.Pattern, actual2.Pattern) + assert.Equal(t, schema.MaxItems, actual2.MaxItems) + assert.Equal(t, schema.MinItems, actual2.MinItems) + assert.True(t, actual2.UniqueItems) + assert.Equal(t, schema.MultipleOf, actual2.MultipleOf) + assert.Equal(t, schema.Enum, actual2.Enum) + assert.Equal(t, schema.Type, actual2.Type) + assert.Equal(t, schema.Format, actual2.Format) + assert.Equal(t, schema.Title, actual2.Title) + assert.Equal(t, schema.MaxProperties, actual2.MaxProperties) + assert.Equal(t, schema.MinProperties, actual2.MinProperties) + assert.Equal(t, schema.Required, actual2.Required) + assert.Equal(t, schema.Items, actual2.Items) + assert.Equal(t, schema.AllOf, actual2.AllOf) + assert.Equal(t, schema.Properties, actual2.Properties) + assert.Equal(t, schema.Discriminator, actual2.Discriminator) + assert.Equal(t, schema.ReadOnly, actual2.ReadOnly) + assert.Equal(t, schema.XML, actual2.XML) + assert.Equal(t, schema.ExternalDocs, actual2.ExternalDocs) + assert.Equal(t, schema.AdditionalProperties, actual2.AdditionalProperties) + assert.Equal(t, schema.Extensions, actual2.Extensions) + examples := actual2.Example.([]interface{}) + expEx := schema.Example.([]interface{}) + ex1 := examples[0].(map[string]interface{}) + ex2 := examples[1].(map[string]interface{}) + exp1 := expEx[0].(map[string]interface{}) + exp2 := expEx[1].(map[string]interface{}) + + assert.EqualValues(t, exp1["id"], ex1["id"]) + assert.Equal(t, exp1["name"], ex1["name"]) + assert.EqualValues(t, exp2["id"], ex2["id"]) + assert.Equal(t, exp2["name"], ex2["name"]) + } + +} diff --git a/vendor/github.com/go-openapi/spec/structs_test.go b/vendor/github.com/go-openapi/spec/structs_test.go new file mode 100644 index 000000000..bfa59ee03 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/structs_test.go @@ -0,0 +1,110 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" +) + +func assertSerializeJSON(t testing.TB, actual interface{}, expected string) bool { + ser, err := json.Marshal(actual) + if err != nil { + return assert.Fail(t, "unable to marshal to json (%s): %#v", err, actual) + } + return assert.Equal(t, string(ser), expected) +} + +func assertParsesJSON(t testing.TB, actual string, expected interface{}) bool { + tpe := reflect.TypeOf(expected) + var pointed bool + if tpe.Kind() == reflect.Ptr { + tpe = tpe.Elem() + pointed = true + } + + parsed := reflect.New(tpe) + err := json.Unmarshal([]byte(actual), parsed.Interface()) + if err != nil { + return assert.Fail(t, "unable to unmarshal from json (%s): %s", err, actual) + } + act := parsed.Interface() + if !pointed { + act = reflect.Indirect(parsed).Interface() + } + return assert.Equal(t, act, expected) +} + +func assertSerializeYAML(t testing.TB, actual interface{}, expected string) bool { + ser, err := yaml.Marshal(actual) + if err != nil { + return assert.Fail(t, "unable to marshal to yaml (%s): %#v", err, actual) + } + return assert.Equal(t, string(ser), expected) +} + +func assertParsesYAML(t testing.TB, actual string, expected interface{}) bool { + tpe := reflect.TypeOf(expected) + var pointed bool + if tpe.Kind() == reflect.Ptr { + tpe = tpe.Elem() + pointed = true + } + parsed := reflect.New(tpe) + err := yaml.Unmarshal([]byte(actual), parsed.Interface()) + if err != nil { + return assert.Fail(t, "unable to unmarshal from yaml (%s): %s", err, actual) + } + act := parsed.Interface() + if !pointed { + act = reflect.Indirect(parsed).Interface() + } + return assert.EqualValues(t, act, expected) +} + +func TestSerialization_SerializeJSON(t *testing.T) { + assertSerializeJSON(t, []string{"hello"}, "[\"hello\"]") + assertSerializeJSON(t, []string{"hello", "world", "and", "stuff"}, "[\"hello\",\"world\",\"and\",\"stuff\"]") + assertSerializeJSON(t, StringOrArray(nil), "null") + assertSerializeJSON(t, SchemaOrArray{Schemas: []Schema{Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}}}, "[{\"type\":\"string\"}]") + assertSerializeJSON(t, SchemaOrArray{ + Schemas: []Schema{ + Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + }}, "[{\"type\":\"string\"},{\"type\":\"string\"}]") + assertSerializeJSON(t, SchemaOrArray{}, "null") +} + +func TestSerialization_DeserializeJSON(t *testing.T) { + // String + assertParsesJSON(t, "\"hello\"", StringOrArray([]string{"hello"})) + assertParsesJSON(t, "[\"hello\",\"world\",\"and\",\"stuff\"]", StringOrArray([]string{"hello", "world", "and", "stuff"})) + assertParsesJSON(t, "[\"hello\",\"world\",null,\"stuff\"]", StringOrArray([]string{"hello", "world", "", "stuff"})) + assertParsesJSON(t, "null", StringOrArray(nil)) + + // Schema + assertParsesJSON(t, "{\"type\":\"string\"}", SchemaOrArray{Schema: &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}}) + assertParsesJSON(t, "[{\"type\":\"string\"},{\"type\":\"string\"}]", &SchemaOrArray{ + Schemas: []Schema{ + Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}, + }, + }) + assertParsesJSON(t, "null", SchemaOrArray{}) +} diff --git a/vendor/github.com/go-openapi/spec/swagger_test.go b/vendor/github.com/go-openapi/spec/swagger_test.go new file mode 100644 index 000000000..c46f738aa --- /dev/null +++ b/vendor/github.com/go-openapi/spec/swagger_test.go @@ -0,0 +1,321 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/go-openapi/swag" + "github.com/stretchr/testify/assert" +) + +var spec = Swagger{ + SwaggerProps: SwaggerProps{ + ID: "http://localhost:3849/api-docs", + Swagger: "2.0", + Consumes: []string{"application/json", "application/x-yaml"}, + Produces: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Info: &info, + Host: "some.api.out.there", + BasePath: "/", + Paths: &paths, + Definitions: map[string]Schema{"Category": {SchemaProps: SchemaProps{Type: []string{"string"}}}}, + Parameters: map[string]Parameter{ + "categoryParam": {ParamProps: ParamProps{Name: "category", In: "query"}, SimpleSchema: SimpleSchema{Type: "string"}}, + }, + Responses: map[string]Response{ + "EmptyAnswer": { + ResponseProps: ResponseProps{ + Description: "no data to return for this operation", + }, + }, + }, + SecurityDefinitions: map[string]*SecurityScheme{ + "internalApiKey": APIKeyAuth("api_key", "header"), + }, + Security: []map[string][]string{ + {"internalApiKey": {}}, + }, + Tags: []Tag{NewTag("pets", "", nil)}, + ExternalDocs: &ExternalDocumentation{"the name", "the url"}, + }, + VendorExtensible: VendorExtensible{map[string]interface{}{ + "x-some-extension": "vendor", + "x-schemes": []interface{}{"unix", "amqp"}, + }}, +} + +var specJSON = `{ + "id": "http://localhost:3849/api-docs", + "consumes": ["application/json", "application/x-yaml"], + "produces": ["application/json"], + "schemes": ["http", "https"], + "swagger": "2.0", + "info": { + "contact": { + "name": "wordnik api team", + "url": "http://developer.wordnik.com" + }, + "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", + "license": { + "name": "Creative Commons 4.0 International", + "url": "http://creativecommons.org/licenses/by/4.0/" + }, + "termsOfService": "http://helloreverb.com/terms/", + "title": "Swagger Sample API", + "version": "1.0.9-abcd", + "x-framework": "go-swagger" + }, + "host": "some.api.out.there", + "basePath": "/", + "paths": {"x-framework":"go-swagger","/":{"$ref":"cats"}}, + "definitions": { "Category": { "type": "string"} }, + "parameters": { + "categoryParam": { + "name": "category", + "in": "query", + "type": "string" + } + }, + "responses": { "EmptyAnswer": { "description": "no data to return for this operation" } }, + "securityDefinitions": { + "internalApiKey": { + "type": "apiKey", + "in": "header", + "name": "api_key" + } + }, + "security": [{"internalApiKey":[]}], + "tags": [{"name":"pets"}], + "externalDocs": {"description":"the name","url":"the url"}, + "x-some-extension": "vendor", + "x-schemes": ["unix","amqp"] +}` + +// +// func verifySpecSerialize(specJSON []byte, spec Swagger) { +// expected := map[string]interface{}{} +// json.Unmarshal(specJSON, &expected) +// b, err := json.MarshalIndent(spec, "", " ") +// So(err, ShouldBeNil) +// var actual map[string]interface{} +// err = json.Unmarshal(b, &actual) +// So(err, ShouldBeNil) +// compareSpecMaps(actual, expected) +// } + +func assertEquivalent(t testing.TB, actual, expected interface{}) bool { + if actual == nil || expected == nil || reflect.DeepEqual(actual, expected) { + return true + } + + actualType := reflect.TypeOf(actual) + expectedType := reflect.TypeOf(expected) + if reflect.TypeOf(actual).ConvertibleTo(expectedType) { + expectedValue := reflect.ValueOf(expected) + if swag.IsZero(expectedValue) && swag.IsZero(reflect.ValueOf(actual)) { + return true + } + + // Attempt comparison after type conversion + if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) { + return true + } + } + + // Last ditch effort + if fmt.Sprintf("%#v", expected) == fmt.Sprintf("%#v", actual) { + return true + } + errFmt := "Expected: '%T(%#v)'\nActual: '%T(%#v)'\n(Should be equivalent)!" + return assert.Fail(t, errFmt, expected, expected, actual, actual) +} + +func ShouldBeEquivalentTo(actual interface{}, expecteds ...interface{}) string { + expected := expecteds[0] + if actual == nil || expected == nil { + return "" + } + + if reflect.DeepEqual(expected, actual) { + return "" + } + + actualType := reflect.TypeOf(actual) + expectedType := reflect.TypeOf(expected) + if reflect.TypeOf(actual).ConvertibleTo(expectedType) { + expectedValue := reflect.ValueOf(expected) + if swag.IsZero(expectedValue) && swag.IsZero(reflect.ValueOf(actual)) { + return "" + } + + // Attempt comparison after type conversion + if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) { + return "" + } + } + + // Last ditch effort + if fmt.Sprintf("%#v", expected) == fmt.Sprintf("%#v", actual) { + return "" + } + errFmt := "Expected: '%T(%#v)'\nActual: '%T(%#v)'\n(Should be equivalent)!" + return fmt.Sprintf(errFmt, expected, expected, actual, actual) + +} + +func assertSpecMaps(t testing.TB, actual, expected map[string]interface{}) bool { + res := true + if id, ok := expected["id"]; ok { + res = assert.Equal(t, id, actual["id"]) + } + res = res && assert.Equal(t, expected["consumes"], actual["consumes"]) + res = res && assert.Equal(t, expected["produces"], actual["produces"]) + res = res && assert.Equal(t, expected["schemes"], actual["schemes"]) + res = res && assert.Equal(t, expected["swagger"], actual["swagger"]) + res = res && assert.Equal(t, expected["info"], actual["info"]) + res = res && assert.Equal(t, expected["host"], actual["host"]) + res = res && assert.Equal(t, expected["basePath"], actual["basePath"]) + res = res && assert.Equal(t, expected["paths"], actual["paths"]) + res = res && assert.Equal(t, expected["definitions"], actual["definitions"]) + res = res && assert.Equal(t, expected["responses"], actual["responses"]) + res = res && assert.Equal(t, expected["securityDefinitions"], actual["securityDefinitions"]) + res = res && assert.Equal(t, expected["tags"], actual["tags"]) + res = res && assert.Equal(t, expected["externalDocs"], actual["externalDocs"]) + res = res && assert.Equal(t, expected["x-some-extension"], actual["x-some-extension"]) + res = res && assert.Equal(t, expected["x-schemes"], actual["x-schemes"]) + + return res +} + +// +// func compareSpecMaps(actual, expected map[string]interface{}) { +// if id, ok := expected["id"]; ok { +// So(actual["id"], ShouldEqual, id) +// } +// //So(actual["$schema"], ShouldEqual, SwaggerSchemaURL) +// So(actual["consumes"], ShouldResemble, expected["consumes"]) +// So(actual["produces"], ShouldResemble, expected["produces"]) +// So(actual["schemes"], ShouldResemble, expected["schemes"]) +// So(actual["swagger"], ShouldEqual, expected["swagger"]) +// So(actual["info"], ShouldResemble, expected["info"]) +// So(actual["host"], ShouldEqual, expected["host"]) +// So(actual["basePath"], ShouldEqual, expected["basePath"]) +// So(actual["paths"], ShouldBeEquivalentTo, expected["paths"]) +// So(actual["definitions"], ShouldBeEquivalentTo, expected["definitions"]) +// So(actual["responses"], ShouldBeEquivalentTo, expected["responses"]) +// So(actual["securityDefinitions"], ShouldResemble, expected["securityDefinitions"]) +// So(actual["tags"], ShouldResemble, expected["tags"]) +// So(actual["externalDocs"], ShouldResemble, expected["externalDocs"]) +// So(actual["x-some-extension"], ShouldResemble, expected["x-some-extension"]) +// So(actual["x-schemes"], ShouldResemble, expected["x-schemes"]) +// } + +func assertSpecs(t testing.TB, actual, expected Swagger) bool { + expected.Swagger = "2.0" + return assert.Equal(t, actual, expected) +} + +// +// func compareSpecs(actual Swagger, spec Swagger) { +// spec.Swagger = "2.0" +// So(actual, ShouldBeEquivalentTo, spec) +// } + +func assertSpecJSON(t testing.TB, specJSON []byte) bool { + var expected map[string]interface{} + if !assert.NoError(t, json.Unmarshal(specJSON, &expected)) { + return false + } + + obj := Swagger{} + if !assert.NoError(t, json.Unmarshal(specJSON, &obj)) { + return false + } + + cb, err := json.MarshalIndent(obj, "", " ") + if assert.NoError(t, err) { + return false + } + var actual map[string]interface{} + if !assert.NoError(t, json.Unmarshal(cb, &actual)) { + return false + } + return assertSpecMaps(t, actual, expected) +} + +// func verifySpecJSON(specJSON []byte) { +// //Println() +// //Println("json to verify", string(specJson)) +// var expected map[string]interface{} +// err := json.Unmarshal(specJSON, &expected) +// So(err, ShouldBeNil) +// +// obj := Swagger{} +// err = json.Unmarshal(specJSON, &obj) +// So(err, ShouldBeNil) +// +// //spew.Dump(obj) +// +// cb, err := json.MarshalIndent(obj, "", " ") +// So(err, ShouldBeNil) +// //Println() +// //Println("Marshalling to json returned", string(cb)) +// +// var actual map[string]interface{} +// err = json.Unmarshal(cb, &actual) +// So(err, ShouldBeNil) +// //Println() +// //spew.Dump(expected) +// //spew.Dump(actual) +// //fmt.Printf("comparing %s\n\t%#v\nto\n\t%#+v\n", fileName, expected, actual) +// compareSpecMaps(actual, expected) +// } + +func TestSwaggerSpec_Serialize(t *testing.T) { + expected := make(map[string]interface{}) + json.Unmarshal([]byte(specJSON), &expected) + b, err := json.MarshalIndent(spec, "", " ") + if assert.NoError(t, err) { + var actual map[string]interface{} + err := json.Unmarshal(b, &actual) + if assert.NoError(t, err) { + assert.EqualValues(t, actual, expected) + } + } +} + +func TestSwaggerSpec_Deserialize(t *testing.T) { + var actual Swagger + err := json.Unmarshal([]byte(specJSON), &actual) + if assert.NoError(t, err) { + assert.EqualValues(t, actual, spec) + } +} + +func TestVendorExtensionStringSlice(t *testing.T) { + var actual Swagger + err := json.Unmarshal([]byte(specJSON), &actual) + if assert.NoError(t, err) { + schemes, ok := actual.Extensions.GetStringSlice("x-schemes") + if assert.True(t, ok) { + assert.EqualValues(t, []string{"unix", "amqp"}, schemes) + } + } +} diff --git a/vendor/github.com/go-openapi/spec/xml_object_test.go b/vendor/github.com/go-openapi/spec/xml_object_test.go new file mode 100644 index 000000000..fda3b1084 --- /dev/null +++ b/vendor/github.com/go-openapi/spec/xml_object_test.go @@ -0,0 +1,65 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestXmlObject_Serialize(t *testing.T) { + obj1 := XMLObject{} + actual, err := json.Marshal(obj1) + if assert.NoError(t, err) { + assert.Equal(t, "{}", string(actual)) + } + + obj2 := XMLObject{ + Name: "the name", + Namespace: "the namespace", + Prefix: "the prefix", + Attribute: true, + Wrapped: true, + } + + actual, err = json.Marshal(obj2) + if assert.NoError(t, err) { + var ad map[string]interface{} + if assert.NoError(t, json.Unmarshal(actual, &ad)) { + assert.Equal(t, obj2.Name, ad["name"]) + assert.Equal(t, obj2.Namespace, ad["namespace"]) + assert.Equal(t, obj2.Prefix, ad["prefix"]) + assert.True(t, ad["attribute"].(bool)) + assert.True(t, ad["wrapped"].(bool)) + } + } +} + +func TestXmlObject_Deserialize(t *testing.T) { + expected := XMLObject{} + actual := XMLObject{} + if assert.NoError(t, json.Unmarshal([]byte("{}"), &actual)) { + assert.Equal(t, expected, actual) + } + + completed := `{"name":"the name","namespace":"the namespace","prefix":"the prefix","attribute":true,"wrapped":true}` + expected = XMLObject{"the name", "the namespace", "the prefix", true, true} + actual = XMLObject{} + if assert.NoError(t, json.Unmarshal([]byte(completed), &actual)) { + assert.Equal(t, expected, actual) + } +} diff --git a/vendor/github.com/go-openapi/swag/.editorconfig b/vendor/github.com/go-openapi/swag/.editorconfig new file mode 100644 index 000000000..3152da69a --- /dev/null +++ b/vendor/github.com/go-openapi/swag/.editorconfig @@ -0,0 +1,26 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +# Set default charset +[*.{js,py,go,scala,rb,java,html,css,less,sass,md}] +charset = utf-8 + +# Tab indentation (no size specified) +[*.go] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/vendor/github.com/go-openapi/swag/.gitignore b/vendor/github.com/go-openapi/swag/.gitignore new file mode 100644 index 000000000..5862205ee --- /dev/null +++ b/vendor/github.com/go-openapi/swag/.gitignore @@ -0,0 +1,3 @@ +secrets.yml +vendor +Godeps diff --git a/vendor/github.com/go-openapi/swag/.travis.yml b/vendor/github.com/go-openapi/swag/.travis.yml new file mode 100644 index 000000000..24c69bdf3 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: +- 1.8 +install: +- go get -u github.com/stretchr/testify +- go get -u github.com/mailru/easyjson +- go get -u gopkg.in/yaml.v2 +script: +- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./... +after_success: +- bash <(curl -s https://codecov.io/bash) +notifications: + slack: + secure: QUWvCkBBK09GF7YtEvHHVt70JOkdlNBG0nIKu/5qc4/nW5HP8I2w0SEf/XR2je0eED1Qe3L/AfMCWwrEj+IUZc3l4v+ju8X8R3Lomhme0Eb0jd1MTMCuPcBT47YCj0M7RON7vXtbFfm1hFJ/jLe5+9FXz0hpXsR24PJc5ZIi/ogNwkaPqG4BmndzecpSh0vc2FJPZUD9LT0I09REY/vXR0oQAalLkW0asGD5taHZTUZq/kBpsNxaAFrLM23i4mUcf33M5fjLpvx5LRICrX/57XpBrDh2TooBU6Qj3CgoY0uPRYUmSNxbVx1czNzl2JtEpb5yjoxfVPQeg0BvQM00G8LJINISR+ohrjhkZmAqchDupAX+yFrxTtORa78CtnIL6z/aTNlgwwVD8kvL/1pFA/JWYmKDmz93mV/+6wubGzNSQCstzjkFA4/iZEKewKUoRIAi/fxyscP6L/rCpmY/4llZZvrnyTqVbt6URWpopUpH4rwYqreXAtJxJsfBJIeSmUIiDIOMGkCTvyTEW3fWGmGoqWtSHLoaWDyAIGb7azb+KvfpWtEcoPFWfSWU+LGee0A/YsUhBl7ADB9A0CJEuR8q4BPpKpfLwPKSiKSAXL7zDkyjExyhtgqbSl2jS+rKIHOZNL8JkCcTP2MKMVd563C5rC5FMKqu3S9m2b6380E= diff --git a/vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md b/vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..9322b065e --- /dev/null +++ b/vendor/github.com/go-openapi/swag/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at ivan+abuse@flanders.co.nz. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md new file mode 100644 index 000000000..5d43728e8 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/README.md @@ -0,0 +1,12 @@ +# Swag [![Build Status](https://travis-ci.org/go-openapi/swag.svg?branch=master)](https://travis-ci.org/go-openapi/swag) [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) + +[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE) [![GoDoc](https://godoc.org/github.com/go-openapi/swag?status.svg)](http://godoc.org/github.com/go-openapi/swag) + +Contains a bunch of helper functions: + +* convert between value and pointers for builtins +* convert from string to builtin +* fast json concatenation +* search in path +* load from file or http +* name manglin \ No newline at end of file diff --git a/vendor/github.com/go-openapi/swag/convert_test.go b/vendor/github.com/go-openapi/swag/convert_test.go new file mode 100644 index 000000000..2f0073236 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/convert_test.go @@ -0,0 +1,215 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 swag + +import ( + "math" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" +) + +// These are really dumb tests + +func TestConvertBool(t *testing.T) { + for k := range evaluatesAsTrue { + r, err := ConvertBool(k) + if assert.NoError(t, err) { + assert.True(t, r) + } + } + for _, k := range []string{"a", "", "0", "false", "unchecked"} { + r, err := ConvertBool(k) + if assert.NoError(t, err) { + assert.False(t, r) + } + } +} + +func TestConvertFloat32(t *testing.T) { + validFloats := []float32{1.0, -1, math.MaxFloat32, math.SmallestNonzeroFloat32, 0, 5.494430303} + invalidFloats := []string{"a", strconv.FormatFloat(math.MaxFloat64, 'f', -1, 64), "true"} + + for _, f := range validFloats { + c, err := ConvertFloat32(FormatFloat32(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidFloats { + _, err := ConvertFloat32(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertFloat64(t *testing.T) { + validFloats := []float64{1.0, -1, float64(math.MaxFloat32), float64(math.SmallestNonzeroFloat32), math.MaxFloat64, math.SmallestNonzeroFloat64, 0, 5.494430303} + invalidFloats := []string{"a", "true"} + + for _, f := range validFloats { + c, err := ConvertFloat64(FormatFloat64(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidFloats { + _, err := ConvertFloat64(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertInt8(t *testing.T) { + validInts := []int8{0, 1, -1, math.MaxInt8, math.MinInt8} + invalidInts := []string{"1.233", "a", "false", strconv.Itoa(int(math.MaxInt64))} + + for _, f := range validInts { + c, err := ConvertInt8(FormatInt8(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidInts { + _, err := ConvertInt8(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertInt16(t *testing.T) { + validInts := []int16{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16} + invalidInts := []string{"1.233", "a", "false", strconv.Itoa(int(math.MaxInt64))} + + for _, f := range validInts { + c, err := ConvertInt16(FormatInt16(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidInts { + _, err := ConvertInt16(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertInt32(t *testing.T) { + validInts := []int32{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32} + invalidInts := []string{"1.233", "a", "false", strconv.Itoa(int(math.MaxInt64))} + + for _, f := range validInts { + c, err := ConvertInt32(FormatInt32(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidInts { + _, err := ConvertInt32(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertInt64(t *testing.T) { + validInts := []int64{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32, math.MaxInt64, math.MinInt64} + invalidInts := []string{"1.233", "a", "false"} + + for _, f := range validInts { + c, err := ConvertInt64(FormatInt64(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidInts { + _, err := ConvertInt64(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertUint8(t *testing.T) { + validInts := []uint8{0, 1, math.MaxUint8} + invalidInts := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} + + for _, f := range validInts { + c, err := ConvertUint8(FormatUint8(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidInts { + _, err := ConvertUint8(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertUint16(t *testing.T) { + validUints := []uint16{0, 1, math.MaxUint8, math.MaxUint16} + invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} + + for _, f := range validUints { + c, err := ConvertUint16(FormatUint16(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidUints { + _, err := ConvertUint16(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertUint32(t *testing.T) { + validUints := []uint32{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32} + invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} + + for _, f := range validUints { + c, err := ConvertUint32(FormatUint32(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidUints { + _, err := ConvertUint32(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestConvertUint64(t *testing.T) { + validUints := []uint64{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64} + invalidUints := []string{"1.233", "a", "false"} + + for _, f := range validUints { + c, err := ConvertUint64(FormatUint64(f)) + if assert.NoError(t, err) { + assert.EqualValues(t, f, c) + } + } + for _, f := range invalidUints { + _, err := ConvertUint64(f) + assert.Error(t, err, "expected '"+f+"' to generate an error") + } +} + +func TestIsFloat64AJSONInteger(t *testing.T) { + assert.False(t, IsFloat64AJSONInteger(math.Inf(1))) + assert.False(t, IsFloat64AJSONInteger(maxJSONFloat+1)) + + assert.False(t, IsFloat64AJSONInteger(minJSONFloat-1)) + assert.True(t, IsFloat64AJSONInteger(1.0)) + assert.True(t, IsFloat64AJSONInteger(maxJSONFloat)) + assert.True(t, IsFloat64AJSONInteger(minJSONFloat)) +} + +func TestFormatBool(t *testing.T) { + assert.Equal(t, "true", FormatBool(true)) + assert.Equal(t, "false", FormatBool(false)) +} diff --git a/vendor/github.com/go-openapi/swag/convert_types_test.go b/vendor/github.com/go-openapi/swag/convert_types_test.go new file mode 100644 index 000000000..978cf3a1d --- /dev/null +++ b/vendor/github.com/go-openapi/swag/convert_types_test.go @@ -0,0 +1,579 @@ +package swag + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +var testCasesStringSlice = [][]string{ + {"a", "b", "c", "d", "e"}, + {"a", "b", "", "", "e"}, +} + +func TestStringSlice(t *testing.T) { + for idx, in := range testCasesStringSlice { + if in == nil { + continue + } + out := StringSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := StringValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesStringValueSlice = [][]*string{ + {String("a"), String("b"), nil, String("c")}, +} + +func TestStringValueSlice(t *testing.T) { + for idx, in := range testCasesStringValueSlice { + if in == nil { + continue + } + out := StringValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := StringSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesStringMap = []map[string]string{ + {"a": "1", "b": "2", "c": "3"}, +} + +func TestStringMap(t *testing.T) { + for idx, in := range testCasesStringMap { + if in == nil { + continue + } + out := StringMap(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := StringValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesBoolSlice = [][]bool{ + {true, true, false, false}, +} + +func TestBoolSlice(t *testing.T) { + for idx, in := range testCasesBoolSlice { + if in == nil { + continue + } + out := BoolSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := BoolValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesBoolValueSlice = [][]*bool{} + +func TestBoolValueSlice(t *testing.T) { + for idx, in := range testCasesBoolValueSlice { + if in == nil { + continue + } + out := BoolValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := BoolSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesBoolMap = []map[string]bool{ + {"a": true, "b": false, "c": true}, +} + +func TestBoolMap(t *testing.T) { + for idx, in := range testCasesBoolMap { + if in == nil { + continue + } + out := BoolMap(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := BoolValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesIntSlice = [][]int{ + {1, 2, 3, 4}, +} + +func TestIntSlice(t *testing.T) { + for idx, in := range testCasesIntSlice { + if in == nil { + continue + } + out := IntSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := IntValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesIntValueSlice = [][]*int{} + +func TestIntValueSlice(t *testing.T) { + for idx, in := range testCasesIntValueSlice { + if in == nil { + continue + } + out := IntValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := IntSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesIntMap = []map[string]int{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestIntMap(t *testing.T) { + for idx, in := range testCasesIntMap { + if in == nil { + continue + } + out := IntMap(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := IntValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesInt64Slice = [][]int64{ + {1, 2, 3, 4}, +} + +func TestInt64Slice(t *testing.T) { + for idx, in := range testCasesInt64Slice { + if in == nil { + continue + } + out := Int64Slice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := Int64ValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesInt64ValueSlice = [][]*int64{} + +func TestInt64ValueSlice(t *testing.T) { + for idx, in := range testCasesInt64ValueSlice { + if in == nil { + continue + } + out := Int64ValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := Int64Slice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesInt64Map = []map[string]int64{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestInt64Map(t *testing.T) { + for idx, in := range testCasesInt64Map { + if in == nil { + continue + } + out := Int64Map(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := Int64ValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesFloat64Slice = [][]float64{ + {1, 2, 3, 4}, +} + +func TestFloat64Slice(t *testing.T) { + for idx, in := range testCasesFloat64Slice { + if in == nil { + continue + } + out := Float64Slice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := Float64ValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesUintSlice = [][]uint{ + {1, 2, 3, 4}, +} + +func TestUintSlice(t *testing.T) { + for idx, in := range testCasesUintSlice { + if in == nil { + continue + } + out := UintSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := UintValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesUintValueSlice = [][]*uint{} + +func TestUintValueSlice(t *testing.T) { + for idx, in := range testCasesUintValueSlice { + if in == nil { + continue + } + out := UintValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := UintSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesUintMap = []map[string]uint{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestUintMap(t *testing.T) { + for idx, in := range testCasesUintMap { + if in == nil { + continue + } + out := UintMap(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := UintValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesUint64Slice = [][]uint64{ + {1, 2, 3, 4}, +} + +func TestUint64Slice(t *testing.T) { + for idx, in := range testCasesUint64Slice { + if in == nil { + continue + } + out := Uint64Slice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := Uint64ValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesUint64ValueSlice = [][]*uint64{} + +func TestUint64ValueSlice(t *testing.T) { + for idx, in := range testCasesUint64ValueSlice { + if in == nil { + continue + } + out := Uint64ValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := Uint64Slice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesUint64Map = []map[string]uint64{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestUint64Map(t *testing.T) { + for idx, in := range testCasesUint64Map { + if in == nil { + continue + } + out := Uint64Map(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := Uint64ValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesFloat64ValueSlice = [][]*float64{} + +func TestFloat64ValueSlice(t *testing.T) { + for idx, in := range testCasesFloat64ValueSlice { + if in == nil { + continue + } + out := Float64ValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := Float64Slice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesFloat64Map = []map[string]float64{ + {"a": 3, "b": 2, "c": 1}, +} + +func TestFloat64Map(t *testing.T) { + for idx, in := range testCasesFloat64Map { + if in == nil { + continue + } + out := Float64Map(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := Float64ValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesTimeSlice = [][]time.Time{ + {time.Now(), time.Now().AddDate(100, 0, 0)}, +} + +func TestTimeSlice(t *testing.T) { + for idx, in := range testCasesTimeSlice { + if in == nil { + continue + } + out := TimeSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := TimeValueSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} + +var testCasesTimeValueSlice = [][]*time.Time{} + +func TestTimeValueSlice(t *testing.T) { + for idx, in := range testCasesTimeValueSlice { + if in == nil { + continue + } + out := TimeValueSlice(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + if in[i] == nil { + assert.Empty(t, out[i], "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx) + } + } + + out2 := TimeSlice(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + for i := range out2 { + if in[i] == nil { + assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx) + } else { + assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx) + } + } + } +} + +var testCasesTimeMap = []map[string]time.Time{ + {"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()}, +} + +func TestTimeMap(t *testing.T) { + for idx, in := range testCasesTimeMap { + if in == nil { + continue + } + out := TimeMap(in) + assert.Len(t, out, len(in), "Unexpected len at idx %d", idx) + for i := range out { + assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx) + } + + out2 := TimeValueMap(out) + assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx) + assert.Equal(t, in, out2, "Unexpected value at idx %d", idx) + } +} diff --git a/vendor/github.com/go-openapi/swag/json_test.go b/vendor/github.com/go-openapi/swag/json_test.go new file mode 100644 index 000000000..853c672cc --- /dev/null +++ b/vendor/github.com/go-openapi/swag/json_test.go @@ -0,0 +1,169 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 swag + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/assert" +) + +type testNameStruct struct { + Name string `json:"name"` + NotTheSame int64 `json:"plain"` + Ignored string `json:"-"` +} + +func TestNameProvider(t *testing.T) { + + provider := NewNameProvider() + + var obj = testNameStruct{} + + nm, ok := provider.GetGoName(obj, "name") + assert.True(t, ok) + assert.Equal(t, "Name", nm) + + nm, ok = provider.GetGoName(obj, "plain") + assert.True(t, ok) + assert.Equal(t, "NotTheSame", nm) + + nm, ok = provider.GetGoName(obj, "doesNotExist") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetGoName(obj, "ignored") + assert.False(t, ok) + assert.Empty(t, nm) + + tpe := reflect.TypeOf(obj) + nm, ok = provider.GetGoNameForType(tpe, "name") + assert.True(t, ok) + assert.Equal(t, "Name", nm) + + nm, ok = provider.GetGoNameForType(tpe, "plain") + assert.True(t, ok) + assert.Equal(t, "NotTheSame", nm) + + nm, ok = provider.GetGoNameForType(tpe, "doesNotExist") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetGoNameForType(tpe, "ignored") + assert.False(t, ok) + assert.Empty(t, nm) + + ptr := &obj + nm, ok = provider.GetGoName(ptr, "name") + assert.True(t, ok) + assert.Equal(t, "Name", nm) + + nm, ok = provider.GetGoName(ptr, "plain") + assert.True(t, ok) + assert.Equal(t, "NotTheSame", nm) + + nm, ok = provider.GetGoName(ptr, "doesNotExist") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetGoName(ptr, "ignored") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetJSONName(obj, "Name") + assert.True(t, ok) + assert.Equal(t, "name", nm) + + nm, ok = provider.GetJSONName(obj, "NotTheSame") + assert.True(t, ok) + assert.Equal(t, "plain", nm) + + nm, ok = provider.GetJSONName(obj, "DoesNotExist") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetJSONName(obj, "Ignored") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetJSONNameForType(tpe, "Name") + assert.True(t, ok) + assert.Equal(t, "name", nm) + + nm, ok = provider.GetJSONNameForType(tpe, "NotTheSame") + assert.True(t, ok) + assert.Equal(t, "plain", nm) + + nm, ok = provider.GetJSONNameForType(tpe, "doesNotExist") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetJSONNameForType(tpe, "Ignored") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetJSONName(ptr, "Name") + assert.True(t, ok) + assert.Equal(t, "name", nm) + + nm, ok = provider.GetJSONName(ptr, "NotTheSame") + assert.True(t, ok) + assert.Equal(t, "plain", nm) + + nm, ok = provider.GetJSONName(ptr, "doesNotExist") + assert.False(t, ok) + assert.Empty(t, nm) + + nm, ok = provider.GetJSONName(ptr, "Ignored") + assert.False(t, ok) + assert.Empty(t, nm) + + nms := provider.GetJSONNames(ptr) + assert.Len(t, nms, 2) + + assert.Len(t, provider.index, 1) + +} + +func TestJSONConcatenation(t *testing.T) { + assert.Nil(t, ConcatJSON()) + assert.Equal(t, ConcatJSON([]byte(`{"id":1}`)), []byte(`{"id":1}`)) + assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{}`)), []byte(`{}`)) + assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[]`)), []byte(`[]`)) + assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{"name":"Rachel"}`)), []byte(`{"id":1,"name":"Rachel"}`)) + assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[{"name":"Rachel"}]`)), []byte(`[{"id":1},{"name":"Rachel"}]`)) + assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{"name":"Rachel"}`)), []byte(`{"name":"Rachel"}`)) + assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[{"name":"Rachel"}]`)), []byte(`[{"name":"Rachel"}]`)) + assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{}`)), []byte(`{"id":1}`)) + assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[]`)), []byte(`[{"id":1}]`)) + assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{}`), []byte(`{}`)), []byte(`{}`)) + assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[]`), []byte(`[]`)), []byte(`[]`)) + assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{"name":"Rachel"}`), []byte(`{"age":32}`)), []byte(`{"id":1,"name":"Rachel","age":32}`)) + assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[{"name":"Rachel"}]`), []byte(`[{"age":32}]`)), []byte(`[{"id":1},{"name":"Rachel"},{"age":32}]`)) + assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{"name":"Rachel"}`), []byte(`{"age":32}`)), []byte(`{"name":"Rachel","age":32}`)) + assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[{"name":"Rachel"}]`), []byte(`[{"age":32}]`)), []byte(`[{"name":"Rachel"},{"age":32}]`)) + assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{}`), []byte(`{"age":32}`)), []byte(`{"id":1,"age":32}`)) + assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[]`), []byte(`[{"age":32}]`)), []byte(`[{"id":1},{"age":32}]`)) + assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{"name":"Rachel"}`), []byte(`{}`)), []byte(`{"id":1,"name":"Rachel"}`)) + assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[{"name":"Rachel"}]`), []byte(`[]`)), []byte(`[{"id":1},{"name":"Rachel"}]`)) + + // add test on null + assert.Equal(t, ConcatJSON([]byte(nil)), []byte(nil)) + assert.Equal(t, ConcatJSON([]byte(`null`)), []byte(nil)) + assert.Equal(t, ConcatJSON([]byte(nil), []byte(`null`)), []byte(nil)) + assert.Equal(t, ConcatJSON([]byte(`{"id":null}`), []byte(`null`)), []byte(`{"id":null}`)) + assert.Equal(t, ConcatJSON([]byte(`{"id":null}`), []byte(`null`), []byte(`{"name":"Rachel"}`)), []byte(`{"id":null,"name":"Rachel"}`)) +} diff --git a/vendor/github.com/go-openapi/swag/loading_test.go b/vendor/github.com/go-openapi/swag/loading_test.go new file mode 100644 index 000000000..7b8bdf48d --- /dev/null +++ b/vendor/github.com/go-openapi/swag/loading_test.go @@ -0,0 +1,47 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 swag + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestLoadFromHTTP(t *testing.T) { + + _, err := LoadFromFileOrHTTP("httx://12394:abd") + assert.Error(t, err) + + serv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusNotFound) + })) + defer serv.Close() + + _, err = LoadFromFileOrHTTP(serv.URL) + assert.Error(t, err) + + ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusOK) + rw.Write([]byte("the content")) + })) + defer ts2.Close() + + d, err := LoadFromFileOrHTTP(ts2.URL) + assert.NoError(t, err) + assert.Equal(t, []byte("the content"), d) +} diff --git a/vendor/github.com/go-openapi/swag/net_test.go b/vendor/github.com/go-openapi/swag/net_test.go new file mode 100644 index 000000000..041db60a2 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/net_test.go @@ -0,0 +1,30 @@ +package swag + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSplitHostPort(t *testing.T) { + data := []struct { + Input string + Host string + Port int + Err bool + }{ + {"localhost:3933", "localhost", 3933, false}, + {"localhost:yellow", "", -1, true}, + {"localhost", "", -1, true}, + {"localhost:", "", -1, true}, + {"localhost:3933", "localhost", 3933, false}, + } + + for _, e := range data { + h, p, err := SplitHostPort(e.Input) + if (!e.Err && assert.NoError(t, err)) || (e.Err && assert.Error(t, err)) { + assert.Equal(t, e.Host, h) + assert.Equal(t, e.Port, p) + } + } +} diff --git a/vendor/github.com/go-openapi/swag/path_test.go b/vendor/github.com/go-openapi/swag/path_test.go new file mode 100644 index 000000000..c5a670646 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/path_test.go @@ -0,0 +1,118 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 swag + +import ( + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" +) + +func makeDirStructure(t *testing.T, tgt string) (string, string, error) { + if tgt == "" { + tgt = "pkgpaths" + } + td, err := ioutil.TempDir("", tgt) + if err != nil { + return "", "", err + } + td2, err := ioutil.TempDir("", tgt+"-2") + if err != nil { + return "", "", err + } + realPath := filepath.Join(td, "src", "foo", "bar") + if err := os.MkdirAll(realPath, os.ModePerm); err != nil { + return "", "", err + } + linkPathBase := filepath.Join(td, "src", "baz") + if err := os.MkdirAll(linkPathBase, os.ModePerm); err != nil { + return "", "", err + } + linkPath := filepath.Join(linkPathBase, "das") + if err := os.Symlink(realPath, linkPath); err != nil { + return "", "", err + } + + realPath = filepath.Join(td2, "src", "fuu", "bir") + if err := os.MkdirAll(realPath, os.ModePerm); err != nil { + return "", "", err + } + linkPathBase = filepath.Join(td2, "src", "biz") + if err := os.MkdirAll(linkPathBase, os.ModePerm); err != nil { + return "", "", err + } + linkPath = filepath.Join(linkPathBase, "dis") + if err := os.Symlink(realPath, linkPath); err != nil { + return "", "", err + } + return td, td2, nil +} + +func TestFindPackage(t *testing.T) { + pth, pth2, err := makeDirStructure(t, "") + if err != nil { + t.Fatal(err) + } + defer func() { + os.RemoveAll(pth) + os.RemoveAll(pth2) + }() + + searchPath := pth + string(filepath.ListSeparator) + pth2 + // finds package when real name mentioned + pkg := FindInSearchPath(searchPath, "foo/bar") + assert.NotEmpty(t, pkg) + assertPath(t, path.Join(pth, "src", "foo", "bar"), pkg) + // finds package when real name is mentioned in secondary + pkg = FindInSearchPath(searchPath, "fuu/bir") + assert.NotEmpty(t, pkg) + assertPath(t, path.Join(pth2, "src", "fuu", "bir"), pkg) + // finds package when symlinked + pkg = FindInSearchPath(searchPath, "baz/das") + assert.NotEmpty(t, pkg) + assertPath(t, path.Join(pth, "src", "foo", "bar"), pkg) + // finds package when symlinked in secondary + pkg = FindInSearchPath(searchPath, "biz/dis") + assert.NotEmpty(t, pkg) + assertPath(t, path.Join(pth2, "src", "fuu", "bir"), pkg) + // return empty string when nothing is found + pkg = FindInSearchPath(searchPath, "not/there") + assert.Empty(t, pkg) +} + +func assertPath(t testing.TB, expected, actual string) bool { + fp, err := filepath.EvalSymlinks(expected) + if assert.NoError(t, err) { + return assert.Equal(t, fp, actual) + } + return true +} + +func TestFullGOPATH(t *testing.T) { + os.Unsetenv(GOPATHKey) + ngp := "/some/where:/other/place" + os.Setenv(GOPATHKey, ngp) + + ogp := os.Getenv(GOPATHKey) + defer os.Setenv(GOPATHKey, ogp) + + expected := ngp + ":" + runtime.GOROOT() + assert.Equal(t, expected, FullGoSearchPath()) +} diff --git a/vendor/github.com/go-openapi/swag/util_test.go b/vendor/github.com/go-openapi/swag/util_test.go new file mode 100644 index 000000000..c00738ef6 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/util_test.go @@ -0,0 +1,293 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 swag + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +type translationSample struct { + str, out string +} + +func titleize(s string) string { return strings.ToTitle(s[:1]) + lower(s[1:]) } + +func init() { + AddInitialisms("elb", "cap", "capwd", "wd") +} + +func TestToGoName(t *testing.T) { + samples := []translationSample{ + {"sample text", "SampleText"}, + {"sample-text", "SampleText"}, + {"sample_text", "SampleText"}, + {"sampleText", "SampleText"}, + {"sample 2 Text", "Sample2Text"}, + {"findThingById", "FindThingByID"}, + {"日本語sample 2 Text", "X日本語sample2Text"}, + {"日本語findThingById", "X日本語findThingByID"}, + {"findTHINGSbyID", "FindTHINGSbyID"}, + } + + for k := range commonInitialisms { + samples = append(samples, + translationSample{"sample " + lower(k) + " text", "Sample" + k + "Text"}, + translationSample{"sample-" + lower(k) + "-text", "Sample" + k + "Text"}, + translationSample{"sample_" + lower(k) + "_text", "Sample" + k + "Text"}, + translationSample{"sample" + titleize(k) + "Text", "Sample" + k + "Text"}, + translationSample{"sample " + lower(k), "Sample" + k}, + translationSample{"sample-" + lower(k), "Sample" + k}, + translationSample{"sample_" + lower(k), "Sample" + k}, + translationSample{"sample" + titleize(k), "Sample" + k}, + translationSample{"sample " + titleize(k) + " text", "Sample" + k + "Text"}, + translationSample{"sample-" + titleize(k) + "-text", "Sample" + k + "Text"}, + translationSample{"sample_" + titleize(k) + "_text", "Sample" + k + "Text"}, + ) + } + + for _, sample := range samples { + assert.Equal(t, sample.out, ToGoName(sample.str)) + } +} + +func TestContainsStringsCI(t *testing.T) { + list := []string{"hello", "world", "and", "such"} + + assert.True(t, ContainsStringsCI(list, "hELLo")) + assert.True(t, ContainsStringsCI(list, "world")) + assert.True(t, ContainsStringsCI(list, "AND")) + assert.False(t, ContainsStringsCI(list, "nuts")) +} + +func TestSplitByFormat(t *testing.T) { + expected := []string{"one", "two", "three"} + for _, fmt := range []string{"csv", "pipes", "tsv", "ssv", "multi"} { + + var actual []string + switch fmt { + case "multi": + assert.Nil(t, SplitByFormat("", fmt)) + assert.Nil(t, SplitByFormat("blah", fmt)) + case "ssv": + actual = SplitByFormat(strings.Join(expected, " "), fmt) + assert.EqualValues(t, expected, actual) + case "pipes": + actual = SplitByFormat(strings.Join(expected, "|"), fmt) + assert.EqualValues(t, expected, actual) + case "tsv": + actual = SplitByFormat(strings.Join(expected, "\t"), fmt) + assert.EqualValues(t, expected, actual) + default: + actual = SplitByFormat(strings.Join(expected, ","), fmt) + assert.EqualValues(t, expected, actual) + } + } +} + +func TestJoinByFormat(t *testing.T) { + for _, fmt := range []string{"csv", "pipes", "tsv", "ssv", "multi"} { + + lval := []string{"one", "two", "three"} + var expected []string + switch fmt { + case "multi": + expected = lval + case "ssv": + expected = []string{strings.Join(lval, " ")} + case "pipes": + expected = []string{strings.Join(lval, "|")} + case "tsv": + expected = []string{strings.Join(lval, "\t")} + default: + expected = []string{strings.Join(lval, ",")} + } + assert.Nil(t, JoinByFormat(nil, fmt)) + assert.EqualValues(t, expected, JoinByFormat(lval, fmt)) + } +} + +func TestToFileName(t *testing.T) { + samples := []translationSample{ + {"SampleText", "sample_text"}, + {"FindThingByID", "find_thing_by_id"}, + {"CAPWD.folwdBylc", "capwd_folwd_bylc"}, + {"CAPWDfolwdBylc", "capwdfolwd_bylc"}, + {"CAP_WD_folwdBylc", "cap_wd_folwd_bylc"}, + {"TypeOAI_alias", "type_oai_alias"}, + {"Type_OAI_alias", "type_oai_alias"}, + {"Type_OAIAlias", "type_oai_alias"}, + {"ELB.HTTPLoadBalancer", "elb_http_load_balancer"}, + {"elbHTTPLoadBalancer", "elb_http_load_balancer"}, + {"ELBHTTPLoadBalancer", "elb_http_load_balancer"}, + } + for k := range commonInitialisms { + samples = append(samples, + translationSample{"Sample" + k + "Text", "sample_" + lower(k) + "_text"}, + ) + } + + for _, sample := range samples { + assert.Equal(t, sample.out, ToFileName(sample.str)) + } +} + +func TestToCommandName(t *testing.T) { + samples := []translationSample{ + {"SampleText", "sample-text"}, + {"FindThingByID", "find-thing-by-id"}, + {"elbHTTPLoadBalancer", "elb-http-load-balancer"}, + } + + for k := range commonInitialisms { + samples = append(samples, + translationSample{"Sample" + k + "Text", "sample-" + lower(k) + "-text"}, + ) + } + + for _, sample := range samples { + assert.Equal(t, sample.out, ToCommandName(sample.str)) + } +} + +func TestToHumanName(t *testing.T) { + samples := []translationSample{ + {"SampleText", "sample text"}, + {"FindThingByID", "find thing by ID"}, + {"elbHTTPLoadBalancer", "elb HTTP load balancer"}, + } + + for k := range commonInitialisms { + samples = append(samples, + translationSample{"Sample" + k + "Text", "sample " + k + " text"}, + ) + } + + for _, sample := range samples { + assert.Equal(t, sample.out, ToHumanNameLower(sample.str)) + } +} + +func TestToJSONName(t *testing.T) { + samples := []translationSample{ + {"SampleText", "sampleText"}, + {"FindThingByID", "findThingById"}, + {"elbHTTPLoadBalancer", "elbHttpLoadBalancer"}, + } + + for k := range commonInitialisms { + samples = append(samples, + translationSample{"Sample" + k + "Text", "sample" + titleize(k) + "Text"}, + ) + } + + for _, sample := range samples { + assert.Equal(t, sample.out, ToJSONName(sample.str)) + } +} + +type SimpleZeroes struct { + ID string + Name string +} +type ZeroesWithTime struct { + Time time.Time +} + +func TestIsZero(t *testing.T) { + var strs [5]string + var strss []string + var a int + var b int8 + var c int16 + var d int32 + var e int64 + var f uint + var g uint8 + var h uint16 + var i uint32 + var j uint64 + var k map[string]string + var l interface{} + var m *SimpleZeroes + var n string + var o SimpleZeroes + var p ZeroesWithTime + var q time.Time + data := []struct { + Data interface{} + Expected bool + }{ + {a, true}, + {b, true}, + {c, true}, + {d, true}, + {e, true}, + {f, true}, + {g, true}, + {h, true}, + {i, true}, + {j, true}, + {k, true}, + {l, true}, + {m, true}, + {n, true}, + {o, true}, + {p, true}, + {q, true}, + {strss, true}, + {strs, true}, + {"", true}, + {nil, true}, + {1, false}, + {0, true}, + {int8(1), false}, + {int8(0), true}, + {int16(1), false}, + {int16(0), true}, + {int32(1), false}, + {int32(0), true}, + {int64(1), false}, + {int64(0), true}, + {uint(1), false}, + {uint(0), true}, + {uint8(1), false}, + {uint8(0), true}, + {uint16(1), false}, + {uint16(0), true}, + {uint32(1), false}, + {uint32(0), true}, + {uint64(1), false}, + {uint64(0), true}, + {0.0, true}, + {0.1, false}, + {float32(0.0), true}, + {float32(0.1), false}, + {float64(0.0), true}, + {float64(0.1), false}, + {[...]string{}, true}, + {[...]string{"hello"}, false}, + {[]string(nil), true}, + {[]string{"a"}, false}, + } + + for _, it := range data { + assert.Equal(t, it.Expected, IsZero(it.Data), fmt.Sprintf("%#v", it.Data)) + } +} diff --git a/vendor/github.com/go-openapi/swag/yaml_test.go b/vendor/github.com/go-openapi/swag/yaml_test.go new file mode 100644 index 000000000..ee32fab7d --- /dev/null +++ b/vendor/github.com/go-openapi/swag/yaml_test.go @@ -0,0 +1,444 @@ +// Copyright 2015 go-swagger maintainers +// +// 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 swag + +import ( + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + yaml "gopkg.in/yaml.v2" + + "github.com/stretchr/testify/assert" +) + +type failJSONMarhal struct { +} + +func (f failJSONMarhal) MarshalJSON() ([]byte, error) { + return nil, errors.New("expected") +} + +func TestLoadHTTPBytes(t *testing.T) { + _, err := LoadFromFileOrHTTP("httx://12394:abd") + assert.Error(t, err) + + serv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusNotFound) + })) + defer serv.Close() + + _, err = LoadFromFileOrHTTP(serv.URL) + assert.Error(t, err) + + ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusOK) + rw.Write([]byte("the content")) + })) + defer ts2.Close() + + d, err := LoadFromFileOrHTTP(ts2.URL) + assert.NoError(t, err) + assert.Equal(t, []byte("the content"), d) +} + +func TestYAMLToJSON(t *testing.T) { + + sd := `--- +1: the int key value +name: a string value +'y': some value +` + var data yaml.MapSlice + yaml.Unmarshal([]byte(sd), &data) + + d, err := YAMLToJSON(data) + if assert.NoError(t, err) { + assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value"}`, string(d)) + } + + data = append(data, yaml.MapItem{Key: true, Value: "the bool value"}) + d, err = YAMLToJSON(data) + assert.Error(t, err) + assert.Nil(t, d) + + data = data[:len(data)-1] + + tag := yaml.MapSlice{{Key: "name", Value: "tag name"}} + data = append(data, yaml.MapItem{Key: "tag", Value: tag}) + + d, err = YAMLToJSON(data) + assert.NoError(t, err) + assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value","tag":{"name":"tag name"}}`, string(d)) + + tag = yaml.MapSlice{{Key: true, Value: "bool tag name"}} + data = append(data[:len(data)-1], yaml.MapItem{Key: "tag", Value: tag}) + + d, err = YAMLToJSON(data) + assert.Error(t, err) + assert.Nil(t, d) + + var lst []interface{} + lst = append(lst, "hello") + + d, err = YAMLToJSON(lst) + assert.NoError(t, err) + assert.Equal(t, []byte(`["hello"]`), []byte(d)) + + lst = append(lst, data) + + d, err = YAMLToJSON(lst) + assert.Error(t, err) + assert.Nil(t, d) + + // _, err := yamlToJSON(failJSONMarhal{}) + // assert.Error(t, err) + + _, err = BytesToYAMLDoc([]byte("- name: hello\n")) + assert.Error(t, err) + + dd, err := BytesToYAMLDoc([]byte("description: 'object created'\n")) + assert.NoError(t, err) + + d, err = YAMLToJSON(dd) + assert.NoError(t, err) + assert.Equal(t, json.RawMessage(`{"description":"object created"}`), d) +} + +func TestLoadStrategy(t *testing.T) { + + loader := func(p string) ([]byte, error) { + return []byte(yamlPetStore), nil + } + remLoader := func(p string) ([]byte, error) { + return []byte("not it"), nil + } + + ld := LoadStrategy("blah", loader, remLoader) + b, _ := ld("") + assert.Equal(t, []byte(yamlPetStore), b) + + serv := httptest.NewServer(http.HandlerFunc(yamlPestoreServer)) + defer serv.Close() + + s, err := YAMLDoc(serv.URL) + assert.NoError(t, err) + assert.NotNil(t, s) + + ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusNotFound) + rw.Write([]byte("\n")) + })) + defer ts2.Close() + _, err = YAMLDoc(ts2.URL) + assert.Error(t, err) +} + +var yamlPestoreServer = func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusOK) + rw.Write([]byte(yamlPetStore)) +} + +func TestWithYKey(t *testing.T) { + doc, err := BytesToYAMLDoc([]byte(withYKey)) + if assert.NoError(t, err) { + _, err := YAMLToJSON(doc) + if assert.Error(t, err) { + doc, err := BytesToYAMLDoc([]byte(withQuotedYKey)) + if assert.NoError(t, err) { + jsond, err := YAMLToJSON(doc) + if assert.NoError(t, err) { + var yt struct { + Definitions struct { + Viewbox struct { + Properties struct { + Y struct { + Type string `json:"type"` + } `json:"y"` + } `json:"properties"` + } `json:"viewbox"` + } `json:"definitions"` + } + if assert.NoError(t, json.Unmarshal(jsond, &yt)) { + assert.Equal(t, "integer", yt.Definitions.Viewbox.Properties.Y.Type) + } + } + } + } + + } +} + +const withQuotedYKey = `consumes: +- application/json +definitions: + viewBox: + type: object + properties: + x: + type: integer + format: int16 + # y -> types don't match: expect map key string or int get: bool + "y": + type: integer + format: int16 + width: + type: integer + format: int16 + height: + type: integer + format: int16 +info: + description: Test RESTful APIs + title: Test Server + version: 1.0.0 +basePath: /api +paths: + /test: + get: + operationId: findAll + parameters: + - name: since + in: query + type: integer + format: int64 + - name: limit + in: query + type: integer + format: int32 + default: 20 + responses: + 200: + description: Array[Trigger] + schema: + type: array + items: + $ref: "#/definitions/viewBox" +produces: +- application/json +schemes: +- https +swagger: "2.0" +` + +const withYKey = `consumes: +- application/json +definitions: + viewBox: + type: object + properties: + x: + type: integer + format: int16 + # y -> types don't match: expect map key string or int get: bool + y: + type: integer + format: int16 + width: + type: integer + format: int16 + height: + type: integer + format: int16 +info: + description: Test RESTful APIs + title: Test Server + version: 1.0.0 +basePath: /api +paths: + /test: + get: + operationId: findAll + parameters: + - name: since + in: query + type: integer + format: int64 + - name: limit + in: query + type: integer + format: int32 + default: 20 + responses: + 200: + description: Array[Trigger] + schema: + type: array + items: + $ref: "#/definitions/viewBox" +produces: +- application/json +schemes: +- https +swagger: "2.0" +` + +const yamlPetStore = `swagger: '2.0' +info: + version: '1.0.0' + title: Swagger Petstore + description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification + termsOfService: http://helloreverb.com/terms/ + contact: + name: Swagger API team + email: foo@example.com + url: http://swagger.io + license: + name: MIT + url: http://opensource.org/licenses/MIT +host: petstore.swagger.wordnik.com +basePath: /api +schemes: + - http +consumes: + - application/json +produces: + - application/json +paths: + /pets: + get: + description: Returns all pets from the system that the user has access to + operationId: findPets + produces: + - application/json + - application/xml + - text/xml + - text/html + parameters: + - name: tags + in: query + description: tags to filter by + required: false + type: array + items: + type: string + collectionFormat: csv + - name: limit + in: query + description: maximum number of results to return + required: false + type: integer + format: int32 + responses: + '200': + description: pet response + schema: + type: array + items: + $ref: '#/definitions/pet' + default: + description: unexpected error + schema: + $ref: '#/definitions/errorModel' + post: + description: Creates a new pet in the store. Duplicates are allowed + operationId: addPet + produces: + - application/json + parameters: + - name: pet + in: body + description: Pet to add to the store + required: true + schema: + $ref: '#/definitions/newPet' + responses: + '200': + description: pet response + schema: + $ref: '#/definitions/pet' + default: + description: unexpected error + schema: + $ref: '#/definitions/errorModel' + /pets/{id}: + get: + description: Returns a user based on a single ID, if the user does not have access to the pet + operationId: findPetById + produces: + - application/json + - application/xml + - text/xml + - text/html + parameters: + - name: id + in: path + description: ID of pet to fetch + required: true + type: integer + format: int64 + responses: + '200': + description: pet response + schema: + $ref: '#/definitions/pet' + default: + description: unexpected error + schema: + $ref: '#/definitions/errorModel' + delete: + description: deletes a single pet based on the ID supplied + operationId: deletePet + parameters: + - name: id + in: path + description: ID of pet to delete + required: true + type: integer + format: int64 + responses: + '204': + description: pet deleted + default: + description: unexpected error + schema: + $ref: '#/definitions/errorModel' +definitions: + pet: + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + newPet: + allOf: + - $ref: '#/definitions/pet' + - required: + - name + properties: + id: + type: integer + format: int64 + name: + type: string + errorModel: + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string +` diff --git a/vendor/github.com/gogo/protobuf/.gitignore b/vendor/github.com/gogo/protobuf/.gitignore new file mode 100644 index 000000000..76009479d --- /dev/null +++ b/vendor/github.com/gogo/protobuf/.gitignore @@ -0,0 +1,3 @@ +._* +*.js +*.js.map diff --git a/vendor/github.com/gogo/protobuf/.mailmap b/vendor/github.com/gogo/protobuf/.mailmap new file mode 100644 index 000000000..bc0010219 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/.mailmap @@ -0,0 +1,8 @@ +Walter Schulze Walter Schulze +Walter Schulze +Walter Schulze awalterschulze +Walter Schulze awalterschulze@gmail.com +John Tuley +Anton Povarov +Denis Smirnov dennwc +DongYun Kang \ No newline at end of file diff --git a/vendor/github.com/gogo/protobuf/.travis.yml b/vendor/github.com/gogo/protobuf/.travis.yml new file mode 100644 index 000000000..12302e006 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/.travis.yml @@ -0,0 +1,20 @@ +env: + - PROTOBUF_VERSION=2.6.1 + - PROTOBUF_VERSION=3.0.2 + - PROTOBUF_VERSION=3.5.1 + +before_install: + - ./install-protobuf.sh + - PATH=/home/travis/bin:$PATH protoc --version + +script: + - PATH=/home/travis/bin:$PATH make buildserverall + - echo $TRAVIS_GO_VERSION + - if [[ "$PROTOBUF_VERSION" == "3.5.1" ]] && [[ "$TRAVIS_GO_VERSION" =~ ^1\.9\.[0-9]+$ ]]; then ! git status --porcelain | read || (git status; git diff; exit 1); fi + +language: go + +go: + - 1.8.x + - 1.9.x + - 1.10beta1 diff --git a/vendor/github.com/gogo/protobuf/Makefile b/vendor/github.com/gogo/protobuf/Makefile new file mode 100644 index 000000000..1d9ad1f56 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/Makefile @@ -0,0 +1,162 @@ +# Protocol Buffers for Go with Gadgets +# +# Copyright (c) 2013, The GoGo Authors. All rights reserved. +# http://github.com/gogo/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +GO_VERSION:=$(shell go version) + +.PHONY: nuke regenerate tests clean install gofmt vet contributors + +all: clean install regenerate install tests errcheck vet + +buildserverall: clean install regenerate install tests vet js + +install: + go install ./proto + go install ./gogoproto + go install ./jsonpb + go install ./protoc-gen-gogo + go install ./protoc-gen-gofast + go install ./protoc-gen-gogofast + go install ./protoc-gen-gogofaster + go install ./protoc-gen-gogoslick + go install ./protoc-gen-gostring + go install ./protoc-min-version + go install ./protoc-gen-combo + go install ./gogoreplace + +clean: + go clean ./... + +nuke: + go clean -i ./... + +gofmt: + gofmt -l -s -w . + +regenerate: + make -C protoc-gen-gogo/descriptor regenerate + make -C protoc-gen-gogo/plugin regenerate + make -C protoc-gen-gogo/testdata regenerate + make -C gogoproto regenerate + make -C proto/testdata regenerate + make -C jsonpb/jsonpb_test_proto regenerate + make -C _conformance regenerate + make -C types regenerate + make -C test regenerate + make -C test/example regenerate + make -C test/unrecognized regenerate + make -C test/group regenerate + make -C test/unrecognizedgroup regenerate + make -C test/enumstringer regenerate + make -C test/unmarshalmerge regenerate + make -C test/moredefaults regenerate + make -C test/issue8 regenerate + make -C test/enumprefix regenerate + make -C test/enumcustomname regenerate + make -C test/packed regenerate + make -C test/protosize regenerate + make -C test/tags regenerate + make -C test/oneof regenerate + make -C test/oneof3 regenerate + make -C test/theproto3 regenerate + make -C test/mapdefaults regenerate + make -C test/mapsproto2 regenerate + make -C test/issue42order regenerate + make -C proto generate-test-pbs + make -C test/importdedup regenerate + make -C test/importduplicate regenerate + make -C test/custombytesnonstruct regenerate + make -C test/required regenerate + make -C test/casttype regenerate + make -C test/castvalue regenerate + make -C vanity/test regenerate + make -C test/sizeunderscore regenerate + make -C test/issue34 regenerate + make -C test/empty-issue70 regenerate + make -C test/indeximport-issue72 regenerate + make -C test/fuzztests regenerate + make -C test/oneofembed regenerate + make -C test/asymetric-issue125 regenerate + make -C test/filedotname regenerate + make -C test/nopackage regenerate + make -C test/types regenerate + make -C test/proto3extension regenerate + make -C test/stdtypes regenerate + make -C test/data regenerate + make -C test/typedecl regenerate + make -C test/issue260 regenerate + make -C test/issue261 regenerate + make -C test/issue262 regenerate + make -C test/issue312 regenerate + make -C test/enumdecl regenerate + make -C test/typedecl_all regenerate + make -C test/enumdecl_all regenerate + make -C test/int64support regenerate + make -C test/issue322 regenerate + make -C test/issue330 regenerate + make gofmt + +tests: + go build ./test/enumprefix + go test ./... + (cd test/stdtypes && make test) + +vet: + go vet ./... + go tool vet --shadow . + +errcheck: + go get github.com/kisielk/errcheck + errcheck ./test/... + +drone: + sudo apt-get install protobuf-compiler + (cd $(GOPATH)/src/github.com/gogo/protobuf && make buildserverall) + +testall: + go get -u github.com/golang/protobuf/proto + make -C protoc-gen-gogo/testdata test + make -C vanity/test test + make -C test/registration test + make tests + +bench: + go get golang.org/x/tools/cmd/benchcmp + (cd test/mixbench && go build .) + ./test/mixbench/mixbench + +contributors: + git log --format='%aN <%aE>' | sort -fu > CONTRIBUTORS + +js: +ifeq (go1.9, $(findstring go1.9, $(GO_VERSION))) + go get -u github.com/gopherjs/gopherjs + gopherjs build github.com/gogo/protobuf/protoc-gen-gogo +endif + +update: + (cd protobuf && make update) diff --git a/vendor/github.com/gogo/protobuf/README b/vendor/github.com/gogo/protobuf/README new file mode 100644 index 000000000..035426df5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/README @@ -0,0 +1,258 @@ +GoGoProtobuf http://github.com/gogo/protobuf extends +GoProtobuf http://github.com/golang/protobuf + +# Go support for Protocol Buffers + +Google's data interchange format. +Copyright 2010 The Go Authors. +https://github.com/golang/protobuf + +This package and the code it generates requires at least Go 1.4. + +This software implements Go bindings for protocol buffers. For +information about protocol buffers themselves, see + https://developers.google.com/protocol-buffers/ + +## Installation ## + +To use this software, you must: +- Install the standard C++ implementation of protocol buffers from + https://developers.google.com/protocol-buffers/ +- Of course, install the Go compiler and tools from + https://golang.org/ + See + https://golang.org/doc/install + for details or, if you are using gccgo, follow the instructions at + https://golang.org/doc/install/gccgo +- Grab the code from the repository and install the proto package. + The simplest way is to run `go get -u github.com/golang/protobuf/protoc-gen-go`. + The compiler plugin, protoc-gen-go, will be installed in $GOBIN, + defaulting to $GOPATH/bin. It must be in your $PATH for the protocol + compiler, protoc, to find it. + +This software has two parts: a 'protocol compiler plugin' that +generates Go source files that, once compiled, can access and manage +protocol buffers; and a library that implements run-time support for +encoding (marshaling), decoding (unmarshaling), and accessing protocol +buffers. + +There is support for gRPC in Go using protocol buffers. +See the note at the bottom of this file for details. + +There are no insertion points in the plugin. + +GoGoProtobuf provides extensions for protocol buffers and GoProtobuf +see http://github.com/gogo/protobuf/gogoproto/doc.go + +## Using protocol buffers with Go ## + +Once the software is installed, there are two steps to using it. +First you must compile the protocol buffer definitions and then import +them, with the support library, into your program. + +To compile the protocol buffer definition, run protoc with the --gogo_out +parameter set to the directory you want to output the Go code to. + + protoc --gogo_out=. *.proto + +The generated files will be suffixed .pb.go. See the Test code below +for an example using such a file. + +The package comment for the proto library contains text describing +the interface provided in Go for protocol buffers. Here is an edited +version. + +If you are using any gogo.proto extensions you will need to specify the +proto_path to include the descriptor.proto and gogo.proto. +gogo.proto is located in github.com/gogo/protobuf/gogoproto +This should be fine, since your import is the same. +descriptor.proto is located in either github.com/gogo/protobuf/protobuf +or code.google.com/p/protobuf/trunk/src/ +Its import is google/protobuf/descriptor.proto so it might need some help. + + protoc --gogo_out=. -I=.:github.com/gogo/protobuf/protobuf *.proto + +========== + +The proto package converts data structures to and from the +wire format of protocol buffers. It works in concert with the +Go source code generated for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + Helpers for getting values are superseded by the + GetFoo methods and their use is deprecated. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed with the enum's type name. Enum types have + a String method, and a Enum method to assist in message construction. + - Nested groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +Consider file test.proto, containing + +```proto + syntax = "proto2"; + package example; + + enum FOO { X = 17; }; + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + } +``` + +To create and play with a Test object from the example package, + +```go + package main + + import ( + "log" + + "github.com/gogo/protobuf/proto" + "path/to/example" + ) + + func main() { + test := &example.Test { + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &example.Test_OptionalGroup { + RequiredField: proto.String("good bye"), + }, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &example.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // etc. + } +``` + + +## Parameters ## + +To pass extra parameters to the plugin, use a comma-separated +parameter list separated from the output directory by a colon: + + + protoc --gogo_out=plugins=grpc,import_path=mypackage:. *.proto + + +- `import_prefix=xxx` - a prefix that is added onto the beginning of + all imports. Useful for things like generating protos in a + subdirectory, or regenerating vendored protobufs in-place. +- `import_path=foo/bar` - used as the package if no input files + declare `go_package`. If it contains slashes, everything up to the + rightmost slash is ignored. +- `plugins=plugin1+plugin2` - specifies the list of sub-plugins to + load. The only plugin in this repo is `grpc`. +- `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is + associated with Go package quux/shme. This is subject to the + import_prefix parameter. + +## gRPC Support ## + +If a proto file specifies RPC services, protoc-gen-go can be instructed to +generate code compatible with gRPC (http://www.grpc.io/). To do this, pass +the `plugins` parameter to protoc-gen-go; the usual way is to insert it into +the --go_out argument to protoc: + + protoc --gogo_out=plugins=grpc:. *.proto + +## Compatibility ## + +The library and the generated code are expected to be stable over time. +However, we reserve the right to make breaking changes without notice for the +following reasons: + +- Security. A security issue in the specification or implementation may come to + light whose resolution requires breaking compatibility. We reserve the right + to address such security issues. +- Unspecified behavior. There are some aspects of the Protocol Buffers + specification that are undefined. Programs that depend on such unspecified + behavior may break in future releases. +- Specification errors or changes. If it becomes necessary to address an + inconsistency, incompleteness, or change in the Protocol Buffers + specification, resolving the issue could affect the meaning or legality of + existing programs. We reserve the right to address such issues, including + updating the implementations. +- Bugs. If the library has a bug that violates the specification, a program + that depends on the buggy behavior may break if the bug is fixed. We reserve + the right to fix such bugs. +- Adding methods or fields to generated structs. These may conflict with field + names that already exist in a schema, causing applications to break. When the + code generator encounters a field in the schema that would collide with a + generated field or method name, the code generator will append an underscore + to the generated field or method name. +- Adding, removing, or changing methods or fields in generated structs that + start with `XXX`. These parts of the generated code are exported out of + necessity, but should not be considered part of the public API. +- Adding, removing, or changing unexported symbols in generated code. + +Any breaking changes outside of these will be announced 6 months in advance to +protobuf@googlegroups.com. + +You should, whenever possible, use generated code created by the `protoc-gen-go` +tool built at the same commit as the `proto` package. The `proto` package +declares package-level constants in the form `ProtoPackageIsVersionX`. +Application code and generated code may depend on one of these constants to +ensure that compilation will fail if the available version of the proto library +is too old. Whenever we make a change to the generated code that requires newer +library support, in the same commit we will increment the version number of the +generated code and declare a new package-level constant whose name incorporates +the latest version number. Removing a compatibility constant is considered a +breaking change and would be subject to the announcement policy stated above. + +## Plugins ## + +The `protoc-gen-go/generator` package exposes a plugin interface, +which is used by the gRPC code generation. This interface is not +supported and is subject to incompatible changes without notice. diff --git a/vendor/github.com/gogo/protobuf/Readme.md b/vendor/github.com/gogo/protobuf/Readme.md new file mode 100644 index 000000000..a4ad3eecd --- /dev/null +++ b/vendor/github.com/gogo/protobuf/Readme.md @@ -0,0 +1,139 @@ +# Protocol Buffers for Go with Gadgets + +[![Build Status](https://travis-ci.org/gogo/protobuf.svg?branch=master)](https://travis-ci.org/gogo/protobuf) + +gogoprotobuf is a fork of golang/protobuf with extra code generation features. + +This code generation is used to achieve: + + - fast marshalling and unmarshalling + - more canonical Go structures + - goprotobuf compatibility + - less typing by optionally generating extra helper code + - peace of mind by optionally generating test and benchmark code + - other serialization formats + +Keeping track of how up to date gogoprotobuf is relative to golang/protobuf is done in this +issue + +## Users + +These projects use gogoprotobuf: + + - etcd - blog - sample proto file + - spacemonkey - blog + - badoo - sample proto file + - mesos-go - sample proto file + - heka - the switch from golang/protobuf to gogo/protobuf when it was still on code.google.com + - cockroachdb - sample proto file + - go-ipfs - sample proto file + - rkive-go - sample proto file + - dropbox + - srclib - sample proto file + - adyoulike + - cloudfoundry - sample proto file + - kubernetes - go2idl built on top of gogoprotobuf + - dgraph - release notes - benchmarks + - centrifugo - release notes - blog + - docker swarmkit - sample proto file + - nats.io - go-nats-streaming + - tidb - Communication between tidb and tikv + - protoactor-go - vanity command that also generates actors from service definitions + - containerd - vanity command with custom field names that conforms to the golang convention. + - nakama + - proteus + - carbonzipper stack + - sendgrid + - zero-os/0-stor + +Please let us know if you are using gogoprotobuf by posting on our GoogleGroup. + +### Mentioned + + - Cloudflare - go serialization talk - Albert Strasheim + - GopherCon 2014 Writing High Performance Databases in Go by Ben Johnson + - alecthomas' go serialization benchmarks + +## Getting Started + +There are several ways to use gogoprotobuf, but for all you need to install go and protoc. +After that you can choose: + + - Speed + - More Speed and more generated code + - Most Speed and most customization + +### Installation + +To install it, you must first have Go (at least version 1.6.3) installed (see [http://golang.org/doc/install](http://golang.org/doc/install)). Latest patch versions of Go 1.8, 1.9 and 1.10 are continuously tested. + +Next, install the standard protocol buffer implementation from [https://github.com/google/protobuf](https://github.com/google/protobuf). +Most versions from 2.3.1 should not give any problems, but 2.6.1, 3.0.2 and 3.5.1 are continuously tested. + +### Speed + +Install the protoc-gen-gofast binary + + go get github.com/gogo/protobuf/protoc-gen-gofast + +Use it to generate faster marshaling and unmarshaling go code for your protocol buffers. + + protoc --gofast_out=. myproto.proto + +This does not allow you to use any of the other gogoprotobuf [extensions](https://github.com/gogo/protobuf/blob/master/extensions.md). + +### More Speed and more generated code + +Fields without pointers cause less time in the garbage collector. +More code generation results in more convenient methods. + +Other binaries are also included: + + protoc-gen-gogofast (same as gofast, but imports gogoprotobuf) + protoc-gen-gogofaster (same as gogofast, without XXX_unrecognized, less pointer fields) + protoc-gen-gogoslick (same as gogofaster, but with generated string, gostring and equal methods) + +Installing any of these binaries is easy. Simply run: + + go get github.com/gogo/protobuf/proto + go get github.com/gogo/protobuf/{binary} + go get github.com/gogo/protobuf/gogoproto + +These binaries allow you to use gogoprotobuf [extensions](https://github.com/gogo/protobuf/blob/master/extensions.md). You can also use your own binary. + +To generate the code, you also need to set the include path properly. + + protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf/protobuf --{binary}_out=. myproto.proto + +To use proto files from "google/protobuf" you need to add additional args to protoc. + + protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf/protobuf --{binary}_out=\ + Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,\ + Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,\ + Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,\ + Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,\ + Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types:. \ + myproto.proto + +Note that in the protoc command, {binary} does not contain the initial prefix of "protoc-gen". + +### Most Speed and most customization + +Customizing the fields of the messages to be the fields that you actually want to use removes the need to copy between the structs you use and structs you use to serialize. +gogoprotobuf also offers more serialization formats and generation of tests and even more methods. + +Please visit the [extensions](https://github.com/gogo/protobuf/blob/master/extensions.md) page for more documentation. + +Install protoc-gen-gogo: + + go get github.com/gogo/protobuf/proto + go get github.com/gogo/protobuf/jsonpb + go get github.com/gogo/protobuf/protoc-gen-gogo + go get github.com/gogo/protobuf/gogoproto + +## GRPC + +It works the same as golang/protobuf, simply specify the plugin. +Here is an example using gofast: + + protoc --gofast_out=plugins=grpc:. my.proto diff --git a/vendor/github.com/gogo/protobuf/bench.md b/vendor/github.com/gogo/protobuf/bench.md new file mode 100644 index 000000000..16da66ad2 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/bench.md @@ -0,0 +1,190 @@ +# Benchmarks + +## How to reproduce + +For a comparison run: + + make bench + +followed by [benchcmp](http://code.google.com/p/go/source/browse/misc/benchcmp benchcmp) on the resulting files: + + $GOROOT/misc/benchcmp $GOPATH/src/github.com/gogo/protobuf/test/mixbench/marshal.txt $GOPATH/src/github.com/gogo/protobuf/test/mixbench/marshaler.txt + $GOROOT/misc/benchcmp $GOPATH/src/github.com/gogo/protobuf/test/mixbench/unmarshal.txt $GOPATH/src/github.com/gogo/protobuf/test/mixbench/unmarshaler.txt + +Benchmarks ran on Revision: 11c56be39364 + +June 2013 + +Processor 2,66 GHz Intel Core i7 + +Memory 8 GB 1067 MHz DDR3 + +## Marshaler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
benchmarkold ns/opnew ns/opdelta
BenchmarkNidOptNativeProtoMarshal2656889-66.53%
BenchmarkNinOptNativeProtoMarshal26511015-61.71%
BenchmarkNidRepNativeProtoMarshal4266112519-70.65%
BenchmarkNinRepNativeProtoMarshal4230612354-70.80%
BenchmarkNidRepPackedNativeProtoMarshal3414811902-65.15%
BenchmarkNinRepPackedNativeProtoMarshal3337511969-64.14%
BenchmarkNidOptStructProtoMarshal71483727-47.86%
BenchmarkNinOptStructProtoMarshal69563481-49.96%
BenchmarkNidRepStructProtoMarshal4655119492-58.13%
BenchmarkNinRepStructProtoMarshal4671519043-59.24%
BenchmarkNidEmbeddedStructProtoMarshal52312050-60.81%
BenchmarkNinEmbeddedStructProtoMarshal46652000-57.13%
BenchmarkNidNestedStructProtoMarshal181106103604-42.79%
BenchmarkNinNestedStructProtoMarshal182053102069-43.93%
BenchmarkNidOptCustomProtoMarshal1209310-74.36%
BenchmarkNinOptCustomProtoMarshal1435277-80.70%
BenchmarkNidRepCustomProtoMarshal4126763-81.51%
BenchmarkNinRepCustomProtoMarshal3972769-80.64%
BenchmarkNinOptNativeUnionProtoMarshal973303-68.86%
BenchmarkNinOptStructUnionProtoMarshal1536521-66.08%
BenchmarkNinEmbeddedStructUnionProtoMarshal2327884-62.01%
BenchmarkNinNestedStructUnionProtoMarshal2070743-64.11%
BenchmarkTreeProtoMarshal1554838-46.07%
BenchmarkOrBranchProtoMarshal31562012-36.25%
BenchmarkAndBranchProtoMarshal31831996-37.29%
BenchmarkLeafProtoMarshal965606-37.20%
BenchmarkDeepTreeProtoMarshal23161283-44.60%
BenchmarkADeepBranchProtoMarshal27191492-45.13%
BenchmarkAndDeepBranchProtoMarshal46632922-37.34%
BenchmarkDeepLeafProtoMarshal18491016-45.05%
BenchmarkNilProtoMarshal43976-82.53%
BenchmarkNidOptEnumProtoMarshal514152-70.43%
BenchmarkNinOptEnumProtoMarshal550158-71.27%
BenchmarkNidRepEnumProtoMarshal647207-68.01%
BenchmarkNinRepEnumProtoMarshal662213-67.82%
BenchmarkTimerProtoMarshal934271-70.99%
BenchmarkMyExtendableProtoMarshal608185-69.57%
BenchmarkOtherExtenableProtoMarshal1112332-70.14%
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
benchmarkold MB/snew MB/sspeedup
BenchmarkNidOptNativeProtoMarshal126.86378.862.99x
BenchmarkNinOptNativeProtoMarshal114.27298.422.61x
BenchmarkNidRepNativeProtoMarshal164.25561.203.42x
BenchmarkNinRepNativeProtoMarshal166.10568.233.42x
BenchmarkNidRepPackedNativeProtoMarshal99.10283.972.87x
BenchmarkNinRepPackedNativeProtoMarshal101.30282.312.79x
BenchmarkNidOptStructProtoMarshal176.83339.071.92x
BenchmarkNinOptStructProtoMarshal163.59326.572.00x
BenchmarkNidRepStructProtoMarshal178.84427.492.39x
BenchmarkNinRepStructProtoMarshal178.70437.692.45x
BenchmarkNidEmbeddedStructProtoMarshal124.24317.562.56x
BenchmarkNinEmbeddedStructProtoMarshal132.03307.992.33x
BenchmarkNidNestedStructProtoMarshal192.91337.861.75x
BenchmarkNinNestedStructProtoMarshal192.44344.451.79x
BenchmarkNidOptCustomProtoMarshal29.77116.033.90x
BenchmarkNinOptCustomProtoMarshal22.29115.385.18x
BenchmarkNidRepCustomProtoMarshal35.14189.805.40x
BenchmarkNinRepCustomProtoMarshal36.50188.405.16x
BenchmarkNinOptNativeUnionProtoMarshal32.87105.393.21x
BenchmarkNinOptStructUnionProtoMarshal66.40195.762.95x
BenchmarkNinEmbeddedStructUnionProtoMarshal93.24245.262.63x
BenchmarkNinNestedStructUnionProtoMarshal57.49160.062.78x
BenchmarkTreeProtoMarshal137.64255.121.85x
BenchmarkOrBranchProtoMarshal137.80216.101.57x
BenchmarkAndBranchProtoMarshal136.64217.891.59x
BenchmarkLeafProtoMarshal214.48341.531.59x
BenchmarkDeepTreeProtoMarshal95.85173.031.81x
BenchmarkADeepBranchProtoMarshal82.73150.781.82x
BenchmarkAndDeepBranchProtoMarshal96.72153.981.59x
BenchmarkDeepLeafProtoMarshal117.34213.411.82x
BenchmarkNidOptEnumProtoMarshal3.8913.163.38x
BenchmarkNinOptEnumProtoMarshal1.826.303.46x
BenchmarkNidRepEnumProtoMarshal12.3638.503.11x
BenchmarkNinRepEnumProtoMarshal12.0837.533.11x
BenchmarkTimerProtoMarshal73.81253.873.44x
BenchmarkMyExtendableProtoMarshal13.1543.083.28x
BenchmarkOtherExtenableProtoMarshal24.2881.093.34x
+ +## Unmarshaler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
benchmarkold ns/opnew ns/opdelta
BenchmarkNidOptNativeProtoUnmarshal25211006-60.10%
BenchmarkNinOptNativeProtoUnmarshal25291750-30.80%
BenchmarkNidRepNativeProtoUnmarshal4906735299-28.06%
BenchmarkNinRepNativeProtoUnmarshal4799035456-26.12%
BenchmarkNidRepPackedNativeProtoUnmarshal2645623950-9.47%
BenchmarkNinRepPackedNativeProtoUnmarshal2649924037-9.29%
BenchmarkNidOptStructProtoUnmarshal68033873-43.07%
BenchmarkNinOptStructProtoUnmarshal67864154-38.79%
BenchmarkNidRepStructProtoUnmarshal5627631970-43.19%
BenchmarkNinRepStructProtoUnmarshal4875031832-34.70%
BenchmarkNidEmbeddedStructProtoUnmarshal45561973-56.69%
BenchmarkNinEmbeddedStructProtoUnmarshal44851975-55.96%
BenchmarkNidNestedStructProtoUnmarshal223395135844-39.19%
BenchmarkNinNestedStructProtoUnmarshal226446134022-40.82%
BenchmarkNidOptCustomProtoUnmarshal1859300-83.86%
BenchmarkNinOptCustomProtoUnmarshal1486402-72.95%
BenchmarkNidRepCustomProtoUnmarshal82291669-79.72%
BenchmarkNinRepCustomProtoUnmarshal82531649-80.02%
BenchmarkNinOptNativeUnionProtoUnmarshal840307-63.45%
BenchmarkNinOptStructUnionProtoUnmarshal1395639-54.19%
BenchmarkNinEmbeddedStructUnionProtoUnmarshal22971167-49.19%
BenchmarkNinNestedStructUnionProtoUnmarshal1820889-51.15%
BenchmarkTreeProtoUnmarshal1521720-52.66%
BenchmarkOrBranchProtoUnmarshal26691385-48.11%
BenchmarkAndBranchProtoUnmarshal26671420-46.76%
BenchmarkLeafProtoUnmarshal1171584-50.13%
BenchmarkDeepTreeProtoUnmarshal20651081-47.65%
BenchmarkADeepBranchProtoUnmarshal26951178-56.29%
BenchmarkAndDeepBranchProtoUnmarshal40551918-52.70%
BenchmarkDeepLeafProtoUnmarshal1758865-50.80%
BenchmarkNilProtoUnmarshal56463-88.79%
BenchmarkNidOptEnumProtoUnmarshal76273-90.34%
BenchmarkNinOptEnumProtoUnmarshal764163-78.66%
BenchmarkNidRepEnumProtoUnmarshal1078447-58.53%
BenchmarkNinRepEnumProtoUnmarshal1071479-55.28%
BenchmarkTimerProtoUnmarshal1128362-67.91%
BenchmarkMyExtendableProtoUnmarshal808217-73.14%
BenchmarkOtherExtenableProtoUnmarshal1233517-58.07%
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
benchmarkold MB/snew MB/sspeedup
BenchmarkNidOptNativeProtoUnmarshal133.67334.982.51x
BenchmarkNinOptNativeProtoUnmarshal119.77173.081.45x
BenchmarkNidRepNativeProtoUnmarshal143.23199.121.39x
BenchmarkNinRepNativeProtoUnmarshal146.07198.161.36x
BenchmarkNidRepPackedNativeProtoUnmarshal127.80141.041.10x
BenchmarkNinRepPackedNativeProtoUnmarshal127.55140.781.10x
BenchmarkNidOptStructProtoUnmarshal185.79326.311.76x
BenchmarkNinOptStructProtoUnmarshal167.68273.661.63x
BenchmarkNidRepStructProtoUnmarshal147.88260.391.76x
BenchmarkNinRepStructProtoUnmarshal171.20261.971.53x
BenchmarkNidEmbeddedStructProtoUnmarshal142.86329.422.31x
BenchmarkNinEmbeddedStructProtoUnmarshal137.33311.832.27x
BenchmarkNidNestedStructProtoUnmarshal154.97259.471.67x
BenchmarkNinNestedStructProtoUnmarshal154.32258.421.67x
BenchmarkNidOptCustomProtoUnmarshal19.36119.666.18x
BenchmarkNinOptCustomProtoUnmarshal21.5279.503.69x
BenchmarkNidRepCustomProtoUnmarshal17.6286.864.93x
BenchmarkNinRepCustomProtoUnmarshal17.5787.925.00x
BenchmarkNinOptNativeUnionProtoUnmarshal38.07104.122.73x
BenchmarkNinOptStructUnionProtoUnmarshal73.08159.542.18x
BenchmarkNinEmbeddedStructUnionProtoUnmarshal94.00185.921.98x
BenchmarkNinNestedStructUnionProtoUnmarshal65.35133.752.05x
BenchmarkTreeProtoUnmarshal141.28297.132.10x
BenchmarkOrBranchProtoUnmarshal162.56313.961.93x
BenchmarkAndBranchProtoUnmarshal163.06306.151.88x
BenchmarkLeafProtoUnmarshal176.72354.192.00x
BenchmarkDeepTreeProtoUnmarshal107.50205.301.91x
BenchmarkADeepBranchProtoUnmarshal83.48190.882.29x
BenchmarkAndDeepBranchProtoUnmarshal110.97234.602.11x
BenchmarkDeepLeafProtoUnmarshal123.40250.732.03x
BenchmarkNidOptEnumProtoUnmarshal2.6227.1610.37x
BenchmarkNinOptEnumProtoUnmarshal1.316.114.66x
BenchmarkNidRepEnumProtoUnmarshal7.4217.882.41x
BenchmarkNinRepEnumProtoUnmarshal7.4716.692.23x
BenchmarkTimerProtoUnmarshal61.12190.343.11x
BenchmarkMyExtendableProtoUnmarshal9.9036.713.71x
BenchmarkOtherExtenableProtoUnmarshal21.9052.132.38x
\ No newline at end of file diff --git a/vendor/github.com/gogo/protobuf/custom_types.md b/vendor/github.com/gogo/protobuf/custom_types.md new file mode 100644 index 000000000..3eed249b5 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/custom_types.md @@ -0,0 +1,68 @@ +# Custom types + +Custom types is a gogo protobuf extensions that allows for using a custom +struct type to decorate the underlying structure of the protocol message. + +# How to use + +## Defining the protobuf message + +```proto +message CustomType { + optional ProtoType Field = 1 [(gogoproto.customtype) = "T"]; +} + +message ProtoType { + optional string Field = 1; +} +``` + +or alternatively you can declare the field type in the protocol message to be +`bytes`: + +```proto +message BytesCustomType { + optional bytes Field = 1 [(gogoproto.customtype) = "T"]; +} +``` + +The downside of using `bytes` is that it makes it harder to generate protobuf +code in other languages. In either case, it is the user responsibility to +ensure that the custom type marshals and unmarshals to the expected wire +format. That is, in the first example, gogo protobuf will not attempt to ensure +that the wire format of `ProtoType` and `T` are wire compatible. + +## Custom type method signatures + +The custom type must define the following methods with the given +signatures. Assuming the custom type is called `T`: + +```go +func (t T) Marshal() ([]byte, error) {} +func (t *T) MarshalTo(data []byte) (n int, err error) {} +func (t *T) Unmarshal(data []byte) error {} + +func (t T) MarshalJSON() ([]byte, error) {} +func (t *T) UnmarshalJSON(data []byte) error {} + +// only required if the compare option is set +func (t T) Compare(other T) int {} +// only required if the equal option is set +func (t T) Equal(other T) bool {} +// only required if populate option is set +func NewPopulatedT(r randyThetest) *T {} +``` + +Check [t.go](test/t.go) for a full example + +# Warnings and issues + +`Warning about customtype: It is your responsibility to test all cases of your marshaling, unmarshaling and size methods implemented for your custom type.` + +Issues with customtype include: + * A Bytes method is not allowed. + * Defining a customtype as a fake proto message is broken. + * proto.Clone is broken. + * Using a proto message as a customtype is not allowed. + * cusomtype of type map can not UnmarshalText + * customtype of type struct cannot jsonpb unmarshal diff --git a/vendor/github.com/gogo/protobuf/extensions.md b/vendor/github.com/gogo/protobuf/extensions.md new file mode 100644 index 000000000..35dfee16f --- /dev/null +++ b/vendor/github.com/gogo/protobuf/extensions.md @@ -0,0 +1,162 @@ +# gogoprotobuf Extensions + +Here is an [example.proto](https://github.com/gogo/protobuf/blob/master/test/example/example.proto) which uses most of the gogoprotobuf code generation plugins. + +Please also look at the example [Makefile](https://github.com/gogo/protobuf/blob/master/test/example/Makefile) which shows how to specify the `descriptor.proto` and `gogo.proto` in your proto_path + +The documentation at [http://godoc.org/github.com/gogo/protobuf/gogoproto](http://godoc.org/github.com/gogo/protobuf/gogoproto) describes the extensions made to goprotobuf in more detail. + +Also see [http://godoc.org/github.com/gogo/protobuf/plugin/](http://godoc.org/github.com/gogo/protobuf/plugin/) for documentation of each of the extensions which have their own plugins. + +# Fast Marshalling and Unmarshalling + +Generating a `Marshal`, `MarshalTo`, `Size` (or `ProtoSize`) and `Unmarshal` method for a struct results in faster marshalling and unmarshalling than when using reflect. + +See [BenchComparison](https://github.com/gogo/protobuf/blob/master/bench.md) for a comparison between reflect and generated code used for marshalling and unmarshalling. + + + + + + + + + + + +
NameOptionTypeDescriptionDefault
marshalerMessageboolif true, a Marshal and MarshalTo method is generated for the specific messagefalse
sizerMessageboolif true, a Size method is generated for the specific messagefalse
unmarshaler Message bool if true, an Unmarshal method is generated for the specific message false
protosizerMessageboolif true, a ProtoSize method is generated for the specific messagefalse
unsafe_marshaler (deprecated) Message bool if true, a Marshal and MarshalTo method is generated. false
unsafe_unmarshaler (deprecated) Message bool if true, an Unmarshal method is generated. false
stable_marshaler Message bool if true, a Marshal and MarshalTo method is generated for the specific message, but unlike marshaler the output is guaranteed to be deterministic, at the sacrifice of some speed false
typedecl (beta) Message bool if false, type declaration of the message is excluded from the generated output. Requires the marshaler and unmarshaler to be generated. true
+ +# More Canonical Go Structures + +Lots of times working with a goprotobuf struct will lead you to a place where you create another struct that is easier to work with and then have a function to copy the values between the two structs. + +You might also find that basic structs that started their life as part of an API need to be sent over the wire. With gob, you could just send it. With goprotobuf, you need to make a new struct. + +`gogoprotobuf` tries to fix these problems with the nullable, embed, customtype, customname, casttype, castkey and castvalue field extensions. + + + + + + + + + + + + + + + +
NameOptionTypeDescriptionDefault
nullable Field bool if false, a field is generated without a pointer (see warning below). true
embed Field bool if true, the field is generated as an embedded field. false
customtype Field string It works with the Marshal and Unmarshal methods, to allow you to have your own types in your struct, but marshal to bytes. For example, custom.Uuid or custom.Fixed128. For more information please refer to the CustomTypes document goprotobuf type
customname (beta) Field string Changes the generated fieldname. This is especially useful when generated methods conflict with fieldnames. goprotobuf field name
casttype (beta) Field string Changes the generated field type. It assumes that this type is castable to the original goprotobuf field type. It currently does not support maps, structs or enums. goprotobuf field type
castkey (beta) Field string Changes the generated fieldtype for a map key. All generated code assumes that this type is castable to the protocol buffer field type. Only supported on maps. goprotobuf field type
castvalue (beta) Field string Changes the generated fieldtype for a map value. All generated code assumes that this type is castable to the protocol buffer field type. Only supported on maps. goprotobuf field type
enum_customname (beta) Enum string Sets the type name of an enum. If goproto_enum_prefix is enabled, this value will be used as a prefix when generating enum values.goprotobuf enum type name. Helps with golint issues.
enumdecl (beta) Enum bool if false, type declaration of the enum is excluded from the generated output. Requires the marshaler and unmarshaler to be generated. true
enumvalue_customname (beta) Enum Value string Changes the generated enum name. Helps with golint issues.goprotobuf enum value name
stdtime Timestamp Field bool Changes the Well Known Timestamp Type to time.TimeTimestamp
stdduration Duration Field bool Changes the Well Known Duration Type to time.DurationDuration
+ +`Warning about nullable: according to the Protocol Buffer specification, you should be able to tell whether a field is set or unset. With the option nullable=false this feature is lost, since your non-nullable fields will always be set.` + +# Goprotobuf Compatibility + +Gogoprotobuf is compatible with Goprotobuf, because it is compatible with protocol buffers (see the section on tests below). + +Gogoprotobuf generates the same code as goprotobuf if no extensions are used. + +The enumprefix, getters and stringer extensions can be used to remove some of the unnecessary code generated by goprotobuf. + + + + + + + + + + + +
NameOptionTypeDescriptionDefault
gogoproto_import File bool if false, the generated code imports github.com/golang/protobuf/proto instead of github.com/gogo/protobuf/proto. true
goproto_enum_prefix Enum bool if false, generates the enum constant names without the messagetype prefix true
goproto_getters Message bool if false, the message is generated without get methods, this is useful when you would rather want to use face true
goproto_stringer Message bool if false, the message is generated without the default string method, this is useful for rather using stringer true
goproto_enum_stringer (experimental) Enum bool if false, the enum is generated without the default string method, this is useful for rather using enum_stringer true
goproto_extensions_map (beta) Message bool if false, the extensions field is generated as type []byte instead of type map[int32]proto.Extension true
goproto_unrecognized (beta) Message bool if false, XXX_unrecognized field is not generated. This is useful to reduce GC pressure at the cost of losing information about unrecognized fields. true
goproto_registration (beta) File bool if true, the generated files will register all messages and types against both gogo/protobuf and golang/protobuf. This is necessary when using third-party packages which read registrations from golang/protobuf (such as the grpc-gateway). false
+ +# Less Typing + +The Protocol Buffer language is very parseable and extra code can be easily generated for structures. + +Helper methods, functions and interfaces can be generated by triggering certain extensions like gostring. + + + + + + + + + + + + + +
NameOptionTypeDescriptionDefault
gostring Message bool if true, a `GoString` method is generated. This returns a string representing valid go code to reproduce the current state of the struct. false
onlyone Message bool if true, all fields must be nullable and only one of the fields may be set, like a union. Two methods are generated: `GetValue() interface{}` and `SetValue(v interface{}) (set bool)`. These provide easier interaction with a union. false
equal Message bool if true, an Equal method is generated false
compare Message bool if true, a Compare method is generated. This is very useful for quickly implementing sort on a list of protobuf structs false
verbose_equal Message bool if true, a verbose equal method is generated for the message. This returns an error which describes the exact element which is not equal to the exact element in the other struct. false
stringer Message bool if true, a String method is generated for the message. false
face Message bool if true, a function will be generated which can convert a structure which satisfies an interface (face) to the specified structure. This interface contains getters for each of the fields in the struct. The specified struct is also generated with the getters. This allows it to satisfy its own face. false
description (beta) Message bool if true, a Description method is generated for the message. false
populate Message bool if true, a `NewPopulated` function is generated. This is necessary for generated tests. false
enum_stringer (experimental) Enum bool if true, a String method is generated for an Enum false
+ +Issues with Compare include: + * Oneof is not supported yet + * Not all Well Known Types are supported yet + * Maps are not supported + +#Peace of Mind + +Test and Benchmark generation is done with the following extensions: + + + + +
testgen Message bool if true, tests are generated for proto, json and prototext marshalling as well as for some of the other enabled plugins false
benchgen Message bool if true, benchmarks are generated for proto, json and prototext marshalling as well as for some of the other enabled plugins false
+ +# More Serialization Formats + +Other serialization formats like xml and json typically use reflect to marshal and unmarshal structured data. Manipulating these structs into something other than the default Go requires editing tags. The following extensions provide ways of editing these tags for the generated protobuf structs. + + + + +
jsontag (beta) Field string if set, the json tag value between the double quotes is replaced with this string fieldname
moretags (beta) Field string if set, this string is appended to the tag string empty
+ +Here is a longer explanation of jsontag and moretags + +# File Options + +Each of the boolean message and enum extensions also have a file extension: + + * `marshaler_all` + * `sizer_all` + * `protosizer_all` + * `unmarshaler_all` + * `unsafe_marshaler_all` + * `unsafe_unmarshaler_all` + * `stable_marshaler_all` + * `goproto_enum_prefix_all` + * `goproto_getters_all` + * `goproto_stringer_all` + * `goproto_enum_stringer_all` + * `goproto_extensions_map_all` + * `goproto_unrecognized_all` + * `gostring_all` + * `onlyone_all` + * `equal_all` + * `compare_all` + * `verbose_equal_all` + * `stringer_all` + * `enum_stringer_all` + * `face_all` + * `description_all` + * `populate_all` + * `testgen_all` + * `benchgen_all` + * `enumdecl_all` + * `typedecl_all` + +Each of these are the same as their Message Option counterparts, except they apply to all messages in the file. Their Message option counterparts can also be used to overwrite their effect. + +# Tests + + * The normal barrage of tests are run with: `make tests` + * A few weird tests: `make testall` + * Tests for compatibility with [golang/protobuf](https://github.com/golang/protobuf) are handled by a different project [harmonytests](https://github.com/gogo/harmonytests), since it requires goprotobuf. + * Cross version tests are made with [Travis CI](https://travis-ci.org/gogo/protobuf). + * GRPC Tests are also handled by a different project [grpctests](https://github.com/gogo/grpctests), since it depends on a lot of grpc libraries. + * Thanks to [go-fuzz](https://github.com/dvyukov/go-fuzz/) we have proper [fuzztests](https://github.com/gogo/fuzztests). + diff --git a/vendor/github.com/gogo/protobuf/install-protobuf.sh b/vendor/github.com/gogo/protobuf/install-protobuf.sh new file mode 100755 index 000000000..f42fc9e63 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/install-protobuf.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -ex + +die() { + echo "$@" >&2 + exit 1 +} + +cd /home/travis + +case "$PROTOBUF_VERSION" in +2*) + basename=protobuf-$PROTOBUF_VERSION + wget https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/$basename.tar.gz + tar xzf $basename.tar.gz + cd protobuf-$PROTOBUF_VERSION + ./configure --prefix=/home/travis && make -j2 && make install + ;; +3*) + basename=protoc-$PROTOBUF_VERSION-linux-x86_64 + wget https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/$basename.zip + unzip $basename.zip + ;; +*) + die "unknown protobuf version: $PROTOBUF_VERSION" + ;; +esac diff --git a/vendor/github.com/gogo/protobuf/proto/Makefile b/vendor/github.com/gogo/protobuf/proto/Makefile new file mode 100644 index 000000000..41c717573 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/Makefile @@ -0,0 +1,43 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +install: + go install + +test: install generate-test-pbs + go test + + +generate-test-pbs: + make install + make -C testdata + protoc-min-version --version="3.0.0" --proto_path=.:../../../../:../protobuf --gogo_out=Mtestdata/test.proto=github.com/gogo/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. proto3_proto/proto3.proto + make diff --git a/vendor/github.com/gogo/protobuf/proto/all_test.go b/vendor/github.com/gogo/protobuf/proto/all_test.go new file mode 100644 index 000000000..b5f8709d8 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/all_test.go @@ -0,0 +1,2278 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "math" + "math/rand" + "reflect" + "runtime/debug" + "strings" + "testing" + "time" + + . "github.com/gogo/protobuf/proto" + . "github.com/gogo/protobuf/proto/testdata" +) + +var globalO *Buffer + +func old() *Buffer { + if globalO == nil { + globalO = NewBuffer(nil) + } + globalO.Reset() + return globalO +} + +func equalbytes(b1, b2 []byte, t *testing.T) { + if len(b1) != len(b2) { + t.Errorf("wrong lengths: 2*%d != %d", len(b1), len(b2)) + return + } + for i := 0; i < len(b1); i++ { + if b1[i] != b2[i] { + t.Errorf("bad byte[%d]:%x %x: %s %s", i, b1[i], b2[i], b1, b2) + } + } +} + +func initGoTestField() *GoTestField { + f := new(GoTestField) + f.Label = String("label") + f.Type = String("type") + return f +} + +// These are all structurally equivalent but the tag numbers differ. +// (It's remarkable that required, optional, and repeated all have +// 8 letters.) +func initGoTest_RequiredGroup() *GoTest_RequiredGroup { + return &GoTest_RequiredGroup{ + RequiredField: String("required"), + } +} + +func initGoTest_OptionalGroup() *GoTest_OptionalGroup { + return &GoTest_OptionalGroup{ + RequiredField: String("optional"), + } +} + +func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup { + return &GoTest_RepeatedGroup{ + RequiredField: String("repeated"), + } +} + +func initGoTest(setdefaults bool) *GoTest { + pb := new(GoTest) + if setdefaults { + pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted) + pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted) + pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted) + pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted) + pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted) + pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted) + pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted) + pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted) + pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted) + pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted) + pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted + pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) + pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) + } + + pb.Kind = GoTest_TIME.Enum() + pb.RequiredField = initGoTestField() + pb.F_BoolRequired = Bool(true) + pb.F_Int32Required = Int32(3) + pb.F_Int64Required = Int64(6) + pb.F_Fixed32Required = Uint32(32) + pb.F_Fixed64Required = Uint64(64) + pb.F_Uint32Required = Uint32(3232) + pb.F_Uint64Required = Uint64(6464) + pb.F_FloatRequired = Float32(3232) + pb.F_DoubleRequired = Float64(6464) + pb.F_StringRequired = String("string") + pb.F_BytesRequired = []byte("bytes") + pb.F_Sint32Required = Int32(-32) + pb.F_Sint64Required = Int64(-64) + pb.Requiredgroup = initGoTest_RequiredGroup() + + return pb +} + +func fail(msg string, b *bytes.Buffer, s string, t *testing.T) { + data := b.Bytes() + ld := len(data) + ls := len(s) / 2 + + fmt.Printf("fail %s ld=%d ls=%d\n", msg, ld, ls) + + // find the interesting spot - n + n := ls + if ld < ls { + n = ld + } + j := 0 + for i := 0; i < n; i++ { + bs := hex(s[j])*16 + hex(s[j+1]) + j += 2 + if data[i] == bs { + continue + } + n = i + break + } + l := n - 10 + if l < 0 { + l = 0 + } + h := n + 10 + + // find the interesting spot - n + fmt.Printf("is[%d]:", l) + for i := l; i < h; i++ { + if i >= ld { + fmt.Printf(" --") + continue + } + fmt.Printf(" %.2x", data[i]) + } + fmt.Printf("\n") + + fmt.Printf("sb[%d]:", l) + for i := l; i < h; i++ { + if i >= ls { + fmt.Printf(" --") + continue + } + bs := hex(s[j])*16 + hex(s[j+1]) + j += 2 + fmt.Printf(" %.2x", bs) + } + fmt.Printf("\n") + + t.Fail() + + // t.Errorf("%s: \ngood: %s\nbad: %x", msg, s, b.Bytes()) + // Print the output in a partially-decoded format; can + // be helpful when updating the test. It produces the output + // that is pasted, with minor edits, into the argument to verify(). + // data := b.Bytes() + // nesting := 0 + // for b.Len() > 0 { + // start := len(data) - b.Len() + // var u uint64 + // u, err := DecodeVarint(b) + // if err != nil { + // fmt.Printf("decode error on varint:", err) + // return + // } + // wire := u & 0x7 + // tag := u >> 3 + // switch wire { + // case WireVarint: + // v, err := DecodeVarint(b) + // if err != nil { + // fmt.Printf("decode error on varint:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", + // data[start:len(data)-b.Len()], tag, wire, v) + // case WireFixed32: + // v, err := DecodeFixed32(b) + // if err != nil { + // fmt.Printf("decode error on fixed32:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", + // data[start:len(data)-b.Len()], tag, wire, v) + // case WireFixed64: + // v, err := DecodeFixed64(b) + // if err != nil { + // fmt.Printf("decode error on fixed64:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" // field %d, encoding %d, value %d\n", + // data[start:len(data)-b.Len()], tag, wire, v) + // case WireBytes: + // nb, err := DecodeVarint(b) + // if err != nil { + // fmt.Printf("decode error on bytes:", err) + // return + // } + // after_tag := len(data) - b.Len() + // str := make([]byte, nb) + // _, err = b.Read(str) + // if err != nil { + // fmt.Printf("decode error on bytes:", err) + // return + // } + // fmt.Printf("\t\t\"%x\" \"%x\" // field %d, encoding %d (FIELD)\n", + // data[start:after_tag], str, tag, wire) + // case WireStartGroup: + // nesting++ + // fmt.Printf("\t\t\"%x\"\t\t// start group field %d level %d\n", + // data[start:len(data)-b.Len()], tag, nesting) + // case WireEndGroup: + // fmt.Printf("\t\t\"%x\"\t\t// end group field %d level %d\n", + // data[start:len(data)-b.Len()], tag, nesting) + // nesting-- + // default: + // fmt.Printf("unrecognized wire type %d\n", wire) + // return + // } + // } +} + +func hex(c uint8) uint8 { + if '0' <= c && c <= '9' { + return c - '0' + } + if 'a' <= c && c <= 'f' { + return 10 + c - 'a' + } + if 'A' <= c && c <= 'F' { + return 10 + c - 'A' + } + return 0 +} + +func equal(b []byte, s string, t *testing.T) bool { + if 2*len(b) != len(s) { + // fail(fmt.Sprintf("wrong lengths: 2*%d != %d", len(b), len(s)), b, s, t) + fmt.Printf("wrong lengths: 2*%d != %d\n", len(b), len(s)) + return false + } + for i, j := 0, 0; i < len(b); i, j = i+1, j+2 { + x := hex(s[j])*16 + hex(s[j+1]) + if b[i] != x { + // fail(fmt.Sprintf("bad byte[%d]:%x %x", i, b[i], x), b, s, t) + fmt.Printf("bad byte[%d]:%x %x", i, b[i], x) + return false + } + } + return true +} + +func overify(t *testing.T, pb *GoTest, expected string) { + o := old() + err := o.Marshal(pb) + if err != nil { + fmt.Printf("overify marshal-1 err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("expected = %s", expected) + } + if !equal(o.Bytes(), expected, t) { + o.DebugPrint("overify neq 1", o.Bytes()) + t.Fatalf("expected = %s", expected) + } + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + err = o.Unmarshal(pbd) + if err != nil { + t.Fatalf("overify unmarshal err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("string = %s", expected) + } + o.Reset() + err = o.Marshal(pbd) + if err != nil { + t.Errorf("overify marshal-2 err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("string = %s", expected) + } + if !equal(o.Bytes(), expected, t) { + o.DebugPrint("overify neq 2", o.Bytes()) + t.Fatalf("string = %s", expected) + } +} + +// Simple tests for numeric encode/decode primitives (varint, etc.) +func TestNumericPrimitives(t *testing.T) { + for i := uint64(0); i < 1e6; i += 111 { + o := old() + if o.EncodeVarint(i) != nil { + t.Error("EncodeVarint") + break + } + x, e := o.DecodeVarint() + if e != nil { + t.Fatal("DecodeVarint") + } + if x != i { + t.Fatal("varint decode fail:", i, x) + } + + o = old() + if o.EncodeFixed32(i) != nil { + t.Fatal("encFixed32") + } + x, e = o.DecodeFixed32() + if e != nil { + t.Fatal("decFixed32") + } + if x != i { + t.Fatal("fixed32 decode fail:", i, x) + } + + o = old() + if o.EncodeFixed64(i*1234567) != nil { + t.Error("encFixed64") + break + } + x, e = o.DecodeFixed64() + if e != nil { + t.Error("decFixed64") + break + } + if x != i*1234567 { + t.Error("fixed64 decode fail:", i*1234567, x) + break + } + + o = old() + i32 := int32(i - 12345) + if o.EncodeZigzag32(uint64(i32)) != nil { + t.Fatal("EncodeZigzag32") + } + x, e = o.DecodeZigzag32() + if e != nil { + t.Fatal("DecodeZigzag32") + } + if x != uint64(uint32(i32)) { + t.Fatal("zigzag32 decode fail:", i32, x) + } + + o = old() + i64 := int64(i - 12345) + if o.EncodeZigzag64(uint64(i64)) != nil { + t.Fatal("EncodeZigzag64") + } + x, e = o.DecodeZigzag64() + if e != nil { + t.Fatal("DecodeZigzag64") + } + if x != uint64(i64) { + t.Fatal("zigzag64 decode fail:", i64, x) + } + } +} + +// fakeMarshaler is a simple struct implementing Marshaler and Message interfaces. +type fakeMarshaler struct { + b []byte + err error +} + +func (f *fakeMarshaler) Marshal() ([]byte, error) { return f.b, f.err } +func (f *fakeMarshaler) String() string { return fmt.Sprintf("Bytes: %v Error: %v", f.b, f.err) } +func (f *fakeMarshaler) ProtoMessage() {} +func (f *fakeMarshaler) Reset() {} + +type msgWithFakeMarshaler struct { + M *fakeMarshaler `protobuf:"bytes,1,opt,name=fake"` +} + +func (m *msgWithFakeMarshaler) String() string { return CompactTextString(m) } +func (m *msgWithFakeMarshaler) ProtoMessage() {} +func (m *msgWithFakeMarshaler) Reset() {} + +// Simple tests for proto messages that implement the Marshaler interface. +func TestMarshalerEncoding(t *testing.T) { + tests := []struct { + name string + m Message + want []byte + errType reflect.Type + }{ + { + name: "Marshaler that fails", + m: &fakeMarshaler{ + err: errors.New("some marshal err"), + b: []byte{5, 6, 7}, + }, + // Since the Marshal method returned bytes, they should be written to the + // buffer. (For efficiency, we assume that Marshal implementations are + // always correct w.r.t. RequiredNotSetError and output.) + want: []byte{5, 6, 7}, + errType: reflect.TypeOf(errors.New("some marshal err")), + }, + { + name: "Marshaler that fails with RequiredNotSetError", + m: &msgWithFakeMarshaler{ + M: &fakeMarshaler{ + err: &RequiredNotSetError{}, + b: []byte{5, 6, 7}, + }, + }, + // Since there's an error that can be continued after, + // the buffer should be written. + want: []byte{ + 10, 3, // for &msgWithFakeMarshaler + 5, 6, 7, // for &fakeMarshaler + }, + errType: reflect.TypeOf(&RequiredNotSetError{}), + }, + { + name: "Marshaler that succeeds", + m: &fakeMarshaler{ + b: []byte{0, 1, 2, 3, 4, 127, 255}, + }, + want: []byte{0, 1, 2, 3, 4, 127, 255}, + }, + } + for _, test := range tests { + b := NewBuffer(nil) + err := b.Marshal(test.m) + if reflect.TypeOf(err) != test.errType { + t.Errorf("%s: got err %T(%v) wanted %T", test.name, err, err, test.errType) + } + if !reflect.DeepEqual(test.want, b.Bytes()) { + t.Errorf("%s: got bytes %v wanted %v", test.name, b.Bytes(), test.want) + } + if size := Size(test.m); size != len(b.Bytes()) { + t.Errorf("%s: Size(_) = %v, but marshaled to %v bytes", test.name, size, len(b.Bytes())) + } + + m, mErr := Marshal(test.m) + if !bytes.Equal(b.Bytes(), m) { + t.Errorf("%s: Marshal returned %v, but (*Buffer).Marshal wrote %v", test.name, m, b.Bytes()) + } + if !reflect.DeepEqual(err, mErr) { + t.Errorf("%s: Marshal err = %q, but (*Buffer).Marshal returned %q", + test.name, fmt.Sprint(mErr), fmt.Sprint(err)) + } + } +} + +// Simple tests for bytes +func TestBytesPrimitives(t *testing.T) { + o := old() + bytes := []byte{'n', 'o', 'w', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 't', 'i', 'm', 'e'} + if o.EncodeRawBytes(bytes) != nil { + t.Error("EncodeRawBytes") + } + decb, e := o.DecodeRawBytes(false) + if e != nil { + t.Error("DecodeRawBytes") + } + equalbytes(bytes, decb, t) +} + +// Simple tests for strings +func TestStringPrimitives(t *testing.T) { + o := old() + s := "now is the time" + if o.EncodeStringBytes(s) != nil { + t.Error("enc_string") + } + decs, e := o.DecodeStringBytes() + if e != nil { + t.Error("dec_string") + } + if s != decs { + t.Error("string encode/decode fail:", s, decs) + } +} + +// Do we catch the "required bit not set" case? +func TestRequiredBit(t *testing.T) { + o := old() + pb := new(GoTest) + err := o.Marshal(pb) + if err == nil { + t.Error("did not catch missing required fields") + } else if strings.Index(err.Error(), "Kind") < 0 { + t.Error("wrong error type:", err) + } +} + +// Check that all fields are nil. +// Clearly silly, and a residue from a more interesting test with an earlier, +// different initialization property, but it once caught a compiler bug so +// it lives. +func checkInitialized(pb *GoTest, t *testing.T) { + if pb.F_BoolDefaulted != nil { + t.Error("New or Reset did not set boolean:", *pb.F_BoolDefaulted) + } + if pb.F_Int32Defaulted != nil { + t.Error("New or Reset did not set int32:", *pb.F_Int32Defaulted) + } + if pb.F_Int64Defaulted != nil { + t.Error("New or Reset did not set int64:", *pb.F_Int64Defaulted) + } + if pb.F_Fixed32Defaulted != nil { + t.Error("New or Reset did not set fixed32:", *pb.F_Fixed32Defaulted) + } + if pb.F_Fixed64Defaulted != nil { + t.Error("New or Reset did not set fixed64:", *pb.F_Fixed64Defaulted) + } + if pb.F_Uint32Defaulted != nil { + t.Error("New or Reset did not set uint32:", *pb.F_Uint32Defaulted) + } + if pb.F_Uint64Defaulted != nil { + t.Error("New or Reset did not set uint64:", *pb.F_Uint64Defaulted) + } + if pb.F_FloatDefaulted != nil { + t.Error("New or Reset did not set float:", *pb.F_FloatDefaulted) + } + if pb.F_DoubleDefaulted != nil { + t.Error("New or Reset did not set double:", *pb.F_DoubleDefaulted) + } + if pb.F_StringDefaulted != nil { + t.Error("New or Reset did not set string:", *pb.F_StringDefaulted) + } + if pb.F_BytesDefaulted != nil { + t.Error("New or Reset did not set bytes:", string(pb.F_BytesDefaulted)) + } + if pb.F_Sint32Defaulted != nil { + t.Error("New or Reset did not set int32:", *pb.F_Sint32Defaulted) + } + if pb.F_Sint64Defaulted != nil { + t.Error("New or Reset did not set int64:", *pb.F_Sint64Defaulted) + } +} + +// Does Reset() reset? +func TestReset(t *testing.T) { + pb := initGoTest(true) + // muck with some values + pb.F_BoolDefaulted = Bool(false) + pb.F_Int32Defaulted = Int32(237) + pb.F_Int64Defaulted = Int64(12346) + pb.F_Fixed32Defaulted = Uint32(32000) + pb.F_Fixed64Defaulted = Uint64(666) + pb.F_Uint32Defaulted = Uint32(323232) + pb.F_Uint64Defaulted = nil + pb.F_FloatDefaulted = nil + pb.F_DoubleDefaulted = Float64(0) + pb.F_StringDefaulted = String("gotcha") + pb.F_BytesDefaulted = []byte("asdfasdf") + pb.F_Sint32Defaulted = Int32(123) + pb.F_Sint64Defaulted = Int64(789) + pb.Reset() + checkInitialized(pb, t) +} + +// All required fields set, no defaults provided. +func TestEncodeDecode1(t *testing.T) { + pb := initGoTest(false) + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 0x20 + "714000000000000000"+ // field 14, encoding 1, value 0x40 + "78a019"+ // field 15, encoding 0, value 0xca0 = 3232 + "8001c032"+ // field 16, encoding 0, value 0x1940 = 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2, string "string" + "b304"+ // field 70, encoding 3, start group + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // field 70, encoding 4, end group + "aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f") // field 103, encoding 0, 0x7f zigzag64 +} + +// All required fields set, defaults provided. +func TestEncodeDecode2(t *testing.T) { + pb := initGoTest(true) + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All default fields set to their default value by hand +func TestEncodeDecode3(t *testing.T) { + pb := initGoTest(false) + pb.F_BoolDefaulted = Bool(true) + pb.F_Int32Defaulted = Int32(32) + pb.F_Int64Defaulted = Int64(64) + pb.F_Fixed32Defaulted = Uint32(320) + pb.F_Fixed64Defaulted = Uint64(640) + pb.F_Uint32Defaulted = Uint32(3200) + pb.F_Uint64Defaulted = Uint64(6400) + pb.F_FloatDefaulted = Float32(314159) + pb.F_DoubleDefaulted = Float64(271828) + pb.F_StringDefaulted = String("hello, \"world!\"\n") + pb.F_BytesDefaulted = []byte("Bignose") + pb.F_Sint32Defaulted = Int32(-32) + pb.F_Sint64Defaulted = Int64(-64) + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All required fields set, defaults provided, all non-defaulted optional fields have values. +func TestEncodeDecode4(t *testing.T) { + pb := initGoTest(true) + pb.Table = String("hello") + pb.Param = Int32(7) + pb.OptionalField = initGoTestField() + pb.F_BoolOptional = Bool(true) + pb.F_Int32Optional = Int32(32) + pb.F_Int64Optional = Int64(64) + pb.F_Fixed32Optional = Uint32(3232) + pb.F_Fixed64Optional = Uint64(6464) + pb.F_Uint32Optional = Uint32(323232) + pb.F_Uint64Optional = Uint64(646464) + pb.F_FloatOptional = Float32(32.) + pb.F_DoubleOptional = Float64(64.) + pb.F_StringOptional = String("hello") + pb.F_BytesOptional = []byte("Bignose") + pb.F_Sint32Optional = Int32(-32) + pb.F_Sint64Optional = Int64(-64) + pb.Optionalgroup = initGoTest_OptionalGroup() + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "1205"+"68656c6c6f"+ // field 2, encoding 2, string "hello" + "1807"+ // field 3, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "320d"+"0a056c6162656c120474797065"+ // field 6, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "f00101"+ // field 30, encoding 0, value 1 + "f80120"+ // field 31, encoding 0, value 32 + "800240"+ // field 32, encoding 0, value 64 + "8d02a00c0000"+ // field 33, encoding 5, value 3232 + "91024019000000000000"+ // field 34, encoding 1, value 6464 + "9802a0dd13"+ // field 35, encoding 0, value 323232 + "a002c0ba27"+ // field 36, encoding 0, value 646464 + "ad0200000042"+ // field 37, encoding 5, value 32.0 + "b1020000000000005040"+ // field 38, encoding 1, value 64.0 + "ba0205"+"68656c6c6f"+ // field 39, encoding 2, string "hello" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "d305"+ // start group field 90 level 1 + "da0508"+"6f7074696f6e616c"+ // field 91, encoding 2, string "optional" + "d405"+ // end group field 90 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose" + "f0123f"+ // field 302, encoding 0, value 63 + "f8127f"+ // field 303, encoding 0, value 127 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All required fields set, defaults provided, all repeated fields given two values. +func TestEncodeDecode5(t *testing.T) { + pb := initGoTest(true) + pb.RepeatedField = []*GoTestField{initGoTestField(), initGoTestField()} + pb.F_BoolRepeated = []bool{false, true} + pb.F_Int32Repeated = []int32{32, 33} + pb.F_Int64Repeated = []int64{64, 65} + pb.F_Fixed32Repeated = []uint32{3232, 3333} + pb.F_Fixed64Repeated = []uint64{6464, 6565} + pb.F_Uint32Repeated = []uint32{323232, 333333} + pb.F_Uint64Repeated = []uint64{646464, 656565} + pb.F_FloatRepeated = []float32{32., 33.} + pb.F_DoubleRepeated = []float64{64., 65.} + pb.F_StringRepeated = []string{"hello", "sailor"} + pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")} + pb.F_Sint32Repeated = []int32{32, -32} + pb.F_Sint64Repeated = []int64{64, -64} + pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()} + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) + "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "a00100"+ // field 20, encoding 0, value 0 + "a00101"+ // field 20, encoding 0, value 1 + "a80120"+ // field 21, encoding 0, value 32 + "a80121"+ // field 21, encoding 0, value 33 + "b00140"+ // field 22, encoding 0, value 64 + "b00141"+ // field 22, encoding 0, value 65 + "bd01a00c0000"+ // field 23, encoding 5, value 3232 + "bd01050d0000"+ // field 23, encoding 5, value 3333 + "c1014019000000000000"+ // field 24, encoding 1, value 6464 + "c101a519000000000000"+ // field 24, encoding 1, value 6565 + "c801a0dd13"+ // field 25, encoding 0, value 323232 + "c80195ac14"+ // field 25, encoding 0, value 333333 + "d001c0ba27"+ // field 26, encoding 0, value 646464 + "d001b58928"+ // field 26, encoding 0, value 656565 + "dd0100000042"+ // field 27, encoding 5, value 32.0 + "dd0100000442"+ // field 27, encoding 5, value 33.0 + "e1010000000000005040"+ // field 28, encoding 1, value 64.0 + "e1010000000000405040"+ // field 28, encoding 1, value 65.0 + "ea0105"+"68656c6c6f"+ // field 29, encoding 2, string "hello" + "ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "8305"+ // start group field 80 level 1 + "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" + "8405"+ // end group field 80 level 1 + "8305"+ // start group field 80 level 1 + "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" + "8405"+ // end group field 80 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "ca0c03"+"626967"+ // field 201, encoding 2, string "big" + "ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose" + "d00c40"+ // field 202, encoding 0, value 32 + "d00c3f"+ // field 202, encoding 0, value -32 + "d80c8001"+ // field 203, encoding 0, value 64 + "d80c7f"+ // field 203, encoding 0, value -64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f") // field 403, encoding 0, value 127 + +} + +// All required fields set, all packed repeated fields given two values. +func TestEncodeDecode6(t *testing.T) { + pb := initGoTest(false) + pb.F_BoolRepeatedPacked = []bool{false, true} + pb.F_Int32RepeatedPacked = []int32{32, 33} + pb.F_Int64RepeatedPacked = []int64{64, 65} + pb.F_Fixed32RepeatedPacked = []uint32{3232, 3333} + pb.F_Fixed64RepeatedPacked = []uint64{6464, 6565} + pb.F_Uint32RepeatedPacked = []uint32{323232, 333333} + pb.F_Uint64RepeatedPacked = []uint64{646464, 656565} + pb.F_FloatRepeatedPacked = []float32{32., 33.} + pb.F_DoubleRepeatedPacked = []float64{64., 65.} + pb.F_Sint32RepeatedPacked = []int32{32, -32} + pb.F_Sint64RepeatedPacked = []int64{64, -64} + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "9203020001"+ // field 50, encoding 2, 2 bytes, value 0, value 1 + "9a03022021"+ // field 51, encoding 2, 2 bytes, value 32, value 33 + "a203024041"+ // field 52, encoding 2, 2 bytes, value 64, value 65 + "aa0308"+ // field 53, encoding 2, 8 bytes + "a00c0000050d0000"+ // value 3232, value 3333 + "b20310"+ // field 54, encoding 2, 16 bytes + "4019000000000000a519000000000000"+ // value 6464, value 6565 + "ba0306"+ // field 55, encoding 2, 6 bytes + "a0dd1395ac14"+ // value 323232, value 333333 + "c20306"+ // field 56, encoding 2, 6 bytes + "c0ba27b58928"+ // value 646464, value 656565 + "ca0308"+ // field 57, encoding 2, 8 bytes + "0000004200000442"+ // value 32.0, value 33.0 + "d20310"+ // field 58, encoding 2, 16 bytes + "00000000000050400000000000405040"+ // value 64.0, value 65.0 + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "b21f02"+ // field 502, encoding 2, 2 bytes + "403f"+ // value 32, value -32 + "ba1f03"+ // field 503, encoding 2, 3 bytes + "80017f") // value 64, value -64 +} + +// Test that we can encode empty bytes fields. +func TestEncodeDecodeBytes1(t *testing.T) { + pb := initGoTest(false) + + // Create our bytes + pb.F_BytesRequired = []byte{} + pb.F_BytesRepeated = [][]byte{{}} + pb.F_BytesOptional = []byte{} + + d, err := Marshal(pb) + if err != nil { + t.Error(err) + } + + pbd := new(GoTest) + if err := Unmarshal(d, pbd); err != nil { + t.Error(err) + } + + if pbd.F_BytesRequired == nil || len(pbd.F_BytesRequired) != 0 { + t.Error("required empty bytes field is incorrect") + } + if pbd.F_BytesRepeated == nil || len(pbd.F_BytesRepeated) == 1 && pbd.F_BytesRepeated[0] == nil { + t.Error("repeated empty bytes field is incorrect") + } + if pbd.F_BytesOptional == nil || len(pbd.F_BytesOptional) != 0 { + t.Error("optional empty bytes field is incorrect") + } +} + +// Test that we encode nil-valued fields of a repeated bytes field correctly. +// Since entries in a repeated field cannot be nil, nil must mean empty value. +func TestEncodeDecodeBytes2(t *testing.T) { + pb := initGoTest(false) + + // Create our bytes + pb.F_BytesRepeated = [][]byte{nil} + + d, err := Marshal(pb) + if err != nil { + t.Error(err) + } + + pbd := new(GoTest) + if err := Unmarshal(d, pbd); err != nil { + t.Error(err) + } + + if len(pbd.F_BytesRepeated) != 1 || pbd.F_BytesRepeated[0] == nil { + t.Error("Unexpected value for repeated bytes field") + } +} + +// All required fields set, defaults provided, all repeated fields given two values. +func TestSkippingUnrecognizedFields(t *testing.T) { + o := old() + pb := initGoTestField() + + // Marshal it normally. + o.Marshal(pb) + + // Now new a GoSkipTest record. + skip := &GoSkipTest{ + SkipInt32: Int32(32), + SkipFixed32: Uint32(3232), + SkipFixed64: Uint64(6464), + SkipString: String("skipper"), + Skipgroup: &GoSkipTest_SkipGroup{ + GroupInt32: Int32(75), + GroupString: String("wxyz"), + }, + } + + // Marshal it into same buffer. + o.Marshal(skip) + + pbd := new(GoTestField) + o.Unmarshal(pbd) + + // The __unrecognized field should be a marshaling of GoSkipTest + skipd := new(GoSkipTest) + + o.SetBuf(pbd.XXX_unrecognized) + o.Unmarshal(skipd) + + if *skipd.SkipInt32 != *skip.SkipInt32 { + t.Error("skip int32", skipd.SkipInt32) + } + if *skipd.SkipFixed32 != *skip.SkipFixed32 { + t.Error("skip fixed32", skipd.SkipFixed32) + } + if *skipd.SkipFixed64 != *skip.SkipFixed64 { + t.Error("skip fixed64", skipd.SkipFixed64) + } + if *skipd.SkipString != *skip.SkipString { + t.Error("skip string", *skipd.SkipString) + } + if *skipd.Skipgroup.GroupInt32 != *skip.Skipgroup.GroupInt32 { + t.Error("skip group int32", skipd.Skipgroup.GroupInt32) + } + if *skipd.Skipgroup.GroupString != *skip.Skipgroup.GroupString { + t.Error("skip group string", *skipd.Skipgroup.GroupString) + } +} + +// Check that unrecognized fields of a submessage are preserved. +func TestSubmessageUnrecognizedFields(t *testing.T) { + nm := &NewMessage{ + Nested: &NewMessage_Nested{ + Name: String("Nigel"), + FoodGroup: String("carbs"), + }, + } + b, err := Marshal(nm) + if err != nil { + t.Fatalf("Marshal of NewMessage: %v", err) + } + + // Unmarshal into an OldMessage. + om := new(OldMessage) + if err = Unmarshal(b, om); err != nil { + t.Fatalf("Unmarshal to OldMessage: %v", err) + } + exp := &OldMessage{ + Nested: &OldMessage_Nested{ + Name: String("Nigel"), + // normal protocol buffer users should not do this + XXX_unrecognized: []byte("\x12\x05carbs"), + }, + } + if !Equal(om, exp) { + t.Errorf("om = %v, want %v", om, exp) + } + + // Clone the OldMessage. + om = Clone(om).(*OldMessage) + if !Equal(om, exp) { + t.Errorf("Clone(om) = %v, want %v", om, exp) + } + + // Marshal the OldMessage, then unmarshal it into an empty NewMessage. + if b, err = Marshal(om); err != nil { + t.Fatalf("Marshal of OldMessage: %v", err) + } + t.Logf("Marshal(%v) -> %q", om, b) + nm2 := new(NewMessage) + if err := Unmarshal(b, nm2); err != nil { + t.Fatalf("Unmarshal to NewMessage: %v", err) + } + if !Equal(nm, nm2) { + t.Errorf("NewMessage round-trip: %v => %v", nm, nm2) + } +} + +// Check that an int32 field can be upgraded to an int64 field. +func TestNegativeInt32(t *testing.T) { + om := &OldMessage{ + Num: Int32(-1), + } + b, err := Marshal(om) + if err != nil { + t.Fatalf("Marshal of OldMessage: %v", err) + } + + // Check the size. It should be 11 bytes; + // 1 for the field/wire type, and 10 for the negative number. + if len(b) != 11 { + t.Errorf("%v marshaled as %q, wanted 11 bytes", om, b) + } + + // Unmarshal into a NewMessage. + nm := new(NewMessage) + if err := Unmarshal(b, nm); err != nil { + t.Fatalf("Unmarshal to NewMessage: %v", err) + } + want := &NewMessage{ + Num: Int64(-1), + } + if !Equal(nm, want) { + t.Errorf("nm = %v, want %v", nm, want) + } +} + +// Check that we can grow an array (repeated field) to have many elements. +// This test doesn't depend only on our encoding; for variety, it makes sure +// we create, encode, and decode the correct contents explicitly. It's therefore +// a bit messier. +// This test also uses (and hence tests) the Marshal/Unmarshal functions +// instead of the methods. +func TestBigRepeated(t *testing.T) { + pb := initGoTest(true) + + // Create the arrays + const N = 50 // Internally the library starts much smaller. + pb.Repeatedgroup = make([]*GoTest_RepeatedGroup, N) + pb.F_Sint64Repeated = make([]int64, N) + pb.F_Sint32Repeated = make([]int32, N) + pb.F_BytesRepeated = make([][]byte, N) + pb.F_StringRepeated = make([]string, N) + pb.F_DoubleRepeated = make([]float64, N) + pb.F_FloatRepeated = make([]float32, N) + pb.F_Uint64Repeated = make([]uint64, N) + pb.F_Uint32Repeated = make([]uint32, N) + pb.F_Fixed64Repeated = make([]uint64, N) + pb.F_Fixed32Repeated = make([]uint32, N) + pb.F_Int64Repeated = make([]int64, N) + pb.F_Int32Repeated = make([]int32, N) + pb.F_BoolRepeated = make([]bool, N) + pb.RepeatedField = make([]*GoTestField, N) + + // Fill in the arrays with checkable values. + igtf := initGoTestField() + igtrg := initGoTest_RepeatedGroup() + for i := 0; i < N; i++ { + pb.Repeatedgroup[i] = igtrg + pb.F_Sint64Repeated[i] = int64(i) + pb.F_Sint32Repeated[i] = int32(i) + s := fmt.Sprint(i) + pb.F_BytesRepeated[i] = []byte(s) + pb.F_StringRepeated[i] = s + pb.F_DoubleRepeated[i] = float64(i) + pb.F_FloatRepeated[i] = float32(i) + pb.F_Uint64Repeated[i] = uint64(i) + pb.F_Uint32Repeated[i] = uint32(i) + pb.F_Fixed64Repeated[i] = uint64(i) + pb.F_Fixed32Repeated[i] = uint32(i) + pb.F_Int64Repeated[i] = int64(i) + pb.F_Int32Repeated[i] = int32(i) + pb.F_BoolRepeated[i] = i%2 == 0 + pb.RepeatedField[i] = igtf + } + + // Marshal. + buf, _ := Marshal(pb) + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + Unmarshal(buf, pbd) + + // Check the checkable values + for i := uint64(0); i < N; i++ { + if pbd.Repeatedgroup[i] == nil { // TODO: more checking? + t.Error("pbd.Repeatedgroup bad") + } + var x uint64 + x = uint64(pbd.F_Sint64Repeated[i]) + if x != i { + t.Error("pbd.F_Sint64Repeated bad", x, i) + } + x = uint64(pbd.F_Sint32Repeated[i]) + if x != i { + t.Error("pbd.F_Sint32Repeated bad", x, i) + } + s := fmt.Sprint(i) + equalbytes(pbd.F_BytesRepeated[i], []byte(s), t) + if pbd.F_StringRepeated[i] != s { + t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i) + } + x = uint64(pbd.F_DoubleRepeated[i]) + if x != i { + t.Error("pbd.F_DoubleRepeated bad", x, i) + } + x = uint64(pbd.F_FloatRepeated[i]) + if x != i { + t.Error("pbd.F_FloatRepeated bad", x, i) + } + x = pbd.F_Uint64Repeated[i] + if x != i { + t.Error("pbd.F_Uint64Repeated bad", x, i) + } + x = uint64(pbd.F_Uint32Repeated[i]) + if x != i { + t.Error("pbd.F_Uint32Repeated bad", x, i) + } + x = pbd.F_Fixed64Repeated[i] + if x != i { + t.Error("pbd.F_Fixed64Repeated bad", x, i) + } + x = uint64(pbd.F_Fixed32Repeated[i]) + if x != i { + t.Error("pbd.F_Fixed32Repeated bad", x, i) + } + x = uint64(pbd.F_Int64Repeated[i]) + if x != i { + t.Error("pbd.F_Int64Repeated bad", x, i) + } + x = uint64(pbd.F_Int32Repeated[i]) + if x != i { + t.Error("pbd.F_Int32Repeated bad", x, i) + } + if pbd.F_BoolRepeated[i] != (i%2 == 0) { + t.Error("pbd.F_BoolRepeated bad", x, i) + } + if pbd.RepeatedField[i] == nil { // TODO: more checking? + t.Error("pbd.RepeatedField bad") + } + } +} + +// Verify we give a useful message when decoding to the wrong structure type. +func TestTypeMismatch(t *testing.T) { + pb1 := initGoTest(true) + + // Marshal + o := old() + o.Marshal(pb1) + + // Now Unmarshal it to the wrong type. + pb2 := initGoTestField() + err := o.Unmarshal(pb2) + if err == nil { + t.Error("expected error, got no error") + } else if !strings.Contains(err.Error(), "bad wiretype") { + t.Error("expected bad wiretype error, got", err) + } +} + +func encodeDecode(t *testing.T, in, out Message, msg string) { + buf, err := Marshal(in) + if err != nil { + t.Fatalf("failed marshaling %v: %v", msg, err) + } + if err := Unmarshal(buf, out); err != nil { + t.Fatalf("failed unmarshaling %v: %v", msg, err) + } +} + +func TestPackedNonPackedDecoderSwitching(t *testing.T) { + np, p := new(NonPackedTest), new(PackedTest) + + // non-packed -> packed + np.A = []int32{0, 1, 1, 2, 3, 5} + encodeDecode(t, np, p, "non-packed -> packed") + if !reflect.DeepEqual(np.A, p.B) { + t.Errorf("failed non-packed -> packed; np.A=%+v, p.B=%+v", np.A, p.B) + } + + // packed -> non-packed + np.Reset() + p.B = []int32{3, 1, 4, 1, 5, 9} + encodeDecode(t, p, np, "packed -> non-packed") + if !reflect.DeepEqual(p.B, np.A) { + t.Errorf("failed packed -> non-packed; p.B=%+v, np.A=%+v", p.B, np.A) + } +} + +func TestProto1RepeatedGroup(t *testing.T) { + pb := &MessageList{ + Message: []*MessageList_Message{ + { + Name: String("blah"), + Count: Int32(7), + }, + // NOTE: pb.Message[1] is a nil + nil, + }, + } + + o := old() + err := o.Marshal(pb) + if err == nil || !strings.Contains(err.Error(), "repeated field Message has nil") { + t.Fatalf("unexpected or no error when marshaling: %v", err) + } +} + +// Test that enums work. Checks for a bug introduced by making enums +// named types instead of int32: newInt32FromUint64 would crash with +// a type mismatch in reflect.PointTo. +func TestEnum(t *testing.T) { + pb := new(GoEnum) + pb.Foo = FOO_FOO1.Enum() + o := old() + if err := o.Marshal(pb); err != nil { + t.Fatal("error encoding enum:", err) + } + pb1 := new(GoEnum) + if err := o.Unmarshal(pb1); err != nil { + t.Fatal("error decoding enum:", err) + } + if *pb1.Foo != FOO_FOO1 { + t.Error("expected 7 but got ", *pb1.Foo) + } +} + +// Enum types have String methods. Check that enum fields can be printed. +// We don't care what the value actually is, just as long as it doesn't crash. +func TestPrintingNilEnumFields(t *testing.T) { + pb := new(GoEnum) + _ = fmt.Sprintf("%+v", pb) +} + +// Verify that absent required fields cause Marshal/Unmarshal to return errors. +func TestRequiredFieldEnforcement(t *testing.T) { + pb := new(GoTestField) + _, err := Marshal(pb) + if err == nil { + t.Error("marshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Label") { + t.Errorf("marshal: bad error type: %v", err) + } + + // A slightly sneaky, yet valid, proto. It encodes the same required field twice, + // so simply counting the required fields is insufficient. + // field 1, encoding 2, value "hi" + buf := []byte("\x0A\x02hi\x0A\x02hi") + err = Unmarshal(buf, pb) + if err == nil { + t.Error("unmarshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "{Unknown}") { + t.Errorf("unmarshal: bad error type: %v", err) + } +} + +// Verify that absent required fields in groups cause Marshal/Unmarshal to return errors. +func TestRequiredFieldEnforcementGroups(t *testing.T) { + pb := &GoTestRequiredGroupField{Group: &GoTestRequiredGroupField_Group{}} + if _, err := Marshal(pb); err == nil { + t.Error("marshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.Field") { + t.Errorf("marshal: bad error type: %v", err) + } + + buf := []byte{11, 12} + if err := Unmarshal(buf, pb); err == nil { + t.Error("unmarshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.{Unknown}") { + t.Errorf("unmarshal: bad error type: %v", err) + } +} + +func TestTypedNilMarshal(t *testing.T) { + // A typed nil should return ErrNil and not crash. + { + var m *GoEnum + if _, err := Marshal(m); err != ErrNil { + t.Errorf("Marshal(%#v): got %v, want ErrNil", m, err) + } + } + + { + m := &Communique{Union: &Communique_Msg{Msg: nil}} + if _, err := Marshal(m); err == nil || err == ErrNil { + t.Errorf("Marshal(%#v): got %v, want errOneofHasNil", m, err) + } + } +} + +// A type that implements the Marshaler interface, but is not nillable. +type nonNillableInt uint64 + +func (nni nonNillableInt) Marshal() ([]byte, error) { + return EncodeVarint(uint64(nni)), nil +} + +type NNIMessage struct { + nni nonNillableInt +} + +func (*NNIMessage) Reset() {} +func (*NNIMessage) String() string { return "" } +func (*NNIMessage) ProtoMessage() {} + +// A type that implements the Marshaler interface and is nillable. +type nillableMessage struct { + x uint64 +} + +func (nm *nillableMessage) Marshal() ([]byte, error) { + return EncodeVarint(nm.x), nil +} + +type NMMessage struct { + nm *nillableMessage +} + +func (*NMMessage) Reset() {} +func (*NMMessage) String() string { return "" } +func (*NMMessage) ProtoMessage() {} + +// Verify a type that uses the Marshaler interface, but has a nil pointer. +func TestNilMarshaler(t *testing.T) { + // Try a struct with a Marshaler field that is nil. + // It should be directly marshable. + nmm := new(NMMessage) + if _, err := Marshal(nmm); err != nil { + t.Error("unexpected error marshaling nmm: ", err) + } + + // Try a struct with a Marshaler field that is not nillable. + nnim := new(NNIMessage) + nnim.nni = 7 + var _ Marshaler = nnim.nni // verify it is truly a Marshaler + if _, err := Marshal(nnim); err != nil { + t.Error("unexpected error marshaling nnim: ", err) + } +} + +func TestAllSetDefaults(t *testing.T) { + // Exercise SetDefaults with all scalar field types. + m := &Defaults{ + // NaN != NaN, so override that here. + F_Nan: Float32(1.7), + } + expected := &Defaults{ + F_Bool: Bool(true), + F_Int32: Int32(32), + F_Int64: Int64(64), + F_Fixed32: Uint32(320), + F_Fixed64: Uint64(640), + F_Uint32: Uint32(3200), + F_Uint64: Uint64(6400), + F_Float: Float32(314159), + F_Double: Float64(271828), + F_String: String(`hello, "world!"` + "\n"), + F_Bytes: []byte("Bignose"), + F_Sint32: Int32(-32), + F_Sint64: Int64(-64), + F_Enum: Defaults_GREEN.Enum(), + F_Pinf: Float32(float32(math.Inf(1))), + F_Ninf: Float32(float32(math.Inf(-1))), + F_Nan: Float32(1.7), + StrZero: String(""), + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("SetDefaults failed\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultsWithSetField(t *testing.T) { + // Check that a set value is not overridden. + m := &Defaults{ + F_Int32: Int32(12), + } + SetDefaults(m) + if v := m.GetF_Int32(); v != 12 { + t.Errorf("m.FInt32 = %v, want 12", v) + } +} + +func TestSetDefaultsWithSubMessage(t *testing.T) { + m := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("gopher"), + }, + } + expected := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("gopher"), + Port: Int32(4000), + }, + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultsWithRepeatedSubMessage(t *testing.T) { + m := &MyMessage{ + RepInner: []*InnerMessage{{}}, + } + expected := &MyMessage{ + RepInner: []*InnerMessage{{ + Port: Int32(4000), + }}, + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultWithRepeatedNonMessage(t *testing.T) { + m := &MyMessage{ + Pet: []string{"turtle", "wombat"}, + } + expected := Clone(m) + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestMaximumTagNumber(t *testing.T) { + m := &MaxTag{ + LastField: String("natural goat essence"), + } + buf, err := Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal failed: %v", err) + } + m2 := new(MaxTag) + if err := Unmarshal(buf, m2); err != nil { + t.Fatalf("proto.Unmarshal failed: %v", err) + } + if got, want := m2.GetLastField(), *m.LastField; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func TestJSON(t *testing.T) { + m := &MyMessage{ + Count: Int32(4), + Pet: []string{"bunny", "kitty"}, + Inner: &InnerMessage{ + Host: String("cauchy"), + }, + Bikeshed: MyMessage_GREEN.Enum(), + } + const expected = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":1}` + + b, err := json.Marshal(m) + if err != nil { + t.Fatalf("json.Marshal failed: %v", err) + } + s := string(b) + if s != expected { + t.Errorf("got %s\nwant %s", s, expected) + } + + received := new(MyMessage) + if err := json.Unmarshal(b, received); err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + if !Equal(received, m) { + t.Fatalf("got %s, want %s", received, m) + } + + // Test unmarshalling of JSON with symbolic enum name. + const old = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":"GREEN"}` + received.Reset() + if err := json.Unmarshal([]byte(old), received); err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + if !Equal(received, m) { + t.Fatalf("got %s, want %s", received, m) + } +} + +func TestBadWireType(t *testing.T) { + b := []byte{7<<3 | 6} // field 7, wire type 6 + pb := new(OtherMessage) + if err := Unmarshal(b, pb); err == nil { + t.Errorf("Unmarshal did not fail") + } else if !strings.Contains(err.Error(), "unknown wire type") { + t.Errorf("wrong error: %v", err) + } +} + +func TestBytesWithInvalidLength(t *testing.T) { + // If a byte sequence has an invalid (negative) length, Unmarshal should not panic. + b := []byte{2<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0} + Unmarshal(b, new(MyMessage)) +} + +func TestLengthOverflow(t *testing.T) { + // Overflowing a length should not panic. + b := []byte{2<<3 | WireBytes, 1, 1, 3<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01} + Unmarshal(b, new(MyMessage)) +} + +func TestVarintOverflow(t *testing.T) { + // Overflowing a 64-bit length should not be allowed. + b := []byte{1<<3 | WireVarint, 0x01, 3<<3 | WireBytes, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01} + if err := Unmarshal(b, new(MyMessage)); err == nil { + t.Fatalf("Overflowed uint64 length without error") + } +} + +func TestUnmarshalFuzz(t *testing.T) { + const N = 1000 + seed := time.Now().UnixNano() + t.Logf("RNG seed is %d", seed) + rng := rand.New(rand.NewSource(seed)) + buf := make([]byte, 20) + for i := 0; i < N; i++ { + for j := range buf { + buf[j] = byte(rng.Intn(256)) + } + fuzzUnmarshal(t, buf) + } +} + +func TestMergeMessages(t *testing.T) { + pb := &MessageList{Message: []*MessageList_Message{{Name: String("x"), Count: Int32(1)}}} + data, err := Marshal(pb) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + pb1 := new(MessageList) + if err := Unmarshal(data, pb1); err != nil { + t.Fatalf("first Unmarshal: %v", err) + } + if err := Unmarshal(data, pb1); err != nil { + t.Fatalf("second Unmarshal: %v", err) + } + if len(pb1.Message) != 1 { + t.Errorf("two Unmarshals produced %d Messages, want 1", len(pb1.Message)) + } + + pb2 := new(MessageList) + if err := UnmarshalMerge(data, pb2); err != nil { + t.Fatalf("first UnmarshalMerge: %v", err) + } + if err := UnmarshalMerge(data, pb2); err != nil { + t.Fatalf("second UnmarshalMerge: %v", err) + } + if len(pb2.Message) != 2 { + t.Errorf("two UnmarshalMerges produced %d Messages, want 2", len(pb2.Message)) + } +} + +func TestExtensionMarshalOrder(t *testing.T) { + m := &MyMessage{Count: Int(123)} + if err := SetExtension(m, E_Ext_More, &Ext{Data: String("alpha")}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + if err := SetExtension(m, E_Ext_Text, String("aleph")); err != nil { + t.Fatalf("SetExtension: %v", err) + } + if err := SetExtension(m, E_Ext_Number, Int32(1)); err != nil { + t.Fatalf("SetExtension: %v", err) + } + + // Serialize m several times, and check we get the same bytes each time. + var orig []byte + for i := 0; i < 100; i++ { + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if i == 0 { + orig = b + continue + } + if !bytes.Equal(b, orig) { + t.Errorf("Bytes differ on attempt #%d", i) + } + } +} + +// Many extensions, because small maps might not iterate differently on each iteration. +var exts = []*ExtensionDesc{ + E_X201, + E_X202, + E_X203, + E_X204, + E_X205, + E_X206, + E_X207, + E_X208, + E_X209, + E_X210, + E_X211, + E_X212, + E_X213, + E_X214, + E_X215, + E_X216, + E_X217, + E_X218, + E_X219, + E_X220, + E_X221, + E_X222, + E_X223, + E_X224, + E_X225, + E_X226, + E_X227, + E_X228, + E_X229, + E_X230, + E_X231, + E_X232, + E_X233, + E_X234, + E_X235, + E_X236, + E_X237, + E_X238, + E_X239, + E_X240, + E_X241, + E_X242, + E_X243, + E_X244, + E_X245, + E_X246, + E_X247, + E_X248, + E_X249, + E_X250, +} + +func TestMessageSetMarshalOrder(t *testing.T) { + m := &MyMessageSet{} + for _, x := range exts { + if err := SetExtension(m, x, &Empty{}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + } + + buf, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + // Serialize m several times, and check we get the same bytes each time. + for i := 0; i < 10; i++ { + b1, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if !bytes.Equal(b1, buf) { + t.Errorf("Bytes differ on re-Marshal #%d", i) + } + + m2 := &MyMessageSet{} + if err = Unmarshal(buf, m2); err != nil { + t.Errorf("Unmarshal: %v", err) + } + b2, err := Marshal(m2) + if err != nil { + t.Errorf("re-Marshal: %v", err) + } + if !bytes.Equal(b2, buf) { + t.Errorf("Bytes differ on round-trip #%d", i) + } + } +} + +func TestUnmarshalMergesMessages(t *testing.T) { + // If a nested message occurs twice in the input, + // the fields should be merged when decoding. + a := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("polhode"), + Port: Int32(1234), + }, + } + aData, err := Marshal(a) + if err != nil { + t.Fatalf("Marshal(a): %v", err) + } + b := &OtherMessage{ + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Connected: Bool(true), + }, + } + bData, err := Marshal(b) + if err != nil { + t.Fatalf("Marshal(b): %v", err) + } + want := &OtherMessage{ + Key: Int64(123), + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Port: Int32(1234), + Connected: Bool(true), + }, + } + got := new(OtherMessage) + if err := Unmarshal(append(aData, bData...), got); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + +func TestEncodingSizes(t *testing.T) { + tests := []struct { + m Message + n int + }{ + {&Defaults{F_Int32: Int32(math.MaxInt32)}, 6}, + {&Defaults{F_Int32: Int32(math.MinInt32)}, 11}, + {&Defaults{F_Uint32: Uint32(uint32(math.MaxInt32) + 1)}, 6}, + {&Defaults{F_Uint32: Uint32(math.MaxUint32)}, 6}, + } + for _, test := range tests { + b, err := Marshal(test.m) + if err != nil { + t.Errorf("Marshal(%v): %v", test.m, err) + continue + } + if len(b) != test.n { + t.Errorf("Marshal(%v) yielded %d bytes, want %d bytes", test.m, len(b), test.n) + } + } +} + +func TestRequiredNotSetError(t *testing.T) { + pb := initGoTest(false) + pb.RequiredField.Label = nil + pb.F_Int32Required = nil + pb.F_Int64Required = nil + + expected := "0807" + // field 1, encoding 0, value 7 + "2206" + "120474797065" + // field 4, encoding 2 (GoTestField) + "5001" + // field 10, encoding 0, value 1 + "6d20000000" + // field 13, encoding 5, value 0x20 + "714000000000000000" + // field 14, encoding 1, value 0x40 + "78a019" + // field 15, encoding 0, value 0xca0 = 3232 + "8001c032" + // field 16, encoding 0, value 0x1940 = 6464 + "8d0100004a45" + // field 17, encoding 5, value 3232.0 + "9101000000000040b940" + // field 18, encoding 1, value 6464.0 + "9a0106" + "737472696e67" + // field 19, encoding 2, string "string" + "b304" + // field 70, encoding 3, start group + "ba0408" + "7265717569726564" + // field 71, encoding 2, string "required" + "b404" + // field 70, encoding 4, end group + "aa0605" + "6279746573" + // field 101, encoding 2, string "bytes" + "b0063f" + // field 102, encoding 0, 0x3f zigzag32 + "b8067f" // field 103, encoding 0, 0x7f zigzag64 + + o := old() + mbytes, err := Marshal(pb) + if _, ok := err.(*RequiredNotSetError); !ok { + fmt.Printf("marshal-1 err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", mbytes) + t.Fatalf("expected = %s", expected) + } + if strings.Index(err.Error(), "RequiredField.Label") < 0 { + t.Errorf("marshal-1 wrong err msg: %v", err) + } + if !equal(mbytes, expected, t) { + o.DebugPrint("neq 1", mbytes) + t.Fatalf("expected = %s", expected) + } + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + err = Unmarshal(mbytes, pbd) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Fatalf("unmarshal err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", mbytes) + t.Fatalf("string = %s", expected) + } + if strings.Index(err.Error(), "RequiredField.{Unknown}") < 0 { + t.Errorf("unmarshal wrong err msg: %v", err) + } + mbytes, err = Marshal(pbd) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Errorf("marshal-2 err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", mbytes) + t.Fatalf("string = %s", expected) + } + if strings.Index(err.Error(), "RequiredField.Label") < 0 { + t.Errorf("marshal-2 wrong err msg: %v", err) + } + if !equal(mbytes, expected, t) { + o.DebugPrint("neq 2", mbytes) + t.Fatalf("string = %s", expected) + } +} + +func fuzzUnmarshal(t *testing.T, data []byte) { + defer func() { + if e := recover(); e != nil { + t.Errorf("These bytes caused a panic: %+v", data) + t.Logf("Stack:\n%s", debug.Stack()) + t.FailNow() + } + }() + + pb := new(MyMessage) + Unmarshal(data, pb) +} + +func TestMapFieldMarshal(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + } + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + // b should be the concatenation of these three byte sequences in some order. + parts := []string{ + "\n\a\b\x01\x12\x03Rob", + "\n\a\b\x04\x12\x03Ian", + "\n\b\b\x08\x12\x04Dave", + } + ok := false + for i := range parts { + for j := range parts { + if j == i { + continue + } + for k := range parts { + if k == i || k == j { + continue + } + try := parts[i] + parts[j] + parts[k] + if bytes.Equal(b, []byte(try)) { + ok = true + break + } + } + } + } + if !ok { + t.Fatalf("Incorrect Marshal output.\n got %q\nwant %q (or a permutation of that)", b, parts[0]+parts[1]+parts[2]) + } + t.Logf("FYI b: %q", b) + + (new(Buffer)).DebugPrint("Dump of b", b) +} + +func TestMapFieldRoundTrips(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + MsgMapping: map[int64]*FloatingPoint{ + 0x7001: {F: Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{ + false: []byte("that's not right!"), + true: []byte("aye, 'tis true!"), + }, + } + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + t.Logf("FYI b: %q", b) + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + for _, pair := range [][2]interface{}{ + {m.NameMapping, m2.NameMapping}, + {m.MsgMapping, m2.MsgMapping}, + {m.ByteMapping, m2.ByteMapping}, + } { + if !reflect.DeepEqual(pair[0], pair[1]) { + t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", pair[0], pair[1]) + } + } +} + +func TestMapFieldWithNil(t *testing.T) { + m1 := &MessageWithMap{ + MsgMapping: map[int64]*FloatingPoint{ + 1: nil, + }, + } + b, err := Marshal(m1) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) + } + if v, ok := m2.MsgMapping[1]; !ok { + t.Error("msg_mapping[1] not present") + } else if v != nil { + t.Errorf("msg_mapping[1] not nil: %v", v) + } +} + +func TestMapFieldWithNilBytes(t *testing.T) { + m1 := &MessageWithMap{ + ByteMapping: map[bool][]byte{ + false: {}, + true: nil, + }, + } + n := Size(m1) + b, err := Marshal(m1) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if n != len(b) { + t.Errorf("Size(m1) = %d; want len(Marshal(m1)) = %d", n, len(b)) + } + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) + } + if v, ok := m2.ByteMapping[false]; !ok { + t.Error("byte_mapping[false] not present") + } else if len(v) != 0 { + t.Errorf("byte_mapping[false] not empty: %#v", v) + } + if v, ok := m2.ByteMapping[true]; !ok { + t.Error("byte_mapping[true] not present") + } else if len(v) != 0 { + t.Errorf("byte_mapping[true] not empty: %#v", v) + } +} + +func TestDecodeMapFieldMissingKey(t *testing.T) { + b := []byte{ + 0x0A, 0x03, // message, tag 1 (name_mapping), of length 3 bytes + // no key + 0x12, 0x01, 0x6D, // string value of length 1 byte, value "m" + } + got := &MessageWithMap{} + err := Unmarshal(b, got) + if err != nil { + t.Fatalf("failed to marshal map with missing key: %v", err) + } + want := &MessageWithMap{NameMapping: map[int32]string{0: "m"}} + if !Equal(got, want) { + t.Errorf("Unmarshaled map with no key was not as expected. got: %v, want %v", got, want) + } +} + +func TestDecodeMapFieldMissingValue(t *testing.T) { + b := []byte{ + 0x0A, 0x02, // message, tag 1 (name_mapping), of length 2 bytes + 0x08, 0x01, // varint key, value 1 + // no value + } + got := &MessageWithMap{} + err := Unmarshal(b, got) + if err != nil { + t.Fatalf("failed to marshal map with missing value: %v", err) + } + want := &MessageWithMap{NameMapping: map[int32]string{1: ""}} + if !Equal(got, want) { + t.Errorf("Unmarshaled map with no value was not as expected. got: %v, want %v", got, want) + } +} + +func TestOneof(t *testing.T) { + m := &Communique{} + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal of empty message with oneof: %v", err) + } + if len(b) != 0 { + t.Errorf("Marshal of empty message yielded too many bytes: %v", b) + } + + m = &Communique{ + Union: &Communique_Name{Name: "Barry"}, + } + + // Round-trip. + b, err = Marshal(m) + if err != nil { + t.Fatalf("Marshal of message with oneof: %v", err) + } + if len(b) != 7 { // name tag/wire (1) + name len (1) + name (5) + t.Errorf("Incorrect marshal of message with oneof: %v", b) + } + m.Reset() + if err = Unmarshal(b, m); err != nil { + t.Fatalf("Unmarshal of message with oneof: %v", err) + } + if x, ok := m.Union.(*Communique_Name); !ok || x.Name != "Barry" { + t.Errorf("After round trip, Union = %+v", m.Union) + } + if name := m.GetName(); name != "Barry" { + t.Errorf("After round trip, GetName = %q, want %q", name, "Barry") + } + + // Let's try with a message in the oneof. + m.Union = &Communique_Msg{Msg: &Strings{StringField: String("deep deep string")}} + b, err = Marshal(m) + if err != nil { + t.Fatalf("Marshal of message with oneof set to message: %v", err) + } + if len(b) != 20 { // msg tag/wire (1) + msg len (1) + msg (1 + 1 + 16) + t.Errorf("Incorrect marshal of message with oneof set to message: %v", b) + } + m.Reset() + if err := Unmarshal(b, m); err != nil { + t.Fatalf("Unmarshal of message with oneof set to message: %v", err) + } + ss, ok := m.Union.(*Communique_Msg) + if !ok || ss.Msg.GetStringField() != "deep deep string" { + t.Errorf("After round trip with oneof set to message, Union = %+v", m.Union) + } +} + +func TestInefficientPackedBool(t *testing.T) { + // https://github.com/golang/protobuf/issues/76 + inp := []byte{ + 0x12, 0x02, // 0x12 = 2<<3|2; 2 bytes + // Usually a bool should take a single byte, + // but it is permitted to be any varint. + 0xb9, 0x30, + } + if err := Unmarshal(inp, new(MoreRepeated)); err != nil { + t.Error(err) + } +} + +// Benchmarks + +func testMsg() *GoTest { + pb := initGoTest(true) + const N = 1000 // Internally the library starts much smaller. + pb.F_Int32Repeated = make([]int32, N) + pb.F_DoubleRepeated = make([]float64, N) + for i := 0; i < N; i++ { + pb.F_Int32Repeated[i] = int32(i) + pb.F_DoubleRepeated[i] = float64(i) + } + return pb +} + +func bytesMsg() *GoTest { + pb := initGoTest(true) + buf := make([]byte, 4000) + for i := range buf { + buf[i] = byte(i) + } + pb.F_BytesDefaulted = buf + return pb +} + +func benchmarkMarshal(b *testing.B, pb Message, marshal func(Message) ([]byte, error)) { + d, _ := marshal(pb) + b.SetBytes(int64(len(d))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + marshal(pb) + } +} + +func benchmarkBufferMarshal(b *testing.B, pb Message) { + p := NewBuffer(nil) + benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { + p.Reset() + err := p.Marshal(pb0) + return p.Bytes(), err + }) +} + +func benchmarkSize(b *testing.B, pb Message) { + benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { + Size(pb) + return nil, nil + }) +} + +func newOf(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + return reflect.New(in.Type().Elem()).Interface().(Message) +} + +func benchmarkUnmarshal(b *testing.B, pb Message, unmarshal func([]byte, Message) error) { + d, _ := Marshal(pb) + b.SetBytes(int64(len(d))) + pbd := newOf(pb) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + unmarshal(d, pbd) + } +} + +func benchmarkBufferUnmarshal(b *testing.B, pb Message) { + p := NewBuffer(nil) + benchmarkUnmarshal(b, pb, func(d []byte, pb0 Message) error { + p.SetBuf(d) + return p.Unmarshal(pb0) + }) +} + +// Benchmark{Marshal,BufferMarshal,Size,Unmarshal,BufferUnmarshal}{,Bytes} + +func BenchmarkMarshal(b *testing.B) { + benchmarkMarshal(b, testMsg(), Marshal) +} + +func BenchmarkBufferMarshal(b *testing.B) { + benchmarkBufferMarshal(b, testMsg()) +} + +func BenchmarkSize(b *testing.B) { + benchmarkSize(b, testMsg()) +} + +func BenchmarkUnmarshal(b *testing.B) { + benchmarkUnmarshal(b, testMsg(), Unmarshal) +} + +func BenchmarkBufferUnmarshal(b *testing.B) { + benchmarkBufferUnmarshal(b, testMsg()) +} + +func BenchmarkMarshalBytes(b *testing.B) { + benchmarkMarshal(b, bytesMsg(), Marshal) +} + +func BenchmarkBufferMarshalBytes(b *testing.B) { + benchmarkBufferMarshal(b, bytesMsg()) +} + +func BenchmarkSizeBytes(b *testing.B) { + benchmarkSize(b, bytesMsg()) +} + +func BenchmarkUnmarshalBytes(b *testing.B) { + benchmarkUnmarshal(b, bytesMsg(), Unmarshal) +} + +func BenchmarkBufferUnmarshalBytes(b *testing.B) { + benchmarkBufferUnmarshal(b, bytesMsg()) +} + +func BenchmarkUnmarshalUnrecognizedFields(b *testing.B) { + b.StopTimer() + pb := initGoTestField() + skip := &GoSkipTest{ + SkipInt32: Int32(32), + SkipFixed32: Uint32(3232), + SkipFixed64: Uint64(6464), + SkipString: String("skipper"), + Skipgroup: &GoSkipTest_SkipGroup{ + GroupInt32: Int32(75), + GroupString: String("wxyz"), + }, + } + + pbd := new(GoTestField) + p := NewBuffer(nil) + p.Marshal(pb) + p.Marshal(skip) + p2 := NewBuffer(nil) + + b.StartTimer() + for i := 0; i < b.N; i++ { + p2.SetBuf(p.Bytes()) + p2.Unmarshal(pbd) + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/any_test.go b/vendor/github.com/gogo/protobuf/proto/any_test.go new file mode 100644 index 000000000..f098d8287 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/any_test.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "strings" + "testing" + + "github.com/gogo/protobuf/proto" + + pb "github.com/gogo/protobuf/proto/proto3_proto" + testpb "github.com/gogo/protobuf/proto/testdata" + "github.com/gogo/protobuf/types" +) + +var ( + expandedMarshaler = proto.TextMarshaler{ExpandAny: true} + expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true} +) + +// anyEqual reports whether two messages which may be google.protobuf.Any or may +// contain google.protobuf.Any fields are equal. We can't use proto.Equal for +// comparison, because semantically equivalent messages may be marshaled to +// binary in different tag order. Instead, trust that TextMarshaler with +// ExpandAny option works and compare the text marshaling results. +func anyEqual(got, want proto.Message) bool { + // if messages are proto.Equal, no need to marshal. + if proto.Equal(got, want) { + return true + } + g := expandedMarshaler.Text(got) + w := expandedMarshaler.Text(want) + return g == w +} + +type golden struct { + m proto.Message + t, c string +} + +var goldenMessages = makeGolden() + +func makeGolden() []golden { + nested := &pb.Nested{Bunny: "Monty"} + nb, err := proto.Marshal(nested) + if err != nil { + panic(err) + } + m1 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}, + } + m2 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &types.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb}, + } + m3 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &types.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb}, + } + m4 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &types.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb}, + } + m5 := &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb} + + any1 := &testpb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")} + proto.SetExtension(any1, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("foo")}) + proto.SetExtension(any1, testpb.E_Ext_Text, proto.String("bar")) + any1b, err := proto.Marshal(any1) + if err != nil { + panic(err) + } + any2 := &testpb.MyMessage{Count: proto.Int32(42), Bikeshed: testpb.MyMessage_GREEN.Enum(), RepBytes: [][]byte{[]byte("roboto")}} + proto.SetExtension(any2, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("baz")}) + any2b, err := proto.Marshal(any2) + if err != nil { + panic(err) + } + m6 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, + ManyThings: []*types.Any{ + {TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b}, + {TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, + }, + } + + const ( + m1Golden = ` +name: "David" +result_count: 47 +anything: < + [type.googleapis.com/proto3_proto.Nested]: < + bunny: "Monty" + > +> +` + m2Golden = ` +name: "David" +result_count: 47 +anything: < + ["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: < + bunny: "Monty" + > +> +` + m3Golden = ` +name: "David" +result_count: 47 +anything: < + ["type.googleapis.com/\"/proto3_proto.Nested"]: < + bunny: "Monty" + > +> +` + m4Golden = ` +name: "David" +result_count: 47 +anything: < + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Monty" + > +> +` + m5Golden = ` +[type.googleapis.com/proto3_proto.Nested]: < + bunny: "Monty" +> +` + m6Golden = ` +name: "David" +result_count: 47 +anything: < + [type.googleapis.com/testdata.MyMessage]: < + count: 47 + name: "David" + [testdata.Ext.more]: < + data: "foo" + > + [testdata.Ext.text]: "bar" + > +> +many_things: < + [type.googleapis.com/testdata.MyMessage]: < + count: 42 + bikeshed: GREEN + rep_bytes: "roboto" + [testdata.Ext.more]: < + data: "baz" + > + > +> +many_things: < + [type.googleapis.com/testdata.MyMessage]: < + count: 47 + name: "David" + [testdata.Ext.more]: < + data: "foo" + > + [testdata.Ext.text]: "bar" + > +> +` + ) + return []golden{ + {m1, strings.TrimSpace(m1Golden) + "\n", strings.TrimSpace(compact(m1Golden)) + " "}, + {m2, strings.TrimSpace(m2Golden) + "\n", strings.TrimSpace(compact(m2Golden)) + " "}, + {m3, strings.TrimSpace(m3Golden) + "\n", strings.TrimSpace(compact(m3Golden)) + " "}, + {m4, strings.TrimSpace(m4Golden) + "\n", strings.TrimSpace(compact(m4Golden)) + " "}, + {m5, strings.TrimSpace(m5Golden) + "\n", strings.TrimSpace(compact(m5Golden)) + " "}, + {m6, strings.TrimSpace(m6Golden) + "\n", strings.TrimSpace(compact(m6Golden)) + " "}, + } +} + +func TestMarshalGolden(t *testing.T) { + for _, tt := range goldenMessages { + if got, want := expandedMarshaler.Text(tt.m), tt.t; got != want { + t.Errorf("message %v: got:\n%s\nwant:\n%s", tt.m, got, want) + } + if got, want := expandedCompactMarshaler.Text(tt.m), tt.c; got != want { + t.Errorf("message %v: got:\n`%s`\nwant:\n`%s`", tt.m, got, want) + } + } +} + +func TestUnmarshalGolden(t *testing.T) { + for _, tt := range goldenMessages { + want := tt.m + got := proto.Clone(tt.m) + got.Reset() + if err := proto.UnmarshalText(tt.t, got); err != nil { + t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err) + } + if !anyEqual(got, want) { + t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want) + } + got.Reset() + if err := proto.UnmarshalText(tt.c, got); err != nil { + t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err) + } + if !anyEqual(got, want) { + t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want) + } + } +} + +func TestMarshalUnknownAny(t *testing.T) { + m := &pb.Message{ + Anything: &types.Any{ + TypeUrl: "foo", + Value: []byte("bar"), + }, + } + want := `anything: < + type_url: "foo" + value: "bar" +> +` + got := expandedMarshaler.Text(m) + if got != want { + t.Errorf("got\n`%s`\nwant\n`%s`", got, want) + } +} + +func TestAmbiguousAny(t *testing.T) { + pb := &types.Any{} + err := proto.UnmarshalText(` + type_url: "ttt/proto3_proto.Nested" + value: "\n\x05Monty" + `, pb) + t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err) + if err != nil { + t.Errorf("failed to parse ambiguous Any message: %v", err) + } +} + +func TestUnmarshalOverwriteAny(t *testing.T) { + pb := &types.Any{} + err := proto.UnmarshalText(` + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Monty" + > + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Rabbit of Caerbannog" + > + `, pb) + want := `line 7: Any message unpacked multiple times, or "type_url" already set` + if err.Error() != want { + t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) + } +} + +func TestUnmarshalAnyMixAndMatch(t *testing.T) { + pb := &types.Any{} + err := proto.UnmarshalText(` + value: "\n\x05Monty" + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Rabbit of Caerbannog" + > + `, pb) + want := `line 5: Any message unpacked multiple times, or "value" already set` + if err.Error() != want { + t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/clone_test.go b/vendor/github.com/gogo/protobuf/proto/clone_test.go new file mode 100644 index 000000000..1a16eb554 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/clone_test.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/gogo/protobuf/proto" + + proto3pb "github.com/gogo/protobuf/proto/proto3_proto" + pb "github.com/gogo/protobuf/proto/testdata" +) + +var cloneTestMessage = &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &pb.InnerMessage{ + Host: proto.String("niles"), + Port: proto.Int32(9099), + Connected: proto.Bool(true), + }, + Others: []*pb.OtherMessage{ + { + Value: []byte("some bytes"), + }, + }, + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, +} + +func init() { + ext := &pb.Ext{ + Data: proto.String("extension"), + } + if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil { + panic("SetExtension: " + err.Error()) + } +} + +func TestClone(t *testing.T) { + m := proto.Clone(cloneTestMessage).(*pb.MyMessage) + if !proto.Equal(m, cloneTestMessage) { + t.Errorf("Clone(%v) = %v", cloneTestMessage, m) + } + + // Verify it was a deep copy. + *m.Inner.Port++ + if proto.Equal(m, cloneTestMessage) { + t.Error("Mutating clone changed the original") + } + // Byte fields and repeated fields should be copied. + if &m.Pet[0] == &cloneTestMessage.Pet[0] { + t.Error("Pet: repeated field not copied") + } + if &m.Others[0] == &cloneTestMessage.Others[0] { + t.Error("Others: repeated field not copied") + } + if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { + t.Error("Others[0].Value: bytes field not copied") + } + if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { + t.Error("RepBytes: repeated field not copied") + } + if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { + t.Error("RepBytes[0]: bytes field not copied") + } +} + +func TestCloneNil(t *testing.T) { + var m *pb.MyMessage + if c := proto.Clone(m); !proto.Equal(m, c) { + t.Errorf("Clone(%v) = %v", m, c) + } +} + +var mergeTests = []struct { + src, dst, want proto.Message +}{ + { + src: &pb.MyMessage{ + Count: proto.Int32(42), + }, + dst: &pb.MyMessage{ + Name: proto.String("Dave"), + }, + want: &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + }, + }, + { + src: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("hey"), + Connected: proto.Bool(true), + }, + Pet: []string{"horsey"}, + Others: []*pb.OtherMessage{ + { + Value: []byte("some bytes"), + }, + }, + }, + dst: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("niles"), + Port: proto.Int32(9099), + }, + Pet: []string{"bunny", "kitty"}, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(31415926535), + }, + { + // Explicitly test a src=nil field + Inner: nil, + }, + }, + }, + want: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("hey"), + Connected: proto.Bool(true), + Port: proto.Int32(9099), + }, + Pet: []string{"bunny", "kitty", "horsey"}, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(31415926535), + }, + {}, + { + Value: []byte("some bytes"), + }, + }, + }, + }, + { + src: &pb.MyMessage{ + RepBytes: [][]byte{[]byte("wow")}, + }, + dst: &pb.MyMessage{ + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham")}, + }, + want: &pb.MyMessage{ + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, + }, + }, + // Check that a scalar bytes field replaces rather than appends. + { + src: &pb.OtherMessage{Value: []byte("foo")}, + dst: &pb.OtherMessage{Value: []byte("bar")}, + want: &pb.OtherMessage{Value: []byte("foo")}, + }, + { + src: &pb.MessageWithMap{ + NameMapping: map[int32]string{6: "Nigel"}, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: {F: proto.Float64(2.0)}, + 0x4002: { + F: proto.Float64(2.0), + }, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + dst: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Bruce", // should be overwritten + 7: "Andrew", + }, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4002: { + F: proto.Float64(3.0), + Exact: proto.Bool(true), + }, // the entire message should be overwritten + }, + }, + want: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Nigel", + 7: "Andrew", + }, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: {F: proto.Float64(2.0)}, + 0x4002: { + F: proto.Float64(2.0), + }, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + }, + // proto3 shouldn't merge zero values, + // in the same way that proto2 shouldn't merge nils. + { + src: &proto3pb.Message{ + Name: "Aaron", + Data: []byte(""), // zero value, but not nil + }, + dst: &proto3pb.Message{ + HeightInCm: 176, + Data: []byte("texas!"), + }, + want: &proto3pb.Message{ + Name: "Aaron", + HeightInCm: 176, + Data: []byte("texas!"), + }, + }, + // Oneof fields should merge by assignment. + { + src: &pb.Communique{ + Union: &pb.Communique_Number{Number: 41}, + }, + dst: &pb.Communique{ + Union: &pb.Communique_Name{Name: "Bobby Tables"}, + }, + want: &pb.Communique{ + Union: &pb.Communique_Number{Number: 41}, + }, + }, + // Oneof nil is the same as not set. + { + src: &pb.Communique{}, + dst: &pb.Communique{ + Union: &pb.Communique_Name{Name: "Bobby Tables"}, + }, + want: &pb.Communique{ + Union: &pb.Communique_Name{Name: "Bobby Tables"}, + }, + }, + { + src: &proto3pb.Message{ + Terrain: map[string]*proto3pb.Nested{ + "kay_a": {Cute: true}, // replace + "kay_b": {Bunny: "rabbit"}, // insert + }, + }, + dst: &proto3pb.Message{ + Terrain: map[string]*proto3pb.Nested{ + "kay_a": {Bunny: "lost"}, // replaced + "kay_c": {Bunny: "bunny"}, // keep + }, + }, + want: &proto3pb.Message{ + Terrain: map[string]*proto3pb.Nested{ + "kay_a": {Cute: true}, + "kay_b": {Bunny: "rabbit"}, + "kay_c": {Bunny: "bunny"}, + }, + }, + }, +} + +func TestMerge(t *testing.T) { + for _, m := range mergeTests { + got := proto.Clone(m.dst) + proto.Merge(got, m.src) + if !proto.Equal(got, m.want) { + t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want) + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/decode_test.go b/vendor/github.com/gogo/protobuf/proto/decode_test.go new file mode 100644 index 000000000..64d4decd9 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/decode_test.go @@ -0,0 +1,262 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build go1.7 + +package proto_test + +import ( + "testing" + + "github.com/gogo/protobuf/proto" + tpb "github.com/gogo/protobuf/proto/proto3_proto" +) + +var ( + bytesBlackhole []byte + msgBlackhole = new(tpb.Message) +) + +// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5 +// BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and +// 2 bytes long). +// func BenchmarkVarint32ArraySmall(b *testing.B) { +// for i := uint(1); i <= 10; i++ { +// dist := genInt32Dist([7]int{0, 3, 1}, 1<unmarshal. +} + +func TestMarshalUnmarshalRepeatedExtension(t *testing.T) { + // Add a repeated extension to the result. + tests := []struct { + name string + ext []*pb.ComplexExtension + }{ + { + "two fields", + []*pb.ComplexExtension{ + {First: proto.Int32(7)}, + {Second: proto.Int32(11)}, + }, + }, + { + "repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {Third: []int32{2000}}, + }, + }, + { + "two fields and repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {First: proto.Int32(9)}, + {Second: proto.Int32(21)}, + {Third: []int32{2000}}, + }, + }, + } + for _, test := range tests { + // Marshal message with a repeated extension. + msg1 := new(pb.OtherMessage) + err := proto.SetExtension(msg1, pb.E_RComplex, test.ext) + if err != nil { + t.Fatalf("[%s] Error setting extension: %v", test.name, err) + } + b, err := proto.Marshal(msg1) + if err != nil { + t.Fatalf("[%s] Error marshaling message: %v", test.name, err) + } + + // Unmarshal and read the merged proto. + msg2 := new(pb.OtherMessage) + err = proto.Unmarshal(b, msg2) + if err != nil { + t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) + } + e, err := proto.GetExtension(msg2, pb.E_RComplex) + if err != nil { + t.Fatalf("[%s] Error getting extension: %v", test.name, err) + } + ext := e.([]*pb.ComplexExtension) + if ext == nil { + t.Fatalf("[%s] Invalid extension", test.name) + } + if !reflect.DeepEqual(ext, test.ext) { + t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, test.ext) + } + } +} + +func TestUnmarshalRepeatingNonRepeatedExtension(t *testing.T) { + // We may see multiple instances of the same extension in the wire + // format. For example, the proto compiler may encode custom options in + // this way. Here, we verify that we merge the extensions together. + tests := []struct { + name string + ext []*pb.ComplexExtension + }{ + { + "two fields", + []*pb.ComplexExtension{ + {First: proto.Int32(7)}, + {Second: proto.Int32(11)}, + }, + }, + { + "repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {Third: []int32{2000}}, + }, + }, + { + "two fields and repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {First: proto.Int32(9)}, + {Second: proto.Int32(21)}, + {Third: []int32{2000}}, + }, + }, + } + for _, test := range tests { + var buf bytes.Buffer + var want pb.ComplexExtension + + // Generate a serialized representation of a repeated extension + // by catenating bytes together. + for i, e := range test.ext { + // Merge to create the wanted proto. + proto.Merge(&want, e) + + // serialize the message + msg := new(pb.OtherMessage) + err := proto.SetExtension(msg, pb.E_Complex, e) + if err != nil { + t.Fatalf("[%s] Error setting extension %d: %v", test.name, i, err) + } + b, err := proto.Marshal(msg) + if err != nil { + t.Fatalf("[%s] Error marshaling message %d: %v", test.name, i, err) + } + buf.Write(b) + } + + // Unmarshal and read the merged proto. + msg2 := new(pb.OtherMessage) + err := proto.Unmarshal(buf.Bytes(), msg2) + if err != nil { + t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) + } + e, err := proto.GetExtension(msg2, pb.E_Complex) + if err != nil { + t.Fatalf("[%s] Error getting extension: %v", test.name, err) + } + ext := e.(*pb.ComplexExtension) + if ext == nil { + t.Fatalf("[%s] Invalid extension", test.name) + } + if !reflect.DeepEqual(*ext, want) { + t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, want) + } + } +} + +func TestClearAllExtensions(t *testing.T) { + // unregistered extension + desc := &proto.ExtensionDesc{ + ExtendedType: (*pb.MyMessage)(nil), + ExtensionType: (*bool)(nil), + Field: 101010100, + Name: "emptyextension", + Tag: "varint,0,opt", + } + m := &pb.MyMessage{} + if proto.HasExtension(m, desc) { + t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) + } + if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { + t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) + } + if !proto.HasExtension(m, desc) { + t.Errorf("proto.HasExtension(%s): got false, want true", proto.MarshalTextString(m)) + } + proto.ClearAllExtensions(m) + if proto.HasExtension(m, desc) { + t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) + } +} + +func TestMarshalRace(t *testing.T) { + // unregistered extension + desc := &proto.ExtensionDesc{ + ExtendedType: (*pb.MyMessage)(nil), + ExtensionType: (*bool)(nil), + Field: 101010100, + Name: "emptyextension", + Tag: "varint,0,opt", + } + + m := &pb.MyMessage{Count: proto.Int32(4)} + if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { + t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) + } + + errChan := make(chan error, 3) + for n := 3; n > 0; n-- { + go func() { + _, err := proto.Marshal(m) + errChan <- err + }() + } + for i := 0; i < 3; i++ { + err := <-errChan + if err != nil { + t.Fatal(err) + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/map_test.go b/vendor/github.com/gogo/protobuf/proto/map_test.go new file mode 100644 index 000000000..18b946d00 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/map_test.go @@ -0,0 +1,46 @@ +package proto_test + +import ( + "fmt" + "testing" + + "github.com/gogo/protobuf/proto" + ppb "github.com/gogo/protobuf/proto/proto3_proto" +) + +func marshalled() []byte { + m := &ppb.IntMaps{} + for i := 0; i < 1000; i++ { + m.Maps = append(m.Maps, &ppb.IntMap{ + Rtt: map[int32]int32{1: 2}, + }) + } + b, err := proto.Marshal(m) + if err != nil { + panic(fmt.Sprintf("Can't marshal %+v: %v", m, err)) + } + return b +} + +func BenchmarkConcurrentMapUnmarshal(b *testing.B) { + in := marshalled() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + var out ppb.IntMaps + if err := proto.Unmarshal(in, &out); err != nil { + b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) + } + } + }) +} + +func BenchmarkSequentialMapUnmarshal(b *testing.B) { + in := marshalled() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var out ppb.IntMaps + if err := proto.Unmarshal(in, &out); err != nil { + b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/message_set_test.go b/vendor/github.com/gogo/protobuf/proto/message_set_test.go new file mode 100644 index 000000000..353a3ea76 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/message_set_test.go @@ -0,0 +1,66 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "bytes" + "testing" +) + +func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { + // Check that a repeated message set entry will be concatenated. + in := &messageSet{ + Item: []*_MessageSet_Item{ + {TypeId: Int32(12345), Message: []byte("hoo")}, + {TypeId: Int32(12345), Message: []byte("hah")}, + }, + } + b, err := Marshal(in) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + t.Logf("Marshaled bytes: %q", b) + + var extensions XXX_InternalExtensions + if err := UnmarshalMessageSet(b, &extensions); err != nil { + t.Fatalf("UnmarshalMessageSet: %v", err) + } + ext, ok := extensions.p.extensionMap[12345] + if !ok { + t.Fatalf("Didn't retrieve extension 12345; map is %v", extensions.p.extensionMap) + } + // Skip wire type/field number and length varints. + got := skipVarint(skipVarint(ext.enc)) + if want := []byte("hoohah"); !bytes.Equal(got, want) { + t.Errorf("Combined extension is %q, want %q", got, want) + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/proto3_test.go b/vendor/github.com/gogo/protobuf/proto/proto3_test.go new file mode 100644 index 000000000..75b66c179 --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/proto3_test.go @@ -0,0 +1,135 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/gogo/protobuf/proto" + pb "github.com/gogo/protobuf/proto/proto3_proto" + tpb "github.com/gogo/protobuf/proto/testdata" +) + +func TestProto3ZeroValues(t *testing.T) { + tests := []struct { + desc string + m proto.Message + }{ + {"zero message", &pb.Message{}}, + {"empty bytes field", &pb.Message{Data: []byte{}}}, + } + for _, test := range tests { + b, err := proto.Marshal(test.m) + if err != nil { + t.Errorf("%s: proto.Marshal: %v", test.desc, err) + continue + } + if len(b) > 0 { + t.Errorf("%s: Encoding is non-empty: %q", test.desc, b) + } + } +} + +func TestRoundTripProto3(t *testing.T) { + m := &pb.Message{ + Name: "David", // (2 | 1<<3): 0x0a 0x05 "David" + Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01 + HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01 + Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto" + ResultCount: 47, // (0 | 7<<3): 0x38 0x2f + TrueScotsman: true, // (0 | 8<<3): 0x40 0x01 + Score: 8.1, // (5 | 9<<3): 0x4d <8.1> + + Key: []uint64{1, 0xdeadbeef}, + Nested: &pb.Nested{ + Bunny: "Monty", + }, + } + t.Logf(" m: %v", m) + + b, err := proto.Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal: %v", err) + } + t.Logf(" b: %q", b) + + m2 := new(pb.Message) + if err := proto.Unmarshal(b, m2); err != nil { + t.Fatalf("proto.Unmarshal: %v", err) + } + t.Logf("m2: %v", m2) + + if !proto.Equal(m, m2) { + t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2) + } +} + +func TestGettersForBasicTypesExist(t *testing.T) { + var m pb.Message + if got := m.GetNested().GetBunny(); got != "" { + t.Errorf("m.GetNested().GetBunny() = %q, want empty string", got) + } + if got := m.GetNested().GetCute(); got { + t.Errorf("m.GetNested().GetCute() = %t, want false", got) + } +} + +func TestProto3SetDefaults(t *testing.T) { + in := &pb.Message{ + Terrain: map[string]*pb.Nested{ + "meadow": new(pb.Nested), + }, + Proto2Field: new(tpb.SubDefaults), + Proto2Value: map[string]*tpb.SubDefaults{ + "badlands": new(tpb.SubDefaults), + }, + } + + got := proto.Clone(in).(*pb.Message) + proto.SetDefaults(got) + + // There are no defaults in proto3. Everything should be the zero value, but + // we need to remember to set defaults for nested proto2 messages. + want := &pb.Message{ + Terrain: map[string]*pb.Nested{ + "meadow": new(pb.Nested), + }, + Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, + Proto2Value: map[string]*tpb.SubDefaults{ + "badlands": {N: proto.Int64(7)}, + }, + } + + if !proto.Equal(got, want) { + t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/size2_test.go b/vendor/github.com/gogo/protobuf/proto/size2_test.go new file mode 100644 index 000000000..a2729c39a --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/size2_test.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "testing" +) + +// This is a separate file and package from size_test.go because that one uses +// generated messages and thus may not be in package proto without having a circular +// dependency, whereas this file tests unexported details of size.go. + +func TestVarintSize(t *testing.T) { + // Check the edge cases carefully. + testCases := []struct { + n uint64 + size int + }{ + {0, 1}, + {1, 1}, + {127, 1}, + {128, 2}, + {16383, 2}, + {16384, 3}, + {1<<63 - 1, 9}, + {1 << 63, 10}, + } + for _, tc := range testCases { + size := sizeVarint(tc.n) + if size != tc.size { + t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/size_test.go b/vendor/github.com/gogo/protobuf/proto/size_test.go new file mode 100644 index 000000000..0a6c1772b --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/size_test.go @@ -0,0 +1,164 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "log" + "strings" + "testing" + + . "github.com/gogo/protobuf/proto" + proto3pb "github.com/gogo/protobuf/proto/proto3_proto" + pb "github.com/gogo/protobuf/proto/testdata" +) + +var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} + +// messageWithExtension2 is in equal_test.go. +var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)} + +func init() { + if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil { + log.Panicf("SetExtension: %v", err) + } + if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil { + log.Panicf("SetExtension: %v", err) + } + + // Force messageWithExtension3 to have the extension encoded. + Marshal(messageWithExtension3) + +} + +var SizeTests = []struct { + desc string + pb Message +}{ + {"empty", &pb.OtherMessage{}}, + // Basic types. + {"bool", &pb.Defaults{F_Bool: Bool(true)}}, + {"int32", &pb.Defaults{F_Int32: Int32(12)}}, + {"negative int32", &pb.Defaults{F_Int32: Int32(-1)}}, + {"small int64", &pb.Defaults{F_Int64: Int64(1)}}, + {"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}}, + {"negative int64", &pb.Defaults{F_Int64: Int64(-1)}}, + {"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}}, + {"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}}, + {"uint32", &pb.Defaults{F_Uint32: Uint32(123)}}, + {"uint64", &pb.Defaults{F_Uint64: Uint64(124)}}, + {"float", &pb.Defaults{F_Float: Float32(12.6)}}, + {"double", &pb.Defaults{F_Double: Float64(13.9)}}, + {"string", &pb.Defaults{F_String: String("niles")}}, + {"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}}, + {"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}}, + {"sint32", &pb.Defaults{F_Sint32: Int32(65)}}, + {"sint64", &pb.Defaults{F_Sint64: Int64(67)}}, + {"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}}, + // Repeated. + {"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}}, + {"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}}, + {"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}}, + {"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}}, + {"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}}, + {"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{ + // Need enough large numbers to verify that the header is counting the number of bytes + // for the field, not the number of elements. + 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, + 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, + }}}, + {"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}}, + {"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}}, + // Nested. + {"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}}, + {"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}}, + // Other things. + {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, + {"extension (unencoded)", messageWithExtension1}, + {"extension (encoded)", messageWithExtension3}, + // proto3 message + {"proto3 empty", &proto3pb.Message{}}, + {"proto3 bool", &proto3pb.Message{TrueScotsman: true}}, + {"proto3 int64", &proto3pb.Message{ResultCount: 1}}, + {"proto3 uint32", &proto3pb.Message{HeightInCm: 123}}, + {"proto3 float", &proto3pb.Message{Score: 12.6}}, + {"proto3 string", &proto3pb.Message{Name: "Snezana"}}, + {"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}}, + {"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}}, + {"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}}, + {"proto3 map field with empty bytes", &proto3pb.MessageWithMap{ByteMapping: map[bool][]byte{false: {}}}}, + + {"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}}, + {"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: {F: Float64(2.0)}}}}, + {"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}}, + {"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: {}}}}, + + {"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}}, + {"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}}, + {"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}}, + + {"oneof not set", &pb.Oneof{}}, + {"oneof bool", &pb.Oneof{Union: &pb.Oneof_F_Bool{F_Bool: true}}}, + {"oneof zero int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{F_Int32: 0}}}, + {"oneof big int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{F_Int32: 1 << 20}}}, + {"oneof int64", &pb.Oneof{Union: &pb.Oneof_F_Int64{F_Int64: 42}}}, + {"oneof fixed32", &pb.Oneof{Union: &pb.Oneof_F_Fixed32{F_Fixed32: 43}}}, + {"oneof fixed64", &pb.Oneof{Union: &pb.Oneof_F_Fixed64{F_Fixed64: 44}}}, + {"oneof uint32", &pb.Oneof{Union: &pb.Oneof_F_Uint32{F_Uint32: 45}}}, + {"oneof uint64", &pb.Oneof{Union: &pb.Oneof_F_Uint64{F_Uint64: 46}}}, + {"oneof float", &pb.Oneof{Union: &pb.Oneof_F_Float{F_Float: 47.1}}}, + {"oneof double", &pb.Oneof{Union: &pb.Oneof_F_Double{F_Double: 48.9}}}, + {"oneof string", &pb.Oneof{Union: &pb.Oneof_F_String{F_String: "Rhythmic Fman"}}}, + {"oneof bytes", &pb.Oneof{Union: &pb.Oneof_F_Bytes{F_Bytes: []byte("let go")}}}, + {"oneof sint32", &pb.Oneof{Union: &pb.Oneof_F_Sint32{F_Sint32: 50}}}, + {"oneof sint64", &pb.Oneof{Union: &pb.Oneof_F_Sint64{F_Sint64: 51}}}, + {"oneof enum", &pb.Oneof{Union: &pb.Oneof_F_Enum{F_Enum: pb.MyMessage_BLUE}}}, + {"message for oneof", &pb.GoTestField{Label: String("k"), Type: String("v")}}, + {"oneof message", &pb.Oneof{Union: &pb.Oneof_F_Message{F_Message: &pb.GoTestField{Label: String("k"), Type: String("v")}}}}, + {"oneof group", &pb.Oneof{Union: &pb.Oneof_FGroup{FGroup: &pb.Oneof_F_Group{X: Int32(52)}}}}, + {"oneof largest tag", &pb.Oneof{Union: &pb.Oneof_F_Largest_Tag{F_Largest_Tag: 1}}}, + {"multiple oneofs", &pb.Oneof{Union: &pb.Oneof_F_Int32{F_Int32: 1}, Tormato: &pb.Oneof_Value{Value: 2}}}, +} + +func TestSize(t *testing.T) { + for _, tc := range SizeTests { + size := Size(tc.pb) + b, err := Marshal(tc.pb) + if err != nil { + t.Errorf("%v: Marshal failed: %v", tc.desc, err) + continue + } + if size != len(b) { + t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b)) + t.Logf("%v: bytes: %#v", tc.desc, b) + } + } +} diff --git a/vendor/github.com/gogo/protobuf/proto/text_parser_test.go b/vendor/github.com/gogo/protobuf/proto/text_parser_test.go new file mode 100644 index 000000000..9a3a447ce --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_parser_test.go @@ -0,0 +1,673 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "math" + "reflect" + "testing" + + . "github.com/gogo/protobuf/proto" + proto3pb "github.com/gogo/protobuf/proto/proto3_proto" + . "github.com/gogo/protobuf/proto/testdata" +) + +type UnmarshalTextTest struct { + in string + err string // if "", no error expected + out *MyMessage +} + +func buildExtStructTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + SetExtension(msg, E_Ext_More, &Ext{ + Data: String("Hello, world!"), + }) + return UnmarshalTextTest{in: text, out: msg} +} + +func buildExtDataTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + SetExtension(msg, E_Ext_Text, String("Hello, world!")) + SetExtension(msg, E_Ext_Number, Int32(1729)) + return UnmarshalTextTest{in: text, out: msg} +} + +func buildExtRepStringTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil { + panic(err) + } + return UnmarshalTextTest{in: text, out: msg} +} + +var unMarshalTextTests = []UnmarshalTextTest{ + // Basic + { + in: " count:42\n name:\"Dave\" ", + out: &MyMessage{ + Count: Int32(42), + Name: String("Dave"), + }, + }, + + // Empty quoted string + { + in: `count:42 name:""`, + out: &MyMessage{ + Count: Int32(42), + Name: String(""), + }, + }, + + // Quoted string concatenation with double quotes + { + in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string concatenation with single quotes + { + in: "count:42 name: 'My name is '\n'elsewhere'", + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string concatenations with mixed quotes + { + in: "count:42 name: 'My name is '\n\"elsewhere\"", + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + { + in: "count:42 name: \"My name is \"\n'elsewhere'", + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string with escaped apostrophe + { + in: `count:42 name: "HOLIDAY - New Year\'s Day"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("HOLIDAY - New Year's Day"), + }, + }, + + // Quoted string with single quote + { + in: `count:42 name: 'Roger "The Ramster" Ramjet'`, + out: &MyMessage{ + Count: Int32(42), + Name: String(`Roger "The Ramster" Ramjet`), + }, + }, + + // Quoted string with all the accepted special characters from the C++ test + { + in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"", + out: &MyMessage{ + Count: Int32(42), + Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"), + }, + }, + + // Quoted string with quoted backslash + { + in: `count:42 name: "\\'xyz"`, + out: &MyMessage{ + Count: Int32(42), + Name: String(`\'xyz`), + }, + }, + + // Quoted string with UTF-8 bytes. + { + in: "count:42 name: '\303\277\302\201\xAB'", + out: &MyMessage{ + Count: Int32(42), + Name: String("\303\277\302\201\xAB"), + }, + }, + + // Bad quoted string + { + in: `inner: < host: "\0" >` + "\n", + err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`, + }, + + // Number too large for int64 + { + in: "count: 1 others { key: 123456789012345678901 }", + err: "line 1.23: invalid int64: 123456789012345678901", + }, + + // Number too large for int32 + { + in: "count: 1234567890123", + err: "line 1.7: invalid int32: 1234567890123", + }, + + // Number in hexadecimal + { + in: "count: 0x2beef", + out: &MyMessage{ + Count: Int32(0x2beef), + }, + }, + + // Number in octal + { + in: "count: 024601", + out: &MyMessage{ + Count: Int32(024601), + }, + }, + + // Floating point number with "f" suffix + { + in: "count: 4 others:< weight: 17.0f >", + out: &MyMessage{ + Count: Int32(4), + Others: []*OtherMessage{ + { + Weight: Float32(17), + }, + }, + }, + }, + + // Floating point positive infinity + { + in: "count: 4 bigfloat: inf", + out: &MyMessage{ + Count: Int32(4), + Bigfloat: Float64(math.Inf(1)), + }, + }, + + // Floating point negative infinity + { + in: "count: 4 bigfloat: -inf", + out: &MyMessage{ + Count: Int32(4), + Bigfloat: Float64(math.Inf(-1)), + }, + }, + + // Number too large for float32 + { + in: "others:< weight: 12345678901234567890123456789012345678901234567890 >", + err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890", + }, + + // Number posing as a quoted string + { + in: `inner: < host: 12 >` + "\n", + err: `line 1.15: invalid string: 12`, + }, + + // Quoted string posing as int32 + { + in: `count: "12"`, + err: `line 1.7: invalid int32: "12"`, + }, + + // Quoted string posing a float32 + { + in: `others:< weight: "17.4" >`, + err: `line 1.17: invalid float32: "17.4"`, + }, + + // Enum + { + in: `count:42 bikeshed: BLUE`, + out: &MyMessage{ + Count: Int32(42), + Bikeshed: MyMessage_BLUE.Enum(), + }, + }, + + // Repeated field + { + in: `count:42 pet: "horsey" pet:"bunny"`, + out: &MyMessage{ + Count: Int32(42), + Pet: []string{"horsey", "bunny"}, + }, + }, + + // Repeated field with list notation + { + in: `count:42 pet: ["horsey", "bunny"]`, + out: &MyMessage{ + Count: Int32(42), + Pet: []string{"horsey", "bunny"}, + }, + }, + + // Repeated message with/without colon and <>/{} + { + in: `count:42 others:{} others{} others:<> others:{}`, + out: &MyMessage{ + Count: Int32(42), + Others: []*OtherMessage{ + {}, + {}, + {}, + {}, + }, + }, + }, + + // Missing colon for inner message + { + in: `count:42 inner < host: "cauchy.syd" >`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("cauchy.syd"), + }, + }, + }, + + // Missing colon for string field + { + in: `name "Dave"`, + err: `line 1.5: expected ':', found "\"Dave\""`, + }, + + // Missing colon for int32 field + { + in: `count 42`, + err: `line 1.6: expected ':', found "42"`, + }, + + // Missing required field + { + in: `name: "Pawel"`, + err: `proto: required field "testdata.MyMessage.count" not set`, + out: &MyMessage{ + Name: String("Pawel"), + }, + }, + + // Missing required field in a required submessage + { + in: `count: 42 we_must_go_deeper < leo_finally_won_an_oscar <> >`, + err: `proto: required field "testdata.InnerMessage.host" not set`, + out: &MyMessage{ + Count: Int32(42), + WeMustGoDeeper: &RequiredInnerMessage{LeoFinallyWonAnOscar: &InnerMessage{}}, + }, + }, + + // Repeated non-repeated field + { + in: `name: "Rob" name: "Russ"`, + err: `line 1.12: non-repeated field "name" was repeated`, + }, + + // Group + { + in: `count: 17 SomeGroup { group_field: 12 }`, + out: &MyMessage{ + Count: Int32(17), + Somegroup: &MyMessage_SomeGroup{ + GroupField: Int32(12), + }, + }, + }, + + // Semicolon between fields + { + in: `count:3;name:"Calvin"`, + out: &MyMessage{ + Count: Int32(3), + Name: String("Calvin"), + }, + }, + // Comma between fields + { + in: `count:4,name:"Ezekiel"`, + out: &MyMessage{ + Count: Int32(4), + Name: String("Ezekiel"), + }, + }, + + // Boolean false + { + in: `count:42 inner { host: "example.com" connected: false }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean true + { + in: `count:42 inner { host: "example.com" connected: true }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + // Boolean 0 + { + in: `count:42 inner { host: "example.com" connected: 0 }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean 1 + { + in: `count:42 inner { host: "example.com" connected: 1 }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + // Boolean f + { + in: `count:42 inner { host: "example.com" connected: f }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean t + { + in: `count:42 inner { host: "example.com" connected: t }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + // Boolean False + { + in: `count:42 inner { host: "example.com" connected: False }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean True + { + in: `count:42 inner { host: "example.com" connected: True }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + + // Extension + buildExtStructTest(`count: 42 [testdata.Ext.more]:`), + buildExtStructTest(`count: 42 [testdata.Ext.more] {data:"Hello, world!"}`), + buildExtDataTest(`count: 42 [testdata.Ext.text]:"Hello, world!" [testdata.Ext.number]:1729`), + buildExtRepStringTest(`count: 42 [testdata.greeting]:"bula" [testdata.greeting]:"hola"`), + + // Big all-in-one + { + in: "count:42 # Meaning\n" + + `name:"Dave" ` + + `quote:"\"I didn't want to go.\"" ` + + `pet:"bunny" ` + + `pet:"kitty" ` + + `pet:"horsey" ` + + `inner:<` + + ` host:"footrest.syd" ` + + ` port:7001 ` + + ` connected:true ` + + `> ` + + `others:<` + + ` key:3735928559 ` + + ` value:"\x01A\a\f" ` + + `> ` + + `others:<` + + " weight:58.9 # Atomic weight of Co\n" + + ` inner:<` + + ` host:"lesha.mtv" ` + + ` port:8002 ` + + ` >` + + `>`, + out: &MyMessage{ + Count: Int32(42), + Name: String("Dave"), + Quote: String(`"I didn't want to go."`), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &InnerMessage{ + Host: String("footrest.syd"), + Port: Int32(7001), + Connected: Bool(true), + }, + Others: []*OtherMessage{ + { + Key: Int64(3735928559), + Value: []byte{0x1, 'A', '\a', '\f'}, + }, + { + Weight: Float32(58.9), + Inner: &InnerMessage{ + Host: String("lesha.mtv"), + Port: Int32(8002), + }, + }, + }, + }, + }, +} + +func TestUnmarshalText(t *testing.T) { + for i, test := range unMarshalTextTests { + pb := new(MyMessage) + err := UnmarshalText(test.in, pb) + if test.err == "" { + // We don't expect failure. + if err != nil { + t.Errorf("Test %d: Unexpected error: %v", i, err) + } else if !reflect.DeepEqual(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) + } + } else { + // We do expect failure. + if err == nil { + t.Errorf("Test %d: Didn't get expected error: %v", i, test.err) + } else if err.Error() != test.err { + t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", + i, err.Error(), test.err) + } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !reflect.DeepEqual(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) + } + } + } +} + +func TestUnmarshalTextCustomMessage(t *testing.T) { + msg := &textMessage{} + if err := UnmarshalText("custom", msg); err != nil { + t.Errorf("Unexpected error from custom unmarshal: %v", err) + } + if UnmarshalText("not custom", msg) == nil { + t.Errorf("Didn't get expected error from custom unmarshal") + } +} + +// Regression test; this caused a panic. +func TestRepeatedEnum(t *testing.T) { + pb := new(RepeatedEnum) + if err := UnmarshalText("color: RED", pb); err != nil { + t.Fatal(err) + } + exp := &RepeatedEnum{ + Color: []RepeatedEnum_Color{RepeatedEnum_RED}, + } + if !Equal(pb, exp) { + t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp) + } +} + +func TestProto3TextParsing(t *testing.T) { + m := new(proto3pb.Message) + const in = `name: "Wallace" true_scotsman: true` + want := &proto3pb.Message{ + Name: "Wallace", + TrueScotsman: true, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + +func TestMapParsing(t *testing.T) { + m := new(MessageWithMap) + const in = `name_mapping: name_mapping:` + + `msg_mapping:,>` + // separating commas are okay + `msg_mapping>` + // no colon after "value" + `msg_mapping:>` + // omitted key + `msg_mapping:` + // omitted value + `byte_mapping:` + + `byte_mapping:<>` // omitted key and value + want := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Beatles", + 1234: "Feist", + }, + MsgMapping: map[int64]*FloatingPoint{ + -4: {F: Float64(2.0)}, + -2: {F: Float64(4.0)}, + 0: {F: Float64(5.0)}, + 1: nil, + }, + ByteMapping: map[bool][]byte{ + false: nil, + true: []byte("so be it"), + }, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + +func TestOneofParsing(t *testing.T) { + const in = `name:"Shrek"` + m := new(Communique) + want := &Communique{Union: &Communique_Name{Name: "Shrek"}} + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } + + const inOverwrite = `name:"Shrek" number:42` + m = new(Communique) + testErr := "line 1.13: field 'number' would overwrite already parsed oneof 'Union'" + if err := UnmarshalText(inOverwrite, m); err == nil { + t.Errorf("TestOneofParsing: Didn't get expected error: %v", testErr) + } else if err.Error() != testErr { + t.Errorf("TestOneofParsing: Incorrect error.\nHave: %v\nWant: %v", + err.Error(), testErr) + } + +} + +var benchInput string + +func init() { + benchInput = "count: 4\n" + for i := 0; i < 1000; i++ { + benchInput += "pet: \"fido\"\n" + } + + // Check it is valid input. + pb := new(MyMessage) + err := UnmarshalText(benchInput, pb) + if err != nil { + panic("Bad benchmark input: " + err.Error()) + } +} + +func BenchmarkUnmarshalText(b *testing.B) { + pb := new(MyMessage) + for i := 0; i < b.N; i++ { + UnmarshalText(benchInput, pb) + } + b.SetBytes(int64(len(benchInput))) +} diff --git a/vendor/github.com/gogo/protobuf/proto/text_test.go b/vendor/github.com/gogo/protobuf/proto/text_test.go new file mode 100644 index 000000000..27df6cb9b --- /dev/null +++ b/vendor/github.com/gogo/protobuf/proto/text_test.go @@ -0,0 +1,474 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "errors" + "io/ioutil" + "math" + "strings" + "testing" + + "github.com/gogo/protobuf/proto" + + proto3pb "github.com/gogo/protobuf/proto/proto3_proto" + pb "github.com/gogo/protobuf/proto/testdata" +) + +// textMessage implements the methods that allow it to marshal and unmarshal +// itself as text. +type textMessage struct { +} + +func (*textMessage) MarshalText() ([]byte, error) { + return []byte("custom"), nil +} + +func (*textMessage) UnmarshalText(bytes []byte) error { + if string(bytes) != "custom" { + return errors.New("expected 'custom'") + } + return nil +} + +func (*textMessage) Reset() {} +func (*textMessage) String() string { return "" } +func (*textMessage) ProtoMessage() {} + +func newTestMessage() *pb.MyMessage { + msg := &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + Quote: proto.String(`"I didn't want to go."`), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &pb.InnerMessage{ + Host: proto.String("footrest.syd"), + Port: proto.Int32(7001), + Connected: proto.Bool(true), + }, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(0xdeadbeef), + Value: []byte{1, 65, 7, 12}, + }, + { + Weight: proto.Float32(6.022), + Inner: &pb.InnerMessage{ + Host: proto.String("lesha.mtv"), + Port: proto.Int32(8002), + }, + }, + }, + Bikeshed: pb.MyMessage_BLUE.Enum(), + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(8), + }, + // One normally wouldn't do this. + // This is an undeclared tag 13, as a varint (wire type 0) with value 4. + XXX_unrecognized: []byte{13<<3 | 0, 4}, + } + ext := &pb.Ext{ + Data: proto.String("Big gobs for big rats"), + } + if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil { + panic(err) + } + greetings := []string{"adg", "easy", "cow"} + if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil { + panic(err) + } + + // Add an unknown extension. We marshal a pb.Ext, and fake the ID. + b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")}) + if err != nil { + panic(err) + } + b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...) + proto.SetRawExtension(msg, 201, b) + + // Extensions can be plain fields, too, so let's test that. + b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19) + proto.SetRawExtension(msg, 202, b) + + return msg +} + +const text = `count: 42 +name: "Dave" +quote: "\"I didn't want to go.\"" +pet: "bunny" +pet: "kitty" +pet: "horsey" +inner: < + host: "footrest.syd" + port: 7001 + connected: true +> +others: < + key: 3735928559 + value: "\001A\007\014" +> +others: < + weight: 6.022 + inner: < + host: "lesha.mtv" + port: 8002 + > +> +bikeshed: BLUE +SomeGroup { + group_field: 8 +} +/* 2 unknown bytes */ +13: 4 +[testdata.Ext.more]: < + data: "Big gobs for big rats" +> +[testdata.greeting]: "adg" +[testdata.greeting]: "easy" +[testdata.greeting]: "cow" +/* 13 unknown bytes */ +201: "\t3G skiing" +/* 3 unknown bytes */ +202: 19 +` + +func TestMarshalText(t *testing.T) { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, newTestMessage()); err != nil { + t.Fatalf("proto.MarshalText: %v", err) + } + s := buf.String() + if s != text { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text) + } +} + +func TestMarshalTextCustomMessage(t *testing.T) { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, &textMessage{}); err != nil { + t.Fatalf("proto.MarshalText: %v", err) + } + s := buf.String() + if s != "custom" { + t.Errorf("Got %q, expected %q", s, "custom") + } +} +func TestMarshalTextNil(t *testing.T) { + want := "" + tests := []proto.Message{nil, (*pb.MyMessage)(nil)} + for i, test := range tests { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, test); err != nil { + t.Fatal(err) + } + if got := buf.String(); got != want { + t.Errorf("%d: got %q want %q", i, got, want) + } + } +} + +func TestMarshalTextUnknownEnum(t *testing.T) { + // The Color enum only specifies values 0-2. + m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()} + got := m.String() + const want = `bikeshed:3 ` + if got != want { + t.Errorf("\n got %q\nwant %q", got, want) + } +} + +func TestTextOneof(t *testing.T) { + tests := []struct { + m proto.Message + want string + }{ + // zero message + {&pb.Communique{}, ``}, + // scalar field + {&pb.Communique{Union: &pb.Communique_Number{Number: 4}}, `number:4`}, + // message field + {&pb.Communique{Union: &pb.Communique_Msg{ + Msg: &pb.Strings{StringField: proto.String("why hello!")}, + }}, `msg:`}, + // bad oneof (should not panic) + {&pb.Communique{Union: &pb.Communique_Msg{Msg: nil}}, `msg:/* nil */`}, + } + for _, test := range tests { + got := strings.TrimSpace(test.m.String()) + if got != test.want { + t.Errorf("\n got %s\nwant %s", got, test.want) + } + } +} + +func BenchmarkMarshalTextBuffered(b *testing.B) { + buf := new(bytes.Buffer) + m := newTestMessage() + for i := 0; i < b.N; i++ { + buf.Reset() + proto.MarshalText(buf, m) + } +} + +func BenchmarkMarshalTextUnbuffered(b *testing.B) { + w := ioutil.Discard + m := newTestMessage() + for i := 0; i < b.N; i++ { + proto.MarshalText(w, m) + } +} + +func compact(src string) string { + // s/[ \n]+/ /g; s/ $//; + dst := make([]byte, len(src)) + space, comment := false, false + j := 0 + for i := 0; i < len(src); i++ { + if strings.HasPrefix(src[i:], "/*") { + comment = true + i++ + continue + } + if comment && strings.HasPrefix(src[i:], "*/") { + comment = false + i++ + continue + } + if comment { + continue + } + c := src[i] + if c == ' ' || c == '\n' { + space = true + continue + } + if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') { + space = false + } + if c == '{' { + space = false + } + if space { + dst[j] = ' ' + j++ + space = false + } + dst[j] = c + j++ + } + if space { + dst[j] = ' ' + j++ + } + return string(dst[0:j]) +} + +var compactText = compact(text) + +func TestCompactText(t *testing.T) { + s := proto.CompactTextString(newTestMessage()) + if s != compactText { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText) + } +} + +func TestStringEscaping(t *testing.T) { + testCases := []struct { + in *pb.Strings + out string + }{ + { + // Test data from C++ test (TextFormatTest.StringEscape). + // Single divergence: we don't escape apostrophes. + &pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")}, + "string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n", + }, + { + // Test data from the same C++ test. + &pb.Strings{StringField: proto.String("\350\260\267\346\255\214")}, + "string_field: \"\\350\\260\\267\\346\\255\\214\"\n", + }, + { + // Some UTF-8. + &pb.Strings{StringField: proto.String("\x00\x01\xff\x81")}, + `string_field: "\000\001\377\201"` + "\n", + }, + } + + for i, tc := range testCases { + var buf bytes.Buffer + if err := proto.MarshalText(&buf, tc.in); err != nil { + t.Errorf("proto.MarsalText: %v", err) + continue + } + s := buf.String() + if s != tc.out { + t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out) + continue + } + + // Check round-trip. + pbStrings := new(pb.Strings) + if err := proto.UnmarshalText(s, pbStrings); err != nil { + t.Errorf("#%d: UnmarshalText: %v", i, err) + continue + } + if !proto.Equal(pbStrings, tc.in) { + t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pbStrings) + } + } +} + +// A limitedWriter accepts some output before it fails. +// This is a proxy for something like a nearly-full or imminently-failing disk, +// or a network connection that is about to die. +type limitedWriter struct { + b bytes.Buffer + limit int +} + +var outOfSpace = errors.New("proto: insufficient space") + +func (w *limitedWriter) Write(p []byte) (n int, err error) { + var avail = w.limit - w.b.Len() + if avail <= 0 { + return 0, outOfSpace + } + if len(p) <= avail { + return w.b.Write(p) + } + n, _ = w.b.Write(p[:avail]) + return n, outOfSpace +} + +func TestMarshalTextFailing(t *testing.T) { + // Try lots of different sizes to exercise more error code-paths. + for lim := 0; lim < len(text); lim++ { + buf := new(limitedWriter) + buf.limit = lim + err := proto.MarshalText(buf, newTestMessage()) + // We expect a certain error, but also some partial results in the buffer. + if err != outOfSpace { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace) + } + s := buf.b.String() + x := text[:buf.limit] + if s != x { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x) + } + } +} + +func TestFloats(t *testing.T) { + tests := []struct { + f float64 + want string + }{ + {0, "0"}, + {4.7, "4.7"}, + {math.Inf(1), "inf"}, + {math.Inf(-1), "-inf"}, + {math.NaN(), "nan"}, + } + for _, test := range tests { + msg := &pb.FloatingPoint{F: &test.f} + got := strings.TrimSpace(msg.String()) + want := `f:` + test.want + if got != want { + t.Errorf("f=%f: got %q, want %q", test.f, got, want) + } + } +} + +func TestRepeatedNilText(t *testing.T) { + m := &pb.MessageList{ + Message: []*pb.MessageList_Message{ + nil, + { + Name: proto.String("Horse"), + }, + nil, + }, + } + want := `Message +Message { + name: "Horse" +} +Message +` + if s := proto.MarshalTextString(m); s != want { + t.Errorf(" got: %s\nwant: %s", s, want) + } +} + +func TestProto3Text(t *testing.T) { + tests := []struct { + m proto.Message + want string + }{ + // zero message + {&proto3pb.Message{}, ``}, + // zero message except for an empty byte slice + {&proto3pb.Message{Data: []byte{}}, ``}, + // trivial case + {&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`}, + // empty map + {&pb.MessageWithMap{}, ``}, + // non-empty map; map format is the same as a repeated struct, + // and they are sorted by key (numerically for numeric keys). + { + &pb.MessageWithMap{NameMapping: map[int32]string{ + -1: "Negatory", + 7: "Lucky", + 1234: "Feist", + 6345789: "Otis", + }}, + `name_mapping: ` + + `name_mapping: ` + + `name_mapping: ` + + `name_mapping:`, + }, + // map with nil value; not well-defined, but we shouldn't crash + { + &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{7: nil}}, + `msg_mapping:`, + }, + } + for _, test := range tests { + got := strings.TrimSpace(test.m.String()) + if got != test.want { + t.Errorf("\n got %s\nwant %s", got, test.want) + } + } +} diff --git a/vendor/github.com/golang/glog/README b/vendor/github.com/golang/glog/README new file mode 100644 index 000000000..5f9c11485 --- /dev/null +++ b/vendor/github.com/golang/glog/README @@ -0,0 +1,44 @@ +glog +==== + +Leveled execution logs for Go. + +This is an efficient pure Go implementation of leveled logs in the +manner of the open source C++ package + http://code.google.com/p/google-glog + +By binding methods to booleans it is possible to use the log package +without paying the expense of evaluating the arguments to the log. +Through the -vmodule flag, the package also provides fine-grained +control over logging at the file level. + +The comment from glog.go introduces the ideas: + + Package glog implements logging analogous to the Google-internal + C++ INFO/ERROR/V setup. It provides functions Info, Warning, + Error, Fatal, plus formatting variants such as Infof. It + also provides V-style logging controlled by the -v and + -vmodule=file=2 flags. + + Basic examples: + + glog.Info("Prepare to repel boarders") + + glog.Fatalf("Initialization failed: %s", err) + + See the documentation for the V function for an explanation + of these examples: + + if glog.V(2) { + glog.Info("Starting transaction...") + } + + glog.V(2).Infoln("Processed", nItems, "elements") + + +The repository contains an open source version of the log package +used inside Google. The master copy of the source lives inside +Google, not here. The code in this repo is for export only and is not itself +under development. Feature requests will be ignored. + +Send bug reports to golang-nuts@googlegroups.com. diff --git a/vendor/github.com/golang/glog/glog_test.go b/vendor/github.com/golang/glog/glog_test.go new file mode 100644 index 000000000..0fb376e1f --- /dev/null +++ b/vendor/github.com/golang/glog/glog_test.go @@ -0,0 +1,415 @@ +// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ +// +// Copyright 2013 Google Inc. All Rights Reserved. +// +// 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 glog + +import ( + "bytes" + "fmt" + stdLog "log" + "path/filepath" + "runtime" + "strconv" + "strings" + "testing" + "time" +) + +// Test that shortHostname works as advertised. +func TestShortHostname(t *testing.T) { + for hostname, expect := range map[string]string{ + "": "", + "host": "host", + "host.google.com": "host", + } { + if got := shortHostname(hostname); expect != got { + t.Errorf("shortHostname(%q): expected %q, got %q", hostname, expect, got) + } + } +} + +// flushBuffer wraps a bytes.Buffer to satisfy flushSyncWriter. +type flushBuffer struct { + bytes.Buffer +} + +func (f *flushBuffer) Flush() error { + return nil +} + +func (f *flushBuffer) Sync() error { + return nil +} + +// swap sets the log writers and returns the old array. +func (l *loggingT) swap(writers [numSeverity]flushSyncWriter) (old [numSeverity]flushSyncWriter) { + l.mu.Lock() + defer l.mu.Unlock() + old = l.file + for i, w := range writers { + logging.file[i] = w + } + return +} + +// newBuffers sets the log writers to all new byte buffers and returns the old array. +func (l *loggingT) newBuffers() [numSeverity]flushSyncWriter { + return l.swap([numSeverity]flushSyncWriter{new(flushBuffer), new(flushBuffer), new(flushBuffer), new(flushBuffer)}) +} + +// contents returns the specified log value as a string. +func contents(s severity) string { + return logging.file[s].(*flushBuffer).String() +} + +// contains reports whether the string is contained in the log. +func contains(s severity, str string, t *testing.T) bool { + return strings.Contains(contents(s), str) +} + +// setFlags configures the logging flags how the test expects them. +func setFlags() { + logging.toStderr = false +} + +// Test that Info works as advertised. +func TestInfo(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + Info("test") + if !contains(infoLog, "I", t) { + t.Errorf("Info has wrong character: %q", contents(infoLog)) + } + if !contains(infoLog, "test", t) { + t.Error("Info failed") + } +} + +func TestInfoDepth(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + + f := func() { InfoDepth(1, "depth-test1") } + + // The next three lines must stay together + _, _, wantLine, _ := runtime.Caller(0) + InfoDepth(0, "depth-test0") + f() + + msgs := strings.Split(strings.TrimSuffix(contents(infoLog), "\n"), "\n") + if len(msgs) != 2 { + t.Fatalf("Got %d lines, expected 2", len(msgs)) + } + + for i, m := range msgs { + if !strings.HasPrefix(m, "I") { + t.Errorf("InfoDepth[%d] has wrong character: %q", i, m) + } + w := fmt.Sprintf("depth-test%d", i) + if !strings.Contains(m, w) { + t.Errorf("InfoDepth[%d] missing %q: %q", i, w, m) + } + + // pull out the line number (between : and ]) + msg := m[strings.LastIndex(m, ":")+1:] + x := strings.Index(msg, "]") + if x < 0 { + t.Errorf("InfoDepth[%d]: missing ']': %q", i, m) + continue + } + line, err := strconv.Atoi(msg[:x]) + if err != nil { + t.Errorf("InfoDepth[%d]: bad line number: %q", i, m) + continue + } + wantLine++ + if wantLine != line { + t.Errorf("InfoDepth[%d]: got line %d, want %d", i, line, wantLine) + } + } +} + +func init() { + CopyStandardLogTo("INFO") +} + +// Test that CopyStandardLogTo panics on bad input. +func TestCopyStandardLogToPanic(t *testing.T) { + defer func() { + if s, ok := recover().(string); !ok || !strings.Contains(s, "LOG") { + t.Errorf(`CopyStandardLogTo("LOG") should have panicked: %v`, s) + } + }() + CopyStandardLogTo("LOG") +} + +// Test that using the standard log package logs to INFO. +func TestStandardLog(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + stdLog.Print("test") + if !contains(infoLog, "I", t) { + t.Errorf("Info has wrong character: %q", contents(infoLog)) + } + if !contains(infoLog, "test", t) { + t.Error("Info failed") + } +} + +// Test that the header has the correct format. +func TestHeader(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + defer func(previous func() time.Time) { timeNow = previous }(timeNow) + timeNow = func() time.Time { + return time.Date(2006, 1, 2, 15, 4, 5, .067890e9, time.Local) + } + pid = 1234 + Info("test") + var line int + format := "I0102 15:04:05.067890 1234 glog_test.go:%d] test\n" + n, err := fmt.Sscanf(contents(infoLog), format, &line) + if n != 1 || err != nil { + t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog)) + } + // Scanf treats multiple spaces as equivalent to a single space, + // so check for correct space-padding also. + want := fmt.Sprintf(format, line) + if contents(infoLog) != want { + t.Errorf("log format error: got:\n\t%q\nwant:\t%q", contents(infoLog), want) + } +} + +// Test that an Error log goes to Warning and Info. +// Even in the Info log, the source character will be E, so the data should +// all be identical. +func TestError(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + Error("test") + if !contains(errorLog, "E", t) { + t.Errorf("Error has wrong character: %q", contents(errorLog)) + } + if !contains(errorLog, "test", t) { + t.Error("Error failed") + } + str := contents(errorLog) + if !contains(warningLog, str, t) { + t.Error("Warning failed") + } + if !contains(infoLog, str, t) { + t.Error("Info failed") + } +} + +// Test that a Warning log goes to Info. +// Even in the Info log, the source character will be W, so the data should +// all be identical. +func TestWarning(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + Warning("test") + if !contains(warningLog, "W", t) { + t.Errorf("Warning has wrong character: %q", contents(warningLog)) + } + if !contains(warningLog, "test", t) { + t.Error("Warning failed") + } + str := contents(warningLog) + if !contains(infoLog, str, t) { + t.Error("Info failed") + } +} + +// Test that a V log goes to Info. +func TestV(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + logging.verbosity.Set("2") + defer logging.verbosity.Set("0") + V(2).Info("test") + if !contains(infoLog, "I", t) { + t.Errorf("Info has wrong character: %q", contents(infoLog)) + } + if !contains(infoLog, "test", t) { + t.Error("Info failed") + } +} + +// Test that a vmodule enables a log in this file. +func TestVmoduleOn(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + logging.vmodule.Set("glog_test=2") + defer logging.vmodule.Set("") + if !V(1) { + t.Error("V not enabled for 1") + } + if !V(2) { + t.Error("V not enabled for 2") + } + if V(3) { + t.Error("V enabled for 3") + } + V(2).Info("test") + if !contains(infoLog, "I", t) { + t.Errorf("Info has wrong character: %q", contents(infoLog)) + } + if !contains(infoLog, "test", t) { + t.Error("Info failed") + } +} + +// Test that a vmodule of another file does not enable a log in this file. +func TestVmoduleOff(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + logging.vmodule.Set("notthisfile=2") + defer logging.vmodule.Set("") + for i := 1; i <= 3; i++ { + if V(Level(i)) { + t.Errorf("V enabled for %d", i) + } + } + V(2).Info("test") + if contents(infoLog) != "" { + t.Error("V logged incorrectly") + } +} + +// vGlobs are patterns that match/don't match this file at V=2. +var vGlobs = map[string]bool{ + // Easy to test the numeric match here. + "glog_test=1": false, // If -vmodule sets V to 1, V(2) will fail. + "glog_test=2": true, + "glog_test=3": true, // If -vmodule sets V to 1, V(3) will succeed. + // These all use 2 and check the patterns. All are true. + "*=2": true, + "?l*=2": true, + "????_*=2": true, + "??[mno]?_*t=2": true, + // These all use 2 and check the patterns. All are false. + "*x=2": false, + "m*=2": false, + "??_*=2": false, + "?[abc]?_*t=2": false, +} + +// Test that vmodule globbing works as advertised. +func testVmoduleGlob(pat string, match bool, t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + defer logging.vmodule.Set("") + logging.vmodule.Set(pat) + if V(2) != Verbose(match) { + t.Errorf("incorrect match for %q: got %t expected %t", pat, V(2), match) + } +} + +// Test that a vmodule globbing works as advertised. +func TestVmoduleGlob(t *testing.T) { + for glob, match := range vGlobs { + testVmoduleGlob(glob, match, t) + } +} + +func TestRollover(t *testing.T) { + setFlags() + var err error + defer func(previous func(error)) { logExitFunc = previous }(logExitFunc) + logExitFunc = func(e error) { + err = e + } + defer func(previous uint64) { MaxSize = previous }(MaxSize) + MaxSize = 512 + + Info("x") // Be sure we have a file. + info, ok := logging.file[infoLog].(*syncBuffer) + if !ok { + t.Fatal("info wasn't created") + } + if err != nil { + t.Fatalf("info has initial error: %v", err) + } + fname0 := info.file.Name() + Info(strings.Repeat("x", int(MaxSize))) // force a rollover + if err != nil { + t.Fatalf("info has error after big write: %v", err) + } + + // Make sure the next log file gets a file name with a different + // time stamp. + // + // TODO: determine whether we need to support subsecond log + // rotation. C++ does not appear to handle this case (nor does it + // handle Daylight Savings Time properly). + time.Sleep(1 * time.Second) + + Info("x") // create a new file + if err != nil { + t.Fatalf("error after rotation: %v", err) + } + fname1 := info.file.Name() + if fname0 == fname1 { + t.Errorf("info.f.Name did not change: %v", fname0) + } + if info.nbytes >= MaxSize { + t.Errorf("file size was not reset: %d", info.nbytes) + } +} + +func TestLogBacktraceAt(t *testing.T) { + setFlags() + defer logging.swap(logging.newBuffers()) + // The peculiar style of this code simplifies line counting and maintenance of the + // tracing block below. + var infoLine string + setTraceLocation := func(file string, line int, ok bool, delta int) { + if !ok { + t.Fatal("could not get file:line") + } + _, file = filepath.Split(file) + infoLine = fmt.Sprintf("%s:%d", file, line+delta) + err := logging.traceLocation.Set(infoLine) + if err != nil { + t.Fatal("error setting log_backtrace_at: ", err) + } + } + { + // Start of tracing block. These lines know about each other's relative position. + _, file, line, ok := runtime.Caller(0) + setTraceLocation(file, line, ok, +2) // Two lines between Caller and Info calls. + Info("we want a stack trace here") + } + numAppearances := strings.Count(contents(infoLog), infoLine) + if numAppearances < 2 { + // Need 2 appearances, one in the log header and one in the trace: + // log_test.go:281: I0511 16:36:06.952398 02238 log_test.go:280] we want a stack trace here + // ... + // github.com/glog/glog_test.go:280 (0x41ba91) + // ... + // We could be more precise but that would require knowing the details + // of the traceback format, which may not be dependable. + t.Fatal("got no trace back; log is ", contents(infoLog)) + } +} + +func BenchmarkHeader(b *testing.B) { + for i := 0; i < b.N; i++ { + buf, _, _ := logging.header(infoLog, 0) + logging.putBuffer(buf) + } +} diff --git a/vendor/github.com/golang/groupcache/.gitignore b/vendor/github.com/golang/groupcache/.gitignore new file mode 100644 index 000000000..b25c15b81 --- /dev/null +++ b/vendor/github.com/golang/groupcache/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/vendor/github.com/golang/groupcache/.travis.yml b/vendor/github.com/golang/groupcache/.travis.yml new file mode 100644 index 000000000..ef6e67633 --- /dev/null +++ b/vendor/github.com/golang/groupcache/.travis.yml @@ -0,0 +1,18 @@ +language: go +go_import_path: github.com/golang/groupcache + +os: linux +dist: trusty +sudo: false + +script: + - go test ./... + +go: + - 1.9.x + - 1.10.x + - master + +cache: + directories: + - $GOPATH/pkg diff --git a/vendor/github.com/golang/groupcache/README.md b/vendor/github.com/golang/groupcache/README.md new file mode 100644 index 000000000..70c29da16 --- /dev/null +++ b/vendor/github.com/golang/groupcache/README.md @@ -0,0 +1,73 @@ +# groupcache + +## Summary + +groupcache is a caching and cache-filling library, intended as a +replacement for memcached in many cases. + +For API docs and examples, see http://godoc.org/github.com/golang/groupcache + +## Comparison to memcached + +### **Like memcached**, groupcache: + + * shards by key to select which peer is responsible for that key + +### **Unlike memcached**, groupcache: + + * does not require running a separate set of servers, thus massively + reducing deployment/configuration pain. groupcache is a client + library as well as a server. It connects to its own peers. + + * comes with a cache filling mechanism. Whereas memcached just says + "Sorry, cache miss", often resulting in a thundering herd of + database (or whatever) loads from an unbounded number of clients + (which has resulted in several fun outages), groupcache coordinates + cache fills such that only one load in one process of an entire + replicated set of processes populates the cache, then multiplexes + the loaded value to all callers. + + * does not support versioned values. If key "foo" is value "bar", + key "foo" must always be "bar". There are neither cache expiration + times, nor explicit cache evictions. Thus there is also no CAS, + nor Increment/Decrement. This also means that groupcache.... + + * ... supports automatic mirroring of super-hot items to multiple + processes. This prevents memcached hot spotting where a machine's + CPU and/or NIC are overloaded by very popular keys/values. + + * is currently only available for Go. It's very unlikely that I + (bradfitz@) will port the code to any other language. + +## Loading process + +In a nutshell, a groupcache lookup of **Get("foo")** looks like: + +(On machine #5 of a set of N machines running the same code) + + 1. Is the value of "foo" in local memory because it's super hot? If so, use it. + + 2. Is the value of "foo" in local memory because peer #5 (the current + peer) is the owner of it? If so, use it. + + 3. Amongst all the peers in my set of N, am I the owner of the key + "foo"? (e.g. does it consistent hash to 5?) If so, load it. If + other callers come in, via the same process or via RPC requests + from peers, they block waiting for the load to finish and get the + same answer. If not, RPC to the peer that's the owner and get + the answer. If the RPC fails, just load it locally (still with + local dup suppression). + +## Users + +groupcache is in production use by dl.google.com (its original user), +parts of Blogger, parts of Google Code, parts of Google Fiber, parts +of Google production monitoring systems, etc. + +## Presentations + +See http://talks.golang.org/2013/oscon-dl.slide + +## Help + +Use the golang-nuts mailing list for any discussion or questions. diff --git a/vendor/github.com/golang/groupcache/byteview.go b/vendor/github.com/golang/groupcache/byteview.go new file mode 100644 index 000000000..a2c2c493d --- /dev/null +++ b/vendor/github.com/golang/groupcache/byteview.go @@ -0,0 +1,175 @@ +/* +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 groupcache + +import ( + "bytes" + "errors" + "io" + "strings" +) + +// A ByteView holds an immutable view of bytes. +// Internally it wraps either a []byte or a string, +// but that detail is invisible to callers. +// +// A ByteView is meant to be used as a value type, not +// a pointer (like a time.Time). +type ByteView struct { + // If b is non-nil, b is used, else s is used. + b []byte + s string +} + +// Len returns the view's length. +func (v ByteView) Len() int { + if v.b != nil { + return len(v.b) + } + return len(v.s) +} + +// ByteSlice returns a copy of the data as a byte slice. +func (v ByteView) ByteSlice() []byte { + if v.b != nil { + return cloneBytes(v.b) + } + return []byte(v.s) +} + +// String returns the data as a string, making a copy if necessary. +func (v ByteView) String() string { + if v.b != nil { + return string(v.b) + } + return v.s +} + +// At returns the byte at index i. +func (v ByteView) At(i int) byte { + if v.b != nil { + return v.b[i] + } + return v.s[i] +} + +// Slice slices the view between the provided from and to indices. +func (v ByteView) Slice(from, to int) ByteView { + if v.b != nil { + return ByteView{b: v.b[from:to]} + } + return ByteView{s: v.s[from:to]} +} + +// SliceFrom slices the view from the provided index until the end. +func (v ByteView) SliceFrom(from int) ByteView { + if v.b != nil { + return ByteView{b: v.b[from:]} + } + return ByteView{s: v.s[from:]} +} + +// Copy copies b into dest and returns the number of bytes copied. +func (v ByteView) Copy(dest []byte) int { + if v.b != nil { + return copy(dest, v.b) + } + return copy(dest, v.s) +} + +// Equal returns whether the bytes in b are the same as the bytes in +// b2. +func (v ByteView) Equal(b2 ByteView) bool { + if b2.b == nil { + return v.EqualString(b2.s) + } + return v.EqualBytes(b2.b) +} + +// EqualString returns whether the bytes in b are the same as the bytes +// in s. +func (v ByteView) EqualString(s string) bool { + if v.b == nil { + return v.s == s + } + l := v.Len() + if len(s) != l { + return false + } + for i, bi := range v.b { + if bi != s[i] { + return false + } + } + return true +} + +// EqualBytes returns whether the bytes in b are the same as the bytes +// in b2. +func (v ByteView) EqualBytes(b2 []byte) bool { + if v.b != nil { + return bytes.Equal(v.b, b2) + } + l := v.Len() + if len(b2) != l { + return false + } + for i, bi := range b2 { + if bi != v.s[i] { + return false + } + } + return true +} + +// Reader returns an io.ReadSeeker for the bytes in v. +func (v ByteView) Reader() io.ReadSeeker { + if v.b != nil { + return bytes.NewReader(v.b) + } + return strings.NewReader(v.s) +} + +// ReadAt implements io.ReaderAt on the bytes in v. +func (v ByteView) ReadAt(p []byte, off int64) (n int, err error) { + if off < 0 { + return 0, errors.New("view: invalid offset") + } + if off >= int64(v.Len()) { + return 0, io.EOF + } + n = v.SliceFrom(int(off)).Copy(p) + if n < len(p) { + err = io.EOF + } + return +} + +// WriteTo implements io.WriterTo on the bytes in v. +func (v ByteView) WriteTo(w io.Writer) (n int64, err error) { + var m int + if v.b != nil { + m, err = w.Write(v.b) + } else { + m, err = io.WriteString(w, v.s) + } + if err == nil && m < v.Len() { + err = io.ErrShortWrite + } + n = int64(m) + return +} diff --git a/vendor/github.com/golang/groupcache/byteview_test.go b/vendor/github.com/golang/groupcache/byteview_test.go new file mode 100644 index 000000000..a09757aa8 --- /dev/null +++ b/vendor/github.com/golang/groupcache/byteview_test.go @@ -0,0 +1,147 @@ +/* +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 groupcache + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "testing" +) + +func TestByteView(t *testing.T) { + for _, s := range []string{"", "x", "yy"} { + for _, v := range []ByteView{of([]byte(s)), of(s)} { + name := fmt.Sprintf("string %q, view %+v", s, v) + if v.Len() != len(s) { + t.Errorf("%s: Len = %d; want %d", name, v.Len(), len(s)) + } + if v.String() != s { + t.Errorf("%s: String = %q; want %q", name, v.String(), s) + } + var longDest [3]byte + if n := v.Copy(longDest[:]); n != len(s) { + t.Errorf("%s: long Copy = %d; want %d", name, n, len(s)) + } + var shortDest [1]byte + if n := v.Copy(shortDest[:]); n != min(len(s), 1) { + t.Errorf("%s: short Copy = %d; want %d", name, n, min(len(s), 1)) + } + if got, err := ioutil.ReadAll(v.Reader()); err != nil || string(got) != s { + t.Errorf("%s: Reader = %q, %v; want %q", name, got, err, s) + } + if got, err := ioutil.ReadAll(io.NewSectionReader(v, 0, int64(len(s)))); err != nil || string(got) != s { + t.Errorf("%s: SectionReader of ReaderAt = %q, %v; want %q", name, got, err, s) + } + var dest bytes.Buffer + if _, err := v.WriteTo(&dest); err != nil || !bytes.Equal(dest.Bytes(), []byte(s)) { + t.Errorf("%s: WriteTo = %q, %v; want %q", name, dest.Bytes(), err, s) + } + } + } +} + +// of returns a byte view of the []byte or string in x. +func of(x interface{}) ByteView { + if bytes, ok := x.([]byte); ok { + return ByteView{b: bytes} + } + return ByteView{s: x.(string)} +} + +func TestByteViewEqual(t *testing.T) { + tests := []struct { + a interface{} // string or []byte + b interface{} // string or []byte + want bool + }{ + {"x", "x", true}, + {"x", "y", false}, + {"x", "yy", false}, + {[]byte("x"), []byte("x"), true}, + {[]byte("x"), []byte("y"), false}, + {[]byte("x"), []byte("yy"), false}, + {[]byte("x"), "x", true}, + {[]byte("x"), "y", false}, + {[]byte("x"), "yy", false}, + {"x", []byte("x"), true}, + {"x", []byte("y"), false}, + {"x", []byte("yy"), false}, + } + for i, tt := range tests { + va := of(tt.a) + if bytes, ok := tt.b.([]byte); ok { + if got := va.EqualBytes(bytes); got != tt.want { + t.Errorf("%d. EqualBytes = %v; want %v", i, got, tt.want) + } + } else { + if got := va.EqualString(tt.b.(string)); got != tt.want { + t.Errorf("%d. EqualString = %v; want %v", i, got, tt.want) + } + } + if got := va.Equal(of(tt.b)); got != tt.want { + t.Errorf("%d. Equal = %v; want %v", i, got, tt.want) + } + } +} + +func TestByteViewSlice(t *testing.T) { + tests := []struct { + in string + from int + to interface{} // nil to mean the end (SliceFrom); else int + want string + }{ + { + in: "abc", + from: 1, + to: 2, + want: "b", + }, + { + in: "abc", + from: 1, + want: "bc", + }, + { + in: "abc", + to: 2, + want: "ab", + }, + } + for i, tt := range tests { + for _, v := range []ByteView{of([]byte(tt.in)), of(tt.in)} { + name := fmt.Sprintf("test %d, view %+v", i, v) + if tt.to != nil { + v = v.Slice(tt.from, tt.to.(int)) + } else { + v = v.SliceFrom(tt.from) + } + if v.String() != tt.want { + t.Errorf("%s: got %q; want %q", name, v.String(), tt.want) + } + } + } +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/golang/groupcache/groupcache.go b/vendor/github.com/golang/groupcache/groupcache.go new file mode 100644 index 000000000..316ca4940 --- /dev/null +++ b/vendor/github.com/golang/groupcache/groupcache.go @@ -0,0 +1,491 @@ +/* +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 groupcache provides a data loading mechanism with caching +// and de-duplication that works across a set of peer processes. +// +// Each data Get first consults its local cache, otherwise delegates +// to the requested key's canonical owner, which then checks its cache +// or finally gets the data. In the common case, many concurrent +// cache misses across a set of peers for the same key result in just +// one cache fill. +package groupcache + +import ( + "errors" + "math/rand" + "strconv" + "sync" + "sync/atomic" + + pb "github.com/golang/groupcache/groupcachepb" + "github.com/golang/groupcache/lru" + "github.com/golang/groupcache/singleflight" +) + +// A Getter loads data for a key. +type Getter interface { + // Get returns the value identified by key, populating dest. + // + // The returned data must be unversioned. That is, key must + // uniquely describe the loaded data, without an implicit + // current time, and without relying on cache expiration + // mechanisms. + Get(ctx Context, key string, dest Sink) error +} + +// A GetterFunc implements Getter with a function. +type GetterFunc func(ctx Context, key string, dest Sink) error + +func (f GetterFunc) Get(ctx Context, key string, dest Sink) error { + return f(ctx, key, dest) +} + +var ( + mu sync.RWMutex + groups = make(map[string]*Group) + + initPeerServerOnce sync.Once + initPeerServer func() +) + +// GetGroup returns the named group previously created with NewGroup, or +// nil if there's no such group. +func GetGroup(name string) *Group { + mu.RLock() + g := groups[name] + mu.RUnlock() + return g +} + +// NewGroup creates a coordinated group-aware Getter from a Getter. +// +// The returned Getter tries (but does not guarantee) to run only one +// Get call at once for a given key across an entire set of peer +// processes. Concurrent callers both in the local process and in +// other processes receive copies of the answer once the original Get +// completes. +// +// The group name must be unique for each getter. +func NewGroup(name string, cacheBytes int64, getter Getter) *Group { + return newGroup(name, cacheBytes, getter, nil) +} + +// If peers is nil, the peerPicker is called via a sync.Once to initialize it. +func newGroup(name string, cacheBytes int64, getter Getter, peers PeerPicker) *Group { + if getter == nil { + panic("nil Getter") + } + mu.Lock() + defer mu.Unlock() + initPeerServerOnce.Do(callInitPeerServer) + if _, dup := groups[name]; dup { + panic("duplicate registration of group " + name) + } + g := &Group{ + name: name, + getter: getter, + peers: peers, + cacheBytes: cacheBytes, + loadGroup: &singleflight.Group{}, + } + if fn := newGroupHook; fn != nil { + fn(g) + } + groups[name] = g + return g +} + +// newGroupHook, if non-nil, is called right after a new group is created. +var newGroupHook func(*Group) + +// RegisterNewGroupHook registers a hook that is run each time +// a group is created. +func RegisterNewGroupHook(fn func(*Group)) { + if newGroupHook != nil { + panic("RegisterNewGroupHook called more than once") + } + newGroupHook = fn +} + +// RegisterServerStart registers a hook that is run when the first +// group is created. +func RegisterServerStart(fn func()) { + if initPeerServer != nil { + panic("RegisterServerStart called more than once") + } + initPeerServer = fn +} + +func callInitPeerServer() { + if initPeerServer != nil { + initPeerServer() + } +} + +// A Group is a cache namespace and associated data loaded spread over +// a group of 1 or more machines. +type Group struct { + name string + getter Getter + peersOnce sync.Once + peers PeerPicker + cacheBytes int64 // limit for sum of mainCache and hotCache size + + // mainCache is a cache of the keys for which this process + // (amongst its peers) is authoritative. That is, this cache + // contains keys which consistent hash on to this process's + // peer number. + mainCache cache + + // hotCache contains keys/values for which this peer is not + // authoritative (otherwise they would be in mainCache), but + // are popular enough to warrant mirroring in this process to + // avoid going over the network to fetch from a peer. Having + // a hotCache avoids network hotspotting, where a peer's + // network card could become the bottleneck on a popular key. + // This cache is used sparingly to maximize the total number + // of key/value pairs that can be stored globally. + hotCache cache + + // loadGroup ensures that each key is only fetched once + // (either locally or remotely), regardless of the number of + // concurrent callers. + loadGroup flightGroup + + _ int32 // force Stats to be 8-byte aligned on 32-bit platforms + + // Stats are statistics on the group. + Stats Stats +} + +// flightGroup is defined as an interface which flightgroup.Group +// satisfies. We define this so that we may test with an alternate +// implementation. +type flightGroup interface { + // Done is called when Do is done. + Do(key string, fn func() (interface{}, error)) (interface{}, error) +} + +// Stats are per-group statistics. +type Stats struct { + Gets AtomicInt // any Get request, including from peers + CacheHits AtomicInt // either cache was good + PeerLoads AtomicInt // either remote load or remote cache hit (not an error) + PeerErrors AtomicInt + Loads AtomicInt // (gets - cacheHits) + LoadsDeduped AtomicInt // after singleflight + LocalLoads AtomicInt // total good local loads + LocalLoadErrs AtomicInt // total bad local loads + ServerRequests AtomicInt // gets that came over the network from peers +} + +// Name returns the name of the group. +func (g *Group) Name() string { + return g.name +} + +func (g *Group) initPeers() { + if g.peers == nil { + g.peers = getPeers(g.name) + } +} + +func (g *Group) Get(ctx Context, key string, dest Sink) error { + g.peersOnce.Do(g.initPeers) + g.Stats.Gets.Add(1) + if dest == nil { + return errors.New("groupcache: nil dest Sink") + } + value, cacheHit := g.lookupCache(key) + + if cacheHit { + g.Stats.CacheHits.Add(1) + return setSinkView(dest, value) + } + + // Optimization to avoid double unmarshalling or copying: keep + // track of whether the dest was already populated. One caller + // (if local) will set this; the losers will not. The common + // case will likely be one caller. + destPopulated := false + value, destPopulated, err := g.load(ctx, key, dest) + if err != nil { + return err + } + if destPopulated { + return nil + } + return setSinkView(dest, value) +} + +// load loads key either by invoking the getter locally or by sending it to another machine. +func (g *Group) load(ctx Context, key string, dest Sink) (value ByteView, destPopulated bool, err error) { + g.Stats.Loads.Add(1) + viewi, err := g.loadGroup.Do(key, func() (interface{}, error) { + // Check the cache again because singleflight can only dedup calls + // that overlap concurrently. It's possible for 2 concurrent + // requests to miss the cache, resulting in 2 load() calls. An + // unfortunate goroutine scheduling would result in this callback + // being run twice, serially. If we don't check the cache again, + // cache.nbytes would be incremented below even though there will + // be only one entry for this key. + // + // Consider the following serialized event ordering for two + // goroutines in which this callback gets called twice for hte + // same key: + // 1: Get("key") + // 2: Get("key") + // 1: lookupCache("key") + // 2: lookupCache("key") + // 1: load("key") + // 2: load("key") + // 1: loadGroup.Do("key", fn) + // 1: fn() + // 2: loadGroup.Do("key", fn) + // 2: fn() + if value, cacheHit := g.lookupCache(key); cacheHit { + g.Stats.CacheHits.Add(1) + return value, nil + } + g.Stats.LoadsDeduped.Add(1) + var value ByteView + var err error + if peer, ok := g.peers.PickPeer(key); ok { + value, err = g.getFromPeer(ctx, peer, key) + if err == nil { + g.Stats.PeerLoads.Add(1) + return value, nil + } + g.Stats.PeerErrors.Add(1) + // TODO(bradfitz): log the peer's error? keep + // log of the past few for /groupcachez? It's + // probably boring (normal task movement), so not + // worth logging I imagine. + } + value, err = g.getLocally(ctx, key, dest) + if err != nil { + g.Stats.LocalLoadErrs.Add(1) + return nil, err + } + g.Stats.LocalLoads.Add(1) + destPopulated = true // only one caller of load gets this return value + g.populateCache(key, value, &g.mainCache) + return value, nil + }) + if err == nil { + value = viewi.(ByteView) + } + return +} + +func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) { + err := g.getter.Get(ctx, key, dest) + if err != nil { + return ByteView{}, err + } + return dest.view() +} + +func (g *Group) getFromPeer(ctx Context, peer ProtoGetter, key string) (ByteView, error) { + req := &pb.GetRequest{ + Group: &g.name, + Key: &key, + } + res := &pb.GetResponse{} + err := peer.Get(ctx, req, res) + if err != nil { + return ByteView{}, err + } + value := ByteView{b: res.Value} + // TODO(bradfitz): use res.MinuteQps or something smart to + // conditionally populate hotCache. For now just do it some + // percentage of the time. + if rand.Intn(10) == 0 { + g.populateCache(key, value, &g.hotCache) + } + return value, nil +} + +func (g *Group) lookupCache(key string) (value ByteView, ok bool) { + if g.cacheBytes <= 0 { + return + } + value, ok = g.mainCache.get(key) + if ok { + return + } + value, ok = g.hotCache.get(key) + return +} + +func (g *Group) populateCache(key string, value ByteView, cache *cache) { + if g.cacheBytes <= 0 { + return + } + cache.add(key, value) + + // Evict items from cache(s) if necessary. + for { + mainBytes := g.mainCache.bytes() + hotBytes := g.hotCache.bytes() + if mainBytes+hotBytes <= g.cacheBytes { + return + } + + // TODO(bradfitz): this is good-enough-for-now logic. + // It should be something based on measurements and/or + // respecting the costs of different resources. + victim := &g.mainCache + if hotBytes > mainBytes/8 { + victim = &g.hotCache + } + victim.removeOldest() + } +} + +// CacheType represents a type of cache. +type CacheType int + +const ( + // The MainCache is the cache for items that this peer is the + // owner for. + MainCache CacheType = iota + 1 + + // The HotCache is the cache for items that seem popular + // enough to replicate to this node, even though it's not the + // owner. + HotCache +) + +// CacheStats returns stats about the provided cache within the group. +func (g *Group) CacheStats(which CacheType) CacheStats { + switch which { + case MainCache: + return g.mainCache.stats() + case HotCache: + return g.hotCache.stats() + default: + return CacheStats{} + } +} + +// cache is a wrapper around an *lru.Cache that adds synchronization, +// makes values always be ByteView, and counts the size of all keys and +// values. +type cache struct { + mu sync.RWMutex + nbytes int64 // of all keys and values + lru *lru.Cache + nhit, nget int64 + nevict int64 // number of evictions +} + +func (c *cache) stats() CacheStats { + c.mu.RLock() + defer c.mu.RUnlock() + return CacheStats{ + Bytes: c.nbytes, + Items: c.itemsLocked(), + Gets: c.nget, + Hits: c.nhit, + Evictions: c.nevict, + } +} + +func (c *cache) add(key string, value ByteView) { + c.mu.Lock() + defer c.mu.Unlock() + if c.lru == nil { + c.lru = &lru.Cache{ + OnEvicted: func(key lru.Key, value interface{}) { + val := value.(ByteView) + c.nbytes -= int64(len(key.(string))) + int64(val.Len()) + c.nevict++ + }, + } + } + c.lru.Add(key, value) + c.nbytes += int64(len(key)) + int64(value.Len()) +} + +func (c *cache) get(key string) (value ByteView, ok bool) { + c.mu.Lock() + defer c.mu.Unlock() + c.nget++ + if c.lru == nil { + return + } + vi, ok := c.lru.Get(key) + if !ok { + return + } + c.nhit++ + return vi.(ByteView), true +} + +func (c *cache) removeOldest() { + c.mu.Lock() + defer c.mu.Unlock() + if c.lru != nil { + c.lru.RemoveOldest() + } +} + +func (c *cache) bytes() int64 { + c.mu.RLock() + defer c.mu.RUnlock() + return c.nbytes +} + +func (c *cache) items() int64 { + c.mu.RLock() + defer c.mu.RUnlock() + return c.itemsLocked() +} + +func (c *cache) itemsLocked() int64 { + if c.lru == nil { + return 0 + } + return int64(c.lru.Len()) +} + +// An AtomicInt is an int64 to be accessed atomically. +type AtomicInt int64 + +// Add atomically adds n to i. +func (i *AtomicInt) Add(n int64) { + atomic.AddInt64((*int64)(i), n) +} + +// Get atomically gets the value of i. +func (i *AtomicInt) Get() int64 { + return atomic.LoadInt64((*int64)(i)) +} + +func (i *AtomicInt) String() string { + return strconv.FormatInt(i.Get(), 10) +} + +// CacheStats are returned by stats accessors on Group. +type CacheStats struct { + Bytes int64 + Items int64 + Gets int64 + Hits int64 + Evictions int64 +} diff --git a/vendor/github.com/golang/groupcache/groupcache_test.go b/vendor/github.com/golang/groupcache/groupcache_test.go new file mode 100644 index 000000000..ea05cac4a --- /dev/null +++ b/vendor/github.com/golang/groupcache/groupcache_test.go @@ -0,0 +1,456 @@ +/* +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. +*/ + +// Tests for groupcache. + +package groupcache + +import ( + "errors" + "fmt" + "hash/crc32" + "math/rand" + "reflect" + "sync" + "testing" + "time" + "unsafe" + + "github.com/golang/protobuf/proto" + + pb "github.com/golang/groupcache/groupcachepb" + testpb "github.com/golang/groupcache/testpb" +) + +var ( + once sync.Once + stringGroup, protoGroup Getter + + stringc = make(chan string) + + dummyCtx Context + + // cacheFills is the number of times stringGroup or + // protoGroup's Getter have been called. Read using the + // cacheFills function. + cacheFills AtomicInt +) + +const ( + stringGroupName = "string-group" + protoGroupName = "proto-group" + testMessageType = "google3/net/groupcache/go/test_proto.TestMessage" + fromChan = "from-chan" + cacheSize = 1 << 20 +) + +func testSetup() { + stringGroup = NewGroup(stringGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error { + if key == fromChan { + key = <-stringc + } + cacheFills.Add(1) + return dest.SetString("ECHO:" + key) + })) + + protoGroup = NewGroup(protoGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error { + if key == fromChan { + key = <-stringc + } + cacheFills.Add(1) + return dest.SetProto(&testpb.TestMessage{ + Name: proto.String("ECHO:" + key), + City: proto.String("SOME-CITY"), + }) + })) +} + +// tests that a Getter's Get method is only called once with two +// outstanding callers. This is the string variant. +func TestGetDupSuppressString(t *testing.T) { + once.Do(testSetup) + // Start two getters. The first should block (waiting reading + // from stringc) and the second should latch on to the first + // one. + resc := make(chan string, 2) + for i := 0; i < 2; i++ { + go func() { + var s string + if err := stringGroup.Get(dummyCtx, fromChan, StringSink(&s)); err != nil { + resc <- "ERROR:" + err.Error() + return + } + resc <- s + }() + } + + // Wait a bit so both goroutines get merged together via + // singleflight. + // TODO(bradfitz): decide whether there are any non-offensive + // debug/test hooks that could be added to singleflight to + // make a sleep here unnecessary. + time.Sleep(250 * time.Millisecond) + + // Unblock the first getter, which should unblock the second + // as well. + stringc <- "foo" + + for i := 0; i < 2; i++ { + select { + case v := <-resc: + if v != "ECHO:foo" { + t.Errorf("got %q; want %q", v, "ECHO:foo") + } + case <-time.After(5 * time.Second): + t.Errorf("timeout waiting on getter #%d of 2", i+1) + } + } +} + +// tests that a Getter's Get method is only called once with two +// outstanding callers. This is the proto variant. +func TestGetDupSuppressProto(t *testing.T) { + once.Do(testSetup) + // Start two getters. The first should block (waiting reading + // from stringc) and the second should latch on to the first + // one. + resc := make(chan *testpb.TestMessage, 2) + for i := 0; i < 2; i++ { + go func() { + tm := new(testpb.TestMessage) + if err := protoGroup.Get(dummyCtx, fromChan, ProtoSink(tm)); err != nil { + tm.Name = proto.String("ERROR:" + err.Error()) + } + resc <- tm + }() + } + + // Wait a bit so both goroutines get merged together via + // singleflight. + // TODO(bradfitz): decide whether there are any non-offensive + // debug/test hooks that could be added to singleflight to + // make a sleep here unnecessary. + time.Sleep(250 * time.Millisecond) + + // Unblock the first getter, which should unblock the second + // as well. + stringc <- "Fluffy" + want := &testpb.TestMessage{ + Name: proto.String("ECHO:Fluffy"), + City: proto.String("SOME-CITY"), + } + for i := 0; i < 2; i++ { + select { + case v := <-resc: + if !reflect.DeepEqual(v, want) { + t.Errorf(" Got: %v\nWant: %v", proto.CompactTextString(v), proto.CompactTextString(want)) + } + case <-time.After(5 * time.Second): + t.Errorf("timeout waiting on getter #%d of 2", i+1) + } + } +} + +func countFills(f func()) int64 { + fills0 := cacheFills.Get() + f() + return cacheFills.Get() - fills0 +} + +func TestCaching(t *testing.T) { + once.Do(testSetup) + fills := countFills(func() { + for i := 0; i < 10; i++ { + var s string + if err := stringGroup.Get(dummyCtx, "TestCaching-key", StringSink(&s)); err != nil { + t.Fatal(err) + } + } + }) + if fills != 1 { + t.Errorf("expected 1 cache fill; got %d", fills) + } +} + +func TestCacheEviction(t *testing.T) { + once.Do(testSetup) + testKey := "TestCacheEviction-key" + getTestKey := func() { + var res string + for i := 0; i < 10; i++ { + if err := stringGroup.Get(dummyCtx, testKey, StringSink(&res)); err != nil { + t.Fatal(err) + } + } + } + fills := countFills(getTestKey) + if fills != 1 { + t.Fatalf("expected 1 cache fill; got %d", fills) + } + + g := stringGroup.(*Group) + evict0 := g.mainCache.nevict + + // Trash the cache with other keys. + var bytesFlooded int64 + // cacheSize/len(testKey) is approximate + for bytesFlooded < cacheSize+1024 { + var res string + key := fmt.Sprintf("dummy-key-%d", bytesFlooded) + stringGroup.Get(dummyCtx, key, StringSink(&res)) + bytesFlooded += int64(len(key) + len(res)) + } + evicts := g.mainCache.nevict - evict0 + if evicts <= 0 { + t.Errorf("evicts = %v; want more than 0", evicts) + } + + // Test that the key is gone. + fills = countFills(getTestKey) + if fills != 1 { + t.Fatalf("expected 1 cache fill after cache trashing; got %d", fills) + } +} + +type fakePeer struct { + hits int + fail bool +} + +func (p *fakePeer) Get(_ Context, in *pb.GetRequest, out *pb.GetResponse) error { + p.hits++ + if p.fail { + return errors.New("simulated error from peer") + } + out.Value = []byte("got:" + in.GetKey()) + return nil +} + +type fakePeers []ProtoGetter + +func (p fakePeers) PickPeer(key string) (peer ProtoGetter, ok bool) { + if len(p) == 0 { + return + } + n := crc32.Checksum([]byte(key), crc32.IEEETable) % uint32(len(p)) + return p[n], p[n] != nil +} + +// tests that peers (virtual, in-process) are hit, and how much. +func TestPeers(t *testing.T) { + once.Do(testSetup) + rand.Seed(123) + peer0 := &fakePeer{} + peer1 := &fakePeer{} + peer2 := &fakePeer{} + peerList := fakePeers([]ProtoGetter{peer0, peer1, peer2, nil}) + const cacheSize = 0 // disabled + localHits := 0 + getter := func(_ Context, key string, dest Sink) error { + localHits++ + return dest.SetString("got:" + key) + } + testGroup := newGroup("TestPeers-group", cacheSize, GetterFunc(getter), peerList) + run := func(name string, n int, wantSummary string) { + // Reset counters + localHits = 0 + for _, p := range []*fakePeer{peer0, peer1, peer2} { + p.hits = 0 + } + + for i := 0; i < n; i++ { + key := fmt.Sprintf("key-%d", i) + want := "got:" + key + var got string + err := testGroup.Get(dummyCtx, key, StringSink(&got)) + if err != nil { + t.Errorf("%s: error on key %q: %v", name, key, err) + continue + } + if got != want { + t.Errorf("%s: for key %q, got %q; want %q", name, key, got, want) + } + } + summary := func() string { + return fmt.Sprintf("localHits = %d, peers = %d %d %d", localHits, peer0.hits, peer1.hits, peer2.hits) + } + if got := summary(); got != wantSummary { + t.Errorf("%s: got %q; want %q", name, got, wantSummary) + } + } + resetCacheSize := func(maxBytes int64) { + g := testGroup + g.cacheBytes = maxBytes + g.mainCache = cache{} + g.hotCache = cache{} + } + + // Base case; peers all up, with no problems. + resetCacheSize(1 << 20) + run("base", 200, "localHits = 49, peers = 51 49 51") + + // Verify cache was hit. All localHits are gone, and some of + // the peer hits (the ones randomly selected to be maybe hot) + run("cached_base", 200, "localHits = 0, peers = 49 47 48") + resetCacheSize(0) + + // With one of the peers being down. + // TODO(bradfitz): on a peer number being unavailable, the + // consistent hashing should maybe keep trying others to + // spread the load out. Currently it fails back to local + // execution if the first consistent-hash slot is unavailable. + peerList[0] = nil + run("one_peer_down", 200, "localHits = 100, peers = 0 49 51") + + // Failing peer + peerList[0] = peer0 + peer0.fail = true + run("peer0_failing", 200, "localHits = 100, peers = 51 49 51") +} + +func TestTruncatingByteSliceTarget(t *testing.T) { + var buf [100]byte + s := buf[:] + if err := stringGroup.Get(dummyCtx, "short", TruncatingByteSliceSink(&s)); err != nil { + t.Fatal(err) + } + if want := "ECHO:short"; string(s) != want { + t.Errorf("short key got %q; want %q", s, want) + } + + s = buf[:6] + if err := stringGroup.Get(dummyCtx, "truncated", TruncatingByteSliceSink(&s)); err != nil { + t.Fatal(err) + } + if want := "ECHO:t"; string(s) != want { + t.Errorf("truncated key got %q; want %q", s, want) + } +} + +func TestAllocatingByteSliceTarget(t *testing.T) { + var dst []byte + sink := AllocatingByteSliceSink(&dst) + + inBytes := []byte("some bytes") + sink.SetBytes(inBytes) + if want := "some bytes"; string(dst) != want { + t.Errorf("SetBytes resulted in %q; want %q", dst, want) + } + v, err := sink.view() + if err != nil { + t.Fatalf("view after SetBytes failed: %v", err) + } + if &inBytes[0] == &dst[0] { + t.Error("inBytes and dst share memory") + } + if &inBytes[0] == &v.b[0] { + t.Error("inBytes and view share memory") + } + if &dst[0] == &v.b[0] { + t.Error("dst and view share memory") + } +} + +// orderedFlightGroup allows the caller to force the schedule of when +// orig.Do will be called. This is useful to serialize calls such +// that singleflight cannot dedup them. +type orderedFlightGroup struct { + mu sync.Mutex + stage1 chan bool + stage2 chan bool + orig flightGroup +} + +func (g *orderedFlightGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) { + <-g.stage1 + <-g.stage2 + g.mu.Lock() + defer g.mu.Unlock() + return g.orig.Do(key, fn) +} + +// TestNoDedup tests invariants on the cache size when singleflight is +// unable to dedup calls. +func TestNoDedup(t *testing.T) { + const testkey = "testkey" + const testval = "testval" + g := newGroup("testgroup", 1024, GetterFunc(func(_ Context, key string, dest Sink) error { + return dest.SetString(testval) + }), nil) + + orderedGroup := &orderedFlightGroup{ + stage1: make(chan bool), + stage2: make(chan bool), + orig: g.loadGroup, + } + // Replace loadGroup with our wrapper so we can control when + // loadGroup.Do is entered for each concurrent request. + g.loadGroup = orderedGroup + + // Issue two idential requests concurrently. Since the cache is + // empty, it will miss. Both will enter load(), but we will only + // allow one at a time to enter singleflight.Do, so the callback + // function will be called twice. + resc := make(chan string, 2) + for i := 0; i < 2; i++ { + go func() { + var s string + if err := g.Get(dummyCtx, testkey, StringSink(&s)); err != nil { + resc <- "ERROR:" + err.Error() + return + } + resc <- s + }() + } + + // Ensure both goroutines have entered the Do routine. This implies + // both concurrent requests have checked the cache, found it empty, + // and called load(). + orderedGroup.stage1 <- true + orderedGroup.stage1 <- true + orderedGroup.stage2 <- true + orderedGroup.stage2 <- true + + for i := 0; i < 2; i++ { + if s := <-resc; s != testval { + t.Errorf("result is %s want %s", s, testval) + } + } + + const wantItems = 1 + if g.mainCache.items() != wantItems { + t.Errorf("mainCache has %d items, want %d", g.mainCache.items(), wantItems) + } + + // If the singleflight callback doesn't double-check the cache again + // upon entry, we would increment nbytes twice but the entry would + // only be in the cache once. + const wantBytes = int64(len(testkey) + len(testval)) + if g.mainCache.nbytes != wantBytes { + t.Errorf("cache has %d bytes, want %d", g.mainCache.nbytes, wantBytes) + } +} + +func TestGroupStatsAlignment(t *testing.T) { + var g Group + off := unsafe.Offsetof(g.Stats) + if off%8 != 0 { + t.Fatal("Stats structure is not 8-byte aligned.") + } +} + +// TODO(bradfitz): port the Google-internal full integration test into here, +// using HTTP requests instead of our RPC system. diff --git a/vendor/github.com/golang/groupcache/http.go b/vendor/github.com/golang/groupcache/http.go new file mode 100644 index 000000000..f37467a78 --- /dev/null +++ b/vendor/github.com/golang/groupcache/http.go @@ -0,0 +1,227 @@ +/* +Copyright 2013 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 groupcache + +import ( + "bytes" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "sync" + + "github.com/golang/groupcache/consistenthash" + pb "github.com/golang/groupcache/groupcachepb" + "github.com/golang/protobuf/proto" +) + +const defaultBasePath = "/_groupcache/" + +const defaultReplicas = 50 + +// HTTPPool implements PeerPicker for a pool of HTTP peers. +type HTTPPool struct { + // Context optionally specifies a context for the server to use when it + // receives a request. + // If nil, the server uses a nil Context. + Context func(*http.Request) Context + + // Transport optionally specifies an http.RoundTripper for the client + // to use when it makes a request. + // If nil, the client uses http.DefaultTransport. + Transport func(Context) http.RoundTripper + + // this peer's base URL, e.g. "https://example.net:8000" + self string + + // opts specifies the options. + opts HTTPPoolOptions + + mu sync.Mutex // guards peers and httpGetters + peers *consistenthash.Map + httpGetters map[string]*httpGetter // keyed by e.g. "http://10.0.0.2:8008" +} + +// HTTPPoolOptions are the configurations of a HTTPPool. +type HTTPPoolOptions struct { + // BasePath specifies the HTTP path that will serve groupcache requests. + // If blank, it defaults to "/_groupcache/". + BasePath string + + // Replicas specifies the number of key replicas on the consistent hash. + // If blank, it defaults to 50. + Replicas int + + // HashFn specifies the hash function of the consistent hash. + // If blank, it defaults to crc32.ChecksumIEEE. + HashFn consistenthash.Hash +} + +// NewHTTPPool initializes an HTTP pool of peers, and registers itself as a PeerPicker. +// For convenience, it also registers itself as an http.Handler with http.DefaultServeMux. +// The self argument should be a valid base URL that points to the current server, +// for example "http://example.net:8000". +func NewHTTPPool(self string) *HTTPPool { + p := NewHTTPPoolOpts(self, nil) + http.Handle(p.opts.BasePath, p) + return p +} + +var httpPoolMade bool + +// NewHTTPPoolOpts initializes an HTTP pool of peers with the given options. +// Unlike NewHTTPPool, this function does not register the created pool as an HTTP handler. +// The returned *HTTPPool implements http.Handler and must be registered using http.Handle. +func NewHTTPPoolOpts(self string, o *HTTPPoolOptions) *HTTPPool { + if httpPoolMade { + panic("groupcache: NewHTTPPool must be called only once") + } + httpPoolMade = true + + p := &HTTPPool{ + self: self, + httpGetters: make(map[string]*httpGetter), + } + if o != nil { + p.opts = *o + } + if p.opts.BasePath == "" { + p.opts.BasePath = defaultBasePath + } + if p.opts.Replicas == 0 { + p.opts.Replicas = defaultReplicas + } + p.peers = consistenthash.New(p.opts.Replicas, p.opts.HashFn) + + RegisterPeerPicker(func() PeerPicker { return p }) + return p +} + +// Set updates the pool's list of peers. +// Each peer value should be a valid base URL, +// for example "http://example.net:8000". +func (p *HTTPPool) Set(peers ...string) { + p.mu.Lock() + defer p.mu.Unlock() + p.peers = consistenthash.New(p.opts.Replicas, p.opts.HashFn) + p.peers.Add(peers...) + p.httpGetters = make(map[string]*httpGetter, len(peers)) + for _, peer := range peers { + p.httpGetters[peer] = &httpGetter{transport: p.Transport, baseURL: peer + p.opts.BasePath} + } +} + +func (p *HTTPPool) PickPeer(key string) (ProtoGetter, bool) { + p.mu.Lock() + defer p.mu.Unlock() + if p.peers.IsEmpty() { + return nil, false + } + if peer := p.peers.Get(key); peer != p.self { + return p.httpGetters[peer], true + } + return nil, false +} + +func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Parse request. + if !strings.HasPrefix(r.URL.Path, p.opts.BasePath) { + panic("HTTPPool serving unexpected path: " + r.URL.Path) + } + parts := strings.SplitN(r.URL.Path[len(p.opts.BasePath):], "/", 2) + if len(parts) != 2 { + http.Error(w, "bad request", http.StatusBadRequest) + return + } + groupName := parts[0] + key := parts[1] + + // Fetch the value for this group/key. + group := GetGroup(groupName) + if group == nil { + http.Error(w, "no such group: "+groupName, http.StatusNotFound) + return + } + var ctx Context + if p.Context != nil { + ctx = p.Context(r) + } + + group.Stats.ServerRequests.Add(1) + var value []byte + err := group.Get(ctx, key, AllocatingByteSliceSink(&value)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Write the value to the response body as a proto message. + body, err := proto.Marshal(&pb.GetResponse{Value: value}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/x-protobuf") + w.Write(body) +} + +type httpGetter struct { + transport func(Context) http.RoundTripper + baseURL string +} + +var bufferPool = sync.Pool{ + New: func() interface{} { return new(bytes.Buffer) }, +} + +func (h *httpGetter) Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error { + u := fmt.Sprintf( + "%v%v/%v", + h.baseURL, + url.QueryEscape(in.GetGroup()), + url.QueryEscape(in.GetKey()), + ) + req, err := http.NewRequest("GET", u, nil) + if err != nil { + return err + } + tr := http.DefaultTransport + if h.transport != nil { + tr = h.transport(context) + } + res, err := tr.RoundTrip(req) + if err != nil { + return err + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return fmt.Errorf("server returned: %v", res.Status) + } + b := bufferPool.Get().(*bytes.Buffer) + b.Reset() + defer bufferPool.Put(b) + _, err = io.Copy(b, res.Body) + if err != nil { + return fmt.Errorf("reading response body: %v", err) + } + err = proto.Unmarshal(b.Bytes(), out) + if err != nil { + return fmt.Errorf("decoding response body: %v", err) + } + return nil +} diff --git a/vendor/github.com/golang/groupcache/http_test.go b/vendor/github.com/golang/groupcache/http_test.go new file mode 100644 index 000000000..b42edd7f0 --- /dev/null +++ b/vendor/github.com/golang/groupcache/http_test.go @@ -0,0 +1,166 @@ +/* +Copyright 2013 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 groupcache + +import ( + "errors" + "flag" + "log" + "net" + "net/http" + "os" + "os/exec" + "strconv" + "strings" + "sync" + "testing" + "time" +) + +var ( + peerAddrs = flag.String("test_peer_addrs", "", "Comma-separated list of peer addresses; used by TestHTTPPool") + peerIndex = flag.Int("test_peer_index", -1, "Index of which peer this child is; used by TestHTTPPool") + peerChild = flag.Bool("test_peer_child", false, "True if running as a child process; used by TestHTTPPool") +) + +func TestHTTPPool(t *testing.T) { + if *peerChild { + beChildForTestHTTPPool() + os.Exit(0) + } + + const ( + nChild = 4 + nGets = 100 + ) + + var childAddr []string + for i := 0; i < nChild; i++ { + childAddr = append(childAddr, pickFreeAddr(t)) + } + + var cmds []*exec.Cmd + var wg sync.WaitGroup + for i := 0; i < nChild; i++ { + cmd := exec.Command(os.Args[0], + "--test.run=TestHTTPPool", + "--test_peer_child", + "--test_peer_addrs="+strings.Join(childAddr, ","), + "--test_peer_index="+strconv.Itoa(i), + ) + cmds = append(cmds, cmd) + wg.Add(1) + if err := cmd.Start(); err != nil { + t.Fatal("failed to start child process: ", err) + } + go awaitAddrReady(t, childAddr[i], &wg) + } + defer func() { + for i := 0; i < nChild; i++ { + if cmds[i].Process != nil { + cmds[i].Process.Kill() + } + } + }() + wg.Wait() + + // Use a dummy self address so that we don't handle gets in-process. + p := NewHTTPPool("should-be-ignored") + p.Set(addrToURL(childAddr)...) + + // Dummy getter function. Gets should go to children only. + // The only time this process will handle a get is when the + // children can't be contacted for some reason. + getter := GetterFunc(func(ctx Context, key string, dest Sink) error { + return errors.New("parent getter called; something's wrong") + }) + g := NewGroup("httpPoolTest", 1<<20, getter) + + for _, key := range testKeys(nGets) { + var value string + if err := g.Get(nil, key, StringSink(&value)); err != nil { + t.Fatal(err) + } + if suffix := ":" + key; !strings.HasSuffix(value, suffix) { + t.Errorf("Get(%q) = %q, want value ending in %q", key, value, suffix) + } + t.Logf("Get key=%q, value=%q (peer:key)", key, value) + } +} + +func testKeys(n int) (keys []string) { + keys = make([]string, n) + for i := range keys { + keys[i] = strconv.Itoa(i) + } + return +} + +func beChildForTestHTTPPool() { + addrs := strings.Split(*peerAddrs, ",") + + p := NewHTTPPool("http://" + addrs[*peerIndex]) + p.Set(addrToURL(addrs)...) + + getter := GetterFunc(func(ctx Context, key string, dest Sink) error { + dest.SetString(strconv.Itoa(*peerIndex) + ":" + key) + return nil + }) + NewGroup("httpPoolTest", 1<<20, getter) + + log.Fatal(http.ListenAndServe(addrs[*peerIndex], p)) +} + +// This is racy. Another process could swoop in and steal the port between the +// call to this function and the next listen call. Should be okay though. +// The proper way would be to pass the l.File() as ExtraFiles to the child +// process, and then close your copy once the child starts. +func pickFreeAddr(t *testing.T) string { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + defer l.Close() + return l.Addr().String() +} + +func addrToURL(addr []string) []string { + url := make([]string, len(addr)) + for i := range addr { + url[i] = "http://" + addr[i] + } + return url +} + +func awaitAddrReady(t *testing.T, addr string, wg *sync.WaitGroup) { + defer wg.Done() + const max = 1 * time.Second + tries := 0 + for { + tries++ + c, err := net.Dial("tcp", addr) + if err == nil { + c.Close() + return + } + delay := time.Duration(tries) * 25 * time.Millisecond + if delay > max { + delay = max + } + time.Sleep(delay) + } +} diff --git a/vendor/github.com/golang/groupcache/lru/lru_test.go b/vendor/github.com/golang/groupcache/lru/lru_test.go new file mode 100644 index 000000000..b7d9d8acf --- /dev/null +++ b/vendor/github.com/golang/groupcache/lru/lru_test.go @@ -0,0 +1,97 @@ +/* +Copyright 2013 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 lru + +import ( + "fmt" + "testing" +) + +type simpleStruct struct { + int + string +} + +type complexStruct struct { + int + simpleStruct +} + +var getTests = []struct { + name string + keyToAdd interface{} + keyToGet interface{} + expectedOk bool +}{ + {"string_hit", "myKey", "myKey", true}, + {"string_miss", "myKey", "nonsense", false}, + {"simple_struct_hit", simpleStruct{1, "two"}, simpleStruct{1, "two"}, true}, + {"simeple_struct_miss", simpleStruct{1, "two"}, simpleStruct{0, "noway"}, false}, + {"complex_struct_hit", complexStruct{1, simpleStruct{2, "three"}}, + complexStruct{1, simpleStruct{2, "three"}}, true}, +} + +func TestGet(t *testing.T) { + for _, tt := range getTests { + lru := New(0) + lru.Add(tt.keyToAdd, 1234) + val, ok := lru.Get(tt.keyToGet) + if ok != tt.expectedOk { + t.Fatalf("%s: cache hit = %v; want %v", tt.name, ok, !ok) + } else if ok && val != 1234 { + t.Fatalf("%s expected get to return 1234 but got %v", tt.name, val) + } + } +} + +func TestRemove(t *testing.T) { + lru := New(0) + lru.Add("myKey", 1234) + if val, ok := lru.Get("myKey"); !ok { + t.Fatal("TestRemove returned no match") + } else if val != 1234 { + t.Fatalf("TestRemove failed. Expected %d, got %v", 1234, val) + } + + lru.Remove("myKey") + if _, ok := lru.Get("myKey"); ok { + t.Fatal("TestRemove returned a removed entry") + } +} + +func TestEvict(t *testing.T) { + evictedKeys := make([]Key, 0) + onEvictedFun := func(key Key, value interface{}) { + evictedKeys = append(evictedKeys, key) + } + + lru := New(20) + lru.OnEvicted = onEvictedFun + for i := 0; i < 22; i++ { + lru.Add(fmt.Sprintf("myKey%d", i), 1234) + } + + if len(evictedKeys) != 2 { + t.Fatalf("got %d evicted keys; want 2", len(evictedKeys)) + } + if evictedKeys[0] != Key("myKey0") { + t.Fatalf("got %v in first evicted key; want %s", evictedKeys[0], "myKey0") + } + if evictedKeys[1] != Key("myKey1") { + t.Fatalf("got %v in second evicted key; want %s", evictedKeys[1], "myKey1") + } +} diff --git a/vendor/github.com/golang/groupcache/peers.go b/vendor/github.com/golang/groupcache/peers.go new file mode 100644 index 000000000..1625ff043 --- /dev/null +++ b/vendor/github.com/golang/groupcache/peers.go @@ -0,0 +1,85 @@ +/* +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. +*/ + +// peers.go defines how processes find and communicate with their peers. + +package groupcache + +import ( + pb "github.com/golang/groupcache/groupcachepb" +) + +// Context is an opaque value passed through calls to the +// ProtoGetter. It may be nil if your ProtoGetter implementation does +// not require a context. +type Context interface{} + +// ProtoGetter is the interface that must be implemented by a peer. +type ProtoGetter interface { + Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error +} + +// PeerPicker is the interface that must be implemented to locate +// the peer that owns a specific key. +type PeerPicker interface { + // PickPeer returns the peer that owns the specific key + // and true to indicate that a remote peer was nominated. + // It returns nil, false if the key owner is the current peer. + PickPeer(key string) (peer ProtoGetter, ok bool) +} + +// NoPeers is an implementation of PeerPicker that never finds a peer. +type NoPeers struct{} + +func (NoPeers) PickPeer(key string) (peer ProtoGetter, ok bool) { return } + +var ( + portPicker func(groupName string) PeerPicker +) + +// RegisterPeerPicker registers the peer initialization function. +// It is called once, when the first group is created. +// Either RegisterPeerPicker or RegisterPerGroupPeerPicker should be +// called exactly once, but not both. +func RegisterPeerPicker(fn func() PeerPicker) { + if portPicker != nil { + panic("RegisterPeerPicker called more than once") + } + portPicker = func(_ string) PeerPicker { return fn() } +} + +// RegisterPerGroupPeerPicker registers the peer initialization function, +// which takes the groupName, to be used in choosing a PeerPicker. +// It is called once, when the first group is created. +// Either RegisterPeerPicker or RegisterPerGroupPeerPicker should be +// called exactly once, but not both. +func RegisterPerGroupPeerPicker(fn func(groupName string) PeerPicker) { + if portPicker != nil { + panic("RegisterPeerPicker called more than once") + } + portPicker = fn +} + +func getPeers(groupName string) PeerPicker { + if portPicker == nil { + return NoPeers{} + } + pk := portPicker(groupName) + if pk == nil { + pk = NoPeers{} + } + return pk +} diff --git a/vendor/github.com/golang/groupcache/sinks.go b/vendor/github.com/golang/groupcache/sinks.go new file mode 100644 index 000000000..6c0b8be5c --- /dev/null +++ b/vendor/github.com/golang/groupcache/sinks.go @@ -0,0 +1,322 @@ +/* +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 groupcache + +import ( + "errors" + + "github.com/golang/protobuf/proto" +) + +// A Sink receives data from a Get call. +// +// Implementation of Getter must call exactly one of the Set methods +// on success. +type Sink interface { + // SetString sets the value to s. + SetString(s string) error + + // SetBytes sets the value to the contents of v. + // The caller retains ownership of v. + SetBytes(v []byte) error + + // SetProto sets the value to the encoded version of m. + // The caller retains ownership of m. + SetProto(m proto.Message) error + + // view returns a frozen view of the bytes for caching. + view() (ByteView, error) +} + +func cloneBytes(b []byte) []byte { + c := make([]byte, len(b)) + copy(c, b) + return c +} + +func setSinkView(s Sink, v ByteView) error { + // A viewSetter is a Sink that can also receive its value from + // a ByteView. This is a fast path to minimize copies when the + // item was already cached locally in memory (where it's + // cached as a ByteView) + type viewSetter interface { + setView(v ByteView) error + } + if vs, ok := s.(viewSetter); ok { + return vs.setView(v) + } + if v.b != nil { + return s.SetBytes(v.b) + } + return s.SetString(v.s) +} + +// StringSink returns a Sink that populates the provided string pointer. +func StringSink(sp *string) Sink { + return &stringSink{sp: sp} +} + +type stringSink struct { + sp *string + v ByteView + // TODO(bradfitz): track whether any Sets were called. +} + +func (s *stringSink) view() (ByteView, error) { + // TODO(bradfitz): return an error if no Set was called + return s.v, nil +} + +func (s *stringSink) SetString(v string) error { + s.v.b = nil + s.v.s = v + *s.sp = v + return nil +} + +func (s *stringSink) SetBytes(v []byte) error { + return s.SetString(string(v)) +} + +func (s *stringSink) SetProto(m proto.Message) error { + b, err := proto.Marshal(m) + if err != nil { + return err + } + s.v.b = b + *s.sp = string(b) + return nil +} + +// ByteViewSink returns a Sink that populates a ByteView. +func ByteViewSink(dst *ByteView) Sink { + if dst == nil { + panic("nil dst") + } + return &byteViewSink{dst: dst} +} + +type byteViewSink struct { + dst *ByteView + + // if this code ever ends up tracking that at least one set* + // method was called, don't make it an error to call set + // methods multiple times. Lorry's payload.go does that, and + // it makes sense. The comment at the top of this file about + // "exactly one of the Set methods" is overly strict. We + // really care about at least once (in a handler), but if + // multiple handlers fail (or multiple functions in a program + // using a Sink), it's okay to re-use the same one. +} + +func (s *byteViewSink) setView(v ByteView) error { + *s.dst = v + return nil +} + +func (s *byteViewSink) view() (ByteView, error) { + return *s.dst, nil +} + +func (s *byteViewSink) SetProto(m proto.Message) error { + b, err := proto.Marshal(m) + if err != nil { + return err + } + *s.dst = ByteView{b: b} + return nil +} + +func (s *byteViewSink) SetBytes(b []byte) error { + *s.dst = ByteView{b: cloneBytes(b)} + return nil +} + +func (s *byteViewSink) SetString(v string) error { + *s.dst = ByteView{s: v} + return nil +} + +// ProtoSink returns a sink that unmarshals binary proto values into m. +func ProtoSink(m proto.Message) Sink { + return &protoSink{ + dst: m, + } +} + +type protoSink struct { + dst proto.Message // authoritative value + typ string + + v ByteView // encoded +} + +func (s *protoSink) view() (ByteView, error) { + return s.v, nil +} + +func (s *protoSink) SetBytes(b []byte) error { + err := proto.Unmarshal(b, s.dst) + if err != nil { + return err + } + s.v.b = cloneBytes(b) + s.v.s = "" + return nil +} + +func (s *protoSink) SetString(v string) error { + b := []byte(v) + err := proto.Unmarshal(b, s.dst) + if err != nil { + return err + } + s.v.b = b + s.v.s = "" + return nil +} + +func (s *protoSink) SetProto(m proto.Message) error { + b, err := proto.Marshal(m) + if err != nil { + return err + } + // TODO(bradfitz): optimize for same-task case more and write + // right through? would need to document ownership rules at + // the same time. but then we could just assign *dst = *m + // here. This works for now: + err = proto.Unmarshal(b, s.dst) + if err != nil { + return err + } + s.v.b = b + s.v.s = "" + return nil +} + +// AllocatingByteSliceSink returns a Sink that allocates +// a byte slice to hold the received value and assigns +// it to *dst. The memory is not retained by groupcache. +func AllocatingByteSliceSink(dst *[]byte) Sink { + return &allocBytesSink{dst: dst} +} + +type allocBytesSink struct { + dst *[]byte + v ByteView +} + +func (s *allocBytesSink) view() (ByteView, error) { + return s.v, nil +} + +func (s *allocBytesSink) setView(v ByteView) error { + if v.b != nil { + *s.dst = cloneBytes(v.b) + } else { + *s.dst = []byte(v.s) + } + s.v = v + return nil +} + +func (s *allocBytesSink) SetProto(m proto.Message) error { + b, err := proto.Marshal(m) + if err != nil { + return err + } + return s.setBytesOwned(b) +} + +func (s *allocBytesSink) SetBytes(b []byte) error { + return s.setBytesOwned(cloneBytes(b)) +} + +func (s *allocBytesSink) setBytesOwned(b []byte) error { + if s.dst == nil { + return errors.New("nil AllocatingByteSliceSink *[]byte dst") + } + *s.dst = cloneBytes(b) // another copy, protecting the read-only s.v.b view + s.v.b = b + s.v.s = "" + return nil +} + +func (s *allocBytesSink) SetString(v string) error { + if s.dst == nil { + return errors.New("nil AllocatingByteSliceSink *[]byte dst") + } + *s.dst = []byte(v) + s.v.b = nil + s.v.s = v + return nil +} + +// TruncatingByteSliceSink returns a Sink that writes up to len(*dst) +// bytes to *dst. If more bytes are available, they're silently +// truncated. If fewer bytes are available than len(*dst), *dst +// is shrunk to fit the number of bytes available. +func TruncatingByteSliceSink(dst *[]byte) Sink { + return &truncBytesSink{dst: dst} +} + +type truncBytesSink struct { + dst *[]byte + v ByteView +} + +func (s *truncBytesSink) view() (ByteView, error) { + return s.v, nil +} + +func (s *truncBytesSink) SetProto(m proto.Message) error { + b, err := proto.Marshal(m) + if err != nil { + return err + } + return s.setBytesOwned(b) +} + +func (s *truncBytesSink) SetBytes(b []byte) error { + return s.setBytesOwned(cloneBytes(b)) +} + +func (s *truncBytesSink) setBytesOwned(b []byte) error { + if s.dst == nil { + return errors.New("nil TruncatingByteSliceSink *[]byte dst") + } + n := copy(*s.dst, b) + if n < len(*s.dst) { + *s.dst = (*s.dst)[:n] + } + s.v.b = b + s.v.s = "" + return nil +} + +func (s *truncBytesSink) SetString(v string) error { + if s.dst == nil { + return errors.New("nil TruncatingByteSliceSink *[]byte dst") + } + n := copy(*s.dst, v) + if n < len(*s.dst) { + *s.dst = (*s.dst)[:n] + } + s.v.b = nil + s.v.s = v + return nil +} diff --git a/vendor/github.com/golang/protobuf/.gitignore b/vendor/github.com/golang/protobuf/.gitignore new file mode 100644 index 000000000..c7dd40587 --- /dev/null +++ b/vendor/github.com/golang/protobuf/.gitignore @@ -0,0 +1,17 @@ +.DS_Store +*.[568ao] +*.ao +*.so +*.pyc +._* +.nfs.* +[568a].out +*~ +*.orig +core +_obj +_test +_testmain.go + +# Conformance test output and transient files. +conformance/failing_tests.txt diff --git a/vendor/github.com/golang/protobuf/.travis.yml b/vendor/github.com/golang/protobuf/.travis.yml new file mode 100644 index 000000000..455fa660c --- /dev/null +++ b/vendor/github.com/golang/protobuf/.travis.yml @@ -0,0 +1,30 @@ +sudo: false +language: go +go: +- 1.6.x +- 1.10.x +- 1.x + +install: + - go get -v -d -t github.com/golang/protobuf/... + - curl -L https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-linux-x86_64.zip -o /tmp/protoc.zip + - unzip /tmp/protoc.zip -d "$HOME"/protoc + - mkdir -p "$HOME"/src && ln -s "$HOME"/protoc "$HOME"/src/protobuf + +env: + - PATH=$HOME/protoc/bin:$PATH + +script: + - make all + - make regenerate + # TODO(tamird): When https://github.com/travis-ci/gimme/pull/130 is + # released, make this look for "1.x". + - if [[ "$TRAVIS_GO_VERSION" == 1.10* ]]; then + if [[ "$(git status --porcelain 2>&1)" != "" ]]; then + git status >&2; + git diff -a >&2; + exit 1; + fi; + echo "git status is clean."; + fi; + - make test diff --git a/vendor/github.com/golang/protobuf/Makefile b/vendor/github.com/golang/protobuf/Makefile new file mode 100644 index 000000000..2bc2621aa --- /dev/null +++ b/vendor/github.com/golang/protobuf/Makefile @@ -0,0 +1,48 @@ +# Go support for Protocol Buffers - Google's data interchange format +# +# Copyright 2010 The Go Authors. All rights reserved. +# https://github.com/golang/protobuf +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +all: install + +install: + go install ./proto ./jsonpb ./ptypes ./protoc-gen-go + +test: + go test ./... ./protoc-gen-go/testdata + make -C conformance test + +clean: + go clean ./... + +nuke: + go clean -i ./... + +regenerate: + ./regenerate.sh diff --git a/vendor/github.com/golang/protobuf/README.md b/vendor/github.com/golang/protobuf/README.md new file mode 100644 index 000000000..01b29daf2 --- /dev/null +++ b/vendor/github.com/golang/protobuf/README.md @@ -0,0 +1,283 @@ +# Go support for Protocol Buffers + +[![Build Status](https://travis-ci.org/golang/protobuf.svg?branch=master)](https://travis-ci.org/golang/protobuf) +[![GoDoc](https://godoc.org/github.com/golang/protobuf?status.svg)](https://godoc.org/github.com/golang/protobuf) + +Google's data interchange format. +Copyright 2010 The Go Authors. +https://github.com/golang/protobuf + +This package and the code it generates requires at least Go 1.6. + +This software implements Go bindings for protocol buffers. For +information about protocol buffers themselves, see + https://developers.google.com/protocol-buffers/ + +## Installation ## + +To use this software, you must: +- Install the standard C++ implementation of protocol buffers from + https://developers.google.com/protocol-buffers/ +- Of course, install the Go compiler and tools from + https://golang.org/ + See + https://golang.org/doc/install + for details or, if you are using gccgo, follow the instructions at + https://golang.org/doc/install/gccgo +- Grab the code from the repository and install the proto package. + The simplest way is to run `go get -u github.com/golang/protobuf/protoc-gen-go`. + The compiler plugin, protoc-gen-go, will be installed in $GOBIN, + defaulting to $GOPATH/bin. It must be in your $PATH for the protocol + compiler, protoc, to find it. + +This software has two parts: a 'protocol compiler plugin' that +generates Go source files that, once compiled, can access and manage +protocol buffers; and a library that implements run-time support for +encoding (marshaling), decoding (unmarshaling), and accessing protocol +buffers. + +There is support for gRPC in Go using protocol buffers. +See the note at the bottom of this file for details. + +There are no insertion points in the plugin. + + +## Using protocol buffers with Go ## + +Once the software is installed, there are two steps to using it. +First you must compile the protocol buffer definitions and then import +them, with the support library, into your program. + +To compile the protocol buffer definition, run protoc with the --go_out +parameter set to the directory you want to output the Go code to. + + protoc --go_out=. *.proto + +The generated files will be suffixed .pb.go. See the Test code below +for an example using such a file. + +## Packages and input paths ## + +The protocol buffer language has a concept of "packages" which does not +correspond well to the Go notion of packages. In generated Go code, +each source `.proto` file is associated with a single Go package. The +name and import path for this package is specified with the `go_package` +proto option: + + option go_package = "github.com/golang/protobuf/ptypes/any"; + +The protocol buffer compiler will attempt to derive a package name and +import path if a `go_package` option is not present, but it is +best to always specify one explicitly. + +There is a one-to-one relationship between source `.proto` files and +generated `.pb.go` files, but any number of `.pb.go` files may be +contained in the same Go package. + +The output name of a generated file is produced by replacing the +`.proto` suffix with `.pb.go` (e.g., `foo.proto` produces `foo.pb.go`). +However, the output directory is selected in one of two ways. Let +us say we have `inputs/x.proto` with a `go_package` option of +`github.com/golang/protobuf/p`. The corresponding output file may +be: + +- Relative to the import path: + + protoc --go_out=. inputs/x.proto + # writes ./github.com/golang/protobuf/p/x.pb.go + + (This can work well with `--go_out=$GOPATH`.) + +- Relative to the input file: + + protoc --go_out=paths=source_relative:. inputs/x.proto + # generate ./inputs/x.pb.go + +## Generated code ## + +The package comment for the proto library contains text describing +the interface provided in Go for protocol buffers. Here is an edited +version. + +The proto package converts data structures to and from the +wire format of protocol buffers. It works in concert with the +Go source code generated for .proto files by the protocol compiler. + +A summary of the properties of the protocol buffer interface +for a protocol buffer variable v: + + - Names are turned from camel_case to CamelCase for export. + - There are no methods on v to set fields; just treat + them as structure fields. + - There are getters that return a field's value if set, + and return the field's default value if unset. + The getters work even if the receiver is a nil message. + - The zero value for a struct is its correct initialization state. + All desired fields must be set before marshaling. + - A Reset() method will restore a protobuf struct to its zero state. + - Non-repeated fields are pointers to the values; nil means unset. + That is, optional or required field int32 f becomes F *int32. + - Repeated fields are slices. + - Helper functions are available to aid the setting of fields. + Helpers for getting values are superseded by the + GetFoo methods and their use is deprecated. + msg.Foo = proto.String("hello") // set field + - Constants are defined to hold the default values of all fields that + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. + - Enums are given type names and maps from names to values. + Enum values are prefixed with the enum's type name. Enum types have + a String method, and a Enum method to assist in message construction. + - Nested groups and enums have type names prefixed with the name of + the surrounding message type. + - Extensions are given descriptor names that start with E_, + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. + - Oneof field sets are given a single field in their message, + with distinguished wrapper types for each possible field value. + - Marshal and Unmarshal are functions to encode and decode the wire format. + +When the .proto file specifies `syntax="proto3"`, there are some differences: + + - Non-repeated fields of non-message type are values instead of pointers. + - Enum types do not get an Enum method. + +Consider file test.proto, containing + +```proto + syntax = "proto2"; + package example; + + enum FOO { X = 17; }; + + message Test { + required string label = 1; + optional int32 type = 2 [default=77]; + repeated int64 reps = 3; + optional group OptionalGroup = 4 { + required string RequiredField = 5; + } + } +``` + +To create and play with a Test object from the example package, + +```go + package main + + import ( + "log" + + "github.com/golang/protobuf/proto" + "path/to/example" + ) + + func main() { + test := &example.Test { + Label: proto.String("hello"), + Type: proto.Int32(17), + Reps: []int64{1, 2, 3}, + Optionalgroup: &example.Test_OptionalGroup { + RequiredField: proto.String("good bye"), + }, + } + data, err := proto.Marshal(test) + if err != nil { + log.Fatal("marshaling error: ", err) + } + newTest := &example.Test{} + err = proto.Unmarshal(data, newTest) + if err != nil { + log.Fatal("unmarshaling error: ", err) + } + // Now test and newTest contain the same data. + if test.GetLabel() != newTest.GetLabel() { + log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel()) + } + // etc. + } +``` + +## Parameters ## + +To pass extra parameters to the plugin, use a comma-separated +parameter list separated from the output directory by a colon: + + protoc --go_out=plugins=grpc,import_path=mypackage:. *.proto + +- `paths=(import | source_relative)` - specifies how the paths of + generated files are structured. See the "Packages and imports paths" + section above. The default is `import`. +- `plugins=plugin1+plugin2` - specifies the list of sub-plugins to + load. The only plugin in this repo is `grpc`. +- `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is + associated with Go package quux/shme. This is subject to the + import_prefix parameter. + +The following parameters are deprecated and should not be used: + +- `import_prefix=xxx` - a prefix that is added onto the beginning of + all imports. +- `import_path=foo/bar` - used as the package if no input files + declare `go_package`. If it contains slashes, everything up to the + rightmost slash is ignored. + +## gRPC Support ## + +If a proto file specifies RPC services, protoc-gen-go can be instructed to +generate code compatible with gRPC (http://www.grpc.io/). To do this, pass +the `plugins` parameter to protoc-gen-go; the usual way is to insert it into +the --go_out argument to protoc: + + protoc --go_out=plugins=grpc:. *.proto + +## Compatibility ## + +The library and the generated code are expected to be stable over time. +However, we reserve the right to make breaking changes without notice for the +following reasons: + +- Security. A security issue in the specification or implementation may come to + light whose resolution requires breaking compatibility. We reserve the right + to address such security issues. +- Unspecified behavior. There are some aspects of the Protocol Buffers + specification that are undefined. Programs that depend on such unspecified + behavior may break in future releases. +- Specification errors or changes. If it becomes necessary to address an + inconsistency, incompleteness, or change in the Protocol Buffers + specification, resolving the issue could affect the meaning or legality of + existing programs. We reserve the right to address such issues, including + updating the implementations. +- Bugs. If the library has a bug that violates the specification, a program + that depends on the buggy behavior may break if the bug is fixed. We reserve + the right to fix such bugs. +- Adding methods or fields to generated structs. These may conflict with field + names that already exist in a schema, causing applications to break. When the + code generator encounters a field in the schema that would collide with a + generated field or method name, the code generator will append an underscore + to the generated field or method name. +- Adding, removing, or changing methods or fields in generated structs that + start with `XXX`. These parts of the generated code are exported out of + necessity, but should not be considered part of the public API. +- Adding, removing, or changing unexported symbols in generated code. + +Any breaking changes outside of these will be announced 6 months in advance to +protobuf@googlegroups.com. + +You should, whenever possible, use generated code created by the `protoc-gen-go` +tool built at the same commit as the `proto` package. The `proto` package +declares package-level constants in the form `ProtoPackageIsVersionX`. +Application code and generated code may depend on one of these constants to +ensure that compilation will fail if the available version of the proto library +is too old. Whenever we make a change to the generated code that requires newer +library support, in the same commit we will increment the version number of the +generated code and declare a new package-level constant whose name incorporates +the latest version number. Removing a compatibility constant is considered a +breaking change and would be subject to the announcement policy stated above. + +The `protoc-gen-go/generator` package exposes a plugin interface, +which is used by the gRPC code generation. This interface is not +supported and is subject to incompatible changes without notice. diff --git a/vendor/github.com/golang/protobuf/proto/all_test.go b/vendor/github.com/golang/protobuf/proto/all_test.go new file mode 100644 index 000000000..361f72fbd --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/all_test.go @@ -0,0 +1,2410 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "math" + "math/rand" + "reflect" + "runtime/debug" + "strings" + "sync" + "testing" + "time" + + . "github.com/golang/protobuf/proto" + . "github.com/golang/protobuf/proto/test_proto" +) + +var globalO *Buffer + +func old() *Buffer { + if globalO == nil { + globalO = NewBuffer(nil) + } + globalO.Reset() + return globalO +} + +func equalbytes(b1, b2 []byte, t *testing.T) { + if len(b1) != len(b2) { + t.Errorf("wrong lengths: 2*%d != %d", len(b1), len(b2)) + return + } + for i := 0; i < len(b1); i++ { + if b1[i] != b2[i] { + t.Errorf("bad byte[%d]:%x %x: %s %s", i, b1[i], b2[i], b1, b2) + } + } +} + +func initGoTestField() *GoTestField { + f := new(GoTestField) + f.Label = String("label") + f.Type = String("type") + return f +} + +// These are all structurally equivalent but the tag numbers differ. +// (It's remarkable that required, optional, and repeated all have +// 8 letters.) +func initGoTest_RequiredGroup() *GoTest_RequiredGroup { + return &GoTest_RequiredGroup{ + RequiredField: String("required"), + } +} + +func initGoTest_OptionalGroup() *GoTest_OptionalGroup { + return &GoTest_OptionalGroup{ + RequiredField: String("optional"), + } +} + +func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup { + return &GoTest_RepeatedGroup{ + RequiredField: String("repeated"), + } +} + +func initGoTest(setdefaults bool) *GoTest { + pb := new(GoTest) + if setdefaults { + pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted) + pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted) + pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted) + pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted) + pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted) + pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted) + pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted) + pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted) + pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted) + pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted) + pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted + pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) + pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) + pb.F_Sfixed32Defaulted = Int32(Default_GoTest_F_Sfixed32Defaulted) + pb.F_Sfixed64Defaulted = Int64(Default_GoTest_F_Sfixed64Defaulted) + } + + pb.Kind = GoTest_TIME.Enum() + pb.RequiredField = initGoTestField() + pb.F_BoolRequired = Bool(true) + pb.F_Int32Required = Int32(3) + pb.F_Int64Required = Int64(6) + pb.F_Fixed32Required = Uint32(32) + pb.F_Fixed64Required = Uint64(64) + pb.F_Uint32Required = Uint32(3232) + pb.F_Uint64Required = Uint64(6464) + pb.F_FloatRequired = Float32(3232) + pb.F_DoubleRequired = Float64(6464) + pb.F_StringRequired = String("string") + pb.F_BytesRequired = []byte("bytes") + pb.F_Sint32Required = Int32(-32) + pb.F_Sint64Required = Int64(-64) + pb.F_Sfixed32Required = Int32(-32) + pb.F_Sfixed64Required = Int64(-64) + pb.Requiredgroup = initGoTest_RequiredGroup() + + return pb +} + +func hex(c uint8) uint8 { + if '0' <= c && c <= '9' { + return c - '0' + } + if 'a' <= c && c <= 'f' { + return 10 + c - 'a' + } + if 'A' <= c && c <= 'F' { + return 10 + c - 'A' + } + return 0 +} + +func equal(b []byte, s string, t *testing.T) bool { + if 2*len(b) != len(s) { + // fail(fmt.Sprintf("wrong lengths: 2*%d != %d", len(b), len(s)), b, s, t) + fmt.Printf("wrong lengths: 2*%d != %d\n", len(b), len(s)) + return false + } + for i, j := 0, 0; i < len(b); i, j = i+1, j+2 { + x := hex(s[j])*16 + hex(s[j+1]) + if b[i] != x { + // fail(fmt.Sprintf("bad byte[%d]:%x %x", i, b[i], x), b, s, t) + fmt.Printf("bad byte[%d]:%x %x", i, b[i], x) + return false + } + } + return true +} + +func overify(t *testing.T, pb *GoTest, expected string) { + o := old() + err := o.Marshal(pb) + if err != nil { + fmt.Printf("overify marshal-1 err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("expected = %s", expected) + } + if !equal(o.Bytes(), expected, t) { + o.DebugPrint("overify neq 1", o.Bytes()) + t.Fatalf("expected = %s", expected) + } + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + err = o.Unmarshal(pbd) + if err != nil { + t.Fatalf("overify unmarshal err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("string = %s", expected) + } + o.Reset() + err = o.Marshal(pbd) + if err != nil { + t.Errorf("overify marshal-2 err = %v", err) + o.DebugPrint("", o.Bytes()) + t.Fatalf("string = %s", expected) + } + if !equal(o.Bytes(), expected, t) { + o.DebugPrint("overify neq 2", o.Bytes()) + t.Fatalf("string = %s", expected) + } +} + +// Simple tests for numeric encode/decode primitives (varint, etc.) +func TestNumericPrimitives(t *testing.T) { + for i := uint64(0); i < 1e6; i += 111 { + o := old() + if o.EncodeVarint(i) != nil { + t.Error("EncodeVarint") + break + } + x, e := o.DecodeVarint() + if e != nil { + t.Fatal("DecodeVarint") + } + if x != i { + t.Fatal("varint decode fail:", i, x) + } + + o = old() + if o.EncodeFixed32(i) != nil { + t.Fatal("encFixed32") + } + x, e = o.DecodeFixed32() + if e != nil { + t.Fatal("decFixed32") + } + if x != i { + t.Fatal("fixed32 decode fail:", i, x) + } + + o = old() + if o.EncodeFixed64(i*1234567) != nil { + t.Error("encFixed64") + break + } + x, e = o.DecodeFixed64() + if e != nil { + t.Error("decFixed64") + break + } + if x != i*1234567 { + t.Error("fixed64 decode fail:", i*1234567, x) + break + } + + o = old() + i32 := int32(i - 12345) + if o.EncodeZigzag32(uint64(i32)) != nil { + t.Fatal("EncodeZigzag32") + } + x, e = o.DecodeZigzag32() + if e != nil { + t.Fatal("DecodeZigzag32") + } + if x != uint64(uint32(i32)) { + t.Fatal("zigzag32 decode fail:", i32, x) + } + + o = old() + i64 := int64(i - 12345) + if o.EncodeZigzag64(uint64(i64)) != nil { + t.Fatal("EncodeZigzag64") + } + x, e = o.DecodeZigzag64() + if e != nil { + t.Fatal("DecodeZigzag64") + } + if x != uint64(i64) { + t.Fatal("zigzag64 decode fail:", i64, x) + } + } +} + +// fakeMarshaler is a simple struct implementing Marshaler and Message interfaces. +type fakeMarshaler struct { + b []byte + err error +} + +func (f *fakeMarshaler) Marshal() ([]byte, error) { return f.b, f.err } +func (f *fakeMarshaler) String() string { return fmt.Sprintf("Bytes: %v Error: %v", f.b, f.err) } +func (f *fakeMarshaler) ProtoMessage() {} +func (f *fakeMarshaler) Reset() {} + +type msgWithFakeMarshaler struct { + M *fakeMarshaler `protobuf:"bytes,1,opt,name=fake"` +} + +func (m *msgWithFakeMarshaler) String() string { return CompactTextString(m) } +func (m *msgWithFakeMarshaler) ProtoMessage() {} +func (m *msgWithFakeMarshaler) Reset() {} + +// Simple tests for proto messages that implement the Marshaler interface. +func TestMarshalerEncoding(t *testing.T) { + tests := []struct { + name string + m Message + want []byte + errType reflect.Type + }{ + { + name: "Marshaler that fails", + m: &fakeMarshaler{ + err: errors.New("some marshal err"), + b: []byte{5, 6, 7}, + }, + // Since the Marshal method returned bytes, they should be written to the + // buffer. (For efficiency, we assume that Marshal implementations are + // always correct w.r.t. RequiredNotSetError and output.) + want: []byte{5, 6, 7}, + errType: reflect.TypeOf(errors.New("some marshal err")), + }, + { + name: "Marshaler that fails with RequiredNotSetError", + m: &msgWithFakeMarshaler{ + M: &fakeMarshaler{ + err: &RequiredNotSetError{}, + b: []byte{5, 6, 7}, + }, + }, + // Since there's an error that can be continued after, + // the buffer should be written. + want: []byte{ + 10, 3, // for &msgWithFakeMarshaler + 5, 6, 7, // for &fakeMarshaler + }, + errType: reflect.TypeOf(&RequiredNotSetError{}), + }, + { + name: "Marshaler that succeeds", + m: &fakeMarshaler{ + b: []byte{0, 1, 2, 3, 4, 127, 255}, + }, + want: []byte{0, 1, 2, 3, 4, 127, 255}, + }, + } + for _, test := range tests { + b := NewBuffer(nil) + err := b.Marshal(test.m) + if reflect.TypeOf(err) != test.errType { + t.Errorf("%s: got err %T(%v) wanted %T", test.name, err, err, test.errType) + } + if !reflect.DeepEqual(test.want, b.Bytes()) { + t.Errorf("%s: got bytes %v wanted %v", test.name, b.Bytes(), test.want) + } + if size := Size(test.m); size != len(b.Bytes()) { + t.Errorf("%s: Size(_) = %v, but marshaled to %v bytes", test.name, size, len(b.Bytes())) + } + + m, mErr := Marshal(test.m) + if !bytes.Equal(b.Bytes(), m) { + t.Errorf("%s: Marshal returned %v, but (*Buffer).Marshal wrote %v", test.name, m, b.Bytes()) + } + if !reflect.DeepEqual(err, mErr) { + t.Errorf("%s: Marshal err = %q, but (*Buffer).Marshal returned %q", + test.name, fmt.Sprint(mErr), fmt.Sprint(err)) + } + } +} + +// Ensure that Buffer.Marshal uses O(N) memory for N messages +func TestBufferMarshalAllocs(t *testing.T) { + value := &OtherMessage{Key: Int64(1)} + msg := &MyMessage{Count: Int32(1), Others: []*OtherMessage{value}} + + reallocSize := func(t *testing.T, items int, prealloc int) (int64, int64) { + var b Buffer + b.SetBuf(make([]byte, 0, prealloc)) + + var allocSpace int64 + prevCap := cap(b.Bytes()) + for i := 0; i < items; i++ { + err := b.Marshal(msg) + if err != nil { + t.Errorf("Marshal err = %q", err) + break + } + if c := cap(b.Bytes()); prevCap != c { + allocSpace += int64(c) + prevCap = c + } + } + needSpace := int64(len(b.Bytes())) + return allocSpace, needSpace + } + + for _, prealloc := range []int{0, 100, 10000} { + for _, items := range []int{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000} { + runtimeSpace, need := reallocSize(t, items, prealloc) + totalSpace := int64(prealloc) + runtimeSpace + + runtimeRatio := float64(runtimeSpace) / float64(need) + totalRatio := float64(totalSpace) / float64(need) + + if totalRatio < 1 || runtimeRatio > 4 { + t.Errorf("needed %dB, allocated %dB total (ratio %.1f), allocated %dB at runtime (ratio %.1f)", + need, totalSpace, totalRatio, runtimeSpace, runtimeRatio) + } + } + } +} + +// Simple tests for bytes +func TestBytesPrimitives(t *testing.T) { + o := old() + bytes := []byte{'n', 'o', 'w', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 't', 'i', 'm', 'e'} + if o.EncodeRawBytes(bytes) != nil { + t.Error("EncodeRawBytes") + } + decb, e := o.DecodeRawBytes(false) + if e != nil { + t.Error("DecodeRawBytes") + } + equalbytes(bytes, decb, t) +} + +// Simple tests for strings +func TestStringPrimitives(t *testing.T) { + o := old() + s := "now is the time" + if o.EncodeStringBytes(s) != nil { + t.Error("enc_string") + } + decs, e := o.DecodeStringBytes() + if e != nil { + t.Error("dec_string") + } + if s != decs { + t.Error("string encode/decode fail:", s, decs) + } +} + +// Do we catch the "required bit not set" case? +func TestRequiredBit(t *testing.T) { + o := old() + pb := new(GoTest) + err := o.Marshal(pb) + if err == nil { + t.Error("did not catch missing required fields") + } else if !strings.Contains(err.Error(), "Kind") { + t.Error("wrong error type:", err) + } +} + +// Check that all fields are nil. +// Clearly silly, and a residue from a more interesting test with an earlier, +// different initialization property, but it once caught a compiler bug so +// it lives. +func checkInitialized(pb *GoTest, t *testing.T) { + if pb.F_BoolDefaulted != nil { + t.Error("New or Reset did not set boolean:", *pb.F_BoolDefaulted) + } + if pb.F_Int32Defaulted != nil { + t.Error("New or Reset did not set int32:", *pb.F_Int32Defaulted) + } + if pb.F_Int64Defaulted != nil { + t.Error("New or Reset did not set int64:", *pb.F_Int64Defaulted) + } + if pb.F_Fixed32Defaulted != nil { + t.Error("New or Reset did not set fixed32:", *pb.F_Fixed32Defaulted) + } + if pb.F_Fixed64Defaulted != nil { + t.Error("New or Reset did not set fixed64:", *pb.F_Fixed64Defaulted) + } + if pb.F_Uint32Defaulted != nil { + t.Error("New or Reset did not set uint32:", *pb.F_Uint32Defaulted) + } + if pb.F_Uint64Defaulted != nil { + t.Error("New or Reset did not set uint64:", *pb.F_Uint64Defaulted) + } + if pb.F_FloatDefaulted != nil { + t.Error("New or Reset did not set float:", *pb.F_FloatDefaulted) + } + if pb.F_DoubleDefaulted != nil { + t.Error("New or Reset did not set double:", *pb.F_DoubleDefaulted) + } + if pb.F_StringDefaulted != nil { + t.Error("New or Reset did not set string:", *pb.F_StringDefaulted) + } + if pb.F_BytesDefaulted != nil { + t.Error("New or Reset did not set bytes:", string(pb.F_BytesDefaulted)) + } + if pb.F_Sint32Defaulted != nil { + t.Error("New or Reset did not set int32:", *pb.F_Sint32Defaulted) + } + if pb.F_Sint64Defaulted != nil { + t.Error("New or Reset did not set int64:", *pb.F_Sint64Defaulted) + } +} + +// Does Reset() reset? +func TestReset(t *testing.T) { + pb := initGoTest(true) + // muck with some values + pb.F_BoolDefaulted = Bool(false) + pb.F_Int32Defaulted = Int32(237) + pb.F_Int64Defaulted = Int64(12346) + pb.F_Fixed32Defaulted = Uint32(32000) + pb.F_Fixed64Defaulted = Uint64(666) + pb.F_Uint32Defaulted = Uint32(323232) + pb.F_Uint64Defaulted = nil + pb.F_FloatDefaulted = nil + pb.F_DoubleDefaulted = Float64(0) + pb.F_StringDefaulted = String("gotcha") + pb.F_BytesDefaulted = []byte("asdfasdf") + pb.F_Sint32Defaulted = Int32(123) + pb.F_Sint64Defaulted = Int64(789) + pb.Reset() + checkInitialized(pb, t) +} + +// All required fields set, no defaults provided. +func TestEncodeDecode1(t *testing.T) { + pb := initGoTest(false) + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 0x20 + "714000000000000000"+ // field 14, encoding 1, value 0x40 + "78a019"+ // field 15, encoding 0, value 0xca0 = 3232 + "8001c032"+ // field 16, encoding 0, value 0x1940 = 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2, string "string" + "b304"+ // field 70, encoding 3, start group + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // field 70, encoding 4, end group + "aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff") // field 105, encoding 1, -64 fixed64 +} + +// All required fields set, defaults provided. +func TestEncodeDecode2(t *testing.T) { + pb := initGoTest(true) + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 + +} + +// All default fields set to their default value by hand +func TestEncodeDecode3(t *testing.T) { + pb := initGoTest(false) + pb.F_BoolDefaulted = Bool(true) + pb.F_Int32Defaulted = Int32(32) + pb.F_Int64Defaulted = Int64(64) + pb.F_Fixed32Defaulted = Uint32(320) + pb.F_Fixed64Defaulted = Uint64(640) + pb.F_Uint32Defaulted = Uint32(3200) + pb.F_Uint64Defaulted = Uint64(6400) + pb.F_FloatDefaulted = Float32(314159) + pb.F_DoubleDefaulted = Float64(271828) + pb.F_StringDefaulted = String("hello, \"world!\"\n") + pb.F_BytesDefaulted = []byte("Bignose") + pb.F_Sint32Defaulted = Int32(-32) + pb.F_Sint64Defaulted = Int64(-64) + pb.F_Sfixed32Defaulted = Int32(-32) + pb.F_Sfixed64Defaulted = Int64(-64) + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 + +} + +// All required fields set, defaults provided, all non-defaulted optional fields have values. +func TestEncodeDecode4(t *testing.T) { + pb := initGoTest(true) + pb.Table = String("hello") + pb.Param = Int32(7) + pb.OptionalField = initGoTestField() + pb.F_BoolOptional = Bool(true) + pb.F_Int32Optional = Int32(32) + pb.F_Int64Optional = Int64(64) + pb.F_Fixed32Optional = Uint32(3232) + pb.F_Fixed64Optional = Uint64(6464) + pb.F_Uint32Optional = Uint32(323232) + pb.F_Uint64Optional = Uint64(646464) + pb.F_FloatOptional = Float32(32.) + pb.F_DoubleOptional = Float64(64.) + pb.F_StringOptional = String("hello") + pb.F_BytesOptional = []byte("Bignose") + pb.F_Sint32Optional = Int32(-32) + pb.F_Sint64Optional = Int64(-64) + pb.F_Sfixed32Optional = Int32(-32) + pb.F_Sfixed64Optional = Int64(-64) + pb.Optionalgroup = initGoTest_OptionalGroup() + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "1205"+"68656c6c6f"+ // field 2, encoding 2, string "hello" + "1807"+ // field 3, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "320d"+"0a056c6162656c120474797065"+ // field 6, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "f00101"+ // field 30, encoding 0, value 1 + "f80120"+ // field 31, encoding 0, value 32 + "800240"+ // field 32, encoding 0, value 64 + "8d02a00c0000"+ // field 33, encoding 5, value 3232 + "91024019000000000000"+ // field 34, encoding 1, value 6464 + "9802a0dd13"+ // field 35, encoding 0, value 323232 + "a002c0ba27"+ // field 36, encoding 0, value 646464 + "ad0200000042"+ // field 37, encoding 5, value 32.0 + "b1020000000000005040"+ // field 38, encoding 1, value 64.0 + "ba0205"+"68656c6c6f"+ // field 39, encoding 2, string "hello" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "d305"+ // start group field 90 level 1 + "da0508"+"6f7074696f6e616c"+ // field 91, encoding 2, string "optional" + "d405"+ // end group field 90 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 + "ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose" + "f0123f"+ // field 302, encoding 0, value 63 + "f8127f"+ // field 303, encoding 0, value 127 + "8513e0ffffff"+ // field 304, encoding 5, -32 fixed32 + "8913c0ffffffffffffff"+ // field 305, encoding 1, -64 fixed64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 + +} + +// All required fields set, defaults provided, all repeated fields given two values. +func TestEncodeDecode5(t *testing.T) { + pb := initGoTest(true) + pb.RepeatedField = []*GoTestField{initGoTestField(), initGoTestField()} + pb.F_BoolRepeated = []bool{false, true} + pb.F_Int32Repeated = []int32{32, 33} + pb.F_Int64Repeated = []int64{64, 65} + pb.F_Fixed32Repeated = []uint32{3232, 3333} + pb.F_Fixed64Repeated = []uint64{6464, 6565} + pb.F_Uint32Repeated = []uint32{323232, 333333} + pb.F_Uint64Repeated = []uint64{646464, 656565} + pb.F_FloatRepeated = []float32{32., 33.} + pb.F_DoubleRepeated = []float64{64., 65.} + pb.F_StringRepeated = []string{"hello", "sailor"} + pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")} + pb.F_Sint32Repeated = []int32{32, -32} + pb.F_Sint64Repeated = []int64{64, -64} + pb.F_Sfixed32Repeated = []int32{32, -32} + pb.F_Sfixed64Repeated = []int64{64, -64} + pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()} + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) + "2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "a00100"+ // field 20, encoding 0, value 0 + "a00101"+ // field 20, encoding 0, value 1 + "a80120"+ // field 21, encoding 0, value 32 + "a80121"+ // field 21, encoding 0, value 33 + "b00140"+ // field 22, encoding 0, value 64 + "b00141"+ // field 22, encoding 0, value 65 + "bd01a00c0000"+ // field 23, encoding 5, value 3232 + "bd01050d0000"+ // field 23, encoding 5, value 3333 + "c1014019000000000000"+ // field 24, encoding 1, value 6464 + "c101a519000000000000"+ // field 24, encoding 1, value 6565 + "c801a0dd13"+ // field 25, encoding 0, value 323232 + "c80195ac14"+ // field 25, encoding 0, value 333333 + "d001c0ba27"+ // field 26, encoding 0, value 646464 + "d001b58928"+ // field 26, encoding 0, value 656565 + "dd0100000042"+ // field 27, encoding 5, value 32.0 + "dd0100000442"+ // field 27, encoding 5, value 33.0 + "e1010000000000005040"+ // field 28, encoding 1, value 64.0 + "e1010000000000405040"+ // field 28, encoding 1, value 65.0 + "ea0105"+"68656c6c6f"+ // field 29, encoding 2, string "hello" + "ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor" + "c00201"+ // field 40, encoding 0, value 1 + "c80220"+ // field 41, encoding 0, value 32 + "d00240"+ // field 42, encoding 0, value 64 + "dd0240010000"+ // field 43, encoding 5, value 320 + "e1028002000000000000"+ // field 44, encoding 1, value 640 + "e8028019"+ // field 45, encoding 0, value 3200 + "f0028032"+ // field 46, encoding 0, value 6400 + "fd02e0659948"+ // field 47, encoding 5, value 314159.0 + "81030000000050971041"+ // field 48, encoding 1, value 271828.0 + "8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n" + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "8305"+ // start group field 80 level 1 + "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" + "8405"+ // end group field 80 level 1 + "8305"+ // start group field 80 level 1 + "8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated" + "8405"+ // end group field 80 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 + "ca0c03"+"626967"+ // field 201, encoding 2, string "big" + "ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose" + "d00c40"+ // field 202, encoding 0, value 32 + "d00c3f"+ // field 202, encoding 0, value -32 + "d80c8001"+ // field 203, encoding 0, value 64 + "d80c7f"+ // field 203, encoding 0, value -64 + "e50c20000000"+ // field 204, encoding 5, 32 fixed32 + "e50ce0ffffff"+ // field 204, encoding 5, -32 fixed32 + "e90c4000000000000000"+ // field 205, encoding 1, 64 fixed64 + "e90cc0ffffffffffffff"+ // field 205, encoding 1, -64 fixed64 + "8a1907"+"4269676e6f7365"+ // field 401, encoding 2, string "Bignose" + "90193f"+ // field 402, encoding 0, value 63 + "98197f"+ // field 403, encoding 0, value 127 + "a519e0ffffff"+ // field 404, encoding 5, -32 fixed32 + "a919c0ffffffffffffff") // field 405, encoding 1, -64 fixed64 + +} + +// All required fields set, all packed repeated fields given two values. +func TestEncodeDecode6(t *testing.T) { + pb := initGoTest(false) + pb.F_BoolRepeatedPacked = []bool{false, true} + pb.F_Int32RepeatedPacked = []int32{32, 33} + pb.F_Int64RepeatedPacked = []int64{64, 65} + pb.F_Fixed32RepeatedPacked = []uint32{3232, 3333} + pb.F_Fixed64RepeatedPacked = []uint64{6464, 6565} + pb.F_Uint32RepeatedPacked = []uint32{323232, 333333} + pb.F_Uint64RepeatedPacked = []uint64{646464, 656565} + pb.F_FloatRepeatedPacked = []float32{32., 33.} + pb.F_DoubleRepeatedPacked = []float64{64., 65.} + pb.F_Sint32RepeatedPacked = []int32{32, -32} + pb.F_Sint64RepeatedPacked = []int64{64, -64} + pb.F_Sfixed32RepeatedPacked = []int32{32, -32} + pb.F_Sfixed64RepeatedPacked = []int64{64, -64} + + overify(t, pb, + "0807"+ // field 1, encoding 0, value 7 + "220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField) + "5001"+ // field 10, encoding 0, value 1 + "5803"+ // field 11, encoding 0, value 3 + "6006"+ // field 12, encoding 0, value 6 + "6d20000000"+ // field 13, encoding 5, value 32 + "714000000000000000"+ // field 14, encoding 1, value 64 + "78a019"+ // field 15, encoding 0, value 3232 + "8001c032"+ // field 16, encoding 0, value 6464 + "8d0100004a45"+ // field 17, encoding 5, value 3232.0 + "9101000000000040b940"+ // field 18, encoding 1, value 6464.0 + "9a0106"+"737472696e67"+ // field 19, encoding 2 string "string" + "9203020001"+ // field 50, encoding 2, 2 bytes, value 0, value 1 + "9a03022021"+ // field 51, encoding 2, 2 bytes, value 32, value 33 + "a203024041"+ // field 52, encoding 2, 2 bytes, value 64, value 65 + "aa0308"+ // field 53, encoding 2, 8 bytes + "a00c0000050d0000"+ // value 3232, value 3333 + "b20310"+ // field 54, encoding 2, 16 bytes + "4019000000000000a519000000000000"+ // value 6464, value 6565 + "ba0306"+ // field 55, encoding 2, 6 bytes + "a0dd1395ac14"+ // value 323232, value 333333 + "c20306"+ // field 56, encoding 2, 6 bytes + "c0ba27b58928"+ // value 646464, value 656565 + "ca0308"+ // field 57, encoding 2, 8 bytes + "0000004200000442"+ // value 32.0, value 33.0 + "d20310"+ // field 58, encoding 2, 16 bytes + "00000000000050400000000000405040"+ // value 64.0, value 65.0 + "b304"+ // start group field 70 level 1 + "ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required" + "b404"+ // end group field 70 level 1 + "aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes" + "b0063f"+ // field 102, encoding 0, 0x3f zigzag32 + "b8067f"+ // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff"+ // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff"+ // field 105, encoding 1, -64 fixed64 + "b21f02"+ // field 502, encoding 2, 2 bytes + "403f"+ // value 32, value -32 + "ba1f03"+ // field 503, encoding 2, 3 bytes + "80017f"+ // value 64, value -64 + "c21f08"+ // field 504, encoding 2, 8 bytes + "20000000e0ffffff"+ // value 32, value -32 + "ca1f10"+ // field 505, encoding 2, 16 bytes + "4000000000000000c0ffffffffffffff") // value 64, value -64 + +} + +// Test that we can encode empty bytes fields. +func TestEncodeDecodeBytes1(t *testing.T) { + pb := initGoTest(false) + + // Create our bytes + pb.F_BytesRequired = []byte{} + pb.F_BytesRepeated = [][]byte{{}} + pb.F_BytesOptional = []byte{} + + d, err := Marshal(pb) + if err != nil { + t.Error(err) + } + + pbd := new(GoTest) + if err := Unmarshal(d, pbd); err != nil { + t.Error(err) + } + + if pbd.F_BytesRequired == nil || len(pbd.F_BytesRequired) != 0 { + t.Error("required empty bytes field is incorrect") + } + if pbd.F_BytesRepeated == nil || len(pbd.F_BytesRepeated) == 1 && pbd.F_BytesRepeated[0] == nil { + t.Error("repeated empty bytes field is incorrect") + } + if pbd.F_BytesOptional == nil || len(pbd.F_BytesOptional) != 0 { + t.Error("optional empty bytes field is incorrect") + } +} + +// Test that we encode nil-valued fields of a repeated bytes field correctly. +// Since entries in a repeated field cannot be nil, nil must mean empty value. +func TestEncodeDecodeBytes2(t *testing.T) { + pb := initGoTest(false) + + // Create our bytes + pb.F_BytesRepeated = [][]byte{nil} + + d, err := Marshal(pb) + if err != nil { + t.Error(err) + } + + pbd := new(GoTest) + if err := Unmarshal(d, pbd); err != nil { + t.Error(err) + } + + if len(pbd.F_BytesRepeated) != 1 || pbd.F_BytesRepeated[0] == nil { + t.Error("Unexpected value for repeated bytes field") + } +} + +// All required fields set, defaults provided, all repeated fields given two values. +func TestSkippingUnrecognizedFields(t *testing.T) { + o := old() + pb := initGoTestField() + + // Marshal it normally. + o.Marshal(pb) + + // Now new a GoSkipTest record. + skip := &GoSkipTest{ + SkipInt32: Int32(32), + SkipFixed32: Uint32(3232), + SkipFixed64: Uint64(6464), + SkipString: String("skipper"), + Skipgroup: &GoSkipTest_SkipGroup{ + GroupInt32: Int32(75), + GroupString: String("wxyz"), + }, + } + + // Marshal it into same buffer. + o.Marshal(skip) + + pbd := new(GoTestField) + o.Unmarshal(pbd) + + // The __unrecognized field should be a marshaling of GoSkipTest + skipd := new(GoSkipTest) + + o.SetBuf(pbd.XXX_unrecognized) + o.Unmarshal(skipd) + + if *skipd.SkipInt32 != *skip.SkipInt32 { + t.Error("skip int32", skipd.SkipInt32) + } + if *skipd.SkipFixed32 != *skip.SkipFixed32 { + t.Error("skip fixed32", skipd.SkipFixed32) + } + if *skipd.SkipFixed64 != *skip.SkipFixed64 { + t.Error("skip fixed64", skipd.SkipFixed64) + } + if *skipd.SkipString != *skip.SkipString { + t.Error("skip string", *skipd.SkipString) + } + if *skipd.Skipgroup.GroupInt32 != *skip.Skipgroup.GroupInt32 { + t.Error("skip group int32", skipd.Skipgroup.GroupInt32) + } + if *skipd.Skipgroup.GroupString != *skip.Skipgroup.GroupString { + t.Error("skip group string", *skipd.Skipgroup.GroupString) + } +} + +// Check that unrecognized fields of a submessage are preserved. +func TestSubmessageUnrecognizedFields(t *testing.T) { + nm := &NewMessage{ + Nested: &NewMessage_Nested{ + Name: String("Nigel"), + FoodGroup: String("carbs"), + }, + } + b, err := Marshal(nm) + if err != nil { + t.Fatalf("Marshal of NewMessage: %v", err) + } + + // Unmarshal into an OldMessage. + om := new(OldMessage) + if err := Unmarshal(b, om); err != nil { + t.Fatalf("Unmarshal to OldMessage: %v", err) + } + exp := &OldMessage{ + Nested: &OldMessage_Nested{ + Name: String("Nigel"), + // normal protocol buffer users should not do this + XXX_unrecognized: []byte("\x12\x05carbs"), + }, + } + if !Equal(om, exp) { + t.Errorf("om = %v, want %v", om, exp) + } + + // Clone the OldMessage. + om = Clone(om).(*OldMessage) + if !Equal(om, exp) { + t.Errorf("Clone(om) = %v, want %v", om, exp) + } + + // Marshal the OldMessage, then unmarshal it into an empty NewMessage. + if b, err = Marshal(om); err != nil { + t.Fatalf("Marshal of OldMessage: %v", err) + } + t.Logf("Marshal(%v) -> %q", om, b) + nm2 := new(NewMessage) + if err := Unmarshal(b, nm2); err != nil { + t.Fatalf("Unmarshal to NewMessage: %v", err) + } + if !Equal(nm, nm2) { + t.Errorf("NewMessage round-trip: %v => %v", nm, nm2) + } +} + +// Check that an int32 field can be upgraded to an int64 field. +func TestNegativeInt32(t *testing.T) { + om := &OldMessage{ + Num: Int32(-1), + } + b, err := Marshal(om) + if err != nil { + t.Fatalf("Marshal of OldMessage: %v", err) + } + + // Check the size. It should be 11 bytes; + // 1 for the field/wire type, and 10 for the negative number. + if len(b) != 11 { + t.Errorf("%v marshaled as %q, wanted 11 bytes", om, b) + } + + // Unmarshal into a NewMessage. + nm := new(NewMessage) + if err := Unmarshal(b, nm); err != nil { + t.Fatalf("Unmarshal to NewMessage: %v", err) + } + want := &NewMessage{ + Num: Int64(-1), + } + if !Equal(nm, want) { + t.Errorf("nm = %v, want %v", nm, want) + } +} + +// Check that we can grow an array (repeated field) to have many elements. +// This test doesn't depend only on our encoding; for variety, it makes sure +// we create, encode, and decode the correct contents explicitly. It's therefore +// a bit messier. +// This test also uses (and hence tests) the Marshal/Unmarshal functions +// instead of the methods. +func TestBigRepeated(t *testing.T) { + pb := initGoTest(true) + + // Create the arrays + const N = 50 // Internally the library starts much smaller. + pb.Repeatedgroup = make([]*GoTest_RepeatedGroup, N) + pb.F_Sint64Repeated = make([]int64, N) + pb.F_Sint32Repeated = make([]int32, N) + pb.F_BytesRepeated = make([][]byte, N) + pb.F_StringRepeated = make([]string, N) + pb.F_DoubleRepeated = make([]float64, N) + pb.F_FloatRepeated = make([]float32, N) + pb.F_Uint64Repeated = make([]uint64, N) + pb.F_Uint32Repeated = make([]uint32, N) + pb.F_Fixed64Repeated = make([]uint64, N) + pb.F_Fixed32Repeated = make([]uint32, N) + pb.F_Int64Repeated = make([]int64, N) + pb.F_Int32Repeated = make([]int32, N) + pb.F_BoolRepeated = make([]bool, N) + pb.RepeatedField = make([]*GoTestField, N) + + // Fill in the arrays with checkable values. + igtf := initGoTestField() + igtrg := initGoTest_RepeatedGroup() + for i := 0; i < N; i++ { + pb.Repeatedgroup[i] = igtrg + pb.F_Sint64Repeated[i] = int64(i) + pb.F_Sint32Repeated[i] = int32(i) + s := fmt.Sprint(i) + pb.F_BytesRepeated[i] = []byte(s) + pb.F_StringRepeated[i] = s + pb.F_DoubleRepeated[i] = float64(i) + pb.F_FloatRepeated[i] = float32(i) + pb.F_Uint64Repeated[i] = uint64(i) + pb.F_Uint32Repeated[i] = uint32(i) + pb.F_Fixed64Repeated[i] = uint64(i) + pb.F_Fixed32Repeated[i] = uint32(i) + pb.F_Int64Repeated[i] = int64(i) + pb.F_Int32Repeated[i] = int32(i) + pb.F_BoolRepeated[i] = i%2 == 0 + pb.RepeatedField[i] = igtf + } + + // Marshal. + buf, _ := Marshal(pb) + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + Unmarshal(buf, pbd) + + // Check the checkable values + for i := uint64(0); i < N; i++ { + if pbd.Repeatedgroup[i] == nil { // TODO: more checking? + t.Error("pbd.Repeatedgroup bad") + } + if x := uint64(pbd.F_Sint64Repeated[i]); x != i { + t.Error("pbd.F_Sint64Repeated bad", x, i) + } + if x := uint64(pbd.F_Sint32Repeated[i]); x != i { + t.Error("pbd.F_Sint32Repeated bad", x, i) + } + s := fmt.Sprint(i) + equalbytes(pbd.F_BytesRepeated[i], []byte(s), t) + if pbd.F_StringRepeated[i] != s { + t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i) + } + if x := uint64(pbd.F_DoubleRepeated[i]); x != i { + t.Error("pbd.F_DoubleRepeated bad", x, i) + } + if x := uint64(pbd.F_FloatRepeated[i]); x != i { + t.Error("pbd.F_FloatRepeated bad", x, i) + } + if x := pbd.F_Uint64Repeated[i]; x != i { + t.Error("pbd.F_Uint64Repeated bad", x, i) + } + if x := uint64(pbd.F_Uint32Repeated[i]); x != i { + t.Error("pbd.F_Uint32Repeated bad", x, i) + } + if x := pbd.F_Fixed64Repeated[i]; x != i { + t.Error("pbd.F_Fixed64Repeated bad", x, i) + } + if x := uint64(pbd.F_Fixed32Repeated[i]); x != i { + t.Error("pbd.F_Fixed32Repeated bad", x, i) + } + if x := uint64(pbd.F_Int64Repeated[i]); x != i { + t.Error("pbd.F_Int64Repeated bad", x, i) + } + if x := uint64(pbd.F_Int32Repeated[i]); x != i { + t.Error("pbd.F_Int32Repeated bad", x, i) + } + if x := pbd.F_BoolRepeated[i]; x != (i%2 == 0) { + t.Error("pbd.F_BoolRepeated bad", x, i) + } + if pbd.RepeatedField[i] == nil { // TODO: more checking? + t.Error("pbd.RepeatedField bad") + } + } +} + +func TestBadWireTypeUnknown(t *testing.T) { + var b []byte + fmt.Sscanf("0a01780d00000000080b101612036161611521000000202c220362626225370000002203636363214200000000000000584d5a036464645900000000000056405d63000000", "%x", &b) + + m := new(MyMessage) + if err := Unmarshal(b, m); err != nil { + t.Errorf("unexpected Unmarshal error: %v", err) + } + + var unknown []byte + fmt.Sscanf("0a01780d0000000010161521000000202c2537000000214200000000000000584d5a036464645d63000000", "%x", &unknown) + if !bytes.Equal(m.XXX_unrecognized, unknown) { + t.Errorf("unknown bytes mismatch:\ngot %x\nwant %x", m.XXX_unrecognized, unknown) + } + DiscardUnknown(m) + + want := &MyMessage{Count: Int32(11), Name: String("aaa"), Pet: []string{"bbb", "ccc"}, Bigfloat: Float64(88)} + if !Equal(m, want) { + t.Errorf("message mismatch:\ngot %v\nwant %v", m, want) + } +} + +func encodeDecode(t *testing.T, in, out Message, msg string) { + buf, err := Marshal(in) + if err != nil { + t.Fatalf("failed marshaling %v: %v", msg, err) + } + if err := Unmarshal(buf, out); err != nil { + t.Fatalf("failed unmarshaling %v: %v", msg, err) + } +} + +func TestPackedNonPackedDecoderSwitching(t *testing.T) { + np, p := new(NonPackedTest), new(PackedTest) + + // non-packed -> packed + np.A = []int32{0, 1, 1, 2, 3, 5} + encodeDecode(t, np, p, "non-packed -> packed") + if !reflect.DeepEqual(np.A, p.B) { + t.Errorf("failed non-packed -> packed; np.A=%+v, p.B=%+v", np.A, p.B) + } + + // packed -> non-packed + np.Reset() + p.B = []int32{3, 1, 4, 1, 5, 9} + encodeDecode(t, p, np, "packed -> non-packed") + if !reflect.DeepEqual(p.B, np.A) { + t.Errorf("failed packed -> non-packed; p.B=%+v, np.A=%+v", p.B, np.A) + } +} + +func TestProto1RepeatedGroup(t *testing.T) { + pb := &MessageList{ + Message: []*MessageList_Message{ + { + Name: String("blah"), + Count: Int32(7), + }, + // NOTE: pb.Message[1] is a nil + nil, + }, + } + + o := old() + err := o.Marshal(pb) + if err == nil || !strings.Contains(err.Error(), "repeated field Message has nil") { + t.Fatalf("unexpected or no error when marshaling: %v", err) + } +} + +// Test that enums work. Checks for a bug introduced by making enums +// named types instead of int32: newInt32FromUint64 would crash with +// a type mismatch in reflect.PointTo. +func TestEnum(t *testing.T) { + pb := new(GoEnum) + pb.Foo = FOO_FOO1.Enum() + o := old() + if err := o.Marshal(pb); err != nil { + t.Fatal("error encoding enum:", err) + } + pb1 := new(GoEnum) + if err := o.Unmarshal(pb1); err != nil { + t.Fatal("error decoding enum:", err) + } + if *pb1.Foo != FOO_FOO1 { + t.Error("expected 7 but got ", *pb1.Foo) + } +} + +// Enum types have String methods. Check that enum fields can be printed. +// We don't care what the value actually is, just as long as it doesn't crash. +func TestPrintingNilEnumFields(t *testing.T) { + pb := new(GoEnum) + _ = fmt.Sprintf("%+v", pb) +} + +// Verify that absent required fields cause Marshal/Unmarshal to return errors. +func TestRequiredFieldEnforcement(t *testing.T) { + pb := new(GoTestField) + _, err := Marshal(pb) + if err == nil { + t.Error("marshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Label") { + t.Errorf("marshal: bad error type: %v", err) + } + + // A slightly sneaky, yet valid, proto. It encodes the same required field twice, + // so simply counting the required fields is insufficient. + // field 1, encoding 2, value "hi" + buf := []byte("\x0A\x02hi\x0A\x02hi") + err = Unmarshal(buf, pb) + if err == nil { + t.Error("unmarshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Type") && !strings.Contains(err.Error(), "{Unknown}") { + // TODO: remove unknown cases once we commit to the new unmarshaler. + t.Errorf("unmarshal: bad error type: %v", err) + } +} + +// Verify that absent required fields in groups cause Marshal/Unmarshal to return errors. +func TestRequiredFieldEnforcementGroups(t *testing.T) { + pb := &GoTestRequiredGroupField{Group: &GoTestRequiredGroupField_Group{}} + if _, err := Marshal(pb); err == nil { + t.Error("marshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.Field") { + t.Errorf("marshal: bad error type: %v", err) + } + + buf := []byte{11, 12} + if err := Unmarshal(buf, pb); err == nil { + t.Error("unmarshal: expected error, got nil") + } else if _, ok := err.(*RequiredNotSetError); !ok || !strings.Contains(err.Error(), "Group.Field") && !strings.Contains(err.Error(), "Group.{Unknown}") { + t.Errorf("unmarshal: bad error type: %v", err) + } +} + +func TestTypedNilMarshal(t *testing.T) { + // A typed nil should return ErrNil and not crash. + { + var m *GoEnum + if _, err := Marshal(m); err != ErrNil { + t.Errorf("Marshal(%#v): got %v, want ErrNil", m, err) + } + } + + { + m := &Communique{Union: &Communique_Msg{nil}} + if _, err := Marshal(m); err == nil || err == ErrNil { + t.Errorf("Marshal(%#v): got %v, want errOneofHasNil", m, err) + } + } +} + +// A type that implements the Marshaler interface, but is not nillable. +type nonNillableInt uint64 + +func (nni nonNillableInt) Marshal() ([]byte, error) { + return EncodeVarint(uint64(nni)), nil +} + +type NNIMessage struct { + nni nonNillableInt +} + +func (*NNIMessage) Reset() {} +func (*NNIMessage) String() string { return "" } +func (*NNIMessage) ProtoMessage() {} + +type NMMessage struct{} + +func (*NMMessage) Reset() {} +func (*NMMessage) String() string { return "" } +func (*NMMessage) ProtoMessage() {} + +// Verify a type that uses the Marshaler interface, but has a nil pointer. +func TestNilMarshaler(t *testing.T) { + // Try a struct with a Marshaler field that is nil. + // It should be directly marshable. + nmm := new(NMMessage) + if _, err := Marshal(nmm); err != nil { + t.Error("unexpected error marshaling nmm: ", err) + } + + // Try a struct with a Marshaler field that is not nillable. + nnim := new(NNIMessage) + nnim.nni = 7 + var _ Marshaler = nnim.nni // verify it is truly a Marshaler + if _, err := Marshal(nnim); err != nil { + t.Error("unexpected error marshaling nnim: ", err) + } +} + +func TestAllSetDefaults(t *testing.T) { + // Exercise SetDefaults with all scalar field types. + m := &Defaults{ + // NaN != NaN, so override that here. + F_Nan: Float32(1.7), + } + expected := &Defaults{ + F_Bool: Bool(true), + F_Int32: Int32(32), + F_Int64: Int64(64), + F_Fixed32: Uint32(320), + F_Fixed64: Uint64(640), + F_Uint32: Uint32(3200), + F_Uint64: Uint64(6400), + F_Float: Float32(314159), + F_Double: Float64(271828), + F_String: String(`hello, "world!"` + "\n"), + F_Bytes: []byte("Bignose"), + F_Sint32: Int32(-32), + F_Sint64: Int64(-64), + F_Enum: Defaults_GREEN.Enum(), + F_Pinf: Float32(float32(math.Inf(1))), + F_Ninf: Float32(float32(math.Inf(-1))), + F_Nan: Float32(1.7), + StrZero: String(""), + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("SetDefaults failed\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultsWithSetField(t *testing.T) { + // Check that a set value is not overridden. + m := &Defaults{ + F_Int32: Int32(12), + } + SetDefaults(m) + if v := m.GetF_Int32(); v != 12 { + t.Errorf("m.FInt32 = %v, want 12", v) + } +} + +func TestSetDefaultsWithSubMessage(t *testing.T) { + m := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("gopher"), + }, + } + expected := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("gopher"), + Port: Int32(4000), + }, + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultsWithRepeatedSubMessage(t *testing.T) { + m := &MyMessage{ + RepInner: []*InnerMessage{{}}, + } + expected := &MyMessage{ + RepInner: []*InnerMessage{{ + Port: Int32(4000), + }}, + } + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestSetDefaultWithRepeatedNonMessage(t *testing.T) { + m := &MyMessage{ + Pet: []string{"turtle", "wombat"}, + } + expected := Clone(m) + SetDefaults(m) + if !Equal(m, expected) { + t.Errorf("\n got %v\nwant %v", m, expected) + } +} + +func TestMaximumTagNumber(t *testing.T) { + m := &MaxTag{ + LastField: String("natural goat essence"), + } + buf, err := Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal failed: %v", err) + } + m2 := new(MaxTag) + if err := Unmarshal(buf, m2); err != nil { + t.Fatalf("proto.Unmarshal failed: %v", err) + } + if got, want := m2.GetLastField(), *m.LastField; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func TestJSON(t *testing.T) { + m := &MyMessage{ + Count: Int32(4), + Pet: []string{"bunny", "kitty"}, + Inner: &InnerMessage{ + Host: String("cauchy"), + }, + Bikeshed: MyMessage_GREEN.Enum(), + } + const expected = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":1}` + + b, err := json.Marshal(m) + if err != nil { + t.Fatalf("json.Marshal failed: %v", err) + } + s := string(b) + if s != expected { + t.Errorf("got %s\nwant %s", s, expected) + } + + received := new(MyMessage) + if err := json.Unmarshal(b, received); err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + if !Equal(received, m) { + t.Fatalf("got %s, want %s", received, m) + } + + // Test unmarshalling of JSON with symbolic enum name. + const old = `{"count":4,"pet":["bunny","kitty"],"inner":{"host":"cauchy"},"bikeshed":"GREEN"}` + received.Reset() + if err := json.Unmarshal([]byte(old), received); err != nil { + t.Fatalf("json.Unmarshal failed: %v", err) + } + if !Equal(received, m) { + t.Fatalf("got %s, want %s", received, m) + } +} + +func TestBadWireType(t *testing.T) { + b := []byte{7<<3 | 6} // field 7, wire type 6 + pb := new(OtherMessage) + if err := Unmarshal(b, pb); err == nil { + t.Errorf("Unmarshal did not fail") + } else if !strings.Contains(err.Error(), "unknown wire type") { + t.Errorf("wrong error: %v", err) + } +} + +func TestBytesWithInvalidLength(t *testing.T) { + // If a byte sequence has an invalid (negative) length, Unmarshal should not panic. + b := []byte{2<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0} + Unmarshal(b, new(MyMessage)) +} + +func TestLengthOverflow(t *testing.T) { + // Overflowing a length should not panic. + b := []byte{2<<3 | WireBytes, 1, 1, 3<<3 | WireBytes, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01} + Unmarshal(b, new(MyMessage)) +} + +func TestVarintOverflow(t *testing.T) { + // Overflowing a 64-bit length should not be allowed. + b := []byte{1<<3 | WireVarint, 0x01, 3<<3 | WireBytes, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01} + if err := Unmarshal(b, new(MyMessage)); err == nil { + t.Fatalf("Overflowed uint64 length without error") + } +} + +func TestBytesWithInvalidLengthInGroup(t *testing.T) { + // Overflowing a 64-bit length should not be allowed. + b := []byte{0xbb, 0x30, 0xb2, 0x30, 0xb0, 0xb2, 0x83, 0xf1, 0xb0, 0xb2, 0xef, 0xbf, 0xbd, 0x01} + if err := Unmarshal(b, new(MyMessage)); err == nil { + t.Fatalf("Overflowed uint64 length without error") + } +} + +func TestUnmarshalFuzz(t *testing.T) { + const N = 1000 + seed := time.Now().UnixNano() + t.Logf("RNG seed is %d", seed) + rng := rand.New(rand.NewSource(seed)) + buf := make([]byte, 20) + for i := 0; i < N; i++ { + for j := range buf { + buf[j] = byte(rng.Intn(256)) + } + fuzzUnmarshal(t, buf) + } +} + +func TestMergeMessages(t *testing.T) { + pb := &MessageList{Message: []*MessageList_Message{{Name: String("x"), Count: Int32(1)}}} + data, err := Marshal(pb) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + pb1 := new(MessageList) + if err := Unmarshal(data, pb1); err != nil { + t.Fatalf("first Unmarshal: %v", err) + } + if err := Unmarshal(data, pb1); err != nil { + t.Fatalf("second Unmarshal: %v", err) + } + if len(pb1.Message) != 1 { + t.Errorf("two Unmarshals produced %d Messages, want 1", len(pb1.Message)) + } + + pb2 := new(MessageList) + if err := UnmarshalMerge(data, pb2); err != nil { + t.Fatalf("first UnmarshalMerge: %v", err) + } + if err := UnmarshalMerge(data, pb2); err != nil { + t.Fatalf("second UnmarshalMerge: %v", err) + } + if len(pb2.Message) != 2 { + t.Errorf("two UnmarshalMerges produced %d Messages, want 2", len(pb2.Message)) + } +} + +func TestExtensionMarshalOrder(t *testing.T) { + m := &MyMessage{Count: Int(123)} + if err := SetExtension(m, E_Ext_More, &Ext{Data: String("alpha")}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + if err := SetExtension(m, E_Ext_Text, String("aleph")); err != nil { + t.Fatalf("SetExtension: %v", err) + } + if err := SetExtension(m, E_Ext_Number, Int32(1)); err != nil { + t.Fatalf("SetExtension: %v", err) + } + + // Serialize m several times, and check we get the same bytes each time. + var orig []byte + for i := 0; i < 100; i++ { + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if i == 0 { + orig = b + continue + } + if !bytes.Equal(b, orig) { + t.Errorf("Bytes differ on attempt #%d", i) + } + } +} + +func TestExtensionMapFieldMarshalDeterministic(t *testing.T) { + m := &MyMessage{Count: Int(123)} + if err := SetExtension(m, E_Ext_More, &Ext{MapField: map[int32]int32{1: 1, 2: 2, 3: 3, 4: 4}}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + marshal := func(m Message) []byte { + var b Buffer + b.SetDeterministic(true) + if err := b.Marshal(m); err != nil { + t.Fatalf("Marshal failed: %v", err) + } + return b.Bytes() + } + + want := marshal(m) + for i := 0; i < 100; i++ { + if got := marshal(m); !bytes.Equal(got, want) { + t.Errorf("Marshal produced inconsistent output with determinism enabled (pass %d).\n got %v\nwant %v", i, got, want) + } + } +} + +// Many extensions, because small maps might not iterate differently on each iteration. +var exts = []*ExtensionDesc{ + E_X201, + E_X202, + E_X203, + E_X204, + E_X205, + E_X206, + E_X207, + E_X208, + E_X209, + E_X210, + E_X211, + E_X212, + E_X213, + E_X214, + E_X215, + E_X216, + E_X217, + E_X218, + E_X219, + E_X220, + E_X221, + E_X222, + E_X223, + E_X224, + E_X225, + E_X226, + E_X227, + E_X228, + E_X229, + E_X230, + E_X231, + E_X232, + E_X233, + E_X234, + E_X235, + E_X236, + E_X237, + E_X238, + E_X239, + E_X240, + E_X241, + E_X242, + E_X243, + E_X244, + E_X245, + E_X246, + E_X247, + E_X248, + E_X249, + E_X250, +} + +func TestMessageSetMarshalOrder(t *testing.T) { + m := &MyMessageSet{} + for _, x := range exts { + if err := SetExtension(m, x, &Empty{}); err != nil { + t.Fatalf("SetExtension: %v", err) + } + } + + buf, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + // Serialize m several times, and check we get the same bytes each time. + for i := 0; i < 10; i++ { + b1, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if !bytes.Equal(b1, buf) { + t.Errorf("Bytes differ on re-Marshal #%d", i) + } + + m2 := &MyMessageSet{} + if err := Unmarshal(buf, m2); err != nil { + t.Errorf("Unmarshal: %v", err) + } + b2, err := Marshal(m2) + if err != nil { + t.Errorf("re-Marshal: %v", err) + } + if !bytes.Equal(b2, buf) { + t.Errorf("Bytes differ on round-trip #%d", i) + } + } +} + +func TestUnmarshalMergesMessages(t *testing.T) { + // If a nested message occurs twice in the input, + // the fields should be merged when decoding. + a := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("polhode"), + Port: Int32(1234), + }, + } + aData, err := Marshal(a) + if err != nil { + t.Fatalf("Marshal(a): %v", err) + } + b := &OtherMessage{ + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Connected: Bool(true), + }, + } + bData, err := Marshal(b) + if err != nil { + t.Fatalf("Marshal(b): %v", err) + } + want := &OtherMessage{ + Key: Int64(123), + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Port: Int32(1234), + Connected: Bool(true), + }, + } + got := new(OtherMessage) + if err := Unmarshal(append(aData, bData...), got); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + +func TestUnmarshalMergesGroups(t *testing.T) { + // If a nested group occurs twice in the input, + // the fields should be merged when decoding. + a := &GroupNew{ + G: &GroupNew_G{ + X: Int32(7), + Y: Int32(8), + }, + } + aData, err := Marshal(a) + if err != nil { + t.Fatalf("Marshal(a): %v", err) + } + b := &GroupNew{ + G: &GroupNew_G{ + X: Int32(9), + }, + } + bData, err := Marshal(b) + if err != nil { + t.Fatalf("Marshal(b): %v", err) + } + want := &GroupNew{ + G: &GroupNew_G{ + X: Int32(9), + Y: Int32(8), + }, + } + got := new(GroupNew) + if err := Unmarshal(append(aData, bData...), got); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + +func TestEncodingSizes(t *testing.T) { + tests := []struct { + m Message + n int + }{ + {&Defaults{F_Int32: Int32(math.MaxInt32)}, 6}, + {&Defaults{F_Int32: Int32(math.MinInt32)}, 11}, + {&Defaults{F_Uint32: Uint32(uint32(math.MaxInt32) + 1)}, 6}, + {&Defaults{F_Uint32: Uint32(math.MaxUint32)}, 6}, + } + for _, test := range tests { + b, err := Marshal(test.m) + if err != nil { + t.Errorf("Marshal(%v): %v", test.m, err) + continue + } + if len(b) != test.n { + t.Errorf("Marshal(%v) yielded %d bytes, want %d bytes", test.m, len(b), test.n) + } + } +} + +func TestRequiredNotSetError(t *testing.T) { + pb := initGoTest(false) + pb.RequiredField.Label = nil + pb.F_Int32Required = nil + pb.F_Int64Required = nil + + expected := "0807" + // field 1, encoding 0, value 7 + "2206" + "120474797065" + // field 4, encoding 2 (GoTestField) + "5001" + // field 10, encoding 0, value 1 + "6d20000000" + // field 13, encoding 5, value 0x20 + "714000000000000000" + // field 14, encoding 1, value 0x40 + "78a019" + // field 15, encoding 0, value 0xca0 = 3232 + "8001c032" + // field 16, encoding 0, value 0x1940 = 6464 + "8d0100004a45" + // field 17, encoding 5, value 3232.0 + "9101000000000040b940" + // field 18, encoding 1, value 6464.0 + "9a0106" + "737472696e67" + // field 19, encoding 2, string "string" + "b304" + // field 70, encoding 3, start group + "ba0408" + "7265717569726564" + // field 71, encoding 2, string "required" + "b404" + // field 70, encoding 4, end group + "aa0605" + "6279746573" + // field 101, encoding 2, string "bytes" + "b0063f" + // field 102, encoding 0, 0x3f zigzag32 + "b8067f" + // field 103, encoding 0, 0x7f zigzag64 + "c506e0ffffff" + // field 104, encoding 5, -32 fixed32 + "c906c0ffffffffffffff" // field 105, encoding 1, -64 fixed64 + + o := old() + bytes, err := Marshal(pb) + if _, ok := err.(*RequiredNotSetError); !ok { + fmt.Printf("marshal-1 err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", bytes) + t.Fatalf("expected = %s", expected) + } + if !strings.Contains(err.Error(), "RequiredField.Label") { + t.Errorf("marshal-1 wrong err msg: %v", err) + } + if !equal(bytes, expected, t) { + o.DebugPrint("neq 1", bytes) + t.Fatalf("expected = %s", expected) + } + + // Now test Unmarshal by recreating the original buffer. + pbd := new(GoTest) + err = Unmarshal(bytes, pbd) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Fatalf("unmarshal err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", bytes) + t.Fatalf("string = %s", expected) + } + if !strings.Contains(err.Error(), "RequiredField.Label") && !strings.Contains(err.Error(), "RequiredField.{Unknown}") { + t.Errorf("unmarshal wrong err msg: %v", err) + } + bytes, err = Marshal(pbd) + if _, ok := err.(*RequiredNotSetError); !ok { + t.Errorf("marshal-2 err = %v, want *RequiredNotSetError", err) + o.DebugPrint("", bytes) + t.Fatalf("string = %s", expected) + } + if !strings.Contains(err.Error(), "RequiredField.Label") { + t.Errorf("marshal-2 wrong err msg: %v", err) + } + if !equal(bytes, expected, t) { + o.DebugPrint("neq 2", bytes) + t.Fatalf("string = %s", expected) + } +} + +func TestRequiredNotSetErrorWithBadWireTypes(t *testing.T) { + // Required field expects a varint, and properly found a varint. + if err := Unmarshal([]byte{0x08, 0x00}, new(GoEnum)); err != nil { + t.Errorf("Unmarshal = %v, want nil", err) + } + // Required field expects a varint, but found a fixed32 instead. + if err := Unmarshal([]byte{0x0d, 0x00, 0x00, 0x00, 0x00}, new(GoEnum)); err == nil { + t.Errorf("Unmarshal = nil, want RequiredNotSetError") + } + // Required field expects a varint, and found both a varint and fixed32 (ignored). + m := new(GoEnum) + if err := Unmarshal([]byte{0x08, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00}, m); err != nil { + t.Errorf("Unmarshal = %v, want nil", err) + } + if !bytes.Equal(m.XXX_unrecognized, []byte{0x0d, 0x00, 0x00, 0x00, 0x00}) { + t.Errorf("expected fixed32 to appear as unknown bytes: %x", m.XXX_unrecognized) + } +} + +func fuzzUnmarshal(t *testing.T, data []byte) { + defer func() { + if e := recover(); e != nil { + t.Errorf("These bytes caused a panic: %+v", data) + t.Logf("Stack:\n%s", debug.Stack()) + t.FailNow() + } + }() + + pb := new(MyMessage) + Unmarshal(data, pb) +} + +func TestMapFieldMarshal(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + } + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + // b should be the concatenation of these three byte sequences in some order. + parts := []string{ + "\n\a\b\x01\x12\x03Rob", + "\n\a\b\x04\x12\x03Ian", + "\n\b\b\x08\x12\x04Dave", + } + ok := false + for i := range parts { + for j := range parts { + if j == i { + continue + } + for k := range parts { + if k == i || k == j { + continue + } + try := parts[i] + parts[j] + parts[k] + if bytes.Equal(b, []byte(try)) { + ok = true + break + } + } + } + } + if !ok { + t.Fatalf("Incorrect Marshal output.\n got %q\nwant %q (or a permutation of that)", b, parts[0]+parts[1]+parts[2]) + } + t.Logf("FYI b: %q", b) + + (new(Buffer)).DebugPrint("Dump of b", b) +} + +func TestMapFieldDeterministicMarshal(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + } + + marshal := func(m Message) []byte { + var b Buffer + b.SetDeterministic(true) + if err := b.Marshal(m); err != nil { + t.Fatalf("Marshal failed: %v", err) + } + return b.Bytes() + } + + want := marshal(m) + for i := 0; i < 10; i++ { + if got := marshal(m); !bytes.Equal(got, want) { + t.Errorf("Marshal produced inconsistent output with determinism enabled (pass %d).\n got %v\nwant %v", i, got, want) + } + } +} + +func TestMapFieldRoundTrips(t *testing.T) { + m := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Rob", + 4: "Ian", + 8: "Dave", + }, + MsgMapping: map[int64]*FloatingPoint{ + 0x7001: {F: Float64(2.0)}, + }, + ByteMapping: map[bool][]byte{ + false: []byte("that's not right!"), + true: []byte("aye, 'tis true!"), + }, + } + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + t.Logf("FYI b: %q", b) + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(m, m2) { + t.Errorf("Map did not survive a round trip.\ninitial: %v\n final: %v", m, m2) + } +} + +func TestMapFieldWithNil(t *testing.T) { + m1 := &MessageWithMap{ + MsgMapping: map[int64]*FloatingPoint{ + 1: nil, + }, + } + b, err := Marshal(m1) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) + } + if v, ok := m2.MsgMapping[1]; !ok { + t.Error("msg_mapping[1] not present") + } else if v != nil { + t.Errorf("msg_mapping[1] not nil: %v", v) + } +} + +func TestMapFieldWithNilBytes(t *testing.T) { + m1 := &MessageWithMap{ + ByteMapping: map[bool][]byte{ + false: {}, + true: nil, + }, + } + n := Size(m1) + b, err := Marshal(m1) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if n != len(b) { + t.Errorf("Size(m1) = %d; want len(Marshal(m1)) = %d", n, len(b)) + } + m2 := new(MessageWithMap) + if err := Unmarshal(b, m2); err != nil { + t.Fatalf("Unmarshal: %v, got these bytes: %v", err, b) + } + if v, ok := m2.ByteMapping[false]; !ok { + t.Error("byte_mapping[false] not present") + } else if len(v) != 0 { + t.Errorf("byte_mapping[false] not empty: %#v", v) + } + if v, ok := m2.ByteMapping[true]; !ok { + t.Error("byte_mapping[true] not present") + } else if len(v) != 0 { + t.Errorf("byte_mapping[true] not empty: %#v", v) + } +} + +func TestDecodeMapFieldMissingKey(t *testing.T) { + b := []byte{ + 0x0A, 0x03, // message, tag 1 (name_mapping), of length 3 bytes + // no key + 0x12, 0x01, 0x6D, // string value of length 1 byte, value "m" + } + got := &MessageWithMap{} + err := Unmarshal(b, got) + if err != nil { + t.Fatalf("failed to marshal map with missing key: %v", err) + } + want := &MessageWithMap{NameMapping: map[int32]string{0: "m"}} + if !Equal(got, want) { + t.Errorf("Unmarshaled map with no key was not as expected. got: %v, want %v", got, want) + } +} + +func TestDecodeMapFieldMissingValue(t *testing.T) { + b := []byte{ + 0x0A, 0x02, // message, tag 1 (name_mapping), of length 2 bytes + 0x08, 0x01, // varint key, value 1 + // no value + } + got := &MessageWithMap{} + err := Unmarshal(b, got) + if err != nil { + t.Fatalf("failed to marshal map with missing value: %v", err) + } + want := &MessageWithMap{NameMapping: map[int32]string{1: ""}} + if !Equal(got, want) { + t.Errorf("Unmarshaled map with no value was not as expected. got: %v, want %v", got, want) + } +} + +func TestOneof(t *testing.T) { + m := &Communique{} + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal of empty message with oneof: %v", err) + } + if len(b) != 0 { + t.Errorf("Marshal of empty message yielded too many bytes: %v", b) + } + + m = &Communique{ + Union: &Communique_Name{"Barry"}, + } + + // Round-trip. + b, err = Marshal(m) + if err != nil { + t.Fatalf("Marshal of message with oneof: %v", err) + } + if len(b) != 7 { // name tag/wire (1) + name len (1) + name (5) + t.Errorf("Incorrect marshal of message with oneof: %v", b) + } + m.Reset() + if err := Unmarshal(b, m); err != nil { + t.Fatalf("Unmarshal of message with oneof: %v", err) + } + if x, ok := m.Union.(*Communique_Name); !ok || x.Name != "Barry" { + t.Errorf("After round trip, Union = %+v", m.Union) + } + if name := m.GetName(); name != "Barry" { + t.Errorf("After round trip, GetName = %q, want %q", name, "Barry") + } + + // Let's try with a message in the oneof. + m.Union = &Communique_Msg{&Strings{StringField: String("deep deep string")}} + b, err = Marshal(m) + if err != nil { + t.Fatalf("Marshal of message with oneof set to message: %v", err) + } + if len(b) != 20 { // msg tag/wire (1) + msg len (1) + msg (1 + 1 + 16) + t.Errorf("Incorrect marshal of message with oneof set to message: %v", b) + } + m.Reset() + if err := Unmarshal(b, m); err != nil { + t.Fatalf("Unmarshal of message with oneof set to message: %v", err) + } + ss, ok := m.Union.(*Communique_Msg) + if !ok || ss.Msg.GetStringField() != "deep deep string" { + t.Errorf("After round trip with oneof set to message, Union = %+v", m.Union) + } +} + +func TestOneofNilBytes(t *testing.T) { + // A oneof with nil byte slice should marshal to tag + 0 (size), with no error. + m := &Communique{Union: &Communique_Data{Data: nil}} + b, err := Marshal(m) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + want := []byte{ + 7<<3 | 2, // tag 7, wire type 2 + 0, // size + } + if !bytes.Equal(b, want) { + t.Errorf("Wrong result of Marshal: got %x, want %x", b, want) + } +} + +func TestInefficientPackedBool(t *testing.T) { + // https://github.com/golang/protobuf/issues/76 + inp := []byte{ + 0x12, 0x02, // 0x12 = 2<<3|2; 2 bytes + // Usually a bool should take a single byte, + // but it is permitted to be any varint. + 0xb9, 0x30, + } + if err := Unmarshal(inp, new(MoreRepeated)); err != nil { + t.Error(err) + } +} + +// Make sure pure-reflect-based implementation handles +// []int32-[]enum conversion correctly. +func TestRepeatedEnum2(t *testing.T) { + pb := &RepeatedEnum{ + Color: []RepeatedEnum_Color{RepeatedEnum_RED}, + } + b, err := Marshal(pb) + if err != nil { + t.Fatalf("Marshal failed: %v", err) + } + x := new(RepeatedEnum) + err = Unmarshal(b, x) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + if !Equal(pb, x) { + t.Errorf("Incorrect result: want: %v got: %v", pb, x) + } +} + +// TestConcurrentMarshal makes sure that it is safe to marshal +// same message in multiple goroutines concurrently. +func TestConcurrentMarshal(t *testing.T) { + pb := initGoTest(true) + const N = 100 + b := make([][]byte, N) + + var wg sync.WaitGroup + for i := 0; i < N; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + var err error + b[i], err = Marshal(pb) + if err != nil { + t.Errorf("marshal error: %v", err) + } + }(i) + } + + wg.Wait() + for i := 1; i < N; i++ { + if !bytes.Equal(b[0], b[i]) { + t.Errorf("concurrent marshal result not same: b[0] = %v, b[%d] = %v", b[0], i, b[i]) + } + } +} + +func TestInvalidUTF8(t *testing.T) { + const wire = "\x12\x04\xde\xea\xca\xfe" + + var m GoTest + if err := Unmarshal([]byte(wire), &m); err == nil { + t.Errorf("Unmarshal error: got nil, want non-nil") + } + + m.Reset() + m.Table = String(wire[2:]) + if _, err := Marshal(&m); err == nil { + t.Errorf("Marshal error: got nil, want non-nil") + } +} + +// Benchmarks + +func testMsg() *GoTest { + pb := initGoTest(true) + const N = 1000 // Internally the library starts much smaller. + pb.F_Int32Repeated = make([]int32, N) + pb.F_DoubleRepeated = make([]float64, N) + for i := 0; i < N; i++ { + pb.F_Int32Repeated[i] = int32(i) + pb.F_DoubleRepeated[i] = float64(i) + } + return pb +} + +func bytesMsg() *GoTest { + pb := initGoTest(true) + buf := make([]byte, 4000) + for i := range buf { + buf[i] = byte(i) + } + pb.F_BytesDefaulted = buf + return pb +} + +func benchmarkMarshal(b *testing.B, pb Message, marshal func(Message) ([]byte, error)) { + d, _ := marshal(pb) + b.SetBytes(int64(len(d))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + marshal(pb) + } +} + +func benchmarkBufferMarshal(b *testing.B, pb Message) { + p := NewBuffer(nil) + benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { + p.Reset() + err := p.Marshal(pb0) + return p.Bytes(), err + }) +} + +func benchmarkSize(b *testing.B, pb Message) { + benchmarkMarshal(b, pb, func(pb0 Message) ([]byte, error) { + Size(pb) + return nil, nil + }) +} + +func newOf(pb Message) Message { + in := reflect.ValueOf(pb) + if in.IsNil() { + return pb + } + return reflect.New(in.Type().Elem()).Interface().(Message) +} + +func benchmarkUnmarshal(b *testing.B, pb Message, unmarshal func([]byte, Message) error) { + d, _ := Marshal(pb) + b.SetBytes(int64(len(d))) + pbd := newOf(pb) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + unmarshal(d, pbd) + } +} + +func benchmarkBufferUnmarshal(b *testing.B, pb Message) { + p := NewBuffer(nil) + benchmarkUnmarshal(b, pb, func(d []byte, pb0 Message) error { + p.SetBuf(d) + return p.Unmarshal(pb0) + }) +} + +// Benchmark{Marshal,BufferMarshal,Size,Unmarshal,BufferUnmarshal}{,Bytes} + +func BenchmarkMarshal(b *testing.B) { + benchmarkMarshal(b, testMsg(), Marshal) +} + +func BenchmarkBufferMarshal(b *testing.B) { + benchmarkBufferMarshal(b, testMsg()) +} + +func BenchmarkSize(b *testing.B) { + benchmarkSize(b, testMsg()) +} + +func BenchmarkUnmarshal(b *testing.B) { + benchmarkUnmarshal(b, testMsg(), Unmarshal) +} + +func BenchmarkBufferUnmarshal(b *testing.B) { + benchmarkBufferUnmarshal(b, testMsg()) +} + +func BenchmarkMarshalBytes(b *testing.B) { + benchmarkMarshal(b, bytesMsg(), Marshal) +} + +func BenchmarkBufferMarshalBytes(b *testing.B) { + benchmarkBufferMarshal(b, bytesMsg()) +} + +func BenchmarkSizeBytes(b *testing.B) { + benchmarkSize(b, bytesMsg()) +} + +func BenchmarkUnmarshalBytes(b *testing.B) { + benchmarkUnmarshal(b, bytesMsg(), Unmarshal) +} + +func BenchmarkBufferUnmarshalBytes(b *testing.B) { + benchmarkBufferUnmarshal(b, bytesMsg()) +} + +func BenchmarkUnmarshalUnrecognizedFields(b *testing.B) { + b.StopTimer() + pb := initGoTestField() + skip := &GoSkipTest{ + SkipInt32: Int32(32), + SkipFixed32: Uint32(3232), + SkipFixed64: Uint64(6464), + SkipString: String("skipper"), + Skipgroup: &GoSkipTest_SkipGroup{ + GroupInt32: Int32(75), + GroupString: String("wxyz"), + }, + } + + pbd := new(GoTestField) + p := NewBuffer(nil) + p.Marshal(pb) + p.Marshal(skip) + p2 := NewBuffer(nil) + + b.StartTimer() + for i := 0; i < b.N; i++ { + p2.SetBuf(p.Bytes()) + p2.Unmarshal(pbd) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/any_test.go b/vendor/github.com/golang/protobuf/proto/any_test.go new file mode 100644 index 000000000..56fc97c11 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/any_test.go @@ -0,0 +1,300 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "strings" + "testing" + + "github.com/golang/protobuf/proto" + + pb "github.com/golang/protobuf/proto/proto3_proto" + testpb "github.com/golang/protobuf/proto/test_proto" + anypb "github.com/golang/protobuf/ptypes/any" +) + +var ( + expandedMarshaler = proto.TextMarshaler{ExpandAny: true} + expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true} +) + +// anyEqual reports whether two messages which may be google.protobuf.Any or may +// contain google.protobuf.Any fields are equal. We can't use proto.Equal for +// comparison, because semantically equivalent messages may be marshaled to +// binary in different tag order. Instead, trust that TextMarshaler with +// ExpandAny option works and compare the text marshaling results. +func anyEqual(got, want proto.Message) bool { + // if messages are proto.Equal, no need to marshal. + if proto.Equal(got, want) { + return true + } + g := expandedMarshaler.Text(got) + w := expandedMarshaler.Text(want) + return g == w +} + +type golden struct { + m proto.Message + t, c string +} + +var goldenMessages = makeGolden() + +func makeGolden() []golden { + nested := &pb.Nested{Bunny: "Monty"} + nb, err := proto.Marshal(nested) + if err != nil { + panic(err) + } + m1 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}, + } + m2 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb}, + } + m3 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb}, + } + m4 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb}, + } + m5 := &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb} + + any1 := &testpb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")} + proto.SetExtension(any1, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("foo")}) + proto.SetExtension(any1, testpb.E_Ext_Text, proto.String("bar")) + any1b, err := proto.Marshal(any1) + if err != nil { + panic(err) + } + any2 := &testpb.MyMessage{Count: proto.Int32(42), Bikeshed: testpb.MyMessage_GREEN.Enum(), RepBytes: [][]byte{[]byte("roboto")}} + proto.SetExtension(any2, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("baz")}) + any2b, err := proto.Marshal(any2) + if err != nil { + panic(err) + } + m6 := &pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, + ManyThings: []*anypb.Any{ + &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b}, + &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b}, + }, + } + + const ( + m1Golden = ` +name: "David" +result_count: 47 +anything: < + [type.googleapis.com/proto3_proto.Nested]: < + bunny: "Monty" + > +> +` + m2Golden = ` +name: "David" +result_count: 47 +anything: < + ["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: < + bunny: "Monty" + > +> +` + m3Golden = ` +name: "David" +result_count: 47 +anything: < + ["type.googleapis.com/\"/proto3_proto.Nested"]: < + bunny: "Monty" + > +> +` + m4Golden = ` +name: "David" +result_count: 47 +anything: < + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Monty" + > +> +` + m5Golden = ` +[type.googleapis.com/proto3_proto.Nested]: < + bunny: "Monty" +> +` + m6Golden = ` +name: "David" +result_count: 47 +anything: < + [type.googleapis.com/test_proto.MyMessage]: < + count: 47 + name: "David" + [test_proto.Ext.more]: < + data: "foo" + > + [test_proto.Ext.text]: "bar" + > +> +many_things: < + [type.googleapis.com/test_proto.MyMessage]: < + count: 42 + bikeshed: GREEN + rep_bytes: "roboto" + [test_proto.Ext.more]: < + data: "baz" + > + > +> +many_things: < + [type.googleapis.com/test_proto.MyMessage]: < + count: 47 + name: "David" + [test_proto.Ext.more]: < + data: "foo" + > + [test_proto.Ext.text]: "bar" + > +> +` + ) + return []golden{ + {m1, strings.TrimSpace(m1Golden) + "\n", strings.TrimSpace(compact(m1Golden)) + " "}, + {m2, strings.TrimSpace(m2Golden) + "\n", strings.TrimSpace(compact(m2Golden)) + " "}, + {m3, strings.TrimSpace(m3Golden) + "\n", strings.TrimSpace(compact(m3Golden)) + " "}, + {m4, strings.TrimSpace(m4Golden) + "\n", strings.TrimSpace(compact(m4Golden)) + " "}, + {m5, strings.TrimSpace(m5Golden) + "\n", strings.TrimSpace(compact(m5Golden)) + " "}, + {m6, strings.TrimSpace(m6Golden) + "\n", strings.TrimSpace(compact(m6Golden)) + " "}, + } +} + +func TestMarshalGolden(t *testing.T) { + for _, tt := range goldenMessages { + if got, want := expandedMarshaler.Text(tt.m), tt.t; got != want { + t.Errorf("message %v: got:\n%s\nwant:\n%s", tt.m, got, want) + } + if got, want := expandedCompactMarshaler.Text(tt.m), tt.c; got != want { + t.Errorf("message %v: got:\n`%s`\nwant:\n`%s`", tt.m, got, want) + } + } +} + +func TestUnmarshalGolden(t *testing.T) { + for _, tt := range goldenMessages { + want := tt.m + got := proto.Clone(tt.m) + got.Reset() + if err := proto.UnmarshalText(tt.t, got); err != nil { + t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err) + } + if !anyEqual(got, want) { + t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want) + } + got.Reset() + if err := proto.UnmarshalText(tt.c, got); err != nil { + t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err) + } + if !anyEqual(got, want) { + t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want) + } + } +} + +func TestMarshalUnknownAny(t *testing.T) { + m := &pb.Message{ + Anything: &anypb.Any{ + TypeUrl: "foo", + Value: []byte("bar"), + }, + } + want := `anything: < + type_url: "foo" + value: "bar" +> +` + got := expandedMarshaler.Text(m) + if got != want { + t.Errorf("got\n`%s`\nwant\n`%s`", got, want) + } +} + +func TestAmbiguousAny(t *testing.T) { + pb := &anypb.Any{} + err := proto.UnmarshalText(` + type_url: "ttt/proto3_proto.Nested" + value: "\n\x05Monty" + `, pb) + t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err) + if err != nil { + t.Errorf("failed to parse ambiguous Any message: %v", err) + } +} + +func TestUnmarshalOverwriteAny(t *testing.T) { + pb := &anypb.Any{} + err := proto.UnmarshalText(` + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Monty" + > + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Rabbit of Caerbannog" + > + `, pb) + want := `line 7: Any message unpacked multiple times, or "type_url" already set` + if err.Error() != want { + t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) + } +} + +func TestUnmarshalAnyMixAndMatch(t *testing.T) { + pb := &anypb.Any{} + err := proto.UnmarshalText(` + value: "\n\x05Monty" + [type.googleapis.com/a/path/proto3_proto.Nested]: < + bunny: "Rabbit of Caerbannog" + > + `, pb) + want := `line 5: Any message unpacked multiple times, or "value" already set` + if err.Error() != want { + t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/clone_test.go b/vendor/github.com/golang/protobuf/proto/clone_test.go new file mode 100644 index 000000000..0d3b12737 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/clone_test.go @@ -0,0 +1,390 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2011 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "testing" + + "github.com/golang/protobuf/proto" + + proto3pb "github.com/golang/protobuf/proto/proto3_proto" + pb "github.com/golang/protobuf/proto/test_proto" +) + +var cloneTestMessage = &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &pb.InnerMessage{ + Host: proto.String("niles"), + Port: proto.Int32(9099), + Connected: proto.Bool(true), + }, + Others: []*pb.OtherMessage{ + { + Value: []byte("some bytes"), + }, + }, + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, +} + +func init() { + ext := &pb.Ext{ + Data: proto.String("extension"), + } + if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil { + panic("SetExtension: " + err.Error()) + } +} + +func TestClone(t *testing.T) { + m := proto.Clone(cloneTestMessage).(*pb.MyMessage) + if !proto.Equal(m, cloneTestMessage) { + t.Fatalf("Clone(%v) = %v", cloneTestMessage, m) + } + + // Verify it was a deep copy. + *m.Inner.Port++ + if proto.Equal(m, cloneTestMessage) { + t.Error("Mutating clone changed the original") + } + // Byte fields and repeated fields should be copied. + if &m.Pet[0] == &cloneTestMessage.Pet[0] { + t.Error("Pet: repeated field not copied") + } + if &m.Others[0] == &cloneTestMessage.Others[0] { + t.Error("Others: repeated field not copied") + } + if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] { + t.Error("Others[0].Value: bytes field not copied") + } + if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] { + t.Error("RepBytes: repeated field not copied") + } + if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] { + t.Error("RepBytes[0]: bytes field not copied") + } +} + +func TestCloneNil(t *testing.T) { + var m *pb.MyMessage + if c := proto.Clone(m); !proto.Equal(m, c) { + t.Errorf("Clone(%v) = %v", m, c) + } +} + +var mergeTests = []struct { + src, dst, want proto.Message +}{ + { + src: &pb.MyMessage{ + Count: proto.Int32(42), + }, + dst: &pb.MyMessage{ + Name: proto.String("Dave"), + }, + want: &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + }, + }, + { + src: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("hey"), + Connected: proto.Bool(true), + }, + Pet: []string{"horsey"}, + Others: []*pb.OtherMessage{ + { + Value: []byte("some bytes"), + }, + }, + }, + dst: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("niles"), + Port: proto.Int32(9099), + }, + Pet: []string{"bunny", "kitty"}, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(31415926535), + }, + { + // Explicitly test a src=nil field + Inner: nil, + }, + }, + }, + want: &pb.MyMessage{ + Inner: &pb.InnerMessage{ + Host: proto.String("hey"), + Connected: proto.Bool(true), + Port: proto.Int32(9099), + }, + Pet: []string{"bunny", "kitty", "horsey"}, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(31415926535), + }, + {}, + { + Value: []byte("some bytes"), + }, + }, + }, + }, + { + src: &pb.MyMessage{ + RepBytes: [][]byte{[]byte("wow")}, + }, + dst: &pb.MyMessage{ + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham")}, + }, + want: &pb.MyMessage{ + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(6), + }, + RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, + }, + }, + // Check that a scalar bytes field replaces rather than appends. + { + src: &pb.OtherMessage{Value: []byte("foo")}, + dst: &pb.OtherMessage{Value: []byte("bar")}, + want: &pb.OtherMessage{Value: []byte("foo")}, + }, + { + src: &pb.MessageWithMap{ + NameMapping: map[int32]string{6: "Nigel"}, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, + 0x4002: &pb.FloatingPoint{ + F: proto.Float64(2.0), + }, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + dst: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Bruce", // should be overwritten + 7: "Andrew", + }, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4002: &pb.FloatingPoint{ + F: proto.Float64(3.0), + Exact: proto.Bool(true), + }, // the entire message should be overwritten + }, + }, + want: &pb.MessageWithMap{ + NameMapping: map[int32]string{ + 6: "Nigel", + 7: "Andrew", + }, + MsgMapping: map[int64]*pb.FloatingPoint{ + 0x4001: &pb.FloatingPoint{F: proto.Float64(2.0)}, + 0x4002: &pb.FloatingPoint{ + F: proto.Float64(2.0), + }, + }, + ByteMapping: map[bool][]byte{true: []byte("wowsa")}, + }, + }, + // proto3 shouldn't merge zero values, + // in the same way that proto2 shouldn't merge nils. + { + src: &proto3pb.Message{ + Name: "Aaron", + Data: []byte(""), // zero value, but not nil + }, + dst: &proto3pb.Message{ + HeightInCm: 176, + Data: []byte("texas!"), + }, + want: &proto3pb.Message{ + Name: "Aaron", + HeightInCm: 176, + Data: []byte("texas!"), + }, + }, + { // Oneof fields should merge by assignment. + src: &pb.Communique{Union: &pb.Communique_Number{41}}, + dst: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}}, + want: &pb.Communique{Union: &pb.Communique_Number{41}}, + }, + { // Oneof nil is the same as not set. + src: &pb.Communique{}, + dst: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}}, + want: &pb.Communique{Union: &pb.Communique_Name{"Bobby Tables"}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Number{1337}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Number{1337}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Col{pb.MyMessage_RED}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Col{pb.MyMessage_RED}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Data{[]byte("hello")}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Data{[]byte("hello")}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Msg{}}, + dst: &pb.Communique{}, + want: &pb.Communique{Union: &pb.Communique_Msg{}}, + }, + { + src: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123")}}}, + dst: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{BytesField: []byte{1, 2, 3}}}}, + want: &pb.Communique{Union: &pb.Communique_Msg{&pb.Strings{StringField: proto.String("123"), BytesField: []byte{1, 2, 3}}}}, + }, + { + src: &proto3pb.Message{ + Terrain: map[string]*proto3pb.Nested{ + "kay_a": &proto3pb.Nested{Cute: true}, // replace + "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, // insert + }, + }, + dst: &proto3pb.Message{ + Terrain: map[string]*proto3pb.Nested{ + "kay_a": &proto3pb.Nested{Bunny: "lost"}, // replaced + "kay_c": &proto3pb.Nested{Bunny: "bunny"}, // keep + }, + }, + want: &proto3pb.Message{ + Terrain: map[string]*proto3pb.Nested{ + "kay_a": &proto3pb.Nested{Cute: true}, + "kay_b": &proto3pb.Nested{Bunny: "rabbit"}, + "kay_c": &proto3pb.Nested{Bunny: "bunny"}, + }, + }, + }, + { + src: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + dst: &pb.GoTest{}, + want: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + }, + { + src: &pb.GoTest{}, + dst: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + want: &pb.GoTest{ + F_BoolRepeated: []bool{}, + F_Int32Repeated: []int32{}, + F_Int64Repeated: []int64{}, + F_Uint32Repeated: []uint32{}, + F_Uint64Repeated: []uint64{}, + F_FloatRepeated: []float32{}, + F_DoubleRepeated: []float64{}, + F_StringRepeated: []string{}, + F_BytesRepeated: [][]byte{}, + }, + }, + { + src: &pb.GoTest{ + F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}}, + }, + dst: &pb.GoTest{}, + want: &pb.GoTest{ + F_BytesRepeated: [][]byte{nil, []byte{}, []byte{0}}, + }, + }, + { + src: &pb.MyMessage{ + Others: []*pb.OtherMessage{}, + }, + dst: &pb.MyMessage{}, + want: &pb.MyMessage{ + Others: []*pb.OtherMessage{}, + }, + }, +} + +func TestMerge(t *testing.T) { + for _, m := range mergeTests { + got := proto.Clone(m.dst) + if !proto.Equal(got, m.dst) { + t.Errorf("Clone()\ngot %v\nwant %v", got, m.dst) + continue + } + proto.Merge(got, m.src) + if !proto.Equal(got, m.want) { + t.Errorf("Merge(%v, %v)\ngot %v\nwant %v", m.dst, m.src, got, m.want) + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/decode_test.go b/vendor/github.com/golang/protobuf/proto/decode_test.go new file mode 100644 index 000000000..949be3abd --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/decode_test.go @@ -0,0 +1,255 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build go1.7 + +package proto_test + +import ( + "fmt" + "testing" + + "github.com/golang/protobuf/proto" + tpb "github.com/golang/protobuf/proto/proto3_proto" +) + +var msgBlackhole = new(tpb.Message) + +// BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and +// 2 bytes long). +func BenchmarkVarint32ArraySmall(b *testing.B) { + for i := uint(1); i <= 10; i++ { + dist := genInt32Dist([7]int{0, 3, 1}, 1<unmarshal. +} + +func TestMarshalUnmarshalRepeatedExtension(t *testing.T) { + // Add a repeated extension to the result. + tests := []struct { + name string + ext []*pb.ComplexExtension + }{ + { + "two fields", + []*pb.ComplexExtension{ + {First: proto.Int32(7)}, + {Second: proto.Int32(11)}, + }, + }, + { + "repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {Third: []int32{2000}}, + }, + }, + { + "two fields and repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {First: proto.Int32(9)}, + {Second: proto.Int32(21)}, + {Third: []int32{2000}}, + }, + }, + } + for _, test := range tests { + // Marshal message with a repeated extension. + msg1 := new(pb.OtherMessage) + err := proto.SetExtension(msg1, pb.E_RComplex, test.ext) + if err != nil { + t.Fatalf("[%s] Error setting extension: %v", test.name, err) + } + b, err := proto.Marshal(msg1) + if err != nil { + t.Fatalf("[%s] Error marshaling message: %v", test.name, err) + } + + // Unmarshal and read the merged proto. + msg2 := new(pb.OtherMessage) + err = proto.Unmarshal(b, msg2) + if err != nil { + t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) + } + e, err := proto.GetExtension(msg2, pb.E_RComplex) + if err != nil { + t.Fatalf("[%s] Error getting extension: %v", test.name, err) + } + ext := e.([]*pb.ComplexExtension) + if ext == nil { + t.Fatalf("[%s] Invalid extension", test.name) + } + if len(ext) != len(test.ext) { + t.Errorf("[%s] Wrong length of ComplexExtension: got: %v want: %v\n", test.name, len(ext), len(test.ext)) + } + for i := range test.ext { + if !proto.Equal(ext[i], test.ext[i]) { + t.Errorf("[%s] Wrong value for ComplexExtension[%d]: got: %v want: %v\n", test.name, i, ext[i], test.ext[i]) + } + } + } +} + +func TestUnmarshalRepeatingNonRepeatedExtension(t *testing.T) { + // We may see multiple instances of the same extension in the wire + // format. For example, the proto compiler may encode custom options in + // this way. Here, we verify that we merge the extensions together. + tests := []struct { + name string + ext []*pb.ComplexExtension + }{ + { + "two fields", + []*pb.ComplexExtension{ + {First: proto.Int32(7)}, + {Second: proto.Int32(11)}, + }, + }, + { + "repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {Third: []int32{2000}}, + }, + }, + { + "two fields and repeated field", + []*pb.ComplexExtension{ + {Third: []int32{1000}}, + {First: proto.Int32(9)}, + {Second: proto.Int32(21)}, + {Third: []int32{2000}}, + }, + }, + } + for _, test := range tests { + var buf bytes.Buffer + var want pb.ComplexExtension + + // Generate a serialized representation of a repeated extension + // by catenating bytes together. + for i, e := range test.ext { + // Merge to create the wanted proto. + proto.Merge(&want, e) + + // serialize the message + msg := new(pb.OtherMessage) + err := proto.SetExtension(msg, pb.E_Complex, e) + if err != nil { + t.Fatalf("[%s] Error setting extension %d: %v", test.name, i, err) + } + b, err := proto.Marshal(msg) + if err != nil { + t.Fatalf("[%s] Error marshaling message %d: %v", test.name, i, err) + } + buf.Write(b) + } + + // Unmarshal and read the merged proto. + msg2 := new(pb.OtherMessage) + err := proto.Unmarshal(buf.Bytes(), msg2) + if err != nil { + t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err) + } + e, err := proto.GetExtension(msg2, pb.E_Complex) + if err != nil { + t.Fatalf("[%s] Error getting extension: %v", test.name, err) + } + ext := e.(*pb.ComplexExtension) + if ext == nil { + t.Fatalf("[%s] Invalid extension", test.name) + } + if !proto.Equal(ext, &want) { + t.Errorf("[%s] Wrong value for ComplexExtension: got: %s want: %s\n", test.name, ext, &want) + } + } +} + +func TestClearAllExtensions(t *testing.T) { + // unregistered extension + desc := &proto.ExtensionDesc{ + ExtendedType: (*pb.MyMessage)(nil), + ExtensionType: (*bool)(nil), + Field: 101010100, + Name: "emptyextension", + Tag: "varint,0,opt", + } + m := &pb.MyMessage{} + if proto.HasExtension(m, desc) { + t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) + } + if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil { + t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err) + } + if !proto.HasExtension(m, desc) { + t.Errorf("proto.HasExtension(%s): got false, want true", proto.MarshalTextString(m)) + } + proto.ClearAllExtensions(m) + if proto.HasExtension(m, desc) { + t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m)) + } +} + +func TestMarshalRace(t *testing.T) { + ext := &pb.Ext{} + m := &pb.MyMessage{Count: proto.Int32(4)} + if err := proto.SetExtension(m, pb.E_Ext_More, ext); err != nil { + t.Fatalf("proto.SetExtension(m, desc, true): got error %q, want nil", err) + } + + b, err := proto.Marshal(m) + if err != nil { + t.Fatalf("Could not marshal message: %v", err) + } + if err := proto.Unmarshal(b, m); err != nil { + t.Fatalf("Could not unmarshal message: %v", err) + } + // after Unmarshal, the extension is in undecoded form. + // GetExtension will decode it lazily. Make sure this does + // not race against Marshal. + + var g errgroup.Group + for n := 3; n > 0; n-- { + g.Go(func() error { + _, err := proto.Marshal(m) + return err + }) + g.Go(func() error { + _, err := proto.GetExtension(m, pb.E_Ext_More) + return err + }) + } + if err := g.Wait(); err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/map_test.go b/vendor/github.com/golang/protobuf/proto/map_test.go new file mode 100644 index 000000000..b1e1529ee --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/map_test.go @@ -0,0 +1,70 @@ +package proto_test + +import ( + "fmt" + "reflect" + "testing" + + "github.com/golang/protobuf/proto" + ppb "github.com/golang/protobuf/proto/proto3_proto" +) + +func TestMap(t *testing.T) { + var b []byte + fmt.Sscanf("a2010c0a044b657931120456616c31a201130a044b657932120556616c3261120456616c32a201240a044b6579330d05000000120556616c33621a0556616c3361120456616c331505000000a20100a201260a044b657934130a07536f6d6555524c1209536f6d655469746c651a08536e69707065743114", "%x", &b) + + var m ppb.Message + if err := proto.Unmarshal(b, &m); err != nil { + t.Fatalf("proto.Unmarshal error: %v", err) + } + + got := m.StringMap + want := map[string]string{ + "": "", + "Key1": "Val1", + "Key2": "Val2", + "Key3": "Val3", + "Key4": "", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("maps differ:\ngot %#v\nwant %#v", got, want) + } +} + +func marshalled() []byte { + m := &ppb.IntMaps{} + for i := 0; i < 1000; i++ { + m.Maps = append(m.Maps, &ppb.IntMap{ + Rtt: map[int32]int32{1: 2}, + }) + } + b, err := proto.Marshal(m) + if err != nil { + panic(fmt.Sprintf("Can't marshal %+v: %v", m, err)) + } + return b +} + +func BenchmarkConcurrentMapUnmarshal(b *testing.B) { + in := marshalled() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + var out ppb.IntMaps + if err := proto.Unmarshal(in, &out); err != nil { + b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) + } + } + }) +} + +func BenchmarkSequentialMapUnmarshal(b *testing.B) { + in := marshalled() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var out ppb.IntMaps + if err := proto.Unmarshal(in, &out); err != nil { + b.Errorf("Can't unmarshal ppb.IntMaps: %v", err) + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/message_set_test.go b/vendor/github.com/golang/protobuf/proto/message_set_test.go new file mode 100644 index 000000000..2c170c5f2 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/message_set_test.go @@ -0,0 +1,77 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "bytes" + "testing" +) + +func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { + // Check that a repeated message set entry will be concatenated. + in := &messageSet{ + Item: []*_MessageSet_Item{ + {TypeId: Int32(12345), Message: []byte("hoo")}, + {TypeId: Int32(12345), Message: []byte("hah")}, + }, + } + b, err := Marshal(in) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + t.Logf("Marshaled bytes: %q", b) + + var extensions XXX_InternalExtensions + if err := UnmarshalMessageSet(b, &extensions); err != nil { + t.Fatalf("UnmarshalMessageSet: %v", err) + } + ext, ok := extensions.p.extensionMap[12345] + if !ok { + t.Fatalf("Didn't retrieve extension 12345; map is %v", extensions.p.extensionMap) + } + // Skip wire type/field number and length varints. + got := skipVarint(skipVarint(ext.enc)) + if want := []byte("hoohah"); !bytes.Equal(got, want) { + t.Errorf("Combined extension is %q, want %q", got, want) + } +} + +func TestMarshalMessageSetJSON_UnknownType(t *testing.T) { + extMap := map[int32]Extension{12345: Extension{}} + got, err := MarshalMessageSetJSON(extMap) + if err != nil { + t.Fatalf("MarshalMessageSetJSON: %v", err) + } + if want := []byte("{}"); !bytes.Equal(got, want) { + t.Errorf("MarshalMessageSetJSON(%v) = %q, want %q", extMap, got, want) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/proto3_test.go b/vendor/github.com/golang/protobuf/proto/proto3_test.go new file mode 100644 index 000000000..73eed6c0b --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/proto3_test.go @@ -0,0 +1,151 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2014 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "testing" + + "github.com/golang/protobuf/proto" + pb "github.com/golang/protobuf/proto/proto3_proto" + tpb "github.com/golang/protobuf/proto/test_proto" +) + +func TestProto3ZeroValues(t *testing.T) { + tests := []struct { + desc string + m proto.Message + }{ + {"zero message", &pb.Message{}}, + {"empty bytes field", &pb.Message{Data: []byte{}}}, + } + for _, test := range tests { + b, err := proto.Marshal(test.m) + if err != nil { + t.Errorf("%s: proto.Marshal: %v", test.desc, err) + continue + } + if len(b) > 0 { + t.Errorf("%s: Encoding is non-empty: %q", test.desc, b) + } + } +} + +func TestRoundTripProto3(t *testing.T) { + m := &pb.Message{ + Name: "David", // (2 | 1<<3): 0x0a 0x05 "David" + Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01 + HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01 + Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto" + ResultCount: 47, // (0 | 7<<3): 0x38 0x2f + TrueScotsman: true, // (0 | 8<<3): 0x40 0x01 + Score: 8.1, // (5 | 9<<3): 0x4d <8.1> + + Key: []uint64{1, 0xdeadbeef}, + Nested: &pb.Nested{ + Bunny: "Monty", + }, + } + t.Logf(" m: %v", m) + + b, err := proto.Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal: %v", err) + } + t.Logf(" b: %q", b) + + m2 := new(pb.Message) + if err := proto.Unmarshal(b, m2); err != nil { + t.Fatalf("proto.Unmarshal: %v", err) + } + t.Logf("m2: %v", m2) + + if !proto.Equal(m, m2) { + t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2) + } +} + +func TestGettersForBasicTypesExist(t *testing.T) { + var m pb.Message + if got := m.GetNested().GetBunny(); got != "" { + t.Errorf("m.GetNested().GetBunny() = %q, want empty string", got) + } + if got := m.GetNested().GetCute(); got { + t.Errorf("m.GetNested().GetCute() = %t, want false", got) + } +} + +func TestProto3SetDefaults(t *testing.T) { + in := &pb.Message{ + Terrain: map[string]*pb.Nested{ + "meadow": new(pb.Nested), + }, + Proto2Field: new(tpb.SubDefaults), + Proto2Value: map[string]*tpb.SubDefaults{ + "badlands": new(tpb.SubDefaults), + }, + } + + got := proto.Clone(in).(*pb.Message) + proto.SetDefaults(got) + + // There are no defaults in proto3. Everything should be the zero value, but + // we need to remember to set defaults for nested proto2 messages. + want := &pb.Message{ + Terrain: map[string]*pb.Nested{ + "meadow": new(pb.Nested), + }, + Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, + Proto2Value: map[string]*tpb.SubDefaults{ + "badlands": &tpb.SubDefaults{N: proto.Int64(7)}, + }, + } + + if !proto.Equal(got, want) { + t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) + } +} + +func TestUnknownFieldPreservation(t *testing.T) { + b1 := "\x0a\x05David" // Known tag 1 + b2 := "\xc2\x0c\x06Google" // Unknown tag 200 + b := []byte(b1 + b2) + + m := new(pb.Message) + if err := proto.Unmarshal(b, m); err != nil { + t.Fatalf("proto.Unmarshal: %v", err) + } + + if !bytes.Equal(m.XXX_unrecognized, []byte(b2)) { + t.Fatalf("mismatching unknown fields:\ngot %q\nwant %q", m.XXX_unrecognized, b2) + } +} diff --git a/vendor/github.com/golang/protobuf/proto/size2_test.go b/vendor/github.com/golang/protobuf/proto/size2_test.go new file mode 100644 index 000000000..7846b0617 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/size2_test.go @@ -0,0 +1,63 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto + +import ( + "testing" +) + +// This is a separate file and package from size_test.go because that one uses +// generated messages and thus may not be in package proto without having a circular +// dependency, whereas this file tests unexported details of size.go. + +func TestVarintSize(t *testing.T) { + // Check the edge cases carefully. + testCases := []struct { + n uint64 + size int + }{ + {0, 1}, + {1, 1}, + {127, 1}, + {128, 2}, + {16383, 2}, + {16384, 3}, + {1<<63 - 1, 9}, + {1 << 63, 10}, + } + for _, tc := range testCases { + size := SizeVarint(tc.n) + if size != tc.size { + t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/size_test.go b/vendor/github.com/golang/protobuf/proto/size_test.go new file mode 100644 index 000000000..3abac418a --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/size_test.go @@ -0,0 +1,191 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2012 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "log" + "strings" + "testing" + + . "github.com/golang/protobuf/proto" + proto3pb "github.com/golang/protobuf/proto/proto3_proto" + pb "github.com/golang/protobuf/proto/test_proto" +) + +var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)} + +// messageWithExtension2 is in equal_test.go. +var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)} + +func init() { + if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil { + log.Panicf("SetExtension: %v", err) + } + if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil { + log.Panicf("SetExtension: %v", err) + } + + // Force messageWithExtension3 to have the extension encoded. + Marshal(messageWithExtension3) + +} + +// non-pointer custom message +type nonptrMessage struct{} + +func (m nonptrMessage) ProtoMessage() {} +func (m nonptrMessage) Reset() {} +func (m nonptrMessage) String() string { return "" } + +func (m nonptrMessage) Marshal() ([]byte, error) { + return []byte{42}, nil +} + +// custom message embedding a proto.Message +type messageWithEmbedding struct { + *pb.OtherMessage +} + +func (m *messageWithEmbedding) ProtoMessage() {} +func (m *messageWithEmbedding) Reset() {} +func (m *messageWithEmbedding) String() string { return "" } + +func (m *messageWithEmbedding) Marshal() ([]byte, error) { + return []byte{42}, nil +} + +var SizeTests = []struct { + desc string + pb Message +}{ + {"empty", &pb.OtherMessage{}}, + // Basic types. + {"bool", &pb.Defaults{F_Bool: Bool(true)}}, + {"int32", &pb.Defaults{F_Int32: Int32(12)}}, + {"negative int32", &pb.Defaults{F_Int32: Int32(-1)}}, + {"small int64", &pb.Defaults{F_Int64: Int64(1)}}, + {"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}}, + {"negative int64", &pb.Defaults{F_Int64: Int64(-1)}}, + {"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}}, + {"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}}, + {"uint32", &pb.Defaults{F_Uint32: Uint32(123)}}, + {"uint64", &pb.Defaults{F_Uint64: Uint64(124)}}, + {"float", &pb.Defaults{F_Float: Float32(12.6)}}, + {"double", &pb.Defaults{F_Double: Float64(13.9)}}, + {"string", &pb.Defaults{F_String: String("niles")}}, + {"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}}, + {"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}}, + {"sint32", &pb.Defaults{F_Sint32: Int32(65)}}, + {"sint64", &pb.Defaults{F_Sint64: Int64(67)}}, + {"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}}, + // Repeated. + {"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}}, + {"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}}, + {"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}}, + {"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}}, + {"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}}, + {"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{ + // Need enough large numbers to verify that the header is counting the number of bytes + // for the field, not the number of elements. + 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, + 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, + }}}, + {"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}}, + {"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}}, + // Nested. + {"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}}, + {"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}}, + // Other things. + {"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}}, + {"extension (unencoded)", messageWithExtension1}, + {"extension (encoded)", messageWithExtension3}, + // proto3 message + {"proto3 empty", &proto3pb.Message{}}, + {"proto3 bool", &proto3pb.Message{TrueScotsman: true}}, + {"proto3 int64", &proto3pb.Message{ResultCount: 1}}, + {"proto3 uint32", &proto3pb.Message{HeightInCm: 123}}, + {"proto3 float", &proto3pb.Message{Score: 12.6}}, + {"proto3 string", &proto3pb.Message{Name: "Snezana"}}, + {"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}}, + {"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}}, + {"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}}, + {"proto3 map field with empty bytes", &proto3pb.MessageWithMap{ByteMapping: map[bool][]byte{false: []byte{}}}}, + + {"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}}, + {"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: &pb.FloatingPoint{F: Float64(2.0)}}}}, + {"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}}, + {"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte{}}}}, + + {"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}}, + {"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}}, + {"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}}, + + {"oneof not set", &pb.Oneof{}}, + {"oneof bool", &pb.Oneof{Union: &pb.Oneof_F_Bool{true}}}, + {"oneof zero int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{0}}}, + {"oneof big int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{1 << 20}}}, + {"oneof int64", &pb.Oneof{Union: &pb.Oneof_F_Int64{42}}}, + {"oneof fixed32", &pb.Oneof{Union: &pb.Oneof_F_Fixed32{43}}}, + {"oneof fixed64", &pb.Oneof{Union: &pb.Oneof_F_Fixed64{44}}}, + {"oneof uint32", &pb.Oneof{Union: &pb.Oneof_F_Uint32{45}}}, + {"oneof uint64", &pb.Oneof{Union: &pb.Oneof_F_Uint64{46}}}, + {"oneof float", &pb.Oneof{Union: &pb.Oneof_F_Float{47.1}}}, + {"oneof double", &pb.Oneof{Union: &pb.Oneof_F_Double{48.9}}}, + {"oneof string", &pb.Oneof{Union: &pb.Oneof_F_String{"Rhythmic Fman"}}}, + {"oneof bytes", &pb.Oneof{Union: &pb.Oneof_F_Bytes{[]byte("let go")}}}, + {"oneof sint32", &pb.Oneof{Union: &pb.Oneof_F_Sint32{50}}}, + {"oneof sint64", &pb.Oneof{Union: &pb.Oneof_F_Sint64{51}}}, + {"oneof enum", &pb.Oneof{Union: &pb.Oneof_F_Enum{pb.MyMessage_BLUE}}}, + {"message for oneof", &pb.GoTestField{Label: String("k"), Type: String("v")}}, + {"oneof message", &pb.Oneof{Union: &pb.Oneof_F_Message{&pb.GoTestField{Label: String("k"), Type: String("v")}}}}, + {"oneof group", &pb.Oneof{Union: &pb.Oneof_FGroup{&pb.Oneof_F_Group{X: Int32(52)}}}}, + {"oneof largest tag", &pb.Oneof{Union: &pb.Oneof_F_Largest_Tag{1}}}, + {"multiple oneofs", &pb.Oneof{Union: &pb.Oneof_F_Int32{1}, Tormato: &pb.Oneof_Value{2}}}, + + {"non-pointer message", nonptrMessage{}}, + {"custom message with embedding", &messageWithEmbedding{&pb.OtherMessage{}}}, +} + +func TestSize(t *testing.T) { + for _, tc := range SizeTests { + size := Size(tc.pb) + b, err := Marshal(tc.pb) + if err != nil { + t.Errorf("%v: Marshal failed: %v", tc.desc, err) + continue + } + if size != len(b) { + t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b)) + t.Logf("%v: bytes: %#v", tc.desc, b) + } + } +} diff --git a/vendor/github.com/golang/protobuf/proto/text_parser_test.go b/vendor/github.com/golang/protobuf/proto/text_parser_test.go new file mode 100644 index 000000000..a81980879 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text_parser_test.go @@ -0,0 +1,706 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "fmt" + "math" + "testing" + + . "github.com/golang/protobuf/proto" + proto3pb "github.com/golang/protobuf/proto/proto3_proto" + . "github.com/golang/protobuf/proto/test_proto" +) + +type UnmarshalTextTest struct { + in string + err string // if "", no error expected + out *MyMessage +} + +func buildExtStructTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + SetExtension(msg, E_Ext_More, &Ext{ + Data: String("Hello, world!"), + }) + return UnmarshalTextTest{in: text, out: msg} +} + +func buildExtDataTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + SetExtension(msg, E_Ext_Text, String("Hello, world!")) + SetExtension(msg, E_Ext_Number, Int32(1729)) + return UnmarshalTextTest{in: text, out: msg} +} + +func buildExtRepStringTest(text string) UnmarshalTextTest { + msg := &MyMessage{ + Count: Int32(42), + } + if err := SetExtension(msg, E_Greeting, []string{"bula", "hola"}); err != nil { + panic(err) + } + return UnmarshalTextTest{in: text, out: msg} +} + +var unMarshalTextTests = []UnmarshalTextTest{ + // Basic + { + in: " count:42\n name:\"Dave\" ", + out: &MyMessage{ + Count: Int32(42), + Name: String("Dave"), + }, + }, + + // Empty quoted string + { + in: `count:42 name:""`, + out: &MyMessage{ + Count: Int32(42), + Name: String(""), + }, + }, + + // Quoted string concatenation with double quotes + { + in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string concatenation with single quotes + { + in: "count:42 name: 'My name is '\n'elsewhere'", + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string concatenations with mixed quotes + { + in: "count:42 name: 'My name is '\n\"elsewhere\"", + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + { + in: "count:42 name: \"My name is \"\n'elsewhere'", + out: &MyMessage{ + Count: Int32(42), + Name: String("My name is elsewhere"), + }, + }, + + // Quoted string with escaped apostrophe + { + in: `count:42 name: "HOLIDAY - New Year\'s Day"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("HOLIDAY - New Year's Day"), + }, + }, + + // Quoted string with single quote + { + in: `count:42 name: 'Roger "The Ramster" Ramjet'`, + out: &MyMessage{ + Count: Int32(42), + Name: String(`Roger "The Ramster" Ramjet`), + }, + }, + + // Quoted string with all the accepted special characters from the C++ test + { + in: `count:42 name: ` + "\"\\\"A string with \\' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"", + out: &MyMessage{ + Count: Int32(42), + Name: String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces"), + }, + }, + + // Quoted string with quoted backslash + { + in: `count:42 name: "\\'xyz"`, + out: &MyMessage{ + Count: Int32(42), + Name: String(`\'xyz`), + }, + }, + + // Quoted string with UTF-8 bytes. + { + in: "count:42 name: '\303\277\302\201\x00\xAB\xCD\xEF'", + out: &MyMessage{ + Count: Int32(42), + Name: String("\303\277\302\201\x00\xAB\xCD\xEF"), + }, + }, + + // Quoted string with unicode escapes. + { + in: `count: 42 name: "\u0047\U00000047\uffff\U0010ffff"`, + out: &MyMessage{ + Count: Int32(42), + Name: String("GG\uffff\U0010ffff"), + }, + }, + + // Bad quoted string + { + in: `inner: < host: "\0" >` + "\n", + err: `line 1.15: invalid quoted string "\0": \0 requires 2 following digits`, + }, + + // Bad \u escape + { + in: `count: 42 name: "\u000"`, + err: `line 1.16: invalid quoted string "\u000": \u requires 4 following digits`, + }, + + // Bad \U escape + { + in: `count: 42 name: "\U0000000"`, + err: `line 1.16: invalid quoted string "\U0000000": \U requires 8 following digits`, + }, + + // Bad \U escape + { + in: `count: 42 name: "\xxx"`, + err: `line 1.16: invalid quoted string "\xxx": \xxx contains non-hexadecimal digits`, + }, + + // Number too large for int64 + { + in: "count: 1 others { key: 123456789012345678901 }", + err: "line 1.23: invalid int64: 123456789012345678901", + }, + + // Number too large for int32 + { + in: "count: 1234567890123", + err: "line 1.7: invalid int32: 1234567890123", + }, + + // Number in hexadecimal + { + in: "count: 0x2beef", + out: &MyMessage{ + Count: Int32(0x2beef), + }, + }, + + // Number in octal + { + in: "count: 024601", + out: &MyMessage{ + Count: Int32(024601), + }, + }, + + // Floating point number with "f" suffix + { + in: "count: 4 others:< weight: 17.0f >", + out: &MyMessage{ + Count: Int32(4), + Others: []*OtherMessage{ + { + Weight: Float32(17), + }, + }, + }, + }, + + // Floating point positive infinity + { + in: "count: 4 bigfloat: inf", + out: &MyMessage{ + Count: Int32(4), + Bigfloat: Float64(math.Inf(1)), + }, + }, + + // Floating point negative infinity + { + in: "count: 4 bigfloat: -inf", + out: &MyMessage{ + Count: Int32(4), + Bigfloat: Float64(math.Inf(-1)), + }, + }, + + // Number too large for float32 + { + in: "others:< weight: 12345678901234567890123456789012345678901234567890 >", + err: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890", + }, + + // Number posing as a quoted string + { + in: `inner: < host: 12 >` + "\n", + err: `line 1.15: invalid string: 12`, + }, + + // Quoted string posing as int32 + { + in: `count: "12"`, + err: `line 1.7: invalid int32: "12"`, + }, + + // Quoted string posing a float32 + { + in: `others:< weight: "17.4" >`, + err: `line 1.17: invalid float32: "17.4"`, + }, + + // unclosed bracket doesn't cause infinite loop + { + in: `[`, + err: `line 1.0: unclosed type_url or extension name`, + }, + + // Enum + { + in: `count:42 bikeshed: BLUE`, + out: &MyMessage{ + Count: Int32(42), + Bikeshed: MyMessage_BLUE.Enum(), + }, + }, + + // Repeated field + { + in: `count:42 pet: "horsey" pet:"bunny"`, + out: &MyMessage{ + Count: Int32(42), + Pet: []string{"horsey", "bunny"}, + }, + }, + + // Repeated field with list notation + { + in: `count:42 pet: ["horsey", "bunny"]`, + out: &MyMessage{ + Count: Int32(42), + Pet: []string{"horsey", "bunny"}, + }, + }, + + // Repeated message with/without colon and <>/{} + { + in: `count:42 others:{} others{} others:<> others:{}`, + out: &MyMessage{ + Count: Int32(42), + Others: []*OtherMessage{ + {}, + {}, + {}, + {}, + }, + }, + }, + + // Missing colon for inner message + { + in: `count:42 inner < host: "cauchy.syd" >`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("cauchy.syd"), + }, + }, + }, + + // Missing colon for string field + { + in: `name "Dave"`, + err: `line 1.5: expected ':', found "\"Dave\""`, + }, + + // Missing colon for int32 field + { + in: `count 42`, + err: `line 1.6: expected ':', found "42"`, + }, + + // Missing required field + { + in: `name: "Pawel"`, + err: fmt.Sprintf(`proto: required field "%T.count" not set`, MyMessage{}), + out: &MyMessage{ + Name: String("Pawel"), + }, + }, + + // Missing required field in a required submessage + { + in: `count: 42 we_must_go_deeper < leo_finally_won_an_oscar <> >`, + err: fmt.Sprintf(`proto: required field "%T.host" not set`, InnerMessage{}), + out: &MyMessage{ + Count: Int32(42), + WeMustGoDeeper: &RequiredInnerMessage{LeoFinallyWonAnOscar: &InnerMessage{}}, + }, + }, + + // Repeated non-repeated field + { + in: `name: "Rob" name: "Russ"`, + err: `line 1.12: non-repeated field "name" was repeated`, + }, + + // Group + { + in: `count: 17 SomeGroup { group_field: 12 }`, + out: &MyMessage{ + Count: Int32(17), + Somegroup: &MyMessage_SomeGroup{ + GroupField: Int32(12), + }, + }, + }, + + // Semicolon between fields + { + in: `count:3;name:"Calvin"`, + out: &MyMessage{ + Count: Int32(3), + Name: String("Calvin"), + }, + }, + // Comma between fields + { + in: `count:4,name:"Ezekiel"`, + out: &MyMessage{ + Count: Int32(4), + Name: String("Ezekiel"), + }, + }, + + // Boolean false + { + in: `count:42 inner { host: "example.com" connected: false }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean true + { + in: `count:42 inner { host: "example.com" connected: true }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + // Boolean 0 + { + in: `count:42 inner { host: "example.com" connected: 0 }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean 1 + { + in: `count:42 inner { host: "example.com" connected: 1 }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + // Boolean f + { + in: `count:42 inner { host: "example.com" connected: f }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean t + { + in: `count:42 inner { host: "example.com" connected: t }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + // Boolean False + { + in: `count:42 inner { host: "example.com" connected: False }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(false), + }, + }, + }, + // Boolean True + { + in: `count:42 inner { host: "example.com" connected: True }`, + out: &MyMessage{ + Count: Int32(42), + Inner: &InnerMessage{ + Host: String("example.com"), + Connected: Bool(true), + }, + }, + }, + + // Extension + buildExtStructTest(`count: 42 [test_proto.Ext.more]:`), + buildExtStructTest(`count: 42 [test_proto.Ext.more] {data:"Hello, world!"}`), + buildExtDataTest(`count: 42 [test_proto.Ext.text]:"Hello, world!" [test_proto.Ext.number]:1729`), + buildExtRepStringTest(`count: 42 [test_proto.greeting]:"bula" [test_proto.greeting]:"hola"`), + + // Big all-in-one + { + in: "count:42 # Meaning\n" + + `name:"Dave" ` + + `quote:"\"I didn't want to go.\"" ` + + `pet:"bunny" ` + + `pet:"kitty" ` + + `pet:"horsey" ` + + `inner:<` + + ` host:"footrest.syd" ` + + ` port:7001 ` + + ` connected:true ` + + `> ` + + `others:<` + + ` key:3735928559 ` + + ` value:"\x01A\a\f" ` + + `> ` + + `others:<` + + " weight:58.9 # Atomic weight of Co\n" + + ` inner:<` + + ` host:"lesha.mtv" ` + + ` port:8002 ` + + ` >` + + `>`, + out: &MyMessage{ + Count: Int32(42), + Name: String("Dave"), + Quote: String(`"I didn't want to go."`), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &InnerMessage{ + Host: String("footrest.syd"), + Port: Int32(7001), + Connected: Bool(true), + }, + Others: []*OtherMessage{ + { + Key: Int64(3735928559), + Value: []byte{0x1, 'A', '\a', '\f'}, + }, + { + Weight: Float32(58.9), + Inner: &InnerMessage{ + Host: String("lesha.mtv"), + Port: Int32(8002), + }, + }, + }, + }, + }, +} + +func TestUnmarshalText(t *testing.T) { + for i, test := range unMarshalTextTests { + pb := new(MyMessage) + err := UnmarshalText(test.in, pb) + if test.err == "" { + // We don't expect failure. + if err != nil { + t.Errorf("Test %d: Unexpected error: %v", i, err) + } else if !Equal(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) + } + } else { + // We do expect failure. + if err == nil { + t.Errorf("Test %d: Didn't get expected error: %v", i, test.err) + } else if err.Error() != test.err { + t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v", + i, err.Error(), test.err) + } else if _, ok := err.(*RequiredNotSetError); ok && test.out != nil && !Equal(pb, test.out) { + t.Errorf("Test %d: Incorrect populated \nHave: %v\nWant: %v", + i, pb, test.out) + } + } + } +} + +func TestUnmarshalTextCustomMessage(t *testing.T) { + msg := &textMessage{} + if err := UnmarshalText("custom", msg); err != nil { + t.Errorf("Unexpected error from custom unmarshal: %v", err) + } + if UnmarshalText("not custom", msg) == nil { + t.Errorf("Didn't get expected error from custom unmarshal") + } +} + +// Regression test; this caused a panic. +func TestRepeatedEnum(t *testing.T) { + pb := new(RepeatedEnum) + if err := UnmarshalText("color: RED", pb); err != nil { + t.Fatal(err) + } + exp := &RepeatedEnum{ + Color: []RepeatedEnum_Color{RepeatedEnum_RED}, + } + if !Equal(pb, exp) { + t.Errorf("Incorrect populated \nHave: %v\nWant: %v", pb, exp) + } +} + +func TestProto3TextParsing(t *testing.T) { + m := new(proto3pb.Message) + const in = `name: "Wallace" true_scotsman: true` + want := &proto3pb.Message{ + Name: "Wallace", + TrueScotsman: true, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + +func TestMapParsing(t *testing.T) { + m := new(MessageWithMap) + const in = `name_mapping: name_mapping:` + + `msg_mapping:,>` + // separating commas are okay + `msg_mapping>` + // no colon after "value" + `msg_mapping:>` + // omitted key + `msg_mapping:` + // omitted value + `byte_mapping:` + + `byte_mapping:<>` // omitted key and value + want := &MessageWithMap{ + NameMapping: map[int32]string{ + 1: "Beatles", + 1234: "Feist", + }, + MsgMapping: map[int64]*FloatingPoint{ + -4: {F: Float64(2.0)}, + -2: {F: Float64(4.0)}, + 0: {F: Float64(5.0)}, + 1: nil, + }, + ByteMapping: map[bool][]byte{ + false: nil, + true: []byte("so be it"), + }, + } + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } +} + +func TestOneofParsing(t *testing.T) { + const in = `name:"Shrek"` + m := new(Communique) + want := &Communique{Union: &Communique_Name{"Shrek"}} + if err := UnmarshalText(in, m); err != nil { + t.Fatal(err) + } + if !Equal(m, want) { + t.Errorf("\n got %v\nwant %v", m, want) + } + + const inOverwrite = `name:"Shrek" number:42` + m = new(Communique) + testErr := "line 1.13: field 'number' would overwrite already parsed oneof 'Union'" + if err := UnmarshalText(inOverwrite, m); err == nil { + t.Errorf("TestOneofParsing: Didn't get expected error: %v", testErr) + } else if err.Error() != testErr { + t.Errorf("TestOneofParsing: Incorrect error.\nHave: %v\nWant: %v", + err.Error(), testErr) + } + +} + +var benchInput string + +func init() { + benchInput = "count: 4\n" + for i := 0; i < 1000; i++ { + benchInput += "pet: \"fido\"\n" + } + + // Check it is valid input. + pb := new(MyMessage) + err := UnmarshalText(benchInput, pb) + if err != nil { + panic("Bad benchmark input: " + err.Error()) + } +} + +func BenchmarkUnmarshalText(b *testing.B) { + pb := new(MyMessage) + for i := 0; i < b.N; i++ { + UnmarshalText(benchInput, pb) + } + b.SetBytes(int64(len(benchInput))) +} diff --git a/vendor/github.com/golang/protobuf/proto/text_test.go b/vendor/github.com/golang/protobuf/proto/text_test.go new file mode 100644 index 000000000..3c8b033c0 --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/text_test.go @@ -0,0 +1,518 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2010 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package proto_test + +import ( + "bytes" + "errors" + "io/ioutil" + "math" + "strings" + "sync" + "testing" + + "github.com/golang/protobuf/proto" + + proto3pb "github.com/golang/protobuf/proto/proto3_proto" + pb "github.com/golang/protobuf/proto/test_proto" + anypb "github.com/golang/protobuf/ptypes/any" +) + +// textMessage implements the methods that allow it to marshal and unmarshal +// itself as text. +type textMessage struct { +} + +func (*textMessage) MarshalText() ([]byte, error) { + return []byte("custom"), nil +} + +func (*textMessage) UnmarshalText(bytes []byte) error { + if string(bytes) != "custom" { + return errors.New("expected 'custom'") + } + return nil +} + +func (*textMessage) Reset() {} +func (*textMessage) String() string { return "" } +func (*textMessage) ProtoMessage() {} + +func newTestMessage() *pb.MyMessage { + msg := &pb.MyMessage{ + Count: proto.Int32(42), + Name: proto.String("Dave"), + Quote: proto.String(`"I didn't want to go."`), + Pet: []string{"bunny", "kitty", "horsey"}, + Inner: &pb.InnerMessage{ + Host: proto.String("footrest.syd"), + Port: proto.Int32(7001), + Connected: proto.Bool(true), + }, + Others: []*pb.OtherMessage{ + { + Key: proto.Int64(0xdeadbeef), + Value: []byte{1, 65, 7, 12}, + }, + { + Weight: proto.Float32(6.022), + Inner: &pb.InnerMessage{ + Host: proto.String("lesha.mtv"), + Port: proto.Int32(8002), + }, + }, + }, + Bikeshed: pb.MyMessage_BLUE.Enum(), + Somegroup: &pb.MyMessage_SomeGroup{ + GroupField: proto.Int32(8), + }, + // One normally wouldn't do this. + // This is an undeclared tag 13, as a varint (wire type 0) with value 4. + XXX_unrecognized: []byte{13<<3 | 0, 4}, + } + ext := &pb.Ext{ + Data: proto.String("Big gobs for big rats"), + } + if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil { + panic(err) + } + greetings := []string{"adg", "easy", "cow"} + if err := proto.SetExtension(msg, pb.E_Greeting, greetings); err != nil { + panic(err) + } + + // Add an unknown extension. We marshal a pb.Ext, and fake the ID. + b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")}) + if err != nil { + panic(err) + } + b = append(proto.EncodeVarint(201<<3|proto.WireBytes), b...) + proto.SetRawExtension(msg, 201, b) + + // Extensions can be plain fields, too, so let's test that. + b = append(proto.EncodeVarint(202<<3|proto.WireVarint), 19) + proto.SetRawExtension(msg, 202, b) + + return msg +} + +const text = `count: 42 +name: "Dave" +quote: "\"I didn't want to go.\"" +pet: "bunny" +pet: "kitty" +pet: "horsey" +inner: < + host: "footrest.syd" + port: 7001 + connected: true +> +others: < + key: 3735928559 + value: "\001A\007\014" +> +others: < + weight: 6.022 + inner: < + host: "lesha.mtv" + port: 8002 + > +> +bikeshed: BLUE +SomeGroup { + group_field: 8 +} +/* 2 unknown bytes */ +13: 4 +[test_proto.Ext.more]: < + data: "Big gobs for big rats" +> +[test_proto.greeting]: "adg" +[test_proto.greeting]: "easy" +[test_proto.greeting]: "cow" +/* 13 unknown bytes */ +201: "\t3G skiing" +/* 3 unknown bytes */ +202: 19 +` + +func TestMarshalText(t *testing.T) { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, newTestMessage()); err != nil { + t.Fatalf("proto.MarshalText: %v", err) + } + s := buf.String() + if s != text { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text) + } +} + +func TestMarshalTextCustomMessage(t *testing.T) { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, &textMessage{}); err != nil { + t.Fatalf("proto.MarshalText: %v", err) + } + s := buf.String() + if s != "custom" { + t.Errorf("Got %q, expected %q", s, "custom") + } +} +func TestMarshalTextNil(t *testing.T) { + want := "" + tests := []proto.Message{nil, (*pb.MyMessage)(nil)} + for i, test := range tests { + buf := new(bytes.Buffer) + if err := proto.MarshalText(buf, test); err != nil { + t.Fatal(err) + } + if got := buf.String(); got != want { + t.Errorf("%d: got %q want %q", i, got, want) + } + } +} + +func TestMarshalTextUnknownEnum(t *testing.T) { + // The Color enum only specifies values 0-2. + m := &pb.MyMessage{Bikeshed: pb.MyMessage_Color(3).Enum()} + got := m.String() + const want = `bikeshed:3 ` + if got != want { + t.Errorf("\n got %q\nwant %q", got, want) + } +} + +func TestTextOneof(t *testing.T) { + tests := []struct { + m proto.Message + want string + }{ + // zero message + {&pb.Communique{}, ``}, + // scalar field + {&pb.Communique{Union: &pb.Communique_Number{4}}, `number:4`}, + // message field + {&pb.Communique{Union: &pb.Communique_Msg{ + &pb.Strings{StringField: proto.String("why hello!")}, + }}, `msg:`}, + // bad oneof (should not panic) + {&pb.Communique{Union: &pb.Communique_Msg{nil}}, `msg:/* nil */`}, + } + for _, test := range tests { + got := strings.TrimSpace(test.m.String()) + if got != test.want { + t.Errorf("\n got %s\nwant %s", got, test.want) + } + } +} + +func BenchmarkMarshalTextBuffered(b *testing.B) { + buf := new(bytes.Buffer) + m := newTestMessage() + for i := 0; i < b.N; i++ { + buf.Reset() + proto.MarshalText(buf, m) + } +} + +func BenchmarkMarshalTextUnbuffered(b *testing.B) { + w := ioutil.Discard + m := newTestMessage() + for i := 0; i < b.N; i++ { + proto.MarshalText(w, m) + } +} + +func compact(src string) string { + // s/[ \n]+/ /g; s/ $//; + dst := make([]byte, len(src)) + space, comment := false, false + j := 0 + for i := 0; i < len(src); i++ { + if strings.HasPrefix(src[i:], "/*") { + comment = true + i++ + continue + } + if comment && strings.HasPrefix(src[i:], "*/") { + comment = false + i++ + continue + } + if comment { + continue + } + c := src[i] + if c == ' ' || c == '\n' { + space = true + continue + } + if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<' || dst[j-1] == '{') { + space = false + } + if c == '{' { + space = false + } + if space { + dst[j] = ' ' + j++ + space = false + } + dst[j] = c + j++ + } + if space { + dst[j] = ' ' + j++ + } + return string(dst[0:j]) +} + +var compactText = compact(text) + +func TestCompactText(t *testing.T) { + s := proto.CompactTextString(newTestMessage()) + if s != compactText { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v\n===\n", s, compactText) + } +} + +func TestStringEscaping(t *testing.T) { + testCases := []struct { + in *pb.Strings + out string + }{ + { + // Test data from C++ test (TextFormatTest.StringEscape). + // Single divergence: we don't escape apostrophes. + &pb.Strings{StringField: proto.String("\"A string with ' characters \n and \r newlines and \t tabs and \001 slashes \\ and multiple spaces")}, + "string_field: \"\\\"A string with ' characters \\n and \\r newlines and \\t tabs and \\001 slashes \\\\ and multiple spaces\"\n", + }, + { + // Test data from the same C++ test. + &pb.Strings{StringField: proto.String("\350\260\267\346\255\214")}, + "string_field: \"\\350\\260\\267\\346\\255\\214\"\n", + }, + { + // Some UTF-8. + &pb.Strings{StringField: proto.String("\x00\x01\xff\x81")}, + `string_field: "\000\001\377\201"` + "\n", + }, + } + + for i, tc := range testCases { + var buf bytes.Buffer + if err := proto.MarshalText(&buf, tc.in); err != nil { + t.Errorf("proto.MarsalText: %v", err) + continue + } + s := buf.String() + if s != tc.out { + t.Errorf("#%d: Got:\n%s\nExpected:\n%s\n", i, s, tc.out) + continue + } + + // Check round-trip. + pb := new(pb.Strings) + if err := proto.UnmarshalText(s, pb); err != nil { + t.Errorf("#%d: UnmarshalText: %v", i, err) + continue + } + if !proto.Equal(pb, tc.in) { + t.Errorf("#%d: Round-trip failed:\nstart: %v\n end: %v", i, tc.in, pb) + } + } +} + +// A limitedWriter accepts some output before it fails. +// This is a proxy for something like a nearly-full or imminently-failing disk, +// or a network connection that is about to die. +type limitedWriter struct { + b bytes.Buffer + limit int +} + +var outOfSpace = errors.New("proto: insufficient space") + +func (w *limitedWriter) Write(p []byte) (n int, err error) { + var avail = w.limit - w.b.Len() + if avail <= 0 { + return 0, outOfSpace + } + if len(p) <= avail { + return w.b.Write(p) + } + n, _ = w.b.Write(p[:avail]) + return n, outOfSpace +} + +func TestMarshalTextFailing(t *testing.T) { + // Try lots of different sizes to exercise more error code-paths. + for lim := 0; lim < len(text); lim++ { + buf := new(limitedWriter) + buf.limit = lim + err := proto.MarshalText(buf, newTestMessage()) + // We expect a certain error, but also some partial results in the buffer. + if err != outOfSpace { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", err, outOfSpace) + } + s := buf.b.String() + x := text[:buf.limit] + if s != x { + t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, x) + } + } +} + +func TestFloats(t *testing.T) { + tests := []struct { + f float64 + want string + }{ + {0, "0"}, + {4.7, "4.7"}, + {math.Inf(1), "inf"}, + {math.Inf(-1), "-inf"}, + {math.NaN(), "nan"}, + } + for _, test := range tests { + msg := &pb.FloatingPoint{F: &test.f} + got := strings.TrimSpace(msg.String()) + want := `f:` + test.want + if got != want { + t.Errorf("f=%f: got %q, want %q", test.f, got, want) + } + } +} + +func TestRepeatedNilText(t *testing.T) { + m := &pb.MessageList{ + Message: []*pb.MessageList_Message{ + nil, + &pb.MessageList_Message{ + Name: proto.String("Horse"), + }, + nil, + }, + } + want := `Message +Message { + name: "Horse" +} +Message +` + if s := proto.MarshalTextString(m); s != want { + t.Errorf(" got: %s\nwant: %s", s, want) + } +} + +func TestProto3Text(t *testing.T) { + tests := []struct { + m proto.Message + want string + }{ + // zero message + {&proto3pb.Message{}, ``}, + // zero message except for an empty byte slice + {&proto3pb.Message{Data: []byte{}}, ``}, + // trivial case + {&proto3pb.Message{Name: "Rob", HeightInCm: 175}, `name:"Rob" height_in_cm:175`}, + // empty map + {&pb.MessageWithMap{}, ``}, + // non-empty map; map format is the same as a repeated struct, + // and they are sorted by key (numerically for numeric keys). + { + &pb.MessageWithMap{NameMapping: map[int32]string{ + -1: "Negatory", + 7: "Lucky", + 1234: "Feist", + 6345789: "Otis", + }}, + `name_mapping: ` + + `name_mapping: ` + + `name_mapping: ` + + `name_mapping:`, + }, + // map with nil value; not well-defined, but we shouldn't crash + { + &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{7: nil}}, + `msg_mapping:`, + }, + } + for _, test := range tests { + got := strings.TrimSpace(test.m.String()) + if got != test.want { + t.Errorf("\n got %s\nwant %s", got, test.want) + } + } +} + +func TestRacyMarshal(t *testing.T) { + // This test should be run with the race detector. + + any := &pb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")} + proto.SetExtension(any, pb.E_Ext_Text, proto.String("bar")) + b, err := proto.Marshal(any) + if err != nil { + panic(err) + } + m := &proto3pb.Message{ + Name: "David", + ResultCount: 47, + Anything: &anypb.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any), Value: b}, + } + + wantText := proto.MarshalTextString(m) + wantBytes, err := proto.Marshal(m) + if err != nil { + t.Fatalf("proto.Marshal error: %v", err) + } + + var wg sync.WaitGroup + defer wg.Wait() + wg.Add(20) + for i := 0; i < 10; i++ { + go func() { + defer wg.Done() + got := proto.MarshalTextString(m) + if got != wantText { + t.Errorf("proto.MarshalTextString = %q, want %q", got, wantText) + } + }() + go func() { + defer wg.Done() + got, err := proto.Marshal(m) + if !bytes.Equal(got, wantBytes) || err != nil { + t.Errorf("proto.Marshal = (%x, %v), want (%x, nil)", got, err, wantBytes) + } + }() + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any/any.proto b/vendor/github.com/golang/protobuf/ptypes/any/any.proto new file mode 100644 index 000000000..c74866762 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any/any.proto @@ -0,0 +1,149 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name whose content describes the type of the + // serialized protocol buffer message. + // + // For URLs which use the scheme `http`, `https`, or no scheme, the + // following restrictions and interpretations apply: + // + // * If no scheme is provided, `https` is assumed. + // * The last segment of the URL's path must represent the fully + // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/any_test.go b/vendor/github.com/golang/protobuf/ptypes/any_test.go new file mode 100644 index 000000000..ed675b489 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/any_test.go @@ -0,0 +1,113 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package ptypes + +import ( + "testing" + + "github.com/golang/protobuf/proto" + pb "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/golang/protobuf/ptypes/any" +) + +func TestMarshalUnmarshal(t *testing.T) { + orig := &any.Any{Value: []byte("test")} + + packed, err := MarshalAny(orig) + if err != nil { + t.Errorf("MarshalAny(%+v): got: _, %v exp: _, nil", orig, err) + } + + unpacked := &any.Any{} + err = UnmarshalAny(packed, unpacked) + if err != nil || !proto.Equal(unpacked, orig) { + t.Errorf("got: %v, %+v; want nil, %+v", err, unpacked, orig) + } +} + +func TestIs(t *testing.T) { + a, err := MarshalAny(&pb.FileDescriptorProto{}) + if err != nil { + t.Fatal(err) + } + if Is(a, &pb.DescriptorProto{}) { + t.Error("FileDescriptorProto is not a DescriptorProto, but Is says it is") + } + if !Is(a, &pb.FileDescriptorProto{}) { + t.Error("FileDescriptorProto is indeed a FileDescriptorProto, but Is says it is not") + } +} + +func TestIsDifferentUrlPrefixes(t *testing.T) { + m := &pb.FileDescriptorProto{} + a := &any.Any{TypeUrl: "foo/bar/" + proto.MessageName(m)} + if !Is(a, m) { + t.Errorf("message with type url %q didn't satisfy Is for type %q", a.TypeUrl, proto.MessageName(m)) + } +} + +func TestUnmarshalDynamic(t *testing.T) { + want := &pb.FileDescriptorProto{Name: proto.String("foo")} + a, err := MarshalAny(want) + if err != nil { + t.Fatal(err) + } + var got DynamicAny + if err := UnmarshalAny(a, &got); err != nil { + t.Fatal(err) + } + if !proto.Equal(got.Message, want) { + t.Errorf("invalid result from UnmarshalAny, got %q want %q", got.Message, want) + } +} + +func TestEmpty(t *testing.T) { + want := &pb.FileDescriptorProto{} + a, err := MarshalAny(want) + if err != nil { + t.Fatal(err) + } + got, err := Empty(a) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(got, want) { + t.Errorf("unequal empty message, got %q, want %q", got, want) + } + + // that's a valid type_url for a message which shouldn't be linked into this + // test binary. We want an error. + a.TypeUrl = "type.googleapis.com/google.protobuf.FieldMask" + if _, err := Empty(a); err == nil { + t.Errorf("got no error for an attempt to create a message of type %q, which shouldn't be linked in", a.TypeUrl) + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto new file mode 100644 index 000000000..975fce41a --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration/duration.proto @@ -0,0 +1,117 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/duration"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (durations.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +// +message Duration { + + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/duration_test.go b/vendor/github.com/golang/protobuf/ptypes/duration_test.go new file mode 100644 index 000000000..e00491a34 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/duration_test.go @@ -0,0 +1,121 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package ptypes + +import ( + "math" + "testing" + "time" + + "github.com/golang/protobuf/proto" + durpb "github.com/golang/protobuf/ptypes/duration" +) + +const ( + minGoSeconds = math.MinInt64 / int64(1e9) + maxGoSeconds = math.MaxInt64 / int64(1e9) +) + +var durationTests = []struct { + proto *durpb.Duration + isValid bool + inRange bool + dur time.Duration +}{ + // The zero duration. + {&durpb.Duration{Seconds: 0, Nanos: 0}, true, true, 0}, + // Some ordinary non-zero durations. + {&durpb.Duration{Seconds: 100, Nanos: 0}, true, true, 100 * time.Second}, + {&durpb.Duration{Seconds: -100, Nanos: 0}, true, true, -100 * time.Second}, + {&durpb.Duration{Seconds: 100, Nanos: 987}, true, true, 100*time.Second + 987}, + {&durpb.Duration{Seconds: -100, Nanos: -987}, true, true, -(100*time.Second + 987)}, + // The largest duration representable in Go. + {&durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}, true, true, math.MaxInt64}, + // The smallest duration representable in Go. + {&durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}, true, true, math.MinInt64}, + {nil, false, false, 0}, + {&durpb.Duration{Seconds: -100, Nanos: 987}, false, false, 0}, + {&durpb.Duration{Seconds: 100, Nanos: -987}, false, false, 0}, + {&durpb.Duration{Seconds: math.MinInt64, Nanos: 0}, false, false, 0}, + {&durpb.Duration{Seconds: math.MaxInt64, Nanos: 0}, false, false, 0}, + // The largest valid duration. + {&durpb.Duration{Seconds: maxSeconds, Nanos: 1e9 - 1}, true, false, 0}, + // The smallest valid duration. + {&durpb.Duration{Seconds: minSeconds, Nanos: -(1e9 - 1)}, true, false, 0}, + // The smallest invalid duration above the valid range. + {&durpb.Duration{Seconds: maxSeconds + 1, Nanos: 0}, false, false, 0}, + // The largest invalid duration below the valid range. + {&durpb.Duration{Seconds: minSeconds - 1, Nanos: -(1e9 - 1)}, false, false, 0}, + // One nanosecond past the largest duration representable in Go. + {&durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64-1e9*maxGoSeconds) + 1}, true, false, 0}, + // One nanosecond past the smallest duration representable in Go. + {&durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64-1e9*minGoSeconds) - 1}, true, false, 0}, + // One second past the largest duration representable in Go. + {&durpb.Duration{Seconds: maxGoSeconds + 1, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}, true, false, 0}, + // One second past the smallest duration representable in Go. + {&durpb.Duration{Seconds: minGoSeconds - 1, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}, true, false, 0}, +} + +func TestValidateDuration(t *testing.T) { + for _, test := range durationTests { + err := validateDuration(test.proto) + gotValid := (err == nil) + if gotValid != test.isValid { + t.Errorf("validateDuration(%v) = %t, want %t", test.proto, gotValid, test.isValid) + } + } +} + +func TestDuration(t *testing.T) { + for _, test := range durationTests { + got, err := Duration(test.proto) + gotOK := (err == nil) + wantOK := test.isValid && test.inRange + if gotOK != wantOK { + t.Errorf("Duration(%v) ok = %t, want %t", test.proto, gotOK, wantOK) + } + if err == nil && got != test.dur { + t.Errorf("Duration(%v) = %v, want %v", test.proto, got, test.dur) + } + } +} + +func TestDurationProto(t *testing.T) { + for _, test := range durationTests { + if test.isValid && test.inRange { + got := DurationProto(test.dur) + if !proto.Equal(got, test.proto) { + t.Errorf("DurationProto(%v) = %v, want %v", test.dur, got, test.proto) + } + } + } +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto new file mode 100644 index 000000000..06750ab1f --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto @@ -0,0 +1,133 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/timestamp"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// A Timestamp represents a point in time independent of any time zone +// or calendar, represented as seconds and fractions of seconds at +// nanosecond resolution in UTC Epoch time. It is encoded using the +// Proleptic Gregorian Calendar which extends the Gregorian calendar +// backwards to year one. It is encoded assuming all minutes are 60 +// seconds long, i.e. leap seconds are "smeared" so that no leap second +// table is needed for interpretation. Range is from +// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +// By restricting to that range, we ensure that we can convert to +// and from RFC 3339 date strings. +// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// +// Example 5: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required, though only UTC (as indicated by "Z") is presently supported. +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString] +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) +// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one +// can use the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--) +// to obtain a formatter capable of generating timestamps in this format. +// +// +message Timestamp { + + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp_test.go b/vendor/github.com/golang/protobuf/ptypes/timestamp_test.go new file mode 100644 index 000000000..6e3c969b9 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp_test.go @@ -0,0 +1,153 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2016 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package ptypes + +import ( + "math" + "testing" + "time" + + "github.com/golang/protobuf/proto" + tspb "github.com/golang/protobuf/ptypes/timestamp" +) + +var tests = []struct { + ts *tspb.Timestamp + valid bool + t time.Time +}{ + // The timestamp representing the Unix epoch date. + {&tspb.Timestamp{Seconds: 0, Nanos: 0}, true, utcDate(1970, 1, 1)}, + // The smallest representable timestamp. + {&tspb.Timestamp{Seconds: math.MinInt64, Nanos: math.MinInt32}, false, + time.Unix(math.MinInt64, math.MinInt32).UTC()}, + // The smallest representable timestamp with non-negative nanos. + {&tspb.Timestamp{Seconds: math.MinInt64, Nanos: 0}, false, time.Unix(math.MinInt64, 0).UTC()}, + // The earliest valid timestamp. + {&tspb.Timestamp{Seconds: minValidSeconds, Nanos: 0}, true, utcDate(1, 1, 1)}, + //"0001-01-01T00:00:00Z"}, + // The largest representable timestamp. + {&tspb.Timestamp{Seconds: math.MaxInt64, Nanos: math.MaxInt32}, false, + time.Unix(math.MaxInt64, math.MaxInt32).UTC()}, + // The largest representable timestamp with nanos in range. + {&tspb.Timestamp{Seconds: math.MaxInt64, Nanos: 1e9 - 1}, false, + time.Unix(math.MaxInt64, 1e9-1).UTC()}, + // The largest valid timestamp. + {&tspb.Timestamp{Seconds: maxValidSeconds - 1, Nanos: 1e9 - 1}, true, + time.Date(9999, 12, 31, 23, 59, 59, 1e9-1, time.UTC)}, + // The smallest invalid timestamp that is larger than the valid range. + {&tspb.Timestamp{Seconds: maxValidSeconds, Nanos: 0}, false, time.Unix(maxValidSeconds, 0).UTC()}, + // A date before the epoch. + {&tspb.Timestamp{Seconds: -281836800, Nanos: 0}, true, utcDate(1961, 1, 26)}, + // A date after the epoch. + {&tspb.Timestamp{Seconds: 1296000000, Nanos: 0}, true, utcDate(2011, 1, 26)}, + // A date after the epoch, in the middle of the day. + {&tspb.Timestamp{Seconds: 1296012345, Nanos: 940483}, true, + time.Date(2011, 1, 26, 3, 25, 45, 940483, time.UTC)}, +} + +func TestValidateTimestamp(t *testing.T) { + for _, s := range tests { + got := validateTimestamp(s.ts) + if (got == nil) != s.valid { + t.Errorf("validateTimestamp(%v) = %v, want %v", s.ts, got, s.valid) + } + } +} + +func TestTimestamp(t *testing.T) { + for _, s := range tests { + got, err := Timestamp(s.ts) + if (err == nil) != s.valid { + t.Errorf("Timestamp(%v) error = %v, but valid = %t", s.ts, err, s.valid) + } else if s.valid && got != s.t { + t.Errorf("Timestamp(%v) = %v, want %v", s.ts, got, s.t) + } + } + // Special case: a nil Timestamp is an error, but returns the 0 Unix time. + got, err := Timestamp(nil) + want := time.Unix(0, 0).UTC() + if got != want { + t.Errorf("Timestamp(nil) = %v, want %v", got, want) + } + if err == nil { + t.Errorf("Timestamp(nil) error = nil, expected error") + } +} + +func TestTimestampProto(t *testing.T) { + for _, s := range tests { + got, err := TimestampProto(s.t) + if (err == nil) != s.valid { + t.Errorf("TimestampProto(%v) error = %v, but valid = %t", s.t, err, s.valid) + } else if s.valid && !proto.Equal(got, s.ts) { + t.Errorf("TimestampProto(%v) = %v, want %v", s.t, got, s.ts) + } + } + // No corresponding special case here: no time.Time results in a nil Timestamp. +} + +func TestTimestampString(t *testing.T) { + for _, test := range []struct { + ts *tspb.Timestamp + want string + }{ + // Not much testing needed because presumably time.Format is + // well-tested. + {&tspb.Timestamp{Seconds: 0, Nanos: 0}, "1970-01-01T00:00:00Z"}, + {&tspb.Timestamp{Seconds: minValidSeconds - 1, Nanos: 0}, "(timestamp: seconds:-62135596801 before 0001-01-01)"}, + } { + got := TimestampString(test.ts) + if got != test.want { + t.Errorf("TimestampString(%v) = %q, want %q", test.ts, got, test.want) + } + } +} + +func utcDate(year, month, day int) time.Time { + return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) +} + +func TestTimestampNow(t *testing.T) { + // Bracket the expected time. + before := time.Now() + ts := TimestampNow() + after := time.Now() + + tm, err := Timestamp(ts) + if err != nil { + t.Errorf("between %v and %v\nTimestampNow() = %v\nwhich is invalid (%v)", before, after, ts, err) + } + if tm.Before(before) || tm.After(after) { + t.Errorf("between %v and %v\nTimestamp(TimestampNow()) = %v", before, after, tm) + } +} diff --git a/vendor/github.com/golang/protobuf/regenerate.sh b/vendor/github.com/golang/protobuf/regenerate.sh new file mode 100755 index 000000000..dc7e2d1f6 --- /dev/null +++ b/vendor/github.com/golang/protobuf/regenerate.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -e + +# Install the working tree's protoc-gen-gen in a tempdir. +tmpdir=$(mktemp -d -t regen-wkt.XXXXXX) +trap 'rm -rf $tmpdir' EXIT +mkdir -p $tmpdir/bin +PATH=$tmpdir/bin:$PATH +GOBIN=$tmpdir/bin go install ./protoc-gen-go + +# Public imports require at least Go 1.9. +supportTypeAliases="" +if go list -f '{{context.ReleaseTags}}' runtime | grep -q go1.9; then + supportTypeAliases=1 +fi + +# Generate various test protos. +PROTO_DIRS=( + conformance/internal/conformance_proto + jsonpb/jsonpb_test_proto + proto + protoc-gen-go/testdata +) +for dir in ${PROTO_DIRS[@]}; do + for p in `find $dir -name "*.proto"`; do + if [[ $p == */import_public/* && ! $supportTypeAliases ]]; then + echo "# $p (skipped)" + continue; + fi + echo "# $p" + protoc -I$dir --go_out=plugins=grpc,paths=source_relative:$dir $p + done +done + +# Deriving the location of the source protos from the path to the +# protoc binary may be a bit odd, but this is what protoc itself does. +PROTO_INCLUDE=$(dirname $(dirname $(which protoc)))/include + +# Well-known types. +WKT_PROTOS=(any duration empty struct timestamp wrappers) +for p in ${WKT_PROTOS[@]}; do + echo "# google/protobuf/$p.proto" + protoc --go_out=paths=source_relative:$tmpdir google/protobuf/$p.proto + cp $tmpdir/google/protobuf/$p.pb.go ptypes/$p + cp $PROTO_INCLUDE/google/protobuf/$p.proto ptypes/$p +done + +# descriptor.proto. +echo "# google/protobuf/descriptor.proto" +protoc --go_out=paths=source_relative:$tmpdir google/protobuf/descriptor.proto +cp $tmpdir/google/protobuf/descriptor.pb.go protoc-gen-go/descriptor +cp $PROTO_INCLUDE/google/protobuf/descriptor.proto protoc-gen-go/descriptor diff --git a/vendor/github.com/google/btree/.travis.yml b/vendor/github.com/google/btree/.travis.yml new file mode 100644 index 000000000..4f2ee4d97 --- /dev/null +++ b/vendor/github.com/google/btree/.travis.yml @@ -0,0 +1 @@ +language: go diff --git a/vendor/github.com/google/btree/README.md b/vendor/github.com/google/btree/README.md new file mode 100644 index 000000000..6062a4dac --- /dev/null +++ b/vendor/github.com/google/btree/README.md @@ -0,0 +1,12 @@ +# BTree implementation for Go + +![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master) + +This package provides an in-memory B-Tree implementation for Go, useful as +an ordered, mutable data structure. + +The API is based off of the wonderful +http://godoc.org/github.com/petar/GoLLRB/llrb, and is meant to allow btree to +act as a drop-in replacement for gollrb trees. + +See http://godoc.org/github.com/google/btree for documentation. diff --git a/vendor/github.com/google/btree/btree_test.go b/vendor/github.com/google/btree/btree_test.go new file mode 100644 index 000000000..78a90cd8a --- /dev/null +++ b/vendor/github.com/google/btree/btree_test.go @@ -0,0 +1,785 @@ +// Copyright 2014 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 btree + +import ( + "flag" + "fmt" + "math/rand" + "reflect" + "sort" + "sync" + "testing" + "time" +) + +func init() { + seed := time.Now().Unix() + fmt.Println(seed) + rand.Seed(seed) +} + +// perm returns a random permutation of n Int items in the range [0, n). +func perm(n int) (out []Item) { + for _, v := range rand.Perm(n) { + out = append(out, Int(v)) + } + return +} + +// rang returns an ordered list of Int items in the range [0, n). +func rang(n int) (out []Item) { + for i := 0; i < n; i++ { + out = append(out, Int(i)) + } + return +} + +// all extracts all items from a tree in order as a slice. +func all(t *BTree) (out []Item) { + t.Ascend(func(a Item) bool { + out = append(out, a) + return true + }) + return +} + +// rangerev returns a reversed ordered list of Int items in the range [0, n). +func rangrev(n int) (out []Item) { + for i := n - 1; i >= 0; i-- { + out = append(out, Int(i)) + } + return +} + +// allrev extracts all items from a tree in reverse order as a slice. +func allrev(t *BTree) (out []Item) { + t.Descend(func(a Item) bool { + out = append(out, a) + return true + }) + return +} + +var btreeDegree = flag.Int("degree", 32, "B-Tree degree") + +func TestBTree(t *testing.T) { + tr := New(*btreeDegree) + const treeSize = 10000 + for i := 0; i < 10; i++ { + if min := tr.Min(); min != nil { + t.Fatalf("empty min, got %+v", min) + } + if max := tr.Max(); max != nil { + t.Fatalf("empty max, got %+v", max) + } + for _, item := range perm(treeSize) { + if x := tr.ReplaceOrInsert(item); x != nil { + t.Fatal("insert found item", item) + } + } + for _, item := range perm(treeSize) { + if x := tr.ReplaceOrInsert(item); x == nil { + t.Fatal("insert didn't find item", item) + } + } + if min, want := tr.Min(), Item(Int(0)); min != want { + t.Fatalf("min: want %+v, got %+v", want, min) + } + if max, want := tr.Max(), Item(Int(treeSize-1)); max != want { + t.Fatalf("max: want %+v, got %+v", want, max) + } + got := all(tr) + want := rang(treeSize) + if !reflect.DeepEqual(got, want) { + t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) + } + + gotrev := allrev(tr) + wantrev := rangrev(treeSize) + if !reflect.DeepEqual(gotrev, wantrev) { + t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) + } + + for _, item := range perm(treeSize) { + if x := tr.Delete(item); x == nil { + t.Fatalf("didn't find %v", item) + } + } + if got = all(tr); len(got) > 0 { + t.Fatalf("some left!: %v", got) + } + } +} + +func ExampleBTree() { + tr := New(*btreeDegree) + for i := Int(0); i < 10; i++ { + tr.ReplaceOrInsert(i) + } + fmt.Println("len: ", tr.Len()) + fmt.Println("get3: ", tr.Get(Int(3))) + fmt.Println("get100: ", tr.Get(Int(100))) + fmt.Println("del4: ", tr.Delete(Int(4))) + fmt.Println("del100: ", tr.Delete(Int(100))) + fmt.Println("replace5: ", tr.ReplaceOrInsert(Int(5))) + fmt.Println("replace100:", tr.ReplaceOrInsert(Int(100))) + fmt.Println("min: ", tr.Min()) + fmt.Println("delmin: ", tr.DeleteMin()) + fmt.Println("max: ", tr.Max()) + fmt.Println("delmax: ", tr.DeleteMax()) + fmt.Println("len: ", tr.Len()) + // Output: + // len: 10 + // get3: 3 + // get100: + // del4: 4 + // del100: + // replace5: 5 + // replace100: + // min: 0 + // delmin: 0 + // max: 100 + // delmax: 100 + // len: 8 +} + +func TestDeleteMin(t *testing.T) { + tr := New(3) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + for v := tr.DeleteMin(); v != nil; v = tr.DeleteMin() { + got = append(got, v) + } + if want := rang(100); !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } +} + +func TestDeleteMax(t *testing.T) { + tr := New(3) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + for v := tr.DeleteMax(); v != nil; v = tr.DeleteMax() { + got = append(got, v) + } + // Reverse our list. + for i := 0; i < len(got)/2; i++ { + got[i], got[len(got)-i-1] = got[len(got)-i-1], got[i] + } + if want := rang(100); !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } +} + +func TestAscendRange(t *testing.T) { + tr := New(2) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.AscendRange(Int(40), Int(60), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rang(100)[40:60]; !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.AscendRange(Int(40), Int(60), func(a Item) bool { + if a.(Int) > 50 { + return false + } + got = append(got, a) + return true + }) + if want := rang(100)[40:51]; !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } +} + +func TestDescendRange(t *testing.T) { + tr := New(2) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.DescendRange(Int(60), Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rangrev(100)[39:59]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.DescendRange(Int(60), Int(40), func(a Item) bool { + if a.(Int) < 50 { + return false + } + got = append(got, a) + return true + }) + if want := rangrev(100)[39:50]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendrange:\n got: %v\nwant: %v", got, want) + } +} +func TestAscendLessThan(t *testing.T) { + tr := New(*btreeDegree) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.AscendLessThan(Int(60), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rang(100)[:60]; !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.AscendLessThan(Int(60), func(a Item) bool { + if a.(Int) > 50 { + return false + } + got = append(got, a) + return true + }) + if want := rang(100)[:51]; !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } +} + +func TestDescendLessOrEqual(t *testing.T) { + tr := New(*btreeDegree) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.DescendLessOrEqual(Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rangrev(100)[59:]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.DescendLessOrEqual(Int(60), func(a Item) bool { + if a.(Int) < 50 { + return false + } + got = append(got, a) + return true + }) + if want := rangrev(100)[39:50]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendlessorequal:\n got: %v\nwant: %v", got, want) + } +} +func TestAscendGreaterOrEqual(t *testing.T) { + tr := New(*btreeDegree) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.AscendGreaterOrEqual(Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rang(100)[40:]; !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.AscendGreaterOrEqual(Int(40), func(a Item) bool { + if a.(Int) > 50 { + return false + } + got = append(got, a) + return true + }) + if want := rang(100)[40:51]; !reflect.DeepEqual(got, want) { + t.Fatalf("ascendrange:\n got: %v\nwant: %v", got, want) + } +} + +func TestDescendGreaterThan(t *testing.T) { + tr := New(*btreeDegree) + for _, v := range perm(100) { + tr.ReplaceOrInsert(v) + } + var got []Item + tr.DescendGreaterThan(Int(40), func(a Item) bool { + got = append(got, a) + return true + }) + if want := rangrev(100)[:59]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want) + } + got = got[:0] + tr.DescendGreaterThan(Int(40), func(a Item) bool { + if a.(Int) < 50 { + return false + } + got = append(got, a) + return true + }) + if want := rangrev(100)[:50]; !reflect.DeepEqual(got, want) { + t.Fatalf("descendgreaterthan:\n got: %v\nwant: %v", got, want) + } +} + +const benchmarkTreeSize = 10000 + +func BenchmarkInsert(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + b.StartTimer() + i := 0 + for i < b.N { + tr := New(*btreeDegree) + for _, item := range insertP { + tr.ReplaceOrInsert(item) + i++ + if i >= b.N { + return + } + } + } +} + +func BenchmarkSeek(b *testing.B) { + b.StopTimer() + size := 100000 + insertP := perm(size) + tr := New(*btreeDegree) + for _, item := range insertP { + tr.ReplaceOrInsert(item) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + tr.AscendGreaterOrEqual(Int(i%size), func(i Item) bool { return false }) + } +} + +func BenchmarkDeleteInsert(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, item := range insertP { + tr.ReplaceOrInsert(item) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + tr.Delete(insertP[i%benchmarkTreeSize]) + tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize]) + } +} + +func BenchmarkDeleteInsertCloneOnce(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, item := range insertP { + tr.ReplaceOrInsert(item) + } + tr = tr.Clone() + b.StartTimer() + for i := 0; i < b.N; i++ { + tr.Delete(insertP[i%benchmarkTreeSize]) + tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize]) + } +} + +func BenchmarkDeleteInsertCloneEachTime(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, item := range insertP { + tr.ReplaceOrInsert(item) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + tr = tr.Clone() + tr.Delete(insertP[i%benchmarkTreeSize]) + tr.ReplaceOrInsert(insertP[i%benchmarkTreeSize]) + } +} + +func BenchmarkDelete(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + removeP := perm(benchmarkTreeSize) + b.StartTimer() + i := 0 + for i < b.N { + b.StopTimer() + tr := New(*btreeDegree) + for _, v := range insertP { + tr.ReplaceOrInsert(v) + } + b.StartTimer() + for _, item := range removeP { + tr.Delete(item) + i++ + if i >= b.N { + return + } + } + if tr.Len() > 0 { + panic(tr.Len()) + } + } +} + +func BenchmarkGet(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + removeP := perm(benchmarkTreeSize) + b.StartTimer() + i := 0 + for i < b.N { + b.StopTimer() + tr := New(*btreeDegree) + for _, v := range insertP { + tr.ReplaceOrInsert(v) + } + b.StartTimer() + for _, item := range removeP { + tr.Get(item) + i++ + if i >= b.N { + return + } + } + } +} + +func BenchmarkGetCloneEachTime(b *testing.B) { + b.StopTimer() + insertP := perm(benchmarkTreeSize) + removeP := perm(benchmarkTreeSize) + b.StartTimer() + i := 0 + for i < b.N { + b.StopTimer() + tr := New(*btreeDegree) + for _, v := range insertP { + tr.ReplaceOrInsert(v) + } + b.StartTimer() + for _, item := range removeP { + tr = tr.Clone() + tr.Get(item) + i++ + if i >= b.N { + return + } + } + } +} + +type byInts []Item + +func (a byInts) Len() int { + return len(a) +} + +func (a byInts) Less(i, j int) bool { + return a[i].(Int) < a[j].(Int) +} + +func (a byInts) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func BenchmarkAscend(b *testing.B) { + arr := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, v := range arr { + tr.ReplaceOrInsert(v) + } + sort.Sort(byInts(arr)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + j := 0 + tr.Ascend(func(item Item) bool { + if item.(Int) != arr[j].(Int) { + b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) + } + j++ + return true + }) + } +} + +func BenchmarkDescend(b *testing.B) { + arr := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, v := range arr { + tr.ReplaceOrInsert(v) + } + sort.Sort(byInts(arr)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + j := len(arr) - 1 + tr.Descend(func(item Item) bool { + if item.(Int) != arr[j].(Int) { + b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) + } + j-- + return true + }) + } +} +func BenchmarkAscendRange(b *testing.B) { + arr := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, v := range arr { + tr.ReplaceOrInsert(v) + } + sort.Sort(byInts(arr)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + j := 100 + tr.AscendRange(Int(100), arr[len(arr)-100], func(item Item) bool { + if item.(Int) != arr[j].(Int) { + b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) + } + j++ + return true + }) + if j != len(arr)-100 { + b.Fatalf("expected: %v, got %v", len(arr)-100, j) + } + } +} + +func BenchmarkDescendRange(b *testing.B) { + arr := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, v := range arr { + tr.ReplaceOrInsert(v) + } + sort.Sort(byInts(arr)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + j := len(arr) - 100 + tr.DescendRange(arr[len(arr)-100], Int(100), func(item Item) bool { + if item.(Int) != arr[j].(Int) { + b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) + } + j-- + return true + }) + if j != 100 { + b.Fatalf("expected: %v, got %v", len(arr)-100, j) + } + } +} +func BenchmarkAscendGreaterOrEqual(b *testing.B) { + arr := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, v := range arr { + tr.ReplaceOrInsert(v) + } + sort.Sort(byInts(arr)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + j := 100 + k := 0 + tr.AscendGreaterOrEqual(Int(100), func(item Item) bool { + if item.(Int) != arr[j].(Int) { + b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) + } + j++ + k++ + return true + }) + if j != len(arr) { + b.Fatalf("expected: %v, got %v", len(arr), j) + } + if k != len(arr)-100 { + b.Fatalf("expected: %v, got %v", len(arr)-100, k) + } + } +} +func BenchmarkDescendLessOrEqual(b *testing.B) { + arr := perm(benchmarkTreeSize) + tr := New(*btreeDegree) + for _, v := range arr { + tr.ReplaceOrInsert(v) + } + sort.Sort(byInts(arr)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + j := len(arr) - 100 + k := len(arr) + tr.DescendLessOrEqual(arr[len(arr)-100], func(item Item) bool { + if item.(Int) != arr[j].(Int) { + b.Fatalf("mismatch: expected: %v, got %v", arr[j].(Int), item.(Int)) + } + j-- + k-- + return true + }) + if j != -1 { + b.Fatalf("expected: %v, got %v", -1, j) + } + if k != 99 { + b.Fatalf("expected: %v, got %v", 99, k) + } + } +} + +const cloneTestSize = 10000 + +func cloneTest(t *testing.T, b *BTree, start int, p []Item, wg *sync.WaitGroup, trees *[]*BTree) { + t.Logf("Starting new clone at %v", start) + *trees = append(*trees, b) + for i := start; i < cloneTestSize; i++ { + b.ReplaceOrInsert(p[i]) + if i%(cloneTestSize/5) == 0 { + wg.Add(1) + go cloneTest(t, b.Clone(), i+1, p, wg, trees) + } + } + wg.Done() +} + +func TestCloneConcurrentOperations(t *testing.T) { + b := New(*btreeDegree) + trees := []*BTree{} + p := perm(cloneTestSize) + var wg sync.WaitGroup + wg.Add(1) + go cloneTest(t, b, 0, p, &wg, &trees) + wg.Wait() + want := rang(cloneTestSize) + t.Logf("Starting equality checks on %d trees", len(trees)) + for i, tree := range trees { + if !reflect.DeepEqual(want, all(tree)) { + t.Errorf("tree %v mismatch", i) + } + } + t.Log("Removing half from first half") + toRemove := rang(cloneTestSize)[cloneTestSize/2:] + for i := 0; i < len(trees)/2; i++ { + tree := trees[i] + wg.Add(1) + go func() { + for _, item := range toRemove { + tree.Delete(item) + } + wg.Done() + }() + } + wg.Wait() + t.Log("Checking all values again") + for i, tree := range trees { + var wantpart []Item + if i < len(trees)/2 { + wantpart = want[:cloneTestSize/2] + } else { + wantpart = want + } + if got := all(tree); !reflect.DeepEqual(wantpart, got) { + t.Errorf("tree %v mismatch, want %v got %v", i, len(want), len(got)) + } + } +} + +func BenchmarkDeleteAndRestore(b *testing.B) { + items := perm(16392) + b.ResetTimer() + b.Run(`CopyBigFreeList`, func(b *testing.B) { + fl := NewFreeList(16392) + tr := NewWithFreeList(*btreeDegree, fl) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + dels := make([]Item, 0, tr.Len()) + tr.Ascend(ItemIterator(func(b Item) bool { + dels = append(dels, b) + return true + })) + for _, del := range dels { + tr.Delete(del) + } + // tr is now empty, we make a new empty copy of it. + tr = NewWithFreeList(*btreeDegree, fl) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + } + }) + b.Run(`Copy`, func(b *testing.B) { + tr := New(*btreeDegree) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + dels := make([]Item, 0, tr.Len()) + tr.Ascend(ItemIterator(func(b Item) bool { + dels = append(dels, b) + return true + })) + for _, del := range dels { + tr.Delete(del) + } + // tr is now empty, we make a new empty copy of it. + tr = New(*btreeDegree) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + } + }) + b.Run(`ClearBigFreelist`, func(b *testing.B) { + fl := NewFreeList(16392) + tr := NewWithFreeList(*btreeDegree, fl) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr.Clear(true) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + } + }) + b.Run(`Clear`, func(b *testing.B) { + tr := New(*btreeDegree) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr.Clear(true) + for _, v := range items { + tr.ReplaceOrInsert(v) + } + } + }) +} diff --git a/vendor/github.com/google/gofuzz/.travis.yml b/vendor/github.com/google/gofuzz/.travis.yml new file mode 100644 index 000000000..f8684d99f --- /dev/null +++ b/vendor/github.com/google/gofuzz/.travis.yml @@ -0,0 +1,13 @@ +language: go + +go: + - 1.4 + - 1.3 + - 1.2 + - tip + +install: + - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi + +script: + - go test -cover diff --git a/vendor/github.com/google/gofuzz/CONTRIBUTING.md b/vendor/github.com/google/gofuzz/CONTRIBUTING.md new file mode 100644 index 000000000..51cf5cd1a --- /dev/null +++ b/vendor/github.com/google/gofuzz/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# How to contribute # + +We'd love to accept your patches and contributions to this project. There are +a just a few small guidelines you need to follow. + + +## Contributor License Agreement ## + +Contributions to any Google project must be accompanied by a Contributor +License Agreement. This is not a copyright **assignment**, it simply gives +Google permission to use and redistribute your contributions as part of the +project. + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual + CLA][]. + + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA][]. + +You generally only need to submit a CLA once, so if you've already submitted +one (even if it was for a different project), you probably don't need to do it +again. + +[individual CLA]: https://developers.google.com/open-source/cla/individual +[corporate CLA]: https://developers.google.com/open-source/cla/corporate + + +## Submitting a patch ## + + 1. It's generally best to start by opening a new issue describing the bug or + feature you're intending to fix. Even if you think it's relatively minor, + it's helpful to know what people are working on. Mention in the initial + issue that you are planning to work on that bug or feature so that it can + be assigned to you. + + 1. Follow the normal process of [forking][] the project, and setup a new + branch to work in. It's important that each group of changes be done in + separate branches in order to ensure that a pull request only includes the + commits related to that bug or feature. + + 1. Go makes it very simple to ensure properly formatted code, so always run + `go fmt` on your code before committing it. You should also run + [golint][] over your code. As noted in the [golint readme][], it's not + strictly necessary that your code be completely "lint-free", but this will + help you find common style issues. + + 1. Any significant changes should almost always be accompanied by tests. The + project already has good test coverage, so look at some of the existing + tests if you're unsure how to go about it. [gocov][] and [gocov-html][] + are invaluable tools for seeing which parts of your code aren't being + exercised by your tests. + + 1. Do your best to have [well-formed commit messages][] for each change. + This provides consistency throughout the project, and ensures that commit + messages are able to be formatted properly by various git tools. + + 1. Finally, push the commits to your fork and submit a [pull request][]. + +[forking]: https://help.github.com/articles/fork-a-repo +[golint]: https://github.com/golang/lint +[golint readme]: https://github.com/golang/lint/blob/master/README +[gocov]: https://github.com/axw/gocov +[gocov-html]: https://github.com/matm/gocov-html +[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html +[squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits +[pull request]: https://help.github.com/articles/creating-a-pull-request diff --git a/vendor/github.com/google/gofuzz/README.md b/vendor/github.com/google/gofuzz/README.md new file mode 100644 index 000000000..64869af34 --- /dev/null +++ b/vendor/github.com/google/gofuzz/README.md @@ -0,0 +1,71 @@ +gofuzz +====== + +gofuzz is a library for populating go objects with random values. + +[![GoDoc](https://godoc.org/github.com/google/gofuzz?status.png)](https://godoc.org/github.com/google/gofuzz) +[![Travis](https://travis-ci.org/google/gofuzz.svg?branch=master)](https://travis-ci.org/google/gofuzz) + +This is useful for testing: + +* Do your project's objects really serialize/unserialize correctly in all cases? +* Is there an incorrectly formatted object that will cause your project to panic? + +Import with ```import "github.com/google/gofuzz"``` + +You can use it on single variables: +```go +f := fuzz.New() +var myInt int +f.Fuzz(&myInt) // myInt gets a random value. +``` + +You can use it on maps: +```go +f := fuzz.New().NilChance(0).NumElements(1, 1) +var myMap map[ComplexKeyType]string +f.Fuzz(&myMap) // myMap will have exactly one element. +``` + +Customize the chance of getting a nil pointer: +```go +f := fuzz.New().NilChance(.5) +var fancyStruct struct { + A, B, C, D *string +} +f.Fuzz(&fancyStruct) // About half the pointers should be set. +``` + +You can even customize the randomization completely if needed: +```go +type MyEnum string +const ( + A MyEnum = "A" + B MyEnum = "B" +) +type MyInfo struct { + Type MyEnum + AInfo *string + BInfo *string +} + +f := fuzz.New().NilChance(0).Funcs( + func(e *MyInfo, c fuzz.Continue) { + switch c.Intn(2) { + case 0: + e.Type = A + c.Fuzz(&e.AInfo) + case 1: + e.Type = B + c.Fuzz(&e.BInfo) + } + }, +) + +var myObject MyInfo +f.Fuzz(&myObject) // Type will correspond to whether A or B info is set. +``` + +See more examples in ```example_test.go```. + +Happy testing! diff --git a/vendor/github.com/google/gofuzz/example_test.go b/vendor/github.com/google/gofuzz/example_test.go new file mode 100644 index 000000000..792707a3a --- /dev/null +++ b/vendor/github.com/google/gofuzz/example_test.go @@ -0,0 +1,225 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +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 fuzz_test + +import ( + "encoding/json" + "fmt" + "math/rand" + + "github.com/google/gofuzz" +) + +func ExampleSimple() { + type MyType struct { + A string + B string + C int + D struct { + E float64 + } + } + + f := fuzz.New() + object := MyType{} + + uniqueObjects := map[MyType]int{} + + for i := 0; i < 1000; i++ { + f.Fuzz(&object) + uniqueObjects[object]++ + } + fmt.Printf("Got %v unique objects.\n", len(uniqueObjects)) + // Output: + // Got 1000 unique objects. +} + +func ExampleCustom() { + type MyType struct { + A int + B string + } + + counter := 0 + f := fuzz.New().Funcs( + func(i *int, c fuzz.Continue) { + *i = counter + counter++ + }, + ) + object := MyType{} + + uniqueObjects := map[MyType]int{} + + for i := 0; i < 100; i++ { + f.Fuzz(&object) + if object.A != i { + fmt.Printf("Unexpected value: %#v\n", object) + } + uniqueObjects[object]++ + } + fmt.Printf("Got %v unique objects.\n", len(uniqueObjects)) + // Output: + // Got 100 unique objects. +} + +func ExampleComplex() { + type OtherType struct { + A string + B string + } + type MyType struct { + Pointer *OtherType + Map map[string]OtherType + PointerMap *map[string]OtherType + Slice []OtherType + SlicePointer []*OtherType + PointerSlicePointer *[]*OtherType + } + + f := fuzz.New().RandSource(rand.NewSource(0)).NilChance(0).NumElements(1, 1).Funcs( + func(o *OtherType, c fuzz.Continue) { + o.A = "Foo" + o.B = "Bar" + }, + func(op **OtherType, c fuzz.Continue) { + *op = &OtherType{"A", "B"} + }, + func(m map[string]OtherType, c fuzz.Continue) { + m["Works Because"] = OtherType{ + "Fuzzer", + "Preallocated", + } + }, + ) + object := MyType{} + f.Fuzz(&object) + bytes, err := json.MarshalIndent(&object, "", " ") + if err != nil { + fmt.Printf("error: %v\n", err) + } + fmt.Printf("%s\n", string(bytes)) + // Output: + // { + // "Pointer": { + // "A": "A", + // "B": "B" + // }, + // "Map": { + // "Works Because": { + // "A": "Fuzzer", + // "B": "Preallocated" + // } + // }, + // "PointerMap": { + // "Works Because": { + // "A": "Fuzzer", + // "B": "Preallocated" + // } + // }, + // "Slice": [ + // { + // "A": "Foo", + // "B": "Bar" + // } + // ], + // "SlicePointer": [ + // { + // "A": "A", + // "B": "B" + // } + // ], + // "PointerSlicePointer": [ + // { + // "A": "A", + // "B": "B" + // } + // ] + // } +} + +func ExampleMap() { + f := fuzz.New().NilChance(0).NumElements(1, 1) + var myMap map[struct{ A, B, C int }]string + f.Fuzz(&myMap) + fmt.Printf("myMap has %v element(s).\n", len(myMap)) + // Output: + // myMap has 1 element(s). +} + +func ExampleSingle() { + f := fuzz.New() + var i int + f.Fuzz(&i) + + // Technically, we'd expect this to fail one out of 2 billion attempts... + fmt.Printf("(i == 0) == %v", i == 0) + // Output: + // (i == 0) == false +} + +func ExampleEnum() { + type MyEnum string + const ( + A MyEnum = "A" + B MyEnum = "B" + ) + type MyInfo struct { + Type MyEnum + AInfo *string + BInfo *string + } + + f := fuzz.New().NilChance(0).Funcs( + func(e *MyInfo, c fuzz.Continue) { + // Note c's embedded Rand allows for direct use. + // We could also use c.RandBool() here. + switch c.Intn(2) { + case 0: + e.Type = A + c.Fuzz(&e.AInfo) + case 1: + e.Type = B + c.Fuzz(&e.BInfo) + } + }, + ) + + for i := 0; i < 100; i++ { + var myObject MyInfo + f.Fuzz(&myObject) + switch myObject.Type { + case A: + if myObject.AInfo == nil { + fmt.Println("AInfo should have been set!") + } + if myObject.BInfo != nil { + fmt.Println("BInfo should NOT have been set!") + } + case B: + if myObject.BInfo == nil { + fmt.Println("BInfo should have been set!") + } + if myObject.AInfo != nil { + fmt.Println("AInfo should NOT have been set!") + } + default: + fmt.Println("Invalid enum value!") + } + } + // Output: +} diff --git a/vendor/github.com/google/gofuzz/fuzz_test.go b/vendor/github.com/google/gofuzz/fuzz_test.go new file mode 100644 index 000000000..4059ea6fe --- /dev/null +++ b/vendor/github.com/google/gofuzz/fuzz_test.go @@ -0,0 +1,472 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +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 fuzz + +import ( + "reflect" + "testing" + "time" +) + +func TestFuzz_basic(t *testing.T) { + obj := &struct { + I int + I8 int8 + I16 int16 + I32 int32 + I64 int64 + U uint + U8 uint8 + U16 uint16 + U32 uint32 + U64 uint64 + Uptr uintptr + S string + B bool + T time.Time + }{} + + failed := map[string]int{} + for i := 0; i < 10; i++ { + New().Fuzz(obj) + + if n, v := "i", obj.I; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "i8", obj.I8; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "i16", obj.I16; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "i32", obj.I32; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "i64", obj.I64; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "u", obj.U; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "u8", obj.U8; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "u16", obj.U16; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "u32", obj.U32; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "u64", obj.U64; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "uptr", obj.Uptr; v == 0 { + failed[n] = failed[n] + 1 + } + if n, v := "s", obj.S; v == "" { + failed[n] = failed[n] + 1 + } + if n, v := "b", obj.B; v == false { + failed[n] = failed[n] + 1 + } + if n, v := "t", obj.T; v.IsZero() { + failed[n] = failed[n] + 1 + } + } + checkFailed(t, failed) +} + +func checkFailed(t *testing.T, failed map[string]int) { + for k, v := range failed { + if v > 8 { + t.Errorf("%v seems to not be getting set, was zero value %v times", k, v) + } + } +} + +func TestFuzz_structptr(t *testing.T) { + obj := &struct { + A *struct { + S string + } + }{} + + f := New().NilChance(.5) + failed := map[string]int{} + for i := 0; i < 10; i++ { + f.Fuzz(obj) + + if n, v := "a not nil", obj.A; v == nil { + failed[n] = failed[n] + 1 + } + if n, v := "a nil", obj.A; v != nil { + failed[n] = failed[n] + 1 + } + if n, v := "as", obj.A; v == nil || v.S == "" { + failed[n] = failed[n] + 1 + } + } + checkFailed(t, failed) +} + +// tryFuzz tries fuzzing up to 20 times. Fail if check() never passes, report the highest +// stage it ever got to. +func tryFuzz(t *testing.T, f *Fuzzer, obj interface{}, check func() (stage int, passed bool)) { + maxStage := 0 + for i := 0; i < 20; i++ { + f.Fuzz(obj) + stage, passed := check() + if stage > maxStage { + maxStage = stage + } + if passed { + return + } + } + t.Errorf("Only ever got to stage %v", maxStage) +} + +func TestFuzz_structmap(t *testing.T) { + obj := &struct { + A map[struct { + S string + }]struct { + S2 string + } + B map[string]string + }{} + + tryFuzz(t, New(), obj, func() (int, bool) { + if obj.A == nil { + return 1, false + } + if len(obj.A) == 0 { + return 2, false + } + for k, v := range obj.A { + if k.S == "" { + return 3, false + } + if v.S2 == "" { + return 4, false + } + } + + if obj.B == nil { + return 5, false + } + if len(obj.B) == 0 { + return 6, false + } + for k, v := range obj.B { + if k == "" { + return 7, false + } + if v == "" { + return 8, false + } + } + return 9, true + }) +} + +func TestFuzz_structslice(t *testing.T) { + obj := &struct { + A []struct { + S string + } + B []string + }{} + + tryFuzz(t, New(), obj, func() (int, bool) { + if obj.A == nil { + return 1, false + } + if len(obj.A) == 0 { + return 2, false + } + for _, v := range obj.A { + if v.S == "" { + return 3, false + } + } + + if obj.B == nil { + return 4, false + } + if len(obj.B) == 0 { + return 5, false + } + for _, v := range obj.B { + if v == "" { + return 6, false + } + } + return 7, true + }) +} + +func TestFuzz_structarray(t *testing.T) { + obj := &struct { + A [3]struct { + S string + } + B [2]int + }{} + + tryFuzz(t, New(), obj, func() (int, bool) { + for _, v := range obj.A { + if v.S == "" { + return 1, false + } + } + + for _, v := range obj.B { + if v == 0 { + return 2, false + } + } + return 3, true + }) +} + +func TestFuzz_custom(t *testing.T) { + obj := &struct { + A string + B *string + C map[string]string + D *map[string]string + }{} + + testPhrase := "gotcalled" + testMap := map[string]string{"C": "D"} + f := New().Funcs( + func(s *string, c Continue) { + *s = testPhrase + }, + func(m map[string]string, c Continue) { + m["C"] = "D" + }, + ) + + tryFuzz(t, f, obj, func() (int, bool) { + if obj.A != testPhrase { + return 1, false + } + if obj.B == nil { + return 2, false + } + if *obj.B != testPhrase { + return 3, false + } + if e, a := testMap, obj.C; !reflect.DeepEqual(e, a) { + return 4, false + } + if obj.D == nil { + return 5, false + } + if e, a := testMap, *obj.D; !reflect.DeepEqual(e, a) { + return 6, false + } + return 7, true + }) +} + +type SelfFuzzer string + +// Implement fuzz.Interface. +func (sf *SelfFuzzer) Fuzz(c Continue) { + *sf = selfFuzzerTestPhrase +} + +const selfFuzzerTestPhrase = "was fuzzed" + +func TestFuzz_interface(t *testing.T) { + f := New() + + var obj1 SelfFuzzer + tryFuzz(t, f, &obj1, func() (int, bool) { + if obj1 != selfFuzzerTestPhrase { + return 1, false + } + return 1, true + }) + + var obj2 map[int]SelfFuzzer + tryFuzz(t, f, &obj2, func() (int, bool) { + for _, v := range obj2 { + if v != selfFuzzerTestPhrase { + return 1, false + } + } + return 1, true + }) +} + +func TestFuzz_interfaceAndFunc(t *testing.T) { + const privateTestPhrase = "private phrase" + f := New().Funcs( + // This should take precedence over SelfFuzzer.Fuzz(). + func(s *SelfFuzzer, c Continue) { + *s = privateTestPhrase + }, + ) + + var obj1 SelfFuzzer + tryFuzz(t, f, &obj1, func() (int, bool) { + if obj1 != privateTestPhrase { + return 1, false + } + return 1, true + }) + + var obj2 map[int]SelfFuzzer + tryFuzz(t, f, &obj2, func() (int, bool) { + for _, v := range obj2 { + if v != privateTestPhrase { + return 1, false + } + } + return 1, true + }) +} + +func TestFuzz_noCustom(t *testing.T) { + type Inner struct { + Str string + } + type Outer struct { + Str string + In Inner + } + + testPhrase := "gotcalled" + f := New().Funcs( + func(outer *Outer, c Continue) { + outer.Str = testPhrase + c.Fuzz(&outer.In) + }, + func(inner *Inner, c Continue) { + inner.Str = testPhrase + }, + ) + c := Continue{fc: &fuzzerContext{fuzzer: f}, Rand: f.r} + + // Fuzzer.Fuzz() + obj1 := Outer{} + f.Fuzz(&obj1) + if obj1.Str != testPhrase { + t.Errorf("expected Outer custom function to have been called") + } + if obj1.In.Str != testPhrase { + t.Errorf("expected Inner custom function to have been called") + } + + // Continue.Fuzz() + obj2 := Outer{} + c.Fuzz(&obj2) + if obj2.Str != testPhrase { + t.Errorf("expected Outer custom function to have been called") + } + if obj2.In.Str != testPhrase { + t.Errorf("expected Inner custom function to have been called") + } + + // Fuzzer.FuzzNoCustom() + obj3 := Outer{} + f.FuzzNoCustom(&obj3) + if obj3.Str == testPhrase { + t.Errorf("expected Outer custom function to not have been called") + } + if obj3.In.Str != testPhrase { + t.Errorf("expected Inner custom function to have been called") + } + + // Continue.FuzzNoCustom() + obj4 := Outer{} + c.FuzzNoCustom(&obj4) + if obj4.Str == testPhrase { + t.Errorf("expected Outer custom function to not have been called") + } + if obj4.In.Str != testPhrase { + t.Errorf("expected Inner custom function to have been called") + } +} + +func TestFuzz_NumElements(t *testing.T) { + f := New().NilChance(0).NumElements(0, 1) + obj := &struct { + A []int + }{} + + tryFuzz(t, f, obj, func() (int, bool) { + if obj.A == nil { + return 1, false + } + return 2, len(obj.A) == 0 + }) + tryFuzz(t, f, obj, func() (int, bool) { + if obj.A == nil { + return 3, false + } + return 4, len(obj.A) == 1 + }) +} + +func TestFuzz_Maxdepth(t *testing.T) { + type S struct { + S *S + } + + f := New().NilChance(0) + + f.MaxDepth(1) + for i := 0; i < 100; i++ { + obj := S{} + f.Fuzz(&obj) + + if obj.S != nil { + t.Errorf("Expected nil") + } + } + + f.MaxDepth(3) // field, ptr + for i := 0; i < 100; i++ { + obj := S{} + f.Fuzz(&obj) + + if obj.S == nil { + t.Errorf("Expected obj.S not nil") + } else if obj.S.S != nil { + t.Errorf("Expected obj.S.S nil") + } + } + + f.MaxDepth(5) // field, ptr, field, ptr + for i := 0; i < 100; i++ { + obj := S{} + f.Fuzz(&obj) + + if obj.S == nil { + t.Errorf("Expected obj.S not nil") + } else if obj.S.S == nil { + t.Errorf("Expected obj.S.S not nil") + } else if obj.S.S.S != nil { + t.Errorf("Expected obj.S.S.S nil") + } + } +} diff --git a/vendor/github.com/googleapis/gnostic/.gitignore b/vendor/github.com/googleapis/gnostic/.gitignore new file mode 100644 index 000000000..2a9d09b79 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/.gitignore @@ -0,0 +1,21 @@ +# IntelliJ IDEA +.idea +# Eclipse +.checkstyle +.project +.settings +# Swift +.build +Packages +# Node +node_modules +package-lock.json +bundle.json +# vi +*.swp +# vscode +.vscode +.DS_Store +*~ +Package.resolved +extensions/sample/generated diff --git a/vendor/github.com/googleapis/gnostic/.travis-install.sh b/vendor/github.com/googleapis/gnostic/.travis-install.sh new file mode 100755 index 000000000..83319ae4c --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/.travis-install.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# +# Install dependencies that aren't available as Ubuntu packages. +# +# Everything goes into $HOME/local. +# +# Scripts should add +# - $HOME/local/bin to PATH +# - $HOME/local/lib to LD_LIBRARY_PATH +# + +cd +mkdir -p local + +# Install swift +SWIFT_URL=https://swift.org/builds/swift-4.0-branch/ubuntu1404/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-09-01-a/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-09-01-a-ubuntu14.04.tar.gz +echo $SWIFT_URL +curl -fSsL $SWIFT_URL -o swift.tar.gz +tar -xzf swift.tar.gz --strip-components=2 --directory=local + +# Install protoc +PROTOC_URL=https://github.com/google/protobuf/releases/download/v3.4.0/protoc-3.4.0-linux-x86_64.zip +echo $PROTOC_URL +curl -fSsL $PROTOC_URL -o protoc.zip +unzip protoc.zip -d local + +# Verify installation +find local diff --git a/vendor/github.com/googleapis/gnostic/.travis.yml b/vendor/github.com/googleapis/gnostic/.travis.yml new file mode 100644 index 000000000..c3d2791fc --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/.travis.yml @@ -0,0 +1,49 @@ +# Travis CI build file for OpenAPI Compiler, including Go and Swift plugins + +# Use Ubuntu 14.04 +dist: trusty + +sudo: false + +language: go + +addons: + apt: + packages: + - clang-3.8 + - lldb-3.8 + - libicu-dev + - libtool + - libcurl4-openssl-dev + - libbsd-dev + - build-essential + - libssl-dev + - uuid-dev + - curl + - unzip + +install: + - ./.travis-install.sh + - export PATH=.:$HOME/local/bin:$PATH + - make + +script: + - go test . -v + - pushd plugins/gnostic-go-generator/examples/v2.0/bookstore + - make test + - popd + - pushd plugins/gnostic-go-generator/examples/v2.0/sample + - make test + - popd + - pushd plugins/gnostic-go-generator/examples/v3.0/bookstore + - make test + - popd + - export PATH=.:$HOME/local/bin:$PATH + - export LD_LIBRARY_PATH=$HOME/local/lib + - pushd plugins/gnostic-swift-generator + - make install + - cd examples/bookstore + - make + - .build/debug/Server & + - make test + diff --git a/vendor/github.com/googleapis/gnostic/COMPILE-PROTOS.sh b/vendor/github.com/googleapis/gnostic/COMPILE-PROTOS.sh new file mode 100755 index 000000000..584878a10 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/COMPILE-PROTOS.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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 get github.com/golang/protobuf/protoc-gen-go + +protoc \ +--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. \ +OpenAPIv2/OpenAPIv2.proto + +protoc \ +-I.:$GOPATH/src \ +--go_out=:. \ +plugins/plugin.proto + +protoc \ +--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. \ +OpenAPIv3/OpenAPIv3.proto + +protoc \ +--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. \ +discovery/discovery.proto diff --git a/vendor/github.com/googleapis/gnostic/CONTRIBUTING.md b/vendor/github.com/googleapis/gnostic/CONTRIBUTING.md new file mode 100644 index 000000000..6736efd94 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# How to become a contributor and submit your own code + +## Contributor License Agreements + +We'd love to accept your sample apps and patches! Before we can take them, we +have to jump a couple of legal hurdles. + +Please fill out either the individual or corporate Contributor License Agreement +(CLA). + + * If you are an individual writing original source code and you're sure you + own the intellectual property, then you'll need to sign an [individual CLA] + (https://developers.google.com/open-source/cla/individual). + * If you work for a company that wants to allow you to contribute your work, + then you'll need to sign a [corporate CLA] + (https://developers.google.com/open-source/cla/corporate). + +Follow either of the two links above to access the appropriate CLA and +instructions for how to sign and return it. Once we receive it, we'll be able to +accept your pull requests. + +## Contributing A Patch + +1. Submit an issue describing your proposed change to the repo in question. +1. The repo owner will respond to your issue promptly. +1. If your proposed change is accepted, and you haven't already done so, sign a + Contributor License Agreement (see details above). +1. Fork the desired repo, develop and test your code changes. +1. Ensure that your code adheres to the existing style in the sample to which + you are contributing. Refer to the + [Google Cloud Platform Samples Style Guide] + (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the + recommended coding standards for this organization. +1. Ensure that your code has an appropriate set of unit tests which all pass. +1. Submit a pull request. diff --git a/vendor/github.com/googleapis/gnostic/Makefile b/vendor/github.com/googleapis/gnostic/Makefile new file mode 100644 index 000000000..8a772811e --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/Makefile @@ -0,0 +1,16 @@ + +build: + go get + go install + cd generate-gnostic; go get; go install + cd apps/disco; go get; go install + cd apps/report; go get; go install + cd apps/petstore-builder; go get; go install + cd plugins/gnostic-summary; go get; go install + cd plugins/gnostic-analyze; go get; go install + cd plugins/gnostic-go-generator; go get; go install + rm -f $(GOPATH)/bin/gnostic-go-client $(GOPATH)/bin/gnostic-go-server + ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-client + ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-server + cd extensions/sample; make + diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto new file mode 100644 index 000000000..557c88072 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/OpenAPIv2.proto @@ -0,0 +1,663 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +syntax = "proto3"; + +package openapi.v2; + +import "google/protobuf/any.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v2"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +message AdditionalPropertiesItem { + oneof oneof { + Schema schema = 1; + bool boolean = 2; + } +} + +message Any { + google.protobuf.Any value = 1; + string yaml = 2; +} + +message ApiKeySecurity { + string type = 1; + string name = 2; + string in = 3; + string description = 4; + repeated NamedAny vendor_extension = 5; +} + +message BasicAuthenticationSecurity { + string type = 1; + string description = 2; + repeated NamedAny vendor_extension = 3; +} + +message BodyParameter { + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 1; + // The name of the parameter. + string name = 2; + // Determines the location of the parameter. + string in = 3; + // Determines whether or not this parameter is required or optional. + bool required = 4; + Schema schema = 5; + repeated NamedAny vendor_extension = 6; +} + +// Contact information for the owners of the API. +message Contact { + // The identifying name of the contact person/organization. + string name = 1; + // The URL pointing to the contact information. + string url = 2; + // The email address of the contact person/organization. + string email = 3; + repeated NamedAny vendor_extension = 4; +} + +message Default { + repeated NamedAny additional_properties = 1; +} + +// One or more JSON objects describing the schemas being consumed and produced by the API. +message Definitions { + repeated NamedSchema additional_properties = 1; +} + +message Document { + // The Swagger version of this document. + string swagger = 1; + Info info = 2; + // The host (name or ip) of the API. Example: 'swagger.io' + string host = 3; + // The base path to the API. Example: '/api'. + string base_path = 4; + // The transfer protocol of the API. + repeated string schemes = 5; + // A list of MIME types accepted by the API. + repeated string consumes = 6; + // A list of MIME types the API can produce. + repeated string produces = 7; + Paths paths = 8; + Definitions definitions = 9; + ParameterDefinitions parameters = 10; + ResponseDefinitions responses = 11; + repeated SecurityRequirement security = 12; + SecurityDefinitions security_definitions = 13; + repeated Tag tags = 14; + ExternalDocs external_docs = 15; + repeated NamedAny vendor_extension = 16; +} + +message Examples { + repeated NamedAny additional_properties = 1; +} + +// information about external documentation +message ExternalDocs { + string description = 1; + string url = 2; + repeated NamedAny vendor_extension = 3; +} + +// A deterministic version of a JSON Schema object. +message FileSchema { + string format = 1; + string title = 2; + string description = 3; + Any default = 4; + repeated string required = 5; + string type = 6; + bool read_only = 7; + ExternalDocs external_docs = 8; + Any example = 9; + repeated NamedAny vendor_extension = 10; +} + +message FormDataParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + // allows sending a parameter by name only or with an empty value. + bool allow_empty_value = 5; + string type = 6; + string format = 7; + PrimitivesItems items = 8; + string collection_format = 9; + Any default = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + repeated Any enum = 21; + double multiple_of = 22; + repeated NamedAny vendor_extension = 23; +} + +message Header { + string type = 1; + string format = 2; + PrimitivesItems items = 3; + string collection_format = 4; + Any default = 5; + double maximum = 6; + bool exclusive_maximum = 7; + double minimum = 8; + bool exclusive_minimum = 9; + int64 max_length = 10; + int64 min_length = 11; + string pattern = 12; + int64 max_items = 13; + int64 min_items = 14; + bool unique_items = 15; + repeated Any enum = 16; + double multiple_of = 17; + string description = 18; + repeated NamedAny vendor_extension = 19; +} + +message HeaderParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + string type = 5; + string format = 6; + PrimitivesItems items = 7; + string collection_format = 8; + Any default = 9; + double maximum = 10; + bool exclusive_maximum = 11; + double minimum = 12; + bool exclusive_minimum = 13; + int64 max_length = 14; + int64 min_length = 15; + string pattern = 16; + int64 max_items = 17; + int64 min_items = 18; + bool unique_items = 19; + repeated Any enum = 20; + double multiple_of = 21; + repeated NamedAny vendor_extension = 22; +} + +message Headers { + repeated NamedHeader additional_properties = 1; +} + +// General information about the API. +message Info { + // A unique and precise title of the API. + string title = 1; + // A semantic version number of the API. + string version = 2; + // A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed. + string description = 3; + // The terms of service for the API. + string terms_of_service = 4; + Contact contact = 5; + License license = 6; + repeated NamedAny vendor_extension = 7; +} + +message ItemsItem { + repeated Schema schema = 1; +} + +message JsonReference { + string _ref = 1; + string description = 2; +} + +message License { + // The name of the license type. It's encouraged to use an OSI compatible license. + string name = 1; + // The URL pointing to the license. + string url = 2; + repeated NamedAny vendor_extension = 3; +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +message NamedAny { + // Map key + string name = 1; + // Mapped value + Any value = 2; +} + +// Automatically-generated message used to represent maps of Header as ordered (name,value) pairs. +message NamedHeader { + // Map key + string name = 1; + // Mapped value + Header value = 2; +} + +// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs. +message NamedParameter { + // Map key + string name = 1; + // Mapped value + Parameter value = 2; +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +message NamedPathItem { + // Map key + string name = 1; + // Mapped value + PathItem value = 2; +} + +// Automatically-generated message used to represent maps of Response as ordered (name,value) pairs. +message NamedResponse { + // Map key + string name = 1; + // Mapped value + Response value = 2; +} + +// Automatically-generated message used to represent maps of ResponseValue as ordered (name,value) pairs. +message NamedResponseValue { + // Map key + string name = 1; + // Mapped value + ResponseValue value = 2; +} + +// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs. +message NamedSchema { + // Map key + string name = 1; + // Mapped value + Schema value = 2; +} + +// Automatically-generated message used to represent maps of SecurityDefinitionsItem as ordered (name,value) pairs. +message NamedSecurityDefinitionsItem { + // Map key + string name = 1; + // Mapped value + SecurityDefinitionsItem value = 2; +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +message NamedString { + // Map key + string name = 1; + // Mapped value + string value = 2; +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +message NamedStringArray { + // Map key + string name = 1; + // Mapped value + StringArray value = 2; +} + +message NonBodyParameter { + oneof oneof { + HeaderParameterSubSchema header_parameter_sub_schema = 1; + FormDataParameterSubSchema form_data_parameter_sub_schema = 2; + QueryParameterSubSchema query_parameter_sub_schema = 3; + PathParameterSubSchema path_parameter_sub_schema = 4; + } +} + +message Oauth2AccessCodeSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string authorization_url = 4; + string token_url = 5; + string description = 6; + repeated NamedAny vendor_extension = 7; +} + +message Oauth2ApplicationSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string token_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2ImplicitSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string authorization_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2PasswordSecurity { + string type = 1; + string flow = 2; + Oauth2Scopes scopes = 3; + string token_url = 4; + string description = 5; + repeated NamedAny vendor_extension = 6; +} + +message Oauth2Scopes { + repeated NamedString additional_properties = 1; +} + +message Operation { + repeated string tags = 1; + // A brief summary of the operation. + string summary = 2; + // A longer description of the operation, GitHub Flavored Markdown is allowed. + string description = 3; + ExternalDocs external_docs = 4; + // A unique identifier of the operation. + string operation_id = 5; + // A list of MIME types the API can produce. + repeated string produces = 6; + // A list of MIME types the API can consume. + repeated string consumes = 7; + // The parameters needed to send a valid API call. + repeated ParametersItem parameters = 8; + Responses responses = 9; + // The transfer protocol of the API. + repeated string schemes = 10; + bool deprecated = 11; + repeated SecurityRequirement security = 12; + repeated NamedAny vendor_extension = 13; +} + +message Parameter { + oneof oneof { + BodyParameter body_parameter = 1; + NonBodyParameter non_body_parameter = 2; + } +} + +// One or more JSON representations for parameters +message ParameterDefinitions { + repeated NamedParameter additional_properties = 1; +} + +message ParametersItem { + oneof oneof { + Parameter parameter = 1; + JsonReference json_reference = 2; + } +} + +message PathItem { + string _ref = 1; + Operation get = 2; + Operation put = 3; + Operation post = 4; + Operation delete = 5; + Operation options = 6; + Operation head = 7; + Operation patch = 8; + // The parameters needed to send a valid API call. + repeated ParametersItem parameters = 9; + repeated NamedAny vendor_extension = 10; +} + +message PathParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + string type = 5; + string format = 6; + PrimitivesItems items = 7; + string collection_format = 8; + Any default = 9; + double maximum = 10; + bool exclusive_maximum = 11; + double minimum = 12; + bool exclusive_minimum = 13; + int64 max_length = 14; + int64 min_length = 15; + string pattern = 16; + int64 max_items = 17; + int64 min_items = 18; + bool unique_items = 19; + repeated Any enum = 20; + double multiple_of = 21; + repeated NamedAny vendor_extension = 22; +} + +// Relative paths to the individual endpoints. They must be relative to the 'basePath'. +message Paths { + repeated NamedAny vendor_extension = 1; + repeated NamedPathItem path = 2; +} + +message PrimitivesItems { + string type = 1; + string format = 2; + PrimitivesItems items = 3; + string collection_format = 4; + Any default = 5; + double maximum = 6; + bool exclusive_maximum = 7; + double minimum = 8; + bool exclusive_minimum = 9; + int64 max_length = 10; + int64 min_length = 11; + string pattern = 12; + int64 max_items = 13; + int64 min_items = 14; + bool unique_items = 15; + repeated Any enum = 16; + double multiple_of = 17; + repeated NamedAny vendor_extension = 18; +} + +message Properties { + repeated NamedSchema additional_properties = 1; +} + +message QueryParameterSubSchema { + // Determines whether or not this parameter is required or optional. + bool required = 1; + // Determines the location of the parameter. + string in = 2; + // A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed. + string description = 3; + // The name of the parameter. + string name = 4; + // allows sending a parameter by name only or with an empty value. + bool allow_empty_value = 5; + string type = 6; + string format = 7; + PrimitivesItems items = 8; + string collection_format = 9; + Any default = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + repeated Any enum = 21; + double multiple_of = 22; + repeated NamedAny vendor_extension = 23; +} + +message Response { + string description = 1; + SchemaItem schema = 2; + Headers headers = 3; + Examples examples = 4; + repeated NamedAny vendor_extension = 5; +} + +// One or more JSON representations for parameters +message ResponseDefinitions { + repeated NamedResponse additional_properties = 1; +} + +message ResponseValue { + oneof oneof { + Response response = 1; + JsonReference json_reference = 2; + } +} + +// Response objects names can either be any valid HTTP status code or 'default'. +message Responses { + repeated NamedResponseValue response_code = 1; + repeated NamedAny vendor_extension = 2; +} + +// A deterministic version of a JSON Schema object. +message Schema { + string _ref = 1; + string format = 2; + string title = 3; + string description = 4; + Any default = 5; + double multiple_of = 6; + double maximum = 7; + bool exclusive_maximum = 8; + double minimum = 9; + bool exclusive_minimum = 10; + int64 max_length = 11; + int64 min_length = 12; + string pattern = 13; + int64 max_items = 14; + int64 min_items = 15; + bool unique_items = 16; + int64 max_properties = 17; + int64 min_properties = 18; + repeated string required = 19; + repeated Any enum = 20; + AdditionalPropertiesItem additional_properties = 21; + TypeItem type = 22; + ItemsItem items = 23; + repeated Schema all_of = 24; + Properties properties = 25; + string discriminator = 26; + bool read_only = 27; + Xml xml = 28; + ExternalDocs external_docs = 29; + Any example = 30; + repeated NamedAny vendor_extension = 31; +} + +message SchemaItem { + oneof oneof { + Schema schema = 1; + FileSchema file_schema = 2; + } +} + +message SecurityDefinitions { + repeated NamedSecurityDefinitionsItem additional_properties = 1; +} + +message SecurityDefinitionsItem { + oneof oneof { + BasicAuthenticationSecurity basic_authentication_security = 1; + ApiKeySecurity api_key_security = 2; + Oauth2ImplicitSecurity oauth2_implicit_security = 3; + Oauth2PasswordSecurity oauth2_password_security = 4; + Oauth2ApplicationSecurity oauth2_application_security = 5; + Oauth2AccessCodeSecurity oauth2_access_code_security = 6; + } +} + +message SecurityRequirement { + repeated NamedStringArray additional_properties = 1; +} + +message StringArray { + repeated string value = 1; +} + +message Tag { + string name = 1; + string description = 2; + ExternalDocs external_docs = 3; + repeated NamedAny vendor_extension = 4; +} + +message TypeItem { + repeated string value = 1; +} + +// Any property starting with x- is valid. +message VendorExtension { + repeated NamedAny additional_properties = 1; +} + +message Xml { + string name = 1; + string namespace = 2; + string prefix = 3; + bool attribute = 4; + bool wrapped = 5; + repeated NamedAny vendor_extension = 6; +} + diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md b/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md new file mode 100644 index 000000000..836fb32a7 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/README.md @@ -0,0 +1,16 @@ +# OpenAPI v2 Protocol Buffer Models + +This directory contains a Protocol Buffer-language model +and related code for supporting OpenAPI v2. + +Gnostic applications and plugins can use OpenAPIv2.proto +to generate Protocol Buffer support code for their preferred languages. + +OpenAPIv2.go is used by Gnostic to read JSON and YAML OpenAPI +descriptions into the Protocol Buffer-based datastructures +generated from OpenAPIv2.proto. + +OpenAPIv2.proto and OpenAPIv2.go are generated by the Gnostic +compiler generator, and OpenAPIv2.pb.go is generated by +protoc, the Protocol Buffer compiler, and protoc-gen-go, the +Protocol Buffer Go code generation plugin. diff --git a/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json b/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json new file mode 100644 index 000000000..2815a26ea --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/OpenAPIv2/openapi-2.0.json @@ -0,0 +1,1610 @@ +{ + "title": "A JSON Schema for Swagger 2.0 API.", + "id": "http://swagger.io/v2/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "required": [ + "swagger", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "swagger": { + "type": "string", + "enum": [ + "2.0" + ], + "description": "The Swagger version of this document." + }, + "info": { + "$ref": "#/definitions/info" + }, + "host": { + "type": "string", + "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", + "description": "The host (name or ip) of the API. Example: 'swagger.io'" + }, + "basePath": { + "type": "string", + "pattern": "^/", + "description": "The base path to the API. Example: '/api'." + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "consumes": { + "description": "A list of MIME types accepted by the API.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "definitions": { + "$ref": "#/definitions/definitions" + }, + "parameters": { + "$ref": "#/definitions/parameterDefinitions" + }, + "responses": { + "$ref": "#/definitions/responseDefinitions" + }, + "security": { + "$ref": "#/definitions/security" + }, + "securityDefinitions": { + "$ref": "#/definitions/securityDefinitions" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "paths": { + "type": "object", + "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + }, + "^/": { + "$ref": "#/definitions/pathItem" + } + }, + "additionalProperties": false + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "description": "One or more JSON objects describing the schemas being consumed and produced by the API." + }, + "parameterDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameter" + }, + "description": "One or more JSON representations for parameters" + }, + "responseDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/response" + }, + "description": "One or more JSON representations for parameters" + }, + "externalDocs": { + "type": "object", + "additionalProperties": false, + "description": "information about external documentation", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "examples": { + "type": "object", + "additionalProperties": true + }, + "mimeType": { + "type": "string", + "description": "The MIME type of the HTTP message." + }, + "operation": { + "type": "object", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the operation." + }, + "description": { + "type": "string", + "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string", + "description": "A unique identifier of the operation." + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "consumes": { + "description": "A list of MIME types the API can consume.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "$ref": "#/definitions/security" + } + } + }, + "pathItem": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "parameters": { + "$ref": "#/definitions/parametersList" + } + } + }, + "responses": { + "type": "object", + "description": "Response objects names can either be any valid HTTP status code or 'default'.", + "minProperties": 1, + "additionalProperties": false, + "patternProperties": { + "^([0-9]{3})$|^(default)$": { + "$ref": "#/definitions/responseValue" + }, + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "not": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + } + }, + "responseValue": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/fileSchema" + } + ] + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "examples": { + "$ref": "#/definitions/examples" + } + }, + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/header" + } + }, + "header": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "vendorExtension": { + "description": "Any property starting with x- is valid.", + "additionalProperties": true, + "additionalItems": true + }, + "bodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "schema" + ], + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "body" + ] + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "headerParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "header" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "queryParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "query" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "formDataParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "formData" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array", + "file" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "pathParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "required" + ], + "properties": { + "required": { + "type": "boolean", + "enum": [ + true + ], + "description": "Determines whether or not this parameter is required or optional." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "path" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "nonBodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "type" + ], + "oneOf": [ + { + "$ref": "#/definitions/headerParameterSubSchema" + }, + { + "$ref": "#/definitions/formDataParameterSubSchema" + }, + { + "$ref": "#/definitions/queryParameterSubSchema" + }, + { + "$ref": "#/definitions/pathParameterSubSchema" + } + ] + }, + "parameter": { + "oneOf": [ + { + "$ref": "#/definitions/bodyParameter" + }, + { + "$ref": "#/definitions/nonBodyParameter" + } + ] + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "fileSchema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "type" + ], + "properties": { + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "type": { + "type": "string", + "enum": [ + "file" + ] + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "primitivesItems": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "securityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "tag": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "securityDefinitions": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/basicAuthenticationSecurity" + }, + { + "$ref": "#/definitions/apiKeySecurity" + }, + { + "$ref": "#/definitions/oauth2ImplicitSecurity" + }, + { + "$ref": "#/definitions/oauth2PasswordSecurity" + }, + { + "$ref": "#/definitions/oauth2ApplicationSecurity" + }, + { + "$ref": "#/definitions/oauth2AccessCodeSecurity" + } + ] + } + }, + "basicAuthenticationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "basic" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "apiKeySecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ImplicitSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "implicit" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2PasswordSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "password" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ApplicationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "application" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2AccessCodeSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "accessCode" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2Scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mediaTypeList": { + "type": "array", + "items": { + "$ref": "#/definitions/mimeType" + }, + "uniqueItems": true + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "schemesList": { + "type": "array", + "description": "The transfer protocol of the API.", + "items": { + "type": "string", + "enum": [ + "http", + "https", + "ws", + "wss" + ] + }, + "uniqueItems": true + }, + "collectionFormat": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes" + ], + "default": "csv" + }, + "collectionFormatWithMulti": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes", + "multi" + ], + "default": "csv" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } +} diff --git a/vendor/github.com/googleapis/gnostic/README.md b/vendor/github.com/googleapis/gnostic/README.md new file mode 100644 index 000000000..97de63590 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/README.md @@ -0,0 +1,109 @@ +[![Build Status](https://travis-ci.org/googleapis/gnostic.svg?branch=master)](https://travis-ci.org/googleapis/gnostic) + +# ⨁ gnostic + +This repository contains a Go command line tool which converts +JSON and YAML [OpenAPI](https://github.com/OAI/OpenAPI-Specification) +descriptions to and from equivalent Protocol Buffer representations. + +[Protocol Buffers](https://developers.google.com/protocol-buffers/) +provide a language-neutral, platform-neutral, extensible mechanism +for serializing structured data. +**gnostic**'s Protocol Buffer models for the OpenAPI Specification +can be used to generate code that includes data structures with +explicit fields for the elements of an OpenAPI description. +This makes it possible for developers to work with OpenAPI +descriptions in type-safe ways, which is particularly useful +in strongly-typed languages like Go and Swift. + +**gnostic** reads OpenAPI descriptions into +these generated data structures, reports errors, +resolves internal dependencies, and writes the results +in a binary form that can be used in any language that is +supported by the Protocol Buffer tools. +A plugin interface simplifies integration with API +tools written in a variety of different languages, +and when necessary, Protocol Buffer OpenAPI descriptions +can be reexported as JSON or YAML. + +**gnostic** compilation code and OpenAPI Protocol Buffer +models are automatically generated from an +[OpenAPI JSON Schema](https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json). +Source code for the generator is in the [generate-gnostic](generate-gnostic) directory. + +## Disclaimer + +This is prerelease software and work in progress. Feedback and +contributions are welcome, but we currently make no guarantees of +function or stability. + +## Requirements + +**gnostic** can be run in any environment that supports [Go](http://golang.org) +and the [Google Protocol Buffer Compiler](https://github.com/google/protobuf). + +## Installation + +1. Get this package by downloading it with `go get`. + + go get github.com/googleapis/gnostic + +2. [Optional] Build and run the compiler generator. +This uses the OpenAPI JSON schema to generate a Protocol Buffer language file +that describes the OpenAPI specification and a Go-language file of code that +will read a JSON or YAML OpenAPI representation into the generated protocol +buffers. Pre-generated versions of these files are in the OpenAPIv2 directory. + + cd $GOPATH/src/github.com/googleapis/gnostic/generate-gnostic + go install + cd .. + generate-gnostic --v2 + +3. [Optional] Generate Protocol Buffer support code. +A pre-generated version of this file is checked into the OpenAPIv2 directory. +This step requires a local installation of protoc, the Protocol Buffer Compiler, +and the Go protoc plugin. +You can get protoc [here](https://github.com/google/protobuf). +You can install the plugin with this command: + + go get -u github.com/golang/protobuf/protoc-gen-go + +Then use the following to recompile the Gnostic Protocol Buffer models: + + ./COMPILE-PROTOS.sh + +4. [Optional] Rebuild **gnostic**. This is only necessary if you've performed steps +2 or 3 above. + + go install github.com/googleapis/gnostic + +5. Run **gnostic**. This will create a file in the current directory named "petstore.pb" that contains a binary +Protocol Buffer description of a sample API. + + gnostic --pb-out=. examples/v2.0/json/petstore.json + +6. You can also compile files that you specify with a URL. Here's another way to compile the previous +example. This time we're creating "petstore.text", which contains a textual representation of the +Protocol Buffer description. This is mainly for use in testing and debugging. + + gnostic --text-out=petstore.text https://raw.githubusercontent.com/googleapis/gnostic/master/examples/petstore.json + +7. For a sample application, see apps/report. + + go install github.com/googleapis/gnostic/apps/report + report petstore.pb + +8. **gnostic** supports plugins. This builds and runs a sample plugin +that reports some basic information about an API. The "-" causes the plugin to +write its output to stdout. + + go install github.com/googleapis/gnostic/plugins/gnostic-go-sample + gnostic examples/v2.0/json/petstore.json --go-sample-out=- + +## Copyright + +Copyright 2017, Google Inc. + +## License + +Released under the Apache 2.0 license. diff --git a/vendor/github.com/googleapis/gnostic/compiler/README.md b/vendor/github.com/googleapis/gnostic/compiler/README.md new file mode 100644 index 000000000..848b16c69 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/compiler/README.md @@ -0,0 +1,3 @@ +# Compiler support code + +This directory contains compiler support code used by Gnostic and Gnostic extensions. \ No newline at end of file diff --git a/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh b/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh new file mode 100755 index 000000000..68d02a02a --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/COMPILE-EXTENSION.sh @@ -0,0 +1,5 @@ +go get github.com/golang/protobuf/protoc-gen-go + +protoc \ +--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto + diff --git a/vendor/github.com/googleapis/gnostic/extensions/README.md b/vendor/github.com/googleapis/gnostic/extensions/README.md new file mode 100644 index 000000000..ff1c2eb1e --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/README.md @@ -0,0 +1,5 @@ +# Extensions + +This directory contains support code for building Gnostic extensions and associated examples. + +Extensions are used to compile vendor or specification extensions into protocol buffer structures. diff --git a/vendor/github.com/googleapis/gnostic/extensions/extension.proto b/vendor/github.com/googleapis/gnostic/extensions/extension.proto new file mode 100644 index 000000000..04856f913 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/extensions/extension.proto @@ -0,0 +1,93 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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. + +syntax = "proto3"; + +import "google/protobuf/any.proto"; +package openapiextension.v1; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIExtensionV1"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.gnostic.v1"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +// +option objc_class_prefix = "OAE"; // "OpenAPI Extension" + +// The version number of OpenAPI compiler. +message Version { + int32 major = 1; + int32 minor = 2; + int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + string suffix = 4; +} + +// An encoded Request is written to the ExtensionHandler's stdin. +message ExtensionHandlerRequest { + + // The OpenAPI descriptions that were explicitly listed on the command line. + // The specifications will appear in the order they are specified to gnostic. + Wrapper wrapper = 1; + + // The version number of openapi compiler. + Version compiler_version = 3; +} + +// The extensions writes an encoded ExtensionHandlerResponse to stdout. +message ExtensionHandlerResponse { + + // true if the extension is handled by the extension handler; false otherwise + bool handled = 1; + + // Error message. If non-empty, the extension handling failed. + // The extension handler process should exit with status code zero + // even if it reports an error in this way. + // + // This should be used to indicate errors which prevent the extension from + // operating as intended. Errors which indicate a problem in gnostic + // itself -- such as the input Document being unparseable -- should be + // reported by writing a message to stderr and exiting with a non-zero + // status code. + repeated string error = 2; + + // text output + google.protobuf.Any value = 3; +} + +message Wrapper { + // version of the OpenAPI specification in which this extension was written. + string version = 1; + + // Name of the extension + string extension_name = 2; + + // Must be a valid yaml for the proto + string yaml = 3; +} diff --git a/vendor/github.com/googleapis/gnostic/gnostic.go b/vendor/github.com/googleapis/gnostic/gnostic.go new file mode 100644 index 000000000..960041521 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/gnostic.go @@ -0,0 +1,610 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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 ./COMPILE-PROTOS.sh + +// Gnostic is a tool for building better REST APIs through knowledge. +// +// Gnostic reads declarative descriptions of REST APIs that conform +// to the OpenAPI Specification, reports errors, resolves internal +// dependencies, and puts the results in a binary form that can +// be used in any language that is supported by the Protocol Buffer +// tools. +// +// Gnostic models are validated and typed. This allows API tool +// developers to focus on their product and not worry about input +// validation and type checking. +// +// Gnostic calls plugins that implement a variety of API implementation +// and support features including generation of client and server +// support code. +package main + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "time" + + "github.com/golang/protobuf/proto" + "github.com/googleapis/gnostic/OpenAPIv2" + "github.com/googleapis/gnostic/OpenAPIv3" + "github.com/googleapis/gnostic/compiler" + "github.com/googleapis/gnostic/discovery" + "github.com/googleapis/gnostic/jsonwriter" + plugins "github.com/googleapis/gnostic/plugins" + surface "github.com/googleapis/gnostic/surface" + "gopkg.in/yaml.v2" +) + +const ( // Source Format + SourceFormatUnknown = 0 + SourceFormatOpenAPI2 = 2 + SourceFormatOpenAPI3 = 3 + SourceFormatDiscovery = 4 +) + +// Determine the version of an OpenAPI description read from JSON or YAML. +func getOpenAPIVersionFromInfo(info interface{}) int { + m, ok := compiler.UnpackMap(info) + if !ok { + return SourceFormatUnknown + } + swagger, ok := compiler.MapValueForKey(m, "swagger").(string) + if ok && strings.HasPrefix(swagger, "2.0") { + return SourceFormatOpenAPI2 + } + openapi, ok := compiler.MapValueForKey(m, "openapi").(string) + if ok && strings.HasPrefix(openapi, "3.0") { + return SourceFormatOpenAPI3 + } + kind, ok := compiler.MapValueForKey(m, "kind").(string) + if ok && kind == "discovery#restDescription" { + return SourceFormatDiscovery + } + return SourceFormatUnknown +} + +const ( + pluginPrefix = "gnostic-" + extensionPrefix = "gnostic-x-" +) + +type pluginCall struct { + Name string + Invocation string +} + +// Invokes a plugin. +func (p *pluginCall) perform(document proto.Message, sourceFormat int, sourceName string, timePlugins bool) ([]*plugins.Message, error) { + if p.Name != "" { + request := &plugins.Request{} + + // Infer the name of the executable by adding the prefix. + executableName := pluginPrefix + p.Name + + // Validate invocation string with regular expression. + invocation := p.Invocation + + // + // Plugin invocations must consist of + // zero or more comma-separated key=value pairs followed by a path. + // If pairs are present, a colon separates them from the path. + // Keys and values must be alphanumeric strings and may contain + // dashes, underscores, periods, or forward slashes. + // A path can contain any characters other than the separators ',', ':', and '='. + // + invocationRegex := regexp.MustCompile(`^([\w-_\/\.]+=[\w-_\/\.]+(,[\w-_\/\.]+=[\w-_\/\.]+)*:)?[^,:=]+$`) + if !invocationRegex.Match([]byte(p.Invocation)) { + return nil, fmt.Errorf("Invalid invocation of %s: %s", executableName, invocation) + } + + invocationParts := strings.Split(p.Invocation, ":") + var outputLocation string + switch len(invocationParts) { + case 1: + outputLocation = invocationParts[0] + case 2: + parameters := strings.Split(invocationParts[0], ",") + for _, keyvalue := range parameters { + pair := strings.Split(keyvalue, "=") + if len(pair) == 2 { + request.Parameters = append(request.Parameters, &plugins.Parameter{Name: pair[0], Value: pair[1]}) + } + } + outputLocation = invocationParts[1] + default: + // badly-formed request + outputLocation = invocationParts[len(invocationParts)-1] + } + + version := &plugins.Version{} + version.Major = 0 + version.Minor = 1 + version.Patch = 0 + request.CompilerVersion = version + + request.OutputPath = outputLocation + + request.SourceName = sourceName + switch sourceFormat { + case SourceFormatOpenAPI2: + request.AddModel("openapi.v2.Document", document) + // include experimental API surface model + surfaceModel, err := surface.NewModelFromOpenAPI2(document.(*openapi_v2.Document)) + if err == nil { + request.AddModel("surface.v1.Model", surfaceModel) + } + case SourceFormatOpenAPI3: + request.AddModel("openapi.v3.Document", document) + // include experimental API surface model + surfaceModel, err := surface.NewModelFromOpenAPI3(document.(*openapi_v3.Document)) + if err == nil { + request.AddModel("surface.v1.Model", surfaceModel) + } + case SourceFormatDiscovery: + request.AddModel("discovery.v1.Document", document) + default: + } + + requestBytes, _ := proto.Marshal(request) + + cmd := exec.Command(executableName, "-plugin") + cmd.Stdin = bytes.NewReader(requestBytes) + cmd.Stderr = os.Stderr + pluginStartTime := time.Now() + output, err := cmd.Output() + pluginElapsedTime := time.Since(pluginStartTime) + if timePlugins { + fmt.Printf("> %s (%s)\n", executableName, pluginElapsedTime) + } + if err != nil { + return nil, err + } + response := &plugins.Response{} + err = proto.Unmarshal(output, response) + if err != nil { + // Gnostic expects plugins to only write the + // response message to stdout. Be sure that + // any logging messages are written to stderr only. + return nil, errors.New("Invalid plugin response (plugins must write log messages to stderr, not stdout).") + } + plugins.HandleResponse(response, outputLocation) + return response.Messages, nil + } + return nil, nil +} + +func isFile(path string) bool { + fileInfo, err := os.Stat(path) + if err != nil { + return false + } + return !fileInfo.IsDir() +} + +func isDirectory(path string) bool { + fileInfo, err := os.Stat(path) + if err != nil { + return false + } + return fileInfo.IsDir() +} + +// Write bytes to a named file. +// Certain names have special meaning: +// ! writes nothing +// - writes to stdout +// = writes to stderr +// If a directory name is given, the file is written there with +// a name derived from the source and extension arguments. +func writeFile(name string, bytes []byte, source string, extension string) { + var writer io.Writer + if name == "!" { + return + } else if name == "-" { + writer = os.Stdout + } else if name == "=" { + writer = os.Stderr + } else if isDirectory(name) { + base := filepath.Base(source) + // Remove the original source extension. + base = base[0 : len(base)-len(filepath.Ext(base))] + // Build the path that puts the result in the passed-in directory. + filename := name + "/" + base + "." + extension + file, _ := os.Create(filename) + defer file.Close() + writer = file + } else { + file, _ := os.Create(name) + defer file.Close() + writer = file + } + writer.Write(bytes) + if name == "-" || name == "=" { + writer.Write([]byte("\n")) + } +} + +// The Gnostic structure holds global state information for gnostic. +type Gnostic struct { + usage string + sourceName string + binaryOutputPath string + textOutputPath string + yamlOutputPath string + jsonOutputPath string + errorOutputPath string + messageOutputPath string + resolveReferences bool + pluginCalls []*pluginCall + extensionHandlers []compiler.ExtensionHandler + sourceFormat int + timePlugins bool +} + +// Initialize a structure to store global application state. +func newGnostic() *Gnostic { + g := &Gnostic{} + // Option fields initialize to their default values. + g.usage = ` +Usage: gnostic SOURCE [OPTIONS] + SOURCE is the filename or URL of an API description. +Options: + --pb-out=PATH Write a binary proto to the specified location. + --text-out=PATH Write a text proto to the specified location. + --json-out=PATH Write a json API description to the specified location. + --yaml-out=PATH Write a yaml API description to the specified location. + --errors-out=PATH Write compilation errors to the specified location. + --messages-out=PATH Write messages generated by plugins to the specified + location. Messages from all plugin invocations are + written to a single common file. + --PLUGIN-out=PATH Run the plugin named gnostic-PLUGIN and write results + to the specified location. + --PLUGIN Run the plugin named gnostic-PLUGIN but don't write any + results. Used for plugins that return messages only. + PLUGIN must not match any other gnostic option. + --x-EXTENSION Use the extension named gnostic-x-EXTENSION + to process OpenAPI specification extensions. + --resolve-refs Explicitly resolve $ref references. + This could have problems with recursive definitions. + --time-plugins Report plugin runtimes. +` + // Initialize internal structures. + g.pluginCalls = make([]*pluginCall, 0) + g.extensionHandlers = make([]compiler.ExtensionHandler, 0) + return g +} + +// Parse command-line options. +func (g *Gnostic) readOptions() { + // plugin processing matches patterns of the form "--PLUGIN-out=PATH" and "--PLUGIN_out=PATH" + pluginRegex := regexp.MustCompile("--(.+)[-_]out=(.+)") + + // extension processing matches patterns of the form "--x-EXTENSION" + extensionRegex := regexp.MustCompile("--x-(.+)") + + for i, arg := range os.Args { + if i == 0 { + continue // skip the tool name + } + var m [][]byte + if m = pluginRegex.FindSubmatch([]byte(arg)); m != nil { + pluginName := string(m[1]) + invocation := string(m[2]) + switch pluginName { + case "pb": + g.binaryOutputPath = invocation + case "text": + g.textOutputPath = invocation + case "json": + g.jsonOutputPath = invocation + case "yaml": + g.yamlOutputPath = invocation + case "errors": + g.errorOutputPath = invocation + case "messages": + g.messageOutputPath = invocation + default: + p := &pluginCall{Name: pluginName, Invocation: invocation} + g.pluginCalls = append(g.pluginCalls, p) + } + } else if m = extensionRegex.FindSubmatch([]byte(arg)); m != nil { + extensionName := string(m[1]) + extensionHandler := compiler.ExtensionHandler{Name: extensionPrefix + extensionName} + g.extensionHandlers = append(g.extensionHandlers, extensionHandler) + } else if arg == "--resolve-refs" { + g.resolveReferences = true + } else if arg == "--time-plugins" { + g.timePlugins = true + } else if arg[0] == '-' && arg[1] == '-' { + // try letting the option specify a plugin with no output files (or unwanted output files) + // this is useful for calling plugins like linters that only return messages + p := &pluginCall{Name: arg[2:len(arg)], Invocation: "!"} + g.pluginCalls = append(g.pluginCalls, p) + } else if arg[0] == '-' { + fmt.Fprintf(os.Stderr, "Unknown option: %s.\n%s\n", arg, g.usage) + os.Exit(-1) + } else { + g.sourceName = arg + } + } +} + +// Validate command-line options. +func (g *Gnostic) validateOptions() { + if g.binaryOutputPath == "" && + g.textOutputPath == "" && + g.yamlOutputPath == "" && + g.jsonOutputPath == "" && + g.errorOutputPath == "" && + len(g.pluginCalls) == 0 { + fmt.Fprintf(os.Stderr, "Missing output directives.\n%s\n", g.usage) + os.Exit(-1) + } + if g.sourceName == "" { + fmt.Fprintf(os.Stderr, "No input specified.\n%s\n", g.usage) + os.Exit(-1) + } + // If we get here and the error output is unspecified, write errors to stderr. + if g.errorOutputPath == "" { + g.errorOutputPath = "=" + } +} + +// Generate an error message to be written to stderr or a file. +func (g *Gnostic) errorBytes(err error) []byte { + return []byte("Errors reading " + g.sourceName + "\n" + err.Error()) +} + +// Read an OpenAPI description from YAML or JSON. +func (g *Gnostic) readOpenAPIText(bytes []byte) (message proto.Message, err error) { + info, err := compiler.ReadInfoFromBytes(g.sourceName, bytes) + if err != nil { + return nil, err + } + // Determine the OpenAPI version. + g.sourceFormat = getOpenAPIVersionFromInfo(info) + if g.sourceFormat == SourceFormatUnknown { + return nil, errors.New("unable to identify OpenAPI version") + } + // Compile to the proto model. + if g.sourceFormat == SourceFormatOpenAPI2 { + document, err := openapi_v2.NewDocument(info, compiler.NewContextWithExtensions("$root", nil, &g.extensionHandlers)) + if err != nil { + return nil, err + } + message = document + } else if g.sourceFormat == SourceFormatOpenAPI3 { + document, err := openapi_v3.NewDocument(info, compiler.NewContextWithExtensions("$root", nil, &g.extensionHandlers)) + if err != nil { + return nil, err + } + message = document + } else { + document, err := discovery_v1.NewDocument(info, compiler.NewContextWithExtensions("$root", nil, &g.extensionHandlers)) + if err != nil { + return nil, err + } + message = document + } + return message, err +} + +// Read an OpenAPI binary file. +func (g *Gnostic) readOpenAPIBinary(data []byte) (message proto.Message, err error) { + // try to read an OpenAPI v3 document + documentV3 := &openapi_v3.Document{} + err = proto.Unmarshal(data, documentV3) + if err == nil && strings.HasPrefix(documentV3.Openapi, "3.0") { + g.sourceFormat = SourceFormatOpenAPI3 + return documentV3, nil + } + // if that failed, try to read an OpenAPI v2 document + documentV2 := &openapi_v2.Document{} + err = proto.Unmarshal(data, documentV2) + if err == nil && strings.HasPrefix(documentV2.Swagger, "2.0") { + g.sourceFormat = SourceFormatOpenAPI2 + return documentV2, nil + } + // if that failed, try to read a Discovery Format document + discoveryDocument := &discovery_v1.Document{} + err = proto.Unmarshal(data, discoveryDocument) + if err == nil { // && strings.HasPrefix(documentV2.Swagger, "2.0") { + g.sourceFormat = SourceFormatDiscovery + return discoveryDocument, nil + } + return nil, err +} + +// Write a binary pb representation. +func (g *Gnostic) writeBinaryOutput(message proto.Message) { + protoBytes, err := proto.Marshal(message) + if err != nil { + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + defer os.Exit(-1) + } else { + writeFile(g.binaryOutputPath, protoBytes, g.sourceName, "pb") + } +} + +// Write a text pb representation. +func (g *Gnostic) writeTextOutput(message proto.Message) { + bytes := []byte(proto.MarshalTextString(message)) + writeFile(g.textOutputPath, bytes, g.sourceName, "text") +} + +// Write JSON/YAML OpenAPI representations. +func (g *Gnostic) writeJSONYAMLOutput(message proto.Message) { + // Convert the OpenAPI document into an exportable MapSlice. + var rawInfo yaml.MapSlice + var ok bool + var err error + if g.sourceFormat == SourceFormatOpenAPI2 { + document := message.(*openapi_v2.Document) + rawInfo, ok = document.ToRawInfo().(yaml.MapSlice) + if !ok { + rawInfo = nil + } + } else if g.sourceFormat == SourceFormatOpenAPI3 { + document := message.(*openapi_v3.Document) + rawInfo, ok = document.ToRawInfo().(yaml.MapSlice) + if !ok { + rawInfo = nil + } + } else if g.sourceFormat == SourceFormatDiscovery { + document := message.(*discovery_v1.Document) + rawInfo, ok = document.ToRawInfo().(yaml.MapSlice) + if !ok { + rawInfo = nil + } + } + // Optionally write description in yaml format. + if g.yamlOutputPath != "" { + var bytes []byte + if rawInfo != nil { + bytes, err = yaml.Marshal(rawInfo) + if err != nil { + fmt.Fprintf(os.Stderr, "Error generating yaml output %s\n", err.Error()) + } + writeFile(g.yamlOutputPath, bytes, g.sourceName, "yaml") + } else { + fmt.Fprintf(os.Stderr, "No yaml output available.\n") + } + } + // Optionally write description in json format. + if g.jsonOutputPath != "" { + var bytes []byte + if rawInfo != nil { + bytes, _ = jsonwriter.Marshal(rawInfo) + if err != nil { + fmt.Fprintf(os.Stderr, "Error generating json output %s\n", err.Error()) + } + writeFile(g.jsonOutputPath, bytes, g.sourceName, "json") + } else { + fmt.Fprintf(os.Stderr, "No json output available.\n") + } + } +} + +// Write messages. +func (g *Gnostic) writeMessagesOutput(message proto.Message) { + protoBytes, err := proto.Marshal(message) + if err != nil { + writeFile(g.messageOutputPath, g.errorBytes(err), g.sourceName, "errors") + defer os.Exit(-1) + } else { + writeFile(g.messageOutputPath, protoBytes, g.sourceName, "messages.pb") + } +} + +// Perform all actions specified in the command-line options. +func (g *Gnostic) performActions(message proto.Message) (err error) { + // Optionally resolve internal references. + if g.resolveReferences { + if g.sourceFormat == SourceFormatOpenAPI2 { + document := message.(*openapi_v2.Document) + _, err = document.ResolveReferences(g.sourceName) + } else if g.sourceFormat == SourceFormatOpenAPI3 { + document := message.(*openapi_v3.Document) + _, err = document.ResolveReferences(g.sourceName) + } + if err != nil { + return err + } + } + // Optionally write proto in binary format. + if g.binaryOutputPath != "" { + g.writeBinaryOutput(message) + } + // Optionally write proto in text format. + if g.textOutputPath != "" { + g.writeTextOutput(message) + } + // Optionally write document in yaml and/or json formats. + if g.yamlOutputPath != "" || g.jsonOutputPath != "" { + g.writeJSONYAMLOutput(message) + } + // Call all specified plugins. + messages := make([]*plugins.Message, 0) + for _, p := range g.pluginCalls { + pluginMessages, err := p.perform(message, g.sourceFormat, g.sourceName, g.timePlugins) + if err != nil { + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + defer os.Exit(-1) // run all plugins, even when some have errors + } + messages = append(messages, pluginMessages...) + } + if g.messageOutputPath != "" { + g.writeMessagesOutput(&plugins.Messages{Messages: messages}) + } else { + // Print any messages from the plugins + if len(messages) > 0 { + for _, message := range messages { + fmt.Printf("%+v\n", message) + } + } + } + return nil +} + +func (g *Gnostic) main() { + var err error + g.readOptions() + g.validateOptions() + // Read the OpenAPI source. + bytes, err := compiler.ReadBytesForFile(g.sourceName) + if err != nil { + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + os.Exit(-1) + } + extension := strings.ToLower(filepath.Ext(g.sourceName)) + var message proto.Message + if extension == ".json" || extension == ".yaml" { + // Try to read the source as JSON/YAML. + message, err = g.readOpenAPIText(bytes) + if err != nil { + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + os.Exit(-1) + } + } else if extension == ".pb" { + // Try to read the source as a binary protocol buffer. + message, err = g.readOpenAPIBinary(bytes) + if err != nil { + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + os.Exit(-1) + } + } else { + err = errors.New("unknown file extension. 'json', 'yaml', and 'pb' are accepted") + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + os.Exit(-1) + } + // Perform actions specified by command options. + err = g.performActions(message) + if err != nil { + writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors") + os.Exit(-1) + } +} + +func main() { + g := newGnostic() + g.main() +} diff --git a/vendor/github.com/googleapis/gnostic/gnostic_test.go b/vendor/github.com/googleapis/gnostic/gnostic_test.go new file mode 100644 index 000000000..22eaee827 --- /dev/null +++ b/vendor/github.com/googleapis/gnostic/gnostic_test.go @@ -0,0 +1,453 @@ +package main + +import ( + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +func testCompiler(t *testing.T, inputFile string, referenceFile string, expectErrors bool) { + textFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".text", 1) + errorsFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".errors", 1) + // remove any preexisting output files + os.Remove(textFile) + os.Remove(errorsFile) + // run the compiler + var err error + var cmd = exec.Command( + "gnostic", + inputFile, + "--text-out=.", + "--errors-out=.", + "--resolve-refs") + //t.Log(cmd.Args) + err = cmd.Run() + if err != nil && !expectErrors { + t.Logf("Compile failed: %+v", err) + t.FailNow() + } + // verify the output against a reference + var outputFile string + if expectErrors { + outputFile = errorsFile + } else { + outputFile = textFile + } + err = exec.Command("diff", outputFile, referenceFile).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } else { + // if the test succeeded, clean up + os.Remove(textFile) + os.Remove(errorsFile) + } +} + +func testNormal(t *testing.T, inputFile string, referenceFile string) { + testCompiler(t, inputFile, referenceFile, false) +} + +func testErrors(t *testing.T, inputFile string, referenceFile string) { + testCompiler(t, inputFile, referenceFile, true) +} + +func TestPetstoreJSON(t *testing.T) { + testNormal(t, + "examples/v2.0/json/petstore.json", + "test/v2.0/petstore.text") +} + +func TestPetstoreYAML(t *testing.T) { + testNormal(t, + "examples/v2.0/yaml/petstore.yaml", + "test/v2.0/petstore.text") +} + +func TestSeparateYAML(t *testing.T) { + testNormal(t, + "examples/v2.0/yaml/petstore-separate/spec/swagger.yaml", + "test/v2.0/yaml/petstore-separate/spec/swagger.text") +} + +func TestSeparateJSON(t *testing.T) { + testNormal(t, + "examples/v2.0/json/petstore-separate/spec/swagger.json", + "test/v2.0/yaml/petstore-separate/spec/swagger.text") // yaml and json results should be identical +} + +func TestRemotePetstoreJSON(t *testing.T) { + testNormal(t, + "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore.json", + "test/v2.0/petstore.text") +} + +func TestRemotePetstoreYAML(t *testing.T) { + testNormal(t, + "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore.yaml", + "test/v2.0/petstore.text") +} + +func TestRemoteSeparateYAML(t *testing.T) { + testNormal(t, + "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore-separate/spec/swagger.yaml", + "test/v2.0/yaml/petstore-separate/spec/swagger.text") +} + +func TestRemoteSeparateJSON(t *testing.T) { + testNormal(t, + "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore-separate/spec/swagger.json", + "test/v2.0/yaml/petstore-separate/spec/swagger.text") +} + +func TestErrorBadProperties(t *testing.T) { + testErrors(t, + "examples/errors/petstore-badproperties.yaml", + "test/errors/petstore-badproperties.errors") +} + +func TestErrorUnresolvedRefs(t *testing.T) { + testErrors(t, + "examples/errors/petstore-unresolvedrefs.yaml", + "test/errors/petstore-unresolvedrefs.errors") +} + +func TestErrorMissingVersion(t *testing.T) { + testErrors(t, + "examples/errors/petstore-missingversion.yaml", + "test/errors/petstore-missingversion.errors") +} + +func testPlugin(t *testing.T, plugin string, inputFile string, outputFile string, referenceFile string) { + // remove any preexisting output files + os.Remove(outputFile) + // run the compiler + var err error + output, err := exec.Command( + "gnostic", + "--"+plugin+"-out=-", + inputFile).Output() + if err != nil { + t.Logf("Compile failed: %+v", err) + t.FailNow() + } + _ = ioutil.WriteFile(outputFile, output, 0644) + err = exec.Command("diff", outputFile, referenceFile).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } else { + // if the test succeeded, clean up + os.Remove(outputFile) + } +} + +func TestSamplePluginWithPetstore(t *testing.T) { + testPlugin(t, + "summary", + "examples/v2.0/yaml/petstore.yaml", + "sample-petstore.out", + "test/v2.0/yaml/sample-petstore.out") +} + +func TestErrorInvalidPluginInvocations(t *testing.T) { + var err error + output, err := exec.Command( + "gnostic", + "examples/v2.0/yaml/petstore.yaml", + "--errors-out=-", + "--plugin-out=foo=bar,:abc", + "--plugin-out=,foo=bar:abc", + "--plugin-out=foo=:abc", + "--plugin-out==bar:abc", + "--plugin-out=,,:abc", + "--plugin-out=foo=bar=baz:abc", + ).Output() + if err == nil { + t.Logf("Invalid invocations were accepted") + t.FailNow() + } + outputFile := "invalid-plugin-invocation.errors" + _ = ioutil.WriteFile(outputFile, output, 0644) + err = exec.Command("diff", outputFile, "test/errors/invalid-plugin-invocation.errors").Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } else { + // if the test succeeded, clean up + os.Remove(outputFile) + } +} + +func TestValidPluginInvocations(t *testing.T) { + var err error + output, err := exec.Command( + "gnostic", + "examples/v2.0/yaml/petstore.yaml", + "--errors-out=-", + // verify an invocation with no parameters + "--summary-out=!", // "!" indicates that no output should be generated + // verify single pair of parameters + "--summary-out=a=b:!", + // verify multiple parameters + "--summary-out=a=b,c=123,xyz=alphabetagammadelta:!", + // verify that special characters / . - _ can be included in parameter keys and values + "--summary-out=a/b/c=x/y/z:!", + "--summary-out=a.b.c=x.y.z:!", + "--summary-out=a-b-c=x-y-z:!", + "--summary-out=a_b_c=x_y_z:!", + ).Output() + if len(output) != 0 { + t.Logf("Valid invocations generated invalid errors\n%s", string(output)) + t.FailNow() + } + if err != nil { + t.Logf("Valid invocations were not accepted") + t.FailNow() + } +} + +func TestExtensionHandlerWithLibraryExample(t *testing.T) { + outputFile := "library-example-with-ext.text.out" + inputFile := "test/library-example-with-ext.json" + referenceFile := "test/library-example-with-ext.text.out" + + os.Remove(outputFile) + // run the compiler + var err error + + command := exec.Command( + "gnostic", + "--x-sampleone", + "--x-sampletwo", + "--text-out="+outputFile, + "--resolve-refs", + inputFile) + + _, err = command.Output() + if err != nil { + t.Logf("Compile failed for command %v: %+v", command, err) + t.FailNow() + } + //_ = ioutil.WriteFile(outputFile, output, 0644) + err = exec.Command("diff", outputFile, referenceFile).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } else { + // if the test succeeded, clean up + os.Remove(outputFile) + } +} + +func TestJSONOutput(t *testing.T) { + inputFile := "test/library-example-with-ext.json" + + textFile := "sample.text" + jsonFile := "sample.json" + textFile2 := "sample2.text" + jsonFile2 := "sample2.json" + + os.Remove(textFile) + os.Remove(jsonFile) + os.Remove(textFile2) + os.Remove(jsonFile2) + + var err error + + // Run the compiler once. + command := exec.Command( + "gnostic", + "--text-out="+textFile, + "--json-out="+jsonFile, + inputFile) + _, err = command.Output() + if err != nil { + t.Logf("Compile failed for command %v: %+v", command, err) + t.FailNow() + } + + // Run the compiler again, this time on the generated output. + command = exec.Command( + "gnostic", + "--text-out="+textFile2, + "--json-out="+jsonFile2, + jsonFile) + _, err = command.Output() + if err != nil { + t.Logf("Compile failed for command %v: %+v", command, err) + t.FailNow() + } + + // Verify that both models have the same internal representation. + err = exec.Command("diff", textFile, textFile2).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } else { + // if the test succeeded, clean up + os.Remove(textFile) + os.Remove(jsonFile) + os.Remove(textFile2) + os.Remove(jsonFile2) + } +} + +func TestYAMLOutput(t *testing.T) { + inputFile := "test/library-example-with-ext.json" + + textFile := "sample.text" + yamlFile := "sample.yaml" + textFile2 := "sample2.text" + yamlFile2 := "sample2.yaml" + + os.Remove(textFile) + os.Remove(yamlFile) + os.Remove(textFile2) + os.Remove(yamlFile2) + + var err error + + // Run the compiler once. + command := exec.Command( + "gnostic", + "--text-out="+textFile, + "--yaml-out="+yamlFile, + inputFile) + _, err = command.Output() + if err != nil { + t.Logf("Compile failed for command %v: %+v", command, err) + t.FailNow() + } + + // Run the compiler again, this time on the generated output. + command = exec.Command( + "gnostic", + "--text-out="+textFile2, + "--yaml-out="+yamlFile2, + yamlFile) + _, err = command.Output() + if err != nil { + t.Logf("Compile failed for command %v: %+v", command, err) + t.FailNow() + } + + // Verify that both models have the same internal representation. + err = exec.Command("diff", textFile, textFile2).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } else { + // if the test succeeded, clean up + os.Remove(textFile) + os.Remove(yamlFile) + os.Remove(textFile2) + os.Remove(yamlFile2) + } +} + +func testBuilder(version string, t *testing.T) { + var err error + + pbFile := "petstore-" + version + ".pb" + yamlFile := "petstore.yaml" + jsonFile := "petstore.json" + textFile := "petstore.text" + textReference := "test/" + version + ".0/petstore.text" + + os.Remove(pbFile) + os.Remove(textFile) + os.Remove(yamlFile) + os.Remove(jsonFile) + + // Generate petstore.pb. + command := exec.Command( + "petstore-builder", + "--"+version) + _, err = command.Output() + if err != nil { + t.Logf("Command %v failed: %+v", command, err) + t.FailNow() + } + + // Convert petstore.pb to yaml and json. + command = exec.Command( + "gnostic", + pbFile, + "--json-out="+jsonFile, + "--yaml-out="+yamlFile) + _, err = command.Output() + if err != nil { + t.Logf("Command %v failed: %+v", command, err) + t.FailNow() + } + + // Read petstore.yaml, resolve references, and export text. + command = exec.Command( + "gnostic", + yamlFile, + "--resolve-refs", + "--text-out="+textFile) + _, err = command.Output() + if err != nil { + t.Logf("Command %v failed: %+v", command, err) + t.FailNow() + } + + // Verify that the generated text matches our reference. + err = exec.Command("diff", textFile, textReference).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } + + // Read petstore.json, resolve references, and export text. + command = exec.Command( + "gnostic", + jsonFile, + "--resolve-refs", + "--text-out="+textFile) + _, err = command.Output() + if err != nil { + t.Logf("Command %v failed: %+v", command, err) + t.FailNow() + } + + // Verify that the generated text matches our reference. + err = exec.Command("diff", textFile, textReference).Run() + if err != nil { + t.Logf("Diff failed: %+v", err) + t.FailNow() + } + + // if the test succeeded, clean up + os.Remove(pbFile) + os.Remove(textFile) + os.Remove(yamlFile) + os.Remove(jsonFile) +} + +func TestBuilderV2(t *testing.T) { + testBuilder("v2", t) +} + +func TestBuilderV3(t *testing.T) { + testBuilder("v3", t) +} + +// OpenAPI 3.0 tests + +func TestPetstoreYAML_30(t *testing.T) { + testNormal(t, + "examples/v3.0/yaml/petstore.yaml", + "test/v3.0/petstore.text") +} + +func TestPetstoreJSON_30(t *testing.T) { + testNormal(t, + "examples/v3.0/json/petstore.json", + "test/v3.0/petstore.text") +} diff --git a/vendor/github.com/gophercloud/gophercloud/.gitignore b/vendor/github.com/gophercloud/gophercloud/.gitignore new file mode 100644 index 000000000..df9048a01 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/.gitignore @@ -0,0 +1,2 @@ +**/*.swp +.idea diff --git a/vendor/github.com/gophercloud/gophercloud/.travis.yml b/vendor/github.com/gophercloud/gophercloud/.travis.yml new file mode 100644 index 000000000..59c419495 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/.travis.yml @@ -0,0 +1,21 @@ +language: go +sudo: false +install: +- go get golang.org/x/crypto/ssh +- go get -v -tags 'fixtures acceptance' ./... +- go get github.com/wadey/gocovmerge +- go get github.com/mattn/goveralls +- go get golang.org/x/tools/cmd/goimports +go: +- 1.8 +- tip +env: + global: + - secure: "xSQsAG5wlL9emjbCdxzz/hYQsSpJ/bABO1kkbwMSISVcJ3Nk0u4ywF+LS4bgeOnwPfmFvNTOqVDu3RwEvMeWXSI76t1piCPcObutb2faKLVD/hLoAS76gYX+Z8yGWGHrSB7Do5vTPj1ERe2UljdrnsSeOXzoDwFxYRaZLX4bBOB4AyoGvRniil5QXPATiA1tsWX1VMicj8a4F8X+xeESzjt1Q5Iy31e7vkptu71bhvXCaoo5QhYwT+pLR9dN0S1b7Ro0KVvkRefmr1lUOSYd2e74h6Lc34tC1h3uYZCS4h47t7v5cOXvMNxinEj2C51RvbjvZI1RLVdkuAEJD1Iz4+Ote46nXbZ//6XRZMZz/YxQ13l7ux1PFjgEB6HAapmF5Xd8PRsgeTU9LRJxpiTJ3P5QJ3leS1va8qnziM5kYipj/Rn+V8g2ad/rgkRox9LSiR9VYZD2Pe45YCb1mTKSl2aIJnV7nkOqsShY5LNB4JZSg7xIffA+9YVDktw8dJlATjZqt7WvJJ49g6A61mIUV4C15q2JPGKTkZzDiG81NtmS7hFa7k0yaE2ELgYocbcuyUcAahhxntYTC0i23nJmEHVNiZmBO3u7EgpWe4KGVfumU+lt12tIn5b3dZRBBUk3QakKKozSK1QPHGpk/AZGrhu7H6l8to6IICKWtDcyMPQ=" +before_script: +- go vet ./... +script: +- ./script/coverage +- ./script/format +after_success: +- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=cover.out diff --git a/vendor/github.com/gophercloud/gophercloud/.zuul.yaml b/vendor/github.com/gophercloud/gophercloud/.zuul.yaml new file mode 100644 index 000000000..c259d03e1 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/.zuul.yaml @@ -0,0 +1,12 @@ +- project: + name: gophercloud/gophercloud + check: + jobs: + - gophercloud-unittest + - gophercloud-acceptance-test + recheck-mitaka: + jobs: + - gophercloud-acceptance-test-mitaka + recheck-pike: + jobs: + - gophercloud-acceptance-test-pike diff --git a/vendor/github.com/gophercloud/gophercloud/CHANGELOG.md b/vendor/github.com/gophercloud/gophercloud/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/github.com/gophercloud/gophercloud/FAQ.md b/vendor/github.com/gophercloud/gophercloud/FAQ.md new file mode 100644 index 000000000..88a366a28 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/FAQ.md @@ -0,0 +1,148 @@ +# Tips + +## Implementing default logging and re-authentication attempts + +You can implement custom logging and/or limit re-auth attempts by creating a custom HTTP client +like the following and setting it as the provider client's HTTP Client (via the +`gophercloud.ProviderClient.HTTPClient` field): + +```go +//... + +// LogRoundTripper satisfies the http.RoundTripper interface and is used to +// customize the default Gophercloud RoundTripper to allow for logging. +type LogRoundTripper struct { + rt http.RoundTripper + numReauthAttempts int +} + +// newHTTPClient return a custom HTTP client that allows for logging relevant +// information before and after the HTTP request. +func newHTTPClient() http.Client { + return http.Client{ + Transport: &LogRoundTripper{ + rt: http.DefaultTransport, + }, + } +} + +// RoundTrip performs a round-trip HTTP request and logs relevant information about it. +func (lrt *LogRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) { + glog.Infof("Request URL: %s\n", request.URL) + + response, err := lrt.rt.RoundTrip(request) + if response == nil { + return nil, err + } + + if response.StatusCode == http.StatusUnauthorized { + if lrt.numReauthAttempts == 3 { + return response, fmt.Errorf("Tried to re-authenticate 3 times with no success.") + } + lrt.numReauthAttempts++ + } + + glog.Debugf("Response Status: %s\n", response.Status) + + return response, nil +} + +endpoint := "https://127.0.0.1/auth" +pc := openstack.NewClient(endpoint) +pc.HTTPClient = newHTTPClient() + +//... +``` + + +## Implementing custom objects + +OpenStack request/response objects may differ among variable names or types. + +### Custom request objects + +To pass custom options to a request, implement the desired `OptsBuilder` interface. For +example, to pass in + +```go +type MyCreateServerOpts struct { + Name string + Size int +} +``` + +to `servers.Create`, simply implement the `servers.CreateOptsBuilder` interface: + +```go +func (o MyCreateServeropts) ToServerCreateMap() (map[string]interface{}, error) { + return map[string]interface{}{ + "name": o.Name, + "size": o.Size, + }, nil +} +``` + +create an instance of your custom options object, and pass it to `servers.Create`: + +```go +// ... +myOpts := MyCreateServerOpts{ + Name: "s1", + Size: "100", +} +server, err := servers.Create(computeClient, myOpts).Extract() +// ... +``` + +### Custom response objects + +Some OpenStack services have extensions. Extensions that are supported in Gophercloud can be +combined to create a custom object: + +```go +// ... +type MyVolume struct { + volumes.Volume + tenantattr.VolumeExt +} + +var v struct { + MyVolume `json:"volume"` +} + +err := volumes.Get(client, volID).ExtractInto(&v) +// ... +``` + +## Overriding default `UnmarshalJSON` method + +For some response objects, a field may be a custom type or may be allowed to take on +different types. In these cases, overriding the default `UnmarshalJSON` method may be +necessary. To do this, declare the JSON `struct` field tag as "-" and create an `UnmarshalJSON` +method on the type: + +```go +// ... +type MyVolume struct { + ID string `json: "id"` + TimeCreated time.Time `json: "-"` +} + +func (r *MyVolume) UnmarshalJSON(b []byte) error { + type tmp MyVolume + var s struct { + tmp + TimeCreated gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = Volume(s.tmp) + + r.TimeCreated = time.Time(s.CreatedAt) + + return err +} +// ... +``` diff --git a/vendor/github.com/gophercloud/gophercloud/MIGRATING.md b/vendor/github.com/gophercloud/gophercloud/MIGRATING.md new file mode 100644 index 000000000..aa383c9cc --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/MIGRATING.md @@ -0,0 +1,32 @@ +# Compute + +## Floating IPs + +* `github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingip` is now `github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips` +* `floatingips.Associate` and `floatingips.Disassociate` have been removed. +* `floatingips.DisassociateOpts` is now required to disassociate a Floating IP. + +## Security Groups + +* `secgroups.AddServerToGroup` is now `secgroups.AddServer`. +* `secgroups.RemoveServerFromGroup` is now `secgroups.RemoveServer`. + +## Servers + +* `servers.Reboot` now requires a `servers.RebootOpts` struct: + + ```golang + rebootOpts := &servers.RebootOpts{ + Type: servers.SoftReboot, + } + res := servers.Reboot(client, server.ID, rebootOpts) + ``` + +# Identity + +## V3 + +### Tokens + +* `Token.ExpiresAt` is now of type `gophercloud.JSONRFC3339Milli` instead of + `time.Time` diff --git a/vendor/github.com/gophercloud/gophercloud/README.md b/vendor/github.com/gophercloud/gophercloud/README.md new file mode 100644 index 000000000..bb218c3fe --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/README.md @@ -0,0 +1,159 @@ +# Gophercloud: an OpenStack SDK for Go +[![Build Status](https://travis-ci.org/gophercloud/gophercloud.svg?branch=master)](https://travis-ci.org/gophercloud/gophercloud) +[![Coverage Status](https://coveralls.io/repos/github/gophercloud/gophercloud/badge.svg?branch=master)](https://coveralls.io/github/gophercloud/gophercloud?branch=master) + +Gophercloud is an OpenStack Go SDK. + +## Useful links + +* [Reference documentation](http://godoc.org/github.com/gophercloud/gophercloud) +* [Effective Go](https://golang.org/doc/effective_go.html) + +## How to install + +Before installing, you need to ensure that your [GOPATH environment variable](https://golang.org/doc/code.html#GOPATH) +is pointing to an appropriate directory where you want to install Gophercloud: + +```bash +mkdir $HOME/go +export GOPATH=$HOME/go +``` + +To protect yourself against changes in your dependencies, we highly recommend choosing a +[dependency management solution](https://github.com/golang/go/wiki/PackageManagementTools) for +your projects, such as [godep](https://github.com/tools/godep). Once this is set up, you can install +Gophercloud as a dependency like so: + +```bash +go get github.com/gophercloud/gophercloud + +# Edit your code to import relevant packages from "github.com/gophercloud/gophercloud" + +godep save ./... +``` + +This will install all the source files you need into a `Godeps/_workspace` directory, which is +referenceable from your own source files when you use the `godep go` command. + +## Getting started + +### Credentials + +Because you'll be hitting an API, you will need to retrieve your OpenStack +credentials and either store them as environment variables or in your local Go +files. The first method is recommended because it decouples credential +information from source code, allowing you to push the latter to your version +control system without any security risk. + +You will need to retrieve the following: + +* username +* password +* a valid Keystone identity URL + +For users that have the OpenStack dashboard installed, there's a shortcut. If +you visit the `project/access_and_security` path in Horizon and click on the +"Download OpenStack RC File" button at the top right hand corner, you will +download a bash file that exports all of your access details to environment +variables. To execute the file, run `source admin-openrc.sh` and you will be +prompted for your password. + +### Authentication + +Once you have access to your credentials, you can begin plugging them into +Gophercloud. The next step is authentication, and this is handled by a base +"Provider" struct. To get one, you can either pass in your credentials +explicitly, or tell Gophercloud to use environment variables: + +```go +import ( + "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack" + "github.com/gophercloud/gophercloud/openstack/utils" +) + +// Option 1: Pass in the values yourself +opts := gophercloud.AuthOptions{ + IdentityEndpoint: "https://openstack.example.com:5000/v2.0", + Username: "{username}", + Password: "{password}", +} + +// Option 2: Use a utility function to retrieve all your environment variables +opts, err := openstack.AuthOptionsFromEnv() +``` + +Once you have the `opts` variable, you can pass it in and get back a +`ProviderClient` struct: + +```go +provider, err := openstack.AuthenticatedClient(opts) +``` + +The `ProviderClient` is the top-level client that all of your OpenStack services +derive from. The provider contains all of the authentication details that allow +your Go code to access the API - such as the base URL and token ID. + +### Provision a server + +Once we have a base Provider, we inject it as a dependency into each OpenStack +service. In order to work with the Compute API, we need a Compute service +client; which can be created like so: + +```go +client, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{ + Region: os.Getenv("OS_REGION_NAME"), +}) +``` + +We then use this `client` for any Compute API operation we want. In our case, +we want to provision a new server - so we invoke the `Create` method and pass +in the flavor ID (hardware specification) and image ID (operating system) we're +interested in: + +```go +import "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" + +server, err := servers.Create(client, servers.CreateOpts{ + Name: "My new server!", + FlavorRef: "flavor_id", + ImageRef: "image_id", +}).Extract() +``` + +The above code sample creates a new server with the parameters, and embodies the +new resource in the `server` variable (a +[`servers.Server`](http://godoc.org/github.com/gophercloud/gophercloud) struct). + +## Advanced Usage + +Have a look at the [FAQ](./FAQ.md) for some tips on customizing the way Gophercloud works. + +## Backwards-Compatibility Guarantees + +None. Vendor it and write tests covering the parts you use. + +## Contributing + +See the [contributing guide](./.github/CONTRIBUTING.md). + +## Help and feedback + +If you're struggling with something or have spotted a potential bug, feel free +to submit an issue to our [bug tracker](/issues). + +## Thank You + +We'd like to extend special thanks and appreciation to the following: + +### OpenLab + + + +OpenLab is providing a full CI environment to test each PR and merge for a variety of OpenStack releases. + +### VEXXHOST + + + +VEXXHOST is providing their services to assist with the development and testing of Gophercloud. diff --git a/vendor/github.com/gophercloud/gophercloud/STYLEGUIDE.md b/vendor/github.com/gophercloud/gophercloud/STYLEGUIDE.md new file mode 100644 index 000000000..22a290094 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/STYLEGUIDE.md @@ -0,0 +1,79 @@ + +## On Pull Requests + +- Please make sure to read our [contributing guide](/.github/CONTRIBUTING.md). + +- Before you start a PR there needs to be a Github issue and a discussion about it + on that issue with a core contributor, even if it's just a 'SGTM'. + +- A PR's description must reference the issue it closes with a `For ` (e.g. For #293). + +- A PR's description must contain link(s) to the line(s) in the OpenStack + source code (on Github) that prove(s) the PR code to be valid. Links to documentation + are not good enough. The link(s) should be to a non-`master` branch. For example, + a pull request implementing the creation of a Neutron v2 subnet might put the + following link in the description: + + https://github.com/openstack/neutron/blob/stable/mitaka/neutron/api/v2/attributes.py#L749 + + From that link, a reviewer (or user) can verify the fields in the request/response + objects in the PR. + +- A PR that is in-progress should have `[wip]` in front of the PR's title. When + ready for review, remove the `[wip]` and ping a core contributor with an `@`. + +- Forcing PRs to be small can have the effect of users submitting PRs in a hierarchical chain, with + one depending on the next. If a PR depends on another one, it should have a [Pending #PRNUM] + prefix in the PR title. In addition, it will be the PR submitter's responsibility to remove the + [Pending #PRNUM] tag once the PR has been updated with the merged, dependent PR. That will + let reviewers know it is ready to review. + +- A PR should be small. Even if you intend on implementing an entire + service, a PR should only be one route of that service + (e.g. create server or get server, but not both). + +- Unless explicitly asked, do not squash commits in the middle of a review; only + append. It makes it difficult for the reviewer to see what's changed from one + review to the next. + +- See [#583](https://github.com/gophercloud/gophercloud/issues/583) as an example of a + well-formatted issue which contains all relevant information we need to review and approve. + +## On Code + +- In re design: follow as closely as is reasonable the code already in the library. + Most operations (e.g. create, delete) admit the same design. + +- Unit tests and acceptance (integration) tests must be written to cover each PR. + Tests for operations with several options (e.g. list, create) should include all + the options in the tests. This will allow users to verify an operation on their + own infrastructure and see an example of usage. + +- If in doubt, ask in-line on the PR. + +### File Structure + +- The following should be used in most cases: + + - `requests.go`: contains all the functions that make HTTP requests and the + types associated with the HTTP request (parameters for URL, body, etc) + - `results.go`: contains all the response objects and their methods + - `urls.go`: contains the endpoints to which the requests are made + +### Naming + +- For methods on a type in `results.go`, the receiver should be named `r` and the + variable into which it will be unmarshalled `s`. + +- Functions in `requests.go`, with the exception of functions that return a + `pagination.Pager`, should be named returns of the name `r`. + +- Functions in `requests.go` that accept request bodies should accept as their + last parameter an `interface` named `OptsBuilder` (eg `CreateOptsBuilder`). + This `interface` should have at the least a method named `ToMap` + (eg `ToPortCreateMap`). + +- Functions in `requests.go` that accept query strings should accept as their + last parameter an `interface` named `OptsBuilder` (eg `ListOptsBuilder`). + This `interface` should have at the least a method named `ToQuery` + (eg `ToServerListQuery`). diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/delegate.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/delegate.go new file mode 100644 index 000000000..00e7c3bec --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/delegate.go @@ -0,0 +1,23 @@ +package extensions + +import ( + "github.com/gophercloud/gophercloud" + common "github.com/gophercloud/gophercloud/openstack/common/extensions" + "github.com/gophercloud/gophercloud/pagination" +) + +// ExtractExtensions interprets a Page as a slice of Extensions. +func ExtractExtensions(page pagination.Page) ([]common.Extension, error) { + return common.ExtractExtensions(page) +} + +// Get retrieves information for a specific extension using its alias. +func Get(c *gophercloud.ServiceClient, alias string) common.GetResult { + return common.Get(c, alias) +} + +// List returns a Pager which allows you to iterate over the full collection of extensions. +// It does not accept query parameters. +func List(c *gophercloud.ServiceClient) pagination.Pager { + return common.List(c) +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/doc.go new file mode 100644 index 000000000..2b447da1d --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/doc.go @@ -0,0 +1,3 @@ +// Package extensions provides information and interaction with the +// different extensions available for the OpenStack Compute service. +package extensions diff --git a/vendor/github.com/gregjones/httpcache/.travis.yml b/vendor/github.com/gregjones/httpcache/.travis.yml new file mode 100644 index 000000000..b5ffbe03d --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/.travis.yml @@ -0,0 +1,19 @@ +sudo: false +language: go +go: + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - master +matrix: + allow_failures: + - go: master + fast_finish: true +install: + - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d .) + - go tool vet . + - go test -v -race ./... diff --git a/vendor/github.com/gregjones/httpcache/README.md b/vendor/github.com/gregjones/httpcache/README.md new file mode 100644 index 000000000..09c9e7c17 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/README.md @@ -0,0 +1,25 @@ +httpcache +========= + +[![Build Status](https://travis-ci.org/gregjones/httpcache.svg?branch=master)](https://travis-ci.org/gregjones/httpcache) [![GoDoc](https://godoc.org/github.com/gregjones/httpcache?status.svg)](https://godoc.org/github.com/gregjones/httpcache) + +Package httpcache provides a http.RoundTripper implementation that works as a mostly [RFC 7234](https://tools.ietf.org/html/rfc7234) compliant cache for http responses. + +It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client and not for a shared proxy). + +Cache Backends +-------------- + +- The built-in 'memory' cache stores responses in an in-memory map. +- [`github.com/gregjones/httpcache/diskcache`](https://github.com/gregjones/httpcache/tree/master/diskcache) provides a filesystem-backed cache using the [diskv](https://github.com/peterbourgon/diskv) library. +- [`github.com/gregjones/httpcache/memcache`](https://github.com/gregjones/httpcache/tree/master/memcache) provides memcache implementations, for both App Engine and 'normal' memcache servers. +- [`sourcegraph.com/sourcegraph/s3cache`](https://sourcegraph.com/github.com/sourcegraph/s3cache) uses Amazon S3 for storage. +- [`github.com/gregjones/httpcache/leveldbcache`](https://github.com/gregjones/httpcache/tree/master/leveldbcache) provides a filesystem-backed cache using [leveldb](https://github.com/syndtr/goleveldb/leveldb). +- [`github.com/die-net/lrucache`](https://github.com/die-net/lrucache) provides an in-memory cache that will evict least-recently used entries. +- [`github.com/die-net/lrucache/twotier`](https://github.com/die-net/lrucache/tree/master/twotier) allows caches to be combined, for example to use lrucache above with a persistent disk-cache. +- [`github.com/birkelund/boltdbcache`](https://github.com/birkelund/boltdbcache) provides a BoltDB implementation (based on the [bbolt](https://github.com/coreos/bbolt) fork). + +License +------- + +- [MIT License](LICENSE.txt) diff --git a/vendor/github.com/gregjones/httpcache/diskcache/diskcache_test.go b/vendor/github.com/gregjones/httpcache/diskcache/diskcache_test.go new file mode 100644 index 000000000..35c76cbd1 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/diskcache/diskcache_test.go @@ -0,0 +1,42 @@ +package diskcache + +import ( + "bytes" + "io/ioutil" + "os" + "testing" +) + +func TestDiskCache(t *testing.T) { + tempDir, err := ioutil.TempDir("", "httpcache") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + defer os.RemoveAll(tempDir) + + cache := New(tempDir) + + key := "testKey" + _, ok := cache.Get(key) + if ok { + t.Fatal("retrieved key before adding it") + } + + val := []byte("some bytes") + cache.Set(key, val) + + retVal, ok := cache.Get(key) + if !ok { + t.Fatal("could not retrieve an element we just added") + } + if !bytes.Equal(retVal, val) { + t.Fatal("retrieved a different value than what we put in") + } + + cache.Delete(key) + + _, ok = cache.Get(key) + if ok { + t.Fatal("deleted key still present") + } +} diff --git a/vendor/github.com/gregjones/httpcache/httpcache_test.go b/vendor/github.com/gregjones/httpcache/httpcache_test.go new file mode 100644 index 000000000..a50464180 --- /dev/null +++ b/vendor/github.com/gregjones/httpcache/httpcache_test.go @@ -0,0 +1,1475 @@ +package httpcache + +import ( + "bytes" + "errors" + "flag" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "strconv" + "testing" + "time" +) + +var s struct { + server *httptest.Server + client http.Client + transport *Transport + done chan struct{} // Closed to unlock infinite handlers. +} + +type fakeClock struct { + elapsed time.Duration +} + +func (c *fakeClock) since(t time.Time) time.Duration { + return c.elapsed +} + +func TestMain(m *testing.M) { + flag.Parse() + setup() + code := m.Run() + teardown() + os.Exit(code) +} + +func setup() { + tp := NewMemoryCacheTransport() + client := http.Client{Transport: tp} + s.transport = tp + s.client = client + s.done = make(chan struct{}) + + mux := http.NewServeMux() + s.server = httptest.NewServer(mux) + + mux.HandleFunc("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "max-age=3600") + })) + + mux.HandleFunc("/method", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "max-age=3600") + w.Write([]byte(r.Method)) + })) + + mux.HandleFunc("/range", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + lm := "Fri, 14 Dec 2010 01:01:50 GMT" + if r.Header.Get("if-modified-since") == lm { + w.WriteHeader(http.StatusNotModified) + return + } + w.Header().Set("last-modified", lm) + if r.Header.Get("range") == "bytes=4-9" { + w.WriteHeader(http.StatusPartialContent) + w.Write([]byte(" text ")) + return + } + w.Write([]byte("Some text content")) + })) + + mux.HandleFunc("/nostore", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "no-store") + })) + + mux.HandleFunc("/etag", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + etag := "124567" + if r.Header.Get("if-none-match") == etag { + w.WriteHeader(http.StatusNotModified) + return + } + w.Header().Set("etag", etag) + })) + + mux.HandleFunc("/lastmodified", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + lm := "Fri, 14 Dec 2010 01:01:50 GMT" + if r.Header.Get("if-modified-since") == lm { + w.WriteHeader(http.StatusNotModified) + return + } + w.Header().Set("last-modified", lm) + })) + + mux.HandleFunc("/varyaccept", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "max-age=3600") + w.Header().Set("Content-Type", "text/plain") + w.Header().Set("Vary", "Accept") + w.Write([]byte("Some text content")) + })) + + mux.HandleFunc("/doublevary", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "max-age=3600") + w.Header().Set("Content-Type", "text/plain") + w.Header().Set("Vary", "Accept, Accept-Language") + w.Write([]byte("Some text content")) + })) + mux.HandleFunc("/2varyheaders", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "max-age=3600") + w.Header().Set("Content-Type", "text/plain") + w.Header().Add("Vary", "Accept") + w.Header().Add("Vary", "Accept-Language") + w.Write([]byte("Some text content")) + })) + mux.HandleFunc("/varyunused", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Cache-Control", "max-age=3600") + w.Header().Set("Content-Type", "text/plain") + w.Header().Set("Vary", "X-Madeup-Header") + w.Write([]byte("Some text content")) + })) + + mux.HandleFunc("/cachederror", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + etag := "abc" + if r.Header.Get("if-none-match") == etag { + w.WriteHeader(http.StatusNotModified) + return + } + w.Header().Set("etag", etag) + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not found")) + })) + + updateFieldsCounter := 0 + mux.HandleFunc("/updatefields", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Counter", strconv.Itoa(updateFieldsCounter)) + w.Header().Set("Etag", `"e"`) + updateFieldsCounter++ + if r.Header.Get("if-none-match") != "" { + w.WriteHeader(http.StatusNotModified) + return + } + w.Write([]byte("Some text content")) + })) + + // Take 3 seconds to return 200 OK (for testing client timeouts). + mux.HandleFunc("/3seconds", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(3 * time.Second) + })) + + mux.HandleFunc("/infinite", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for { + select { + case <-s.done: + return + default: + w.Write([]byte{0}) + } + } + })) +} + +func teardown() { + close(s.done) + s.server.Close() +} + +func resetTest() { + s.transport.Cache = NewMemoryCache() + clock = &realClock{} +} + +// TestCacheableMethod ensures that uncacheable method does not get stored +// in cache and get incorrectly used for a following cacheable method request. +func TestCacheableMethod(t *testing.T) { + resetTest() + { + req, err := http.NewRequest("POST", s.server.URL+"/method", nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + _, err = io.Copy(&buf, resp.Body) + if err != nil { + t.Fatal(err) + } + err = resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := buf.String(), "POST"; got != want { + t.Errorf("got %q, want %q", got, want) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode) + } + } + { + req, err := http.NewRequest("GET", s.server.URL+"/method", nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + _, err = io.Copy(&buf, resp.Body) + if err != nil { + t.Fatal(err) + } + err = resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := buf.String(), "GET"; got != want { + t.Errorf("got wrong body %q, want %q", got, want) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode) + } + if resp.Header.Get(XFromCache) != "" { + t.Errorf("XFromCache header isn't blank") + } + } +} + +func TestDontServeHeadResponseToGetRequest(t *testing.T) { + resetTest() + url := s.server.URL + "/" + req, err := http.NewRequest(http.MethodHead, url, nil) + if err != nil { + t.Fatal(err) + } + _, err = s.client.Do(req) + if err != nil { + t.Fatal(err) + } + req, err = http.NewRequest(http.MethodGet, url, nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + if resp.Header.Get(XFromCache) != "" { + t.Errorf("Cache should not match") + } +} + +func TestDontStorePartialRangeInCache(t *testing.T) { + resetTest() + { + req, err := http.NewRequest("GET", s.server.URL+"/range", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("range", "bytes=4-9") + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + _, err = io.Copy(&buf, resp.Body) + if err != nil { + t.Fatal(err) + } + err = resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := buf.String(), " text "; got != want { + t.Errorf("got %q, want %q", got, want) + } + if resp.StatusCode != http.StatusPartialContent { + t.Errorf("response status code isn't 206 Partial Content: %v", resp.StatusCode) + } + } + { + req, err := http.NewRequest("GET", s.server.URL+"/range", nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + _, err = io.Copy(&buf, resp.Body) + if err != nil { + t.Fatal(err) + } + err = resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := buf.String(), "Some text content"; got != want { + t.Errorf("got %q, want %q", got, want) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode) + } + if resp.Header.Get(XFromCache) != "" { + t.Error("XFromCache header isn't blank") + } + } + { + req, err := http.NewRequest("GET", s.server.URL+"/range", nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + _, err = io.Copy(&buf, resp.Body) + if err != nil { + t.Fatal(err) + } + err = resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := buf.String(), "Some text content"; got != want { + t.Errorf("got %q, want %q", got, want) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("response status code isn't 200 OK: %v", resp.StatusCode) + } + if resp.Header.Get(XFromCache) != "1" { + t.Errorf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } + { + req, err := http.NewRequest("GET", s.server.URL+"/range", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("range", "bytes=4-9") + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + var buf bytes.Buffer + _, err = io.Copy(&buf, resp.Body) + if err != nil { + t.Fatal(err) + } + err = resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := buf.String(), " text "; got != want { + t.Errorf("got %q, want %q", got, want) + } + if resp.StatusCode != http.StatusPartialContent { + t.Errorf("response status code isn't 206 Partial Content: %v", resp.StatusCode) + } + } +} + +func TestCacheOnlyIfBodyRead(t *testing.T) { + resetTest() + { + req, err := http.NewRequest("GET", s.server.URL, nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + // We do not read the body + resp.Body.Close() + } + { + req, err := http.NewRequest("GET", s.server.URL, nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatalf("XFromCache header isn't blank") + } + } +} + +func TestOnlyReadBodyOnDemand(t *testing.T) { + resetTest() + + req, err := http.NewRequest("GET", s.server.URL+"/infinite", nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) // This shouldn't hang forever. + if err != nil { + t.Fatal(err) + } + buf := make([]byte, 10) // Only partially read the body. + _, err = resp.Body.Read(buf) + if err != nil { + t.Fatal(err) + } + resp.Body.Close() +} + +func TestGetOnlyIfCachedHit(t *testing.T) { + resetTest() + { + req, err := http.NewRequest("GET", s.server.URL, nil) + if err != nil { + t.Fatal(err) + } + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + req, err := http.NewRequest("GET", s.server.URL, nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("cache-control", "only-if-cached") + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + if resp.StatusCode != http.StatusOK { + t.Fatalf("response status code isn't 200 OK: %v", resp.StatusCode) + } + } +} + +func TestGetOnlyIfCachedMiss(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL, nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("cache-control", "only-if-cached") + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + if resp.StatusCode != http.StatusGatewayTimeout { + t.Fatalf("response status code isn't 504 GatewayTimeout: %v", resp.StatusCode) + } +} + +func TestGetNoStoreRequest(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL, nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("Cache-Control", "no-store") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } +} + +func TestGetNoStoreResponse(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/nostore", nil) + if err != nil { + t.Fatal(err) + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } +} + +func TestGetWithEtag(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/etag", nil) + if err != nil { + t.Fatal(err) + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + // additional assertions to verify that 304 response is converted properly + if resp.StatusCode != http.StatusOK { + t.Fatalf("response status code isn't 200 OK: %v", resp.StatusCode) + } + if _, ok := resp.Header["Connection"]; ok { + t.Fatalf("Connection header isn't absent") + } + } +} + +func TestGetWithLastModified(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/lastmodified", nil) + if err != nil { + t.Fatal(err) + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } +} + +func TestGetWithVary(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/varyaccept", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Accept", "text/plain") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get("Vary") != "Accept" { + t.Fatalf(`Vary header isn't "Accept": %v`, resp.Header.Get("Vary")) + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } + req.Header.Set("Accept", "text/html") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + req.Header.Set("Accept", "") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } +} + +func TestGetWithDoubleVary(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/doublevary", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Accept", "text/plain") + req.Header.Set("Accept-Language", "da, en-gb;q=0.8, en;q=0.7") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get("Vary") == "" { + t.Fatalf(`Vary header is blank`) + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } + req.Header.Set("Accept-Language", "") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + req.Header.Set("Accept-Language", "da") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } +} + +func TestGetWith2VaryHeaders(t *testing.T) { + resetTest() + // Tests that multiple Vary headers' comma-separated lists are + // merged. See https://github.com/gregjones/httpcache/issues/27. + const ( + accept = "text/plain" + acceptLanguage = "da, en-gb;q=0.8, en;q=0.7" + ) + req, err := http.NewRequest("GET", s.server.URL+"/2varyheaders", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Accept", accept) + req.Header.Set("Accept-Language", acceptLanguage) + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get("Vary") == "" { + t.Fatalf(`Vary header is blank`) + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } + req.Header.Set("Accept-Language", "") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + req.Header.Set("Accept-Language", "da") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + req.Header.Set("Accept-Language", acceptLanguage) + req.Header.Set("Accept", "") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + } + req.Header.Set("Accept", "image/png") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "" { + t.Fatal("XFromCache header isn't blank") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } +} + +func TestGetVaryUnused(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/varyunused", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Accept", "text/plain") + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get("Vary") == "" { + t.Fatalf(`Vary header is blank`) + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + } +} + +func TestUpdateFields(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/updatefields", nil) + if err != nil { + t.Fatal(err) + } + var counter, counter2 string + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + counter = resp.Header.Get("x-counter") + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.Header.Get(XFromCache) != "1" { + t.Fatalf(`XFromCache header isn't "1": %v`, resp.Header.Get(XFromCache)) + } + counter2 = resp.Header.Get("x-counter") + } + if counter == counter2 { + t.Fatalf(`both "x-counter" values are equal: %v %v`, counter, counter2) + } +} + +// This tests the fix for https://github.com/gregjones/httpcache/issues/74. +// Previously, after validating a cached response, its StatusCode +// was incorrectly being replaced. +func TestCachedErrorsKeepStatus(t *testing.T) { + resetTest() + req, err := http.NewRequest("GET", s.server.URL+"/cachederror", nil) + if err != nil { + t.Fatal(err) + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + io.Copy(ioutil.Discard, resp.Body) + } + { + resp, err := s.client.Do(req) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusNotFound { + t.Fatalf("Status code isn't 404: %d", resp.StatusCode) + } + } +} + +func TestParseCacheControl(t *testing.T) { + resetTest() + h := http.Header{} + for range parseCacheControl(h) { + t.Fatal("cacheControl should be empty") + } + + h.Set("cache-control", "no-cache") + { + cc := parseCacheControl(h) + if _, ok := cc["foo"]; ok { + t.Error(`Value "foo" shouldn't exist`) + } + noCache, ok := cc["no-cache"] + if !ok { + t.Fatalf(`"no-cache" value isn't set`) + } + if noCache != "" { + t.Fatalf(`"no-cache" value isn't blank: %v`, noCache) + } + } + h.Set("cache-control", "no-cache, max-age=3600") + { + cc := parseCacheControl(h) + noCache, ok := cc["no-cache"] + if !ok { + t.Fatalf(`"no-cache" value isn't set`) + } + if noCache != "" { + t.Fatalf(`"no-cache" value isn't blank: %v`, noCache) + } + if cc["max-age"] != "3600" { + t.Fatalf(`"max-age" value isn't "3600": %v`, cc["max-age"]) + } + } +} + +func TestNoCacheRequestExpiration(t *testing.T) { + resetTest() + respHeaders := http.Header{} + respHeaders.Set("Cache-Control", "max-age=7200") + + reqHeaders := http.Header{} + reqHeaders.Set("Cache-Control", "no-cache") + if getFreshness(respHeaders, reqHeaders) != transparent { + t.Fatal("freshness isn't transparent") + } +} + +func TestNoCacheResponseExpiration(t *testing.T) { + resetTest() + respHeaders := http.Header{} + respHeaders.Set("Cache-Control", "no-cache") + respHeaders.Set("Expires", "Wed, 19 Apr 3000 11:43:00 GMT") + + reqHeaders := http.Header{} + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestReqMustRevalidate(t *testing.T) { + resetTest() + // not paying attention to request setting max-stale means never returning stale + // responses, so always acting as if must-revalidate is set + respHeaders := http.Header{} + + reqHeaders := http.Header{} + reqHeaders.Set("Cache-Control", "must-revalidate") + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestRespMustRevalidate(t *testing.T) { + resetTest() + respHeaders := http.Header{} + respHeaders.Set("Cache-Control", "must-revalidate") + + reqHeaders := http.Header{} + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestFreshExpiration(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("expires", now.Add(time.Duration(2)*time.Second).Format(time.RFC1123)) + + reqHeaders := http.Header{} + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } + + clock = &fakeClock{elapsed: 3 * time.Second} + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestMaxAge(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("cache-control", "max-age=2") + + reqHeaders := http.Header{} + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } + + clock = &fakeClock{elapsed: 3 * time.Second} + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestMaxAgeZero(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("cache-control", "max-age=0") + + reqHeaders := http.Header{} + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestBothMaxAge(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("cache-control", "max-age=2") + + reqHeaders := http.Header{} + reqHeaders.Set("cache-control", "max-age=0") + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestMinFreshWithExpires(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("expires", now.Add(time.Duration(2)*time.Second).Format(time.RFC1123)) + + reqHeaders := http.Header{} + reqHeaders.Set("cache-control", "min-fresh=1") + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } + + reqHeaders = http.Header{} + reqHeaders.Set("cache-control", "min-fresh=2") + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func TestEmptyMaxStale(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("cache-control", "max-age=20") + + reqHeaders := http.Header{} + reqHeaders.Set("cache-control", "max-stale") + clock = &fakeClock{elapsed: 10 * time.Second} + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } + + clock = &fakeClock{elapsed: 60 * time.Second} + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } +} + +func TestMaxStaleValue(t *testing.T) { + resetTest() + now := time.Now() + respHeaders := http.Header{} + respHeaders.Set("date", now.Format(time.RFC1123)) + respHeaders.Set("cache-control", "max-age=10") + + reqHeaders := http.Header{} + reqHeaders.Set("cache-control", "max-stale=20") + clock = &fakeClock{elapsed: 5 * time.Second} + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } + + clock = &fakeClock{elapsed: 15 * time.Second} + if getFreshness(respHeaders, reqHeaders) != fresh { + t.Fatal("freshness isn't fresh") + } + + clock = &fakeClock{elapsed: 30 * time.Second} + if getFreshness(respHeaders, reqHeaders) != stale { + t.Fatal("freshness isn't stale") + } +} + +func containsHeader(headers []string, header string) bool { + for _, v := range headers { + if http.CanonicalHeaderKey(v) == http.CanonicalHeaderKey(header) { + return true + } + } + return false +} + +func TestGetEndToEndHeaders(t *testing.T) { + resetTest() + var ( + headers http.Header + end2end []string + ) + + headers = http.Header{} + headers.Set("content-type", "text/html") + headers.Set("te", "deflate") + + end2end = getEndToEndHeaders(headers) + if !containsHeader(end2end, "content-type") { + t.Fatal(`doesn't contain "content-type" header`) + } + if containsHeader(end2end, "te") { + t.Fatal(`doesn't contain "te" header`) + } + + headers = http.Header{} + headers.Set("connection", "content-type") + headers.Set("content-type", "text/csv") + headers.Set("te", "deflate") + end2end = getEndToEndHeaders(headers) + if containsHeader(end2end, "connection") { + t.Fatal(`doesn't contain "connection" header`) + } + if containsHeader(end2end, "content-type") { + t.Fatal(`doesn't contain "content-type" header`) + } + if containsHeader(end2end, "te") { + t.Fatal(`doesn't contain "te" header`) + } + + headers = http.Header{} + end2end = getEndToEndHeaders(headers) + if len(end2end) != 0 { + t.Fatal(`non-zero end2end headers`) + } + + headers = http.Header{} + headers.Set("connection", "content-type") + end2end = getEndToEndHeaders(headers) + if len(end2end) != 0 { + t.Fatal(`non-zero end2end headers`) + } +} + +type transportMock struct { + response *http.Response + err error +} + +func (t transportMock) RoundTrip(req *http.Request) (resp *http.Response, err error) { + return t.response, t.err +} + +func TestStaleIfErrorRequest(t *testing.T) { + resetTest() + now := time.Now() + tmock := transportMock{ + response: &http.Response{ + Status: http.StatusText(http.StatusOK), + StatusCode: http.StatusOK, + Header: http.Header{ + "Date": []string{now.Format(time.RFC1123)}, + "Cache-Control": []string{"no-cache"}, + }, + Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))), + }, + err: nil, + } + tp := NewMemoryCacheTransport() + tp.Transport = &tmock + + // First time, response is cached on success + r, _ := http.NewRequest("GET", "http://somewhere.com/", nil) + r.Header.Set("Cache-Control", "stale-if-error") + resp, err := tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + // On failure, response is returned from the cache + tmock.response = nil + tmock.err = errors.New("some error") + resp, err = tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } +} + +func TestStaleIfErrorRequestLifetime(t *testing.T) { + resetTest() + now := time.Now() + tmock := transportMock{ + response: &http.Response{ + Status: http.StatusText(http.StatusOK), + StatusCode: http.StatusOK, + Header: http.Header{ + "Date": []string{now.Format(time.RFC1123)}, + "Cache-Control": []string{"no-cache"}, + }, + Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))), + }, + err: nil, + } + tp := NewMemoryCacheTransport() + tp.Transport = &tmock + + // First time, response is cached on success + r, _ := http.NewRequest("GET", "http://somewhere.com/", nil) + r.Header.Set("Cache-Control", "stale-if-error=100") + resp, err := tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + // On failure, response is returned from the cache + tmock.response = nil + tmock.err = errors.New("some error") + resp, err = tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + + // Same for http errors + tmock.response = &http.Response{StatusCode: http.StatusInternalServerError} + tmock.err = nil + resp, err = tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + + // If failure last more than max stale, error is returned + clock = &fakeClock{elapsed: 200 * time.Second} + _, err = tp.RoundTrip(r) + if err != tmock.err { + t.Fatalf("got err %v, want %v", err, tmock.err) + } +} + +func TestStaleIfErrorResponse(t *testing.T) { + resetTest() + now := time.Now() + tmock := transportMock{ + response: &http.Response{ + Status: http.StatusText(http.StatusOK), + StatusCode: http.StatusOK, + Header: http.Header{ + "Date": []string{now.Format(time.RFC1123)}, + "Cache-Control": []string{"no-cache, stale-if-error"}, + }, + Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))), + }, + err: nil, + } + tp := NewMemoryCacheTransport() + tp.Transport = &tmock + + // First time, response is cached on success + r, _ := http.NewRequest("GET", "http://somewhere.com/", nil) + resp, err := tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + // On failure, response is returned from the cache + tmock.response = nil + tmock.err = errors.New("some error") + resp, err = tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } +} + +func TestStaleIfErrorResponseLifetime(t *testing.T) { + resetTest() + now := time.Now() + tmock := transportMock{ + response: &http.Response{ + Status: http.StatusText(http.StatusOK), + StatusCode: http.StatusOK, + Header: http.Header{ + "Date": []string{now.Format(time.RFC1123)}, + "Cache-Control": []string{"no-cache, stale-if-error=100"}, + }, + Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))), + }, + err: nil, + } + tp := NewMemoryCacheTransport() + tp.Transport = &tmock + + // First time, response is cached on success + r, _ := http.NewRequest("GET", "http://somewhere.com/", nil) + resp, err := tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + // On failure, response is returned from the cache + tmock.response = nil + tmock.err = errors.New("some error") + resp, err = tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + + // If failure last more than max stale, error is returned + clock = &fakeClock{elapsed: 200 * time.Second} + _, err = tp.RoundTrip(r) + if err != tmock.err { + t.Fatalf("got err %v, want %v", err, tmock.err) + } +} + +// This tests the fix for https://github.com/gregjones/httpcache/issues/74. +// Previously, after a stale response was used after encountering an error, +// its StatusCode was being incorrectly replaced. +func TestStaleIfErrorKeepsStatus(t *testing.T) { + resetTest() + now := time.Now() + tmock := transportMock{ + response: &http.Response{ + Status: http.StatusText(http.StatusNotFound), + StatusCode: http.StatusNotFound, + Header: http.Header{ + "Date": []string{now.Format(time.RFC1123)}, + "Cache-Control": []string{"no-cache"}, + }, + Body: ioutil.NopCloser(bytes.NewBuffer([]byte("some data"))), + }, + err: nil, + } + tp := NewMemoryCacheTransport() + tp.Transport = &tmock + + // First time, response is cached on success + r, _ := http.NewRequest("GET", "http://somewhere.com/", nil) + r.Header.Set("Cache-Control", "stale-if-error") + resp, err := tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + _, err = ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + // On failure, response is returned from the cache + tmock.response = nil + tmock.err = errors.New("some error") + resp, err = tp.RoundTrip(r) + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("resp is nil") + } + if resp.StatusCode != http.StatusNotFound { + t.Fatalf("Status wasn't 404: %d", resp.StatusCode) + } +} + +// Test that http.Client.Timeout is respected when cache transport is used. +// That is so as long as request cancellation is propagated correctly. +// In the past, that required CancelRequest to be implemented correctly, +// but modern http.Client uses Request.Cancel (or request context) instead, +// so we don't have to do anything. +func TestClientTimeout(t *testing.T) { + if testing.Short() { + t.Skip("skipping timeout test in short mode") // Because it takes at least 3 seconds to run. + } + resetTest() + client := &http.Client{ + Transport: NewMemoryCacheTransport(), + Timeout: time.Second, + } + started := time.Now() + resp, err := client.Get(s.server.URL + "/3seconds") + taken := time.Since(started) + if err == nil { + t.Error("got nil error, want timeout error") + } + if resp != nil { + t.Error("got non-nil resp, want nil resp") + } + if taken >= 2*time.Second { + t.Error("client.Do took 2+ seconds, want < 2 seconds") + } +} diff --git a/vendor/github.com/hashicorp/golang-lru/.gitignore b/vendor/github.com/hashicorp/golang-lru/.gitignore new file mode 100644 index 000000000..836562412 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/vendor/github.com/hashicorp/golang-lru/2q_test.go b/vendor/github.com/hashicorp/golang-lru/2q_test.go new file mode 100644 index 000000000..1b0f35181 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/2q_test.go @@ -0,0 +1,306 @@ +package lru + +import ( + "math/rand" + "testing" +) + +func Benchmark2Q_Rand(b *testing.B) { + l, err := New2Q(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + trace[i] = rand.Int63() % 32768 + } + + b.ResetTimer() + + var hit, miss int + for i := 0; i < 2*b.N; i++ { + if i%2 == 0 { + l.Add(trace[i], trace[i]) + } else { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func Benchmark2Q_Freq(b *testing.B) { + l, err := New2Q(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + if i%2 == 0 { + trace[i] = rand.Int63() % 16384 + } else { + trace[i] = rand.Int63() % 32768 + } + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + l.Add(trace[i], trace[i]) + } + var hit, miss int + for i := 0; i < b.N; i++ { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func Test2Q_RandomOps(t *testing.T) { + size := 128 + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + n := 200000 + for i := 0; i < n; i++ { + key := rand.Int63() % 512 + r := rand.Int63() + switch r % 3 { + case 0: + l.Add(key, key) + case 1: + l.Get(key) + case 2: + l.Remove(key) + } + + if l.recent.Len()+l.frequent.Len() > size { + t.Fatalf("bad: recent: %d freq: %d", + l.recent.Len(), l.frequent.Len()) + } + } +} + +func Test2Q_Get_RecentToFrequent(t *testing.T) { + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Touch all the entries, should be in t1 + for i := 0; i < 128; i++ { + l.Add(i, i) + } + if n := l.recent.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Get should upgrade to t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + + // Get be from t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } +} + +func Test2Q_Add_RecentToFrequent(t *testing.T) { + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Add initially to recent + l.Add(1, 1) + if n := l.recent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Add should upgrade to frequent + l.Add(1, 1) + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Add should remain in frequent + l.Add(1, 1) + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } +} + +func Test2Q_Add_RecentEvict(t *testing.T) { + l, err := New2Q(4) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Add 1,2,3,4,5 -> Evict 1 + l.Add(1, 1) + l.Add(2, 2) + l.Add(3, 3) + l.Add(4, 4) + l.Add(5, 5) + if n := l.recent.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + if n := l.recentEvict.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Pull in the recently evicted + l.Add(1, 1) + if n := l.recent.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + if n := l.recentEvict.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Add 6, should cause another recent evict + l.Add(6, 6) + if n := l.recent.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + if n := l.recentEvict.Len(); n != 2 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } +} + +func Test2Q(t *testing.T) { + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// Test that Contains doesn't update recent-ness +func Test2Q_Contains(t *testing.T) { + l, err := New2Q(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// Test that Peek doesn't update recent-ness +func Test2Q_Peek(t *testing.T) { + l, err := New2Q(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/vendor/github.com/hashicorp/golang-lru/README.md b/vendor/github.com/hashicorp/golang-lru/README.md new file mode 100644 index 000000000..33e58cfaf --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/README.md @@ -0,0 +1,25 @@ +golang-lru +========== + +This provides the `lru` package which implements a fixed-size +thread safe LRU cache. It is based on the cache in Groupcache. + +Documentation +============= + +Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru) + +Example +======= + +Using the LRU is very simple: + +```go +l, _ := New(128) +for i := 0; i < 256; i++ { + l.Add(i, nil) +} +if l.Len() != 128 { + panic(fmt.Sprintf("bad len: %v", l.Len())) +} +``` diff --git a/vendor/github.com/hashicorp/golang-lru/arc_test.go b/vendor/github.com/hashicorp/golang-lru/arc_test.go new file mode 100644 index 000000000..e2d9b68c6 --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/arc_test.go @@ -0,0 +1,377 @@ +package lru + +import ( + "math/rand" + "testing" + "time" +) + +func init() { + rand.Seed(time.Now().Unix()) +} + +func BenchmarkARC_Rand(b *testing.B) { + l, err := NewARC(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + trace[i] = rand.Int63() % 32768 + } + + b.ResetTimer() + + var hit, miss int + for i := 0; i < 2*b.N; i++ { + if i%2 == 0 { + l.Add(trace[i], trace[i]) + } else { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func BenchmarkARC_Freq(b *testing.B) { + l, err := NewARC(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + if i%2 == 0 { + trace[i] = rand.Int63() % 16384 + } else { + trace[i] = rand.Int63() % 32768 + } + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + l.Add(trace[i], trace[i]) + } + var hit, miss int + for i := 0; i < b.N; i++ { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func TestARC_RandomOps(t *testing.T) { + size := 128 + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + n := 200000 + for i := 0; i < n; i++ { + key := rand.Int63() % 512 + r := rand.Int63() + switch r % 3 { + case 0: + l.Add(key, key) + case 1: + l.Get(key) + case 2: + l.Remove(key) + } + + if l.t1.Len()+l.t2.Len() > size { + t.Fatalf("bad: t1: %d t2: %d b1: %d b2: %d p: %d", + l.t1.Len(), l.t2.Len(), l.b1.Len(), l.b2.Len(), l.p) + } + if l.b1.Len()+l.b2.Len() > size { + t.Fatalf("bad: t1: %d t2: %d b1: %d b2: %d p: %d", + l.t1.Len(), l.t2.Len(), l.b1.Len(), l.b2.Len(), l.p) + } + } +} + +func TestARC_Get_RecentToFrequent(t *testing.T) { + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Touch all the entries, should be in t1 + for i := 0; i < 128; i++ { + l.Add(i, i) + } + if n := l.t1.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Get should upgrade to t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + + // Get be from t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } +} + +func TestARC_Add_RecentToFrequent(t *testing.T) { + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Add initially to t1 + l.Add(1, 1) + if n := l.t1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Add should upgrade to t2 + l.Add(1, 1) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Add should remain in t2 + l.Add(1, 1) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } +} + +func TestARC_Adaptive(t *testing.T) { + l, err := NewARC(4) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Fill t1 + for i := 0; i < 4; i++ { + l.Add(i, i) + } + if n := l.t1.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + + // Move to t2 + l.Get(0) + l.Get(1) + if n := l.t2.Len(); n != 2 { + t.Fatalf("bad: %d", n) + } + + // Evict from t1 + l.Add(4, 4) + if n := l.b1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [4, 3] (LRU) + // t2 : (MRU) [1, 0] (LRU) + // b1 : (MRU) [2] (LRU) + // b2 : (MRU) [] (LRU) + + // Add 2, should cause hit on b1 + l.Add(2, 2) + if n := l.b1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if l.p != 1 { + t.Fatalf("bad: %d", l.p) + } + if n := l.t2.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [4] (LRU) + // t2 : (MRU) [2, 1, 0] (LRU) + // b1 : (MRU) [3] (LRU) + // b2 : (MRU) [] (LRU) + + // Add 4, should migrate to t2 + l.Add(4, 4) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [] (LRU) + // t2 : (MRU) [4, 2, 1, 0] (LRU) + // b1 : (MRU) [3] (LRU) + // b2 : (MRU) [] (LRU) + + // Add 4, should evict to b2 + l.Add(5, 5) + if n := l.t1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + if n := l.b2.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [5] (LRU) + // t2 : (MRU) [4, 2, 1] (LRU) + // b1 : (MRU) [3] (LRU) + // b2 : (MRU) [0] (LRU) + + // Add 0, should decrease p + l.Add(0, 0) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + if n := l.b1.Len(); n != 2 { + t.Fatalf("bad: %d", n) + } + if n := l.b2.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if l.p != 0 { + t.Fatalf("bad: %d", l.p) + } + + // Current state + // t1 : (MRU) [] (LRU) + // t2 : (MRU) [0, 4, 2, 1] (LRU) + // b1 : (MRU) [5, 3] (LRU) + // b2 : (MRU) [0] (LRU) +} + +func TestARC(t *testing.T) { + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// Test that Contains doesn't update recent-ness +func TestARC_Contains(t *testing.T) { + l, err := NewARC(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// Test that Peek doesn't update recent-ness +func TestARC_Peek(t *testing.T) { + l, err := NewARC(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/vendor/github.com/hashicorp/golang-lru/lru_test.go b/vendor/github.com/hashicorp/golang-lru/lru_test.go new file mode 100644 index 000000000..e7e23505e --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/lru_test.go @@ -0,0 +1,221 @@ +package lru + +import ( + "math/rand" + "testing" +) + +func BenchmarkLRU_Rand(b *testing.B) { + l, err := New(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + trace[i] = rand.Int63() % 32768 + } + + b.ResetTimer() + + var hit, miss int + for i := 0; i < 2*b.N; i++ { + if i%2 == 0 { + l.Add(trace[i], trace[i]) + } else { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func BenchmarkLRU_Freq(b *testing.B) { + l, err := New(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + if i%2 == 0 { + trace[i] = rand.Int63() % 16384 + } else { + trace[i] = rand.Int63() % 32768 + } + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + l.Add(trace[i], trace[i]) + } + var hit, miss int + for i := 0; i < b.N; i++ { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func TestLRU(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + if k != v { + t.Fatalf("Evict values not equal (%v!=%v)", k, v) + } + evictCounter++ + } + l, err := NewWithEvict(128, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + if evictCounter != 128 { + t.Fatalf("bad evict count: %v", evictCounter) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Get(192) // expect 192 to be last key in l.Keys() + + for i, k := range l.Keys() { + if (i < 63 && k != i+193) || (i == 63 && k != 192) { + t.Fatalf("out of order key: %v", k) + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// test that Add returns true/false if an eviction occurred +func TestLRUAdd(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + evictCounter++ + } + + l, err := NewWithEvict(1, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + if l.Add(1, 1) == true || evictCounter != 0 { + t.Errorf("should not have an eviction") + } + if l.Add(2, 2) == false || evictCounter != 1 { + t.Errorf("should have an eviction") + } +} + +// test that Contains doesn't update recent-ness +func TestLRUContains(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// test that Contains doesn't update recent-ness +func TestLRUContainsOrAdd(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + contains, evict := l.ContainsOrAdd(1, 1) + if !contains { + t.Errorf("1 should be contained") + } + if evict { + t.Errorf("nothing should be evicted here") + } + + l.Add(3, 3) + contains, evict = l.ContainsOrAdd(1, 1) + if contains { + t.Errorf("1 should not have been contained") + } + if !evict { + t.Errorf("an eviction should have occurred") + } + if !l.Contains(1) { + t.Errorf("now 1 should be contained") + } +} + +// test that Peek doesn't update recent-ness +func TestLRUPeek(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_test.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_test.go new file mode 100644 index 000000000..ca5676e1e --- /dev/null +++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_test.go @@ -0,0 +1,167 @@ +package simplelru + +import "testing" + +func TestLRU(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + if k != v { + t.Fatalf("Evict values not equal (%v!=%v)", k, v) + } + evictCounter++ + } + l, err := NewLRU(128, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + if evictCounter != 128 { + t.Fatalf("bad evict count: %v", evictCounter) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + ok := l.Remove(i) + if !ok { + t.Fatalf("should be contained") + } + ok = l.Remove(i) + if ok { + t.Fatalf("should not be contained") + } + _, ok = l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Get(192) // expect 192 to be last key in l.Keys() + + for i, k := range l.Keys() { + if (i < 63 && k != i+193) || (i == 63 && k != 192) { + t.Fatalf("out of order key: %v", k) + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +func TestLRU_GetOldest_RemoveOldest(t *testing.T) { + l, err := NewLRU(128, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + for i := 0; i < 256; i++ { + l.Add(i, i) + } + k, _, ok := l.GetOldest() + if !ok { + t.Fatalf("missing") + } + if k.(int) != 128 { + t.Fatalf("bad: %v", k) + } + + k, _, ok = l.RemoveOldest() + if !ok { + t.Fatalf("missing") + } + if k.(int) != 128 { + t.Fatalf("bad: %v", k) + } + + k, _, ok = l.RemoveOldest() + if !ok { + t.Fatalf("missing") + } + if k.(int) != 129 { + t.Fatalf("bad: %v", k) + } +} + +// Test that Add returns true/false if an eviction occurred +func TestLRU_Add(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + evictCounter++ + } + + l, err := NewLRU(1, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + if l.Add(1, 1) == true || evictCounter != 0 { + t.Errorf("should not have an eviction") + } + if l.Add(2, 2) == false || evictCounter != 1 { + t.Errorf("should have an eviction") + } +} + +// Test that Contains doesn't update recent-ness +func TestLRU_Contains(t *testing.T) { + l, err := NewLRU(2, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// Test that Peek doesn't update recent-ness +func TestLRU_Peek(t *testing.T) { + l, err := NewLRU(2, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/github.com/imdario/mergo/.gitignore new file mode 100644 index 000000000..529c3412b --- /dev/null +++ b/vendor/github.com/imdario/mergo/.gitignore @@ -0,0 +1,33 @@ +#### joe made this: http://goel.io/joe + +#### go #### +# 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 + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +#### vim #### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/github.com/imdario/mergo/.travis.yml new file mode 100644 index 000000000..b13a50ed1 --- /dev/null +++ b/vendor/github.com/imdario/mergo/.travis.yml @@ -0,0 +1,7 @@ +language: go +install: + - go get -t + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls +script: + - $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..469b44907 --- /dev/null +++ b/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md new file mode 100644 index 000000000..d1cefa871 --- /dev/null +++ b/vendor/github.com/imdario/mergo/README.md @@ -0,0 +1,222 @@ +# Mergo + +A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements. + +Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche. + +## Status + +It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild). + +[![GoDoc][3]][4] +[![GoCard][5]][6] +[![Build Status][1]][2] +[![Coverage Status][7]][8] +[![Sourcegraph][9]][10] + +[1]: https://travis-ci.org/imdario/mergo.png +[2]: https://travis-ci.org/imdario/mergo +[3]: https://godoc.org/github.com/imdario/mergo?status.svg +[4]: https://godoc.org/github.com/imdario/mergo +[5]: https://goreportcard.com/badge/imdario/mergo +[6]: https://goreportcard.com/report/github.com/imdario/mergo +[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master +[8]: https://coveralls.io/github/imdario/mergo?branch=master +[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg +[10]: https://sourcegraph.com/github.com/imdario/mergo?badge + +### Latest release + +[Release v0.3.4](https://github.com/imdario/mergo/releases/tag/v0.3.4). + +### Important note + +Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code. + +If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0). + +### Donations + +If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes: + +Buy Me a Coffee at ko-fi.com +[![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo) +[![Beerpay](https://beerpay.io/imdario/mergo/make-wish.svg)](https://beerpay.io/imdario/mergo) +Donate using Liberapay + +### Mergo in the wild + +- [moby/moby](https://github.com/moby/moby) +- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) +- [vmware/dispatch](https://github.com/vmware/dispatch) +- [Shopify/themekit](https://github.com/Shopify/themekit) +- [imdario/zas](https://github.com/imdario/zas) +- [matcornic/hermes](https://github.com/matcornic/hermes) +- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go) +- [kataras/iris](https://github.com/kataras/iris) +- [michaelsauter/crane](https://github.com/michaelsauter/crane) +- [go-task/task](https://github.com/go-task/task) +- [sensu/uchiwa](https://github.com/sensu/uchiwa) +- [ory/hydra](https://github.com/ory/hydra) +- [sisatech/vcli](https://github.com/sisatech/vcli) +- [dairycart/dairycart](https://github.com/dairycart/dairycart) +- [projectcalico/felix](https://github.com/projectcalico/felix) +- [resin-os/balena](https://github.com/resin-os/balena) +- [go-kivik/kivik](https://github.com/go-kivik/kivik) +- [Telefonica/govice](https://github.com/Telefonica/govice) +- [supergiant/supergiant](supergiant/supergiant) +- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce) +- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy) +- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel) +- [EagerIO/Stout](https://github.com/EagerIO/Stout) +- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api) +- [russross/canvasassignments](https://github.com/russross/canvasassignments) +- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api) +- [casualjim/exeggutor](https://github.com/casualjim/exeggutor) +- [divshot/gitling](https://github.com/divshot/gitling) +- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl) +- [andrerocker/deploy42](https://github.com/andrerocker/deploy42) +- [elwinar/rambler](https://github.com/elwinar/rambler) +- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman) +- [jfbus/impressionist](https://github.com/jfbus/impressionist) +- [Jmeyering/zealot](https://github.com/Jmeyering/zealot) +- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host) +- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go) +- [thoas/picfit](https://github.com/thoas/picfit) +- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server) +- [jnuthong/item_search](https://github.com/jnuthong/item_search) +- [bukalapak/snowboard](https://github.com/bukalapak/snowboard) + +## Installation + + go get github.com/imdario/mergo + + // use in your .go code + import ( + "github.com/imdario/mergo" + ) + +## Usage + +You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection). + +```go +if err := mergo.Merge(&dst, src); err != nil { + // ... +} +``` + +Also, you can merge overwriting values using the transformer `WithOverride`. + +```go +if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil { + // ... +} +``` + +Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field. + +```go +if err := mergo.Map(&dst, srcMap); err != nil { + // ... +} +``` + +Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values. + +More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo). + +### Nice example + +```go +package main + +import ( + "fmt" + "github.com/imdario/mergo" +) + +type Foo struct { + A string + B int64 +} + +func main() { + src := Foo{ + A: "one", + B: 2, + } + dest := Foo{ + A: "two", + } + mergo.Merge(&dest, src) + fmt.Println(dest) + // Will print + // {two 2} +} +``` + +Note: if test are failing due missing package, please execute: + + go get gopkg.in/yaml.v2 + +### Transformers + +Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`? + +```go +package main + +import ( + "fmt" + "github.com/imdario/mergo" + "reflect" + "time" +) + +type timeTransfomer struct { +} + +func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ == reflect.TypeOf(time.Time{}) { + return func(dst, src reflect.Value) error { + if dst.CanSet() { + isZero := dst.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if result[0].Bool() { + dst.Set(src) + } + } + return nil + } + } + return nil +} + +type Snapshot struct { + Time time.Time + // ... +} + +func main() { + src := Snapshot{time.Now()} + dest := Snapshot{} + mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{})) + fmt.Println(dest) + // Will print + // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 } +} +``` + + +## Contact me + +If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario) + +## About + +Written by [Dario Castañé](http://dario.im). + +## License + +[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE). diff --git a/vendor/github.com/imdario/mergo/issue17_test.go b/vendor/github.com/imdario/mergo/issue17_test.go new file mode 100644 index 000000000..f9de805ab --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue17_test.go @@ -0,0 +1,25 @@ +package mergo + +import ( + "encoding/json" + "testing" +) + +var ( + request = `{"timestamp":null, "name": "foo"}` + maprequest = map[string]interface{}{ + "timestamp": nil, + "name": "foo", + "newStuff": "foo", + } +) + +func TestIssue17MergeWithOverwrite(t *testing.T) { + var something map[string]interface{} + if err := json.Unmarshal([]byte(request), &something); err != nil { + t.Errorf("Error while Unmarshalling maprequest: %s", err) + } + if err := MergeWithOverwrite(&something, maprequest); err != nil { + t.Errorf("Error while merging: %s", err) + } +} diff --git a/vendor/github.com/imdario/mergo/issue23_test.go b/vendor/github.com/imdario/mergo/issue23_test.go new file mode 100644 index 000000000..283f8c6a3 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue23_test.go @@ -0,0 +1,27 @@ +package mergo + +import ( + "testing" + "time" +) + +type document struct { + Created *time.Time +} + +func TestIssue23MergeWithOverwrite(t *testing.T) { + now := time.Now() + dst := document{ + &now, + } + expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) + src := document{ + &expected, + } + if err := MergeWithOverwrite(&dst, src); err != nil { + t.Errorf("Error while merging %s", err) + } + if !dst.Created.Equal(*src.Created) { //--> https://golang.org/pkg/time/#pkg-overview + t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created) + } +} diff --git a/vendor/github.com/imdario/mergo/issue33_test.go b/vendor/github.com/imdario/mergo/issue33_test.go new file mode 100644 index 000000000..ae55ae236 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue33_test.go @@ -0,0 +1,33 @@ +package mergo + +import ( + "testing" +) + +type Foo struct { + Str string + Bslice []byte +} + +func TestIssue33Merge(t *testing.T) { + dest := Foo{Str: "a"} + toMerge := Foo{ + Str: "b", + Bslice: []byte{1, 2}, + } + if err := Merge(&dest, toMerge); err != nil { + t.Errorf("Error while merging: %s", err) + } + // Merge doesn't overwrite an attribute if in destination it doesn't have a zero value. + // In this case, Str isn't a zero value string. + if dest.Str != "a" { + t.Errorf("dest.Str should have not been override as it has a non-zero value: dest.Str(%v) != 'a'", dest.Str) + } + // If we want to override, we must use MergeWithOverwrite or Merge using WithOverride. + if err := Merge(&dest, toMerge, WithOverride); err != nil { + t.Errorf("Error while merging: %s", err) + } + if dest.Str != toMerge.Str { + t.Errorf("dest.Str should have been override: dest.Str(%v) != toMerge.Str(%v)", dest.Str, toMerge.Str) + } +} diff --git a/vendor/github.com/imdario/mergo/issue38_test.go b/vendor/github.com/imdario/mergo/issue38_test.go new file mode 100644 index 000000000..286b68cb1 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue38_test.go @@ -0,0 +1,59 @@ +package mergo + +import ( + "testing" + "time" +) + +type structWithoutTimePointer struct { + Created time.Time +} + +func TestIssue38Merge(t *testing.T) { + dst := structWithoutTimePointer{ + time.Now(), + } + + expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) + src := structWithoutTimePointer{ + expected, + } + if err := Merge(&dst, src); err != nil { + t.Errorf("Error while merging %s", err) + } + if dst.Created == src.Created { + t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created) + } +} + +func TestIssue38MergeEmptyStruct(t *testing.T) { + dst := structWithoutTimePointer{} + + expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) + src := structWithoutTimePointer{ + expected, + } + if err := Merge(&dst, src); err != nil { + t.Errorf("Error while merging %s", err) + } + if dst.Created == src.Created { + t.Fatalf("Created merged unexpectedly: dst.Created(%v) == src.Created(%v)", dst.Created, src.Created) + } +} + +func TestIssue38MergeWithOverwrite(t *testing.T) { + dst := structWithoutTimePointer{ + time.Now(), + } + + expected := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) + src := structWithoutTimePointer{ + expected, + } + if err := MergeWithOverwrite(&dst, src); err != nil { + t.Errorf("Error while merging %s", err) + } + if dst.Created != src.Created { + t.Fatalf("Created not merged in properly: dst.Created(%v) != src.Created(%v)", dst.Created, src.Created) + } +} diff --git a/vendor/github.com/imdario/mergo/issue50_test.go b/vendor/github.com/imdario/mergo/issue50_test.go new file mode 100644 index 000000000..89aa36345 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue50_test.go @@ -0,0 +1,18 @@ +package mergo + +import ( + "testing" + "time" +) + +type testStruct struct { + time.Duration +} + +func TestIssue50Merge(t *testing.T) { + to := testStruct{} + from := testStruct{} + if err := Merge(&to, from); err != nil { + t.Fail() + } +} diff --git a/vendor/github.com/imdario/mergo/issue52_test.go b/vendor/github.com/imdario/mergo/issue52_test.go new file mode 100644 index 000000000..62cd9fa7c --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue52_test.go @@ -0,0 +1,99 @@ +package mergo + +import ( + "reflect" + "testing" + "time" +) + +type structWithTime struct { + Birth time.Time +} + +type timeTransfomer struct { + overwrite bool +} + +func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ == reflect.TypeOf(time.Time{}) { + return func(dst, src reflect.Value) error { + if dst.CanSet() { + if t.overwrite { + isZero := src.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if !result[0].Bool() { + dst.Set(src) + } + } else { + isZero := dst.MethodByName("IsZero") + result := isZero.Call([]reflect.Value{}) + if result[0].Bool() { + dst.Set(src) + } + } + } + return nil + } + } + return nil +} + +func TestOverwriteZeroSrcTime(t *testing.T) { + now := time.Now() + dst := structWithTime{now} + src := structWithTime{} + if err := MergeWithOverwrite(&dst, src); err != nil { + t.FailNow() + } + if !dst.Birth.IsZero() { + t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now) + } +} + +func TestOverwriteZeroSrcTimeWithTransformer(t *testing.T) { + now := time.Now() + dst := structWithTime{now} + src := structWithTime{} + if err := MergeWithOverwrite(&dst, src, WithTransformers(timeTransfomer{true})); err != nil { + t.FailNow() + } + if dst.Birth.IsZero() { + t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now) + } +} + +func TestOverwriteZeroDstTime(t *testing.T) { + now := time.Now() + dst := structWithTime{} + src := structWithTime{now} + if err := MergeWithOverwrite(&dst, src); err != nil { + t.FailNow() + } + if dst.Birth.IsZero() { + t.Fatalf("dst should have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{}) + } +} + +func TestZeroDstTime(t *testing.T) { + now := time.Now() + dst := structWithTime{} + src := structWithTime{now} + if err := Merge(&dst, src); err != nil { + t.FailNow() + } + if !dst.Birth.IsZero() { + t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{}) + } +} + +func TestZeroDstTimeWithTransformer(t *testing.T) { + now := time.Now() + dst := structWithTime{} + src := structWithTime{now} + if err := Merge(&dst, src, WithTransformers(timeTransfomer{})); err != nil { + t.FailNow() + } + if dst.Birth.IsZero() { + t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now) + } +} diff --git a/vendor/github.com/imdario/mergo/issue61_test.go b/vendor/github.com/imdario/mergo/issue61_test.go new file mode 100644 index 000000000..8efa5e457 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue61_test.go @@ -0,0 +1,20 @@ +package mergo + +import ( + "reflect" + "testing" +) + +func TestIssue61MergeNilMap(t *testing.T) { + type T struct { + I map[string][]string + } + t1 := T{} + t2 := T{I: map[string][]string{"hi": {"there"}}} + if err := Merge(&t1, t2); err != nil { + t.Fail() + } + if !reflect.DeepEqual(t2, T{I: map[string][]string{"hi": {"there"}}}) { + t.FailNow() + } +} diff --git a/vendor/github.com/imdario/mergo/issue64_test.go b/vendor/github.com/imdario/mergo/issue64_test.go new file mode 100644 index 000000000..32382bef1 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue64_test.go @@ -0,0 +1,38 @@ +package mergo + +import ( + "testing" +) + +type Student struct { + Name string + Books []string +} + +var testData = []struct { + S1 Student + S2 Student + ExpectedSlice []string +}{ + {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{"1"}}, []string{"a", "B"}}, + {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{}}, []string{"a", "B"}}, + {Student{"Jack", []string{}}, Student{"Tom", []string{"1"}}, []string{"1"}}, + {Student{"Jack", []string{}}, Student{"Tom", []string{}}, []string{}}, +} + +func TestIssue64MergeSliceWithOverride(t *testing.T) { + for _, data := range testData { + err := Merge(&data.S2, data.S1, WithOverride) + if err != nil { + t.Errorf("Error while merging %s", err) + } + if len(data.S2.Books) != len(data.ExpectedSlice) { + t.Fatalf("Got %d elements in slice, but expected %d", len(data.S2.Books), len(data.ExpectedSlice)) + } + for i, val := range data.S2.Books { + if val != data.ExpectedSlice[i] { + t.Fatalf("Expected %s, but got %s while merging slice with override", data.ExpectedSlice[i], val) + } + } + } +} diff --git a/vendor/github.com/imdario/mergo/issue66_test.go b/vendor/github.com/imdario/mergo/issue66_test.go new file mode 100644 index 000000000..23fa5e271 --- /dev/null +++ b/vendor/github.com/imdario/mergo/issue66_test.go @@ -0,0 +1,29 @@ +package mergo + +import ( + "testing" +) + +type PrivateSliceTest66 struct { + PublicStrings []string + privateStrings []string +} + +func TestPrivateSlice(t *testing.T) { + p1 := PrivateSliceTest66{ + PublicStrings: []string{"one", "two", "three"}, + privateStrings: []string{"four", "five"}, + } + p2 := PrivateSliceTest66{ + PublicStrings: []string{"six", "seven"}, + } + if err := Merge(&p1, p2); err != nil { + t.Fatalf("Error during the merge: %v", err) + } + if len(p1.PublicStrings) != 5 { + t.Error("5 elements should be in 'PublicStrings' field") + } + if len(p1.privateStrings) != 2 { + t.Error("2 elements should be in 'privateStrings' field") + } +} diff --git a/vendor/github.com/imdario/mergo/merge_appendslice_test.go b/vendor/github.com/imdario/mergo/merge_appendslice_test.go new file mode 100644 index 000000000..a780f34a3 --- /dev/null +++ b/vendor/github.com/imdario/mergo/merge_appendslice_test.go @@ -0,0 +1,33 @@ +package mergo + +import ( + "testing" +) + +var testDataS = []struct { + S1 Student + S2 Student + ExpectedSlice []string +}{ + {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{"1"}}, []string{"1", "a", "B"}}, + {Student{"Jack", []string{"a", "B"}}, Student{"Tom", []string{}}, []string{"a", "B"}}, + {Student{"Jack", []string{}}, Student{"Tom", []string{"1"}}, []string{"1"}}, + {Student{"Jack", []string{}}, Student{"Tom", []string{}}, []string{}}, +} + +func TestMergeSliceWithOverrideWithAppendSlice(t *testing.T) { + for _, data := range testDataS { + err := Merge(&data.S2, data.S1, WithOverride, WithAppendSlice) + if err != nil { + t.Errorf("Error while merging %s", err) + } + if len(data.S2.Books) != len(data.ExpectedSlice) { + t.Fatalf("Got %d elements in slice, but expected %d", len(data.S2.Books), len(data.ExpectedSlice)) + } + for i, val := range data.S2.Books { + if val != data.ExpectedSlice[i] { + t.Fatalf("Expected %s, but got %s while merging slice with override", data.ExpectedSlice[i], val) + } + } + } +} diff --git a/vendor/github.com/imdario/mergo/merge_test.go b/vendor/github.com/imdario/mergo/merge_test.go new file mode 100644 index 000000000..5bf808a78 --- /dev/null +++ b/vendor/github.com/imdario/mergo/merge_test.go @@ -0,0 +1,50 @@ +package mergo + +import ( + "reflect" + "testing" +) + +type transformer struct { + m map[reflect.Type]func(dst, src reflect.Value) error +} + +func (s *transformer) Transformer(t reflect.Type) func(dst, src reflect.Value) error { + if fn, ok := s.m[t]; ok { + return fn + } + return nil +} + +type foo struct { + s string + Bar *bar +} + +type bar struct { + i int + s map[string]string +} + +func TestMergeWithTransformerNilStruct(t *testing.T) { + a := foo{s: "foo"} + b := foo{Bar: &bar{i: 2, s: map[string]string{"foo": "bar"}}} + if err := Merge(&a, &b, WithOverride, WithTransformers(&transformer{ + m: map[reflect.Type]func(dst, src reflect.Value) error{ + reflect.TypeOf(&bar{}): func(dst, src reflect.Value) error { + // Do sthg with Elem + t.Log(dst.Elem().FieldByName("i")) + t.Log(src.Elem()) + return nil + }, + }, + })); err != nil { + t.Fatal(err) + } + if a.s != "foo" { + t.Fatalf("b not merged in properly: a.s.Value(%s) != expected(%s)", a.s, "foo") + } + if a.Bar == nil { + t.Fatalf("b not merged in properly: a.Bar shouldn't be nil") + } +} diff --git a/vendor/github.com/imdario/mergo/mergo_test.go b/vendor/github.com/imdario/mergo/mergo_test.go new file mode 100644 index 000000000..854513886 --- /dev/null +++ b/vendor/github.com/imdario/mergo/mergo_test.go @@ -0,0 +1,727 @@ +// Copyright 2013 Dario Castañé. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mergo + +import ( + "gopkg.in/yaml.v2" + "io/ioutil" + "reflect" + "testing" + "time" +) + +type simpleTest struct { + Value int +} + +type complexTest struct { + St simpleTest + sz int + ID string +} + +type mapTest struct { + M map[int]int +} + +type ifcTest struct { + I interface{} +} + +type moreComplextText struct { + Ct complexTest + St simpleTest + Nt simpleTest +} + +type pointerTest struct { + C *simpleTest +} + +type sliceTest struct { + S []int +} + +func TestKb(t *testing.T) { + type testStruct struct { + Name string + KeyValue map[string]interface{} + } + + akv := make(map[string]interface{}) + akv["Key1"] = "not value 1" + akv["Key2"] = "value2" + a := testStruct{} + a.Name = "A" + a.KeyValue = akv + + bkv := make(map[string]interface{}) + bkv["Key1"] = "value1" + bkv["Key3"] = "value3" + b := testStruct{} + b.Name = "B" + b.KeyValue = bkv + + ekv := make(map[string]interface{}) + ekv["Key1"] = "value1" + ekv["Key2"] = "value2" + ekv["Key3"] = "value3" + expected := testStruct{} + expected.Name = "B" + expected.KeyValue = ekv + + Merge(&b, a) + + if !reflect.DeepEqual(b, expected) { + t.Errorf("Actual: %#v did not match \nExpected: %#v", b, expected) + } +} + +func TestNil(t *testing.T) { + if err := Merge(nil, nil); err != ErrNilArguments { + t.Fail() + } +} + +func TestDifferentTypes(t *testing.T) { + a := simpleTest{42} + b := 42 + if err := Merge(&a, b); err != ErrDifferentArgumentsTypes { + t.Fail() + } +} + +func TestSimpleStruct(t *testing.T) { + a := simpleTest{} + b := simpleTest{42} + if err := Merge(&a, b); err != nil { + t.FailNow() + } + if a.Value != 42 { + t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%d)", a.Value, b.Value) + } + if !reflect.DeepEqual(a, b) { + t.FailNow() + } +} + +func TestComplexStruct(t *testing.T) { + a := complexTest{} + a.ID = "athing" + b := complexTest{simpleTest{42}, 1, "bthing"} + if err := Merge(&a, b); err != nil { + t.FailNow() + } + if a.St.Value != 42 { + t.Fatalf("b not merged in properly: a.St.Value(%d) != b.St.Value(%d)", a.St.Value, b.St.Value) + } + if a.sz == 1 { + t.Fatalf("a's private field sz not preserved from merge: a.sz(%d) == b.sz(%d)", a.sz, b.sz) + } + if a.ID == b.ID { + t.Fatalf("a's field ID merged unexpectedly: a.ID(%s) == b.ID(%s)", a.ID, b.ID) + } +} + +func TestComplexStructWithOverwrite(t *testing.T) { + a := complexTest{simpleTest{1}, 1, "do-not-overwrite-with-empty-value"} + b := complexTest{simpleTest{42}, 2, ""} + + expect := complexTest{simpleTest{42}, 1, "do-not-overwrite-with-empty-value"} + if err := MergeWithOverwrite(&a, b); err != nil { + t.FailNow() + } + + if !reflect.DeepEqual(a, expect) { + t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", a, expect) + } +} + +func TestPointerStruct(t *testing.T) { + s1 := simpleTest{} + s2 := simpleTest{19} + a := pointerTest{&s1} + b := pointerTest{&s2} + if err := Merge(&a, b); err != nil { + t.FailNow() + } + if a.C.Value != b.C.Value { + t.Fatalf("b not merged in properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value) + } +} + +type embeddingStruct struct { + embeddedStruct +} + +type embeddedStruct struct { + A string +} + +func TestEmbeddedStruct(t *testing.T) { + tests := []struct { + src embeddingStruct + dst embeddingStruct + expected embeddingStruct + }{ + { + src: embeddingStruct{ + embeddedStruct{"foo"}, + }, + dst: embeddingStruct{ + embeddedStruct{""}, + }, + expected: embeddingStruct{ + embeddedStruct{"foo"}, + }, + }, + { + src: embeddingStruct{ + embeddedStruct{""}, + }, + dst: embeddingStruct{ + embeddedStruct{"bar"}, + }, + expected: embeddingStruct{ + embeddedStruct{"bar"}, + }, + }, + { + src: embeddingStruct{ + embeddedStruct{"foo"}, + }, + dst: embeddingStruct{ + embeddedStruct{"bar"}, + }, + expected: embeddingStruct{ + embeddedStruct{"bar"}, + }, + }, + } + + for _, test := range tests { + err := Merge(&test.dst, test.src) + if err != nil { + t.Errorf("unexpected error: %v", err) + continue + } + if !reflect.DeepEqual(test.dst, test.expected) { + t.Errorf("unexpected output\nexpected:\n%+v\nsaw:\n%+v\n", test.expected, test.dst) + } + } +} + +func TestPointerStructNil(t *testing.T) { + a := pointerTest{nil} + b := pointerTest{&simpleTest{19}} + if err := Merge(&a, b); err != nil { + t.FailNow() + } + if a.C.Value != b.C.Value { + t.Fatalf("b not merged in a properly: a.C.Value(%d) != b.C.Value(%d)", a.C.Value, b.C.Value) + } +} + +func testSlice(t *testing.T, a []int, b []int) { + bc := b + e := append(a, b...) + + sa := sliceTest{a} + sb := sliceTest{b} + if err := Merge(&sa, sb); err != nil { + t.FailNow() + } + if !reflect.DeepEqual(sb.S, bc) { + t.Fatalf("Source slice was modified %d != %d", sb.S, bc) + } + if !reflect.DeepEqual(sa.S, e) { + t.Fatalf("b not merged in a proper way %d != %d", sa.S, e) + } + + ma := map[string][]int{"S": a} + mb := map[string][]int{"S": b} + if err := Merge(&ma, mb); err != nil { + t.FailNow() + } + if !reflect.DeepEqual(mb["S"], bc) { + t.Fatalf("Source slice was modified %d != %d", mb["S"], bc) + } + if !reflect.DeepEqual(ma["S"], e) { + t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e) + } + + if a == nil { + // test case with missing dst key + ma := map[string][]int{} + mb := map[string][]int{"S": b} + if err := Merge(&ma, mb); err != nil { + t.FailNow() + } + if !reflect.DeepEqual(mb["S"], bc) { + t.Fatalf("Source slice was modified %d != %d", mb["S"], bc) + } + if !reflect.DeepEqual(ma["S"], e) { + t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e) + } + } + + if b == nil { + // test case with missing src key + ma := map[string][]int{"S": a} + mb := map[string][]int{} + if err := Merge(&ma, mb); err != nil { + t.FailNow() + } + if !reflect.DeepEqual(mb["S"], bc) { + t.Fatalf("Source slice was modified %d != %d", mb["S"], bc) + } + if !reflect.DeepEqual(ma["S"], e) { + t.Fatalf("b not merged in a proper way %d != %d", ma["S"], e) + } + } +} + +func TestSlice(t *testing.T) { + testSlice(t, nil, []int{1, 2, 3}) + testSlice(t, []int{}, []int{1, 2, 3}) + testSlice(t, []int{1}, []int{2, 3}) + testSlice(t, []int{1}, []int{}) + testSlice(t, []int{1}, nil) +} + +func TestEmptyMaps(t *testing.T) { + a := mapTest{} + b := mapTest{ + map[int]int{}, + } + if err := Merge(&a, b); err != nil { + t.Fail() + } + if !reflect.DeepEqual(a, b) { + t.FailNow() + } +} + +func TestEmptyToEmptyMaps(t *testing.T) { + a := mapTest{} + b := mapTest{} + if err := Merge(&a, b); err != nil { + t.Fail() + } + if !reflect.DeepEqual(a, b) { + t.FailNow() + } +} + +func TestEmptyToNotEmptyMaps(t *testing.T) { + a := mapTest{map[int]int{ + 1: 2, + 3: 4, + }} + aa := mapTest{map[int]int{ + 1: 2, + 3: 4, + }} + b := mapTest{ + map[int]int{}, + } + if err := Merge(&a, b); err != nil { + t.Fail() + } + if !reflect.DeepEqual(a, aa) { + t.FailNow() + } +} + +func TestMapsWithOverwrite(t *testing.T) { + m := map[string]simpleTest{ + "a": {}, // overwritten by 16 + "b": {42}, // not overwritten by empty value + "c": {13}, // overwritten by 12 + "d": {61}, + } + n := map[string]simpleTest{ + "a": {16}, + "b": {}, + "c": {12}, + "e": {14}, + } + expect := map[string]simpleTest{ + "a": {16}, + "b": {}, + "c": {12}, + "d": {61}, + "e": {14}, + } + + if err := MergeWithOverwrite(&m, n); err != nil { + t.Fatalf(err.Error()) + } + + if !reflect.DeepEqual(m, expect) { + t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect) + } +} + +func TestMaps(t *testing.T) { + m := map[string]simpleTest{ + "a": {}, + "b": {42}, + "c": {13}, + "d": {61}, + } + n := map[string]simpleTest{ + "a": {16}, + "b": {}, + "c": {12}, + "e": {14}, + } + expect := map[string]simpleTest{ + "a": {0}, + "b": {42}, + "c": {13}, + "d": {61}, + "e": {14}, + } + + if err := Merge(&m, n); err != nil { + t.Fatalf(err.Error()) + } + + if !reflect.DeepEqual(m, expect) { + t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect) + } + if m["a"].Value != 0 { + t.Fatalf(`n merged in m because I solved non-addressable map values TODO: m["a"].Value(%d) != n["a"].Value(%d)`, m["a"].Value, n["a"].Value) + } + if m["b"].Value != 42 { + t.Fatalf(`n wrongly merged in m: m["b"].Value(%d) != n["b"].Value(%d)`, m["b"].Value, n["b"].Value) + } + if m["c"].Value != 13 { + t.Fatalf(`n overwritten in m: m["c"].Value(%d) != n["c"].Value(%d)`, m["c"].Value, n["c"].Value) + } +} + +func TestMapsWithNilPointer(t *testing.T) { + m := map[string]*simpleTest{ + "a": nil, + "b": nil, + } + n := map[string]*simpleTest{ + "b": nil, + "c": nil, + } + expect := map[string]*simpleTest{ + "a": nil, + "b": nil, + "c": nil, + } + + if err := Merge(&m, n, WithOverride); err != nil { + t.Fatalf(err.Error()) + } + + if !reflect.DeepEqual(m, expect) { + t.Fatalf("Test failed:\ngot :\n%#v\n\nwant :\n%#v\n\n", m, expect) + } +} + +func TestYAMLMaps(t *testing.T) { + thing := loadYAML("testdata/thing.yml") + license := loadYAML("testdata/license.yml") + ft := thing["fields"].(map[interface{}]interface{}) + fl := license["fields"].(map[interface{}]interface{}) + // license has one extra field (site) and another already existing in thing (author) that Mergo won't override. + expectedLength := len(ft) + len(fl) - 1 + if err := Merge(&license, thing); err != nil { + t.Fatal(err.Error()) + } + currentLength := len(license["fields"].(map[interface{}]interface{})) + if currentLength != expectedLength { + t.Fatalf(`thing not merged in license properly, license must have %d elements instead of %d`, expectedLength, currentLength) + } + fields := license["fields"].(map[interface{}]interface{}) + if _, ok := fields["id"]; !ok { + t.Fatalf(`thing not merged in license properly, license must have a new id field from thing`) + } +} + +func TestTwoPointerValues(t *testing.T) { + a := &simpleTest{} + b := &simpleTest{42} + if err := Merge(a, b); err != nil { + t.Fatalf(`Boom. You crossed the streams: %s`, err) + } +} + +func TestMap(t *testing.T) { + a := complexTest{} + a.ID = "athing" + c := moreComplextText{a, simpleTest{}, simpleTest{}} + b := map[string]interface{}{ + "ct": map[string]interface{}{ + "st": map[string]interface{}{ + "value": 42, + }, + "sz": 1, + "id": "bthing", + }, + "st": &simpleTest{144}, // Mapping a reference + "zt": simpleTest{299}, // Mapping a missing field (zt doesn't exist) + "nt": simpleTest{3}, + } + if err := Map(&c, b); err != nil { + t.FailNow() + } + m := b["ct"].(map[string]interface{}) + n := m["st"].(map[string]interface{}) + o := b["st"].(*simpleTest) + p := b["nt"].(simpleTest) + if c.Ct.St.Value != 42 { + t.Fatalf("b not merged in properly: c.Ct.St.Value(%d) != b.Ct.St.Value(%d)", c.Ct.St.Value, n["value"]) + } + if c.St.Value != 144 { + t.Fatalf("b not merged in properly: c.St.Value(%d) != b.St.Value(%d)", c.St.Value, o.Value) + } + if c.Nt.Value != 3 { + t.Fatalf("b not merged in properly: c.Nt.Value(%d) != b.Nt.Value(%d)", c.St.Value, p.Value) + } + if c.Ct.sz == 1 { + t.Fatalf("a's private field sz not preserved from merge: c.Ct.sz(%d) == b.Ct.sz(%d)", c.Ct.sz, m["sz"]) + } + if c.Ct.ID == m["id"] { + t.Fatalf("a's field ID merged unexpectedly: c.Ct.ID(%s) == b.Ct.ID(%s)", c.Ct.ID, m["id"]) + } +} + +func TestSimpleMap(t *testing.T) { + a := simpleTest{} + b := map[string]interface{}{ + "value": 42, + } + if err := Map(&a, b); err != nil { + t.FailNow() + } + if a.Value != 42 { + t.Fatalf("b not merged in properly: a.Value(%d) != b.Value(%v)", a.Value, b["value"]) + } +} + +func TestIfcMap(t *testing.T) { + a := ifcTest{} + b := ifcTest{42} + if err := Map(&a, b); err != nil { + t.FailNow() + } + if a.I != 42 { + t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I) + } + if !reflect.DeepEqual(a, b) { + t.FailNow() + } +} + +func TestIfcMapNoOverwrite(t *testing.T) { + a := ifcTest{13} + b := ifcTest{42} + if err := Map(&a, b); err != nil { + t.FailNow() + } + if a.I != 13 { + t.Fatalf("a not left alone: a.I(%d) == b.I(%d)", a.I, b.I) + } +} + +func TestIfcMapWithOverwrite(t *testing.T) { + a := ifcTest{13} + b := ifcTest{42} + if err := MapWithOverwrite(&a, b); err != nil { + t.FailNow() + } + if a.I != 42 { + t.Fatalf("b not merged in properly: a.I(%d) != b.I(%d)", a.I, b.I) + } + if !reflect.DeepEqual(a, b) { + t.FailNow() + } +} + +type pointerMapTest struct { + A int + hidden int + B *simpleTest +} + +func TestBackAndForth(t *testing.T) { + pt := pointerMapTest{42, 1, &simpleTest{66}} + m := make(map[string]interface{}) + if err := Map(&m, pt); err != nil { + t.FailNow() + } + var ( + v interface{} + ok bool + ) + if v, ok = m["a"]; v.(int) != pt.A || !ok { + t.Fatalf("pt not merged in properly: m[`a`](%d) != pt.A(%d)", v, pt.A) + } + if v, ok = m["b"]; !ok { + t.Fatalf("pt not merged in properly: B is missing in m") + } + var st *simpleTest + if st = v.(*simpleTest); st.Value != 66 { + t.Fatalf("something went wrong while mapping pt on m, B wasn't copied") + } + bpt := pointerMapTest{} + if err := Map(&bpt, m); err != nil { + t.Fatal(err) + } + if bpt.A != pt.A { + t.Fatalf("pt not merged in properly: bpt.A(%d) != pt.A(%d)", bpt.A, pt.A) + } + if bpt.hidden == pt.hidden { + t.Fatalf("pt unexpectedly merged: bpt.hidden(%d) == pt.hidden(%d)", bpt.hidden, pt.hidden) + } + if bpt.B.Value != pt.B.Value { + t.Fatalf("pt not merged in properly: bpt.B.Value(%d) != pt.B.Value(%d)", bpt.B.Value, pt.B.Value) + } +} + +func TestEmbeddedPointerUnpacking(t *testing.T) { + tests := []struct{ input pointerMapTest }{ + {pointerMapTest{42, 1, nil}}, + {pointerMapTest{42, 1, &simpleTest{66}}}, + } + newValue := 77 + m := map[string]interface{}{ + "b": map[string]interface{}{ + "value": newValue, + }, + } + for _, test := range tests { + pt := test.input + if err := MapWithOverwrite(&pt, m); err != nil { + t.FailNow() + } + if pt.B.Value != newValue { + t.Fatalf("pt not mapped properly: pt.A.Value(%d) != m[`b`][`value`](%d)", pt.B.Value, newValue) + } + + } +} + +type structWithTimePointer struct { + Birth *time.Time +} + +func TestTime(t *testing.T) { + now := time.Now() + dataStruct := structWithTimePointer{ + Birth: &now, + } + dataMap := map[string]interface{}{ + "Birth": &now, + } + b := structWithTimePointer{} + if err := Merge(&b, dataStruct); err != nil { + t.FailNow() + } + if b.Birth.IsZero() { + t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth) + } + if b.Birth != dataStruct.Birth { + t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataStruct['Birth'](%v)", b.Birth, dataStruct.Birth) + } + b = structWithTimePointer{} + if err := Map(&b, dataMap); err != nil { + t.FailNow() + } + if b.Birth.IsZero() { + t.Fatalf("time.Time not merged in properly: b.Birth(%v) != dataMap['Birth'](%v)", b.Birth, dataMap["Birth"]) + } +} + +type simpleNested struct { + A int +} + +type structWithNestedPtrValueMap struct { + NestedPtrValue map[string]*simpleNested +} + +func TestNestedPtrValueInMap(t *testing.T) { + src := &structWithNestedPtrValueMap{ + NestedPtrValue: map[string]*simpleNested{ + "x": { + A: 1, + }, + }, + } + dst := &structWithNestedPtrValueMap{ + NestedPtrValue: map[string]*simpleNested{ + "x": {}, + }, + } + if err := Map(dst, src); err != nil { + t.FailNow() + } + if dst.NestedPtrValue["x"].A == 0 { + t.Fatalf("Nested Ptr value not merged in properly: dst.NestedPtrValue[\"x\"].A(%v) != src.NestedPtrValue[\"x\"].A(%v)", dst.NestedPtrValue["x"].A, src.NestedPtrValue["x"].A) + } +} + +func loadYAML(path string) (m map[string]interface{}) { + m = make(map[string]interface{}) + raw, _ := ioutil.ReadFile(path) + _ = yaml.Unmarshal(raw, &m) + return +} + +type structWithMap struct { + m map[string]structWithUnexportedProperty +} + +type structWithUnexportedProperty struct { + s string +} + +func TestUnexportedProperty(t *testing.T) { + a := structWithMap{map[string]structWithUnexportedProperty{ + "key": {"hello"}, + }} + b := structWithMap{map[string]structWithUnexportedProperty{ + "key": {"hi"}, + }} + defer func() { + if r := recover(); r != nil { + t.Errorf("Should not have panicked") + } + }() + Merge(&a, b) +} + +type structWithBoolPointer struct { + C *bool +} + +func TestBooleanPointer(t *testing.T) { + bt, bf := true, false + src := structWithBoolPointer{ + &bt, + } + dst := structWithBoolPointer{ + &bf, + } + if err := Merge(&dst, src); err != nil { + t.FailNow() + } + if dst.C == src.C { + t.Fatalf("dst.C should be a different pointer than src.C") + } + if *dst.C != *src.C { + t.Fatalf("dst.C should be true") + } +} diff --git a/vendor/github.com/imdario/mergo/testdata/license.yml b/vendor/github.com/imdario/mergo/testdata/license.yml deleted file mode 100644 index 2f1ad0082..000000000 --- a/vendor/github.com/imdario/mergo/testdata/license.yml +++ /dev/null @@ -1,4 +0,0 @@ -import: ../../../../fossene/db/schema/thing.yml -fields: - site: string - author: root diff --git a/vendor/github.com/jmespath/go-jmespath/.gitignore b/vendor/github.com/jmespath/go-jmespath/.gitignore new file mode 100644 index 000000000..531fcc11c --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/.gitignore @@ -0,0 +1,4 @@ +jpgo +jmespath-fuzz.zip +cpu.out +go-jmespath.test diff --git a/vendor/github.com/jmespath/go-jmespath/.travis.yml b/vendor/github.com/jmespath/go-jmespath/.travis.yml new file mode 100644 index 000000000..1f9807757 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/.travis.yml @@ -0,0 +1,9 @@ +language: go + +sudo: false + +go: + - 1.4 + +install: go get -v -t ./... +script: make test diff --git a/vendor/github.com/jmespath/go-jmespath/Makefile b/vendor/github.com/jmespath/go-jmespath/Makefile new file mode 100644 index 000000000..a828d2848 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/Makefile @@ -0,0 +1,44 @@ + +CMD = jpgo + +help: + @echo "Please use \`make ' where is one of" + @echo " test to run all the tests" + @echo " build to build the library and jp executable" + @echo " generate to run codegen" + + +generate: + go generate ./... + +build: + rm -f $(CMD) + go build ./... + rm -f cmd/$(CMD)/$(CMD) && cd cmd/$(CMD)/ && go build ./... + mv cmd/$(CMD)/$(CMD) . + +test: + go test -v ./... + +check: + go vet ./... + @echo "golint ./..." + @lint=`golint ./...`; \ + lint=`echo "$$lint" | grep -v "astnodetype_string.go" | grep -v "toktype_string.go"`; \ + echo "$$lint"; \ + if [ "$$lint" != "" ]; then exit 1; fi + +htmlc: + go test -coverprofile="/tmp/jpcov" && go tool cover -html="/tmp/jpcov" && unlink /tmp/jpcov + +buildfuzz: + go-fuzz-build github.com/jmespath/go-jmespath/fuzz + +fuzz: buildfuzz + go-fuzz -bin=./jmespath-fuzz.zip -workdir=fuzz/testdata + +bench: + go test -bench . -cpuprofile cpu.out + +pprof-cpu: + go tool pprof ./go-jmespath.test ./cpu.out diff --git a/vendor/github.com/jmespath/go-jmespath/README.md b/vendor/github.com/jmespath/go-jmespath/README.md new file mode 100644 index 000000000..187ef676d --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/README.md @@ -0,0 +1,7 @@ +# go-jmespath - A JMESPath implementation in Go + +[![Build Status](https://img.shields.io/travis/jmespath/go-jmespath.svg)](https://travis-ci.org/jmespath/go-jmespath) + + + +See http://jmespath.org for more info. diff --git a/vendor/github.com/jmespath/go-jmespath/api_test.go b/vendor/github.com/jmespath/go-jmespath/api_test.go new file mode 100644 index 000000000..b0b106d3d --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/api_test.go @@ -0,0 +1,32 @@ +package jmespath + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidPrecompiledExpressionSearches(t *testing.T) { + assert := assert.New(t) + data := make(map[string]interface{}) + data["foo"] = "bar" + precompiled, err := Compile("foo") + assert.Nil(err) + result, err := precompiled.Search(data) + assert.Nil(err) + assert.Equal("bar", result) +} + +func TestInvalidPrecompileErrors(t *testing.T) { + assert := assert.New(t) + _, err := Compile("not a valid expression") + assert.NotNil(err) +} + +func TestInvalidMustCompilePanics(t *testing.T) { + defer func() { + r := recover() + assert.NotNil(t, r) + }() + MustCompile("not a valid expression") +} diff --git a/vendor/github.com/jmespath/go-jmespath/compliance_test.go b/vendor/github.com/jmespath/go-jmespath/compliance_test.go new file mode 100644 index 000000000..4ee9c959d --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/compliance_test.go @@ -0,0 +1,123 @@ +package jmespath + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +type TestSuite struct { + Given interface{} + TestCases []TestCase `json:"cases"` + Comment string +} +type TestCase struct { + Comment string + Expression string + Result interface{} + Error string +} + +var whiteListed = []string{ + "compliance/basic.json", + "compliance/current.json", + "compliance/escape.json", + "compliance/filters.json", + "compliance/functions.json", + "compliance/identifiers.json", + "compliance/indices.json", + "compliance/literal.json", + "compliance/multiselect.json", + "compliance/ormatch.json", + "compliance/pipe.json", + "compliance/slice.json", + "compliance/syntax.json", + "compliance/unicode.json", + "compliance/wildcard.json", + "compliance/boolean.json", +} + +func allowed(path string) bool { + for _, el := range whiteListed { + if el == path { + return true + } + } + return false +} + +func TestCompliance(t *testing.T) { + assert := assert.New(t) + + var complianceFiles []string + err := filepath.Walk("compliance", func(path string, _ os.FileInfo, _ error) error { + //if strings.HasSuffix(path, ".json") { + if allowed(path) { + complianceFiles = append(complianceFiles, path) + } + return nil + }) + if assert.Nil(err) { + for _, filename := range complianceFiles { + runComplianceTest(assert, filename) + } + } +} + +func runComplianceTest(assert *assert.Assertions, filename string) { + var testSuites []TestSuite + data, err := ioutil.ReadFile(filename) + if assert.Nil(err) { + err := json.Unmarshal(data, &testSuites) + if assert.Nil(err) { + for _, testsuite := range testSuites { + runTestSuite(assert, testsuite, filename) + } + } + } +} + +func runTestSuite(assert *assert.Assertions, testsuite TestSuite, filename string) { + for _, testcase := range testsuite.TestCases { + if testcase.Error != "" { + // This is a test case that verifies we error out properly. + runSyntaxTestCase(assert, testsuite.Given, testcase, filename) + } else { + runTestCase(assert, testsuite.Given, testcase, filename) + } + } +} + +func runSyntaxTestCase(assert *assert.Assertions, given interface{}, testcase TestCase, filename string) { + // Anything with an .Error means that we expect that JMESPath should return + // an error when we try to evaluate the expression. + _, err := Search(testcase.Expression, given) + assert.NotNil(err, fmt.Sprintf("Expression: %s", testcase.Expression)) +} + +func runTestCase(assert *assert.Assertions, given interface{}, testcase TestCase, filename string) { + lexer := NewLexer() + var err error + _, err = lexer.tokenize(testcase.Expression) + if err != nil { + errMsg := fmt.Sprintf("(%s) Could not lex expression: %s -- %s", filename, testcase.Expression, err.Error()) + assert.Fail(errMsg) + return + } + parser := NewParser() + _, err = parser.Parse(testcase.Expression) + if err != nil { + errMsg := fmt.Sprintf("(%s) Could not parse expression: %s -- %s", filename, testcase.Expression, err.Error()) + assert.Fail(errMsg) + return + } + actual, err := Search(testcase.Expression, given) + if assert.Nil(err, fmt.Sprintf("Expression: %s", testcase.Expression)) { + assert.Equal(testcase.Result, actual, fmt.Sprintf("Expression: %s", testcase.Expression)) + } +} diff --git a/vendor/github.com/jmespath/go-jmespath/interpreter_test.go b/vendor/github.com/jmespath/go-jmespath/interpreter_test.go new file mode 100644 index 000000000..11c6d0aa0 --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/interpreter_test.go @@ -0,0 +1,221 @@ +package jmespath + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" +) + +type scalars struct { + Foo string + Bar string +} + +type sliceType struct { + A string + B []scalars + C []*scalars +} + +type benchmarkStruct struct { + Fooasdfasdfasdfasdf string +} + +type benchmarkNested struct { + Fooasdfasdfasdfasdf nestedA +} + +type nestedA struct { + Fooasdfasdfasdfasdf nestedB +} + +type nestedB struct { + Fooasdfasdfasdfasdf nestedC +} + +type nestedC struct { + Fooasdfasdfasdfasdf string +} + +type nestedSlice struct { + A []sliceType +} + +func TestCanSupportEmptyInterface(t *testing.T) { + assert := assert.New(t) + data := make(map[string]interface{}) + data["foo"] = "bar" + result, err := Search("foo", data) + assert.Nil(err) + assert.Equal("bar", result) +} + +func TestCanSupportUserDefinedStructsValue(t *testing.T) { + assert := assert.New(t) + s := scalars{Foo: "one", Bar: "bar"} + result, err := Search("Foo", s) + assert.Nil(err) + assert.Equal("one", result) +} + +func TestCanSupportUserDefinedStructsRef(t *testing.T) { + assert := assert.New(t) + s := scalars{Foo: "one", Bar: "bar"} + result, err := Search("Foo", &s) + assert.Nil(err) + assert.Equal("one", result) +} + +func TestCanSupportStructWithSliceAll(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", B: []scalars{{"f1", "b1"}, {"correct", "b2"}}} + result, err := Search("B[].Foo", data) + assert.Nil(err) + assert.Equal([]interface{}{"f1", "correct"}, result) +} + +func TestCanSupportStructWithSlicingExpression(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", B: []scalars{{"f1", "b1"}, {"correct", "b2"}}} + result, err := Search("B[:].Foo", data) + assert.Nil(err) + assert.Equal([]interface{}{"f1", "correct"}, result) +} + +func TestCanSupportStructWithFilterProjection(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", B: []scalars{{"f1", "b1"}, {"correct", "b2"}}} + result, err := Search("B[? `true` ].Foo", data) + assert.Nil(err) + assert.Equal([]interface{}{"f1", "correct"}, result) +} + +func TestCanSupportStructWithSlice(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", B: []scalars{{"f1", "b1"}, {"correct", "b2"}}} + result, err := Search("B[-1].Foo", data) + assert.Nil(err) + assert.Equal("correct", result) +} + +func TestCanSupportStructWithOrExpressions(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", C: nil} + result, err := Search("C || A", data) + assert.Nil(err) + assert.Equal("foo", result) +} + +func TestCanSupportStructWithSlicePointer(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", C: []*scalars{{"f1", "b1"}, {"correct", "b2"}}} + result, err := Search("C[-1].Foo", data) + assert.Nil(err) + assert.Equal("correct", result) +} + +func TestWillAutomaticallyCapitalizeFieldNames(t *testing.T) { + assert := assert.New(t) + s := scalars{Foo: "one", Bar: "bar"} + // Note that there's a lower cased "foo" instead of "Foo", + // but it should still correspond to the Foo field in the + // scalars struct + result, err := Search("foo", &s) + assert.Nil(err) + assert.Equal("one", result) +} + +func TestCanSupportStructWithSliceLowerCased(t *testing.T) { + assert := assert.New(t) + data := sliceType{A: "foo", B: []scalars{{"f1", "b1"}, {"correct", "b2"}}} + result, err := Search("b[-1].foo", data) + assert.Nil(err) + assert.Equal("correct", result) +} + +func TestCanSupportStructWithNestedPointers(t *testing.T) { + assert := assert.New(t) + data := struct{ A *struct{ B int } }{} + result, err := Search("A.B", data) + assert.Nil(err) + assert.Nil(result) +} + +func TestCanSupportFlattenNestedSlice(t *testing.T) { + assert := assert.New(t) + data := nestedSlice{A: []sliceType{ + {B: []scalars{{Foo: "f1a"}, {Foo: "f1b"}}}, + {B: []scalars{{Foo: "f2a"}, {Foo: "f2b"}}}, + }} + result, err := Search("A[].B[].Foo", data) + assert.Nil(err) + assert.Equal([]interface{}{"f1a", "f1b", "f2a", "f2b"}, result) +} + +func TestCanSupportFlattenNestedEmptySlice(t *testing.T) { + assert := assert.New(t) + data := nestedSlice{A: []sliceType{ + {}, {B: []scalars{{Foo: "a"}}}, + }} + result, err := Search("A[].B[].Foo", data) + assert.Nil(err) + assert.Equal([]interface{}{"a"}, result) +} + +func TestCanSupportProjectionsWithStructs(t *testing.T) { + assert := assert.New(t) + data := nestedSlice{A: []sliceType{ + {A: "first"}, {A: "second"}, {A: "third"}, + }} + result, err := Search("A[*].A", data) + assert.Nil(err) + assert.Equal([]interface{}{"first", "second", "third"}, result) +} + +func TestCanSupportSliceOfStructsWithFunctions(t *testing.T) { + assert := assert.New(t) + data := []scalars{scalars{"a1", "b1"}, scalars{"a2", "b2"}} + result, err := Search("length(@)", data) + assert.Nil(err) + assert.Equal(result.(float64), 2.0) +} + +func BenchmarkInterpretSingleFieldStruct(b *testing.B) { + intr := newInterpreter() + parser := NewParser() + ast, _ := parser.Parse("fooasdfasdfasdfasdf") + data := benchmarkStruct{"foobarbazqux"} + for i := 0; i < b.N; i++ { + intr.Execute(ast, &data) + } +} + +func BenchmarkInterpretNestedStruct(b *testing.B) { + intr := newInterpreter() + parser := NewParser() + ast, _ := parser.Parse("fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf") + data := benchmarkNested{ + nestedA{ + nestedB{ + nestedC{"foobarbazqux"}, + }, + }, + } + for i := 0; i < b.N; i++ { + intr.Execute(ast, &data) + } +} + +func BenchmarkInterpretNestedMaps(b *testing.B) { + jsonData := []byte(`{"fooasdfasdfasdfasdf": {"fooasdfasdfasdfasdf": {"fooasdfasdfasdfasdf": {"fooasdfasdfasdfasdf": "foobarbazqux"}}}}`) + var data interface{} + json.Unmarshal(jsonData, &data) + + intr := newInterpreter() + parser := NewParser() + ast, _ := parser.Parse("fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf.fooasdfasdfasdfasdf") + for i := 0; i < b.N; i++ { + intr.Execute(ast, data) + } +} diff --git a/vendor/github.com/jmespath/go-jmespath/lexer_test.go b/vendor/github.com/jmespath/go-jmespath/lexer_test.go new file mode 100644 index 000000000..d13a042da --- /dev/null +++ b/vendor/github.com/jmespath/go-jmespath/lexer_test.go @@ -0,0 +1,161 @@ +package jmespath + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +var lexingTests = []struct { + expression string + expected []token +}{ + {"*", []token{{tStar, "*", 0, 1}}}, + {".", []token{{tDot, ".", 0, 1}}}, + {"[?", []token{{tFilter, "[?", 0, 2}}}, + {"[]", []token{{tFlatten, "[]", 0, 2}}}, + {"(", []token{{tLparen, "(", 0, 1}}}, + {")", []token{{tRparen, ")", 0, 1}}}, + {"[", []token{{tLbracket, "[", 0, 1}}}, + {"]", []token{{tRbracket, "]", 0, 1}}}, + {"{", []token{{tLbrace, "{", 0, 1}}}, + {"}", []token{{tRbrace, "}", 0, 1}}}, + {"||", []token{{tOr, "||", 0, 2}}}, + {"|", []token{{tPipe, "|", 0, 1}}}, + {"29", []token{{tNumber, "29", 0, 2}}}, + {"2", []token{{tNumber, "2", 0, 1}}}, + {"0", []token{{tNumber, "0", 0, 1}}}, + {"-20", []token{{tNumber, "-20", 0, 3}}}, + {"foo", []token{{tUnquotedIdentifier, "foo", 0, 3}}}, + {`"bar"`, []token{{tQuotedIdentifier, "bar", 0, 3}}}, + // Escaping the delimiter + {`"bar\"baz"`, []token{{tQuotedIdentifier, `bar"baz`, 0, 7}}}, + {",", []token{{tComma, ",", 0, 1}}}, + {":", []token{{tColon, ":", 0, 1}}}, + {"<", []token{{tLT, "<", 0, 1}}}, + {"<=", []token{{tLTE, "<=", 0, 2}}}, + {">", []token{{tGT, ">", 0, 1}}}, + {">=", []token{{tGTE, ">=", 0, 2}}}, + {"==", []token{{tEQ, "==", 0, 2}}}, + {"!=", []token{{tNE, "!=", 0, 2}}}, + {"`[0, 1, 2]`", []token{{tJSONLiteral, "[0, 1, 2]", 1, 9}}}, + {"'foo'", []token{{tStringLiteral, "foo", 1, 3}}}, + {"'a'", []token{{tStringLiteral, "a", 1, 1}}}, + {`'foo\'bar'`, []token{{tStringLiteral, "foo'bar", 1, 7}}}, + {"@", []token{{tCurrent, "@", 0, 1}}}, + {"&", []token{{tExpref, "&", 0, 1}}}, + // Quoted identifier unicode escape sequences + {`"\u2713"`, []token{{tQuotedIdentifier, "✓", 0, 3}}}, + {`"\\"`, []token{{tQuotedIdentifier, `\`, 0, 1}}}, + {"`\"foo\"`", []token{{tJSONLiteral, "\"foo\"", 1, 5}}}, + // Combinations of tokens. + {"foo.bar", []token{ + {tUnquotedIdentifier, "foo", 0, 3}, + {tDot, ".", 3, 1}, + {tUnquotedIdentifier, "bar", 4, 3}, + }}, + {"foo[0]", []token{ + {tUnquotedIdentifier, "foo", 0, 3}, + {tLbracket, "[", 3, 1}, + {tNumber, "0", 4, 1}, + {tRbracket, "]", 5, 1}, + }}, + {"foo[?a true
negative => true
zero => false| 23.2 => 23
-32.1 => -32| 12.1 => 12
-12.1 => 0|as normal|same as origin| +| string | empty string => false
string "0" => false
other strings => true | "123.32" => 123
"-123.4" => -123
"123.23xxxw" => 123
"abcde12" => 0
"-32.1" => -32| 13.2 => 13
-1.1 => 0 |12.1 => 12.1
-12.3 => -12.3
12.4xxa => 12.4
+1.1e2 =>110 |same as origin| +| bool | true => true
false => false| true => 1
false => 0 | true => 1
false => 0 |true => 1
false => 0|true => "true"
false => "false"| +| object | true | 0 | 0 |0|originnal json| +| array | empty array => false
nonempty array => true| [] => 0
[1,2] => 1 | [] => 0
[1,2] => 1 |[] => 0
[1,2] => 1|original json| \ No newline at end of file diff --git a/vendor/github.com/json-iterator/go/iter_skip_sloppy_test.go b/vendor/github.com/json-iterator/go/iter_skip_sloppy_test.go new file mode 100644 index 000000000..bcb491fe6 --- /dev/null +++ b/vendor/github.com/json-iterator/go/iter_skip_sloppy_test.go @@ -0,0 +1,162 @@ +//+build jsoniter_sloppy + +package jsoniter + +import ( + "github.com/stretchr/testify/require" + "io" + "testing" +) + +func Test_string_end(t *testing.T) { + end, escaped := ParseString(ConfigDefault, `abc"`).findStringEnd() + if end != 4 { + t.Fatal(end) + } + if escaped != false { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `abc\\"`).findStringEnd() + if end != 6 { + t.Fatal(end) + } + if escaped != true { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `abc\\\\"`).findStringEnd() + if end != 8 { + t.Fatal(end) + } + if escaped != true { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `abc\"`).findStringEnd() + if end != -1 { + t.Fatal(end) + } + if escaped != false { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `abc\`).findStringEnd() + if end != -1 { + t.Fatal(end) + } + if escaped != true { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `abc\\`).findStringEnd() + if end != -1 { + t.Fatal(end) + } + if escaped != false { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `\\`).findStringEnd() + if end != -1 { + t.Fatal(end) + } + if escaped != false { + t.Fatal(escaped) + } + end, escaped = ParseString(ConfigDefault, `\`).findStringEnd() + if end != -1 { + t.Fatal(end) + } + if escaped != true { + t.Fatal(escaped) + } +} + +type StagedReader struct { + r1 string + r2 string + r3 string + r int +} + +func (reader *StagedReader) Read(p []byte) (n int, err error) { + reader.r++ + switch reader.r { + case 1: + copy(p, []byte(reader.r1)) + return len(reader.r1), nil + case 2: + copy(p, []byte(reader.r2)) + return len(reader.r2), nil + case 3: + copy(p, []byte(reader.r3)) + return len(reader.r3), nil + default: + return 0, io.EOF + } +} + +func Test_skip_string(t *testing.T) { + should := require.New(t) + iter := ParseString(ConfigDefault, `"abc`) + iter.skipString() + should.Equal(1, iter.head) + iter = ParseString(ConfigDefault, `\""abc`) + iter.skipString() + should.Equal(3, iter.head) + reader := &StagedReader{ + r1: `abc`, + r2: `"`, + } + iter = Parse(ConfigDefault, reader, 4096) + iter.skipString() + should.Equal(1, iter.head) + reader = &StagedReader{ + r1: `abc`, + r2: `1"`, + } + iter = Parse(ConfigDefault, reader, 4096) + iter.skipString() + should.Equal(2, iter.head) + reader = &StagedReader{ + r1: `abc\`, + r2: `"`, + } + iter = Parse(ConfigDefault, reader, 4096) + iter.skipString() + should.NotNil(iter.Error) + reader = &StagedReader{ + r1: `abc\`, + r2: `""`, + } + iter = Parse(ConfigDefault, reader, 4096) + iter.skipString() + should.Equal(2, iter.head) +} + +func Test_skip_object(t *testing.T) { + iter := ParseString(ConfigDefault, `}`) + iter.skipObject() + if iter.head != 1 { + t.Fatal(iter.head) + } + iter = ParseString(ConfigDefault, `a}`) + iter.skipObject() + if iter.head != 2 { + t.Fatal(iter.head) + } + iter = ParseString(ConfigDefault, `{}}a`) + iter.skipObject() + if iter.head != 3 { + t.Fatal(iter.head) + } + reader := &StagedReader{ + r1: `{`, + r2: `}}a`, + } + iter = Parse(ConfigDefault, reader, 4096) + iter.skipObject() + if iter.head != 2 { + t.Fatal(iter.head) + } + iter = ParseString(ConfigDefault, `"}"}a`) + iter.skipObject() + if iter.head != 4 { + t.Fatal(iter.head) + } +} diff --git a/vendor/github.com/json-iterator/go/stream_test.go b/vendor/github.com/json-iterator/go/stream_test.go new file mode 100644 index 000000000..d407c7ab7 --- /dev/null +++ b/vendor/github.com/json-iterator/go/stream_test.go @@ -0,0 +1,69 @@ +package jsoniter + +import ( + "github.com/stretchr/testify/require" + "testing" +) + +func Test_writeByte_should_grow_buffer(t *testing.T) { + should := require.New(t) + stream := NewStream(ConfigDefault, nil, 1) + stream.writeByte('1') + should.Equal("1", string(stream.Buffer())) + should.Equal(1, len(stream.buf)) + stream.writeByte('2') + should.Equal("12", string(stream.Buffer())) + should.Equal(2, len(stream.buf)) + stream.writeThreeBytes('3', '4', '5') + should.Equal("12345", string(stream.Buffer())) +} + +func Test_writeBytes_should_grow_buffer(t *testing.T) { + should := require.New(t) + stream := NewStream(ConfigDefault, nil, 1) + stream.Write([]byte{'1', '2'}) + should.Equal("12", string(stream.Buffer())) + should.Equal(2, len(stream.buf)) + stream.Write([]byte{'3', '4', '5', '6', '7'}) + should.Equal("1234567", string(stream.Buffer())) + should.Equal(7, len(stream.buf)) +} + +func Test_writeIndention_should_grow_buffer(t *testing.T) { + should := require.New(t) + stream := NewStream(Config{IndentionStep: 2}.Froze(), nil, 1) + stream.WriteVal([]int{1, 2, 3}) + should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer())) +} + +func Test_writeRaw_should_grow_buffer(t *testing.T) { + should := require.New(t) + stream := NewStream(ConfigDefault, nil, 1) + stream.WriteRaw("123") + should.Nil(stream.Error) + should.Equal("123", string(stream.Buffer())) +} + +func Test_writeString_should_grow_buffer(t *testing.T) { + should := require.New(t) + stream := NewStream(ConfigDefault, nil, 0) + stream.WriteString("123") + should.Nil(stream.Error) + should.Equal(`"123"`, string(stream.Buffer())) +} + +type NopWriter struct { + bufferSize int +} + +func (w *NopWriter) Write(p []byte) (n int, err error) { + w.bufferSize = cap(p) + return len(p), nil +} + +func Test_flush_buffer_should_stop_grow_buffer(t *testing.T) { + writer := new(NopWriter) + NewEncoder(writer).Encode(make([]int, 10000000)) + should := require.New(t) + should.Equal(8, writer.bufferSize) +} diff --git a/vendor/github.com/json-iterator/go/test.sh b/vendor/github.com/json-iterator/go/test.sh new file mode 100755 index 000000000..f4e7c0b2c --- /dev/null +++ b/vendor/github.com/json-iterator/go/test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e +echo "" > coverage.txt + +for d in $(go list ./... | grep -v vendor); do + go test -coverprofile=profile.out -coverpkg=github.com/json-iterator/go $d + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md new file mode 100644 index 000000000..949b77e30 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md @@ -0,0 +1,40 @@ +# Windows Terminal Sequences + +This library allow for enabling Windows terminal color support for Go. + +See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details. + +## Usage + +```go +import ( + "syscall" + + sequences "github.com/konsorten/go-windows-terminal-sequences" +) + +func main() { + sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true) +} + +``` + +## Authors + +The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de). + +We thank all the authors who provided code to this library: + +* Felix Kollmann + +## License + +(The MIT License) + +Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod new file mode 100644 index 000000000..716c61312 --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod @@ -0,0 +1 @@ +module github.com/konsorten/go-windows-terminal-sequences diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go new file mode 100644 index 000000000..aad41c5cf --- /dev/null +++ b/vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_test.go @@ -0,0 +1,48 @@ +// +build windows + +package sequences + +import ( + "fmt" + "os" + "syscall" + "testing" +) + +func TestStdoutSequencesOn(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stdout, true) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + defer EnableVirtualTerminalProcessing(syscall.Stdout, false) + + fmt.Fprintf(os.Stdout, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} + +func TestStdoutSequencesOff(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stdout, false) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + + fmt.Fprintf(os.Stdout, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} + +func TestStderrSequencesOn(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stderr, true) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + defer EnableVirtualTerminalProcessing(syscall.Stderr, false) + + fmt.Fprintf(os.Stderr, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} + +func TestStderrSequencesOff(t *testing.T) { + err := EnableVirtualTerminalProcessing(syscall.Stderr, false) + if err != nil { + t.Fatalf("Failed to enable VTP: %v", err) + } + + fmt.Fprintf(os.Stderr, "\x1b[34mHello \x1b[35mWorld\x1b[0m!\n") +} diff --git a/vendor/github.com/mailru/easyjson/.gitignore b/vendor/github.com/mailru/easyjson/.gitignore new file mode 100644 index 000000000..db8c66edf --- /dev/null +++ b/vendor/github.com/mailru/easyjson/.gitignore @@ -0,0 +1,4 @@ +.root +*_easyjson.go +*.iml +.idea diff --git a/vendor/github.com/mailru/easyjson/.travis.yml b/vendor/github.com/mailru/easyjson/.travis.yml new file mode 100644 index 000000000..884f8bbdf --- /dev/null +++ b/vendor/github.com/mailru/easyjson/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - tip +install: + - go get github.com/ugorji/go/codec + - go get github.com/pquerna/ffjson/fflib/v1 + - go get github.com/json-iterator/go + - go get github.com/golang/lint/golint diff --git a/vendor/github.com/mailru/easyjson/Makefile b/vendor/github.com/mailru/easyjson/Makefile new file mode 100644 index 000000000..49c80f3bd --- /dev/null +++ b/vendor/github.com/mailru/easyjson/Makefile @@ -0,0 +1,60 @@ +PKG=github.com/mailru/easyjson +GOPATH:=$(PWD)/.root:$(GOPATH) +export GOPATH + +all: test + +.root/src/$(PKG): + mkdir -p $@ + for i in $$PWD/* ; do ln -s $$i $@/`basename $$i` ; done + +root: .root/src/$(PKG) + +clean: + rm -rf .root + rm -rf tests/*_easyjson.go + +build: + go build -i -o .root/bin/easyjson $(PKG)/easyjson + +generate: root build + .root/bin/easyjson -stubs \ + .root/src/$(PKG)/tests/snake.go \ + .root/src/$(PKG)/tests/data.go \ + .root/src/$(PKG)/tests/omitempty.go \ + .root/src/$(PKG)/tests/nothing.go \ + .root/src/$(PKG)/tests/named_type.go \ + .root/src/$(PKG)/tests/custom_map_key_type.go \ + .root/src/$(PKG)/tests/embedded_type.go + + .root/bin/easyjson -all .root/src/$(PKG)/tests/data.go + .root/bin/easyjson -all .root/src/$(PKG)/tests/nothing.go + .root/bin/easyjson -all .root/src/$(PKG)/tests/errors.go + .root/bin/easyjson -snake_case .root/src/$(PKG)/tests/snake.go + .root/bin/easyjson -omit_empty .root/src/$(PKG)/tests/omitempty.go + .root/bin/easyjson -build_tags=use_easyjson .root/src/$(PKG)/benchmark/data.go + .root/bin/easyjson .root/src/$(PKG)/tests/nested_easy.go + .root/bin/easyjson .root/src/$(PKG)/tests/named_type.go + .root/bin/easyjson .root/src/$(PKG)/tests/custom_map_key_type.go + .root/bin/easyjson .root/src/$(PKG)/tests/embedded_type.go + +test: generate root + go test \ + $(PKG)/tests \ + $(PKG)/jlexer \ + $(PKG)/gen \ + $(PKG)/buffer + go test -benchmem -tags use_easyjson -bench . $(PKG)/benchmark + golint -set_exit_status .root/src/$(PKG)/tests/*_easyjson.go + +bench-other: generate root + @go test -benchmem -bench . $(PKG)/benchmark + @go test -benchmem -tags use_ffjson -bench . $(PKG)/benchmark + @go test -benchmem -tags use_jsoniter -bench . $(PKG)/benchmark + @go test -benchmem -tags use_codec -bench . $(PKG)/benchmark + +bench-python: + benchmark/ujson.sh + + +.PHONY: root clean generate test build diff --git a/vendor/github.com/mailru/easyjson/README.md b/vendor/github.com/mailru/easyjson/README.md new file mode 100644 index 000000000..9366e3f71 --- /dev/null +++ b/vendor/github.com/mailru/easyjson/README.md @@ -0,0 +1,331 @@ +# easyjson [![Build Status](https://travis-ci.org/mailru/easyjson.svg?branch=master)](https://travis-ci.org/mailru/easyjson) [![Go Report Card](https://goreportcard.com/badge/github.com/mailru/easyjson)](https://goreportcard.com/report/github.com/mailru/easyjson) + +Package easyjson provides a fast and easy way to marshal/unmarshal Go structs +to/from JSON without the use of reflection. In performance tests, easyjson +outperforms the standard `encoding/json` package by a factor of 4-5x, and other +JSON encoding packages by a factor of 2-3x. + +easyjson aims to keep generated Go code simple enough so that it can be easily +optimized or fixed. Another goal is to provide users with the ability to +customize the generated code by providing options not available with the +standard `encoding/json` package, such as generating "snake_case" names or +enabling `omitempty` behavior by default. + +## Usage +```sh +# install +go get -u github.com/mailru/easyjson/... + +# run +easyjson -all .go +``` + +The above will generate `_easyjson.go` containing the appropriate marshaler and +unmarshaler funcs for all structs contained in `.go`. + +Please note that easyjson requires a full Go build environment and the `GOPATH` +environment variable to be set. This is because easyjson code generation +invokes `go run` on a temporary file (an approach to code generation borrowed +from [ffjson](https://github.com/pquerna/ffjson)). + +## Options +```txt +Usage of easyjson: + -all + generate marshaler/unmarshalers for all structs in a file + -build_tags string + build tags to add to generated file + -leave_temps + do not delete temporary files + -no_std_marshalers + don't generate MarshalJSON/UnmarshalJSON funcs + -noformat + do not run 'gofmt -w' on output file + -omit_empty + omit empty fields by default + -output_filename string + specify the filename of the output + -pkg + process the whole package instead of just the given file + -snake_case + use snake_case names instead of CamelCase by default + -lower_camel_case + use lowerCamelCase instead of CamelCase by default + -stubs + only generate stubs for marshaler/unmarshaler funcs +``` + +Using `-all` will generate marshalers/unmarshalers for all Go structs in the +file. If `-all` is not provided, then only those structs whose preceding +comment starts with `easyjson:json` will have marshalers/unmarshalers +generated. For example: + +```go +//easyjson:json +type A struct {} +``` + +Additional option notes: + +* `-snake_case` tells easyjson to generate snake\_case field names by default + (unless overridden by a field tag). The CamelCase to snake\_case conversion + algorithm should work in most cases (ie, HTTPVersion will be converted to + "http_version"). + +* `-build_tags` will add the specified build tags to generated Go sources. + +## Generated Marshaler/Unmarshaler Funcs + +For Go struct types, easyjson generates the funcs `MarshalEasyJSON` / +`UnmarshalEasyJSON` for marshaling/unmarshaling JSON. In turn, these satisify +the `easyjson.Marshaler` and `easyjson.Unmarshaler` interfaces and when used in +conjunction with `easyjson.Marshal` / `easyjson.Unmarshal` avoid unnecessary +reflection / type assertions during marshaling/unmarshaling to/from JSON for Go +structs. + +easyjson also generates `MarshalJSON` and `UnmarshalJSON` funcs for Go struct +types compatible with the standard `json.Marshaler` and `json.Unmarshaler` +interfaces. Please be aware that using the standard `json.Marshal` / +`json.Unmarshal` for marshaling/unmarshaling will incur a significant +performance penalty when compared to using `easyjson.Marshal` / +`easyjson.Unmarshal`. + +Additionally, easyjson exposes utility funcs that use the `MarshalEasyJSON` and +`UnmarshalEasyJSON` for marshaling/unmarshaling to and from standard readers +and writers. For example, easyjson provides `easyjson.MarshalToHTTPResponseWriter` +which marshals to the standard `http.ResponseWriter`. Please see the [GoDoc +listing](https://godoc.org/github.com/mailru/easyjson) for the full listing of +utility funcs that are available. + +## Controlling easyjson Marshaling and Unmarshaling Behavior + +Go types can provide their own `MarshalEasyJSON` and `UnmarshalEasyJSON` funcs +that satisify the `easyjson.Marshaler` / `easyjson.Unmarshaler` interfaces. +These will be used by `easyjson.Marshal` and `easyjson.Unmarshal` when defined +for a Go type. + +Go types can also satisify the `easyjson.Optional` interface, which allows the +type to define its own `omitempty` logic. + +## Type Wrappers + +easyjson provides additional type wrappers defined in the `easyjson/opt` +package. These wrap the standard Go primitives and in turn satisify the +easyjson interfaces. + +The `easyjson/opt` type wrappers are useful when needing to distinguish between +a missing value and/or when needing to specifying a default value. Type +wrappers allow easyjson to avoid additional pointers and heap allocations and +can significantly increase performance when used properly. + +## Memory Pooling + +easyjson uses a buffer pool that allocates data in increasing chunks from 128 +to 32768 bytes. Chunks of 512 bytes and larger will be reused with the help of +`sync.Pool`. The maximum size of a chunk is bounded to reduce redundant memory +allocation and to allow larger reusable buffers. + +easyjson's custom allocation buffer pool is defined in the `easyjson/buffer` +package, and the default behavior pool behavior can be modified (if necessary) +through a call to `buffer.Init()` prior to any marshaling or unmarshaling. +Please see the [GoDoc listing](https://godoc.org/github.com/mailru/easyjson/buffer) +for more information. + +## Issues, Notes, and Limitations + +* easyjson is still early in its development. As such, there are likely to be + bugs and missing features when compared to `encoding/json`. In the case of a + missing feature or bug, please create a GitHub issue. Pull requests are + welcome! + +* Unlike `encoding/json`, object keys are case-sensitive. Case-insensitive + matching is not currently provided due to the significant performance hit + when doing case-insensitive key matching. In the future, case-insensitive + object key matching may be provided via an option to the generator. + +* easyjson makes use of `unsafe`, which simplifies the code and + provides significant performance benefits by allowing no-copy + conversion from `[]byte` to `string`. That said, `unsafe` is used + only when unmarshaling and parsing JSON, and any `unsafe` operations + / memory allocations done will be safely deallocated by + easyjson. Set the build tag `easyjson_nounsafe` to compile it + without `unsafe`. + +* easyjson is compatible with Google App Engine. The `appengine` build + tag (set by App Engine's environment) will automatically disable the + use of `unsafe`, which is not allowed in App Engine's Standard + Environment. Note that the use with App Engine is still experimental. + +* Floats are formatted using the default precision from Go's `strconv` package. + As such, easyjson will not correctly handle high precision floats when + marshaling/unmarshaling JSON. Note, however, that there are very few/limited + uses where this behavior is not sufficient for general use. That said, a + different package may be needed if precise marshaling/unmarshaling of high + precision floats to/from JSON is required. + +* While unmarshaling, the JSON parser does the minimal amount of work needed to + skip over unmatching parens, and as such full validation is not done for the + entire JSON value being unmarshaled/parsed. + +* Currently there is no true streaming support for encoding/decoding as + typically for many uses/protocols the final, marshaled length of the JSON + needs to be known prior to sending the data. Currently this is not possible + with easyjson's architecture. + +## Benchmarks + +Most benchmarks were done using the example +[13kB example JSON](https://dev.twitter.com/rest/reference/get/search/tweets) +(9k after eliminating whitespace). This example is similar to real-world data, +is well-structured, and contains a healthy variety of different types, making +it ideal for JSON serialization benchmarks. + +Note: + +* For small request benchmarks, an 80 byte portion of the above example was + used. + +* For large request marshaling benchmarks, a struct containing 50 regular + samples was used, making a ~500kB output JSON. + +* Benchmarks are showing the results of easyjson's default behaviour, + which makes use of `unsafe`. + +Benchmarks are available in the repository and can be run by invoking `make`. + +### easyjson vs. encoding/json + +easyjson is roughly 5-6 times faster than the standard `encoding/json` for +unmarshaling, and 3-4 times faster for non-concurrent marshaling. Concurrent +marshaling is 6-7x faster if marshaling to a writer. + +### easyjson vs. ffjson + +easyjson uses the same approach for JSON marshaling as +[ffjson](https://github.com/pquerna/ffjson), but takes a significantly +different approach to lexing and parsing JSON during unmarshaling. This means +easyjson is roughly 2-3x faster for unmarshaling and 1.5-2x faster for +non-concurrent unmarshaling. + +As of this writing, `ffjson` seems to have issues when used concurrently: +specifically, large request pooling hurts `ffjson`'s performance and causes +scalability issues. These issues with `ffjson` can likely be fixed, but as of +writing remain outstanding/known issues with `ffjson`. + +easyjson and `ffjson` have similar performance for small requests, however +easyjson outperforms `ffjson` by roughly 2-5x times for large requests when +used with a writer. + +### easyjson vs. go/codec + +[go/codec](https://github.com/ugorji/go) provides +compile-time helpers for JSON generation. In this case, helpers do not work +like marshalers as they are encoding-independent. + +easyjson is generally 2x faster than `go/codec` for non-concurrent benchmarks +and about 3x faster for concurrent encoding (without marshaling to a writer). + +In an attempt to measure marshaling performance of `go/codec` (as opposed to +allocations/memcpy/writer interface invocations), a benchmark was done with +resetting length of a byte slice rather than resetting the whole slice to nil. +However, the optimization in this exact form may not be applicable in practice, +since the memory is not freed between marshaling operations. + +### easyjson vs 'ujson' python module + +[ujson](https://github.com/esnme/ultrajson) is using C code for parsing, so it +is interesting to see how plain golang compares to that. It is imporant to note +that the resulting object for python is slower to access, since the library +parses JSON object into dictionaries. + +easyjson is slightly faster for unmarshaling and 2-3x faster than `ujson` for +marshaling. + +### Benchmark Results + +`ffjson` results are from February 4th, 2016, using the latest `ffjson` and go1.6. +`go/codec` results are from March 4th, 2016, using the latest `go/codec` and go1.6. + +#### Unmarshaling + +| lib | json size | MB/s | allocs/op | B/op | +|:---------|:----------|-----:|----------:|------:| +| standard | regular | 22 | 218 | 10229 | +| standard | small | 9.7 | 14 | 720 | +| | | | | | +| easyjson | regular | 125 | 128 | 9794 | +| easyjson | small | 67 | 3 | 128 | +| | | | | | +| ffjson | regular | 66 | 141 | 9985 | +| ffjson | small | 17.6 | 10 | 488 | +| | | | | | +| codec | regular | 55 | 434 | 19299 | +| codec | small | 29 | 7 | 336 | +| | | | | | +| ujson | regular | 103 | N/A | N/A | + +#### Marshaling, one goroutine. + +| lib | json size | MB/s | allocs/op | B/op | +|:----------|:----------|-----:|----------:|------:| +| standard | regular | 75 | 9 | 23256 | +| standard | small | 32 | 3 | 328 | +| standard | large | 80 | 17 | 1.2M | +| | | | | | +| easyjson | regular | 213 | 9 | 10260 | +| easyjson* | regular | 263 | 8 | 742 | +| easyjson | small | 125 | 1 | 128 | +| easyjson | large | 212 | 33 | 490k | +| easyjson* | large | 262 | 25 | 2879 | +| | | | | | +| ffjson | regular | 122 | 153 | 21340 | +| ffjson** | regular | 146 | 152 | 4897 | +| ffjson | small | 36 | 5 | 384 | +| ffjson** | small | 64 | 4 | 128 | +| ffjson | large | 134 | 7317 | 818k | +| ffjson** | large | 125 | 7320 | 827k | +| | | | | | +| codec | regular | 80 | 17 | 33601 | +| codec*** | regular | 108 | 9 | 1153 | +| codec | small | 42 | 3 | 304 | +| codec*** | small | 56 | 1 | 48 | +| codec | large | 73 | 483 | 2.5M | +| codec*** | large | 103 | 451 | 66007 | +| | | | | | +| ujson | regular | 92 | N/A | N/A | + +\* marshaling to a writer, +\*\* using `ffjson.Pool()`, +\*\*\* reusing output slice instead of resetting it to nil + +#### Marshaling, concurrent. + +| lib | json size | MB/s | allocs/op | B/op | +|:----------|:----------|-----:|----------:|------:| +| standard | regular | 252 | 9 | 23257 | +| standard | small | 124 | 3 | 328 | +| standard | large | 289 | 17 | 1.2M | +| | | | | | +| easyjson | regular | 792 | 9 | 10597 | +| easyjson* | regular | 1748 | 8 | 779 | +| easyjson | small | 333 | 1 | 128 | +| easyjson | large | 718 | 36 | 548k | +| easyjson* | large | 2134 | 25 | 4957 | +| | | | | | +| ffjson | regular | 301 | 153 | 21629 | +| ffjson** | regular | 707 | 152 | 5148 | +| ffjson | small | 62 | 5 | 384 | +| ffjson** | small | 282 | 4 | 128 | +| ffjson | large | 438 | 7330 | 1.0M | +| ffjson** | large | 131 | 7319 | 820k | +| | | | | | +| codec | regular | 183 | 17 | 33603 | +| codec*** | regular | 671 | 9 | 1157 | +| codec | small | 147 | 3 | 304 | +| codec*** | small | 299 | 1 | 48 | +| codec | large | 190 | 483 | 2.5M | +| codec*** | large | 752 | 451 | 77574 | + +\* marshaling to a writer, +\*\* using `ffjson.Pool()`, +\*\*\* reusing output slice instead of resetting it to nil diff --git a/vendor/github.com/mailru/easyjson/buffer/pool_test.go b/vendor/github.com/mailru/easyjson/buffer/pool_test.go new file mode 100644 index 000000000..680623ace --- /dev/null +++ b/vendor/github.com/mailru/easyjson/buffer/pool_test.go @@ -0,0 +1,107 @@ +package buffer + +import ( + "bytes" + "testing" +) + +func TestAppendByte(t *testing.T) { + var b Buffer + var want []byte + + for i := 0; i < 1000; i++ { + b.AppendByte(1) + b.AppendByte(2) + want = append(want, 1, 2) + } + + got := b.BuildBytes() + if !bytes.Equal(got, want) { + t.Errorf("BuildBytes() = %v; want %v", got, want) + } +} + +func TestAppendBytes(t *testing.T) { + var b Buffer + var want []byte + + for i := 0; i < 1000; i++ { + b.AppendBytes([]byte{1, 2}) + want = append(want, 1, 2) + } + + got := b.BuildBytes() + if !bytes.Equal(got, want) { + t.Errorf("BuildBytes() = %v; want %v", got, want) + } +} + +func TestAppendString(t *testing.T) { + var b Buffer + var want []byte + + s := "test" + for i := 0; i < 1000; i++ { + b.AppendBytes([]byte(s)) + want = append(want, s...) + } + + got := b.BuildBytes() + if !bytes.Equal(got, want) { + t.Errorf("BuildBytes() = %v; want %v", got, want) + } +} + +func TestDumpTo(t *testing.T) { + var b Buffer + var want []byte + + s := "test" + for i := 0; i < 1000; i++ { + b.AppendBytes([]byte(s)) + want = append(want, s...) + } + + out := &bytes.Buffer{} + n, err := b.DumpTo(out) + if err != nil { + t.Errorf("DumpTo() error: %v", err) + } + + got := out.Bytes() + if !bytes.Equal(got, want) { + t.Errorf("DumpTo(): got %v; want %v", got, want) + } + + if n != len(want) { + t.Errorf("DumpTo() = %v; want %v", n, len(want)) + } +} + +func TestReadCloser(t *testing.T) { + var b Buffer + var want []byte + + s := "test" + for i := 0; i < 1000; i++ { + b.AppendBytes([]byte(s)) + want = append(want, s...) + } + + out := &bytes.Buffer{} + rc := b.ReadCloser() + n, err := out.ReadFrom(rc) + if err != nil { + t.Errorf("ReadCloser() error: %v", err) + } + rc.Close() // Will always return nil + + got := out.Bytes() + if !bytes.Equal(got, want) { + t.Errorf("DumpTo(): got %v; want %v", got, want) + } + + if n != int64(len(want)) { + t.Errorf("DumpTo() = %v; want %v", n, len(want)) + } +} diff --git a/vendor/github.com/mailru/easyjson/helpers.go b/vendor/github.com/mailru/easyjson/helpers.go new file mode 100644 index 000000000..b86b87d22 --- /dev/null +++ b/vendor/github.com/mailru/easyjson/helpers.go @@ -0,0 +1,78 @@ +// Package easyjson contains marshaler/unmarshaler interfaces and helper functions. +package easyjson + +import ( + "io" + "io/ioutil" + "net/http" + "strconv" + + "github.com/mailru/easyjson/jlexer" + "github.com/mailru/easyjson/jwriter" +) + +// Marshaler is an easyjson-compatible marshaler interface. +type Marshaler interface { + MarshalEasyJSON(w *jwriter.Writer) +} + +// Marshaler is an easyjson-compatible unmarshaler interface. +type Unmarshaler interface { + UnmarshalEasyJSON(w *jlexer.Lexer) +} + +// Optional defines an undefined-test method for a type to integrate with 'omitempty' logic. +type Optional interface { + IsDefined() bool +} + +// Marshal returns data as a single byte slice. Method is suboptimal as the data is likely to be copied +// from a chain of smaller chunks. +func Marshal(v Marshaler) ([]byte, error) { + w := jwriter.Writer{} + v.MarshalEasyJSON(&w) + return w.BuildBytes() +} + +// MarshalToWriter marshals the data to an io.Writer. +func MarshalToWriter(v Marshaler, w io.Writer) (written int, err error) { + jw := jwriter.Writer{} + v.MarshalEasyJSON(&jw) + return jw.DumpTo(w) +} + +// MarshalToHTTPResponseWriter sets Content-Length and Content-Type headers for the +// http.ResponseWriter, and send the data to the writer. started will be equal to +// false if an error occurred before any http.ResponseWriter methods were actually +// invoked (in this case a 500 reply is possible). +func MarshalToHTTPResponseWriter(v Marshaler, w http.ResponseWriter) (started bool, written int, err error) { + jw := jwriter.Writer{} + v.MarshalEasyJSON(&jw) + if jw.Error != nil { + return false, 0, jw.Error + } + w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Length", strconv.Itoa(jw.Size())) + + started = true + written, err = jw.DumpTo(w) + return +} + +// Unmarshal decodes the JSON in data into the object. +func Unmarshal(data []byte, v Unmarshaler) error { + l := jlexer.Lexer{Data: data} + v.UnmarshalEasyJSON(&l) + return l.Error() +} + +// UnmarshalFromReader reads all the data in the reader and decodes as JSON into the object. +func UnmarshalFromReader(r io.Reader, v Unmarshaler) error { + data, err := ioutil.ReadAll(r) + if err != nil { + return err + } + l := jlexer.Lexer{Data: data} + v.UnmarshalEasyJSON(&l) + return l.Error() +} diff --git a/vendor/github.com/mailru/easyjson/jlexer/lexer_test.go b/vendor/github.com/mailru/easyjson/jlexer/lexer_test.go new file mode 100644 index 000000000..529a270b8 --- /dev/null +++ b/vendor/github.com/mailru/easyjson/jlexer/lexer_test.go @@ -0,0 +1,314 @@ +package jlexer + +import ( + "bytes" + "encoding/json" + "reflect" + "testing" +) + +func TestString(t *testing.T) { + for i, test := range []struct { + toParse string + want string + wantError bool + }{ + {toParse: `"simple string"`, want: "simple string"}, + {toParse: " \r\r\n\t " + `"test"`, want: "test"}, + {toParse: `"\n\t\"\/\\\f\r"`, want: "\n\t\"/\\\f\r"}, + {toParse: `"\u0020"`, want: " "}, + {toParse: `"\u0020-\t"`, want: " -\t"}, + {toParse: `"\ufffd\uFFFD"`, want: "\ufffd\ufffd"}, + {toParse: `"\ud83d\ude00"`, want: "😀"}, + {toParse: `"\ud83d\ude08"`, want: "😈"}, + {toParse: `"\ud8"`, wantError: true}, + + {toParse: `"test"junk`, want: "test"}, + + {toParse: `5`, wantError: true}, // not a string + {toParse: `"\x"`, wantError: true}, // invalid escape + {toParse: `"\ud800"`, want: "�"}, // invalid utf-8 char; return replacement char + } { + l := Lexer{Data: []byte(test.toParse)} + + got := l.String() + if got != test.want { + t.Errorf("[%d, %q] String() = %v; want %v", i, test.toParse, got, test.want) + } + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] String() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] String() ok; want error", i, test.toParse) + } + } +} + +func TestBytes(t *testing.T) { + for i, test := range []struct { + toParse string + want string + wantError bool + }{ + {toParse: `"c2ltcGxlIHN0cmluZw=="`, want: "simple string"}, + {toParse: " \r\r\n\t " + `"dGVzdA=="`, want: "test"}, + + {toParse: `5`, wantError: true}, // not a JSON string + {toParse: `"foobar"`, wantError: true}, // not base64 encoded + {toParse: `"c2ltcGxlIHN0cmluZw="`, wantError: true}, // invalid base64 padding + } { + l := Lexer{Data: []byte(test.toParse)} + + got := l.Bytes() + if bytes.Compare(got, []byte(test.want)) != 0 { + t.Errorf("[%d, %q] Bytes() = %v; want: %v", i, test.toParse, got, []byte(test.want)) + } + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] Bytes() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] Bytes() ok; want error", i, test.toParse) + } + } +} + +func TestNumber(t *testing.T) { + for i, test := range []struct { + toParse string + want string + wantError bool + }{ + {toParse: "123", want: "123"}, + {toParse: "-123", want: "-123"}, + {toParse: "\r\n12.35", want: "12.35"}, + {toParse: "12.35e+1", want: "12.35e+1"}, + {toParse: "12.35e-15", want: "12.35e-15"}, + {toParse: "12.35E-15", want: "12.35E-15"}, + {toParse: "12.35E15", want: "12.35E15"}, + + {toParse: `"a"`, wantError: true}, + {toParse: "123junk", wantError: true}, + {toParse: "1.2.3", wantError: true}, + {toParse: "1e2e3", wantError: true}, + {toParse: "1e2.3", wantError: true}, + } { + l := Lexer{Data: []byte(test.toParse)} + + got := l.number() + if got != test.want { + t.Errorf("[%d, %q] number() = %v; want %v", i, test.toParse, got, test.want) + } + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] number() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] number() ok; want error", i, test.toParse) + } + } +} + +func TestBool(t *testing.T) { + for i, test := range []struct { + toParse string + want bool + wantError bool + }{ + {toParse: "true", want: true}, + {toParse: "false", want: false}, + + {toParse: "1", wantError: true}, + {toParse: "truejunk", wantError: true}, + {toParse: `false"junk"`, wantError: true}, + {toParse: "True", wantError: true}, + {toParse: "False", wantError: true}, + } { + l := Lexer{Data: []byte(test.toParse)} + + got := l.Bool() + if got != test.want { + t.Errorf("[%d, %q] Bool() = %v; want %v", i, test.toParse, got, test.want) + } + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] Bool() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] Bool() ok; want error", i, test.toParse) + } + } +} + +func TestSkipRecursive(t *testing.T) { + for i, test := range []struct { + toParse string + left string + wantError bool + }{ + {toParse: "5, 4", left: ", 4"}, + {toParse: "[5, 6], 4", left: ", 4"}, + {toParse: "[5, [7,8]]: 4", left: ": 4"}, + + {toParse: `{"a":1}, 4`, left: ", 4"}, + {toParse: `{"a":1, "b":{"c": 5}, "e":[12,15]}, 4`, left: ", 4"}, + + // array start/end chars in a string + {toParse: `[5, "]"], 4`, left: ", 4"}, + {toParse: `[5, "\"]"], 4`, left: ", 4"}, + {toParse: `[5, "["], 4`, left: ", 4"}, + {toParse: `[5, "\"["], 4`, left: ", 4"}, + + // object start/end chars in a string + {toParse: `{"a}":1}, 4`, left: ", 4"}, + {toParse: `{"a\"}":1}, 4`, left: ", 4"}, + {toParse: `{"a{":1}, 4`, left: ", 4"}, + {toParse: `{"a\"{":1}, 4`, left: ", 4"}, + + // object with double slashes at the end of string + {toParse: `{"a":"hey\\"}, 4`, left: ", 4"}, + } { + l := Lexer{Data: []byte(test.toParse)} + + l.SkipRecursive() + + got := string(l.Data[l.pos:]) + if got != test.left { + t.Errorf("[%d, %q] SkipRecursive() left = %v; want %v", i, test.toParse, got, test.left) + } + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] SkipRecursive() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] SkipRecursive() ok; want error", i, test.toParse) + } + } +} + +func TestInterface(t *testing.T) { + for i, test := range []struct { + toParse string + want interface{} + wantError bool + }{ + {toParse: "null", want: nil}, + {toParse: "true", want: true}, + {toParse: `"a"`, want: "a"}, + {toParse: "5", want: float64(5)}, + + {toParse: `{}`, want: map[string]interface{}{}}, + {toParse: `[]`, want: []interface{}(nil)}, + + {toParse: `{"a": "b"}`, want: map[string]interface{}{"a": "b"}}, + {toParse: `[5]`, want: []interface{}{float64(5)}}, + + {toParse: `{"a":5 , "b" : "string"}`, want: map[string]interface{}{"a": float64(5), "b": "string"}}, + {toParse: `["a", 5 , null, true]`, want: []interface{}{"a", float64(5), nil, true}}, + + {toParse: `{"a" "b"}`, wantError: true}, + {toParse: `{"a": "b",}`, wantError: true}, + {toParse: `{"a":"b","c" "b"}`, wantError: true}, + {toParse: `{"a": "b","c":"d",}`, wantError: true}, + {toParse: `{,}`, wantError: true}, + + {toParse: `[1, 2,]`, wantError: true}, + {toParse: `[1 2]`, wantError: true}, + {toParse: `[,]`, wantError: true}, + } { + l := Lexer{Data: []byte(test.toParse)} + + got := l.Interface() + if !reflect.DeepEqual(got, test.want) { + t.Errorf("[%d, %q] Interface() = %v; want %v", i, test.toParse, got, test.want) + } + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] Interface() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] Interface() ok; want error", i, test.toParse) + } + } +} + +func TestConsumed(t *testing.T) { + for i, test := range []struct { + toParse string + wantError bool + }{ + {toParse: "", wantError: false}, + {toParse: " ", wantError: false}, + {toParse: "\r\n", wantError: false}, + {toParse: "\t\t", wantError: false}, + + {toParse: "{", wantError: true}, + } { + l := Lexer{Data: []byte(test.toParse)} + l.Consumed() + + err := l.Error() + if err != nil && !test.wantError { + t.Errorf("[%d, %q] Consumed() error: %v", i, test.toParse, err) + } else if err == nil && test.wantError { + t.Errorf("[%d, %q] Consumed() ok; want error", i, test.toParse) + } + } +} + +func TestJsonNumber(t *testing.T) { + for i, test := range []struct { + toParse string + want json.Number + wantLexerError bool + wantValue interface{} + wantValueError bool + }{ + {toParse: `10`, want: json.Number("10"), wantValue: int64(10)}, + {toParse: `0`, want: json.Number("0"), wantValue: int64(0)}, + {toParse: `0.12`, want: json.Number("0.12"), wantValue: 0.12}, + {toParse: `25E-4`, want: json.Number("25E-4"), wantValue: 25E-4}, + + {toParse: `"10"`, want: json.Number("10"), wantValue: int64(10)}, + {toParse: `"0"`, want: json.Number("0"), wantValue: int64(0)}, + {toParse: `"0.12"`, want: json.Number("0.12"), wantValue: 0.12}, + {toParse: `"25E-4"`, want: json.Number("25E-4"), wantValue: 25E-4}, + + {toParse: `"foo"`, want: json.Number("foo"), wantValueError: true}, + {toParse: `null`, want: json.Number(""), wantValueError: true}, + + {toParse: `"a""`, want: json.Number("a"), wantValueError: true}, + + {toParse: `[1]`, want: json.Number(""), wantLexerError: true, wantValueError: true}, + {toParse: `{}`, want: json.Number(""), wantLexerError: true, wantValueError: true}, + {toParse: `a`, want: json.Number(""), wantLexerError: true, wantValueError: true}, + } { + l := Lexer{Data: []byte(test.toParse)} + + got := l.JsonNumber() + if got != test.want { + t.Errorf("[%d, %q] JsonNumber() = %v; want %v", i, test.toParse, got, test.want) + } + + err := l.Error() + if err != nil && !test.wantLexerError { + t.Errorf("[%d, %q] JsonNumber() lexer error: %v", i, test.toParse, err) + } else if err == nil && test.wantLexerError { + t.Errorf("[%d, %q] JsonNumber() ok; want lexer error", i, test.toParse) + } + + var valueErr error + var gotValue interface{} + switch test.wantValue.(type) { + case float64: + gotValue, valueErr = got.Float64() + default: + gotValue, valueErr = got.Int64() + } + + if !reflect.DeepEqual(gotValue, test.wantValue) && !test.wantLexerError && !test.wantValueError { + t.Errorf("[%d, %q] JsonNumber() = %v; want %v", i, test.toParse, gotValue, test.wantValue) + } + + if valueErr != nil && !test.wantValueError { + t.Errorf("[%d, %q] JsonNumber() value error: %v", i, test.toParse, valueErr) + } else if valueErr == nil && test.wantValueError { + t.Errorf("[%d, %q] JsonNumber() ok; want value error", i, test.toParse) + } + } +} diff --git a/vendor/github.com/mailru/easyjson/raw.go b/vendor/github.com/mailru/easyjson/raw.go new file mode 100644 index 000000000..81bd002e1 --- /dev/null +++ b/vendor/github.com/mailru/easyjson/raw.go @@ -0,0 +1,45 @@ +package easyjson + +import ( + "github.com/mailru/easyjson/jlexer" + "github.com/mailru/easyjson/jwriter" +) + +// RawMessage is a raw piece of JSON (number, string, bool, object, array or +// null) that is extracted without parsing and output as is during marshaling. +type RawMessage []byte + +// MarshalEasyJSON does JSON marshaling using easyjson interface. +func (v *RawMessage) MarshalEasyJSON(w *jwriter.Writer) { + if len(*v) == 0 { + w.RawString("null") + } else { + w.Raw(*v, nil) + } +} + +// UnmarshalEasyJSON does JSON unmarshaling using easyjson interface. +func (v *RawMessage) UnmarshalEasyJSON(l *jlexer.Lexer) { + *v = RawMessage(l.Raw()) +} + +// UnmarshalJSON implements encoding/json.Unmarshaler interface. +func (v *RawMessage) UnmarshalJSON(data []byte) error { + *v = data + return nil +} + +var nullBytes = []byte("null") + +// MarshalJSON implements encoding/json.Marshaler interface. +func (v RawMessage) MarshalJSON() ([]byte, error) { + if len(v) == 0 { + return nullBytes, nil + } + return v, nil +} + +// IsDefined is required for integration with omitempty easyjson logic. +func (v *RawMessage) IsDefined() bool { + return len(*v) > 0 +} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/.travis.yml b/vendor/github.com/matttproud/golang_protobuf_extensions/.travis.yml new file mode 100644 index 000000000..f1309c9f8 --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/.travis.yml @@ -0,0 +1,2 @@ +language: go + diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/README.md b/vendor/github.com/matttproud/golang_protobuf_extensions/README.md new file mode 100644 index 000000000..751ee6967 --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/README.md @@ -0,0 +1,20 @@ +# Overview +This repository provides various Protocol Buffer extensions for the Go +language (golang), namely support for record length-delimited message +streaming. + +| Java | Go | +| ------------------------------ | --------------------- | +| MessageLite#parseDelimitedFrom | pbutil.ReadDelimited | +| MessageLite#writeDelimitedTo | pbutil.WriteDelimited | + +Because [Code Review 9102043](https://codereview.appspot.com/9102043/) is +destined to never be merged into mainline (i.e., never be promoted to formal +[goprotobuf features](https://github.com/golang/protobuf)), this repository +will live here in the wild. + +# Documentation +We have [generated Go Doc documentation](http://godoc.org/github.com/matttproud/golang_protobuf_extensions/pbutil) here. + +# Testing +[![Build Status](https://travis-ci.org/matttproud/golang_protobuf_extensions.png?branch=master)](https://travis-ci.org/matttproud/golang_protobuf_extensions) diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/all_test.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/all_test.go new file mode 100644 index 000000000..5c463722d --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/all_test.go @@ -0,0 +1,177 @@ +// Copyright 2013 Matt T. Proud +// +// 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 pbutil + +import ( + "bytes" + "testing" + + . "github.com/golang/protobuf/proto" + . "github.com/golang/protobuf/proto/testdata" +) + +func TestWriteDelimited(t *testing.T) { + t.Parallel() + for _, test := range []struct { + msg Message + buf []byte + n int + err error + }{ + { + msg: &Empty{}, + n: 1, + buf: []byte{0}, + }, + { + msg: &GoEnum{Foo: FOO_FOO1.Enum()}, + n: 3, + buf: []byte{2, 8, 1}, + }, + { + msg: &Strings{ + StringField: String(`This is my gigantic, unhappy string. It exceeds +the encoding size of a single byte varint. We are using it to fuzz test the +correctness of the header decoding mechanisms, which may prove problematic. +I expect it may. Let's hope you enjoy testing as much as we do.`), + }, + n: 271, + buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109, + 121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104, + 97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73, + 116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101, + 110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102, + 32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32, + 118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32, + 117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122, + 122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114, + 101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32, + 104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103, + 32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104, + 105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112, + 114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120, + 112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101, + 116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110, + 106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32, + 109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46}, + }, + } { + var buf bytes.Buffer + if n, err := WriteDelimited(&buf, test.msg); n != test.n || err != test.err { + t.Fatalf("WriteDelimited(buf, %#v) = %v, %v; want %v, %v", test.msg, n, err, test.n, test.err) + } + if out := buf.Bytes(); !bytes.Equal(out, test.buf) { + t.Fatalf("WriteDelimited(buf, %#v); buf = %v; want %v", test.msg, out, test.buf) + } + } +} + +func TestReadDelimited(t *testing.T) { + t.Parallel() + for _, test := range []struct { + buf []byte + msg Message + n int + err error + }{ + { + buf: []byte{0}, + msg: &Empty{}, + n: 1, + }, + { + n: 3, + buf: []byte{2, 8, 1}, + msg: &GoEnum{Foo: FOO_FOO1.Enum()}, + }, + { + buf: []byte{141, 2, 10, 138, 2, 84, 104, 105, 115, 32, 105, 115, 32, 109, + 121, 32, 103, 105, 103, 97, 110, 116, 105, 99, 44, 32, 117, 110, 104, + 97, 112, 112, 121, 32, 115, 116, 114, 105, 110, 103, 46, 32, 32, 73, + 116, 32, 101, 120, 99, 101, 101, 100, 115, 10, 116, 104, 101, 32, 101, + 110, 99, 111, 100, 105, 110, 103, 32, 115, 105, 122, 101, 32, 111, 102, + 32, 97, 32, 115, 105, 110, 103, 108, 101, 32, 98, 121, 116, 101, 32, + 118, 97, 114, 105, 110, 116, 46, 32, 32, 87, 101, 32, 97, 114, 101, 32, + 117, 115, 105, 110, 103, 32, 105, 116, 32, 116, 111, 32, 102, 117, 122, + 122, 32, 116, 101, 115, 116, 32, 116, 104, 101, 10, 99, 111, 114, 114, + 101, 99, 116, 110, 101, 115, 115, 32, 111, 102, 32, 116, 104, 101, 32, + 104, 101, 97, 100, 101, 114, 32, 100, 101, 99, 111, 100, 105, 110, 103, + 32, 109, 101, 99, 104, 97, 110, 105, 115, 109, 115, 44, 32, 119, 104, + 105, 99, 104, 32, 109, 97, 121, 32, 112, 114, 111, 118, 101, 32, 112, + 114, 111, 98, 108, 101, 109, 97, 116, 105, 99, 46, 10, 73, 32, 101, 120, + 112, 101, 99, 116, 32, 105, 116, 32, 109, 97, 121, 46, 32, 32, 76, 101, + 116, 39, 115, 32, 104, 111, 112, 101, 32, 121, 111, 117, 32, 101, 110, + 106, 111, 121, 32, 116, 101, 115, 116, 105, 110, 103, 32, 97, 115, 32, + 109, 117, 99, 104, 32, 97, 115, 32, 119, 101, 32, 100, 111, 46}, + msg: &Strings{ + StringField: String(`This is my gigantic, unhappy string. It exceeds +the encoding size of a single byte varint. We are using it to fuzz test the +correctness of the header decoding mechanisms, which may prove problematic. +I expect it may. Let's hope you enjoy testing as much as we do.`), + }, + n: 271, + }, + } { + msg := Clone(test.msg) + msg.Reset() + if n, err := ReadDelimited(bytes.NewBuffer(test.buf), msg); n != test.n || err != test.err { + t.Fatalf("ReadDelimited(%v, msg) = %v, %v; want %v, %v", test.buf, n, err, test.n, test.err) + } + if !Equal(msg, test.msg) { + t.Fatalf("ReadDelimited(%v, msg); msg = %v; want %v", test.buf, msg, test.msg) + } + } +} + +func TestEndToEndValid(t *testing.T) { + t.Parallel() + for _, test := range [][]Message{ + {&Empty{}}, + {&GoEnum{Foo: FOO_FOO1.Enum()}, &Empty{}, &GoEnum{Foo: FOO_FOO1.Enum()}}, + {&GoEnum{Foo: FOO_FOO1.Enum()}}, + {&Strings{ + StringField: String(`This is my gigantic, unhappy string. It exceeds +the encoding size of a single byte varint. We are using it to fuzz test the +correctness of the header decoding mechanisms, which may prove problematic. +I expect it may. Let's hope you enjoy testing as much as we do.`), + }}, + } { + var buf bytes.Buffer + var written int + for i, msg := range test { + n, err := WriteDelimited(&buf, msg) + if err != nil { + // Assumption: TestReadDelimited and TestWriteDelimited are sufficient + // and inputs for this test are explicitly exercised there. + t.Fatalf("WriteDelimited(buf, %v[%d]) = ?, %v; wanted ?, nil", test, i, err) + } + written += n + } + var read int + for i, msg := range test { + out := Clone(msg) + out.Reset() + n, _ := ReadDelimited(&buf, out) + // Decide to do EOF checking? + read += n + if !Equal(out, msg) { + t.Fatalf("out = %v; want %v[%d] = %#v", out, test, i, msg) + } + } + if read != written { + t.Fatalf("%v read = %d; want %d", test, read, written) + } + } +} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode_test.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode_test.go new file mode 100644 index 000000000..364a7b799 --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode_test.go @@ -0,0 +1,99 @@ +// Copyright 2016 Matt T. Proud +// +// 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 pbutil + +import ( + "bytes" + "io" + "testing" + "testing/iotest" +) + +func TestReadDelimitedIllegalVarint(t *testing.T) { + t.Parallel() + var tests = []struct { + in []byte + n int + err error + }{ + { + in: []byte{255, 255, 255, 255, 255}, + n: 5, + err: errInvalidVarint, + }, + { + in: []byte{255, 255, 255, 255, 255, 255}, + n: 5, + err: errInvalidVarint, + }, + } + for _, test := range tests { + n, err := ReadDelimited(bytes.NewReader(test.in), nil) + if got, want := n, test.n; got != want { + t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", test.in, got, want) + } + if got, want := err, test.err; got != want { + t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", test.in, got, want) + } + } +} + +func TestReadDelimitedPrematureHeader(t *testing.T) { + t.Parallel() + var data = []byte{128, 5} // 256 + 256 + 128 + n, err := ReadDelimited(bytes.NewReader(data[0:1]), nil) + if got, want := n, 1; got != want { + t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data[0:1], got, want) + } + if got, want := err, io.EOF; got != want { + t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data[0:1], got, want) + } +} + +func TestReadDelimitedPrematureBody(t *testing.T) { + t.Parallel() + var data = []byte{128, 5, 0, 0, 0} // 256 + 256 + 128 + n, err := ReadDelimited(bytes.NewReader(data[:]), nil) + if got, want := n, 5; got != want { + t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data, got, want) + } + if got, want := err, io.ErrUnexpectedEOF; got != want { + t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data, got, want) + } +} + +func TestReadDelimitedPrematureHeaderIncremental(t *testing.T) { + t.Parallel() + var data = []byte{128, 5} // 256 + 256 + 128 + n, err := ReadDelimited(iotest.OneByteReader(bytes.NewReader(data[0:1])), nil) + if got, want := n, 1; got != want { + t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data[0:1], got, want) + } + if got, want := err, io.EOF; got != want { + t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data[0:1], got, want) + } +} + +func TestReadDelimitedPrematureBodyIncremental(t *testing.T) { + t.Parallel() + var data = []byte{128, 5, 0, 0, 0} // 256 + 256 + 128 + n, err := ReadDelimited(iotest.OneByteReader(bytes.NewReader(data[:])), nil) + if got, want := n, 5; got != want { + t.Errorf("ReadDelimited(%#v, nil) = %#v, ?; want = %v#, ?", data, got, want) + } + if got, want := err, io.ErrUnexpectedEOF; got != want { + t.Errorf("ReadDelimited(%#v, nil) = ?, %#v; want = ?, %#v", data, got, want) + } +} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode_test.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode_test.go new file mode 100644 index 000000000..f92632b0b --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode_test.go @@ -0,0 +1,67 @@ +// Copyright 2016 Matt T. Proud +// +// 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 pbutil + +import ( + "bytes" + "errors" + "testing" + + "github.com/golang/protobuf/proto" +) + +var errMarshal = errors.New("pbutil: can't marshal") + +type cantMarshal struct{ proto.Message } + +func (cantMarshal) Marshal() ([]byte, error) { return nil, errMarshal } + +var _ proto.Message = cantMarshal{} + +func TestWriteDelimitedMarshalErr(t *testing.T) { + t.Parallel() + var data cantMarshal + var buf bytes.Buffer + n, err := WriteDelimited(&buf, data) + if got, want := n, 0; got != want { + t.Errorf("WriteDelimited(buf, %#v) = %#v, ?; want = %v#, ?", data, got, want) + } + if got, want := err, errMarshal; got != want { + t.Errorf("WriteDelimited(buf, %#v) = ?, %#v; want = ?, %#v", data, got, want) + } +} + +type canMarshal struct{ proto.Message } + +func (canMarshal) Marshal() ([]byte, error) { return []byte{0, 1, 2, 3, 4, 5}, nil } + +var errWrite = errors.New("pbutil: can't write") + +type cantWrite struct{} + +func (cantWrite) Write([]byte) (int, error) { return 0, errWrite } + +func TestWriteDelimitedWriteErr(t *testing.T) { + t.Parallel() + var data canMarshal + var buf cantWrite + n, err := WriteDelimited(buf, data) + if got, want := n, 0; got != want { + t.Errorf("WriteDelimited(buf, %#v) = %#v, ?; want = %v#, ?", data, got, want) + } + if got, want := err, errWrite; got != want { + t.Errorf("WriteDelimited(buf, %#v) = ?, %#v; want = ?, %#v", data, got, want) + } +} diff --git a/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/fixtures_test.go b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/fixtures_test.go new file mode 100644 index 000000000..d6d9b2559 --- /dev/null +++ b/vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/fixtures_test.go @@ -0,0 +1,103 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// http://github.com/golang/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package pbutil + +import ( + . "github.com/golang/protobuf/proto" + . "github.com/golang/protobuf/proto/testdata" +) + +// FROM https://github.com/golang/protobuf/blob/master/proto/all_test.go. + +func initGoTestField() *GoTestField { + f := new(GoTestField) + f.Label = String("label") + f.Type = String("type") + return f +} + +// These are all structurally equivalent but the tag numbers differ. +// (It's remarkable that required, optional, and repeated all have +// 8 letters.) +func initGoTest_RequiredGroup() *GoTest_RequiredGroup { + return &GoTest_RequiredGroup{ + RequiredField: String("required"), + } +} + +func initGoTest_OptionalGroup() *GoTest_OptionalGroup { + return &GoTest_OptionalGroup{ + RequiredField: String("optional"), + } +} + +func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup { + return &GoTest_RepeatedGroup{ + RequiredField: String("repeated"), + } +} + +func initGoTest(setdefaults bool) *GoTest { + pb := new(GoTest) + if setdefaults { + pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted) + pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted) + pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted) + pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted) + pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted) + pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted) + pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted) + pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted) + pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted) + pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted) + pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted + pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted) + pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted) + } + + pb.Kind = GoTest_TIME.Enum() + pb.RequiredField = initGoTestField() + pb.F_BoolRequired = Bool(true) + pb.F_Int32Required = Int32(3) + pb.F_Int64Required = Int64(6) + pb.F_Fixed32Required = Uint32(32) + pb.F_Fixed64Required = Uint64(64) + pb.F_Uint32Required = Uint32(3232) + pb.F_Uint64Required = Uint64(6464) + pb.F_FloatRequired = Float32(3232) + pb.F_DoubleRequired = Float64(6464) + pb.F_StringRequired = String("string") + pb.F_BytesRequired = []byte("bytes") + pb.F_Sint32Required = Int32(-32) + pb.F_Sint64Required = Int64(-64) + pb.Requiredgroup = initGoTest_RequiredGroup() + + return pb +} diff --git a/vendor/github.com/modern-go/concurrent/.gitignore b/vendor/github.com/modern-go/concurrent/.gitignore new file mode 100644 index 000000000..3f2bc4741 --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/.gitignore @@ -0,0 +1 @@ +/coverage.txt diff --git a/vendor/github.com/modern-go/concurrent/.travis.yml b/vendor/github.com/modern-go/concurrent/.travis.yml new file mode 100644 index 000000000..449e67cd0 --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/.travis.yml @@ -0,0 +1,14 @@ +language: go + +go: + - 1.8.x + - 1.x + +before_install: + - go get -t -v ./... + +script: + - ./test.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/modern-go/concurrent/README.md b/vendor/github.com/modern-go/concurrent/README.md new file mode 100644 index 000000000..acab3200a --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/README.md @@ -0,0 +1,49 @@ +# concurrent + +[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/concurrent/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/concurrent?badge) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/concurrent) +[![Build Status](https://travis-ci.org/modern-go/concurrent.svg?branch=master)](https://travis-ci.org/modern-go/concurrent) +[![codecov](https://codecov.io/gh/modern-go/concurrent/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/concurrent) +[![rcard](https://goreportcard.com/badge/github.com/modern-go/concurrent)](https://goreportcard.com/report/github.com/modern-go/concurrent) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/concurrent/master/LICENSE) + +* concurrent.Map: backport sync.Map for go below 1.9 +* concurrent.Executor: goroutine with explicit ownership and cancellable + +# concurrent.Map + +because sync.Map is only available in go 1.9, we can use concurrent.Map to make code portable + +```go +m := concurrent.NewMap() +m.Store("hello", "world") +elem, found := m.Load("hello") +// elem will be "world" +// found will be true +``` + +# concurrent.Executor + +```go +executor := concurrent.NewUnboundedExecutor() +executor.Go(func(ctx context.Context) { + everyMillisecond := time.NewTicker(time.Millisecond) + for { + select { + case <-ctx.Done(): + fmt.Println("goroutine exited") + return + case <-everyMillisecond.C: + // do something + } + } +}) +time.Sleep(time.Second) +executor.StopAndWaitForever() +fmt.Println("executor stopped") +``` + +attach goroutine to executor instance, so that we can + +* cancel it by stop the executor with Stop/StopAndWait/StopAndWaitForever +* handle panic by callback: the default behavior will no longer crash your application \ No newline at end of file diff --git a/vendor/github.com/modern-go/concurrent/map_test.go b/vendor/github.com/modern-go/concurrent/map_test.go new file mode 100644 index 000000000..16ba3e5f7 --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/map_test.go @@ -0,0 +1,18 @@ +package concurrent_test + +import ( + "github.com/modern-go/concurrent" + "testing" +) + +func TestMap_Load(t *testing.T) { + m := concurrent.NewMap() + m.Store("hello", "world") + value, found := m.Load("hello") + if !found { + t.Fail() + } + if value != "world" { + t.Fail() + } +} diff --git a/vendor/github.com/modern-go/concurrent/test.sh b/vendor/github.com/modern-go/concurrent/test.sh new file mode 100755 index 000000000..d1e6b2ec5 --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e +echo "" > coverage.txt + +for d in $(go list ./... | grep -v vendor); do + go test -coverprofile=profile.out -coverpkg=github.com/modern-go/concurrent $d + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done diff --git a/vendor/github.com/modern-go/concurrent/unbounded_executor_test.go b/vendor/github.com/modern-go/concurrent/unbounded_executor_test.go new file mode 100644 index 000000000..fe86e84a3 --- /dev/null +++ b/vendor/github.com/modern-go/concurrent/unbounded_executor_test.go @@ -0,0 +1,54 @@ +package concurrent_test + +import ( + "context" + "fmt" + "time" + "github.com/modern-go/concurrent" +) + +func ExampleUnboundedExecutor_Go() { + executor := concurrent.NewUnboundedExecutor() + executor.Go(func(ctx context.Context) { + fmt.Println("abc") + }) + time.Sleep(time.Second) + // output: abc +} + +func ExampleUnboundedExecutor_StopAndWaitForever() { + executor := concurrent.NewUnboundedExecutor() + executor.Go(func(ctx context.Context) { + everyMillisecond := time.NewTicker(time.Millisecond) + for { + select { + case <-ctx.Done(): + fmt.Println("goroutine exited") + return + case <-everyMillisecond.C: + // do something + } + } + }) + time.Sleep(time.Second) + executor.StopAndWaitForever() + fmt.Println("executor stopped") + // output: + // goroutine exited + // executor stopped +} + +func ExampleUnboundedExecutor_Go_panic() { + concurrent.HandlePanic = func(recovered interface{}, funcName string) { + fmt.Println(funcName) + } + executor := concurrent.NewUnboundedExecutor() + executor.Go(willPanic) + time.Sleep(time.Second) + // output: + // github.com/modern-go/concurrent_test.willPanic +} + +func willPanic(ctx context.Context) { + panic("!!!") +} diff --git a/vendor/github.com/modern-go/reflect2/.gitignore b/vendor/github.com/modern-go/reflect2/.gitignore new file mode 100644 index 000000000..7b26c946d --- /dev/null +++ b/vendor/github.com/modern-go/reflect2/.gitignore @@ -0,0 +1,2 @@ +/vendor +/coverage.txt diff --git a/vendor/github.com/modern-go/reflect2/.travis.yml b/vendor/github.com/modern-go/reflect2/.travis.yml new file mode 100644 index 000000000..fbb43744d --- /dev/null +++ b/vendor/github.com/modern-go/reflect2/.travis.yml @@ -0,0 +1,15 @@ +language: go + +go: + - 1.8.x + - 1.x + +before_install: + - go get -t -v ./... + - go get -t -v github.com/modern-go/reflect2-tests/... + +script: + - ./test.sh + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/modern-go/reflect2/Gopkg.lock b/vendor/github.com/modern-go/reflect2/Gopkg.lock new file mode 100644 index 000000000..2a3a69893 --- /dev/null +++ b/vendor/github.com/modern-go/reflect2/Gopkg.lock @@ -0,0 +1,15 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/modern-go/concurrent" + packages = ["."] + revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a" + version = "1.0.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "daee8a88b3498b61c5640056665b8b9eea062006f5e596bbb6a3ed9119a11ec7" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/modern-go/reflect2/Gopkg.toml b/vendor/github.com/modern-go/reflect2/Gopkg.toml new file mode 100644 index 000000000..2f4f4dbdc --- /dev/null +++ b/vendor/github.com/modern-go/reflect2/Gopkg.toml @@ -0,0 +1,35 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# 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 + +ignored = [] + +[[constraint]] + name = "github.com/modern-go/concurrent" + version = "1.0.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/modern-go/reflect2/README.md b/vendor/github.com/modern-go/reflect2/README.md new file mode 100644 index 000000000..6f968aab9 --- /dev/null +++ b/vendor/github.com/modern-go/reflect2/README.md @@ -0,0 +1,71 @@ +# reflect2 + +[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/reflect2/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/reflect2?badge) +[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/reflect2) +[![Build Status](https://travis-ci.org/modern-go/reflect2.svg?branch=master)](https://travis-ci.org/modern-go/reflect2) +[![codecov](https://codecov.io/gh/modern-go/reflect2/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/reflect2) +[![rcard](https://goreportcard.com/badge/github.com/modern-go/reflect2)](https://goreportcard.com/report/github.com/modern-go/reflect2) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/reflect2/master/LICENSE) + +reflect api that avoids runtime reflect.Value cost + +* reflect get/set interface{}, with type checking +* reflect get/set unsafe.Pointer, without type checking +* `reflect2.TypeByName` works like `Class.forName` found in java + +[json-iterator](https://github.com/json-iterator/go) use this package to save runtime dispatching cost. +This package is designed for low level libraries to optimize reflection performance. +General application should still use reflect standard library. + +# reflect2.TypeByName + +```go +// given package is github.com/your/awesome-package +type MyStruct struct { + // ... +} + +// will return the type +reflect2.TypeByName("awesome-package.MyStruct") +// however, if the type has not been used +// it will be eliminated by compiler, so we can not get it in runtime +``` + +# reflect2 get/set interface{} + +```go +valType := reflect2.TypeOf(1) +i := 1 +j := 10 +valType.Set(&i, &j) +// i will be 10 +``` + +to get set `type`, always use its pointer `*type` + +# reflect2 get/set unsafe.Pointer + +```go +valType := reflect2.TypeOf(1) +i := 1 +j := 10 +valType.UnsafeSet(unsafe.Pointer(&i), unsafe.Pointer(&j)) +// i will be 10 +``` + +to get set `type`, always use its pointer `*type` + +# benchmark + +Benchmark is not necessary for this package. It does nothing actually. +As it is just a thin wrapper to make go runtime public. +Both `reflect2` and `reflect` call same function +provided by `runtime` package exposed by go language. + +# unsafe safety + +Instead of casting `[]byte` to `sliceHeader` in your application using unsafe. +We can use reflect2 instead. This way, if `sliceHeader` changes in the future, +only reflect2 need to be upgraded. + +reflect2 tries its best to keep the implementation same as reflect (by testing). \ No newline at end of file diff --git a/vendor/github.com/modern-go/reflect2/test.sh b/vendor/github.com/modern-go/reflect2/test.sh new file mode 100755 index 000000000..3d2b9768c --- /dev/null +++ b/vendor/github.com/modern-go/reflect2/test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e +echo "" > coverage.txt + +for d in $(go list github.com/modern-go/reflect2-tests/... | grep -v vendor); do + go test -coverprofile=profile.out -coverpkg=github.com/modern-go/reflect2 $d + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi +done diff --git a/vendor/github.com/onsi/ginkgo/.gitignore b/vendor/github.com/onsi/ginkgo/.gitignore new file mode 100644 index 000000000..f69b042c3 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +TODO +tmp/**/* +*.coverprofile +.vscode +.idea/ \ No newline at end of file diff --git a/vendor/github.com/onsi/ginkgo/.travis.yml b/vendor/github.com/onsi/ginkgo/.travis.yml new file mode 100644 index 000000000..7ad39b78f --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/.travis.yml @@ -0,0 +1,16 @@ +language: go +go: + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + +install: + - go get -v -t ./... + - go get golang.org/x/tools/cmd/cover + - go get github.com/onsi/gomega + - go install github.com/onsi/ginkgo/ginkgo + - export PATH=$PATH:$HOME/gopath/bin + +script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace && go vet diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md new file mode 100644 index 000000000..b7e787d5b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md @@ -0,0 +1,183 @@ +## 1.5.0 5/10/2018 + +### New Features +- Supports go v1.10 (#443, #446, #451) [e873237, 468e89e, e37dbfe, a37f4c0, c0b857d, bca5260, 4177ca8] +- Add a When() synonym for Context() (#386) [747514b, 7484dad, 7354a07, dd826c8] +- Re-add noisySkippings flag [652e15c] +- Allow coverage to be displayed for focused specs (#367) [11459a8] +- Handle -outputdir flag (#364) [228e3a8] +- Handle -coverprofile flag (#355) [43392d5] + +### Fixes +- When using custom reporters register the custom reporters *before* the default reporter. This allows users to see the output of any print statements in their customer reporters. (#365) [8382b23] +- When running a test and calculating the coverage using the `-coverprofile` and `-outputdir` flags, Ginkgo fails with an error if the directory does not exist. This is due to an [issue in go 1.10](https://github.com/golang/go/issues/24588) (#446) [b36a6e0] +- `unfocus` command ignores vendor folder (#459) [e5e551c, c556e43, a3b6351, 9a820dd] +- Ignore packages whose tests are all ignored by go (#456) [7430ca7, 6d8be98] +- Increase the threshold when checking time measuments (#455) [2f714bf, 68f622c] +- Fix race condition in coverage tests (#423) [a5a8ff7, ab9c08b] +- Add an extra new line after reporting spec run completion for test2json [874520d] +- added name name field to junit reported testsuite [ae61c63] +- Do not set the run time of a spec when the dryRun flag is used (#438) [457e2d9, ba8e856] +- Process FWhen and FSpecify when unfocusing (#434) [9008c7b, ee65bd, df87dfe] +- Synchronise the access to the state of specs to avoid race conditions (#430) [7d481bc, ae6829d] +- Added Duration on GinkgoTestDescription (#383) [5f49dad, 528417e, 0747408, 329d7ed] +- Fix Ginkgo stack trace on failure for Specify (#415) [b977ede, 65ca40e, 6c46eb8] +- Update README with Go 1.6+, Golang -> Go (#409) [17f6b97, bc14b66, 20d1598] +- Use fmt.Errorf instead of errors.New(fmt.Sprintf (#401) [a299f56, 44e2eaa] +- Imports in generated code should follow conventions (#398) [0bec0b0, e8536d8] +- Prevent data race error when Recording a benchmark value from multiple go routines (#390) [c0c4881, 7a241e9] +- Replace GOPATH in Environment [4b883f0] + + +## 1.4.0 7/16/2017 + +- `ginkgo` now provides a hint if you accidentally forget to run `ginkgo bootstrap` to generate a `*_suite_test.go` file that actually invokes the Ginkgo test runner. [#345](https://github.com/onsi/ginkgo/pull/345) +- thanks to improvements in `go test -c` `ginkgo` no longer needs to fix Go's compilation output to ensure compilation errors are expressed relative to the CWD. [#357] +- `ginkgo watch -watchRegExp=...` allows you to specify a custom regular expression to watch. Only files matching the regular expression are watched for changes (the default is `\.go$`) [#356] +- `ginkgo` now always emits compilation output. Previously, only failed compilation output was printed out. [#277] +- `ginkgo -requireSuite` now fails the test run if there are `*_test.go` files but `go test` fails to detect any tests. Typically this means you forgot to run `ginkgo bootstrap` to generate a suite file. [#344] +- `ginkgo -timeout=DURATION` allows you to adjust the timeout for the entire test suite (default is 24 hours) [#248] + +## 1.3.0 3/28/2017 + +Improvements: + +- Significantly improved parallel test distribution. Now instead of pre-sharding test cases across workers (which can result in idle workers and poor test performance) Ginkgo uses a shared queue to keep all workers busy until all tests are complete. This improves test-time performance and consistency. +- `Skip(message)` can be used to skip the current test. +- Added `extensions/table` - a Ginkgo DSL for [Table Driven Tests](http://onsi.github.io/ginkgo/#table-driven-tests) +- Add `GinkgoRandomSeed()` - shorthand for `config.GinkgoConfig.RandomSeed` +- Support for retrying flaky tests with `--flakeAttempts` +- `ginkgo ./...` now recurses as you'd expect +- Added `Specify` a synonym for `It` +- Support colorise on Windows +- Broader support for various go compilation flags in the `ginkgo` CLI + +Bug Fixes: + +- Ginkgo tests now fail when you `panic(nil)` (#167) + +## 1.2.0 5/31/2015 + +Improvements + +- `ginkgo -coverpkg` calls down to `go test -coverpkg` (#160) +- `ginkgo -afterSuiteHook COMMAND` invokes the passed-in `COMMAND` after a test suite completes (#152) +- Relaxed requirement for Go 1.4+. `ginkgo` now works with Go v1.3+ (#166) + +## 1.2.0-beta + +Ginkgo now requires Go 1.4+ + +Improvements: + +- Call reporters in reverse order when announcing spec completion -- allows custom reporters to emit output before the default reporter does. +- Improved focus behavior. Now, this: + + ```golang + FDescribe("Some describe", func() { + It("A", func() {}) + + FIt("B", func() {}) + }) + ``` + + will run `B` but *not* `A`. This tends to be a common usage pattern when in the thick of writing and debugging tests. +- When `SIGINT` is received, Ginkgo will emit the contents of the `GinkgoWriter` before running the `AfterSuite`. Useful for debugging stuck tests. +- When `--progress` is set, Ginkgo will write test progress (in particular, Ginkgo will say when it is about to run a BeforeEach, AfterEach, It, etc...) to the `GinkgoWriter`. This is useful for debugging stuck tests and tests that generate many logs. +- Improved output when an error occurs in a setup or teardown block. +- When `--dryRun` is set, Ginkgo will walk the spec tree and emit to its reporter *without* actually running anything. Best paired with `-v` to understand which specs will run in which order. +- Add `By` to help document long `It`s. `By` simply writes to the `GinkgoWriter`. +- Add support for precompiled tests: + - `ginkgo build ` will now compile the package, producing a file named `package.test` + - The compiled `package.test` file can be run directly. This runs the tests in series. + - To run precompiled tests in parallel, you can run: `ginkgo -p package.test` +- Support `bootstrap`ping and `generate`ing [Agouti](http://agouti.org) specs. +- `ginkgo generate` and `ginkgo bootstrap` now honor the package name already defined in a given directory +- The `ginkgo` CLI ignores `SIGQUIT`. Prevents its stack dump from interlacing with the underlying test suite's stack dump. +- The `ginkgo` CLI now compiles tests into a temporary directory instead of the package directory. This necessitates upgrading to Go v1.4+. +- `ginkgo -notify` now works on Linux + +Bug Fixes: + +- If --skipPackages is used and all packages are skipped, Ginkgo should exit 0. +- Fix tempfile leak when running in parallel +- Fix incorrect failure message when a panic occurs during a parallel test run +- Fixed an issue where a pending test within a focused context (or a focused test within a pending context) would skip all other tests. +- Be more consistent about handling SIGTERM as well as SIGINT +- When interupted while concurrently compiling test suites in the background, Ginkgo now cleans up the compiled artifacts. +- Fixed a long standing bug where `ginkgo -p` would hang if a process spawned by one of the Ginkgo parallel nodes does not exit. (Hooray!) + +## 1.1.0 (8/2/2014) + +No changes, just dropping the beta. + +## 1.1.0-beta (7/22/2014) +New Features: + +- `ginkgo watch` now monitors packages *and their dependencies* for changes. The depth of the dependency tree can be modified with the `-depth` flag. +- Test suites with a programmatic focus (`FIt`, `FDescribe`, etc...) exit with non-zero status code, even when they pass. This allows CI systems to detect accidental commits of focused test suites. +- `ginkgo -p` runs the testsuite in parallel with an auto-detected number of nodes. +- `ginkgo -tags=TAG_LIST` passes a list of tags down to the `go build` command. +- `ginkgo --failFast` aborts the test suite after the first failure. +- `ginkgo generate file_1 file_2` can take multiple file arguments. +- Ginkgo now summarizes any spec failures that occured at the end of the test run. +- `ginkgo --randomizeSuites` will run tests *suites* in random order using the generated/passed-in seed. + +Improvements: + +- `ginkgo -skipPackage` now takes a comma-separated list of strings. If the *relative path* to a package matches one of the entries in the comma-separated list, that package is skipped. +- `ginkgo --untilItFails` no longer recompiles between attempts. +- Ginkgo now panics when a runnable node (`It`, `BeforeEach`, `JustBeforeEach`, `AfterEach`, `Measure`) is nested within another runnable node. This is always a mistake. Any test suites that panic because of this change should be fixed. + +Bug Fixes: + +- `ginkgo boostrap` and `ginkgo generate` no longer fail when dealing with `hyphen-separated-packages`. +- parallel specs are now better distributed across nodes - fixed a crashing bug where (for example) distributing 11 tests across 7 nodes would panic + +## 1.0.0 (5/24/2014) +New Features: + +- Add `GinkgoParallelNode()` - shorthand for `config.GinkgoConfig.ParallelNode` + +Improvements: + +- When compilation fails, the compilation output is rewritten to present a correct *relative* path. Allows ⌘-clicking in iTerm open the file in your text editor. +- `--untilItFails` and `ginkgo watch` now generate new random seeds between test runs, unless a particular random seed is specified. + +Bug Fixes: + +- `-cover` now generates a correctly combined coverprofile when running with in parallel with multiple `-node`s. +- Print out the contents of the `GinkgoWriter` when `BeforeSuite` or `AfterSuite` fail. +- Fix all remaining race conditions in Ginkgo's test suite. + +## 1.0.0-beta (4/14/2014) +Breaking changes: + +- `thirdparty/gomocktestreporter` is gone. Use `GinkgoT()` instead +- Modified the Reporter interface +- `watch` is now a subcommand, not a flag. + +DSL changes: + +- `BeforeSuite` and `AfterSuite` for setting up and tearing down test suites. +- `AfterSuite` is triggered on interrupt (`^C`) as well as exit. +- `SynchronizedBeforeSuite` and `SynchronizedAfterSuite` for setting up and tearing down singleton resources across parallel nodes. + +CLI changes: + +- `watch` is now a subcommand, not a flag +- `--nodot` flag can be passed to `ginkgo generate` and `ginkgo bootstrap` to avoid dot imports. This explicitly imports all exported identifiers in Ginkgo and Gomega. Refreshing this list can be done by running `ginkgo nodot` +- Additional arguments can be passed to specs. Pass them after the `--` separator +- `--skipPackage` flag takes a regexp and ignores any packages with package names passing said regexp. +- `--trace` flag prints out full stack traces when errors occur, not just the line at which the error occurs. + +Misc: + +- Start using semantic versioning +- Start maintaining changelog + +Major refactor: + +- Pull out Ginkgo's internal to `internal` +- Rename `example` everywhere to `spec` +- Much more! diff --git a/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md b/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md new file mode 100644 index 000000000..8559e0136 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Contributing to Ginkgo + +Your contributions to Ginkgo are essential for its long-term maintenance and improvement. To make a contribution: + +- Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code! +- Ensure adequate test coverage: + - If you're adding functionality to the Ginkgo library, make sure to add appropriate unit and/or integration tests (under the `integration` folder). + - If you're adding functionality to the Ginkgo CLI note that there are very few unit tests. Please add an integration test. + - Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR + - Please run following linter locally `go vet ./...` and make sure output does not contain any warnings +- Update the documentation. In addition to standard `godoc` comments Ginkgo has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR. + +Thanks for supporting Ginkgo! diff --git a/vendor/github.com/onsi/ginkgo/README.md b/vendor/github.com/onsi/ginkgo/README.md new file mode 100644 index 000000000..7165b7ec5 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/README.md @@ -0,0 +1,123 @@ +![Ginkgo: A Go BDD Testing Framework](http://onsi.github.io/ginkgo/images/ginkgo.png) + +[![Build Status](https://travis-ci.org/onsi/ginkgo.svg)](https://travis-ci.org/onsi/ginkgo) + +Jump to the [docs](http://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)! + +If you have a question, comment, bug report, feature request, etc. please open a GitHub issue. + +## Feature List + +- Ginkgo uses Go's `testing` package and can live alongside your existing `testing` tests. It's easy to [bootstrap](http://onsi.github.io/ginkgo/#bootstrapping-a-suite) and start writing your [first tests](http://onsi.github.io/ginkgo/#adding-specs-to-a-suite) + +- Structure your BDD-style tests expressively: + - Nestable [`Describe`, `Context` and `When` container blocks](http://onsi.github.io/ginkgo/#organizing-specs-with-containers-describe-and-context) + - [`BeforeEach` and `AfterEach` blocks](http://onsi.github.io/ginkgo/#extracting-common-setup-beforeeach) for setup and teardown + - [`It` and `Specify` blocks](http://onsi.github.io/ginkgo/#individual-specs-) that hold your assertions + - [`JustBeforeEach` blocks](http://onsi.github.io/ginkgo/#separating-creation-and-configuration-justbeforeeach) that separate creation from configuration (also known as the subject action pattern). + - [`BeforeSuite` and `AfterSuite` blocks](http://onsi.github.io/ginkgo/#global-setup-and-teardown-beforesuite-and-aftersuite) to prep for and cleanup after a suite. + +- A comprehensive test runner that lets you: + - Mark specs as [pending](http://onsi.github.io/ginkgo/#pending-specs) + - [Focus](http://onsi.github.io/ginkgo/#focused-specs) individual specs, and groups of specs, either programmatically or on the command line + - Run your tests in [random order](http://onsi.github.io/ginkgo/#spec-permutation), and then reuse random seeds to replicate the same order. + - Break up your test suite into parallel processes for straightforward [test parallelization](http://onsi.github.io/ginkgo/#parallel-specs) + +- `ginkgo`: a command line interface with plenty of handy command line arguments for [running your tests](http://onsi.github.io/ginkgo/#running-tests) and [generating](http://onsi.github.io/ginkgo/#generators) test files. Here are a few choice examples: + - `ginkgo -nodes=N` runs your tests in `N` parallel processes and print out coherent output in realtime + - `ginkgo -cover` runs your tests using Go's code coverage tool + - `ginkgo convert` converts an XUnit-style `testing` package to a Ginkgo-style package + - `ginkgo -focus="REGEXP"` and `ginkgo -skip="REGEXP"` allow you to specify a subset of tests to run via regular expression + - `ginkgo -r` runs all tests suites under the current directory + - `ginkgo -v` prints out identifying information for each tests just before it runs + + And much more: run `ginkgo help` for details! + + The `ginkgo` CLI is convenient, but purely optional -- Ginkgo works just fine with `go test` + +- `ginkgo watch` [watches](https://onsi.github.io/ginkgo/#watching-for-changes) packages *and their dependencies* for changes, then reruns tests. Run tests immediately as you develop! + +- Built-in support for testing [asynchronicity](http://onsi.github.io/ginkgo/#asynchronous-tests) + +- Built-in support for [benchmarking](http://onsi.github.io/ginkgo/#benchmark-tests) your code. Control the number of benchmark samples as you gather runtimes and other, arbitrary, bits of numerical information about your code. + +- [Completions for Sublime Text](https://github.com/onsi/ginkgo-sublime-completions): just use [Package Control](https://sublime.wbond.net/) to install `Ginkgo Completions`. + +- [Completions for VSCode](https://github.com/onsi/vscode-ginkgo): just use VSCode's extension installer to install `vscode-ginkgo`. + +- Straightforward support for third-party testing libraries such as [Gomock](https://code.google.com/p/gomock/) and [Testify](https://github.com/stretchr/testify). Check out the [docs](http://onsi.github.io/ginkgo/#third-party-integrations) for details. + +- A modular architecture that lets you easily: + - Write [custom reporters](http://onsi.github.io/ginkgo/#writing-custom-reporters) (for example, Ginkgo comes with a [JUnit XML reporter](http://onsi.github.io/ginkgo/#generating-junit-xml-output) and a TeamCity reporter). + - [Adapt an existing matcher library (or write your own!)](http://onsi.github.io/ginkgo/#using-other-matcher-libraries) to work with Ginkgo + +## [Gomega](http://github.com/onsi/gomega): Ginkgo's Preferred Matcher Library + +Ginkgo is best paired with Gomega. Learn more about Gomega [here](http://onsi.github.io/gomega/) + +## [Agouti](http://github.com/sclevine/agouti): A Go Acceptance Testing Framework + +Agouti allows you run WebDriver integration tests. Learn more about Agouti [here](http://agouti.org) + +## Set Me Up! + +You'll need the Go command-line tools. Ginkgo is tested with Go 1.6+, but preferably you should get the latest. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed. + +```bash + +go get -u github.com/onsi/ginkgo/ginkgo # installs the ginkgo CLI +go get -u github.com/onsi/gomega/... # fetches the matcher library + +cd path/to/package/you/want/to/test + +ginkgo bootstrap # set up a new ginkgo suite +ginkgo generate # will create a sample test file. edit this file and add your tests then... + +go test # to run your tests + +ginkgo # also runs your tests + +``` + +## I'm new to Go: What are my testing options? + +Of course, I heartily recommend [Ginkgo](https://github.com/onsi/ginkgo) and [Gomega](https://github.com/onsi/gomega). Both packages are seeing heavy, daily, production use on a number of projects and boast a mature and comprehensive feature-set. + +With that said, it's great to know what your options are :) + +### What Go gives you out of the box + +Testing is a first class citizen in Go, however Go's built-in testing primitives are somewhat limited: The [testing](http://golang.org/pkg/testing) package provides basic XUnit style tests and no assertion library. + +### Matcher libraries for Go's XUnit style tests + +A number of matcher libraries have been written to augment Go's built-in XUnit style tests. Here are two that have gained traction: + +- [testify](https://github.com/stretchr/testify) +- [gocheck](http://labix.org/gocheck) + +You can also use Ginkgo's matcher library [Gomega](https://github.com/onsi/gomega) in [XUnit style tests](http://onsi.github.io/gomega/#using-gomega-with-golangs-xunitstyle-tests) + +### BDD style testing frameworks + +There are a handful of BDD-style testing frameworks written for Go. Here are a few: + +- [Ginkgo](https://github.com/onsi/ginkgo) ;) +- [GoConvey](https://github.com/smartystreets/goconvey) +- [Goblin](https://github.com/franela/goblin) +- [Mao](https://github.com/azer/mao) +- [Zen](https://github.com/pranavraja/zen) + +Finally, @shageman has [put together](https://github.com/shageman/gotestit) a comprehensive comparison of Go testing libraries. + +Go explore! + +## License + +Ginkgo is MIT-Licensed + +## Contributing + +Since Ginkgo tests also internal packages, when you fork, you'll have to replace imports with your repository.
+Use `before_pr.sh` for that
+After you finished your changes and before you push your pull request, use `after_pr.sh` to revert those changes diff --git a/vendor/github.com/onsi/ginkgo/RELEASING.md b/vendor/github.com/onsi/ginkgo/RELEASING.md new file mode 100644 index 000000000..1e298c2da --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/RELEASING.md @@ -0,0 +1,14 @@ +A Ginkgo release is a tagged git sha and a GitHub release. To cut a release: + +1. Ensure CHANGELOG.md is up to date. + - Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release + - Categorize the changes into + - Breaking Changes (requires a major version) + - New Features (minor version) + - Fixes (fix version) + - Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact) +1. Update `VERSION` in `config/config.go` +1. Create a commit with the version number as the commit message (e.g. `v1.3.0`) +1. Tag the commit with the version number as the tag name (e.g. `v1.3.0`) +1. Push the commit and tag to GitHub +1. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes. diff --git a/vendor/github.com/onsi/ginkgo/before_pr.sh b/vendor/github.com/onsi/ginkgo/before_pr.sh new file mode 100755 index 000000000..3cf262f38 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/before_pr.sh @@ -0,0 +1,13 @@ +# Take current path +path=$(pwd) + +# Split it +IFS='\/'; arrIN=($path); unset IFS; + +# Find directory before ginkgo +len=${#arrIN[@]} + +userDir=${arrIN[$len-2]} + +# Replace onsi with userdir +find . -type f -name '*.go' -exec sed -i '' s/github.com\\/onsi\\/ginkgo\\/internal/github.com\\/$userDir\\/ginkgo\\/internal/ {} + \ No newline at end of file diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go new file mode 100644 index 000000000..f482ec3dc --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_suite_test.go @@ -0,0 +1,13 @@ +package table_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestTable(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Table Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_test.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_test.go new file mode 100644 index 000000000..b008e432b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_test.go @@ -0,0 +1,64 @@ +package table_test + +import ( + "strings" + + . "github.com/onsi/ginkgo/extensions/table" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Table", func() { + DescribeTable("a simple table", + func(x int, y int, expected bool) { + Ω(x > y).Should(Equal(expected)) + }, + Entry("x > y", 1, 0, true), + Entry("x == y", 0, 0, false), + Entry("x < y", 0, 1, false), + ) + + type ComplicatedThings struct { + Superstructure string + Substructure string + Count int + } + + DescribeTable("a more complicated table", + func(c ComplicatedThings) { + Ω(strings.Count(c.Superstructure, c.Substructure)).Should(BeNumerically("==", c.Count)) + }, + Entry("with no matching substructures", ComplicatedThings{ + Superstructure: "the sixth sheikh's sixth sheep's sick", + Substructure: "emir", + Count: 0, + }), + Entry("with one matching substructure", ComplicatedThings{ + Superstructure: "the sixth sheikh's sixth sheep's sick", + Substructure: "sheep", + Count: 1, + }), + Entry("with many matching substructures", ComplicatedThings{ + Superstructure: "the sixth sheikh's sixth sheep's sick", + Substructure: "si", + Count: 3, + }), + ) + + PDescribeTable("a failure", + func(value bool) { + Ω(value).Should(BeFalse()) + }, + Entry("when true", true), + Entry("when false", false), + Entry("when malformed", 2), + ) + + DescribeTable("an untyped nil as an entry", + func(x interface{}) { + Expect(x).To(BeNil()) + }, + Entry("nil", nil), + ) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_suite_test.go new file mode 100644 index 000000000..f06abf3c5 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_suite_test.go @@ -0,0 +1,13 @@ +package codelocation_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestCodelocation(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "CodeLocation Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go new file mode 100644 index 000000000..cca75a449 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/codelocation/code_location_test.go @@ -0,0 +1,80 @@ +package codelocation_test + +import ( + "runtime" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" +) + +var _ = Describe("CodeLocation", func() { + var ( + codeLocation types.CodeLocation + expectedFileName string + expectedLineNumber int + ) + + caller0 := func() { + codeLocation = codelocation.New(1) + } + + caller1 := func() { + _, expectedFileName, expectedLineNumber, _ = runtime.Caller(0) + expectedLineNumber += 2 + caller0() + } + + BeforeEach(func() { + caller1() + }) + + It("should use the passed in skip parameter to pick out the correct file & line number", func() { + Ω(codeLocation.FileName).Should(Equal(expectedFileName)) + Ω(codeLocation.LineNumber).Should(Equal(expectedLineNumber)) + }) + + Describe("stringer behavior", func() { + It("should stringify nicely", func() { + Ω(codeLocation.String()).Should(ContainSubstring("code_location_test.go:%d", expectedLineNumber)) + }) + }) + + //There's no better way than to test this private method as it + //goes out of its way to prune out ginkgo related code in the stack trace + Describe("PruneStack", func() { + It("should remove any references to ginkgo and pkg/testing and pkg/runtime", func() { + input := `/Skip/me +Skip: skip() +/Skip/me +Skip: skip() +/Users/whoever/gospace/src/github.com/onsi/ginkgo/whatever.go:10 (0x12314) +Something: Func() +/Users/whoever/gospace/src/github.com/onsi/ginkgo/whatever_else.go:10 (0x12314) +SomethingInternalToGinkgo: Func() +/usr/goroot/pkg/strings/oops.go:10 (0x12341) +Oops: BlowUp() +/Users/whoever/gospace/src/mycode/code.go:10 (0x12341) +MyCode: Func() +/Users/whoever/gospace/src/mycode/code_test.go:10 (0x12341) +MyCodeTest: Func() +/Users/whoever/gospace/src/mycode/code_suite_test.go:12 (0x37f08) +TestFoo: RunSpecs(t, "Foo Suite") +/usr/goroot/pkg/testing/testing.go:12 (0x37f08) +TestingT: Blah() +/usr/goroot/pkg/runtime/runtime.go:12 (0x37f08) +Something: Func() +` + prunedStack := codelocation.PruneStack(input, 1) + Ω(prunedStack).Should(Equal(`/usr/goroot/pkg/strings/oops.go:10 (0x12341) +Oops: BlowUp() +/Users/whoever/gospace/src/mycode/code.go:10 (0x12341) +MyCode: Func() +/Users/whoever/gospace/src/mycode/code_test.go:10 (0x12341) +MyCodeTest: Func() +/Users/whoever/gospace/src/mycode/code_suite_test.go:12 (0x37f08) +TestFoo: RunSpecs(t, "Foo Suite")`)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_suite_test.go new file mode 100644 index 000000000..c6fc314ff --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_suite_test.go @@ -0,0 +1,13 @@ +package containernode_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestContainernode(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Containernode Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go b/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go new file mode 100644 index 000000000..11ac9b70b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/containernode/container_node_test.go @@ -0,0 +1,213 @@ +package containernode_test + +import ( + "math/rand" + + "github.com/onsi/ginkgo/internal/leafnodes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/onsi/ginkgo/internal/codelocation" + . "github.com/onsi/ginkgo/internal/containernode" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("Container Node", func() { + var ( + codeLocation types.CodeLocation + container *ContainerNode + ) + + BeforeEach(func() { + codeLocation = codelocation.New(0) + container = New("description text", types.FlagTypeFocused, codeLocation) + }) + + Describe("creating a container node", func() { + It("can answer questions about itself", func() { + Ω(container.Text()).Should(Equal("description text")) + Ω(container.Flag()).Should(Equal(types.FlagTypeFocused)) + Ω(container.CodeLocation()).Should(Equal(codeLocation)) + }) + }) + + Describe("pushing setup nodes", func() { + It("can append setup nodes of various types and fetch them by type", func() { + befA := leafnodes.NewBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) + befB := leafnodes.NewBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) + aftA := leafnodes.NewAfterEachNode(func() {}, codelocation.New(0), 0, nil, 0) + aftB := leafnodes.NewAfterEachNode(func() {}, codelocation.New(0), 0, nil, 0) + jusBefA := leafnodes.NewJustBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) + jusBefB := leafnodes.NewJustBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0) + + container.PushSetupNode(befA) + container.PushSetupNode(befB) + container.PushSetupNode(aftA) + container.PushSetupNode(aftB) + container.PushSetupNode(jusBefA) + container.PushSetupNode(jusBefB) + + subject := leafnodes.NewItNode("subject", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + container.PushSubjectNode(subject) + + Ω(container.SetupNodesOfType(types.SpecComponentTypeBeforeEach)).Should(Equal([]leafnodes.BasicNode{befA, befB})) + Ω(container.SetupNodesOfType(types.SpecComponentTypeAfterEach)).Should(Equal([]leafnodes.BasicNode{aftA, aftB})) + Ω(container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach)).Should(Equal([]leafnodes.BasicNode{jusBefA, jusBefB})) + Ω(container.SetupNodesOfType(types.SpecComponentTypeIt)).Should(BeEmpty()) //subjects are not setup nodes + }) + }) + + Context("With appended containers and subject nodes", func() { + var ( + itA, itB, innerItA, innerItB leafnodes.SubjectNode + innerContainer *ContainerNode + ) + + BeforeEach(func() { + itA = leafnodes.NewItNode("Banana", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + itB = leafnodes.NewItNode("Apple", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + + innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + innerItB = leafnodes.NewItNode("inner B", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + + innerContainer = New("Orange", types.FlagTypeNone, codelocation.New(0)) + + container.PushSubjectNode(itA) + container.PushContainerNode(innerContainer) + innerContainer.PushSubjectNode(innerItA) + innerContainer.PushSubjectNode(innerItB) + container.PushSubjectNode(itB) + }) + + Describe("Collating", func() { + It("should return a collated set of containers and subject nodes in the correct order", func() { + collated := container.Collate() + Ω(collated).Should(HaveLen(4)) + + Ω(collated[0]).Should(Equal(CollatedNodes{ + Containers: []*ContainerNode{container}, + Subject: itA, + })) + + Ω(collated[1]).Should(Equal(CollatedNodes{ + Containers: []*ContainerNode{container, innerContainer}, + Subject: innerItA, + })) + + Ω(collated[2]).Should(Equal(CollatedNodes{ + Containers: []*ContainerNode{container, innerContainer}, + Subject: innerItB, + })) + + Ω(collated[3]).Should(Equal(CollatedNodes{ + Containers: []*ContainerNode{container}, + Subject: itB, + })) + }) + }) + + Describe("Backpropagating Programmatic Focus", func() { + //This allows inner focused specs to override the focus of outer focussed + //specs and more closely maps to what a developer wants to happen + //when debugging a test suite + + Context("when a parent is focused *and* an inner subject is focused", func() { + BeforeEach(func() { + container = New("description text", types.FlagTypeFocused, codeLocation) + itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + container.PushSubjectNode(itA) + + innerContainer = New("Orange", types.FlagTypeNone, codelocation.New(0)) + container.PushContainerNode(innerContainer) + innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeFocused, codelocation.New(0), 0, nil, 0) + innerContainer.PushSubjectNode(innerItA) + }) + + It("should unfocus the parent", func() { + container.BackPropagateProgrammaticFocus() + + Ω(container.Flag()).Should(Equal(types.FlagTypeNone)) + Ω(itA.Flag()).Should(Equal(types.FlagTypeNone)) + Ω(innerContainer.Flag()).Should(Equal(types.FlagTypeNone)) + Ω(innerItA.Flag()).Should(Equal(types.FlagTypeFocused)) + }) + }) + + Context("when a parent is focused *and* an inner container is focused", func() { + BeforeEach(func() { + container = New("description text", types.FlagTypeFocused, codeLocation) + itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + container.PushSubjectNode(itA) + + innerContainer = New("Orange", types.FlagTypeFocused, codelocation.New(0)) + container.PushContainerNode(innerContainer) + innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + innerContainer.PushSubjectNode(innerItA) + }) + + It("should unfocus the parent", func() { + container.BackPropagateProgrammaticFocus() + + Ω(container.Flag()).Should(Equal(types.FlagTypeNone)) + Ω(itA.Flag()).Should(Equal(types.FlagTypeNone)) + Ω(innerContainer.Flag()).Should(Equal(types.FlagTypeFocused)) + Ω(innerItA.Flag()).Should(Equal(types.FlagTypeNone)) + }) + }) + + Context("when a parent is pending and a child is focused", func() { + BeforeEach(func() { + container = New("description text", types.FlagTypeFocused, codeLocation) + itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0) + container.PushSubjectNode(itA) + + innerContainer = New("Orange", types.FlagTypePending, codelocation.New(0)) + container.PushContainerNode(innerContainer) + innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeFocused, codelocation.New(0), 0, nil, 0) + innerContainer.PushSubjectNode(innerItA) + }) + + It("should not do anything", func() { + container.BackPropagateProgrammaticFocus() + + Ω(container.Flag()).Should(Equal(types.FlagTypeFocused)) + Ω(itA.Flag()).Should(Equal(types.FlagTypeNone)) + Ω(innerContainer.Flag()).Should(Equal(types.FlagTypePending)) + Ω(innerItA.Flag()).Should(Equal(types.FlagTypeFocused)) + }) + }) + }) + + Describe("Shuffling", func() { + var unshuffledCollation []CollatedNodes + BeforeEach(func() { + unshuffledCollation = container.Collate() + + r := rand.New(rand.NewSource(17)) + container.Shuffle(r) + }) + + It("should sort, and then shuffle, the top level contents of the container", func() { + shuffledCollation := container.Collate() + Ω(shuffledCollation).Should(HaveLen(len(unshuffledCollation))) + Ω(shuffledCollation).ShouldNot(Equal(unshuffledCollation)) + + for _, entry := range unshuffledCollation { + Ω(shuffledCollation).Should(ContainElement(entry)) + } + + innerAIndex, innerBIndex := 0, 0 + for i, entry := range shuffledCollation { + if entry.Subject == innerItA { + innerAIndex = i + } else if entry.Subject == innerItB { + innerBIndex = i + } + } + + Ω(innerAIndex).Should(Equal(innerBIndex - 1)) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/failer/failer_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/failer/failer_suite_test.go new file mode 100644 index 000000000..8dce7be9a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/failer/failer_suite_test.go @@ -0,0 +1,13 @@ +package failer_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestFailer(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Failer Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/failer/failer_test.go b/vendor/github.com/onsi/ginkgo/internal/failer/failer_test.go new file mode 100644 index 000000000..65210a40a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/failer/failer_test.go @@ -0,0 +1,141 @@ +package failer_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/failer" + . "github.com/onsi/gomega" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("Failer", func() { + var ( + failer *Failer + codeLocationA types.CodeLocation + codeLocationB types.CodeLocation + ) + + BeforeEach(func() { + codeLocationA = codelocation.New(0) + codeLocationB = codelocation.New(0) + failer = New() + }) + + Context("with no failures", func() { + It("should return success when drained", func() { + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + Ω(failure).Should(BeZero()) + Ω(state).Should(Equal(types.SpecStatePassed)) + }) + }) + + Describe("Skip", func() { + It("should handle failures", func() { + failer.Skip("something skipped", codeLocationA) + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "something skipped", + Location: codeLocationA, + ForwardedPanic: "", + ComponentType: types.SpecComponentTypeIt, + ComponentIndex: 3, + ComponentCodeLocation: codeLocationB, + })) + Ω(state).Should(Equal(types.SpecStateSkipped)) + }) + }) + + Describe("Fail", func() { + It("should handle failures", func() { + failer.Fail("something failed", codeLocationA) + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "something failed", + Location: codeLocationA, + ForwardedPanic: "", + ComponentType: types.SpecComponentTypeIt, + ComponentIndex: 3, + ComponentCodeLocation: codeLocationB, + })) + Ω(state).Should(Equal(types.SpecStateFailed)) + }) + }) + + Describe("Panic", func() { + It("should handle panics", func() { + failer.Panic(codeLocationA, "some forwarded panic") + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "Test Panicked", + Location: codeLocationA, + ForwardedPanic: "some forwarded panic", + ComponentType: types.SpecComponentTypeIt, + ComponentIndex: 3, + ComponentCodeLocation: codeLocationB, + })) + Ω(state).Should(Equal(types.SpecStatePanicked)) + }) + }) + + Describe("Timeout", func() { + It("should handle timeouts", func() { + failer.Timeout(codeLocationA) + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "Timed out", + Location: codeLocationA, + ForwardedPanic: "", + ComponentType: types.SpecComponentTypeIt, + ComponentIndex: 3, + ComponentCodeLocation: codeLocationB, + })) + Ω(state).Should(Equal(types.SpecStateTimedOut)) + }) + }) + + Context("when multiple failures are registered", func() { + BeforeEach(func() { + failer.Fail("something failed", codeLocationA) + failer.Fail("something else failed", codeLocationA) + }) + + It("should only report the first one when drained", func() { + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "something failed", + Location: codeLocationA, + ForwardedPanic: "", + ComponentType: types.SpecComponentTypeIt, + ComponentIndex: 3, + ComponentCodeLocation: codeLocationB, + })) + Ω(state).Should(Equal(types.SpecStateFailed)) + }) + + It("should report subsequent failures after being drained", func() { + failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + failer.Fail("yet another thing failed", codeLocationA) + + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "yet another thing failed", + Location: codeLocationA, + ForwardedPanic: "", + ComponentType: types.SpecComponentTypeIt, + ComponentIndex: 3, + ComponentCodeLocation: codeLocationB, + })) + Ω(state).Should(Equal(types.SpecStateFailed)) + }) + + It("should report sucess on subsequent drains if no errors occur", func() { + failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + failure, state := failer.Drain(types.SpecComponentTypeIt, 3, codeLocationB) + Ω(failure).Should(BeZero()) + Ω(state).Should(Equal(types.SpecStatePassed)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go new file mode 100644 index 000000000..29fa0c6e2 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/it_node_test.go @@ -0,0 +1,22 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/leafnodes" + . "github.com/onsi/gomega" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("It Nodes", func() { + It("should report the correct type, text, flag, and code location", func() { + codeLocation := codelocation.New(0) + it := NewItNode("my it node", func() {}, types.FlagTypeFocused, codeLocation, 0, nil, 3) + Ω(it.Type()).Should(Equal(types.SpecComponentTypeIt)) + Ω(it.Flag()).Should(Equal(types.FlagTypeFocused)) + Ω(it.Text()).Should(Equal("my it node")) + Ω(it.CodeLocation()).Should(Equal(codeLocation)) + Ω(it.Samples()).Should(Equal(1)) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go new file mode 100644 index 000000000..a7ba9e006 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/leaf_node_suite_test.go @@ -0,0 +1,13 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestLeafNode(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "LeafNode Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go new file mode 100644 index 000000000..1cd13336a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/measure_node_test.go @@ -0,0 +1,155 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/leafnodes" + . "github.com/onsi/gomega" + + "time" + + "github.com/onsi/ginkgo/internal/codelocation" + Failer "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("Measure Nodes", func() { + It("should report the correct type, text, flag, and code location", func() { + codeLocation := codelocation.New(0) + measure := NewMeasureNode("my measure node", func(b Benchmarker) {}, types.FlagTypeFocused, codeLocation, 10, nil, 3) + Ω(measure.Type()).Should(Equal(types.SpecComponentTypeMeasure)) + Ω(measure.Flag()).Should(Equal(types.FlagTypeFocused)) + Ω(measure.Text()).Should(Equal("my measure node")) + Ω(measure.CodeLocation()).Should(Equal(codeLocation)) + Ω(measure.Samples()).Should(Equal(10)) + }) + + Describe("benchmarking", func() { + var measure *MeasureNode + + Describe("Value", func() { + BeforeEach(func() { + measure = NewMeasureNode("the measurement", func(b Benchmarker) { + b.RecordValue("foo", 7, "info!") + b.RecordValue("foo", 2) + b.RecordValue("foo", 3) + b.RecordValue("bar", 0.3) + b.RecordValue("bar", 0.1) + b.RecordValue("bar", 0.5) + b.RecordValue("bar", 0.7) + }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) + Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) + }) + + It("records passed in values and reports on them", func() { + report := measure.MeasurementsReport() + Ω(report).Should(HaveLen(2)) + Ω(report["foo"].Name).Should(Equal("foo")) + Ω(report["foo"].Info).Should(Equal("info!")) + Ω(report["foo"].Order).Should(Equal(0)) + Ω(report["foo"].SmallestLabel).Should(Equal("Smallest")) + Ω(report["foo"].LargestLabel).Should(Equal(" Largest")) + Ω(report["foo"].AverageLabel).Should(Equal(" Average")) + Ω(report["foo"].Units).Should(Equal("")) + Ω(report["foo"].Results).Should(Equal([]float64{7, 2, 3})) + Ω(report["foo"].Smallest).Should(BeNumerically("==", 2)) + Ω(report["foo"].Largest).Should(BeNumerically("==", 7)) + Ω(report["foo"].Average).Should(BeNumerically("==", 4)) + Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 2.16, 0.01)) + + Ω(report["bar"].Name).Should(Equal("bar")) + Ω(report["bar"].Info).Should(BeNil()) + Ω(report["bar"].SmallestLabel).Should(Equal("Smallest")) + Ω(report["bar"].Order).Should(Equal(1)) + Ω(report["bar"].LargestLabel).Should(Equal(" Largest")) + Ω(report["bar"].AverageLabel).Should(Equal(" Average")) + Ω(report["bar"].Units).Should(Equal("")) + Ω(report["bar"].Results).Should(Equal([]float64{0.3, 0.1, 0.5, 0.7})) + Ω(report["bar"].Smallest).Should(BeNumerically("==", 0.1)) + Ω(report["bar"].Largest).Should(BeNumerically("==", 0.7)) + Ω(report["bar"].Average).Should(BeNumerically("==", 0.4)) + Ω(report["bar"].StdDeviation).Should(BeNumerically("~", 0.22, 0.01)) + }) + }) + + Describe("Value with precision", func() { + BeforeEach(func() { + measure = NewMeasureNode("the measurement", func(b Benchmarker) { + b.RecordValueWithPrecision("foo", 7, "ms", 7, "info!") + b.RecordValueWithPrecision("foo", 2, "ms", 6) + b.RecordValueWithPrecision("foo", 3, "ms", 5) + b.RecordValueWithPrecision("bar", 0.3, "ns", 4) + b.RecordValueWithPrecision("bar", 0.1, "ns", 3) + b.RecordValueWithPrecision("bar", 0.5, "ns", 2) + b.RecordValueWithPrecision("bar", 0.7, "ns", 1) + }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) + Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) + }) + + It("records passed in values and reports on them", func() { + report := measure.MeasurementsReport() + Ω(report).Should(HaveLen(2)) + Ω(report["foo"].Name).Should(Equal("foo")) + Ω(report["foo"].Info).Should(Equal("info!")) + Ω(report["foo"].Order).Should(Equal(0)) + Ω(report["foo"].SmallestLabel).Should(Equal("Smallest")) + Ω(report["foo"].LargestLabel).Should(Equal(" Largest")) + Ω(report["foo"].AverageLabel).Should(Equal(" Average")) + Ω(report["foo"].Units).Should(Equal("ms")) + Ω(report["foo"].Results).Should(Equal([]float64{7, 2, 3})) + Ω(report["foo"].Smallest).Should(BeNumerically("==", 2)) + Ω(report["foo"].Largest).Should(BeNumerically("==", 7)) + Ω(report["foo"].Average).Should(BeNumerically("==", 4)) + Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 2.16, 0.01)) + + Ω(report["bar"].Name).Should(Equal("bar")) + Ω(report["bar"].Info).Should(BeNil()) + Ω(report["bar"].SmallestLabel).Should(Equal("Smallest")) + Ω(report["bar"].Order).Should(Equal(1)) + Ω(report["bar"].LargestLabel).Should(Equal(" Largest")) + Ω(report["bar"].AverageLabel).Should(Equal(" Average")) + Ω(report["bar"].Units).Should(Equal("ns")) + Ω(report["bar"].Results).Should(Equal([]float64{0.3, 0.1, 0.5, 0.7})) + Ω(report["bar"].Smallest).Should(BeNumerically("==", 0.1)) + Ω(report["bar"].Largest).Should(BeNumerically("==", 0.7)) + Ω(report["bar"].Average).Should(BeNumerically("==", 0.4)) + Ω(report["bar"].StdDeviation).Should(BeNumerically("~", 0.22, 0.01)) + }) + }) + + Describe("Time", func() { + BeforeEach(func() { + measure = NewMeasureNode("the measurement", func(b Benchmarker) { + b.Time("foo", func() { + time.Sleep(200 * time.Millisecond) + }, "info!") + b.Time("foo", func() { + time.Sleep(300 * time.Millisecond) + }) + b.Time("foo", func() { + time.Sleep(250 * time.Millisecond) + }) + }, types.FlagTypeFocused, codelocation.New(0), 1, Failer.New(), 3) + Ω(measure.Run()).Should(Equal(types.SpecStatePassed)) + }) + + It("records passed in values and reports on them", func() { + report := measure.MeasurementsReport() + Ω(report).Should(HaveLen(1)) + Ω(report["foo"].Name).Should(Equal("foo")) + Ω(report["foo"].Info).Should(Equal("info!")) + Ω(report["foo"].SmallestLabel).Should(Equal("Fastest Time")) + Ω(report["foo"].LargestLabel).Should(Equal("Slowest Time")) + Ω(report["foo"].AverageLabel).Should(Equal("Average Time")) + Ω(report["foo"].Units).Should(Equal("s")) + Ω(report["foo"].Results).Should(HaveLen(3)) + Ω(report["foo"].Results[0]).Should(BeNumerically("~", 0.2, 0.06)) + Ω(report["foo"].Results[1]).Should(BeNumerically("~", 0.3, 0.06)) + Ω(report["foo"].Results[2]).Should(BeNumerically("~", 0.25, 0.06)) + Ω(report["foo"].Smallest).Should(BeNumerically("~", 0.2, 0.06)) + Ω(report["foo"].Largest).Should(BeNumerically("~", 0.3, 0.06)) + Ω(report["foo"].Average).Should(BeNumerically("~", 0.25, 0.06)) + Ω(report["foo"].StdDeviation).Should(BeNumerically("~", 0.07, 0.04)) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go new file mode 100644 index 000000000..d5b9251f6 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/setup_nodes_test.go @@ -0,0 +1,40 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" + + . "github.com/onsi/ginkgo/internal/leafnodes" + + "github.com/onsi/ginkgo/internal/codelocation" +) + +var _ = Describe("Setup Nodes", func() { + Describe("BeforeEachNodes", func() { + It("should report the correct type and code location", func() { + codeLocation := codelocation.New(0) + beforeEach := NewBeforeEachNode(func() {}, codeLocation, 0, nil, 3) + Ω(beforeEach.Type()).Should(Equal(types.SpecComponentTypeBeforeEach)) + Ω(beforeEach.CodeLocation()).Should(Equal(codeLocation)) + }) + }) + + Describe("AfterEachNodes", func() { + It("should report the correct type and code location", func() { + codeLocation := codelocation.New(0) + afterEach := NewAfterEachNode(func() {}, codeLocation, 0, nil, 3) + Ω(afterEach.Type()).Should(Equal(types.SpecComponentTypeAfterEach)) + Ω(afterEach.CodeLocation()).Should(Equal(codeLocation)) + }) + }) + + Describe("JustBeforeEachNodes", func() { + It("should report the correct type and code location", func() { + codeLocation := codelocation.New(0) + justBeforeEach := NewJustBeforeEachNode(func() {}, codeLocation, 0, nil, 3) + Ω(justBeforeEach.Type()).Should(Equal(types.SpecComponentTypeJustBeforeEach)) + Ω(justBeforeEach.CodeLocation()).Should(Equal(codeLocation)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go new file mode 100644 index 000000000..6f750ff61 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/shared_runner_test.go @@ -0,0 +1,356 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/leafnodes" + . "github.com/onsi/gomega" + + "reflect" + "time" + + "github.com/onsi/ginkgo/internal/codelocation" + Failer "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/types" +) + +type runnable interface { + Run() (outcome types.SpecState, failure types.SpecFailure) + CodeLocation() types.CodeLocation +} + +func SynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType, componentIndex int) { + var ( + outcome types.SpecState + failure types.SpecFailure + + failer *Failer.Failer + + componentCodeLocation types.CodeLocation + innerCodeLocation types.CodeLocation + + didRun bool + ) + + BeforeEach(func() { + failer = Failer.New() + componentCodeLocation = codelocation.New(0) + innerCodeLocation = codelocation.New(0) + + didRun = false + }) + + Describe("synchronous functions", func() { + Context("when the function passes", func() { + BeforeEach(func() { + outcome, failure = build(func() { + didRun = true + }, 0, failer, componentCodeLocation).Run() + }) + + It("should have a succesful outcome", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStatePassed)) + Ω(failure).Should(BeZero()) + }) + }) + + Context("when a failure occurs", func() { + BeforeEach(func() { + outcome, failure = build(func() { + didRun = true + failer.Fail("bam", innerCodeLocation) + panic("should not matter") + }, 0, failer, componentCodeLocation).Run() + }) + + It("should return the failure", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStateFailed)) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "bam", + Location: innerCodeLocation, + ForwardedPanic: "", + ComponentIndex: componentIndex, + ComponentType: componentType, + ComponentCodeLocation: componentCodeLocation, + })) + }) + }) + + Context("when a panic occurs", func() { + BeforeEach(func() { + outcome, failure = build(func() { + didRun = true + innerCodeLocation = codelocation.New(0) + panic("ack!") + }, 0, failer, componentCodeLocation).Run() + }) + + It("should return the panic", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStatePanicked)) + Ω(failure.ForwardedPanic).Should(Equal("ack!")) + }) + }) + + Context("when a panic occurs with a nil value", func() { + BeforeEach(func() { + outcome, failure = build(func() { + didRun = true + innerCodeLocation = codelocation.New(0) + panic(nil) + }, 0, failer, componentCodeLocation).Run() + }) + + It("should return the nil-valued panic", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStatePanicked)) + Ω(failure.ForwardedPanic).Should(Equal("")) + }) + }) + + }) +} + +func AsynchronousSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType, componentIndex int) { + var ( + outcome types.SpecState + failure types.SpecFailure + + failer *Failer.Failer + + componentCodeLocation types.CodeLocation + innerCodeLocation types.CodeLocation + + didRun bool + ) + + BeforeEach(func() { + failer = Failer.New() + componentCodeLocation = codelocation.New(0) + innerCodeLocation = codelocation.New(0) + + didRun = false + }) + + Describe("asynchronous functions", func() { + var timeoutDuration time.Duration + + BeforeEach(func() { + timeoutDuration = time.Duration(1 * float64(time.Second)) + }) + + Context("when running", func() { + It("should run the function as a goroutine, and block until it's done", func() { + proveAsync := make(chan bool) + + build(func(done Done) { + didRun = true + proveAsync <- true + close(done) + }, timeoutDuration, failer, componentCodeLocation).Run() + + Eventually(proveAsync).Should(Receive(Equal(true))) + }) + }) + + Context("when the function passes", func() { + BeforeEach(func() { + outcome, failure = build(func(done Done) { + didRun = true + close(done) + }, timeoutDuration, failer, componentCodeLocation).Run() + }) + + It("should have a succesful outcome", func() { + Ω(didRun).Should(BeTrue()) + Ω(outcome).Should(Equal(types.SpecStatePassed)) + Ω(failure).Should(BeZero()) + }) + }) + + Context("when the function fails", func() { + BeforeEach(func() { + outcome, failure = build(func(done Done) { + didRun = true + failer.Fail("bam", innerCodeLocation) + time.Sleep(20 * time.Millisecond) + defer close(done) + panic("doesn't matter") + }, 10*time.Millisecond, failer, componentCodeLocation).Run() + }) + + It("should return the failure", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStateFailed)) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "bam", + Location: innerCodeLocation, + ForwardedPanic: "", + ComponentIndex: componentIndex, + ComponentType: componentType, + ComponentCodeLocation: componentCodeLocation, + })) + }) + }) + + Context("when the function times out", func() { + var guard chan struct{} + + BeforeEach(func() { + guard = make(chan struct{}) + outcome, failure = build(func(done Done) { + didRun = true + time.Sleep(20 * time.Millisecond) + close(guard) + defer close(done) + panic("doesn't matter") + }, 10*time.Millisecond, failer, componentCodeLocation).Run() + }) + + It("should return the timeout", func() { + <-guard + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStateTimedOut)) + Ω(failure).Should(Equal(types.SpecFailure{ + Message: "Timed out", + Location: componentCodeLocation, + ForwardedPanic: "", + ComponentIndex: componentIndex, + ComponentType: componentType, + ComponentCodeLocation: componentCodeLocation, + })) + }) + }) + + Context("when the function panics", func() { + BeforeEach(func() { + outcome, failure = build(func(done Done) { + didRun = true + innerCodeLocation = codelocation.New(0) + panic("ack!") + }, 100*time.Millisecond, failer, componentCodeLocation).Run() + }) + + It("should return the panic", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStatePanicked)) + Ω(failure.ForwardedPanic).Should(Equal("ack!")) + }) + }) + + Context("when the function panics with a nil value", func() { + BeforeEach(func() { + outcome, failure = build(func(done Done) { + didRun = true + innerCodeLocation = codelocation.New(0) + panic(nil) + }, 100*time.Millisecond, failer, componentCodeLocation).Run() + }) + + It("should return the nil-valued panic", func() { + Ω(didRun).Should(BeTrue()) + + Ω(outcome).Should(Equal(types.SpecStatePanicked)) + Ω(failure.ForwardedPanic).Should(Equal("")) + }) + }) + }) +} + +func InvalidSharedRunnerBehaviors(build func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable, componentType types.SpecComponentType) { + var ( + failer *Failer.Failer + componentCodeLocation types.CodeLocation + ) + + BeforeEach(func() { + failer = Failer.New() + componentCodeLocation = codelocation.New(0) + }) + + Describe("invalid functions", func() { + Context("when passed something that's not a function", func() { + It("should panic", func() { + Ω(func() { + build("not a function", 0, failer, componentCodeLocation) + }).Should(Panic()) + }) + }) + + Context("when the function takes the wrong kind of argument", func() { + It("should panic", func() { + Ω(func() { + build(func(oops string) {}, 0, failer, componentCodeLocation) + }).Should(Panic()) + }) + }) + + Context("when the function takes more than one argument", func() { + It("should panic", func() { + Ω(func() { + build(func(done Done, oops string) {}, 0, failer, componentCodeLocation) + }).Should(Panic()) + }) + }) + }) +} + +var _ = Describe("Shared RunnableNode behavior", func() { + Describe("It Nodes", func() { + build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { + return NewItNode("", body, types.FlagTypeFocused, componentCodeLocation, timeout, failer, 3) + } + + SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeIt, 3) + AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeIt, 3) + InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeIt) + }) + + Describe("Measure Nodes", func() { + build := func(body interface{}, _ time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { + return NewMeasureNode("", func(Benchmarker) { + reflect.ValueOf(body).Call([]reflect.Value{}) + }, types.FlagTypeFocused, componentCodeLocation, 10, failer, 3) + } + + SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeMeasure, 3) + }) + + Describe("BeforeEach Nodes", func() { + build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { + return NewBeforeEachNode(body, componentCodeLocation, timeout, failer, 3) + } + + SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach, 3) + AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach, 3) + InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeBeforeEach) + }) + + Describe("AfterEach Nodes", func() { + build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { + return NewAfterEachNode(body, componentCodeLocation, timeout, failer, 3) + } + + SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach, 3) + AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach, 3) + InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeAfterEach) + }) + + Describe("JustBeforeEach Nodes", func() { + build := func(body interface{}, timeout time.Duration, failer *Failer.Failer, componentCodeLocation types.CodeLocation) runnable { + return NewJustBeforeEachNode(body, componentCodeLocation, timeout, failer, 3) + } + + SynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach, 3) + AsynchronousSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach, 3) + InvalidSharedRunnerBehaviors(build, types.SpecComponentTypeJustBeforeEach) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go new file mode 100644 index 000000000..246b329fe --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/suite_nodes_test.go @@ -0,0 +1,230 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + . "github.com/onsi/ginkgo/internal/leafnodes" + + "time" + + "github.com/onsi/ginkgo/internal/codelocation" + Failer "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("SuiteNodes", func() { + Describe("BeforeSuite nodes", func() { + var befSuite SuiteNode + var failer *Failer.Failer + var codeLocation types.CodeLocation + var innerCodeLocation types.CodeLocation + var outcome bool + + BeforeEach(func() { + failer = Failer.New() + codeLocation = codelocation.New(0) + innerCodeLocation = codelocation.New(0) + }) + + Context("when the body passes", func() { + BeforeEach(func() { + befSuite = NewBeforeSuiteNode(func() { + time.Sleep(10 * time.Millisecond) + }, codeLocation, 0, failer) + outcome = befSuite.Run(0, 0, "") + }) + + It("should return true when run and report as passed", func() { + Ω(outcome).Should(BeTrue()) + Ω(befSuite.Passed()).Should(BeTrue()) + }) + + It("should have the correct summary", func() { + summary := befSuite.Summary() + Ω(summary.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) + Ω(summary.CodeLocation).Should(Equal(codeLocation)) + Ω(summary.State).Should(Equal(types.SpecStatePassed)) + Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) + Ω(summary.Failure).Should(BeZero()) + }) + }) + + Context("when the body fails", func() { + BeforeEach(func() { + befSuite = NewBeforeSuiteNode(func() { + failer.Fail("oops", innerCodeLocation) + }, codeLocation, 0, failer) + outcome = befSuite.Run(0, 0, "") + }) + + It("should return false when run and report as failed", func() { + Ω(outcome).Should(BeFalse()) + Ω(befSuite.Passed()).Should(BeFalse()) + }) + + It("should have the correct summary", func() { + summary := befSuite.Summary() + Ω(summary.State).Should(Equal(types.SpecStateFailed)) + Ω(summary.Failure.Message).Should(Equal("oops")) + Ω(summary.Failure.Location).Should(Equal(innerCodeLocation)) + Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + + Context("when the body times out", func() { + BeforeEach(func() { + befSuite = NewBeforeSuiteNode(func(done Done) { + }, codeLocation, time.Millisecond, failer) + outcome = befSuite.Run(0, 0, "") + }) + + It("should return false when run and report as failed", func() { + Ω(outcome).Should(BeFalse()) + Ω(befSuite.Passed()).Should(BeFalse()) + }) + + It("should have the correct summary", func() { + summary := befSuite.Summary() + Ω(summary.State).Should(Equal(types.SpecStateTimedOut)) + Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + + Context("when the body panics", func() { + BeforeEach(func() { + befSuite = NewBeforeSuiteNode(func() { + panic("bam") + }, codeLocation, 0, failer) + outcome = befSuite.Run(0, 0, "") + }) + + It("should return false when run and report as failed", func() { + Ω(outcome).Should(BeFalse()) + Ω(befSuite.Passed()).Should(BeFalse()) + }) + + It("should have the correct summary", func() { + summary := befSuite.Summary() + Ω(summary.State).Should(Equal(types.SpecStatePanicked)) + Ω(summary.Failure.ForwardedPanic).Should(Equal("bam")) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + }) + + Describe("AfterSuite nodes", func() { + var aftSuite SuiteNode + var failer *Failer.Failer + var codeLocation types.CodeLocation + var innerCodeLocation types.CodeLocation + var outcome bool + + BeforeEach(func() { + failer = Failer.New() + codeLocation = codelocation.New(0) + innerCodeLocation = codelocation.New(0) + }) + + Context("when the body passes", func() { + BeforeEach(func() { + aftSuite = NewAfterSuiteNode(func() { + time.Sleep(10 * time.Millisecond) + }, codeLocation, 0, failer) + outcome = aftSuite.Run(0, 0, "") + }) + + It("should return true when run and report as passed", func() { + Ω(outcome).Should(BeTrue()) + Ω(aftSuite.Passed()).Should(BeTrue()) + }) + + It("should have the correct summary", func() { + summary := aftSuite.Summary() + Ω(summary.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) + Ω(summary.CodeLocation).Should(Equal(codeLocation)) + Ω(summary.State).Should(Equal(types.SpecStatePassed)) + Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) + Ω(summary.Failure).Should(BeZero()) + }) + }) + + Context("when the body fails", func() { + BeforeEach(func() { + aftSuite = NewAfterSuiteNode(func() { + failer.Fail("oops", innerCodeLocation) + }, codeLocation, 0, failer) + outcome = aftSuite.Run(0, 0, "") + }) + + It("should return false when run and report as failed", func() { + Ω(outcome).Should(BeFalse()) + Ω(aftSuite.Passed()).Should(BeFalse()) + }) + + It("should have the correct summary", func() { + summary := aftSuite.Summary() + Ω(summary.State).Should(Equal(types.SpecStateFailed)) + Ω(summary.Failure.Message).Should(Equal("oops")) + Ω(summary.Failure.Location).Should(Equal(innerCodeLocation)) + Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + + Context("when the body times out", func() { + BeforeEach(func() { + aftSuite = NewAfterSuiteNode(func(done Done) { + }, codeLocation, time.Millisecond, failer) + outcome = aftSuite.Run(0, 0, "") + }) + + It("should return false when run and report as failed", func() { + Ω(outcome).Should(BeFalse()) + Ω(aftSuite.Passed()).Should(BeFalse()) + }) + + It("should have the correct summary", func() { + summary := aftSuite.Summary() + Ω(summary.State).Should(Equal(types.SpecStateTimedOut)) + Ω(summary.Failure.ForwardedPanic).Should(BeEmpty()) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + + Context("when the body panics", func() { + BeforeEach(func() { + aftSuite = NewAfterSuiteNode(func() { + panic("bam") + }, codeLocation, 0, failer) + outcome = aftSuite.Run(0, 0, "") + }) + + It("should return false when run and report as failed", func() { + Ω(outcome).Should(BeFalse()) + Ω(aftSuite.Passed()).Should(BeFalse()) + }) + + It("should have the correct summary", func() { + summary := aftSuite.Summary() + Ω(summary.State).Should(Equal(types.SpecStatePanicked)) + Ω(summary.Failure.ForwardedPanic).Should(Equal("bam")) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeAfterSuite)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go new file mode 100644 index 000000000..edbdf6ae5 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_after_suite_node_test.go @@ -0,0 +1,199 @@ +package leafnodes_test + +import ( + "sync" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" + + "net/http" + + "github.com/onsi/gomega/ghttp" + + "time" + + "github.com/onsi/ginkgo/internal/codelocation" + Failer "github.com/onsi/ginkgo/internal/failer" +) + +var _ = Describe("SynchronizedAfterSuiteNode", func() { + var failer *Failer.Failer + var node SuiteNode + var codeLocation types.CodeLocation + var innerCodeLocation types.CodeLocation + var outcome bool + var server *ghttp.Server + var things []string + var lock *sync.Mutex + + BeforeEach(func() { + things = []string{} + server = ghttp.NewServer() + codeLocation = codelocation.New(0) + innerCodeLocation = codelocation.New(0) + failer = Failer.New() + lock = &sync.Mutex{} + }) + + AfterEach(func() { + server.Close() + }) + + newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode { + return NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer) + } + + ranThing := func(thing string) { + lock.Lock() + defer lock.Unlock() + things = append(things, thing) + } + + thingsThatRan := func() []string { + lock.Lock() + defer lock.Unlock() + return things + } + + Context("when not running in parallel", func() { + Context("when all is well", func() { + BeforeEach(func() { + node = newNode(func() { + ranThing("A") + }, func() { + ranThing("B") + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should run A, then B", func() { + Ω(thingsThatRan()).Should(Equal([]string{"A", "B"})) + }) + + It("should report success", func() { + Ω(outcome).Should(BeTrue()) + Ω(node.Passed()).Should(BeTrue()) + Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) + }) + }) + + Context("when A fails", func() { + BeforeEach(func() { + node = newNode(func() { + ranThing("A") + failer.Fail("bam", innerCodeLocation) + }, func() { + ranThing("B") + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should still run B", func() { + Ω(thingsThatRan()).Should(Equal([]string{"A", "B"})) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) + }) + }) + + Context("when B fails", func() { + BeforeEach(func() { + node = newNode(func() { + ranThing("A") + }, func() { + ranThing("B") + failer.Fail("bam", innerCodeLocation) + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should run all the things", func() { + Ω(thingsThatRan()).Should(Equal([]string{"A", "B"})) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) + }) + }) + }) + + Context("when running in parallel", func() { + Context("as the first node", func() { + BeforeEach(func() { + server.AppendHandlers(ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), + func(writer http.ResponseWriter, request *http.Request) { + ranThing("Request1") + }, + ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}), + ), ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), + func(writer http.ResponseWriter, request *http.Request) { + ranThing("Request2") + }, + ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}), + ), ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"), + func(writer http.ResponseWriter, request *http.Request) { + ranThing("Request3") + }, + ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: true}), + )) + + node = newNode(func() { + ranThing("A") + }, func() { + ranThing("B") + }) + + outcome = node.Run(1, 3, server.URL()) + }) + + It("should run A and, when the server says its time, run B", func() { + Ω(thingsThatRan()).Should(Equal([]string{"A", "Request1", "Request2", "Request3", "B"})) + }) + + It("should report success", func() { + Ω(outcome).Should(BeTrue()) + Ω(node.Passed()).Should(BeTrue()) + Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) + }) + }) + + Context("as any other node", func() { + BeforeEach(func() { + node = newNode(func() { + ranThing("A") + }, func() { + ranThing("B") + }) + + outcome = node.Run(2, 3, server.URL()) + }) + + It("should run A, and not run B", func() { + Ω(thingsThatRan()).Should(Equal([]string{"A"})) + }) + + It("should not talk to the server", func() { + Ω(server.ReceivedRequests()).Should(BeEmpty()) + }) + + It("should report success", func() { + Ω(outcome).Should(BeTrue()) + Ω(node.Passed()).Should(BeTrue()) + Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go new file mode 100644 index 000000000..46c3e276b --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/leafnodes/synchronized_before_suite_node_test.go @@ -0,0 +1,446 @@ +package leafnodes_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/leafnodes" + . "github.com/onsi/gomega" + + "net/http" + + "github.com/onsi/gomega/ghttp" + + "time" + + "github.com/onsi/ginkgo/internal/codelocation" + Failer "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("SynchronizedBeforeSuiteNode", func() { + var failer *Failer.Failer + var node SuiteNode + var codeLocation types.CodeLocation + var innerCodeLocation types.CodeLocation + var outcome bool + var server *ghttp.Server + + BeforeEach(func() { + server = ghttp.NewServer() + codeLocation = codelocation.New(0) + innerCodeLocation = codelocation.New(0) + failer = Failer.New() + }) + + AfterEach(func() { + server.Close() + }) + + newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode { + return NewSynchronizedBeforeSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer) + } + + Describe("when not running in parallel", func() { + Context("when all is well", func() { + var data []byte + BeforeEach(func() { + data = nil + + node = newNode(func() []byte { + return []byte("my data") + }, func(d []byte) { + data = d + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should run A, then B passing the output from A to B", func() { + Ω(data).Should(Equal([]byte("my data"))) + }) + + It("should report success", func() { + Ω(outcome).Should(BeTrue()) + Ω(node.Passed()).Should(BeTrue()) + Ω(node.Summary().State).Should(Equal(types.SpecStatePassed)) + }) + }) + + Context("when A fails", func() { + var ranB bool + BeforeEach(func() { + ranB = false + node = newNode(func() []byte { + failer.Fail("boom", innerCodeLocation) + return nil + }, func([]byte) { + ranB = true + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should not run B", func() { + Ω(ranB).Should(BeFalse()) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) + }) + }) + + Context("when B fails", func() { + BeforeEach(func() { + node = newNode(func() []byte { + return nil + }, func([]byte) { + failer.Fail("boom", innerCodeLocation) + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + Ω(node.Summary().State).Should(Equal(types.SpecStateFailed)) + }) + }) + + Context("when A times out", func() { + var ranB bool + BeforeEach(func() { + ranB = false + node = newNode(func(Done) []byte { + time.Sleep(time.Second) + return nil + }, func([]byte) { + ranB = true + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should not run B", func() { + Ω(ranB).Should(BeFalse()) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + Ω(node.Summary().State).Should(Equal(types.SpecStateTimedOut)) + }) + }) + + Context("when B times out", func() { + BeforeEach(func() { + node = newNode(func() []byte { + return nil + }, func([]byte, Done) { + time.Sleep(time.Second) + }) + + outcome = node.Run(1, 1, server.URL()) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + Ω(node.Summary().State).Should(Equal(types.SpecStateTimedOut)) + }) + }) + }) + + Describe("when running in parallel", func() { + var ranB bool + var parallelNode, parallelTotal int + BeforeEach(func() { + ranB = false + parallelNode, parallelTotal = 1, 3 + }) + + Context("as the first node, it runs A", func() { + var expectedState types.RemoteBeforeSuiteData + + BeforeEach(func() { + parallelNode, parallelTotal = 1, 3 + }) + + JustBeforeEach(func() { + server.AppendHandlers(ghttp.CombineHandlers( + ghttp.VerifyRequest("POST", "/BeforeSuiteState"), + ghttp.VerifyJSONRepresenting(expectedState), + )) + + outcome = node.Run(parallelNode, parallelTotal, server.URL()) + }) + + Context("when A succeeds", func() { + BeforeEach(func() { + expectedState = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed} + + node = newNode(func() []byte { + return []byte("my data") + }, func([]byte) { + ranB = true + }) + }) + + It("should post about A succeeding", func() { + Ω(server.ReceivedRequests()).Should(HaveLen(1)) + }) + + It("should run B", func() { + Ω(ranB).Should(BeTrue()) + }) + + It("should report success", func() { + Ω(outcome).Should(BeTrue()) + }) + }) + + Context("when A fails", func() { + BeforeEach(func() { + expectedState = types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateFailed} + + node = newNode(func() []byte { + panic("BAM") + }, func([]byte) { + ranB = true + }) + }) + + It("should post about A failing", func() { + Ω(server.ReceivedRequests()).Should(HaveLen(1)) + }) + + It("should not run B", func() { + Ω(ranB).Should(BeFalse()) + }) + + It("should report failure", func() { + Ω(outcome).Should(BeFalse()) + }) + }) + }) + + Context("as the Nth node", func() { + var statusCode int + var response interface{} + var ranA bool + var bData []byte + + BeforeEach(func() { + ranA = false + bData = nil + + statusCode = http.StatusOK + + server.AppendHandlers(ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/BeforeSuiteState"), + ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())), + ), ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/BeforeSuiteState"), + ghttp.RespondWith(http.StatusOK, string((types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending}).ToJSON())), + ), ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/BeforeSuiteState"), + ghttp.RespondWithJSONEncodedPtr(&statusCode, &response), + )) + + node = newNode(func() []byte { + ranA = true + return nil + }, func(data []byte) { + bData = data + }) + + parallelNode, parallelTotal = 2, 3 + }) + + Context("when A on node1 succeeds", func() { + BeforeEach(func() { + response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStatePassed} + outcome = node.Run(parallelNode, parallelTotal, server.URL()) + }) + + It("should not run A", func() { + Ω(ranA).Should(BeFalse()) + }) + + It("should poll for A", func() { + Ω(server.ReceivedRequests()).Should(HaveLen(3)) + }) + + It("should run B when the polling succeeds", func() { + Ω(bData).Should(Equal([]byte("my data"))) + }) + + It("should succeed", func() { + Ω(outcome).Should(BeTrue()) + Ω(node.Passed()).Should(BeTrue()) + }) + }) + + Context("when A on node1 fails", func() { + BeforeEach(func() { + response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateFailed} + outcome = node.Run(parallelNode, parallelTotal, server.URL()) + }) + + It("should not run A", func() { + Ω(ranA).Should(BeFalse()) + }) + + It("should poll for A", func() { + Ω(server.ReceivedRequests()).Should(HaveLen(3)) + }) + + It("should not run B", func() { + Ω(bData).Should(BeNil()) + }) + + It("should fail", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + + summary := node.Summary() + Ω(summary.State).Should(Equal(types.SpecStateFailed)) + Ω(summary.Failure.Message).Should(Equal("BeforeSuite on Node 1 failed")) + Ω(summary.Failure.Location).Should(Equal(codeLocation)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + + Context("when node1 disappears", func() { + BeforeEach(func() { + response = types.RemoteBeforeSuiteData{Data: []byte("my data"), State: types.RemoteBeforeSuiteStateDisappeared} + outcome = node.Run(parallelNode, parallelTotal, server.URL()) + }) + + It("should not run A", func() { + Ω(ranA).Should(BeFalse()) + }) + + It("should poll for A", func() { + Ω(server.ReceivedRequests()).Should(HaveLen(3)) + }) + + It("should not run B", func() { + Ω(bData).Should(BeNil()) + }) + + It("should fail", func() { + Ω(outcome).Should(BeFalse()) + Ω(node.Passed()).Should(BeFalse()) + + summary := node.Summary() + Ω(summary.State).Should(Equal(types.SpecStateFailed)) + Ω(summary.Failure.Message).Should(Equal("Node 1 disappeared before completing BeforeSuite")) + Ω(summary.Failure.Location).Should(Equal(codeLocation)) + Ω(summary.Failure.ComponentType).Should(Equal(types.SpecComponentTypeBeforeSuite)) + Ω(summary.Failure.ComponentIndex).Should(Equal(0)) + Ω(summary.Failure.ComponentCodeLocation).Should(Equal(codeLocation)) + }) + }) + }) + }) + + Describe("construction", func() { + Describe("the first function", func() { + Context("when the first function returns a byte array", func() { + Context("and takes nothing", func() { + It("should be fine", func() { + Ω(func() { + newNode(func() []byte { return nil }, func([]byte) {}) + }).ShouldNot(Panic()) + }) + }) + + Context("and takes a done function", func() { + It("should be fine", func() { + Ω(func() { + newNode(func(Done) []byte { return nil }, func([]byte) {}) + }).ShouldNot(Panic()) + }) + }) + + Context("and takes more than one thing", func() { + It("should panic", func() { + Ω(func() { + newNode(func(Done, Done) []byte { return nil }, func([]byte) {}) + }).Should(Panic()) + }) + }) + + Context("and takes something else", func() { + It("should panic", func() { + Ω(func() { + newNode(func(bool) []byte { return nil }, func([]byte) {}) + }).Should(Panic()) + }) + }) + }) + + Context("when the first function does not return a byte array", func() { + It("should panic", func() { + Ω(func() { + newNode(func() {}, func([]byte) {}) + }).Should(Panic()) + + Ω(func() { + newNode(func() []int { return nil }, func([]byte) {}) + }).Should(Panic()) + }) + }) + }) + + Describe("the second function", func() { + Context("when the second function takes a byte array", func() { + It("should be fine", func() { + Ω(func() { + newNode(func() []byte { return nil }, func([]byte) {}) + }).ShouldNot(Panic()) + }) + }) + + Context("when it also takes a done channel", func() { + It("should be fine", func() { + Ω(func() { + newNode(func() []byte { return nil }, func([]byte, Done) {}) + }).ShouldNot(Panic()) + }) + }) + + Context("if it takes anything else", func() { + It("should panic", func() { + Ω(func() { + newNode(func() []byte { return nil }, func([]byte, chan bool) {}) + }).Should(Panic()) + + Ω(func() { + newNode(func() []byte { return nil }, func(string) {}) + }).Should(Panic()) + }) + }) + + Context("if it takes nothing at all", func() { + It("should panic", func() { + Ω(func() { + newNode(func() []byte { return nil }, func() {}) + }).Should(Panic()) + }) + }) + + Context("if it returns something", func() { + It("should panic", func() { + Ω(func() { + newNode(func() []byte { return nil }, func([]byte) []byte { return nil }) + }).Should(Panic()) + }) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/aggregator_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/aggregator_test.go new file mode 100644 index 000000000..aedf93927 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/remote/aggregator_test.go @@ -0,0 +1,315 @@ +package remote_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "time" + + "github.com/onsi/ginkgo/config" + . "github.com/onsi/ginkgo/internal/remote" + st "github.com/onsi/ginkgo/reporters/stenographer" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("Aggregator", func() { + var ( + aggregator *Aggregator + reporterConfig config.DefaultReporterConfigType + stenographer *st.FakeStenographer + result chan bool + + ginkgoConfig1 config.GinkgoConfigType + ginkgoConfig2 config.GinkgoConfigType + + suiteSummary1 *types.SuiteSummary + suiteSummary2 *types.SuiteSummary + + beforeSummary *types.SetupSummary + afterSummary *types.SetupSummary + specSummary *types.SpecSummary + + suiteDescription string + ) + + BeforeEach(func() { + reporterConfig = config.DefaultReporterConfigType{ + NoColor: false, + SlowSpecThreshold: 0.1, + NoisyPendings: true, + Succinct: false, + Verbose: true, + } + stenographer = st.NewFakeStenographer() + result = make(chan bool, 1) + aggregator = NewAggregator(2, result, reporterConfig, stenographer) + + // + // now set up some fixture data + // + + ginkgoConfig1 = config.GinkgoConfigType{ + RandomSeed: 1138, + RandomizeAllSpecs: true, + ParallelNode: 1, + ParallelTotal: 2, + } + + ginkgoConfig2 = config.GinkgoConfigType{ + RandomSeed: 1138, + RandomizeAllSpecs: true, + ParallelNode: 2, + ParallelTotal: 2, + } + + suiteDescription = "My Parallel Suite" + + suiteSummary1 = &types.SuiteSummary{ + SuiteDescription: suiteDescription, + + NumberOfSpecsBeforeParallelization: 30, + NumberOfTotalSpecs: 17, + NumberOfSpecsThatWillBeRun: 15, + NumberOfPendingSpecs: 1, + NumberOfSkippedSpecs: 1, + } + + suiteSummary2 = &types.SuiteSummary{ + SuiteDescription: suiteDescription, + + NumberOfSpecsBeforeParallelization: 30, + NumberOfTotalSpecs: 13, + NumberOfSpecsThatWillBeRun: 8, + NumberOfPendingSpecs: 2, + NumberOfSkippedSpecs: 3, + } + + beforeSummary = &types.SetupSummary{ + State: types.SpecStatePassed, + CapturedOutput: "BeforeSuiteOutput", + } + + afterSummary = &types.SetupSummary{ + State: types.SpecStatePassed, + CapturedOutput: "AfterSuiteOutput", + } + + specSummary = &types.SpecSummary{ + State: types.SpecStatePassed, + CapturedOutput: "SpecOutput", + } + }) + + call := func(method string, args ...interface{}) st.FakeStenographerCall { + return st.NewFakeStenographerCall(method, args...) + } + + beginSuite := func() { + stenographer.Reset() + aggregator.SpecSuiteWillBegin(ginkgoConfig2, suiteSummary2) + aggregator.SpecSuiteWillBegin(ginkgoConfig1, suiteSummary1) + Eventually(func() interface{} { + return len(stenographer.Calls()) + }).Should(BeNumerically(">=", 3)) + } + + Describe("Announcing the beginning of the suite", func() { + Context("When one of the parallel-suites starts", func() { + BeforeEach(func() { + aggregator.SpecSuiteWillBegin(ginkgoConfig2, suiteSummary2) + }) + + It("should be silent", func() { + Consistently(func() interface{} { return stenographer.Calls() }).Should(BeEmpty()) + }) + }) + + Context("once all of the parallel-suites have started", func() { + BeforeEach(func() { + aggregator.SpecSuiteWillBegin(ginkgoConfig2, suiteSummary2) + aggregator.SpecSuiteWillBegin(ginkgoConfig1, suiteSummary1) + Eventually(func() interface{} { + return stenographer.Calls() + }).Should(HaveLen(3)) + }) + + It("should announce the beginning of the suite", func() { + Ω(stenographer.Calls()).Should(HaveLen(3)) + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", suiteDescription, ginkgoConfig1.RandomSeed, true, false))) + Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceTotalNumberOfSpecs", 30, false))) + Ω(stenographer.Calls()[2]).Should(Equal(call("AnnounceAggregatedParallelRun", 2, false))) + }) + }) + }) + + Describe("Announcing specs and before suites", func() { + Context("when the parallel-suites have not all started", func() { + BeforeEach(func() { + aggregator.BeforeSuiteDidRun(beforeSummary) + aggregator.AfterSuiteDidRun(afterSummary) + aggregator.SpecDidComplete(specSummary) + }) + + It("should not announce any specs", func() { + Consistently(func() interface{} { return stenographer.Calls() }).Should(BeEmpty()) + }) + + Context("when the parallel-suites subsequently start", func() { + BeforeEach(func() { + beginSuite() + }) + + It("should announce the specs, the before suites and the after suites", func() { + Eventually(func() interface{} { + return stenographer.Calls() + }).Should(ContainElement(call("AnnounceSuccesfulSpec", specSummary))) + + Ω(stenographer.Calls()).Should(ContainElement(call("AnnounceCapturedOutput", beforeSummary.CapturedOutput))) + Ω(stenographer.Calls()).Should(ContainElement(call("AnnounceCapturedOutput", afterSummary.CapturedOutput))) + }) + }) + }) + + Context("When the parallel-suites have all started", func() { + BeforeEach(func() { + beginSuite() + stenographer.Reset() + }) + + Context("When a spec completes", func() { + BeforeEach(func() { + aggregator.BeforeSuiteDidRun(beforeSummary) + aggregator.SpecDidComplete(specSummary) + aggregator.AfterSuiteDidRun(afterSummary) + Eventually(func() interface{} { + return stenographer.Calls() + }).Should(HaveLen(5)) + }) + + It("should announce the captured output of the BeforeSuite", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceCapturedOutput", beforeSummary.CapturedOutput))) + }) + + It("should announce that the spec will run (when in verbose mode)", func() { + Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceSpecWillRun", specSummary))) + }) + + It("should announce the captured stdout of the spec", func() { + Ω(stenographer.Calls()[2]).Should(Equal(call("AnnounceCapturedOutput", specSummary.CapturedOutput))) + }) + + It("should announce completion", func() { + Ω(stenographer.Calls()[3]).Should(Equal(call("AnnounceSuccesfulSpec", specSummary))) + }) + + It("should announce the captured output of the AfterSuite", func() { + Ω(stenographer.Calls()[4]).Should(Equal(call("AnnounceCapturedOutput", afterSummary.CapturedOutput))) + }) + }) + }) + }) + + Describe("Announcing the end of the suite", func() { + BeforeEach(func() { + beginSuite() + stenographer.Reset() + }) + + Context("When one of the parallel-suites ends", func() { + BeforeEach(func() { + aggregator.SpecSuiteDidEnd(suiteSummary2) + }) + + It("should be silent", func() { + Consistently(func() interface{} { return stenographer.Calls() }).Should(BeEmpty()) + }) + + It("should not notify the channel", func() { + Ω(result).Should(BeEmpty()) + }) + }) + + Context("once all of the parallel-suites end", func() { + BeforeEach(func() { + time.Sleep(200 * time.Millisecond) + + suiteSummary1.SuiteSucceeded = true + suiteSummary1.NumberOfPassedSpecs = 15 + suiteSummary1.NumberOfFailedSpecs = 0 + suiteSummary1.NumberOfFlakedSpecs = 3 + suiteSummary2.SuiteSucceeded = false + suiteSummary2.NumberOfPassedSpecs = 5 + suiteSummary2.NumberOfFailedSpecs = 3 + suiteSummary2.NumberOfFlakedSpecs = 4 + + aggregator.SpecSuiteDidEnd(suiteSummary2) + aggregator.SpecSuiteDidEnd(suiteSummary1) + Eventually(func() interface{} { + return stenographer.Calls() + }).Should(HaveLen(2)) + }) + + It("should announce the end of the suite", func() { + compositeSummary := stenographer.Calls()[1].Args[0].(*types.SuiteSummary) + + Ω(compositeSummary.SuiteSucceeded).Should(BeFalse()) + Ω(compositeSummary.NumberOfSpecsThatWillBeRun).Should(Equal(23)) + Ω(compositeSummary.NumberOfTotalSpecs).Should(Equal(30)) + Ω(compositeSummary.NumberOfPassedSpecs).Should(Equal(20)) + Ω(compositeSummary.NumberOfFailedSpecs).Should(Equal(3)) + Ω(compositeSummary.NumberOfPendingSpecs).Should(Equal(3)) + Ω(compositeSummary.NumberOfSkippedSpecs).Should(Equal(4)) + Ω(compositeSummary.NumberOfFlakedSpecs).Should(Equal(7)) + Ω(compositeSummary.RunTime.Seconds()).Should(BeNumerically(">", 0.2)) + }) + }) + + Context("when all the parallel-suites pass", func() { + BeforeEach(func() { + suiteSummary1.SuiteSucceeded = true + suiteSummary2.SuiteSucceeded = true + + aggregator.SpecSuiteDidEnd(suiteSummary2) + aggregator.SpecSuiteDidEnd(suiteSummary1) + Eventually(func() interface{} { + return stenographer.Calls() + }).Should(HaveLen(2)) + }) + + It("should report success", func() { + compositeSummary := stenographer.Calls()[1].Args[0].(*types.SuiteSummary) + + Ω(compositeSummary.SuiteSucceeded).Should(BeTrue()) + }) + + It("should notify the channel that it succeded", func(done Done) { + Ω(<-result).Should(BeTrue()) + close(done) + }) + }) + + Context("when one of the parallel-suites fails", func() { + BeforeEach(func() { + suiteSummary1.SuiteSucceeded = true + suiteSummary2.SuiteSucceeded = false + + aggregator.SpecSuiteDidEnd(suiteSummary2) + aggregator.SpecSuiteDidEnd(suiteSummary1) + Eventually(func() interface{} { + return stenographer.Calls() + }).Should(HaveLen(2)) + }) + + It("should report failure", func() { + compositeSummary := stenographer.Calls()[1].Args[0].(*types.SuiteSummary) + + Ω(compositeSummary.SuiteSucceeded).Should(BeFalse()) + }) + + It("should notify the channel that it failed", func(done Done) { + Ω(<-result).Should(BeFalse()) + close(done) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go new file mode 100644 index 000000000..a928f93d3 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/remote/fake_output_interceptor_test.go @@ -0,0 +1,17 @@ +package remote_test + +type fakeOutputInterceptor struct { + DidStartInterceptingOutput bool + DidStopInterceptingOutput bool + InterceptedOutput string +} + +func (interceptor *fakeOutputInterceptor) StartInterceptingOutput() error { + interceptor.DidStartInterceptingOutput = true + return nil +} + +func (interceptor *fakeOutputInterceptor) StopInterceptingAndReturnOutput() (string, error) { + interceptor.DidStopInterceptingOutput = true + return interceptor.InterceptedOutput, nil +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/fake_poster_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/fake_poster_test.go new file mode 100644 index 000000000..3543c59c6 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/remote/fake_poster_test.go @@ -0,0 +1,33 @@ +package remote_test + +import ( + "io" + "io/ioutil" + "net/http" +) + +type post struct { + url string + bodyType string + bodyContent []byte +} + +type fakePoster struct { + posts []post +} + +func newFakePoster() *fakePoster { + return &fakePoster{ + posts: make([]post, 0), + } +} + +func (poster *fakePoster) Post(url string, bodyType string, body io.Reader) (resp *http.Response, err error) { + bodyContent, _ := ioutil.ReadAll(body) + poster.posts = append(poster.posts, post{ + url: url, + bodyType: bodyType, + bodyContent: bodyContent, + }) + return nil, nil +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go new file mode 100644 index 000000000..be7768e70 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/remote/forwarding_reporter_test.go @@ -0,0 +1,181 @@ +package remote_test + +import ( + "encoding/json" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/config" + . "github.com/onsi/ginkgo/internal/remote" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" +) + +var _ = Describe("ForwardingReporter", func() { + var ( + reporter *ForwardingReporter + interceptor *fakeOutputInterceptor + poster *fakePoster + suiteSummary *types.SuiteSummary + specSummary *types.SpecSummary + setupSummary *types.SetupSummary + serverHost string + ) + + BeforeEach(func() { + serverHost = "http://127.0.0.1:7788" + + poster = newFakePoster() + + interceptor = &fakeOutputInterceptor{ + InterceptedOutput: "The intercepted output!", + } + + reporter = NewForwardingReporter(serverHost, poster, interceptor) + + suiteSummary = &types.SuiteSummary{ + SuiteDescription: "My Test Suite", + } + + setupSummary = &types.SetupSummary{ + State: types.SpecStatePassed, + } + + specSummary = &types.SpecSummary{ + ComponentTexts: []string{"My", "Spec"}, + State: types.SpecStatePassed, + } + }) + + Context("When a suite begins", func() { + BeforeEach(func() { + reporter.SpecSuiteWillBegin(config.GinkgoConfig, suiteSummary) + }) + + It("should start intercepting output", func() { + Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) + }) + + It("should POST the SuiteSummary and Ginkgo Config to the Ginkgo server", func() { + Ω(poster.posts).Should(HaveLen(1)) + Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/SpecSuiteWillBegin")) + Ω(poster.posts[0].bodyType).Should(Equal("application/json")) + + var sentData struct { + SentConfig config.GinkgoConfigType `json:"config"` + SentSuiteSummary *types.SuiteSummary `json:"suite-summary"` + } + + err := json.Unmarshal(poster.posts[0].bodyContent, &sentData) + Ω(err).ShouldNot(HaveOccurred()) + + Ω(sentData.SentConfig).Should(Equal(config.GinkgoConfig)) + Ω(sentData.SentSuiteSummary).Should(Equal(suiteSummary)) + }) + }) + + Context("when a BeforeSuite completes", func() { + BeforeEach(func() { + reporter.BeforeSuiteDidRun(setupSummary) + }) + + It("should stop, then start intercepting output", func() { + Ω(interceptor.DidStopInterceptingOutput).Should(BeTrue()) + Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) + }) + + It("should POST the SetupSummary to the Ginkgo server", func() { + Ω(poster.posts).Should(HaveLen(1)) + Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/BeforeSuiteDidRun")) + Ω(poster.posts[0].bodyType).Should(Equal("application/json")) + + var summary *types.SetupSummary + err := json.Unmarshal(poster.posts[0].bodyContent, &summary) + Ω(err).ShouldNot(HaveOccurred()) + setupSummary.CapturedOutput = interceptor.InterceptedOutput + Ω(summary).Should(Equal(setupSummary)) + }) + }) + + Context("when an AfterSuite completes", func() { + BeforeEach(func() { + reporter.AfterSuiteDidRun(setupSummary) + }) + + It("should stop, then start intercepting output", func() { + Ω(interceptor.DidStopInterceptingOutput).Should(BeTrue()) + Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) + }) + + It("should POST the SetupSummary to the Ginkgo server", func() { + Ω(poster.posts).Should(HaveLen(1)) + Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/AfterSuiteDidRun")) + Ω(poster.posts[0].bodyType).Should(Equal("application/json")) + + var summary *types.SetupSummary + err := json.Unmarshal(poster.posts[0].bodyContent, &summary) + Ω(err).ShouldNot(HaveOccurred()) + setupSummary.CapturedOutput = interceptor.InterceptedOutput + Ω(summary).Should(Equal(setupSummary)) + }) + }) + + Context("When a spec will run", func() { + BeforeEach(func() { + reporter.SpecWillRun(specSummary) + }) + + It("should POST the SpecSummary to the Ginkgo server", func() { + Ω(poster.posts).Should(HaveLen(1)) + Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/SpecWillRun")) + Ω(poster.posts[0].bodyType).Should(Equal("application/json")) + + var summary *types.SpecSummary + err := json.Unmarshal(poster.posts[0].bodyContent, &summary) + Ω(err).ShouldNot(HaveOccurred()) + Ω(summary).Should(Equal(specSummary)) + }) + + Context("When a spec completes", func() { + BeforeEach(func() { + specSummary.State = types.SpecStatePanicked + reporter.SpecDidComplete(specSummary) + }) + + It("should POST the SpecSummary to the Ginkgo server and include any intercepted output", func() { + Ω(poster.posts).Should(HaveLen(2)) + Ω(poster.posts[1].url).Should(Equal("http://127.0.0.1:7788/SpecDidComplete")) + Ω(poster.posts[1].bodyType).Should(Equal("application/json")) + + var summary *types.SpecSummary + err := json.Unmarshal(poster.posts[1].bodyContent, &summary) + Ω(err).ShouldNot(HaveOccurred()) + specSummary.CapturedOutput = interceptor.InterceptedOutput + Ω(summary).Should(Equal(specSummary)) + }) + + It("should stop, then start intercepting output", func() { + Ω(interceptor.DidStopInterceptingOutput).Should(BeTrue()) + Ω(interceptor.DidStartInterceptingOutput).Should(BeTrue()) + }) + }) + }) + + Context("When a suite ends", func() { + BeforeEach(func() { + reporter.SpecSuiteDidEnd(suiteSummary) + }) + + It("should POST the SuiteSummary to the Ginkgo server", func() { + Ω(poster.posts).Should(HaveLen(1)) + Ω(poster.posts[0].url).Should(Equal("http://127.0.0.1:7788/SpecSuiteDidEnd")) + Ω(poster.posts[0].bodyType).Should(Equal("application/json")) + + var summary *types.SuiteSummary + + err := json.Unmarshal(poster.posts[0].bodyContent, &summary) + Ω(err).ShouldNot(HaveOccurred()) + + Ω(summary).Should(Equal(suiteSummary)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/remote_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/remote_suite_test.go new file mode 100644 index 000000000..e6b4e9f32 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/remote/remote_suite_test.go @@ -0,0 +1,13 @@ +package remote_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestRemote(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Remote Spec Forwarding Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go b/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go new file mode 100644 index 000000000..569fafae0 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/remote/server_test.go @@ -0,0 +1,269 @@ +package remote_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/remote" + . "github.com/onsi/gomega" + + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/reporters" + "github.com/onsi/ginkgo/types" + + "bytes" + "encoding/json" + "net/http" +) + +var _ = Describe("Server", func() { + var ( + server *Server + ) + + BeforeEach(func() { + var err error + server, err = NewServer(3) + Ω(err).ShouldNot(HaveOccurred()) + + server.Start() + }) + + AfterEach(func() { + server.Close() + }) + + Describe("Streaming endpoints", func() { + var ( + reporterA, reporterB *reporters.FakeReporter + forwardingReporter *ForwardingReporter + + suiteSummary *types.SuiteSummary + setupSummary *types.SetupSummary + specSummary *types.SpecSummary + ) + + BeforeEach(func() { + reporterA = reporters.NewFakeReporter() + reporterB = reporters.NewFakeReporter() + + server.RegisterReporters(reporterA, reporterB) + + forwardingReporter = NewForwardingReporter(server.Address(), &http.Client{}, &fakeOutputInterceptor{}) + + suiteSummary = &types.SuiteSummary{ + SuiteDescription: "My Test Suite", + } + + setupSummary = &types.SetupSummary{ + State: types.SpecStatePassed, + } + + specSummary = &types.SpecSummary{ + ComponentTexts: []string{"My", "Spec"}, + State: types.SpecStatePassed, + } + }) + + It("should make its address available", func() { + Ω(server.Address()).Should(MatchRegexp(`http://127.0.0.1:\d{2,}`)) + }) + + Describe("/SpecSuiteWillBegin", func() { + It("should decode and forward the Ginkgo config and suite summary", func(done Done) { + forwardingReporter.SpecSuiteWillBegin(config.GinkgoConfig, suiteSummary) + Ω(reporterA.Config).Should(Equal(config.GinkgoConfig)) + Ω(reporterB.Config).Should(Equal(config.GinkgoConfig)) + Ω(reporterA.BeginSummary).Should(Equal(suiteSummary)) + Ω(reporterB.BeginSummary).Should(Equal(suiteSummary)) + close(done) + }) + }) + + Describe("/BeforeSuiteDidRun", func() { + It("should decode and forward the setup summary", func() { + forwardingReporter.BeforeSuiteDidRun(setupSummary) + Ω(reporterA.BeforeSuiteSummary).Should(Equal(setupSummary)) + Ω(reporterB.BeforeSuiteSummary).Should(Equal(setupSummary)) + }) + }) + + Describe("/AfterSuiteDidRun", func() { + It("should decode and forward the setup summary", func() { + forwardingReporter.AfterSuiteDidRun(setupSummary) + Ω(reporterA.AfterSuiteSummary).Should(Equal(setupSummary)) + Ω(reporterB.AfterSuiteSummary).Should(Equal(setupSummary)) + }) + }) + + Describe("/SpecWillRun", func() { + It("should decode and forward the spec summary", func(done Done) { + forwardingReporter.SpecWillRun(specSummary) + Ω(reporterA.SpecWillRunSummaries[0]).Should(Equal(specSummary)) + Ω(reporterB.SpecWillRunSummaries[0]).Should(Equal(specSummary)) + close(done) + }) + }) + + Describe("/SpecDidComplete", func() { + It("should decode and forward the spec summary", func(done Done) { + forwardingReporter.SpecDidComplete(specSummary) + Ω(reporterA.SpecSummaries[0]).Should(Equal(specSummary)) + Ω(reporterB.SpecSummaries[0]).Should(Equal(specSummary)) + close(done) + }) + }) + + Describe("/SpecSuiteDidEnd", func() { + It("should decode and forward the suite summary", func(done Done) { + forwardingReporter.SpecSuiteDidEnd(suiteSummary) + Ω(reporterA.EndSummary).Should(Equal(suiteSummary)) + Ω(reporterB.EndSummary).Should(Equal(suiteSummary)) + close(done) + }) + }) + }) + + Describe("Synchronization endpoints", func() { + Describe("GETting and POSTing BeforeSuiteState", func() { + getBeforeSuite := func() types.RemoteBeforeSuiteData { + resp, err := http.Get(server.Address() + "/BeforeSuiteState") + Ω(err).ShouldNot(HaveOccurred()) + Ω(resp.StatusCode).Should(Equal(http.StatusOK)) + + r := types.RemoteBeforeSuiteData{} + decoder := json.NewDecoder(resp.Body) + err = decoder.Decode(&r) + Ω(err).ShouldNot(HaveOccurred()) + + return r + } + + postBeforeSuite := func(r types.RemoteBeforeSuiteData) { + resp, err := http.Post(server.Address()+"/BeforeSuiteState", "application/json", bytes.NewReader(r.ToJSON())) + Ω(err).ShouldNot(HaveOccurred()) + Ω(resp.StatusCode).Should(Equal(http.StatusOK)) + } + + Context("when the first node's Alive has not been registered yet", func() { + It("should return pending", func() { + state := getBeforeSuite() + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) + + state = getBeforeSuite() + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) + }) + }) + + Context("when the first node is Alive but has not responded yet", func() { + BeforeEach(func() { + server.RegisterAlive(1, func() bool { + return true + }) + }) + + It("should return pending", func() { + state := getBeforeSuite() + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) + + state = getBeforeSuite() + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending})) + }) + }) + + Context("when the first node has responded", func() { + var state types.RemoteBeforeSuiteData + BeforeEach(func() { + server.RegisterAlive(1, func() bool { + return false + }) + + state = types.RemoteBeforeSuiteData{ + Data: []byte("my data"), + State: types.RemoteBeforeSuiteStatePassed, + } + postBeforeSuite(state) + }) + + It("should return the passed in state", func() { + returnedState := getBeforeSuite() + Ω(returnedState).Should(Equal(state)) + }) + }) + + Context("when the first node is no longer Alive and has not responded yet", func() { + BeforeEach(func() { + server.RegisterAlive(1, func() bool { + return false + }) + }) + + It("should return disappeared", func() { + state := getBeforeSuite() + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateDisappeared})) + + state = getBeforeSuite() + Ω(state).Should(Equal(types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStateDisappeared})) + }) + }) + }) + + Describe("GETting RemoteAfterSuiteData", func() { + getRemoteAfterSuiteData := func() bool { + resp, err := http.Get(server.Address() + "/RemoteAfterSuiteData") + Ω(err).ShouldNot(HaveOccurred()) + Ω(resp.StatusCode).Should(Equal(http.StatusOK)) + + a := types.RemoteAfterSuiteData{} + decoder := json.NewDecoder(resp.Body) + err = decoder.Decode(&a) + Ω(err).ShouldNot(HaveOccurred()) + + return a.CanRun + } + + Context("when there are unregistered nodes", func() { + BeforeEach(func() { + server.RegisterAlive(2, func() bool { + return false + }) + }) + + It("should return false", func() { + Ω(getRemoteAfterSuiteData()).Should(BeFalse()) + }) + }) + + Context("when all none-node-1 nodes are still running", func() { + BeforeEach(func() { + server.RegisterAlive(2, func() bool { + return true + }) + + server.RegisterAlive(3, func() bool { + return false + }) + }) + + It("should return false", func() { + Ω(getRemoteAfterSuiteData()).Should(BeFalse()) + }) + }) + + Context("when all none-1 nodes are done", func() { + BeforeEach(func() { + server.RegisterAlive(2, func() bool { + return false + }) + + server.RegisterAlive(3, func() bool { + return false + }) + }) + + It("should return true", func() { + Ω(getRemoteAfterSuiteData()).Should(BeTrue()) + }) + + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/spec_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/spec/spec_suite_test.go new file mode 100644 index 000000000..8681a7206 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec/spec_suite_test.go @@ -0,0 +1,13 @@ +package spec_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestSpec(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Spec Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go b/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go new file mode 100644 index 000000000..7011a42eb --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec/spec_test.go @@ -0,0 +1,664 @@ +package spec_test + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + . "github.com/onsi/ginkgo/internal/spec" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/internal/containernode" + Failer "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/types" +) + +var noneFlag = types.FlagTypeNone +var focusedFlag = types.FlagTypeFocused +var pendingFlag = types.FlagTypePending + +var _ = Describe("Spec", func() { + var ( + failer *Failer.Failer + codeLocation types.CodeLocation + nodesThatRan []string + spec *Spec + buffer *gbytes.Buffer + ) + + newBody := func(text string, fail bool) func() { + return func() { + nodesThatRan = append(nodesThatRan, text) + if fail { + failer.Fail(text, codeLocation) + } + } + } + + newIt := func(text string, flag types.FlagType, fail bool) *leafnodes.ItNode { + return leafnodes.NewItNode(text, newBody(text, fail), flag, codeLocation, 0, failer, 0) + } + + newItWithBody := func(text string, body interface{}) *leafnodes.ItNode { + return leafnodes.NewItNode(text, body, noneFlag, codeLocation, 0, failer, 0) + } + + newMeasure := func(text string, flag types.FlagType, fail bool, samples int) *leafnodes.MeasureNode { + return leafnodes.NewMeasureNode(text, func(Benchmarker) { + nodesThatRan = append(nodesThatRan, text) + if fail { + failer.Fail(text, codeLocation) + } + }, flag, codeLocation, samples, failer, 0) + } + + newBef := func(text string, fail bool) leafnodes.BasicNode { + return leafnodes.NewBeforeEachNode(newBody(text, fail), codeLocation, 0, failer, 0) + } + + newAft := func(text string, fail bool) leafnodes.BasicNode { + return leafnodes.NewAfterEachNode(newBody(text, fail), codeLocation, 0, failer, 0) + } + + newJusBef := func(text string, fail bool) leafnodes.BasicNode { + return leafnodes.NewJustBeforeEachNode(newBody(text, fail), codeLocation, 0, failer, 0) + } + + newContainer := func(text string, flag types.FlagType, setupNodes ...leafnodes.BasicNode) *containernode.ContainerNode { + c := containernode.New(text, flag, codeLocation) + for _, node := range setupNodes { + c.PushSetupNode(node) + } + return c + } + + containers := func(containers ...*containernode.ContainerNode) []*containernode.ContainerNode { + return containers + } + + BeforeEach(func() { + buffer = gbytes.NewBuffer() + failer = Failer.New() + codeLocation = codelocation.New(0) + nodesThatRan = []string{} + }) + + Describe("marking specs focused and pending", func() { + It("should satisfy various caes", func() { + cases := []struct { + ContainerFlags []types.FlagType + SubjectFlag types.FlagType + Pending bool + Focused bool + }{ + {[]types.FlagType{}, noneFlag, false, false}, + {[]types.FlagType{}, focusedFlag, false, true}, + {[]types.FlagType{}, pendingFlag, true, false}, + {[]types.FlagType{noneFlag}, noneFlag, false, false}, + {[]types.FlagType{focusedFlag}, noneFlag, false, true}, + {[]types.FlagType{pendingFlag}, noneFlag, true, false}, + {[]types.FlagType{noneFlag}, focusedFlag, false, true}, + {[]types.FlagType{focusedFlag}, focusedFlag, false, true}, + {[]types.FlagType{pendingFlag}, focusedFlag, true, true}, + {[]types.FlagType{noneFlag}, pendingFlag, true, false}, + {[]types.FlagType{focusedFlag}, pendingFlag, true, true}, + {[]types.FlagType{pendingFlag}, pendingFlag, true, false}, + {[]types.FlagType{focusedFlag, noneFlag}, noneFlag, false, true}, + {[]types.FlagType{noneFlag, focusedFlag}, noneFlag, false, true}, + {[]types.FlagType{pendingFlag, noneFlag}, noneFlag, true, false}, + {[]types.FlagType{noneFlag, pendingFlag}, noneFlag, true, false}, + {[]types.FlagType{focusedFlag, pendingFlag}, noneFlag, true, true}, + } + + for i, c := range cases { + subject := newIt("it node", c.SubjectFlag, false) + containers := []*containernode.ContainerNode{} + for _, flag := range c.ContainerFlags { + containers = append(containers, newContainer("container", flag)) + } + + spec := New(subject, containers, false) + Ω(spec.Pending()).Should(Equal(c.Pending), "Case %d: %#v", i, c) + Ω(spec.Focused()).Should(Equal(c.Focused), "Case %d: %#v", i, c) + + if c.Pending { + Ω(spec.Summary("").State).Should(Equal(types.SpecStatePending)) + } + } + }) + }) + + Describe("Skip", func() { + It("should be skipped", func() { + spec := New(newIt("it node", noneFlag, false), containers(newContainer("container", noneFlag)), false) + Ω(spec.Skipped()).Should(BeFalse()) + spec.Skip() + Ω(spec.Skipped()).Should(BeTrue()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStateSkipped)) + }) + }) + + Describe("IsMeasurement", func() { + It("should be true if the subject is a measurement node", func() { + spec := New(newIt("it node", noneFlag, false), containers(newContainer("container", noneFlag)), false) + Ω(spec.IsMeasurement()).Should(BeFalse()) + Ω(spec.Summary("").IsMeasurement).Should(BeFalse()) + Ω(spec.Summary("").NumberOfSamples).Should(Equal(1)) + + spec = New(newMeasure("measure node", noneFlag, false, 10), containers(newContainer("container", noneFlag)), false) + Ω(spec.IsMeasurement()).Should(BeTrue()) + Ω(spec.Summary("").IsMeasurement).Should(BeTrue()) + Ω(spec.Summary("").NumberOfSamples).Should(Equal(10)) + }) + }) + + Describe("Passed", func() { + It("should pass when the subject passed", func() { + spec := New(newIt("it node", noneFlag, false), containers(), false) + spec.Run(buffer) + + Ω(spec.Passed()).Should(BeTrue()) + Ω(spec.Failed()).Should(BeFalse()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStatePassed)) + Ω(spec.Summary("").Failure).Should(BeZero()) + }) + }) + + Describe("Flaked", func() { + It("should work if Run is called twice and gets different results", func() { + i := 0 + spec := New(newItWithBody("flaky it", func() { + i++ + if i == 1 { + failer.Fail("oops", codeLocation) + } + }), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(spec.Flaked()).Should(BeFalse()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStateFailed)) + Ω(spec.Summary("").Failure.Message).Should(Equal("oops")) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeTrue()) + Ω(spec.Failed()).Should(BeFalse()) + Ω(spec.Flaked()).Should(BeTrue()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStatePassed)) + }) + }) + + Describe("Failed", func() { + It("should be failed if the failure was panic", func() { + spec := New(newItWithBody("panicky it", func() { + panic("bam") + }), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStatePanicked)) + Ω(spec.Summary("").Failure.Message).Should(Equal("Test Panicked")) + Ω(spec.Summary("").Failure.ForwardedPanic).Should(Equal("bam")) + }) + + It("should be failed if the failure was a timeout", func() { + spec := New(newItWithBody("sleepy it", func(done Done) {}), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStateTimedOut)) + Ω(spec.Summary("").Failure.Message).Should(Equal("Timed out")) + }) + + It("should be failed if the failure was... a failure", func() { + spec := New(newItWithBody("failing it", func() { + failer.Fail("bam", codeLocation) + }), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(spec.Summary("").State).Should(Equal(types.SpecStateFailed)) + Ω(spec.Summary("").Failure.Message).Should(Equal("bam")) + }) + }) + + Describe("Concatenated string", func() { + It("should concatenate the texts of the containers and the subject", func() { + spec := New( + newIt("it node", noneFlag, false), + containers( + newContainer("outer container", noneFlag), + newContainer("inner container", noneFlag), + ), + false, + ) + + Ω(spec.ConcatenatedString()).Should(Equal("outer container inner container it node")) + }) + }) + + Describe("running it specs", func() { + Context("with just an it", func() { + Context("that succeeds", func() { + It("should run the it and report on its success", func() { + spec := New(newIt("it node", noneFlag, false), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeTrue()) + Ω(spec.Failed()).Should(BeFalse()) + Ω(nodesThatRan).Should(Equal([]string{"it node"})) + }) + }) + + Context("that fails", func() { + It("should run the it and report on its success", func() { + spec := New(newIt("it node", noneFlag, true), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(spec.Summary("").Failure.Message).Should(Equal("it node")) + Ω(nodesThatRan).Should(Equal([]string{"it node"})) + }) + }) + }) + + Context("with a full set of setup nodes", func() { + var failingNodes map[string]bool + + BeforeEach(func() { + failingNodes = map[string]bool{} + }) + + JustBeforeEach(func() { + spec = New( + newIt("it node", noneFlag, failingNodes["it node"]), + containers( + newContainer("outer container", noneFlag, + newBef("outer bef A", failingNodes["outer bef A"]), + newBef("outer bef B", failingNodes["outer bef B"]), + newJusBef("outer jusbef A", failingNodes["outer jusbef A"]), + newJusBef("outer jusbef B", failingNodes["outer jusbef B"]), + newAft("outer aft A", failingNodes["outer aft A"]), + newAft("outer aft B", failingNodes["outer aft B"]), + ), + newContainer("inner container", noneFlag, + newBef("inner bef A", failingNodes["inner bef A"]), + newBef("inner bef B", failingNodes["inner bef B"]), + newJusBef("inner jusbef A", failingNodes["inner jusbef A"]), + newJusBef("inner jusbef B", failingNodes["inner jusbef B"]), + newAft("inner aft A", failingNodes["inner aft A"]), + newAft("inner aft B", failingNodes["inner aft B"]), + ), + ), + false, + ) + spec.Run(buffer) + }) + + Context("that all pass", func() { + It("should walk through the nodes in the correct order", func() { + Ω(spec.Passed()).Should(BeTrue()) + Ω(spec.Failed()).Should(BeFalse()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "inner bef A", + "inner bef B", + "outer jusbef A", + "outer jusbef B", + "inner jusbef A", + "inner jusbef B", + "it node", + "inner aft A", + "inner aft B", + "outer aft A", + "outer aft B", + })) + }) + }) + + Context("when the subject fails", func() { + BeforeEach(func() { + failingNodes["it node"] = true + }) + + It("should run the afters", func() { + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "inner bef A", + "inner bef B", + "outer jusbef A", + "outer jusbef B", + "inner jusbef A", + "inner jusbef B", + "it node", + "inner aft A", + "inner aft B", + "outer aft A", + "outer aft B", + })) + Ω(spec.Summary("").Failure.Message).Should(Equal("it node")) + }) + }) + + Context("when an inner before fails", func() { + BeforeEach(func() { + failingNodes["inner bef A"] = true + }) + + It("should not run any other befores, but it should run the subsequent afters", func() { + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "inner bef A", + "inner aft A", + "inner aft B", + "outer aft A", + "outer aft B", + })) + Ω(spec.Summary("").Failure.Message).Should(Equal("inner bef A")) + }) + }) + + Context("when an outer before fails", func() { + BeforeEach(func() { + failingNodes["outer bef B"] = true + }) + + It("should not run any other befores, but it should run the subsequent afters", func() { + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "outer aft A", + "outer aft B", + })) + Ω(spec.Summary("").Failure.Message).Should(Equal("outer bef B")) + }) + }) + + Context("when an after fails", func() { + BeforeEach(func() { + failingNodes["inner aft B"] = true + }) + + It("should run all other afters, but mark the test as failed", func() { + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "inner bef A", + "inner bef B", + "outer jusbef A", + "outer jusbef B", + "inner jusbef A", + "inner jusbef B", + "it node", + "inner aft A", + "inner aft B", + "outer aft A", + "outer aft B", + })) + Ω(spec.Summary("").Failure.Message).Should(Equal("inner aft B")) + }) + }) + + Context("when a just before each fails", func() { + BeforeEach(func() { + failingNodes["outer jusbef B"] = true + }) + + It("should run the afters, but not the subject", func() { + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "inner bef A", + "inner bef B", + "outer jusbef A", + "outer jusbef B", + "inner aft A", + "inner aft B", + "outer aft A", + "outer aft B", + })) + Ω(spec.Summary("").Failure.Message).Should(Equal("outer jusbef B")) + }) + }) + + Context("when an after fails after an earlier node has failed", func() { + BeforeEach(func() { + failingNodes["it node"] = true + failingNodes["inner aft B"] = true + }) + + It("should record the earlier failure", func() { + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "outer bef A", + "outer bef B", + "inner bef A", + "inner bef B", + "outer jusbef A", + "outer jusbef B", + "inner jusbef A", + "inner jusbef B", + "it node", + "inner aft A", + "inner aft B", + "outer aft A", + "outer aft B", + })) + Ω(spec.Summary("").Failure.Message).Should(Equal("it node")) + }) + }) + }) + }) + + Describe("running measurement specs", func() { + Context("when the measurement succeeds", func() { + It("should run N samples", func() { + spec = New( + newMeasure("measure node", noneFlag, false, 3), + containers( + newContainer("container", noneFlag, + newBef("bef A", false), + newJusBef("jusbef A", false), + newAft("aft A", false), + ), + ), + false, + ) + spec.Run(buffer) + + Ω(spec.Passed()).Should(BeTrue()) + Ω(spec.Failed()).Should(BeFalse()) + Ω(nodesThatRan).Should(Equal([]string{ + "bef A", + "jusbef A", + "measure node", + "aft A", + "bef A", + "jusbef A", + "measure node", + "aft A", + "bef A", + "jusbef A", + "measure node", + "aft A", + })) + }) + }) + + Context("when the measurement fails", func() { + It("should bail after the failure occurs", func() { + spec = New( + newMeasure("measure node", noneFlag, true, 3), + containers( + newContainer("container", noneFlag, + newBef("bef A", false), + newJusBef("jusbef A", false), + newAft("aft A", false), + ), + ), + false, + ) + spec.Run(buffer) + + Ω(spec.Passed()).Should(BeFalse()) + Ω(spec.Failed()).Should(BeTrue()) + Ω(nodesThatRan).Should(Equal([]string{ + "bef A", + "jusbef A", + "measure node", + "aft A", + })) + }) + }) + }) + + Describe("Summary", func() { + var ( + subjectCodeLocation types.CodeLocation + outerContainerCodeLocation types.CodeLocation + innerContainerCodeLocation types.CodeLocation + summary *types.SpecSummary + ) + + BeforeEach(func() { + subjectCodeLocation = codelocation.New(0) + outerContainerCodeLocation = codelocation.New(0) + innerContainerCodeLocation = codelocation.New(0) + + spec = New( + leafnodes.NewItNode("it node", func() { + time.Sleep(10 * time.Millisecond) + }, noneFlag, subjectCodeLocation, 0, failer, 0), + containers( + containernode.New("outer container", noneFlag, outerContainerCodeLocation), + containernode.New("inner container", noneFlag, innerContainerCodeLocation), + ), + false, + ) + + spec.Run(buffer) + Ω(spec.Passed()).Should(BeTrue()) + summary = spec.Summary("suite id") + }) + + It("should have the suite id", func() { + Ω(summary.SuiteID).Should(Equal("suite id")) + }) + + It("should have the component texts and code locations", func() { + Ω(summary.ComponentTexts).Should(Equal([]string{"outer container", "inner container", "it node"})) + Ω(summary.ComponentCodeLocations).Should(Equal([]types.CodeLocation{outerContainerCodeLocation, innerContainerCodeLocation, subjectCodeLocation})) + }) + + It("should have a runtime", func() { + Ω(summary.RunTime).Should(BeNumerically(">=", 10*time.Millisecond)) + }) + + It("should have a runtime which remains consistent after spec run", func() { + totalRunTime := summary.RunTime + Ω(totalRunTime).Should(BeNumerically(">=", 10*time.Millisecond)) + + Consistently(func() time.Duration { return spec.Summary("suite id").RunTime }).Should(Equal(totalRunTime)) + }) + + It("should not be a measurement, or have a measurement summary", func() { + Ω(summary.IsMeasurement).Should(BeFalse()) + Ω(summary.Measurements).Should(BeEmpty()) + }) + }) + + Describe("Summaries for measurements", func() { + var summary *types.SpecSummary + + BeforeEach(func() { + spec = New(leafnodes.NewMeasureNode("measure node", func(b Benchmarker) { + b.RecordValue("a value", 7, "some info") + b.RecordValueWithPrecision("another value", 8, "ns", 5, "more info") + }, noneFlag, codeLocation, 4, failer, 0), containers(), false) + spec.Run(buffer) + Ω(spec.Passed()).Should(BeTrue()) + summary = spec.Summary("suite id") + }) + + It("should include the number of samples", func() { + Ω(summary.NumberOfSamples).Should(Equal(4)) + }) + + It("should be a measurement", func() { + Ω(summary.IsMeasurement).Should(BeTrue()) + }) + + It("should have the measurements report", func() { + Ω(summary.Measurements).Should(HaveKey("a value")) + report := summary.Measurements["a value"] + Ω(report.Name).Should(Equal("a value")) + Ω(report.Info).Should(Equal("some info")) + Ω(report.Results).Should(Equal([]float64{7, 7, 7, 7})) + + Ω(summary.Measurements).Should(HaveKey("another value")) + report = summary.Measurements["another value"] + Ω(report.Name).Should(Equal("another value")) + Ω(report.Info).Should(Equal("more info")) + Ω(report.Results).Should(Equal([]float64{8, 8, 8, 8})) + Ω(report.Units).Should(Equal("ns")) + Ω(report.Precision).Should(Equal(5)) + }) + }) + + Describe("When told to emit progress", func() { + It("should emit progress to the writer as it runs Befores, JustBefores, Afters, and Its", func() { + spec = New( + newIt("it node", noneFlag, false), + containers( + newContainer("outer container", noneFlag, + newBef("outer bef A", false), + newJusBef("outer jusbef A", false), + newAft("outer aft A", false), + ), + newContainer("inner container", noneFlag, + newBef("inner bef A", false), + newJusBef("inner jusbef A", false), + newAft("inner aft A", false), + ), + ), + true, + ) + spec.Run(buffer) + + Ω(buffer).Should(gbytes.Say(`\[BeforeEach\] outer container`)) + Ω(buffer).Should(gbytes.Say(`\[BeforeEach\] inner container`)) + Ω(buffer).Should(gbytes.Say(`\[JustBeforeEach\] outer container`)) + Ω(buffer).Should(gbytes.Say(`\[JustBeforeEach\] inner container`)) + Ω(buffer).Should(gbytes.Say(`\[It\] it node`)) + Ω(buffer).Should(gbytes.Say(`\[AfterEach\] inner container`)) + Ω(buffer).Should(gbytes.Say(`\[AfterEach\] outer container`)) + }) + + It("should emit progress to the writer as it runs Befores, JustBefores, Afters, and Measures", func() { + spec = New( + newMeasure("measure node", noneFlag, false, 2), + containers(), + true, + ) + spec.Run(buffer) + + Ω(buffer).Should(gbytes.Say(`\[Measure\] measure node`)) + Ω(buffer).Should(gbytes.Say(`\[Measure\] measure node`)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/specs_test.go b/vendor/github.com/onsi/ginkgo/internal/spec/specs_test.go new file mode 100644 index 000000000..066fbbb3a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec/specs_test.go @@ -0,0 +1,287 @@ +package spec_test + +import ( + "math/rand" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/spec" + . "github.com/onsi/gomega" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/internal/containernode" + "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("Specs", func() { + var specs *Specs + + newSpec := func(text string, flag types.FlagType) *Spec { + subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) + return New(subject, []*containernode.ContainerNode{}, false) + } + + newMeasureSpec := func(text string, flag types.FlagType) *Spec { + subject := leafnodes.NewMeasureNode(text, func(Benchmarker) {}, flag, codelocation.New(0), 0, nil, 0) + return New(subject, []*containernode.ContainerNode{}, false) + } + + newSpecs := func(args ...interface{}) *Specs { + specs := []*Spec{} + for index := 0; index < len(args)-1; index += 2 { + specs = append(specs, newSpec(args[index].(string), args[index+1].(types.FlagType))) + } + return NewSpecs(specs) + } + + specTexts := func(specs *Specs) []string { + texts := []string{} + for _, spec := range specs.Specs() { + texts = append(texts, spec.ConcatenatedString()) + } + return texts + } + + willRunTexts := func(specs *Specs) []string { + texts := []string{} + for _, spec := range specs.Specs() { + if !(spec.Skipped() || spec.Pending()) { + texts = append(texts, spec.ConcatenatedString()) + } + } + return texts + } + + skippedTexts := func(specs *Specs) []string { + texts := []string{} + for _, spec := range specs.Specs() { + if spec.Skipped() { + texts = append(texts, spec.ConcatenatedString()) + } + } + return texts + } + + pendingTexts := func(specs *Specs) []string { + texts := []string{} + for _, spec := range specs.Specs() { + if spec.Pending() { + texts = append(texts, spec.ConcatenatedString()) + } + } + return texts + } + + Describe("Shuffling specs", func() { + It("should shuffle the specs using the passed in randomizer", func() { + specs17 := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) + specs17.Shuffle(rand.New(rand.NewSource(17))) + texts17 := specTexts(specs17) + + specs17Again := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) + specs17Again.Shuffle(rand.New(rand.NewSource(17))) + texts17Again := specTexts(specs17Again) + + specs15 := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) + specs15.Shuffle(rand.New(rand.NewSource(15))) + texts15 := specTexts(specs15) + + specsUnshuffled := newSpecs("C", noneFlag, "A", noneFlag, "B", noneFlag) + textsUnshuffled := specTexts(specsUnshuffled) + + Ω(textsUnshuffled).Should(Equal([]string{"C", "A", "B"})) + + Ω(texts17).Should(Equal(texts17Again)) + Ω(texts17).ShouldNot(Equal(texts15)) + Ω(texts17).ShouldNot(Equal(textsUnshuffled)) + Ω(texts15).ShouldNot(Equal(textsUnshuffled)) + + Ω(texts17).Should(HaveLen(3)) + Ω(texts17).Should(ContainElement("A")) + Ω(texts17).Should(ContainElement("B")) + Ω(texts17).Should(ContainElement("C")) + + Ω(texts15).Should(HaveLen(3)) + Ω(texts15).Should(ContainElement("A")) + Ω(texts15).Should(ContainElement("B")) + Ω(texts15).Should(ContainElement("C")) + }) + }) + + Describe("with no programmatic focus", func() { + BeforeEach(func() { + specs = newSpecs("A1", noneFlag, "A2", noneFlag, "B1", noneFlag, "B2", pendingFlag) + specs.ApplyFocus("", "", "") + }) + + It("should not report as having programmatic specs", func() { + Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) + }) + }) + + Describe("Applying focus/skip", func() { + var description, focusString, skipString string + + BeforeEach(func() { + description, focusString, skipString = "", "", "" + }) + + JustBeforeEach(func() { + specs = newSpecs("A1", focusedFlag, "A2", noneFlag, "B1", focusedFlag, "B2", pendingFlag) + specs.ApplyFocus(description, focusString, skipString) + }) + + Context("with neither a focus string nor a skip string", func() { + It("should apply the programmatic focus", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "B1"})) + Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B2"})) + Ω(pendingTexts(specs)).Should(BeEmpty()) + }) + + It("should report as having programmatic specs", func() { + Ω(specs.HasProgrammaticFocus()).Should(BeTrue()) + }) + }) + + Context("with a focus regexp", func() { + BeforeEach(func() { + focusString = "A" + }) + + It("should override the programmatic focus", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2"})) + Ω(skippedTexts(specs)).Should(Equal([]string{"B1", "B2"})) + Ω(pendingTexts(specs)).Should(BeEmpty()) + }) + + It("should not report as having programmatic specs", func() { + Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) + }) + }) + + Context("with a focus regexp", func() { + BeforeEach(func() { + focusString = "B" + }) + + It("should not override any pendings", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"B1"})) + Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"})) + Ω(pendingTexts(specs)).Should(Equal([]string{"B2"})) + }) + }) + + Context("with a description", func() { + BeforeEach(func() { + description = "C" + focusString = "C" + }) + + It("should include the description in the focus determination", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"A1", "A2", "B1"})) + Ω(skippedTexts(specs)).Should(BeEmpty()) + Ω(pendingTexts(specs)).Should(Equal([]string{"B2"})) + }) + }) + + Context("with a description", func() { + BeforeEach(func() { + description = "C" + skipString = "C" + }) + + It("should include the description in the focus determination", func() { + Ω(willRunTexts(specs)).Should(BeEmpty()) + Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2", "B1", "B2"})) + Ω(pendingTexts(specs)).Should(BeEmpty()) + }) + }) + + Context("with a skip regexp", func() { + BeforeEach(func() { + skipString = "A" + }) + + It("should override the programmatic focus", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"B1"})) + Ω(skippedTexts(specs)).Should(Equal([]string{"A1", "A2"})) + Ω(pendingTexts(specs)).Should(Equal([]string{"B2"})) + }) + + It("should not report as having programmatic specs", func() { + Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) + }) + }) + + Context("with both a focus and a skip regexp", func() { + BeforeEach(func() { + focusString = "1" + skipString = "B" + }) + + It("should AND the two", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"A1"})) + Ω(skippedTexts(specs)).Should(Equal([]string{"A2", "B1", "B2"})) + Ω(pendingTexts(specs)).Should(BeEmpty()) + }) + + It("should not report as having programmatic specs", func() { + Ω(specs.HasProgrammaticFocus()).Should(BeFalse()) + }) + }) + }) + + Describe("With a focused spec within a pending context and a pending spec within a focused context", func() { + BeforeEach(func() { + pendingInFocused := New( + leafnodes.NewItNode("PendingInFocused", func() {}, pendingFlag, codelocation.New(0), 0, nil, 0), + []*containernode.ContainerNode{ + containernode.New("", focusedFlag, codelocation.New(0)), + }, false) + + focusedInPending := New( + leafnodes.NewItNode("FocusedInPending", func() {}, focusedFlag, codelocation.New(0), 0, nil, 0), + []*containernode.ContainerNode{ + containernode.New("", pendingFlag, codelocation.New(0)), + }, false) + + specs = NewSpecs([]*Spec{ + newSpec("A", noneFlag), + newSpec("B", noneFlag), + pendingInFocused, + focusedInPending, + }) + specs.ApplyFocus("", "", "") + }) + + It("should not have a programmatic focus and should run all tests", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"})) + Ω(skippedTexts(specs)).Should(BeEmpty()) + Ω(pendingTexts(specs)).Should(ConsistOf(ContainSubstring("PendingInFocused"), ContainSubstring("FocusedInPending"))) + }) + }) + + Describe("skipping measurements", func() { + BeforeEach(func() { + specs = NewSpecs([]*Spec{ + newSpec("A", noneFlag), + newSpec("B", noneFlag), + newSpec("C", pendingFlag), + newMeasureSpec("measurementA", noneFlag), + newMeasureSpec("measurementB", pendingFlag), + }) + }) + + It("should skip measurements", func() { + Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B", "measurementA"})) + Ω(skippedTexts(specs)).Should(BeEmpty()) + Ω(pendingTexts(specs)).Should(Equal([]string{"C", "measurementB"})) + + specs.SkipMeasurements() + + Ω(willRunTexts(specs)).Should(Equal([]string{"A", "B"})) + Ω(skippedTexts(specs)).Should(Equal([]string{"measurementA", "measurementB"})) + Ω(pendingTexts(specs)).Should(Equal([]string{"C"})) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/index_computer_test.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/index_computer_test.go new file mode 100644 index 000000000..65da9837c --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/index_computer_test.go @@ -0,0 +1,149 @@ +package spec_iterator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/spec_iterator" + . "github.com/onsi/gomega" +) + +var _ = Describe("ParallelizedIndexRange", func() { + var startIndex, count int + + It("should return the correct index range for 4 tests on 2 nodes", func() { + startIndex, count = ParallelizedIndexRange(4, 2, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(4, 2, 2) + Ω(startIndex).Should(Equal(2)) + Ω(count).Should(Equal(2)) + }) + + It("should return the correct index range for 5 tests on 2 nodes", func() { + startIndex, count = ParallelizedIndexRange(5, 2, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(3)) + + startIndex, count = ParallelizedIndexRange(5, 2, 2) + Ω(startIndex).Should(Equal(3)) + Ω(count).Should(Equal(2)) + }) + + It("should return the correct index range for 5 tests on 3 nodes", func() { + startIndex, count = ParallelizedIndexRange(5, 3, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(5, 3, 2) + Ω(startIndex).Should(Equal(2)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(5, 3, 3) + Ω(startIndex).Should(Equal(4)) + Ω(count).Should(Equal(1)) + }) + + It("should return the correct index range for 5 tests on 4 nodes", func() { + startIndex, count = ParallelizedIndexRange(5, 4, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(5, 4, 2) + Ω(startIndex).Should(Equal(2)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 4, 3) + Ω(startIndex).Should(Equal(3)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 4, 4) + Ω(startIndex).Should(Equal(4)) + Ω(count).Should(Equal(1)) + }) + + It("should return the correct index range for 5 tests on 5 nodes", func() { + startIndex, count = ParallelizedIndexRange(5, 5, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 5, 2) + Ω(startIndex).Should(Equal(1)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 5, 3) + Ω(startIndex).Should(Equal(2)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 5, 4) + Ω(startIndex).Should(Equal(3)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 5, 5) + Ω(startIndex).Should(Equal(4)) + Ω(count).Should(Equal(1)) + }) + + It("should return the correct index range for 5 tests on 6 nodes", func() { + startIndex, count = ParallelizedIndexRange(5, 6, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 6, 2) + Ω(startIndex).Should(Equal(1)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 6, 3) + Ω(startIndex).Should(Equal(2)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 6, 4) + Ω(startIndex).Should(Equal(3)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 6, 5) + Ω(startIndex).Should(Equal(4)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(5, 6, 6) + Ω(count).Should(Equal(0)) + }) + + It("should return the correct index range for 5 tests on 7 nodes", func() { + startIndex, count = ParallelizedIndexRange(5, 7, 6) + Ω(count).Should(Equal(0)) + + startIndex, count = ParallelizedIndexRange(5, 7, 7) + Ω(count).Should(Equal(0)) + }) + + It("should return the correct index range for 11 tests on 7 nodes", func() { + startIndex, count = ParallelizedIndexRange(11, 7, 1) + Ω(startIndex).Should(Equal(0)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(11, 7, 2) + Ω(startIndex).Should(Equal(2)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(11, 7, 3) + Ω(startIndex).Should(Equal(4)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(11, 7, 4) + Ω(startIndex).Should(Equal(6)) + Ω(count).Should(Equal(2)) + + startIndex, count = ParallelizedIndexRange(11, 7, 5) + Ω(startIndex).Should(Equal(8)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(11, 7, 6) + Ω(startIndex).Should(Equal(9)) + Ω(count).Should(Equal(1)) + + startIndex, count = ParallelizedIndexRange(11, 7, 7) + Ω(startIndex).Should(Equal(10)) + Ω(count).Should(Equal(1)) + }) + +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go new file mode 100644 index 000000000..c5a762fd5 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/parallel_spec_iterator_test.go @@ -0,0 +1,112 @@ +package spec_iterator_test + +import ( + "net/http" + + . "github.com/onsi/ginkgo/internal/spec_iterator" + "github.com/onsi/gomega/ghttp" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/internal/containernode" + "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/internal/spec" + "github.com/onsi/ginkgo/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ParallelSpecIterator", func() { + var specs []*spec.Spec + var iterator *ParallelIterator + var server *ghttp.Server + + newSpec := func(text string, flag types.FlagType) *spec.Spec { + subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) + return spec.New(subject, []*containernode.ContainerNode{}, false) + } + + BeforeEach(func() { + specs = []*spec.Spec{ + newSpec("A", types.FlagTypePending), + newSpec("B", types.FlagTypeNone), + newSpec("C", types.FlagTypeNone), + newSpec("D", types.FlagTypeNone), + } + specs[3].Skip() + + server = ghttp.NewServer() + + iterator = NewParallelIterator(specs, "http://"+server.Addr()) + }) + + AfterEach(func() { + server.Close() + }) + + It("should report the total number of specs", func() { + Ω(iterator.NumberOfSpecsPriorToIteration()).Should(Equal(4)) + }) + + It("should not report the number to be processed", func() { + n, known := iterator.NumberOfSpecsToProcessIfKnown() + Ω(n).Should(Equal(-1)) + Ω(known).Should(BeFalse()) + }) + + It("should not report the number that will be run", func() { + n, known := iterator.NumberOfSpecsThatWillBeRunIfKnown() + Ω(n).Should(Equal(-1)) + Ω(known).Should(BeFalse()) + }) + + Describe("iterating", func() { + Describe("when the server returns well-formed responses", func() { + BeforeEach(func() { + server.AppendHandlers( + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 0}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 1}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 3}), + ghttp.RespondWithJSONEncoded(http.StatusOK, Counter{Index: 4}), + ) + }) + + It("should return the specs in question", func() { + Ω(iterator.Next()).Should(Equal(specs[0])) + Ω(iterator.Next()).Should(Equal(specs[1])) + Ω(iterator.Next()).Should(Equal(specs[3])) + spec, err := iterator.Next() + Ω(spec).Should(BeNil()) + Ω(err).Should(MatchError(ErrClosed)) + }) + }) + + Describe("when the server 404s", func() { + BeforeEach(func() { + server.AppendHandlers( + ghttp.RespondWith(http.StatusNotFound, ""), + ) + }) + + It("should return an error", func() { + spec, err := iterator.Next() + Ω(spec).Should(BeNil()) + Ω(err).Should(MatchError("unexpected status code 404")) + }) + }) + + Describe("when the server returns gibberish", func() { + BeforeEach(func() { + server.AppendHandlers( + ghttp.RespondWith(http.StatusOK, "ß"), + ) + }) + + It("should error", func() { + spec, err := iterator.Next() + Ω(spec).Should(BeNil()) + Ω(err).ShouldNot(BeNil()) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/serial_spec_iterator_test.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/serial_spec_iterator_test.go new file mode 100644 index 000000000..dde4a344e --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/serial_spec_iterator_test.go @@ -0,0 +1,64 @@ +package spec_iterator_test + +import ( + . "github.com/onsi/ginkgo/internal/spec_iterator" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/internal/containernode" + "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/internal/spec" + "github.com/onsi/ginkgo/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("SerialSpecIterator", func() { + var specs []*spec.Spec + var iterator *SerialIterator + + newSpec := func(text string, flag types.FlagType) *spec.Spec { + subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) + return spec.New(subject, []*containernode.ContainerNode{}, false) + } + + BeforeEach(func() { + specs = []*spec.Spec{ + newSpec("A", types.FlagTypePending), + newSpec("B", types.FlagTypeNone), + newSpec("C", types.FlagTypeNone), + newSpec("D", types.FlagTypeNone), + } + specs[3].Skip() + + iterator = NewSerialIterator(specs) + }) + + It("should report the total number of specs", func() { + Ω(iterator.NumberOfSpecsPriorToIteration()).Should(Equal(4)) + }) + + It("should report the number to be processed", func() { + n, known := iterator.NumberOfSpecsToProcessIfKnown() + Ω(n).Should(Equal(4)) + Ω(known).Should(BeTrue()) + }) + + It("should report the number that will be run", func() { + n, known := iterator.NumberOfSpecsThatWillBeRunIfKnown() + Ω(n).Should(Equal(2)) + Ω(known).Should(BeTrue()) + }) + + Describe("iterating", func() { + It("should return the specs in order", func() { + Ω(iterator.Next()).Should(Equal(specs[0])) + Ω(iterator.Next()).Should(Equal(specs[1])) + Ω(iterator.Next()).Should(Equal(specs[2])) + Ω(iterator.Next()).Should(Equal(specs[3])) + spec, err := iterator.Next() + Ω(spec).Should(BeNil()) + Ω(err).Should(MatchError(ErrClosed)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/sharded_parallel_spec_iterator_test.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/sharded_parallel_spec_iterator_test.go new file mode 100644 index 000000000..c3786e03a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/sharded_parallel_spec_iterator_test.go @@ -0,0 +1,62 @@ +package spec_iterator_test + +import ( + . "github.com/onsi/ginkgo/internal/spec_iterator" + + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/internal/containernode" + "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/internal/spec" + "github.com/onsi/ginkgo/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ShardedParallelSpecIterator", func() { + var specs []*spec.Spec + var iterator *ShardedParallelIterator + + newSpec := func(text string, flag types.FlagType) *spec.Spec { + subject := leafnodes.NewItNode(text, func() {}, flag, codelocation.New(0), 0, nil, 0) + return spec.New(subject, []*containernode.ContainerNode{}, false) + } + + BeforeEach(func() { + specs = []*spec.Spec{ + newSpec("A", types.FlagTypePending), + newSpec("B", types.FlagTypeNone), + newSpec("C", types.FlagTypeNone), + newSpec("D", types.FlagTypeNone), + } + specs[3].Skip() + + iterator = NewShardedParallelIterator(specs, 2, 1) + }) + + It("should report the total number of specs", func() { + Ω(iterator.NumberOfSpecsPriorToIteration()).Should(Equal(4)) + }) + + It("should report the number to be processed", func() { + n, known := iterator.NumberOfSpecsToProcessIfKnown() + Ω(n).Should(Equal(2)) + Ω(known).Should(BeTrue()) + }) + + It("should report the number that will be run", func() { + n, known := iterator.NumberOfSpecsThatWillBeRunIfKnown() + Ω(n).Should(Equal(1)) + Ω(known).Should(BeTrue()) + }) + + Describe("iterating", func() { + It("should return the specs in order", func() { + Ω(iterator.Next()).Should(Equal(specs[0])) + Ω(iterator.Next()).Should(Equal(specs[1])) + spec, err := iterator.Next() + Ω(spec).Should(BeNil()) + Ω(err).Should(MatchError(ErrClosed)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/spec_iterator/spec_iterator_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/spec_iterator_suite_test.go new file mode 100644 index 000000000..5c08a77e3 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/spec_iterator/spec_iterator_suite_test.go @@ -0,0 +1,13 @@ +package spec_iterator_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestSpecIterator(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "SpecIterator Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_suite_test.go new file mode 100644 index 000000000..c8388fb6f --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_suite_test.go @@ -0,0 +1,13 @@ +package specrunner_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestSpecRunner(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Spec Runner Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go new file mode 100644 index 000000000..a41437922 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/specrunner/spec_runner_test.go @@ -0,0 +1,785 @@ +package specrunner_test + +import ( + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/internal/spec_iterator" + . "github.com/onsi/ginkgo/internal/specrunner" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" + + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/internal/containernode" + Failer "github.com/onsi/ginkgo/internal/failer" + "github.com/onsi/ginkgo/internal/leafnodes" + "github.com/onsi/ginkgo/internal/spec" + Writer "github.com/onsi/ginkgo/internal/writer" + "github.com/onsi/ginkgo/reporters" +) + +var noneFlag = types.FlagTypeNone +var pendingFlag = types.FlagTypePending + +var _ = Describe("Spec Runner", func() { + var ( + reporter1 *reporters.FakeReporter + reporter2 *reporters.FakeReporter + failer *Failer.Failer + writer *Writer.FakeGinkgoWriter + + thingsThatRan []string + + runner *SpecRunner + ) + + newBefSuite := func(text string, fail bool) leafnodes.SuiteNode { + return leafnodes.NewBeforeSuiteNode(func() { + writer.AddEvent(text) + thingsThatRan = append(thingsThatRan, text) + if fail { + failer.Fail(text, codelocation.New(0)) + } + }, codelocation.New(0), 0, failer) + } + + newAftSuite := func(text string, fail bool) leafnodes.SuiteNode { + return leafnodes.NewAfterSuiteNode(func() { + writer.AddEvent(text) + thingsThatRan = append(thingsThatRan, text) + if fail { + failer.Fail(text, codelocation.New(0)) + } + }, codelocation.New(0), 0, failer) + } + + newSpec := func(text string, flag types.FlagType, fail bool) *spec.Spec { + subject := leafnodes.NewItNode(text, func() { + writer.AddEvent(text) + thingsThatRan = append(thingsThatRan, text) + if fail { + failer.Fail(text, codelocation.New(0)) + } + }, flag, codelocation.New(0), 0, failer, 0) + + return spec.New(subject, []*containernode.ContainerNode{}, false) + } + + newFlakySpec := func(text string, flag types.FlagType, failures int) *spec.Spec { + runs := 0 + subject := leafnodes.NewItNode(text, func() { + writer.AddEvent(text) + thingsThatRan = append(thingsThatRan, text) + runs++ + if runs < failures { + failer.Fail(text, codelocation.New(0)) + } + }, flag, codelocation.New(0), 0, failer, 0) + + return spec.New(subject, []*containernode.ContainerNode{}, false) + } + + newSpecWithBody := func(text string, body interface{}) *spec.Spec { + subject := leafnodes.NewItNode(text, body, noneFlag, codelocation.New(0), 0, failer, 0) + + return spec.New(subject, []*containernode.ContainerNode{}, false) + } + + newRunner := func(config config.GinkgoConfigType, beforeSuiteNode leafnodes.SuiteNode, afterSuiteNode leafnodes.SuiteNode, specs ...*spec.Spec) *SpecRunner { + iterator := spec_iterator.NewSerialIterator(specs) + return New("description", beforeSuiteNode, iterator, afterSuiteNode, []reporters.Reporter{reporter1, reporter2}, writer, config) + } + + BeforeEach(func() { + reporter1 = reporters.NewFakeReporter() + reporter2 = reporters.NewFakeReporter() + writer = Writer.NewFake() + failer = Failer.New() + + thingsThatRan = []string{} + }) + + Describe("Running and Reporting", func() { + var specA, pendingSpec, anotherPendingSpec, failedSpec, specB, skippedSpec *spec.Spec + var willRunCalls, didCompleteCalls []string + var conf config.GinkgoConfigType + + JustBeforeEach(func() { + willRunCalls = []string{} + didCompleteCalls = []string{} + specA = newSpec("spec A", noneFlag, false) + pendingSpec = newSpec("pending spec", pendingFlag, false) + anotherPendingSpec = newSpec("another pending spec", pendingFlag, false) + failedSpec = newSpec("failed spec", noneFlag, true) + specB = newSpec("spec B", noneFlag, false) + skippedSpec = newSpec("skipped spec", noneFlag, false) + skippedSpec.Skip() + + reporter1.SpecWillRunStub = func(specSummary *types.SpecSummary) { + willRunCalls = append(willRunCalls, "Reporter1") + } + reporter2.SpecWillRunStub = func(specSummary *types.SpecSummary) { + willRunCalls = append(willRunCalls, "Reporter2") + } + + reporter1.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { + didCompleteCalls = append(didCompleteCalls, "Reporter1") + } + reporter2.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { + didCompleteCalls = append(didCompleteCalls, "Reporter2") + } + + runner = newRunner(conf, newBefSuite("BefSuite", false), newAftSuite("AftSuite", false), specA, pendingSpec, anotherPendingSpec, failedSpec, specB, skippedSpec) + runner.Run() + }) + + BeforeEach(func() { + conf = config.GinkgoConfigType{RandomSeed: 17} + }) + + It("should skip skipped/pending tests", func() { + Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "spec A", "failed spec", "spec B", "AftSuite"})) + }) + + It("should report to any attached reporters", func() { + Ω(reporter1.Config).Should(Equal(reporter2.Config)) + Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) + Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) + Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) + Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) + Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) + Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) + }) + + It("should report that a spec did end in reverse order", func() { + Ω(willRunCalls[0:4]).Should(Equal([]string{"Reporter1", "Reporter2", "Reporter1", "Reporter2"})) + Ω(didCompleteCalls[0:4]).Should(Equal([]string{"Reporter2", "Reporter1", "Reporter2", "Reporter1"})) + }) + + It("should report the passed in config", func() { + Ω(reporter1.Config.RandomSeed).Should(BeNumerically("==", 17)) + }) + + It("should report the beginning of the suite", func() { + Ω(reporter1.BeginSummary.SuiteDescription).Should(Equal("description")) + Ω(reporter1.BeginSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) + Ω(reporter1.BeginSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) + Ω(reporter1.BeginSummary.NumberOfTotalSpecs).Should(Equal(6)) + Ω(reporter1.BeginSummary.NumberOfSpecsThatWillBeRun).Should(Equal(3)) + Ω(reporter1.BeginSummary.NumberOfPendingSpecs).Should(Equal(-1)) + Ω(reporter1.BeginSummary.NumberOfSkippedSpecs).Should(Equal(-1)) + }) + + It("should report the end of the suite", func() { + Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) + Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(3)) + Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(2)) + Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(2)) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(1)) + }) + + Context("when told to perform a dry run", func() { + BeforeEach(func() { + conf.DryRun = true + }) + + It("should report to the reporters", func() { + Ω(reporter1.Config).Should(Equal(reporter2.Config)) + Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) + Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) + Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) + Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) + Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) + Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) + }) + + It("should not actually run anything", func() { + Ω(thingsThatRan).Should(BeEmpty()) + }) + + It("report before and after suites as passed", func() { + Ω(reporter1.BeforeSuiteSummary.State).Should(Equal(types.SpecStatePassed)) + Ω(reporter1.AfterSuiteSummary.State).Should(Equal(types.SpecStatePassed)) + }) + + It("should report specs as passed", func() { + summaries := reporter1.SpecSummaries + Ω(summaries).Should(HaveLen(6)) + Ω(summaries[0].ComponentTexts).Should(ContainElement("spec A")) + Ω(summaries[0].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[1].ComponentTexts).Should(ContainElement("pending spec")) + Ω(summaries[1].State).Should(Equal(types.SpecStatePending)) + Ω(summaries[2].ComponentTexts).Should(ContainElement("another pending spec")) + Ω(summaries[2].State).Should(Equal(types.SpecStatePending)) + Ω(summaries[3].ComponentTexts).Should(ContainElement("failed spec")) + Ω(summaries[3].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[4].ComponentTexts).Should(ContainElement("spec B")) + Ω(summaries[4].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[5].ComponentTexts).Should(ContainElement("skipped spec")) + Ω(summaries[5].State).Should(Equal(types.SpecStateSkipped)) + }) + + It("should report the end of the suite", func() { + Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) + Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) + Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(3)) + Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(2)) + Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(0)) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) + }) + + It("should not report a slow test", func() { + summaries := reporter1.SpecSummaries + for _, s := range summaries { + Expect(s.RunTime).To(BeZero()) + } + }) + }) + }) + + Describe("reporting on specs", func() { + var proceed chan bool + var ready chan bool + var finished chan bool + BeforeEach(func() { + ready = make(chan bool) + proceed = make(chan bool) + finished = make(chan bool) + skippedSpec := newSpec("SKIP", noneFlag, false) + skippedSpec.Skip() + + runner = newRunner( + config.GinkgoConfigType{}, + newBefSuite("BefSuite", false), + newAftSuite("AftSuite", false), + skippedSpec, + newSpec("PENDING", pendingFlag, false), + newSpecWithBody("RUN", func() { + close(ready) + <-proceed + }), + ) + go func() { + runner.Run() + close(finished) + }() + }) + + It("should report about pending/skipped specs", func() { + <-ready + Ω(reporter1.SpecWillRunSummaries).Should(HaveLen(3)) + + Ω(reporter1.SpecWillRunSummaries[0].ComponentTexts[0]).Should(Equal("SKIP")) + Ω(reporter1.SpecWillRunSummaries[1].ComponentTexts[0]).Should(Equal("PENDING")) + Ω(reporter1.SpecWillRunSummaries[2].ComponentTexts[0]).Should(Equal("RUN")) + + Ω(reporter1.SpecSummaries[0].ComponentTexts[0]).Should(Equal("SKIP")) + Ω(reporter1.SpecSummaries[1].ComponentTexts[0]).Should(Equal("PENDING")) + Ω(reporter1.SpecSummaries).Should(HaveLen(2)) + + close(proceed) + <-finished + + Ω(reporter1.SpecSummaries).Should(HaveLen(3)) + Ω(reporter1.SpecSummaries[2].ComponentTexts[0]).Should(Equal("RUN")) + }) + }) + + Describe("Running and Reporting when there's flakes", func() { + var specA, pendingSpec, flakySpec, failedSpec, specB, skippedSpec *spec.Spec + var willRunCalls, didCompleteCalls []string + var conf config.GinkgoConfigType + var failedSpecFlag = noneFlag + + JustBeforeEach(func() { + willRunCalls = []string{} + didCompleteCalls = []string{} + specA = newSpec("spec A", noneFlag, false) + pendingSpec = newSpec("pending spec", pendingFlag, false) + flakySpec = newFlakySpec("flaky spec", noneFlag, 3) + failedSpec = newSpec("failed spec", failedSpecFlag, true) + specB = newSpec("spec B", noneFlag, false) + skippedSpec = newSpec("skipped spec", noneFlag, false) + skippedSpec.Skip() + + reporter1.SpecWillRunStub = func(specSummary *types.SpecSummary) { + willRunCalls = append(willRunCalls, "Reporter1") + } + reporter2.SpecWillRunStub = func(specSummary *types.SpecSummary) { + willRunCalls = append(willRunCalls, "Reporter2") + } + + reporter1.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { + didCompleteCalls = append(didCompleteCalls, "Reporter1") + } + reporter2.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { + didCompleteCalls = append(didCompleteCalls, "Reporter2") + } + + runner = newRunner(conf, newBefSuite("BefSuite", false), newAftSuite("AftSuite", false), specA, pendingSpec, flakySpec, failedSpec, specB, skippedSpec) + runner.Run() + }) + + BeforeEach(func() { + failedSpecFlag = noneFlag + conf = config.GinkgoConfigType{ + RandomSeed: 17, + FlakeAttempts: 5, + } + }) + + It("should skip skipped/pending tests", func() { + Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "spec A", "flaky spec", "flaky spec", "flaky spec", "failed spec", "failed spec", "failed spec", "failed spec", "failed spec", "spec B", "AftSuite"})) + }) + + It("should report to any attached reporters", func() { + Ω(reporter1.Config).Should(Equal(reporter2.Config)) + Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) + Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) + Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) + Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) + Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) + Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) + }) + + It("should report that a spec did end in reverse order", func() { + Ω(willRunCalls[0:4]).Should(Equal([]string{"Reporter1", "Reporter2", "Reporter1", "Reporter2"})) + Ω(didCompleteCalls[0:4]).Should(Equal([]string{"Reporter2", "Reporter1", "Reporter2", "Reporter1"})) + }) + + It("should report the passed in config", func() { + Ω(reporter1.Config.RandomSeed).Should(BeNumerically("==", 17)) + }) + + It("should report the beginning of the suite", func() { + Ω(reporter1.BeginSummary.SuiteDescription).Should(Equal("description")) + Ω(reporter1.BeginSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) + Ω(reporter1.BeginSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) + Ω(reporter1.BeginSummary.NumberOfTotalSpecs).Should(Equal(6)) + Ω(reporter1.BeginSummary.NumberOfSpecsThatWillBeRun).Should(Equal(4)) + Ω(reporter1.BeginSummary.NumberOfPendingSpecs).Should(Equal(-1)) + Ω(reporter1.BeginSummary.NumberOfSkippedSpecs).Should(Equal(-1)) + }) + + It("should report the end of the suite", func() { + Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) + Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(4)) + Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(3)) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfFlakedSpecs).Should(Equal(1)) + }) + + Context("when nothing fails", func() { + BeforeEach(func() { + failedSpecFlag = pendingFlag + }) + + It("the suite should pass even with flakes", func() { + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) + Ω(reporter1.EndSummary.NumberOfFlakedSpecs).Should(Equal(1)) + }) + }) + + Context("when told to perform a dry run", func() { + BeforeEach(func() { + conf.DryRun = true + }) + + It("should report to the reporters", func() { + Ω(reporter1.Config).Should(Equal(reporter2.Config)) + Ω(reporter1.BeforeSuiteSummary).Should(Equal(reporter2.BeforeSuiteSummary)) + Ω(reporter1.BeginSummary).Should(Equal(reporter2.BeginSummary)) + Ω(reporter1.SpecWillRunSummaries).Should(Equal(reporter2.SpecWillRunSummaries)) + Ω(reporter1.SpecSummaries).Should(Equal(reporter2.SpecSummaries)) + Ω(reporter1.AfterSuiteSummary).Should(Equal(reporter2.AfterSuiteSummary)) + Ω(reporter1.EndSummary).Should(Equal(reporter2.EndSummary)) + }) + + It("should not actually run anything", func() { + Ω(thingsThatRan).Should(BeEmpty()) + }) + + It("report before and after suites as passed", func() { + Ω(reporter1.BeforeSuiteSummary.State).Should(Equal(types.SpecStatePassed)) + Ω(reporter1.AfterSuiteSummary.State).Should(Equal(types.SpecStatePassed)) + }) + + It("should report specs as passed", func() { + summaries := reporter1.SpecSummaries + Ω(summaries).Should(HaveLen(6)) + Ω(summaries[0].ComponentTexts).Should(ContainElement("spec A")) + Ω(summaries[0].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[1].ComponentTexts).Should(ContainElement("pending spec")) + Ω(summaries[1].State).Should(Equal(types.SpecStatePending)) + Ω(summaries[2].ComponentTexts).Should(ContainElement("flaky spec")) + Ω(summaries[2].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[3].ComponentTexts).Should(ContainElement("failed spec")) + Ω(summaries[3].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[4].ComponentTexts).Should(ContainElement("spec B")) + Ω(summaries[4].State).Should(Equal(types.SpecStatePassed)) + Ω(summaries[5].ComponentTexts).Should(ContainElement("skipped spec")) + Ω(summaries[5].State).Should(Equal(types.SpecStateSkipped)) + }) + + It("should report the end of the suite", func() { + Ω(reporter1.EndSummary.SuiteDescription).Should(Equal("description")) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) + Ω(reporter1.EndSummary.SuiteID).Should(MatchRegexp("[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}")) + Ω(reporter1.EndSummary.NumberOfSpecsBeforeParallelization).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfTotalSpecs).Should(Equal(6)) + Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(4)) + Ω(reporter1.EndSummary.NumberOfPendingSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfPassedSpecs).Should(Equal(0)) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) + }) + }) + }) + + Describe("Running BeforeSuite & AfterSuite", func() { + var success bool + var befSuite leafnodes.SuiteNode + var aftSuite leafnodes.SuiteNode + Context("with a nil BeforeSuite & AfterSuite", func() { + BeforeEach(func() { + runner = newRunner( + config.GinkgoConfigType{}, + nil, + nil, + newSpec("A", noneFlag, false), + newSpec("B", noneFlag, false), + ) + success = runner.Run() + }) + + It("should not report about the BeforeSuite", func() { + Ω(reporter1.BeforeSuiteSummary).Should(BeNil()) + }) + + It("should not report about the AfterSuite", func() { + Ω(reporter1.AfterSuiteSummary).Should(BeNil()) + }) + + It("should run the specs", func() { + Ω(thingsThatRan).Should(Equal([]string{"A", "B"})) + }) + }) + + Context("when the BeforeSuite & AfterSuite pass", func() { + BeforeEach(func() { + befSuite = newBefSuite("BefSuite", false) + aftSuite = newBefSuite("AftSuite", false) + runner = newRunner( + config.GinkgoConfigType{}, + befSuite, + aftSuite, + newSpec("A", noneFlag, false), + newSpec("B", noneFlag, false), + ) + success = runner.Run() + }) + + It("should run the BeforeSuite, the AfterSuite and the specs", func() { + Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "A", "B", "AftSuite"})) + }) + + It("should report about the BeforeSuite", func() { + Ω(reporter1.BeforeSuiteSummary).Should(Equal(befSuite.Summary())) + }) + + It("should report about the AfterSuite", func() { + Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) + }) + + It("should report success", func() { + Ω(success).Should(BeTrue()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) + }) + + It("should not dump the writer", func() { + Ω(writer.EventStream).ShouldNot(ContainElement("DUMP")) + }) + }) + + Context("when the BeforeSuite fails", func() { + BeforeEach(func() { + befSuite = newBefSuite("BefSuite", true) + aftSuite = newBefSuite("AftSuite", false) + + skipped := newSpec("Skipped", noneFlag, false) + skipped.Skip() + + runner = newRunner( + config.GinkgoConfigType{}, + befSuite, + aftSuite, + newSpec("A", noneFlag, false), + newSpec("B", noneFlag, false), + newSpec("Pending", pendingFlag, false), + skipped, + ) + success = runner.Run() + }) + + It("should not run the specs, but it should run the AfterSuite", func() { + Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "AftSuite"})) + }) + + It("should report about the BeforeSuite", func() { + Ω(reporter1.BeforeSuiteSummary).Should(Equal(befSuite.Summary())) + }) + + It("should report about the AfterSuite", func() { + Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) + }) + + It("should report failure", func() { + Ω(success).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(2)) + Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(2)) + }) + + It("should dump the writer", func() { + Ω(writer.EventStream).Should(ContainElement("DUMP")) + }) + }) + + Context("when some other test fails", func() { + BeforeEach(func() { + aftSuite = newBefSuite("AftSuite", false) + + runner = newRunner( + config.GinkgoConfigType{}, + nil, + aftSuite, + newSpec("A", noneFlag, true), + ) + success = runner.Run() + }) + + It("should still run the AfterSuite", func() { + Ω(thingsThatRan).Should(Equal([]string{"A", "AftSuite"})) + }) + + It("should report about the AfterSuite", func() { + Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) + }) + + It("should report failure", func() { + Ω(success).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(1)) + Ω(reporter1.EndSummary.NumberOfSpecsThatWillBeRun).Should(Equal(1)) + }) + }) + + Context("when the AfterSuite fails", func() { + BeforeEach(func() { + befSuite = newBefSuite("BefSuite", false) + aftSuite = newBefSuite("AftSuite", true) + runner = newRunner( + config.GinkgoConfigType{}, + befSuite, + aftSuite, + newSpec("A", noneFlag, false), + newSpec("B", noneFlag, false), + ) + success = runner.Run() + }) + + It("should run everything", func() { + Ω(thingsThatRan).Should(Equal([]string{"BefSuite", "A", "B", "AftSuite"})) + }) + + It("should report about the BeforeSuite", func() { + Ω(reporter1.BeforeSuiteSummary).Should(Equal(befSuite.Summary())) + }) + + It("should report about the AfterSuite", func() { + Ω(reporter1.AfterSuiteSummary).Should(Equal(aftSuite.Summary())) + }) + + It("should report failure", func() { + Ω(success).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + Ω(reporter1.EndSummary.NumberOfFailedSpecs).Should(Equal(0)) + }) + + It("should dump the writer", func() { + Ω(writer.EventStream).Should(ContainElement("DUMP")) + }) + }) + }) + + Describe("When instructed to fail fast", func() { + BeforeEach(func() { + conf := config.GinkgoConfigType{ + FailFast: true, + } + runner = newRunner(conf, nil, newAftSuite("after-suite", false), newSpec("passing", noneFlag, false), newSpec("failing", noneFlag, true), newSpec("dont-see", noneFlag, true), newSpec("dont-see", noneFlag, true)) + }) + + It("should return false, report failure, and not run anything past the failing test", func() { + Ω(runner.Run()).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + Ω(thingsThatRan).Should(Equal([]string{"passing", "failing", "after-suite"})) + }) + + It("should announce the subsequent specs as skipped", func() { + runner.Run() + Ω(reporter1.SpecSummaries).Should(HaveLen(4)) + Ω(reporter1.SpecSummaries[2].State).Should(Equal(types.SpecStateSkipped)) + Ω(reporter1.SpecSummaries[3].State).Should(Equal(types.SpecStateSkipped)) + }) + + It("should mark all subsequent specs as skipped", func() { + runner.Run() + Ω(reporter1.EndSummary.NumberOfSkippedSpecs).Should(Equal(2)) + }) + }) + + Describe("Marking failure and success", func() { + Context("when all tests pass", func() { + BeforeEach(func() { + runner = newRunner(config.GinkgoConfigType{}, nil, nil, newSpec("passing", noneFlag, false), newSpec("pending", pendingFlag, false)) + }) + + It("should return true and report success", func() { + Ω(runner.Run()).Should(BeTrue()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeTrue()) + }) + }) + + Context("when a test fails", func() { + BeforeEach(func() { + runner = newRunner(config.GinkgoConfigType{}, nil, nil, newSpec("failing", noneFlag, true), newSpec("pending", pendingFlag, false)) + }) + + It("should return false and report failure", func() { + Ω(runner.Run()).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + }) + }) + + Context("when there is a pending test, but pendings count as failures", func() { + BeforeEach(func() { + runner = newRunner(config.GinkgoConfigType{FailOnPending: true}, nil, nil, newSpec("passing", noneFlag, false), newSpec("pending", pendingFlag, false)) + }) + + It("should return false and report failure", func() { + Ω(runner.Run()).Should(BeFalse()) + Ω(reporter1.EndSummary.SuiteSucceeded).Should(BeFalse()) + }) + }) + }) + + Describe("Managing the writer", func() { + BeforeEach(func() { + runner = newRunner( + config.GinkgoConfigType{}, + nil, + nil, + newSpec("A", noneFlag, false), + newSpec("B", noneFlag, true), + newSpec("C", noneFlag, false), + ) + reporter1.SpecWillRunStub = func(specSummary *types.SpecSummary) { + writer.AddEvent("R1.WillRun") + } + reporter2.SpecWillRunStub = func(specSummary *types.SpecSummary) { + writer.AddEvent("R2.WillRun") + } + reporter1.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { + writer.AddEvent("R1.DidComplete") + } + reporter2.SpecDidCompleteStub = func(specSummary *types.SpecSummary) { + writer.AddEvent("R2.DidComplete") + } + runner.Run() + }) + + It("should truncate between tests, but only dump if a test fails", func() { + Ω(writer.EventStream).Should(Equal([]string{ + "TRUNCATE", + "R1.WillRun", + "R2.WillRun", + "A", + "R2.DidComplete", + "R1.DidComplete", + "TRUNCATE", + "R1.WillRun", + "R2.WillRun", + "B", + "BYTES", + "R2.DidComplete", + "DUMP", + "R1.DidComplete", + "TRUNCATE", + "R1.WillRun", + "R2.WillRun", + "C", + "R2.DidComplete", + "R1.DidComplete", + })) + }) + }) + + Describe("CurrentSpecSummary", func() { + It("should return the spec summary for the currently running spec", func() { + var summary *types.SpecSummary + runner = newRunner( + config.GinkgoConfigType{}, + nil, + nil, + newSpec("A", noneFlag, false), + newSpecWithBody("B", func() { + var ok bool + summary, ok = runner.CurrentSpecSummary() + Ω(ok).Should(BeTrue()) + }), + newSpec("C", noneFlag, false), + ) + runner.Run() + + Ω(summary.ComponentTexts).Should(Equal([]string{"B"})) + + summary, ok := runner.CurrentSpecSummary() + Ω(summary).Should(BeNil()) + Ω(ok).Should(BeFalse()) + }) + }) + + Describe("generating a suite id", func() { + It("should generate an id randomly", func() { + runnerA := newRunner(config.GinkgoConfigType{}, nil, nil) + runnerA.Run() + IDA := reporter1.BeginSummary.SuiteID + + runnerB := newRunner(config.GinkgoConfigType{}, nil, nil) + runnerB.Run() + IDB := reporter1.BeginSummary.SuiteID + + IDRegexp := "[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}" + Ω(IDA).Should(MatchRegexp(IDRegexp)) + Ω(IDB).Should(MatchRegexp(IDRegexp)) + + Ω(IDA).ShouldNot(Equal(IDB)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/suite/suite_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/suite/suite_suite_test.go new file mode 100644 index 000000000..06fe1d12a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/suite/suite_suite_test.go @@ -0,0 +1,35 @@ +package suite_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func Test(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Suite") +} + +var numBeforeSuiteRuns = 0 +var numAfterSuiteRuns = 0 + +var _ = BeforeSuite(func() { + numBeforeSuiteRuns++ +}) + +var _ = AfterSuite(func() { + numAfterSuiteRuns++ + Ω(numBeforeSuiteRuns).Should(Equal(1)) + Ω(numAfterSuiteRuns).Should(Equal(1)) +}) + +//Fakes +type fakeTestingT struct { + didFail bool +} + +func (fakeT *fakeTestingT) Fail() { + fakeT.didFail = true +} diff --git a/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go b/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go new file mode 100644 index 000000000..fd2d11dc3 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/suite/suite_test.go @@ -0,0 +1,385 @@ +package suite_test + +import ( + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/suite" + . "github.com/onsi/gomega" + + "math/rand" + "time" + + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/internal/codelocation" + Failer "github.com/onsi/ginkgo/internal/failer" + Writer "github.com/onsi/ginkgo/internal/writer" + "github.com/onsi/ginkgo/reporters" + "github.com/onsi/ginkgo/types" +) + +var _ = Describe("Suite", func() { + var ( + specSuite *Suite + fakeT *fakeTestingT + fakeR *reporters.FakeReporter + writer *Writer.FakeGinkgoWriter + failer *Failer.Failer + ) + + BeforeEach(func() { + writer = Writer.NewFake() + fakeT = &fakeTestingT{} + fakeR = reporters.NewFakeReporter() + failer = Failer.New() + specSuite = New(failer) + }) + + Describe("running a suite", func() { + var ( + runOrder []string + randomizeAllSpecs bool + randomSeed int64 + focusString string + parallelNode int + parallelTotal int + runResult bool + hasProgrammaticFocus bool + ) + + var f = func(runText string) func() { + return func() { + runOrder = append(runOrder, runText) + } + } + + BeforeEach(func() { + randomizeAllSpecs = false + randomSeed = 11 + parallelNode = 1 + parallelTotal = 1 + focusString = "" + + runOrder = make([]string, 0) + specSuite.SetBeforeSuiteNode(f("BeforeSuite"), codelocation.New(0), 0) + specSuite.PushBeforeEachNode(f("top BE"), codelocation.New(0), 0) + specSuite.PushJustBeforeEachNode(f("top JBE"), codelocation.New(0), 0) + specSuite.PushAfterEachNode(f("top AE"), codelocation.New(0), 0) + + specSuite.PushContainerNode("container", func() { + specSuite.PushBeforeEachNode(f("BE"), codelocation.New(0), 0) + specSuite.PushJustBeforeEachNode(f("JBE"), codelocation.New(0), 0) + specSuite.PushAfterEachNode(f("AE"), codelocation.New(0), 0) + specSuite.PushItNode("it", f("IT"), types.FlagTypeNone, codelocation.New(0), 0) + + specSuite.PushContainerNode("inner container", func() { + specSuite.PushItNode("inner it", f("inner IT"), types.FlagTypeNone, codelocation.New(0), 0) + }, types.FlagTypeNone, codelocation.New(0)) + }, types.FlagTypeNone, codelocation.New(0)) + + specSuite.PushContainerNode("container 2", func() { + specSuite.PushBeforeEachNode(f("BE 2"), codelocation.New(0), 0) + specSuite.PushItNode("it 2", f("IT 2"), types.FlagTypeNone, codelocation.New(0), 0) + }, types.FlagTypeNone, codelocation.New(0)) + + specSuite.PushItNode("top level it", f("top IT"), types.FlagTypeNone, codelocation.New(0), 0) + + specSuite.SetAfterSuiteNode(f("AfterSuite"), codelocation.New(0), 0) + }) + + JustBeforeEach(func() { + runResult, hasProgrammaticFocus = specSuite.Run(fakeT, "suite description", []reporters.Reporter{fakeR}, writer, config.GinkgoConfigType{ + RandomSeed: randomSeed, + RandomizeAllSpecs: randomizeAllSpecs, + FocusString: focusString, + ParallelNode: parallelNode, + ParallelTotal: parallelTotal, + }) + }) + + It("provides the config and suite description to the reporter", func() { + Ω(fakeR.Config.RandomSeed).Should(Equal(int64(randomSeed))) + Ω(fakeR.Config.RandomizeAllSpecs).Should(Equal(randomizeAllSpecs)) + Ω(fakeR.BeginSummary.SuiteDescription).Should(Equal("suite description")) + }) + + It("reports that the BeforeSuite node ran", func() { + Ω(fakeR.BeforeSuiteSummary).ShouldNot(BeNil()) + }) + + It("reports that the AfterSuite node ran", func() { + Ω(fakeR.AfterSuiteSummary).ShouldNot(BeNil()) + }) + + It("provides information about the current test", func() { + description := CurrentGinkgoTestDescription() + Ω(description.ComponentTexts).Should(Equal([]string{"Suite", "running a suite", "provides information about the current test"})) + Ω(description.FullTestText).Should(Equal("Suite running a suite provides information about the current test")) + Ω(description.TestText).Should(Equal("provides information about the current test")) + Ω(description.IsMeasurement).Should(BeFalse()) + Ω(description.FileName).Should(ContainSubstring("suite_test.go")) + Ω(description.LineNumber).Should(BeNumerically(">", 50)) + Ω(description.LineNumber).Should(BeNumerically("<", 150)) + Ω(description.Failed).Should(BeFalse()) + Ω(description.Duration).Should(BeNumerically(">", 0)) + }) + + Measure("should run measurements", func(b Benchmarker) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + runtime := b.Time("sleeping", func() { + sleepTime := time.Duration(r.Float64() * 0.01 * float64(time.Second)) + time.Sleep(sleepTime) + }) + Ω(runtime.Seconds()).Should(BeNumerically("<=", 1)) + Ω(runtime.Seconds()).Should(BeNumerically(">=", 0)) + + randomValue := r.Float64() * 10.0 + b.RecordValue("random value", randomValue) + Ω(randomValue).Should(BeNumerically("<=", 10.0)) + Ω(randomValue).Should(BeNumerically(">=", 0.0)) + + b.RecordValueWithPrecision("specific value", 123.4567, "ms", 2) + b.RecordValueWithPrecision("specific value", 234.5678, "ms", 2) + }, 10) + + It("creates a node hierarchy, converts it to a spec collection, and runs it", func() { + Ω(runOrder).Should(Equal([]string{ + "BeforeSuite", + "top BE", "BE", "top JBE", "JBE", "IT", "AE", "top AE", + "top BE", "BE", "top JBE", "JBE", "inner IT", "AE", "top AE", + "top BE", "BE 2", "top JBE", "IT 2", "top AE", + "top BE", "top JBE", "top IT", "top AE", + "AfterSuite", + })) + }) + Context("when in an AfterEach block", func() { + AfterEach(func() { + description := CurrentGinkgoTestDescription() + Ω(description.IsMeasurement).Should(BeFalse()) + Ω(description.FileName).Should(ContainSubstring("suite_test.go")) + Ω(description.Failed).Should(BeFalse()) + Ω(description.Duration).Should(BeNumerically(">", 0)) + }) + + It("still provides information about the current test", func() { + Ω(true).To(BeTrue()) + }) + }) + + Context("when told to randomize all specs", func() { + BeforeEach(func() { + randomizeAllSpecs = true + }) + + It("does", func() { + Ω(runOrder).Should(Equal([]string{ + "BeforeSuite", + "top BE", "top JBE", "top IT", "top AE", + "top BE", "BE", "top JBE", "JBE", "inner IT", "AE", "top AE", + "top BE", "BE", "top JBE", "JBE", "IT", "AE", "top AE", + "top BE", "BE 2", "top JBE", "IT 2", "top AE", + "AfterSuite", + })) + }) + }) + + Context("when provided with a filter", func() { + BeforeEach(func() { + focusString = `inner|\d` + }) + + It("converts the filter to a regular expression and uses it to filter the running specs", func() { + Ω(runOrder).Should(Equal([]string{ + "BeforeSuite", + "top BE", "BE", "top JBE", "JBE", "inner IT", "AE", "top AE", + "top BE", "BE 2", "top JBE", "IT 2", "top AE", + "AfterSuite", + })) + }) + + It("should not report a programmatic focus", func() { + Ω(hasProgrammaticFocus).Should(BeFalse()) + }) + }) + + Context("with a programatically focused spec", func() { + BeforeEach(func() { + specSuite.PushItNode("focused it", f("focused it"), types.FlagTypeFocused, codelocation.New(0), 0) + + specSuite.PushContainerNode("focused container", func() { + specSuite.PushItNode("inner focused it", f("inner focused it"), types.FlagTypeFocused, codelocation.New(0), 0) + specSuite.PushItNode("inner unfocused it", f("inner unfocused it"), types.FlagTypeNone, codelocation.New(0), 0) + }, types.FlagTypeFocused, codelocation.New(0)) + + }) + + It("should only run the focused test, applying backpropagation to favor most deeply focused leaf nodes", func() { + Ω(runOrder).Should(Equal([]string{ + "BeforeSuite", + "top BE", "top JBE", "focused it", "top AE", + "top BE", "top JBE", "inner focused it", "top AE", + "AfterSuite", + })) + }) + + It("should report a programmatic focus", func() { + Ω(hasProgrammaticFocus).Should(BeTrue()) + }) + }) + + Context("when the specs pass", func() { + It("doesn't report a failure", func() { + Ω(fakeT.didFail).Should(BeFalse()) + }) + + It("should return true", func() { + Ω(runResult).Should(BeTrue()) + }) + }) + + Context("when a spec fails", func() { + var location types.CodeLocation + BeforeEach(func() { + specSuite.PushItNode("top level it", func() { + location = codelocation.New(0) + failer.Fail("oops!", location) + }, types.FlagTypeNone, codelocation.New(0), 0) + }) + + It("should return false", func() { + Ω(runResult).Should(BeFalse()) + }) + + It("reports a failure", func() { + Ω(fakeT.didFail).Should(BeTrue()) + }) + + It("generates the correct failure data", func() { + Ω(fakeR.SpecSummaries[0].Failure.Message).Should(Equal("oops!")) + Ω(fakeR.SpecSummaries[0].Failure.Location).Should(Equal(location)) + }) + }) + + Context("when runnable nodes are nested within other runnable nodes", func() { + Context("when an It is nested", func() { + BeforeEach(func() { + specSuite.PushItNode("top level it", func() { + specSuite.PushItNode("nested it", f("oops"), types.FlagTypeNone, codelocation.New(0), 0) + }, types.FlagTypeNone, codelocation.New(0), 0) + }) + + It("should fail", func() { + Ω(fakeT.didFail).Should(BeTrue()) + }) + }) + + Context("when a Measure is nested", func() { + BeforeEach(func() { + specSuite.PushItNode("top level it", func() { + specSuite.PushMeasureNode("nested measure", func(Benchmarker) {}, types.FlagTypeNone, codelocation.New(0), 10) + }, types.FlagTypeNone, codelocation.New(0), 0) + }) + + It("should fail", func() { + Ω(fakeT.didFail).Should(BeTrue()) + }) + }) + + Context("when a BeforeEach is nested", func() { + BeforeEach(func() { + specSuite.PushItNode("top level it", func() { + specSuite.PushBeforeEachNode(f("nested bef"), codelocation.New(0), 0) + }, types.FlagTypeNone, codelocation.New(0), 0) + }) + + It("should fail", func() { + Ω(fakeT.didFail).Should(BeTrue()) + }) + }) + + Context("when a JustBeforeEach is nested", func() { + BeforeEach(func() { + specSuite.PushItNode("top level it", func() { + specSuite.PushJustBeforeEachNode(f("nested jbef"), codelocation.New(0), 0) + }, types.FlagTypeNone, codelocation.New(0), 0) + }) + + It("should fail", func() { + Ω(fakeT.didFail).Should(BeTrue()) + }) + }) + + Context("when a AfterEach is nested", func() { + BeforeEach(func() { + specSuite.PushItNode("top level it", func() { + specSuite.PushAfterEachNode(f("nested aft"), codelocation.New(0), 0) + }, types.FlagTypeNone, codelocation.New(0), 0) + }) + + It("should fail", func() { + Ω(fakeT.didFail).Should(BeTrue()) + }) + }) + }) + }) + + Describe("BeforeSuite", func() { + Context("when setting BeforeSuite more than once", func() { + It("should panic", func() { + specSuite.SetBeforeSuiteNode(func() {}, codelocation.New(0), 0) + + Ω(func() { + specSuite.SetBeforeSuiteNode(func() {}, codelocation.New(0), 0) + }).Should(Panic()) + + }) + }) + }) + + Describe("AfterSuite", func() { + Context("when setting AfterSuite more than once", func() { + It("should panic", func() { + specSuite.SetAfterSuiteNode(func() {}, codelocation.New(0), 0) + + Ω(func() { + specSuite.SetAfterSuiteNode(func() {}, codelocation.New(0), 0) + }).Should(Panic()) + }) + }) + }) + + Describe("By", func() { + It("writes to the GinkgoWriter", func() { + originalGinkgoWriter := GinkgoWriter + buffer := &bytes.Buffer{} + + GinkgoWriter = buffer + By("Saying Hello GinkgoWriter") + GinkgoWriter = originalGinkgoWriter + + Ω(buffer.String()).Should(ContainSubstring("STEP")) + Ω(buffer.String()).Should(ContainSubstring(": Saying Hello GinkgoWriter\n")) + }) + + It("calls the passed-in callback if present", func() { + a := 0 + By("calling the callback", func() { + a = 1 + }) + Ω(a).Should(Equal(1)) + }) + + It("panics if there is more than one callback", func() { + Ω(func() { + By("registering more than one callback", func() {}, func() {}) + }).Should(Panic()) + }) + }) + + Describe("GinkgoRandomSeed", func() { + It("returns the current config's random seed", func() { + Ω(GinkgoRandomSeed()).Should(Equal(config.GinkgoConfig.RandomSeed)) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/internal/writer/writer_suite_test.go b/vendor/github.com/onsi/ginkgo/internal/writer/writer_suite_test.go new file mode 100644 index 000000000..e20657791 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/writer/writer_suite_test.go @@ -0,0 +1,13 @@ +package writer_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestWriter(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Writer Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/internal/writer/writer_test.go b/vendor/github.com/onsi/ginkgo/internal/writer/writer_test.go new file mode 100644 index 000000000..3e1d17c6d --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/internal/writer/writer_test.go @@ -0,0 +1,75 @@ +package writer_test + +import ( + "github.com/onsi/gomega/gbytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/internal/writer" + . "github.com/onsi/gomega" +) + +var _ = Describe("Writer", func() { + var writer *Writer + var out *gbytes.Buffer + + BeforeEach(func() { + out = gbytes.NewBuffer() + writer = New(out) + }) + + It("should stream directly to the outbuffer by default", func() { + writer.Write([]byte("foo")) + Ω(out).Should(gbytes.Say("foo")) + }) + + It("should not emit the header when asked to DumpOutWitHeader", func() { + writer.Write([]byte("foo")) + writer.DumpOutWithHeader("my header") + Ω(out).ShouldNot(gbytes.Say("my header")) + Ω(out).Should(gbytes.Say("foo")) + }) + + Context("when told not to stream", func() { + BeforeEach(func() { + writer.SetStream(false) + }) + + It("should only write to the buffer when told to DumpOut", func() { + writer.Write([]byte("foo")) + Ω(out).ShouldNot(gbytes.Say("foo")) + writer.DumpOut() + Ω(out).Should(gbytes.Say("foo")) + }) + + It("should truncate the internal buffer when told to truncate", func() { + writer.Write([]byte("foo")) + writer.Truncate() + writer.DumpOut() + Ω(out).ShouldNot(gbytes.Say("foo")) + + writer.Write([]byte("bar")) + writer.DumpOut() + Ω(out).Should(gbytes.Say("bar")) + }) + + Describe("emitting a header", func() { + Context("when the buffer has content", func() { + It("should emit the header followed by the content", func() { + writer.Write([]byte("foo")) + writer.DumpOutWithHeader("my header") + + Ω(out).Should(gbytes.Say("my header")) + Ω(out).Should(gbytes.Say("foo")) + }) + }) + + Context("when the buffer has no content", func() { + It("should not emit the header", func() { + writer.DumpOutWithHeader("my header") + + Ω(out).ShouldNot(gbytes.Say("my header")) + }) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go b/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go new file mode 100644 index 000000000..2dcf276d3 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/default_reporter_test.go @@ -0,0 +1,433 @@ +package reporters_test + +import ( + "time" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/reporters" + st "github.com/onsi/ginkgo/reporters/stenographer" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" +) + +var _ = Describe("DefaultReporter", func() { + var ( + reporter *reporters.DefaultReporter + reporterConfig config.DefaultReporterConfigType + stenographer *st.FakeStenographer + + ginkgoConfig config.GinkgoConfigType + suite *types.SuiteSummary + spec *types.SpecSummary + ) + + BeforeEach(func() { + stenographer = st.NewFakeStenographer() + reporterConfig = config.DefaultReporterConfigType{ + NoColor: false, + SlowSpecThreshold: 0.1, + NoisyPendings: false, + NoisySkippings: false, + Verbose: true, + FullTrace: true, + } + + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + }) + + call := func(method string, args ...interface{}) st.FakeStenographerCall { + return st.NewFakeStenographerCall(method, args...) + } + + Describe("SpecSuiteWillBegin", func() { + BeforeEach(func() { + suite = &types.SuiteSummary{ + SuiteDescription: "A Sweet Suite", + NumberOfTotalSpecs: 10, + NumberOfSpecsThatWillBeRun: 8, + } + + ginkgoConfig = config.GinkgoConfigType{ + RandomSeed: 1138, + RandomizeAllSpecs: true, + } + }) + + Context("when a serial (non-parallel) suite begins", func() { + BeforeEach(func() { + ginkgoConfig.ParallelTotal = 1 + + reporter.SpecSuiteWillBegin(ginkgoConfig, suite) + }) + + It("should announce the suite, then announce the number of specs", func() { + Ω(stenographer.Calls()).Should(HaveLen(2)) + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", "A Sweet Suite", ginkgoConfig.RandomSeed, true, false))) + Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceNumberOfSpecs", 8, 10, false))) + }) + }) + + Context("when a parallel suite begins", func() { + BeforeEach(func() { + ginkgoConfig.ParallelTotal = 2 + ginkgoConfig.ParallelNode = 1 + suite.NumberOfSpecsBeforeParallelization = 20 + + reporter.SpecSuiteWillBegin(ginkgoConfig, suite) + }) + + It("should announce the suite, announce that it's a parallel run, then announce the number of specs", func() { + Ω(stenographer.Calls()).Should(HaveLen(2)) + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", "A Sweet Suite", ginkgoConfig.RandomSeed, true, false))) + Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceParallelRun", 1, 2, false))) + }) + }) + }) + + Describe("BeforeSuiteDidRun", func() { + Context("when the BeforeSuite passes", func() { + It("should announce nothing", func() { + reporter.BeforeSuiteDidRun(&types.SetupSummary{ + State: types.SpecStatePassed, + }) + + Ω(stenographer.Calls()).Should(BeEmpty()) + }) + }) + + Context("when the BeforeSuite fails", func() { + It("should announce the failure", func() { + summary := &types.SetupSummary{ + State: types.SpecStateFailed, + } + reporter.BeforeSuiteDidRun(summary) + + Ω(stenographer.Calls()).Should(HaveLen(1)) + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceBeforeSuiteFailure", summary, false, true))) + }) + }) + }) + + Describe("AfterSuiteDidRun", func() { + Context("when the AfterSuite passes", func() { + It("should announce nothing", func() { + reporter.AfterSuiteDidRun(&types.SetupSummary{ + State: types.SpecStatePassed, + }) + + Ω(stenographer.Calls()).Should(BeEmpty()) + }) + }) + + Context("when the AfterSuite fails", func() { + It("should announce the failure", func() { + summary := &types.SetupSummary{ + State: types.SpecStateFailed, + } + reporter.AfterSuiteDidRun(summary) + + Ω(stenographer.Calls()).Should(HaveLen(1)) + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceAfterSuiteFailure", summary, false, true))) + }) + }) + }) + + Describe("SpecWillRun", func() { + Context("When running in verbose mode", func() { + Context("and the spec will run", func() { + BeforeEach(func() { + spec = &types.SpecSummary{} + reporter.SpecWillRun(spec) + }) + + It("should announce that the spec will run", func() { + Ω(stenographer.Calls()).Should(HaveLen(1)) + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecWillRun", spec))) + }) + }) + + Context("and the spec will not run", func() { + Context("because it is pending", func() { + BeforeEach(func() { + spec = &types.SpecSummary{ + State: types.SpecStatePending, + } + reporter.SpecWillRun(spec) + }) + + It("should announce nothing", func() { + Ω(stenographer.Calls()).Should(BeEmpty()) + }) + }) + + Context("because it is skipped", func() { + BeforeEach(func() { + spec = &types.SpecSummary{ + State: types.SpecStateSkipped, + } + reporter.SpecWillRun(spec) + }) + + It("should announce nothing", func() { + Ω(stenographer.Calls()).Should(BeEmpty()) + }) + }) + }) + }) + + Context("When running in verbose & succinct mode", func() { + BeforeEach(func() { + reporterConfig.Succinct = true + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + spec = &types.SpecSummary{} + reporter.SpecWillRun(spec) + }) + + It("should announce nothing", func() { + Ω(stenographer.Calls()).Should(BeEmpty()) + }) + }) + + Context("When not running in verbose mode", func() { + BeforeEach(func() { + reporterConfig.Verbose = false + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + spec = &types.SpecSummary{} + reporter.SpecWillRun(spec) + }) + + It("should announce nothing", func() { + Ω(stenographer.Calls()).Should(BeEmpty()) + }) + }) + }) + + Describe("SpecDidComplete", func() { + JustBeforeEach(func() { + reporter.SpecDidComplete(spec) + }) + + BeforeEach(func() { + spec = &types.SpecSummary{} + }) + + Context("When the spec passed", func() { + BeforeEach(func() { + spec.State = types.SpecStatePassed + }) + + Context("When the spec was a measurement", func() { + BeforeEach(func() { + spec.IsMeasurement = true + }) + + It("should announce the measurement", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulMeasurement", spec, false))) + }) + }) + + Context("When the spec is slow", func() { + BeforeEach(func() { + spec.RunTime = time.Second + }) + + It("should announce that it was slow", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSlowSpec", spec, false))) + }) + }) + + Context("Otherwise", func() { + It("should announce the succesful spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSpec", spec))) + }) + }) + }) + + Context("When the spec is pending", func() { + BeforeEach(func() { + spec.State = types.SpecStatePending + }) + + It("should announce the pending spec, succinctly", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, false))) + }) + }) + + Context("When the spec is skipped", func() { + BeforeEach(func() { + spec.State = types.SpecStateSkipped + }) + + It("should announce the skipped spec, succinctly", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, true, true))) + }) + }) + + Context("When the spec timed out", func() { + BeforeEach(func() { + spec.State = types.SpecStateTimedOut + }) + + It("should announce the timedout spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecTimedOut", spec, false, true))) + }) + }) + + Context("When the spec panicked", func() { + BeforeEach(func() { + spec.State = types.SpecStatePanicked + }) + + It("should announce the panicked spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecPanicked", spec, false, true))) + }) + }) + + Context("When the spec failed", func() { + BeforeEach(func() { + spec.State = types.SpecStateFailed + }) + + It("should announce the failed spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecFailed", spec, false, true))) + }) + }) + + Context("in noisy pendings mode", func() { + BeforeEach(func() { + reporterConfig.Succinct = false + reporterConfig.NoisyPendings = true + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + }) + + Context("When the spec is pending", func() { + BeforeEach(func() { + spec.State = types.SpecStatePending + }) + + It("should announce the pending spec, noisily", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, true))) + }) + }) + }) + + Context("in noisy skippings mode", func() { + BeforeEach(func() { + reporterConfig.Succinct = false + reporterConfig.NoisySkippings = true + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + }) + + Context("When the spec is skipped", func() { + BeforeEach(func() { + spec.State = types.SpecStateSkipped + }) + + It("should announce the skipped spec, noisily", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, false, true))) + }) + }) + }) + + Context("in succinct mode", func() { + BeforeEach(func() { + reporterConfig.Succinct = true + reporter = reporters.NewDefaultReporter(reporterConfig, stenographer) + }) + + Context("When the spec passed", func() { + BeforeEach(func() { + spec.State = types.SpecStatePassed + }) + + Context("When the spec was a measurement", func() { + BeforeEach(func() { + spec.IsMeasurement = true + }) + + It("should announce the measurement", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulMeasurement", spec, true))) + }) + }) + + Context("When the spec is slow", func() { + BeforeEach(func() { + spec.RunTime = time.Second + }) + + It("should announce that it was slow", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSlowSpec", spec, true))) + }) + }) + + Context("Otherwise", func() { + It("should announce the succesful spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSpec", spec))) + }) + }) + }) + + Context("When the spec is pending", func() { + BeforeEach(func() { + spec.State = types.SpecStatePending + }) + + It("should announce the pending spec, succinctly", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, false))) + }) + }) + + Context("When the spec is skipped", func() { + BeforeEach(func() { + spec.State = types.SpecStateSkipped + }) + + It("should announce the skipped spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, true, true))) + }) + }) + + Context("When the spec timed out", func() { + BeforeEach(func() { + spec.State = types.SpecStateTimedOut + }) + + It("should announce the timedout spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecTimedOut", spec, true, true))) + }) + }) + + Context("When the spec panicked", func() { + BeforeEach(func() { + spec.State = types.SpecStatePanicked + }) + + It("should announce the panicked spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecPanicked", spec, true, true))) + }) + }) + + Context("When the spec failed", func() { + BeforeEach(func() { + spec.State = types.SpecStateFailed + }) + + It("should announce the failed spec", func() { + Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecFailed", spec, true, true))) + }) + }) + }) + }) + + Describe("SpecSuiteDidEnd", func() { + BeforeEach(func() { + suite = &types.SuiteSummary{} + reporter.SpecSuiteDidEnd(suite) + }) + + It("should announce the spec run's completion", func() { + Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceSpecRunCompletion", suite, false))) + }) + }) +}) diff --git a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go new file mode 100644 index 000000000..0e3969e4f --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter_test.go @@ -0,0 +1,251 @@ +package reporters_test + +import ( + "encoding/xml" + "io/ioutil" + "os" + "time" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/reporters" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" +) + +var _ = Describe("JUnit Reporter", func() { + var ( + outputFile string + reporter Reporter + ) + + readOutputFile := func() reporters.JUnitTestSuite { + bytes, err := ioutil.ReadFile(outputFile) + Ω(err).ShouldNot(HaveOccurred()) + var suite reporters.JUnitTestSuite + err = xml.Unmarshal(bytes, &suite) + Ω(err).ShouldNot(HaveOccurred()) + return suite + } + + BeforeEach(func() { + f, err := ioutil.TempFile("", "output") + Ω(err).ShouldNot(HaveOccurred()) + f.Close() + outputFile = f.Name() + + reporter = reporters.NewJUnitReporter(outputFile) + + reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{ + SuiteDescription: "My test suite", + NumberOfSpecsThatWillBeRun: 1, + }) + }) + + AfterEach(func() { + os.RemoveAll(outputFile) + }) + + Describe("a passing test", func() { + BeforeEach(func() { + beforeSuite := &types.SetupSummary{ + State: types.SpecStatePassed, + } + reporter.BeforeSuiteDidRun(beforeSuite) + + afterSuite := &types.SetupSummary{ + State: types.SpecStatePassed, + } + reporter.AfterSuiteDidRun(afterSuite) + + spec := &types.SpecSummary{ + ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, + State: types.SpecStatePassed, + RunTime: 5 * time.Second, + } + reporter.SpecWillRun(spec) + reporter.SpecDidComplete(spec) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 0, + RunTime: 10 * time.Second, + }) + }) + + It("should record the test as passing", func() { + output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) + Ω(output.Tests).Should(Equal(1)) + Ω(output.Failures).Should(Equal(0)) + Ω(output.Time).Should(Equal(10.0)) + Ω(output.TestCases).Should(HaveLen(1)) + Ω(output.TestCases[0].Name).Should(Equal("A B C")) + Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) + Ω(output.TestCases[0].FailureMessage).Should(BeNil()) + Ω(output.TestCases[0].Skipped).Should(BeNil()) + Ω(output.TestCases[0].Time).Should(Equal(5.0)) + }) + }) + + Describe("when the BeforeSuite fails", func() { + var beforeSuite *types.SetupSummary + + BeforeEach(func() { + beforeSuite = &types.SetupSummary{ + State: types.SpecStateFailed, + RunTime: 3 * time.Second, + Failure: types.SpecFailure{ + Message: "failed to setup", + ComponentCodeLocation: codelocation.New(0), + Location: codelocation.New(2), + }, + } + reporter.BeforeSuiteDidRun(beforeSuite) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 1, + RunTime: 10 * time.Second, + }) + }) + + It("should record the test as having failed", func() { + output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) + Ω(output.Tests).Should(Equal(1)) + Ω(output.Failures).Should(Equal(1)) + Ω(output.Time).Should(Equal(10.0)) + Ω(output.TestCases[0].Name).Should(Equal("BeforeSuite")) + Ω(output.TestCases[0].Time).Should(Equal(3.0)) + Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) + Ω(output.TestCases[0].FailureMessage.Type).Should(Equal("Failure")) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring("failed to setup")) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(beforeSuite.Failure.ComponentCodeLocation.String())) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(beforeSuite.Failure.Location.String())) + Ω(output.TestCases[0].Skipped).Should(BeNil()) + }) + }) + + Describe("when the AfterSuite fails", func() { + var afterSuite *types.SetupSummary + + BeforeEach(func() { + afterSuite = &types.SetupSummary{ + State: types.SpecStateFailed, + RunTime: 3 * time.Second, + Failure: types.SpecFailure{ + Message: "failed to setup", + ComponentCodeLocation: codelocation.New(0), + Location: codelocation.New(2), + }, + } + reporter.AfterSuiteDidRun(afterSuite) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 1, + RunTime: 10 * time.Second, + }) + }) + + It("should record the test as having failed", func() { + output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) + Ω(output.Tests).Should(Equal(1)) + Ω(output.Failures).Should(Equal(1)) + Ω(output.Time).Should(Equal(10.0)) + Ω(output.TestCases[0].Name).Should(Equal("AfterSuite")) + Ω(output.TestCases[0].Time).Should(Equal(3.0)) + Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) + Ω(output.TestCases[0].FailureMessage.Type).Should(Equal("Failure")) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring("failed to setup")) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(afterSuite.Failure.ComponentCodeLocation.String())) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(afterSuite.Failure.Location.String())) + Ω(output.TestCases[0].Skipped).Should(BeNil()) + }) + }) + + specStateCases := []struct { + state types.SpecState + message string + }{ + {types.SpecStateFailed, "Failure"}, + {types.SpecStateTimedOut, "Timeout"}, + {types.SpecStatePanicked, "Panic"}, + } + + for _, specStateCase := range specStateCases { + specStateCase := specStateCase + Describe("a failing test", func() { + var spec *types.SpecSummary + BeforeEach(func() { + spec = &types.SpecSummary{ + ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, + State: specStateCase.state, + RunTime: 5 * time.Second, + Failure: types.SpecFailure{ + ComponentCodeLocation: codelocation.New(0), + Location: codelocation.New(2), + Message: "I failed", + }, + } + reporter.SpecWillRun(spec) + reporter.SpecDidComplete(spec) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 1, + RunTime: 10 * time.Second, + }) + }) + + It("should record test as failing", func() { + output := readOutputFile() + Ω(output.Name).Should(Equal("My test suite")) + Ω(output.Tests).Should(Equal(1)) + Ω(output.Failures).Should(Equal(1)) + Ω(output.Time).Should(Equal(10.0)) + Ω(output.TestCases[0].Name).Should(Equal("A B C")) + Ω(output.TestCases[0].ClassName).Should(Equal("My test suite")) + Ω(output.TestCases[0].FailureMessage.Type).Should(Equal(specStateCase.message)) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring("I failed")) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(spec.Failure.ComponentCodeLocation.String())) + Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(spec.Failure.Location.String())) + Ω(output.TestCases[0].Skipped).Should(BeNil()) + }) + }) + } + + for _, specStateCase := range []types.SpecState{types.SpecStatePending, types.SpecStateSkipped} { + specStateCase := specStateCase + Describe("a skipped test", func() { + var spec *types.SpecSummary + BeforeEach(func() { + spec = &types.SpecSummary{ + ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, + State: specStateCase, + RunTime: 5 * time.Second, + } + reporter.SpecWillRun(spec) + reporter.SpecDidComplete(spec) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 0, + RunTime: 10 * time.Second, + }) + }) + + It("should record test as failing", func() { + output := readOutputFile() + Ω(output.Tests).Should(Equal(1)) + Ω(output.Failures).Should(Equal(0)) + Ω(output.Time).Should(Equal(10.0)) + Ω(output.TestCases[0].Name).Should(Equal("A B C")) + Ω(output.TestCases[0].Skipped).ShouldNot(BeNil()) + }) + }) + } +}) diff --git a/vendor/github.com/onsi/ginkgo/reporters/reporters_suite_test.go b/vendor/github.com/onsi/ginkgo/reporters/reporters_suite_test.go new file mode 100644 index 000000000..cec5a4dbf --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/reporters_suite_test.go @@ -0,0 +1,13 @@ +package reporters_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestReporters(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Reporters Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/README.md b/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/README.md new file mode 100644 index 000000000..37de454f4 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/README.md @@ -0,0 +1,6 @@ +## Colorize Windows + +These packages are used for colorize on Windows and contributed by mattn.jp@gmail.com + + * go-colorable: + * go-isatty: diff --git a/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable/README.md b/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable/README.md new file mode 100644 index 000000000..e84226a73 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable/README.md @@ -0,0 +1,43 @@ +# go-colorable + +Colorable writer for windows. + +For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.) +This package is possible to handle escape sequence for ansi color on windows. + +## Too Bad! + +![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png) + + +## So Good! + +![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png) + +## Usage + +```go +logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) +logrus.SetOutput(colorable.NewColorableStdout()) + +logrus.Info("succeeded") +logrus.Warn("not correct") +logrus.Error("something error") +logrus.Fatal("panic") +``` + +You can compile above code on non-windows OSs. + +## Installation + +``` +$ go get github.com/mattn/go-colorable +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty/README.md b/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty/README.md new file mode 100644 index 000000000..74845de4a --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty/README.md @@ -0,0 +1,37 @@ +# go-isatty + +isatty for golang + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/mattn/go-isatty" + "os" +) + +func main() { + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Println("Is Terminal") + } else { + fmt.Println("Is Not Terminal") + } +} +``` + +## Installation + +``` +$ go get github.com/mattn/go-isatty +``` + +# License + +MIT + +# Author + +Yasuhiro Matsumoto (a.k.a mattn) diff --git a/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go new file mode 100644 index 000000000..b45d5db01 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/reporters/teamcity_reporter_test.go @@ -0,0 +1,214 @@ +package reporters_test + +import ( + "bytes" + "fmt" + "time" + + . "github.com/onsi/ginkgo" + "github.com/onsi/ginkgo/config" + "github.com/onsi/ginkgo/internal/codelocation" + "github.com/onsi/ginkgo/reporters" + "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" +) + +var _ = Describe("TeamCity Reporter", func() { + var ( + buffer bytes.Buffer + reporter Reporter + ) + + BeforeEach(func() { + buffer.Truncate(0) + reporter = reporters.NewTeamCityReporter(&buffer) + reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{ + SuiteDescription: "Foo's test suite", + NumberOfSpecsThatWillBeRun: 1, + }) + }) + + Describe("a passing test", func() { + BeforeEach(func() { + beforeSuite := &types.SetupSummary{ + State: types.SpecStatePassed, + } + reporter.BeforeSuiteDidRun(beforeSuite) + + afterSuite := &types.SetupSummary{ + State: types.SpecStatePassed, + } + reporter.AfterSuiteDidRun(afterSuite) + + spec := &types.SpecSummary{ + ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, + State: types.SpecStatePassed, + RunTime: 5 * time.Second, + } + reporter.SpecWillRun(spec) + reporter.SpecDidComplete(spec) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 0, + RunTime: 10 * time.Second, + }) + }) + + It("should record the test as passing", func() { + actual := buffer.String() + expected := + "##teamcity[testSuiteStarted name='Foo|'s test suite']" + + "##teamcity[testStarted name='A B C']" + + "##teamcity[testFinished name='A B C' duration='5000']" + + "##teamcity[testSuiteFinished name='Foo|'s test suite']" + Ω(actual).Should(Equal(expected)) + }) + }) + + Describe("when the BeforeSuite fails", func() { + var beforeSuite *types.SetupSummary + + BeforeEach(func() { + beforeSuite = &types.SetupSummary{ + State: types.SpecStateFailed, + RunTime: 3 * time.Second, + Failure: types.SpecFailure{ + Message: "failed to setup\n", + ComponentCodeLocation: codelocation.New(0), + }, + } + reporter.BeforeSuiteDidRun(beforeSuite) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 1, + RunTime: 10 * time.Second, + }) + }) + + It("should record the test as having failed", func() { + actual := buffer.String() + expected := fmt.Sprintf( + "##teamcity[testSuiteStarted name='Foo|'s test suite']"+ + "##teamcity[testStarted name='BeforeSuite']"+ + "##teamcity[testFailed name='BeforeSuite' message='%s' details='failed to setup|n']"+ + "##teamcity[testFinished name='BeforeSuite' duration='3000']"+ + "##teamcity[testSuiteFinished name='Foo|'s test suite']", beforeSuite.Failure.ComponentCodeLocation.String(), + ) + Ω(actual).Should(Equal(expected)) + }) + }) + + Describe("when the AfterSuite fails", func() { + var afterSuite *types.SetupSummary + + BeforeEach(func() { + afterSuite = &types.SetupSummary{ + State: types.SpecStateFailed, + RunTime: 3 * time.Second, + Failure: types.SpecFailure{ + Message: "failed to setup\n", + ComponentCodeLocation: codelocation.New(0), + }, + } + reporter.AfterSuiteDidRun(afterSuite) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 1, + RunTime: 10 * time.Second, + }) + }) + + It("should record the test as having failed", func() { + actual := buffer.String() + expected := fmt.Sprintf( + "##teamcity[testSuiteStarted name='Foo|'s test suite']"+ + "##teamcity[testStarted name='AfterSuite']"+ + "##teamcity[testFailed name='AfterSuite' message='%s' details='failed to setup|n']"+ + "##teamcity[testFinished name='AfterSuite' duration='3000']"+ + "##teamcity[testSuiteFinished name='Foo|'s test suite']", afterSuite.Failure.ComponentCodeLocation.String(), + ) + Ω(actual).Should(Equal(expected)) + }) + }) + specStateCases := []struct { + state types.SpecState + message string + }{ + {types.SpecStateFailed, "Failure"}, + {types.SpecStateTimedOut, "Timeout"}, + {types.SpecStatePanicked, "Panic"}, + } + + for _, specStateCase := range specStateCases { + specStateCase := specStateCase + Describe("a failing test", func() { + var spec *types.SpecSummary + BeforeEach(func() { + spec = &types.SpecSummary{ + ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, + State: specStateCase.state, + RunTime: 5 * time.Second, + Failure: types.SpecFailure{ + ComponentCodeLocation: codelocation.New(0), + Message: "I failed", + }, + } + reporter.SpecWillRun(spec) + reporter.SpecDidComplete(spec) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 1, + RunTime: 10 * time.Second, + }) + }) + + It("should record test as failing", func() { + actual := buffer.String() + expected := + fmt.Sprintf("##teamcity[testSuiteStarted name='Foo|'s test suite']"+ + "##teamcity[testStarted name='A B C']"+ + "##teamcity[testFailed name='A B C' message='%s' details='I failed']"+ + "##teamcity[testFinished name='A B C' duration='5000']"+ + "##teamcity[testSuiteFinished name='Foo|'s test suite']", spec.Failure.ComponentCodeLocation.String()) + Ω(actual).Should(Equal(expected)) + }) + }) + } + + for _, specStateCase := range []types.SpecState{types.SpecStatePending, types.SpecStateSkipped} { + specStateCase := specStateCase + Describe("a skipped test", func() { + var spec *types.SpecSummary + BeforeEach(func() { + spec = &types.SpecSummary{ + ComponentTexts: []string{"[Top Level]", "A", "B", "C"}, + State: specStateCase, + RunTime: 5 * time.Second, + } + reporter.SpecWillRun(spec) + reporter.SpecDidComplete(spec) + + reporter.SpecSuiteDidEnd(&types.SuiteSummary{ + NumberOfSpecsThatWillBeRun: 1, + NumberOfFailedSpecs: 0, + RunTime: 10 * time.Second, + }) + }) + + It("should record test as ignored", func() { + actual := buffer.String() + expected := + "##teamcity[testSuiteStarted name='Foo|'s test suite']" + + "##teamcity[testStarted name='A B C']" + + "##teamcity[testIgnored name='A B C']" + + "##teamcity[testFinished name='A B C' duration='5000']" + + "##teamcity[testSuiteFinished name='Foo|'s test suite']" + Ω(actual).Should(Equal(expected)) + }) + }) + } +}) diff --git a/vendor/github.com/onsi/ginkgo/types/types_suite_test.go b/vendor/github.com/onsi/ginkgo/types/types_suite_test.go new file mode 100644 index 000000000..b026169c1 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/types/types_suite_test.go @@ -0,0 +1,13 @@ +package types_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestTypes(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Types Suite") +} diff --git a/vendor/github.com/onsi/ginkgo/types/types_test.go b/vendor/github.com/onsi/ginkgo/types/types_test.go new file mode 100644 index 000000000..a0e161c88 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/types/types_test.go @@ -0,0 +1,99 @@ +package types_test + +import ( + . "github.com/onsi/ginkgo/types" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var specStates = []SpecState{ + SpecStatePassed, + SpecStateTimedOut, + SpecStatePanicked, + SpecStateFailed, + SpecStatePending, + SpecStateSkipped, +} + +func verifySpecSummary(caller func(SpecSummary) bool, trueStates ...SpecState) { + summary := SpecSummary{} + trueStateLookup := map[SpecState]bool{} + for _, state := range trueStates { + trueStateLookup[state] = true + summary.State = state + Ω(caller(summary)).Should(BeTrue()) + } + + for _, state := range specStates { + if trueStateLookup[state] { + continue + } + summary.State = state + Ω(caller(summary)).Should(BeFalse()) + } +} + +var _ = Describe("Types", func() { + Describe("IsFailureState", func() { + It("knows when it is in a failure-like state", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.State.IsFailure() + }, SpecStateTimedOut, SpecStatePanicked, SpecStateFailed) + }) + }) + + Describe("SpecSummary", func() { + It("knows when it is in a failure-like state", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.HasFailureState() + }, SpecStateTimedOut, SpecStatePanicked, SpecStateFailed) + }) + + It("knows when it passed", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.Passed() + }, SpecStatePassed) + }) + + It("knows when it has failed", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.Failed() + }, SpecStateFailed) + }) + + It("knows when it has panicked", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.Panicked() + }, SpecStatePanicked) + }) + + It("knows when it has timed out", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.TimedOut() + }, SpecStateTimedOut) + }) + + It("knows when it is pending", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.Pending() + }, SpecStatePending) + }) + + It("knows when it is skipped", func() { + verifySpecSummary(func(summary SpecSummary) bool { + return summary.Skipped() + }, SpecStateSkipped) + }) + }) + + Describe("SpecMeasurement", func() { + It("knows how to format values when the precision is 0", func() { + Ω(SpecMeasurement{}.PrecisionFmt()).Should(Equal("%f")) + }) + + It("knows how to format the values when the precision is 3", func() { + Ω(SpecMeasurement{Precision: 3}.PrecisionFmt()).Should(Equal("%.3f")) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/.gitignore b/vendor/github.com/onsi/gomega/.gitignore new file mode 100644 index 000000000..720c13cba --- /dev/null +++ b/vendor/github.com/onsi/gomega/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +*.test +. +.idea +gomega.iml diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml new file mode 100644 index 000000000..8b982a9ab --- /dev/null +++ b/vendor/github.com/onsi/gomega/.travis.yml @@ -0,0 +1,14 @@ +language: go +go: + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + +install: + - go get -v ./... + - go get github.com/onsi/ginkgo + - go install github.com/onsi/ginkgo/ginkgo + +script: $HOME/gopath/bin/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race && go vet diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md new file mode 100644 index 000000000..2ee5d9b74 --- /dev/null +++ b/vendor/github.com/onsi/gomega/CHANGELOG.md @@ -0,0 +1,99 @@ +## HEAD + +### Features +- Make string pretty diff user configurable (#273) [eb112ce, 649b44d] + +### Fixes +- Use httputil.DumpRequest to pretty-print unhandled requests (#278) [a4ff0fc, b7d1a52] +- fix typo floa32 > float32 (#272) [041ae3b, 6e33911] +- Fix link to documentation on adding your own matchers (#270) [bb2c830, fcebc62] +- Use setters and getters to avoid race condition (#262) [13057c3, a9c79f1] +- Avoid sending a signal if the process is not alive (#259) [b8043e5, 4fc1762] +- Improve message from AssignableToTypeOf when expected value is nil (#281) [9c1fb20] + +## 1.3.0 + +Improvements: + +- The `Equal` matcher matches byte slices more performantly. +- Improved how `MatchError` matches error strings. +- `MatchXML` ignores the order of xml node attributes. +- Improve support for XUnit style golang tests. ([#254](https://github.com/onsi/gomega/issues/254)) + +Bug Fixes: + +- Diff generation now handles multi-byte sequences correctly. +- Multiple goroutines can now call `gexec.Build` concurrently. + +## 1.2.0 + +Improvements: + +- Added `BeSent` which attempts to send a value down a channel and fails if the attempt blocks. Can be paired with `Eventually` to safely send a value down a channel with a timeout. +- `Ω`, `Expect`, `Eventually`, and `Consistently` now immediately `panic` if there is no registered fail handler. This is always a mistake that can hide failing tests. +- `Receive()` no longer errors when passed a closed channel, it's perfectly fine to attempt to read from a closed channel so Ω(c).Should(Receive()) always fails and Ω(c).ShoudlNot(Receive()) always passes with a closed channel. +- Added `HavePrefix` and `HaveSuffix` matchers. +- `ghttp` can now handle concurrent requests. +- Added `Succeed` which allows one to write `Ω(MyFunction()).Should(Succeed())`. +- Improved `ghttp`'s behavior around failing assertions and panics: + - If a registered handler makes a failing assertion `ghttp` will return `500`. + - If a registered handler panics, `ghttp` will return `500` *and* fail the test. This is new behavior that may cause existing code to break. This code is almost certainly incorrect and creating a false positive. +- `ghttp` servers can take an `io.Writer`. `ghttp` will write a line to the writer when each request arrives. +- Added `WithTransform` matcher to allow munging input data before feeding into the relevant matcher +- Added boolean `And`, `Or`, and `Not` matchers to allow creating composite matchers +- Added `gbytes.TimeoutCloser`, `gbytes.TimeoutReader`, and `gbytes.TimeoutWriter` - these are convenience wrappers that timeout if the underlying Closer/Reader/Writer does not return within the alloted time. +- Added `gbytes.BufferReader` - this constructs a `gbytes.Buffer` that asynchronously reads the passed-in `io.Reader` into its buffer. + +Bug Fixes: +- gexec: `session.Wait` now uses `EventuallyWithOffset` to get the right line number in the failure. +- `ContainElement` no longer bails if a passed-in matcher errors. + +## 1.0 (8/2/2014) + +No changes. Dropping "beta" from the version number. + +## 1.0.0-beta (7/8/2014) +Breaking Changes: + +- Changed OmegaMatcher interface. Instead of having `Match` return failure messages, two new methods `FailureMessage` and `NegatedFailureMessage` are called instead. +- Moved and renamed OmegaFailHandler to types.GomegaFailHandler and OmegaMatcher to types.GomegaMatcher. Any references to OmegaMatcher in any custom matchers will need to be changed to point to types.GomegaMatcher + +New Test-Support Features: + +- `ghttp`: supports testing http clients + - Provides a flexible fake http server + - Provides a collection of chainable http handlers that perform assertions. +- `gbytes`: supports making ordered assertions against streams of data + - Provides a `gbytes.Buffer` + - Provides a `Say` matcher to perform ordered assertions against output data +- `gexec`: supports testing external processes + - Provides support for building Go binaries + - Wraps and starts `exec.Cmd` commands + - Makes it easy to assert against stdout and stderr + - Makes it easy to send signals and wait for processes to exit + - Provides an `Exit` matcher to assert against exit code. + +DSL Changes: + +- `Eventually` and `Consistently` can accept `time.Duration` interval and polling inputs. +- The default timeouts for `Eventually` and `Consistently` are now configurable. + +New Matchers: + +- `ConsistOf`: order-independent assertion against the elements of an array/slice or keys of a map. +- `BeTemporally`: like `BeNumerically` but for `time.Time` +- `HaveKeyWithValue`: asserts a map has a given key with the given value. + +Updated Matchers: + +- `Receive` matcher can take a matcher as an argument and passes only if the channel under test receives an objet that satisfies the passed-in matcher. +- Matchers that implement `MatchMayChangeInTheFuture(actual interface{}) bool` can inform `Eventually` and/or `Consistently` when a match has no chance of changing status in the future. For example, `Receive` returns `false` when a channel is closed. + +Misc: + +- Start using semantic versioning +- Start maintaining changelog + +Major refactor: + +- Pull out Gomega's internal to `internal` diff --git a/vendor/github.com/onsi/gomega/CONTRIBUTING.md b/vendor/github.com/onsi/gomega/CONTRIBUTING.md new file mode 100644 index 000000000..0d7a09928 --- /dev/null +++ b/vendor/github.com/onsi/gomega/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing to Gomega + +Your contributions to Gomega are essential for its long-term maintenance and improvement. To make a contribution: + +- Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code! +- Ensure adequate test coverage: + - Make sure to add appropriate unit tests + - Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR + - Please run following linter locally `go vet ./...` and make sure output does not contain any warnings +- Update the documentation. In addition to standard `godoc` comments Gomega has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR. + +If you're a committer, check out RELEASING.md to learn how to cut a release. + +Thanks for supporting Gomega! diff --git a/vendor/github.com/onsi/gomega/README.md b/vendor/github.com/onsi/gomega/README.md new file mode 100644 index 000000000..159be3590 --- /dev/null +++ b/vendor/github.com/onsi/gomega/README.md @@ -0,0 +1,21 @@ +![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png) + +[![Build Status](https://travis-ci.org/onsi/gomega.svg)](https://travis-ci.org/onsi/gomega) + +Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers). + +If you have a question, comment, bug report, feature request, etc. please open a GitHub issue. + +## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang + +Learn more about Ginkgo [here](http://onsi.github.io/ginkgo/) + +## Community Matchers + +A collection of community matchers is available on the [wiki](https://github.com/onsi/gomega/wiki). + +## License + +Gomega is MIT-Licensed + +The `ConsistOf` matcher uses [goraph](https://github.com/amitkgupta/goraph) which is embedded in the source to simplify distribution. goraph has an MIT license. diff --git a/vendor/github.com/onsi/gomega/RELEASING.md b/vendor/github.com/onsi/gomega/RELEASING.md new file mode 100644 index 000000000..998d64ee7 --- /dev/null +++ b/vendor/github.com/onsi/gomega/RELEASING.md @@ -0,0 +1,12 @@ +A Gomega release is a tagged sha and a GitHub release. To cut a release: + +1. Ensure CHANGELOG.md is up to date. + - Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release + - Categorize the changes into + - Breaking Changes (requires a major version) + - New Features (minor version) + - Fixes (fix version) + - Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact) +2. Update GOMEGA_VERSION in `gomega_dsl.go` +3. Push a commit with the version number as the commit message (e.g. `v1.3.0`) +4. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes. diff --git a/vendor/github.com/onsi/gomega/format/format_suite_test.go b/vendor/github.com/onsi/gomega/format/format_suite_test.go new file mode 100644 index 000000000..8e65a9529 --- /dev/null +++ b/vendor/github.com/onsi/gomega/format/format_suite_test.go @@ -0,0 +1,13 @@ +package format_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestFormat(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Format Suite") +} diff --git a/vendor/github.com/onsi/gomega/format/format_test.go b/vendor/github.com/onsi/gomega/format/format_test.go new file mode 100644 index 000000000..9ea781379 --- /dev/null +++ b/vendor/github.com/onsi/gomega/format/format_test.go @@ -0,0 +1,627 @@ +package format_test + +import ( + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/format" + "github.com/onsi/gomega/types" +) + +//recursive struct + +type StringAlias string +type ByteAlias []byte +type IntAlias int + +type AStruct struct { + Exported string +} + +type SimpleStruct struct { + Name string + Enumeration int + Veritas bool + Data []byte + secret uint32 +} + +type ComplexStruct struct { + Strings []string + SimpleThings []*SimpleStruct + DataMaps map[int]ByteAlias +} + +type SecretiveStruct struct { + boolValue bool + intValue int + uintValue uint + uintptrValue uintptr + floatValue float32 + complexValue complex64 + chanValue chan bool + funcValue func() + pointerValue *int + sliceValue []string + byteSliceValue []byte + stringValue string + arrValue [3]int + byteArrValue [3]byte + mapValue map[string]int + structValue AStruct + interfaceValue interface{} +} + +type GoStringer struct { +} + +func (g GoStringer) GoString() string { + return "go-string" +} + +func (g GoStringer) String() string { + return "string" +} + +type Stringer struct { +} + +func (g Stringer) String() string { + return "string" +} + +type ctx struct { +} + +func (c *ctx) Deadline() (deadline time.Time, ok bool) { + return time.Time{}, false +} + +func (c *ctx) Done() <-chan struct{} { + return nil +} + +func (c *ctx) Err() error { + return nil +} + +func (c *ctx) Value(key interface{}) interface{} { + return nil +} + +var _ = Describe("Format", func() { + match := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher { + if len(args) > 0 { + valueRepresentation = fmt.Sprintf(valueRepresentation, args...) + } + return Equal(fmt.Sprintf("%s<%s>: %s", Indent, typeRepresentation, valueRepresentation)) + } + + matchRegexp := func(typeRepresentation string, valueRepresentation string, args ...interface{}) types.GomegaMatcher { + if len(args) > 0 { + valueRepresentation = fmt.Sprintf(valueRepresentation, args...) + } + return MatchRegexp(fmt.Sprintf("%s<%s>: %s", Indent, typeRepresentation, valueRepresentation)) + } + + hashMatchingRegexp := func(entries ...string) string { + entriesSwitch := "(" + strings.Join(entries, "|") + ")" + arr := make([]string, len(entries)) + for i := range arr { + arr[i] = entriesSwitch + } + return "{" + strings.Join(arr, ", ") + "}" + } + + Describe("Message", func() { + Context("with only an actual value", func() { + It("should print out an indented formatted representation of the value and the message", func() { + Expect(Message(3, "to be three.")).Should(Equal("Expected\n : 3\nto be three.")) + }) + }) + + Context("with an actual and an expected value", func() { + It("should print out an indented formatted representatino of both values, and the message", func() { + Expect(Message(3, "to equal", 4)).Should(Equal("Expected\n : 3\nto equal\n : 4")) + }) + }) + }) + + Describe("MessageWithDiff", func() { + It("shows the exact point where two long strings differ", func() { + stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedLongStringFailureMessage)) + }) + + It("truncates the start of long strings that differ only at their end", func() { + stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab" + stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz" + + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedStartStringFailureMessage)) + }) + + It("truncates the start of long strings that differ only in length", func() { + smallString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + largeString := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + Expect(MessageWithDiff(largeString, "to equal", smallString)).Should(Equal(expectedTruncatedStartSizeFailureMessage)) + Expect(MessageWithDiff(smallString, "to equal", largeString)).Should(Equal(expectedTruncatedStartSizeSwappedFailureMessage)) + }) + + It("truncates the end of long strings that differ only at their start", func() { + stringWithB := "baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + stringWithZ := "zaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedTruncatedEndStringFailureMessage)) + }) + + It("handles multi-byte sequences correctly", func() { + stringA := "• abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1" + stringB := "• abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" + + Expect(MessageWithDiff(stringA, "to equal", stringB)).Should(Equal(expectedTruncatedMultiByteFailureMessage)) + }) + + Context("With truncated diff disabled", func() { + BeforeEach(func() { + TruncatedDiff = false + }) + + AfterEach(func() { + TruncatedDiff = true + }) + + It("should show the full diff", func() { + stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + Expect(MessageWithDiff(stringWithB, "to equal", stringWithZ)).Should(Equal(expectedFullFailureDiff)) + }) + }) + }) + + Describe("IndentString", func() { + It("should indent the string", func() { + Expect(IndentString("foo\n bar\nbaz", 2)).Should(Equal(" foo\n bar\n baz")) + }) + }) + + Describe("Object", func() { + Describe("formatting boolean values", func() { + It("should give the type and format values correctly", func() { + Expect(Object(true, 1)).Should(match("bool", "true")) + Expect(Object(false, 1)).Should(match("bool", "false")) + }) + }) + + Describe("formatting numbers", func() { + It("should give the type and format values correctly", func() { + Expect(Object(int(3), 1)).Should(match("int", "3")) + Expect(Object(int8(3), 1)).Should(match("int8", "3")) + Expect(Object(int16(3), 1)).Should(match("int16", "3")) + Expect(Object(int32(3), 1)).Should(match("int32", "3")) + Expect(Object(int64(3), 1)).Should(match("int64", "3")) + + Expect(Object(uint(3), 1)).Should(match("uint", "3")) + Expect(Object(uint8(3), 1)).Should(match("uint8", "3")) + Expect(Object(uint16(3), 1)).Should(match("uint16", "3")) + Expect(Object(uint32(3), 1)).Should(match("uint32", "3")) + Expect(Object(uint64(3), 1)).Should(match("uint64", "3")) + }) + + It("should handle uintptr differently", func() { + Expect(Object(uintptr(3), 1)).Should(match("uintptr", "0x3")) + }) + }) + + Describe("formatting channels", func() { + It("should give the type and format values correctly", func() { + c := make(chan<- bool, 3) + c <- true + c <- false + Expect(Object(c, 1)).Should(match("chan<- bool | len:2, cap:3", "%v", c)) + }) + }) + + Describe("formatting strings", func() { + It("should give the type and format values correctly", func() { + s := "a\nb\nc" + Expect(Object(s, 1)).Should(match("string", `a + b + c`)) + }) + }) + + Describe("formatting []byte slices", func() { + Context("when the slice is made of printable bytes", func() { + It("should present it as string", func() { + b := []byte("a b c") + Expect(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:5, cap:\d+`, `a b c`)) + }) + }) + Context("when the slice contains non-printable bytes", func() { + It("should present it as slice", func() { + b := []byte("a b c\n\x01\x02\x03\xff\x1bH") + Expect(Object(b, 1)).Should(matchRegexp(`\[\]uint8 \| len:12, cap:\d+`, `\[97, 32, 98, 32, 99, 10, 1, 2, 3, 255, 27, 72\]`)) + }) + }) + }) + + Describe("formatting functions", func() { + It("should give the type and format values correctly", func() { + f := func(a string, b []int) ([]byte, error) { + return []byte("abc"), nil + } + Expect(Object(f, 1)).Should(match("func(string, []int) ([]uint8, error)", "%v", f)) + }) + }) + + Describe("formatting pointers", func() { + It("should give the type and dereference the value to format it correctly", func() { + a := 3 + Expect(Object(&a, 1)).Should(match(fmt.Sprintf("*int | %p", &a), "3")) + }) + + Context("when there are pointers to pointers...", func() { + It("should recursively deference the pointer until it gets to a value", func() { + a := 3 + var b *int + var c **int + var d ***int + b = &a + c = &b + d = &c + + Expect(Object(d, 1)).Should(match(fmt.Sprintf("***int | %p", d), "3")) + }) + }) + + Context("when the pointer points to nil", func() { + It("should say nil and not explode", func() { + var a *AStruct + Expect(Object(a, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) + }) + }) + }) + + Describe("formatting arrays", func() { + It("should give the type and format values correctly", func() { + w := [3]string{"Jed Bartlet", "Toby Ziegler", "CJ Cregg"} + Expect(Object(w, 1)).Should(match("[3]string", `["Jed Bartlet", "Toby Ziegler", "CJ Cregg"]`)) + }) + + Context("with byte arrays", func() { + It("should give the type and format values correctly", func() { + w := [3]byte{17, 28, 19} + Expect(Object(w, 1)).Should(match("[3]uint8", `[17, 28, 19]`)) + }) + }) + }) + + Describe("formatting slices", func() { + It("should include the length and capacity in the type information", func() { + s := make([]bool, 3, 4) + Expect(Object(s, 1)).Should(match("[]bool | len:3, cap:4", "[false, false, false]")) + }) + + Context("when the slice contains long entries", func() { + It("should format the entries with newlines", func() { + w := []string{"Josiah Edward Bartlet", "Toby Ziegler", "CJ Cregg"} + expected := `[ + "Josiah Edward Bartlet", + "Toby Ziegler", + "CJ Cregg", + ]` + Expect(Object(w, 1)).Should(match("[]string | len:3, cap:3", expected)) + }) + }) + }) + + Describe("formatting maps", func() { + It("should include the length in the type information", func() { + m := make(map[int]bool, 5) + m[3] = true + m[4] = false + Expect(Object(m, 1)).Should(matchRegexp(`map\[int\]bool \| len:2`, hashMatchingRegexp("3: true", "4: false"))) + }) + + Context("when the slice contains long entries", func() { + It("should format the entries with newlines", func() { + m := map[string][]byte{} + m["Josiah Edward Bartlet"] = []byte("Martin Sheen") + m["Toby Ziegler"] = []byte("Richard Schiff") + m["CJ Cregg"] = []byte("Allison Janney") + expected := `{ + ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), + ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), + ("Josiah Edward Bartlet": "Martin Sheen"|"Toby Ziegler": "Richard Schiff"|"CJ Cregg": "Allison Janney"), + }` + Expect(Object(m, 1)).Should(matchRegexp(`map\[string\]\[\]uint8 \| len:3`, expected)) + }) + }) + }) + + Describe("formatting structs", func() { + It("should include the struct name and the field names", func() { + s := SimpleStruct{ + Name: "Oswald", + Enumeration: 17, + Veritas: true, + Data: []byte("datum"), + secret: 1983, + } + + Expect(Object(s, 1)).Should(match("format_test.SimpleStruct", `{Name: "Oswald", Enumeration: 17, Veritas: true, Data: "datum", secret: 1983}`)) + }) + + Context("when the struct contains long entries", func() { + It("should format the entries with new lines", func() { + s := &SimpleStruct{ + Name: "Mithrandir Gandalf Greyhame", + Enumeration: 2021, + Veritas: true, + Data: []byte("wizard"), + secret: 3, + } + + Expect(Object(s, 1)).Should(match(fmt.Sprintf("*format_test.SimpleStruct | %p", s), `{ + Name: "Mithrandir Gandalf Greyhame", + Enumeration: 2021, + Veritas: true, + Data: "wizard", + secret: 3, + }`)) + }) + }) + }) + + Describe("formatting nil values", func() { + It("should print out nil", func() { + Expect(Object(nil, 1)).Should(match("nil", "nil")) + var typedNil *AStruct + Expect(Object(typedNil, 1)).Should(match("*format_test.AStruct | 0x0", "nil")) + var c chan<- bool + Expect(Object(c, 1)).Should(match("chan<- bool | len:0, cap:0", "nil")) + var s []string + Expect(Object(s, 1)).Should(match("[]string | len:0, cap:0", "nil")) + var m map[string]bool + Expect(Object(m, 1)).Should(match("map[string]bool | len:0", "nil")) + }) + }) + + Describe("formatting aliased types", func() { + It("should print out the correct alias type", func() { + Expect(Object(StringAlias("alias"), 1)).Should(match("format_test.StringAlias", `alias`)) + Expect(Object(ByteAlias("alias"), 1)).Should(matchRegexp(`format_test\.ByteAlias \| len:5, cap:\d+`, `alias`)) + Expect(Object(IntAlias(3), 1)).Should(match("format_test.IntAlias", "3")) + }) + }) + + Describe("handling nested things", func() { + It("should produce a correctly nested representation", func() { + s := ComplexStruct{ + Strings: []string{"lots", "of", "short", "strings"}, + SimpleThings: []*SimpleStruct{ + {"short", 7, true, []byte("succinct"), 17}, + {"something longer", 427, true, []byte("designed to wrap around nicely"), 30}, + }, + DataMaps: map[int]ByteAlias{ + 17: ByteAlias("some substantially longer chunks of data"), + 1138: ByteAlias("that should make things wrap"), + }, + } + expected := `{ + Strings: \["lots", "of", "short", "strings"\], + SimpleThings: \[ + {Name: "short", Enumeration: 7, Veritas: true, Data: "succinct", secret: 17}, + { + Name: "something longer", + Enumeration: 427, + Veritas: true, + Data: "designed to wrap around nicely", + secret: 30, + }, + \], + DataMaps: { + (17: "some substantially longer chunks of data"|1138: "that should make things wrap"), + (17: "some substantially longer chunks of data"|1138: "that should make things wrap"), + }, + }` + Expect(Object(s, 1)).Should(matchRegexp(`format_test\.ComplexStruct`, expected)) + }) + }) + + Describe("formatting times", func() { + It("should format time as RFC3339", func() { + t := time.Date(2016, 10, 31, 9, 57, 23, 12345, time.UTC) + Expect(Object(t, 1)).Should(match("time.Time", `2016-10-31T09:57:23.000012345Z`)) + }) + }) + }) + + Describe("Handling unexported fields in structs", func() { + It("should handle all the various types correctly", func() { + a := int(5) + s := SecretiveStruct{ + boolValue: true, + intValue: 3, + uintValue: 4, + uintptrValue: 5, + floatValue: 6.0, + complexValue: complex(5.0, 3.0), + chanValue: make(chan bool, 2), + funcValue: func() {}, + pointerValue: &a, + sliceValue: []string{"string", "slice"}, + byteSliceValue: []byte("bytes"), + stringValue: "a string", + arrValue: [3]int{11, 12, 13}, + byteArrValue: [3]byte{17, 20, 32}, + mapValue: map[string]int{"a key": 20, "b key": 30}, + structValue: AStruct{"exported"}, + interfaceValue: map[string]int{"a key": 17}, + } + + expected := fmt.Sprintf(`{ + boolValue: true, + intValue: 3, + uintValue: 4, + uintptrValue: 0x5, + floatValue: 6, + complexValue: \(5\+3i\), + chanValue: %p, + funcValue: %p, + pointerValue: 5, + sliceValue: \["string", "slice"\], + byteSliceValue: "bytes", + stringValue: "a string", + arrValue: \[11, 12, 13\], + byteArrValue: \[17, 20, 32\], + mapValue: %s, + structValue: {Exported: "exported"}, + interfaceValue: {"a key": 17}, + }`, s.chanValue, s.funcValue, hashMatchingRegexp(`"a key": 20`, `"b key": 30`)) + + Expect(Object(s, 1)).Should(matchRegexp(`format_test\.SecretiveStruct`, expected)) + }) + }) + + Describe("Handling interfaces", func() { + It("should unpack the interface", func() { + outerHash := map[string]interface{}{} + innerHash := map[string]int{} + + innerHash["inner"] = 3 + outerHash["integer"] = 2 + outerHash["map"] = innerHash + + expected := hashMatchingRegexp(`"integer": 2`, `"map": {"inner": 3}`) + Expect(Object(outerHash, 1)).Should(matchRegexp(`map\[string\]interface {} \| len:2`, expected)) + }) + }) + + Describe("Handling recursive things", func() { + It("should not go crazy...", func() { + m := map[string]interface{}{} + m["integer"] = 2 + m["map"] = m + Expect(Object(m, 1)).Should(ContainSubstring("...")) + }) + + It("really should not go crazy...", func() { + type complexKey struct { + Value map[interface{}]int + } + + complexObject := complexKey{} + complexObject.Value = make(map[interface{}]int) + + complexObject.Value[&complexObject] = 2 + Expect(Object(complexObject, 1)).Should(ContainSubstring("...")) + }) + }) + + Describe("When instructed to use the Stringer representation", func() { + BeforeEach(func() { + UseStringerRepresentation = true + }) + + AfterEach(func() { + UseStringerRepresentation = false + }) + + Context("when passed a GoStringer", func() { + It("should use what GoString() returns", func() { + Expect(Object(GoStringer{}, 1)).Should(ContainSubstring(": go-string")) + }) + }) + + Context("when passed a stringer", func() { + It("should use what String() returns", func() { + Expect(Object(Stringer{}, 1)).Should(ContainSubstring(": string")) + }) + }) + }) + + Describe("Printing a context.Context field", func() { + + type structWithContext struct { + Context Ctx + Value string + } + + context := ctx{} + objWithContext := structWithContext{Value: "some-value", Context: &context} + + It("Suppresses the content by default", func() { + Expect(Object(objWithContext, 1)).Should(ContainSubstring("")) + }) + + It("Doesn't supress the context if it's the object being printed", func() { + Expect(Object(context, 1)).ShouldNot(MatchRegexp("^.*$")) + }) + + Context("PrintContextObjects is set", func() { + BeforeEach(func() { + PrintContextObjects = true + }) + + AfterEach(func() { + PrintContextObjects = false + }) + + It("Prints the context", func() { + Expect(Object(objWithContext, 1)).ShouldNot(ContainSubstring("")) + }) + }) + }) +}) + +var expectedLongStringFailureMessage = strings.TrimSpace(` +Expected + : "...aaaaabaaaaa..." +to equal | + : "...aaaaazaaaaa..." +`) +var expectedTruncatedEndStringFailureMessage = strings.TrimSpace(` +Expected + : "baaaaa..." +to equal | + : "zaaaaa..." +`) +var expectedTruncatedStartStringFailureMessage = strings.TrimSpace(` +Expected + : "...aaaaab" +to equal | + : "...aaaaaz" +`) +var expectedTruncatedStartSizeFailureMessage = strings.TrimSpace(` +Expected + : "...aaaaaa" +to equal | + : "...aaaaa" +`) +var expectedTruncatedStartSizeSwappedFailureMessage = strings.TrimSpace(` +Expected + : "...aaaa" +to equal | + : "...aaaaa" +`) +var expectedTruncatedMultiByteFailureMessage = strings.TrimSpace(` +Expected + : "...tuvwxyz1" +to equal | + : "...tuvwxyz" +`) + +var expectedFullFailureDiff = strings.TrimSpace(` +Expected + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +to equal + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +`) diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go new file mode 100644 index 000000000..dae47a48b --- /dev/null +++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion_suite_test.go @@ -0,0 +1,13 @@ +package assertion_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestAssertion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Assertion Suite") +} diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go new file mode 100644 index 000000000..1334777bd --- /dev/null +++ b/vendor/github.com/onsi/gomega/internal/assertion/assertion_test.go @@ -0,0 +1,252 @@ +package assertion_test + +import ( + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/internal/assertion" + "github.com/onsi/gomega/internal/fakematcher" +) + +var _ = Describe("Assertion", func() { + var ( + a *Assertion + failureMessage string + failureCallerSkip int + matcher *fakematcher.FakeMatcher + ) + + input := "The thing I'm testing" + + var fakeFailHandler = func(message string, callerSkip ...int) { + failureMessage = message + if len(callerSkip) == 1 { + failureCallerSkip = callerSkip[0] + } + } + + BeforeEach(func() { + matcher = &fakematcher.FakeMatcher{} + failureMessage = "" + failureCallerSkip = 0 + a = New(input, fakeFailHandler, 1) + }) + + Context("when called", func() { + It("should pass the provided input value to the matcher", func() { + a.Should(matcher) + + Expect(matcher.ReceivedActual).Should(Equal(input)) + matcher.ReceivedActual = "" + + a.ShouldNot(matcher) + + Expect(matcher.ReceivedActual).Should(Equal(input)) + matcher.ReceivedActual = "" + + a.To(matcher) + + Expect(matcher.ReceivedActual).Should(Equal(input)) + matcher.ReceivedActual = "" + + a.ToNot(matcher) + + Expect(matcher.ReceivedActual).Should(Equal(input)) + matcher.ReceivedActual = "" + + a.NotTo(matcher) + + Expect(matcher.ReceivedActual).Should(Equal(input)) + }) + }) + + Context("when the matcher succeeds", func() { + BeforeEach(func() { + matcher.MatchesToReturn = true + matcher.ErrToReturn = nil + }) + + Context("and a positive assertion is being made", func() { + It("should not call the failure callback", func() { + a.Should(matcher) + Expect(failureMessage).Should(Equal("")) + }) + + It("should be true", func() { + Expect(a.Should(matcher)).Should(BeTrue()) + }) + }) + + Context("and a negative assertion is being made", func() { + It("should call the failure callback", func() { + a.ShouldNot(matcher) + Expect(failureMessage).Should(Equal("negative: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + + It("should be false", func() { + Expect(a.ShouldNot(matcher)).Should(BeFalse()) + }) + }) + }) + + Context("when the matcher fails", func() { + BeforeEach(func() { + matcher.MatchesToReturn = false + matcher.ErrToReturn = nil + }) + + Context("and a positive assertion is being made", func() { + It("should call the failure callback", func() { + a.Should(matcher) + Expect(failureMessage).Should(Equal("positive: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + + It("should be false", func() { + Expect(a.Should(matcher)).Should(BeFalse()) + }) + }) + + Context("and a negative assertion is being made", func() { + It("should not call the failure callback", func() { + a.ShouldNot(matcher) + Expect(failureMessage).Should(Equal("")) + }) + + It("should be true", func() { + Expect(a.ShouldNot(matcher)).Should(BeTrue()) + }) + }) + }) + + Context("When reporting a failure", func() { + BeforeEach(func() { + matcher.MatchesToReturn = false + matcher.ErrToReturn = nil + }) + + Context("and there is an optional description", func() { + It("should append the description to the failure message", func() { + a.Should(matcher, "A description") + Expect(failureMessage).Should(Equal("A description\npositive: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + }) + + Context("and there are multiple arguments to the optional description", func() { + It("should append the formatted description to the failure message", func() { + a.Should(matcher, "A description of [%d]", 3) + Expect(failureMessage).Should(Equal("A description of [3]\npositive: The thing I'm testing")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + }) + }) + + Context("When the matcher returns an error", func() { + BeforeEach(func() { + matcher.ErrToReturn = errors.New("Kaboom!") + }) + + Context("and a positive assertion is being made", func() { + It("should call the failure callback", func() { + matcher.MatchesToReturn = true + a.Should(matcher) + Expect(failureMessage).Should(Equal("Kaboom!")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + }) + + Context("and a negative assertion is being made", func() { + It("should call the failure callback", func() { + matcher.MatchesToReturn = false + a.ShouldNot(matcher) + Expect(failureMessage).Should(Equal("Kaboom!")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + }) + + It("should always be false", func() { + Expect(a.Should(matcher)).Should(BeFalse()) + Expect(a.ShouldNot(matcher)).Should(BeFalse()) + }) + }) + + Context("when there are extra parameters", func() { + It("(a simple example)", func() { + Expect(func() (string, int, error) { + return "foo", 0, nil + }()).Should(Equal("foo")) + }) + + Context("when the parameters are all nil or zero", func() { + It("should invoke the matcher", func() { + matcher.MatchesToReturn = true + matcher.ErrToReturn = nil + + var typedNil []string + a = New(input, fakeFailHandler, 1, 0, nil, typedNil) + + result := a.Should(matcher) + Expect(result).Should(BeTrue()) + Expect(matcher.ReceivedActual).Should(Equal(input)) + + Expect(failureMessage).Should(BeZero()) + }) + }) + + Context("when any of the parameters are not nil or zero", func() { + It("should call the failure callback", func() { + matcher.MatchesToReturn = false + matcher.ErrToReturn = nil + + a = New(input, fakeFailHandler, 1, errors.New("foo")) + result := a.Should(matcher) + Expect(result).Should(BeFalse()) + Expect(matcher.ReceivedActual).Should(BeZero(), "The matcher doesn't even get called") + Expect(failureMessage).Should(ContainSubstring("foo")) + failureMessage = "" + + a = New(input, fakeFailHandler, 1, nil, 1) + result = a.ShouldNot(matcher) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("1")) + failureMessage = "" + + a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) + result = a.To(matcher) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("foo")) + failureMessage = "" + + a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) + result = a.ToNot(matcher) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("foo")) + failureMessage = "" + + a = New(input, fakeFailHandler, 1, nil, 0, []string{"foo"}) + result = a.NotTo(matcher) + Expect(result).Should(BeFalse()) + Expect(failureMessage).Should(ContainSubstring("foo")) + Expect(failureCallerSkip).Should(Equal(3)) + }) + }) + }) + + Context("Making an assertion without a registered fail handler", func() { + It("should panic", func() { + defer func() { + e := recover() + RegisterFailHandler(Fail) + if e == nil { + Fail("expected a panic to have occurred") + } + }() + + RegisterFailHandler(nil) + Expect(true).Should(BeTrue()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go new file mode 100644 index 000000000..bdb0c3d22 --- /dev/null +++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_suite_test.go @@ -0,0 +1,13 @@ +package asyncassertion_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestAsyncAssertion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AsyncAssertion Suite") +} diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go new file mode 100644 index 000000000..13ffae7c5 --- /dev/null +++ b/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion_test.go @@ -0,0 +1,345 @@ +package asyncassertion_test + +import ( + "errors" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/internal/asyncassertion" +) + +var _ = Describe("Async Assertion", func() { + var ( + failureMessage string + callerSkip int + ) + + var fakeFailHandler = func(message string, skip ...int) { + failureMessage = message + callerSkip = skip[0] + } + + BeforeEach(func() { + failureMessage = "" + callerSkip = 0 + }) + + Describe("Eventually", func() { + Context("the positive case", func() { + It("should poll the function and matcher", func() { + counter := 0 + a := New(AsyncAssertionTypeEventually, func() int { + counter++ + return counter + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.Should(BeNumerically("==", 5)) + Expect(failureMessage).Should(BeZero()) + }) + + It("should continue when the matcher errors", func() { + counter := 0 + a := New(AsyncAssertionTypeEventually, func() interface{} { + counter++ + if counter == 5 { + return "not-a-number" //this should cause the matcher to error + } + return counter + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.Should(BeNumerically("==", 5), "My description %d", 2) + + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) + }) + + It("should be able to timeout", func() { + counter := 0 + a := New(AsyncAssertionTypeEventually, func() int { + counter++ + return counter + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.Should(BeNumerically(">", 100), "My description %d", 2) + + Expect(counter).Should(BeNumerically(">", 8)) + Expect(counter).Should(BeNumerically("<=", 10)) + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(MatchRegexp(`\: \d`), "Should pass the correct value to the matcher message formatter.") + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + + Context("the negative case", func() { + It("should poll the function and matcher", func() { + counter := 0 + a := New(AsyncAssertionTypeEventually, func() int { + counter += 1 + return counter + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.ShouldNot(BeNumerically("<", 3)) + + Expect(counter).Should(Equal(3)) + Expect(failureMessage).Should(BeZero()) + }) + + It("should timeout when the matcher errors", func() { + a := New(AsyncAssertionTypeEventually, func() interface{} { + return 0 //this should cause the matcher to error + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.ShouldNot(HaveLen(0), "My description %d", 2) + + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring("Error:")) + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) + }) + + It("should be able to timeout", func() { + a := New(AsyncAssertionTypeEventually, func() int { + return 0 + }, fakeFailHandler, time.Duration(0.1*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.ShouldNot(Equal(0), "My description %d", 2) + + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring(": 0"), "Should pass the correct value to the matcher message formatter.") + Expect(failureMessage).Should(ContainSubstring("My description 2")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + + Context("with a function that returns multiple values", func() { + It("should eventually succeed if the additional arguments are nil", func() { + i := 0 + Eventually(func() (int, error) { + i++ + return i, nil + }).Should(Equal(10)) + }) + + It("should eventually timeout if the additional arguments are not nil", func() { + i := 0 + a := New(AsyncAssertionTypeEventually, func() (int, error) { + i++ + return i, errors.New("bam") + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + a.Should(Equal(2)) + + Expect(failureMessage).Should(ContainSubstring("Timed out after")) + Expect(failureMessage).Should(ContainSubstring("Error:")) + Expect(failureMessage).Should(ContainSubstring("bam")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + + Context("Making an assertion without a registered fail handler", func() { + It("should panic", func() { + defer func() { + e := recover() + RegisterFailHandler(Fail) + if e == nil { + Fail("expected a panic to have occurred") + } + }() + + RegisterFailHandler(nil) + c := make(chan bool, 1) + c <- true + Eventually(c).Should(Receive()) + }) + }) + }) + + Describe("Consistently", func() { + Describe("The positive case", func() { + Context("when the matcher consistently passes for the duration", func() { + It("should pass", func() { + calls := 0 + a := New(AsyncAssertionTypeConsistently, func() string { + calls++ + return "foo" + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.Should(Equal("foo")) + Expect(calls).Should(BeNumerically(">", 8)) + Expect(calls).Should(BeNumerically("<=", 10)) + Expect(failureMessage).Should(BeZero()) + }) + }) + + Context("when the matcher fails at some point", func() { + It("should fail", func() { + calls := 0 + a := New(AsyncAssertionTypeConsistently, func() interface{} { + calls++ + if calls > 5 { + return "bar" + } + return "foo" + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.Should(Equal("foo")) + Expect(failureMessage).Should(ContainSubstring("to equal")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + + Context("when the matcher errors at some point", func() { + It("should fail", func() { + calls := 0 + a := New(AsyncAssertionTypeConsistently, func() interface{} { + calls++ + if calls > 5 { + return 3 + } + return []int{1, 2, 3} + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.Should(HaveLen(3)) + Expect(failureMessage).Should(ContainSubstring("HaveLen matcher expects")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + }) + + Describe("The negative case", func() { + Context("when the matcher consistently passes for the duration", func() { + It("should pass", func() { + c := make(chan bool) + a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.ShouldNot(Receive()) + Expect(failureMessage).Should(BeZero()) + }) + }) + + Context("when the matcher fails at some point", func() { + It("should fail", func() { + c := make(chan bool) + go func() { + time.Sleep(time.Duration(100 * time.Millisecond)) + c <- true + }() + + a := New(AsyncAssertionTypeConsistently, c, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.ShouldNot(Receive()) + Expect(failureMessage).Should(ContainSubstring("not to receive anything")) + }) + }) + + Context("when the matcher errors at some point", func() { + It("should fail", func() { + calls := 0 + a := New(AsyncAssertionTypeConsistently, func() interface{} { + calls++ + return calls + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + + a.ShouldNot(BeNumerically(">", 5)) + Expect(failureMessage).Should(ContainSubstring("not to be >")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + }) + + Context("with a function that returns multiple values", func() { + It("should consistently succeed if the additional arguments are nil", func() { + i := 2 + Consistently(func() (int, error) { + i++ + return i, nil + }).Should(BeNumerically(">=", 2)) + }) + + It("should eventually timeout if the additional arguments are not nil", func() { + i := 2 + a := New(AsyncAssertionTypeEventually, func() (int, error) { + i++ + return i, errors.New("bam") + }, fakeFailHandler, time.Duration(0.2*float64(time.Second)), time.Duration(0.02*float64(time.Second)), 1) + a.Should(BeNumerically(">=", 2)) + + Expect(failureMessage).Should(ContainSubstring("Error:")) + Expect(failureMessage).Should(ContainSubstring("bam")) + Expect(callerSkip).Should(Equal(4)) + }) + }) + + Context("Making an assertion without a registered fail handler", func() { + It("should panic", func() { + defer func() { + e := recover() + RegisterFailHandler(Fail) + if e == nil { + Fail("expected a panic to have occurred") + } + }() + + RegisterFailHandler(nil) + c := make(chan bool) + Consistently(c).ShouldNot(Receive()) + }) + }) + }) + + Context("when passed a function with the wrong # or arguments & returns", func() { + It("should panic", func() { + Expect(func() { + New(AsyncAssertionTypeEventually, func() {}, fakeFailHandler, 0, 0, 1) + }).Should(Panic()) + + Expect(func() { + New(AsyncAssertionTypeEventually, func(a string) int { return 0 }, fakeFailHandler, 0, 0, 1) + }).Should(Panic()) + + Expect(func() { + New(AsyncAssertionTypeEventually, func() int { return 0 }, fakeFailHandler, 0, 0, 1) + }).ShouldNot(Panic()) + + Expect(func() { + New(AsyncAssertionTypeEventually, func() (int, error) { return 0, nil }, fakeFailHandler, 0, 0, 1) + }).ShouldNot(Panic()) + }) + }) + + Describe("bailing early", func() { + Context("when actual is a value", func() { + It("Eventually should bail out and fail early if the matcher says to", func() { + c := make(chan bool) + close(c) + + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(c, 0.1).Should(Receive()) + }) + Expect(time.Since(t)).Should(BeNumerically("<", 90*time.Millisecond)) + + Expect(failures).Should(HaveLen(1)) + }) + }) + + Context("when actual is a function", func() { + It("should never bail early", func() { + c := make(chan bool) + close(c) + + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(func() chan bool { + return c + }, 0.1).Should(Receive()) + }) + Expect(time.Since(t)).Should(BeNumerically(">=", 90*time.Millisecond)) + + Expect(failures).Should(HaveLen(1)) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go new file mode 100644 index 000000000..9c6ccbdfd --- /dev/null +++ b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support_test.go @@ -0,0 +1,34 @@ +package testingtsupport_test + +import ( + . "github.com/onsi/gomega" + + "fmt" + "testing" +) + +type FakeT struct { + LastCall string +} + +func (f *FakeT) Fatalf(format string, args ...interface{}) { + f.LastCall = fmt.Sprintf(format, args...) +} + +func TestTestingT(t *testing.T) { + RegisterTestingT(t) + Expect(true).Should(BeTrue()) +} + +func TestGomegaWithT(t *testing.T) { + g := NewGomegaWithT(t) + + f := &FakeT{} + testG := NewGomegaWithT(f) + + testG.Expect("foo").To(Equal("foo")) + g.Expect(f.LastCall).To(BeZero()) + + testG.Expect("foo").To(Equal("bar")) + g.Expect(f.LastCall).To(ContainSubstring(": foo")) +} diff --git a/vendor/github.com/onsi/gomega/matchers/and_test.go b/vendor/github.com/onsi/gomega/matchers/and_test.go new file mode 100644 index 000000000..acf778cd6 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/and_test.go @@ -0,0 +1,103 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" + "github.com/onsi/gomega/types" +) + +// sample data +var ( + // example input + input = "hi" + // some matchers that succeed against the input + true1 = HaveLen(2) + true2 = Equal("hi") + true3 = MatchRegexp("hi") + // some matchers that fail against the input. + false1 = HaveLen(1) + false2 = Equal("hip") + false3 = MatchRegexp("hope") +) + +// verifyFailureMessage expects the matcher to fail with the given input, and verifies the failure message. +func verifyFailureMessage(m types.GomegaMatcher, input string, expectedFailureMsgFragment string) { + Expect(m.Match(input)).To(BeFalse()) + Expect(m.FailureMessage(input)).To(Equal( + "Expected\n : " + input + "\n" + expectedFailureMsgFragment)) +} + +var _ = Describe("AndMatcher", func() { + It("works with positive cases", func() { + Expect(input).To(And()) + Expect(input).To(And(true1)) + Expect(input).To(And(true1, true2)) + Expect(input).To(And(true1, true2, true3)) + + // use alias + Expect(input).To(SatisfyAll(true1, true2, true3)) + }) + + It("works with negative cases", func() { + Expect(input).ToNot(And(false1, false2)) + Expect(input).ToNot(And(true1, true2, false3)) + Expect(input).ToNot(And(true1, false2, false3)) + Expect(input).ToNot(And(false1, true1, true2)) + }) + + Context("failure messages", func() { + Context("when match fails", func() { + It("gives a descriptive message", func() { + verifyFailureMessage(And(false1, true1), input, "to have length 1") + verifyFailureMessage(And(true1, false2), input, "to equal\n : hip") + verifyFailureMessage(And(true1, true2, false3), input, "to match regular expression\n : hope") + }) + }) + + Context("when match succeeds, but expected it to fail", func() { + It("gives a descriptive message", func() { + verifyFailureMessage(Not(And(true1, true2)), input, + `To not satisfy all of these matchers: [%!s(*matchers.HaveLenMatcher=&{2}) %!s(*matchers.EqualMatcher=&{hi})]`) + }) + }) + }) + + Context("MatchMayChangeInTheFuture", func() { + Context("Match returned false", func() { + Context("returns value of the failed matcher", func() { + It("false if failed matcher not going to change", func() { + // 3 matchers: 1st returns true, 2nd returns false and is not going to change, 3rd is never called + m := And(Not(BeNil()), Or(), Equal(1)) + Expect(m.Match("hi")).To(BeFalse()) + Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // empty Or() indicates not going to change + }) + It("true if failed matcher indicates it might change", func() { + // 3 matchers: 1st returns true, 2nd returns false and "might" change, 3rd is never called + m := And(Not(BeNil()), Equal(5), Equal(1)) + Expect(m.Match("hi")).To(BeFalse()) + Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // Equal(5) indicates it might change + }) + }) + }) + Context("Match returned true", func() { + It("returns true if any of the matchers could change", func() { + // 3 matchers, all return true, and all could change + m := And(Not(BeNil()), Equal("hi"), HaveLen(2)) + Expect(m.Match("hi")).To(BeTrue()) + Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // all 3 of these matchers default to 'true' + }) + It("returns false if none of the matchers could change", func() { + // empty And() has the property of always matching, and never can change since there are no sub-matchers that could change + m := And() + Expect(m.Match("anything")).To(BeTrue()) + Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse()) + + // And() with 3 sub-matchers that return true, and can't change + m = And(And(), And(), And()) + Expect(m.Match("hi")).To(BeTrue()) + Expect(m.(*AndMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // the 3 empty And()'s won't change + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go new file mode 100644 index 000000000..471a46d97 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/assignable_to_type_of_matcher_test.go @@ -0,0 +1,46 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("AssignableToTypeOf", func() { + Context("When asserting assignability between types", func() { + It("should do the right thing", func() { + Expect(0).Should(BeAssignableToTypeOf(0)) + Expect(5).Should(BeAssignableToTypeOf(-1)) + Expect("foo").Should(BeAssignableToTypeOf("bar")) + Expect(struct{ Foo string }{}).Should(BeAssignableToTypeOf(struct{ Foo string }{})) + + Expect(0).ShouldNot(BeAssignableToTypeOf("bar")) + Expect(5).ShouldNot(BeAssignableToTypeOf(struct{ Foo string }{})) + Expect("foo").ShouldNot(BeAssignableToTypeOf(42)) + }) + }) + + Context("When asserting nil values", func() { + It("should error", func() { + success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + + Context("When actual is nil and expected is not nil", func() { + It("should return false without error", func() { + success, err := (&AssignableToTypeOfMatcher{Expected: 17}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + + Context("When actual is not nil and expected is nil", func() { + It("should error", func() { + success, err := (&AssignableToTypeOfMatcher{Expected: nil}).Match(17) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go b/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go new file mode 100644 index 000000000..bc8742763 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_a_directory_test.go @@ -0,0 +1,40 @@ +package matchers_test + +import ( + "io/ioutil" + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeADirectoryMatcher", func() { + Context("when passed a string", func() { + It("should do the right thing", func() { + Expect("/dne/test").ShouldNot(BeADirectory()) + + tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") + Expect(err).ShouldNot(HaveOccurred()) + defer os.Remove(tmpFile.Name()) + Expect(tmpFile.Name()).ShouldNot(BeADirectory()) + + tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") + Expect(err).ShouldNot(HaveOccurred()) + defer os.Remove(tmpDir) + Expect(tmpDir).Should(BeADirectory()) + }) + }) + + Context("when passed something else", func() { + It("should error", func() { + success, err := (&BeADirectoryMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeADirectoryMatcher{}).Match(true) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go new file mode 100644 index 000000000..eae06a03e --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_a_regular_file_test.go @@ -0,0 +1,40 @@ +package matchers_test + +import ( + "io/ioutil" + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeARegularFileMatcher", func() { + Context("when passed a string", func() { + It("should do the right thing", func() { + Expect("/dne/test").ShouldNot(BeARegularFile()) + + tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") + Expect(err).ShouldNot(HaveOccurred()) + defer os.Remove(tmpFile.Name()) + Expect(tmpFile.Name()).Should(BeARegularFile()) + + tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") + Expect(err).ShouldNot(HaveOccurred()) + defer os.Remove(tmpDir) + Expect(tmpDir).ShouldNot(BeARegularFile()) + }) + }) + + Context("when passed something else", func() { + It("should error", func() { + success, err := (&BeARegularFileMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeARegularFileMatcher{}).Match(true) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go new file mode 100644 index 000000000..e28bd0d65 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_an_existing_file_test.go @@ -0,0 +1,40 @@ +package matchers_test + +import ( + "io/ioutil" + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeAnExistingFileMatcher", func() { + Context("when passed a string", func() { + It("should do the right thing", func() { + Expect("/dne/test").ShouldNot(BeAnExistingFile()) + + tmpFile, err := ioutil.TempFile("", "gomega-test-tempfile") + Expect(err).ShouldNot(HaveOccurred()) + defer os.Remove(tmpFile.Name()) + Expect(tmpFile.Name()).Should(BeAnExistingFile()) + + tmpDir, err := ioutil.TempDir("", "gomega-test-tempdir") + Expect(err).ShouldNot(HaveOccurred()) + defer os.Remove(tmpDir) + Expect(tmpDir).Should(BeAnExistingFile()) + }) + }) + + Context("when passed something else", func() { + It("should error", func() { + success, err := (&BeAnExistingFileMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeAnExistingFileMatcher{}).Match(true) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go new file mode 100644 index 000000000..c2e49ab50 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_closed_matcher_test.go @@ -0,0 +1,70 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeClosedMatcher", func() { + Context("when passed a channel", func() { + It("should do the right thing", func() { + openChannel := make(chan bool) + Expect(openChannel).ShouldNot(BeClosed()) + + var openReaderChannel <-chan bool + openReaderChannel = openChannel + Expect(openReaderChannel).ShouldNot(BeClosed()) + + closedChannel := make(chan bool) + close(closedChannel) + + Expect(closedChannel).Should(BeClosed()) + + var closedReaderChannel <-chan bool + closedReaderChannel = closedChannel + Expect(closedReaderChannel).Should(BeClosed()) + }) + }) + + Context("when passed a send-only channel", func() { + It("should error", func() { + openChannel := make(chan bool) + var openWriterChannel chan<- bool + openWriterChannel = openChannel + + success, err := (&BeClosedMatcher{}).Match(openWriterChannel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + closedChannel := make(chan bool) + close(closedChannel) + + var closedWriterChannel chan<- bool + closedWriterChannel = closedChannel + + success, err = (&BeClosedMatcher{}).Match(closedWriterChannel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + }) + }) + + Context("when passed something else", func() { + It("should error", func() { + var nilChannel chan bool + + success, err := (&BeClosedMatcher{}).Match(nilChannel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeClosedMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeClosedMatcher{}).Match(7) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go new file mode 100644 index 000000000..132480cfc --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_empty_matcher_test.go @@ -0,0 +1,52 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeEmpty", func() { + Context("when passed a supported type", func() { + It("should do the right thing", func() { + Expect("").Should(BeEmpty()) + Expect(" ").ShouldNot(BeEmpty()) + + Expect([0]int{}).Should(BeEmpty()) + Expect([1]int{1}).ShouldNot(BeEmpty()) + + Expect([]int{}).Should(BeEmpty()) + Expect([]int{1}).ShouldNot(BeEmpty()) + + Expect(map[string]int{}).Should(BeEmpty()) + Expect(map[string]int{"a": 1}).ShouldNot(BeEmpty()) + + c := make(chan bool, 1) + Expect(c).Should(BeEmpty()) + c <- true + Expect(c).ShouldNot(BeEmpty()) + }) + }) + + Context("when passed a correctly typed nil", func() { + It("should be true", func() { + var nilSlice []int + Expect(nilSlice).Should(BeEmpty()) + + var nilMap map[int]string + Expect(nilMap).Should(BeEmpty()) + }) + }) + + Context("when passed an unsupported type", func() { + It("should error", func() { + success, err := (&BeEmptyMatcher{}).Match(0) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeEmptyMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go new file mode 100644 index 000000000..4d9d11d2d --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_equivalent_to_matcher_test.go @@ -0,0 +1,50 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeEquivalentTo", func() { + Context("when asserting that nil is equivalent to nil", func() { + It("should error", func() { + success, err := (&BeEquivalentToMatcher{Expected: nil}).Match(nil) + + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("When asserting on nil", func() { + It("should do the right thing", func() { + Expect("foo").ShouldNot(BeEquivalentTo(nil)) + Expect(nil).ShouldNot(BeEquivalentTo(3)) + Expect([]int{1, 2}).ShouldNot(BeEquivalentTo(nil)) + }) + }) + + Context("When asserting on type aliases", func() { + It("should the right thing", func() { + Expect(StringAlias("foo")).Should(BeEquivalentTo("foo")) + Expect("foo").Should(BeEquivalentTo(StringAlias("foo"))) + Expect(StringAlias("foo")).ShouldNot(BeEquivalentTo("bar")) + Expect("foo").ShouldNot(BeEquivalentTo(StringAlias("bar"))) + }) + }) + + Context("When asserting on numbers", func() { + It("should convert actual to expected and do the right thing", func() { + Expect(5).Should(BeEquivalentTo(5)) + Expect(5.0).Should(BeEquivalentTo(5.0)) + Expect(5).Should(BeEquivalentTo(5.0)) + + Expect(5).ShouldNot(BeEquivalentTo("5")) + Expect(5).ShouldNot(BeEquivalentTo(3)) + + //Here be dragons! + Expect(5.1).Should(BeEquivalentTo(5)) + Expect(5).ShouldNot(BeEquivalentTo(5.1)) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go new file mode 100644 index 000000000..25e70633d --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_false_matcher_test.go @@ -0,0 +1,20 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeFalse", func() { + It("should handle true and false correctly", func() { + Expect(true).ShouldNot(BeFalse()) + Expect(false).Should(BeFalse()) + }) + + It("should only support booleans", func() { + success, err := (&BeFalseMatcher{}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go b/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go new file mode 100644 index 000000000..7fdd56eed --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_identical_to_test.go @@ -0,0 +1,61 @@ +package matchers_test + +import ( + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeIdenticalTo", func() { + Context("when asserting that nil equals nil", func() { + It("should error", func() { + success, err := (&BeIdenticalToMatcher{Expected: nil}).Match(nil) + + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + It("should treat the same pointer to a struct as identical", func() { + mySpecialStruct := myCustomType{} + Expect(&mySpecialStruct).Should(BeIdenticalTo(&mySpecialStruct)) + Expect(&myCustomType{}).ShouldNot(BeIdenticalTo(&mySpecialStruct)) + }) + + It("should be strict about types", func() { + Expect(5).ShouldNot(BeIdenticalTo("5")) + Expect(5).ShouldNot(BeIdenticalTo(5.0)) + Expect(5).ShouldNot(BeIdenticalTo(3)) + }) + + It("should treat primtives as identical", func() { + Expect("5").Should(BeIdenticalTo("5")) + Expect("5").ShouldNot(BeIdenticalTo("55")) + + Expect(5.55).Should(BeIdenticalTo(5.55)) + Expect(5.55).ShouldNot(BeIdenticalTo(6.66)) + + Expect(5).Should(BeIdenticalTo(5)) + Expect(5).ShouldNot(BeIdenticalTo(55)) + }) + + It("should treat the same pointers to a slice as identical", func() { + mySlice := []int{1, 2} + Expect(&mySlice).Should(BeIdenticalTo(&mySlice)) + Expect(&mySlice).ShouldNot(BeIdenticalTo(&[]int{1, 2})) + }) + + It("should treat the same pointers to a map as identical", func() { + myMap := map[string]string{"a": "b", "c": "d"} + Expect(&myMap).Should(BeIdenticalTo(&myMap)) + Expect(myMap).ShouldNot(BeIdenticalTo(map[string]string{"a": "b", "c": "d"})) + }) + + It("should treat the same pointers to an error as identical", func() { + myError := errors.New("foo") + Expect(&myError).Should(BeIdenticalTo(&myError)) + Expect(errors.New("foo")).ShouldNot(BeIdenticalTo(errors.New("bar"))) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go new file mode 100644 index 000000000..c35aa3d7c --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_nil_matcher_test.go @@ -0,0 +1,28 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("BeNil", func() { + It("should succeed when passed nil", func() { + Expect(nil).Should(BeNil()) + }) + + It("should succeed when passed a typed nil", func() { + var a []int + Expect(a).Should(BeNil()) + }) + + It("should succeed when passing nil pointer", func() { + var f *struct{} + Expect(f).Should(BeNil()) + }) + + It("should not succeed when not passed nil", func() { + Expect(0).ShouldNot(BeNil()) + Expect(false).ShouldNot(BeNil()) + Expect("").ShouldNot(BeNil()) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go new file mode 100644 index 000000000..bd385b7f5 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher_test.go @@ -0,0 +1,148 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeNumerically", func() { + Context("when passed a number", func() { + It("should support ==", func() { + Expect(uint32(5)).Should(BeNumerically("==", 5)) + Expect(float64(5.0)).Should(BeNumerically("==", 5)) + Expect(int8(5)).Should(BeNumerically("==", 5)) + }) + + It("should not have false positives", func() { + Expect(5.1).ShouldNot(BeNumerically("==", 5)) + Expect(5).ShouldNot(BeNumerically("==", 5.1)) + }) + + It("should support >", func() { + Expect(uint32(5)).Should(BeNumerically(">", 4)) + Expect(float64(5.0)).Should(BeNumerically(">", 4.9)) + Expect(int8(5)).Should(BeNumerically(">", 4)) + + Expect(uint32(5)).ShouldNot(BeNumerically(">", 5)) + Expect(float64(5.0)).ShouldNot(BeNumerically(">", 5.0)) + Expect(int8(5)).ShouldNot(BeNumerically(">", 5)) + }) + + It("should support <", func() { + Expect(uint32(5)).Should(BeNumerically("<", 6)) + Expect(float64(5.0)).Should(BeNumerically("<", 5.1)) + Expect(int8(5)).Should(BeNumerically("<", 6)) + + Expect(uint32(5)).ShouldNot(BeNumerically("<", 5)) + Expect(float64(5.0)).ShouldNot(BeNumerically("<", 5.0)) + Expect(int8(5)).ShouldNot(BeNumerically("<", 5)) + }) + + It("should support >=", func() { + Expect(uint32(5)).Should(BeNumerically(">=", 4)) + Expect(float64(5.0)).Should(BeNumerically(">=", 4.9)) + Expect(int8(5)).Should(BeNumerically(">=", 4)) + + Expect(uint32(5)).Should(BeNumerically(">=", 5)) + Expect(float64(5.0)).Should(BeNumerically(">=", 5.0)) + Expect(int8(5)).Should(BeNumerically(">=", 5)) + + Expect(uint32(5)).ShouldNot(BeNumerically(">=", 6)) + Expect(float64(5.0)).ShouldNot(BeNumerically(">=", 5.1)) + Expect(int8(5)).ShouldNot(BeNumerically(">=", 6)) + }) + + It("should support <=", func() { + Expect(uint32(5)).Should(BeNumerically("<=", 6)) + Expect(float64(5.0)).Should(BeNumerically("<=", 5.1)) + Expect(int8(5)).Should(BeNumerically("<=", 6)) + + Expect(uint32(5)).Should(BeNumerically("<=", 5)) + Expect(float64(5.0)).Should(BeNumerically("<=", 5.0)) + Expect(int8(5)).Should(BeNumerically("<=", 5)) + + Expect(uint32(5)).ShouldNot(BeNumerically("<=", 4)) + Expect(float64(5.0)).ShouldNot(BeNumerically("<=", 4.9)) + Expect(int8(5)).Should(BeNumerically("<=", 5)) + }) + + Context("when passed ~", func() { + Context("when passed a float", func() { + Context("and there is no precision parameter", func() { + It("should default to 1e-8", func() { + Expect(5.00000001).Should(BeNumerically("~", 5.00000002)) + Expect(5.00000001).ShouldNot(BeNumerically("~", 5.0000001)) + }) + }) + + Context("and there is a precision parameter", func() { + It("should use the precision parameter", func() { + Expect(5.1).Should(BeNumerically("~", 5.19, 0.1)) + Expect(5.1).Should(BeNumerically("~", 5.01, 0.1)) + Expect(5.1).ShouldNot(BeNumerically("~", 5.22, 0.1)) + Expect(5.1).ShouldNot(BeNumerically("~", 4.98, 0.1)) + }) + }) + }) + + Context("when passed an int/uint", func() { + Context("and there is no precision parameter", func() { + It("should just do strict equality", func() { + Expect(5).Should(BeNumerically("~", 5)) + Expect(5).ShouldNot(BeNumerically("~", 6)) + Expect(uint(5)).ShouldNot(BeNumerically("~", 6)) + }) + }) + + Context("and there is a precision parameter", func() { + It("should use precision paramter", func() { + Expect(5).Should(BeNumerically("~", 6, 2)) + Expect(5).ShouldNot(BeNumerically("~", 8, 2)) + Expect(uint(5)).Should(BeNumerically("~", 6, 1)) + }) + }) + }) + }) + }) + + Context("when passed a non-number", func() { + It("should error", func() { + success, err := (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{5}}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeNumericallyMatcher{Comparator: "=="}).Match(5) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeNumericallyMatcher{Comparator: "~", CompareTo: []interface{}{3.0, "foo"}}).Match(5.0) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match(5) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{"bar"}}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{nil}}).Match(0) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeNumericallyMatcher{Comparator: "==", CompareTo: []interface{}{0}}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed an unsupported comparator", func() { + It("should error", func() { + success, err := (&BeNumericallyMatcher{Comparator: "!=", CompareTo: []interface{}{5}}).Match(4) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go new file mode 100644 index 000000000..68ec72879 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_sent_matcher_test.go @@ -0,0 +1,107 @@ +package matchers_test + +import ( + "time" + + . "github.com/onsi/gomega/matchers" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("BeSent", func() { + Context("when passed a channel and a matching type", func() { + Context("when the channel is ready to receive", func() { + It("should succeed and send the value down the channel", func() { + c := make(chan string) + d := make(chan string) + go func() { + val := <-c + d <- val + }() + + time.Sleep(10 * time.Millisecond) + + Expect(c).Should(BeSent("foo")) + Eventually(d).Should(Receive(Equal("foo"))) + }) + + It("should succeed (with a buffered channel)", func() { + c := make(chan string, 1) + Expect(c).Should(BeSent("foo")) + Expect(<-c).Should(Equal("foo")) + }) + }) + + Context("when the channel is not ready to receive", func() { + It("should fail and not send down the channel", func() { + c := make(chan string) + Expect(c).ShouldNot(BeSent("foo")) + Consistently(c).ShouldNot(Receive()) + }) + }) + + Context("when the channel is eventually ready to receive", func() { + It("should succeed", func() { + c := make(chan string) + d := make(chan string) + go func() { + time.Sleep(30 * time.Millisecond) + val := <-c + d <- val + }() + + Eventually(c).Should(BeSent("foo")) + Eventually(d).Should(Receive(Equal("foo"))) + }) + }) + + Context("when the channel is closed", func() { + It("should error", func() { + c := make(chan string) + close(c) + success, err := (&BeSentMatcher{Arg: "foo"}).Match(c) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + + It("should short-circuit Eventually", func() { + c := make(chan string) + close(c) + + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(c, 10.0).Should(BeSent("foo")) + }) + Expect(failures).Should(HaveLen(1)) + Expect(time.Since(t)).Should(BeNumerically("<", time.Second)) + }) + }) + }) + + Context("when passed a channel and a non-matching type", func() { + It("should error", func() { + success, err := (&BeSentMatcher{Arg: "foo"}).Match(make(chan int, 1)) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed a receive-only channel", func() { + It("should error", func() { + var c <-chan string + c = make(chan string, 1) + success, err := (&BeSentMatcher{Arg: "foo"}).Match(c) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed a nonchannel", func() { + It("should error", func() { + success, err := (&BeSentMatcher{Arg: "foo"}).Match("bar") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go new file mode 100644 index 000000000..95a3a103e --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_temporally_matcher_test.go @@ -0,0 +1,99 @@ +package matchers_test + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeTemporally", func() { + + var t0, t1, t2 time.Time + BeforeEach(func() { + t0 = time.Now() + t1 = t0.Add(time.Second) + t2 = t0.Add(-time.Second) + }) + + Context("When comparing times", func() { + + It("should support ==", func() { + Expect(t0).Should(BeTemporally("==", t0)) + Expect(t1).ShouldNot(BeTemporally("==", t0)) + Expect(t0).ShouldNot(BeTemporally("==", t1)) + Expect(t0).ShouldNot(BeTemporally("==", time.Time{})) + }) + + It("should support >", func() { + Expect(t0).Should(BeTemporally(">", t2)) + Expect(t0).ShouldNot(BeTemporally(">", t0)) + Expect(t2).ShouldNot(BeTemporally(">", t0)) + }) + + It("should support <", func() { + Expect(t0).Should(BeTemporally("<", t1)) + Expect(t0).ShouldNot(BeTemporally("<", t0)) + Expect(t1).ShouldNot(BeTemporally("<", t0)) + }) + + It("should support >=", func() { + Expect(t0).Should(BeTemporally(">=", t2)) + Expect(t0).Should(BeTemporally(">=", t0)) + Expect(t0).ShouldNot(BeTemporally(">=", t1)) + }) + + It("should support <=", func() { + Expect(t0).Should(BeTemporally("<=", t1)) + Expect(t0).Should(BeTemporally("<=", t0)) + Expect(t0).ShouldNot(BeTemporally("<=", t2)) + }) + + Context("when passed ~", func() { + Context("and there is no precision parameter", func() { + BeforeEach(func() { + t1 = t0.Add(time.Millisecond / 2) + t2 = t0.Add(-2 * time.Millisecond) + }) + It("should approximate", func() { + Expect(t0).Should(BeTemporally("~", t0)) + Expect(t0).Should(BeTemporally("~", t1)) + Expect(t0).ShouldNot(BeTemporally("~", t2)) + }) + }) + + Context("and there is a precision parameter", func() { + BeforeEach(func() { + t2 = t0.Add(3 * time.Second) + }) + It("should use precision paramter", func() { + d := 2 * time.Second + Expect(t0).Should(BeTemporally("~", t0, d)) + Expect(t0).Should(BeTemporally("~", t1, d)) + Expect(t0).ShouldNot(BeTemporally("~", t2, d)) + }) + }) + }) + }) + + Context("when passed a non-time", func() { + It("should error", func() { + success, err := (&BeTemporallyMatcher{Comparator: "==", CompareTo: t0}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&BeTemporallyMatcher{Comparator: "=="}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed an unsupported comparator", func() { + It("should error", func() { + success, err := (&BeTemporallyMatcher{Comparator: "!=", CompareTo: t0}).Match(t2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go new file mode 100644 index 000000000..9eda62c33 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_true_matcher_test.go @@ -0,0 +1,20 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("BeTrue", func() { + It("should handle true and false correctly", func() { + Expect(true).Should(BeTrue()) + Expect(false).ShouldNot(BeTrue()) + }) + + It("should only support booleans", func() { + success, err := (&BeTrueMatcher{}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go new file mode 100644 index 000000000..015d87d1c --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/be_zero_matcher_test.go @@ -0,0 +1,30 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("BeZero", func() { + It("should succeed if the passed in object is the zero value for its type", func() { + Expect(nil).Should(BeZero()) + + Expect("").Should(BeZero()) + Expect(" ").ShouldNot(BeZero()) + + Expect(0).Should(BeZero()) + Expect(1).ShouldNot(BeZero()) + + Expect(0.0).Should(BeZero()) + Expect(0.1).ShouldNot(BeZero()) + + // Expect([]int{}).Should(BeZero()) + Expect([]int{1}).ShouldNot(BeZero()) + + // Expect(map[string]int{}).Should(BeZero()) + Expect(map[string]int{"a": 1}).ShouldNot(BeZero()) + + Expect(myCustomType{}).Should(BeZero()) + Expect(myCustomType{s: "a"}).ShouldNot(BeZero()) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of_test.go b/vendor/github.com/onsi/gomega/matchers/consist_of_test.go new file mode 100644 index 000000000..081830f5c --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/consist_of_test.go @@ -0,0 +1,75 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ConsistOf", func() { + Context("with a slice", func() { + It("should do the right thing", func() { + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) + }) + }) + + Context("with an array", func() { + It("should do the right thing", func() { + Expect([3]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect([3]string{"foo", "bar", "baz"}).Should(ConsistOf("baz", "bar", "foo")) + Expect([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) + Expect([3]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("baz", "foo")) + }) + }) + + Context("with a map", func() { + It("should apply to the values", func() { + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("foo", "bar", "baz")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Should(ConsistOf("baz", "bar", "foo")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "bar", "foo", "foo")) + Expect(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ShouldNot(ConsistOf("baz", "foo")) + }) + + }) + + Context("with anything else", func() { + It("should error", func() { + failures := InterceptGomegaFailures(func() { + Expect("foo").Should(ConsistOf("f", "o", "o")) + }) + + Expect(failures).Should(HaveLen(1)) + }) + }) + + Context("when passed matchers", func() { + It("should pass if the matchers pass", func() { + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), "baz")) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"))) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("foo"))) + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("^ba"))) + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf("foo", MatchRegexp("^ba"), MatchRegexp("turducken"))) + }) + + It("should not depend on the order of the matchers", func() { + Expect([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(1), ContainElement(2))) + Expect([][]int{[]int{1, 2}, []int{2}}).Should(ConsistOf(ContainElement(2), ContainElement(1))) + }) + + Context("when a matcher errors", func() { + It("should soldier on", func() { + Expect([]string{"foo", "bar", "baz"}).ShouldNot(ConsistOf(BeFalse(), "foo", "bar")) + Expect([]interface{}{"foo", "bar", false}).Should(ConsistOf(BeFalse(), ContainSubstring("foo"), "bar")) + }) + }) + }) + + Context("when passed exactly one argument, and that argument is a slice", func() { + It("should match against the elements of that argument", func() { + Expect([]string{"foo", "bar", "baz"}).Should(ConsistOf([]string{"foo", "bar", "baz"})) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go new file mode 100644 index 000000000..60fb55e96 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/contain_element_matcher_test.go @@ -0,0 +1,76 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("ContainElement", func() { + Context("when passed a supported type", func() { + Context("and expecting a non-matcher", func() { + It("should do the right thing", func() { + Expect([2]int{1, 2}).Should(ContainElement(2)) + Expect([2]int{1, 2}).ShouldNot(ContainElement(3)) + + Expect([]int{1, 2}).Should(ContainElement(2)) + Expect([]int{1, 2}).ShouldNot(ContainElement(3)) + + Expect(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(2)) + Expect(map[int]int{3: 1, 4: 2}).ShouldNot(ContainElement(3)) + + arr := make([]myCustomType, 2) + arr[0] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}} + arr[1] = myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "c"}} + Expect(arr).Should(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) + Expect(arr).ShouldNot(ContainElement(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"b", "c"}})) + }) + }) + + Context("and expecting a matcher", func() { + It("should pass each element through the matcher", func() { + Expect([]int{1, 2, 3}).Should(ContainElement(BeNumerically(">=", 3))) + Expect([]int{1, 2, 3}).ShouldNot(ContainElement(BeNumerically(">", 3))) + Expect(map[string]int{"foo": 1, "bar": 2}).Should(ContainElement(BeNumerically(">=", 2))) + Expect(map[string]int{"foo": 1, "bar": 2}).ShouldNot(ContainElement(BeNumerically(">", 2))) + }) + + It("should power through even if the matcher ever fails", func() { + Expect([]interface{}{1, 2, "3", 4}).Should(ContainElement(BeNumerically(">=", 3))) + }) + + It("should fail if the matcher fails", func() { + actual := []interface{}{1, 2, "3", "4"} + success, err := (&ContainElementMatcher{Element: BeNumerically(">=", 3)}).Match(actual) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + }) + + Context("when passed a correctly typed nil", func() { + It("should operate succesfully on the passed in value", func() { + var nilSlice []int + Expect(nilSlice).ShouldNot(ContainElement(1)) + + var nilMap map[int]string + Expect(nilMap).ShouldNot(ContainElement("foo")) + }) + }) + + Context("when passed an unsupported type", func() { + It("should error", func() { + success, err := (&ContainElementMatcher{Element: 0}).Match(0) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&ContainElementMatcher{Element: 0}).Match("abc") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&ContainElementMatcher{Element: 0}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go new file mode 100644 index 000000000..efffb4732 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/contain_substring_matcher_test.go @@ -0,0 +1,36 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("ContainSubstringMatcher", func() { + Context("when actual is a string", func() { + It("should match against the string", func() { + Expect("Marvelous").Should(ContainSubstring("rve")) + Expect("Marvelous").ShouldNot(ContainSubstring("boo")) + }) + }) + + Context("when the matcher is called with multiple arguments", func() { + It("should pass the string and arguments to sprintf", func() { + Expect("Marvelous3").Should(ContainSubstring("velous%d", 3)) + }) + }) + + Context("when actual is a stringer", func() { + It("should call the stringer and match agains the returned string", func() { + Expect(&myStringer{a: "Abc3"}).Should(ContainSubstring("bc3")) + }) + }) + + Context("when actual is neither a string nor a stringer", func() { + It("should error", func() { + success, err := (&ContainSubstringMatcher{Substr: "2"}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go new file mode 100644 index 000000000..3ab991e4f --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/equal_matcher_test.go @@ -0,0 +1,80 @@ +package matchers_test + +import ( + "errors" + "strings" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("Equal", func() { + Context("when asserting that nil equals nil", func() { + It("should error", func() { + success, err := (&EqualMatcher{Expected: nil}).Match(nil) + + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("When asserting equality between objects", func() { + It("should do the right thing", func() { + Expect(5).Should(Equal(5)) + Expect(5.0).Should(Equal(5.0)) + + Expect(5).ShouldNot(Equal("5")) + Expect(5).ShouldNot(Equal(5.0)) + Expect(5).ShouldNot(Equal(3)) + + Expect("5").Should(Equal("5")) + Expect([]int{1, 2}).Should(Equal([]int{1, 2})) + Expect([]int{1, 2}).ShouldNot(Equal([]int{2, 1})) + Expect([]byte{'f', 'o', 'o'}).Should(Equal([]byte{'f', 'o', 'o'})) + Expect([]byte{'f', 'o', 'o'}).ShouldNot(Equal([]byte{'b', 'a', 'r'})) + Expect(map[string]string{"a": "b", "c": "d"}).Should(Equal(map[string]string{"a": "b", "c": "d"})) + Expect(map[string]string{"a": "b", "c": "d"}).ShouldNot(Equal(map[string]string{"a": "b", "c": "e"})) + Expect(errors.New("foo")).Should(Equal(errors.New("foo"))) + Expect(errors.New("foo")).ShouldNot(Equal(errors.New("bar"))) + + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).Should(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "bar", n: 3, f: 2.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 2, f: 2.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 3.0, arr: []string{"a", "b"}})) + Expect(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b"}}).ShouldNot(Equal(myCustomType{s: "foo", n: 3, f: 2.0, arr: []string{"a", "b", "c"}})) + }) + }) + + Describe("failure messages", func() { + It("shows the two strings simply when they are short", func() { + subject := EqualMatcher{Expected: "eric"} + + failureMessage := subject.FailureMessage("tim") + Expect(failureMessage).To(BeEquivalentTo(expectedShortStringFailureMessage)) + }) + + It("shows the exact point where two long strings differ", func() { + stringWithB := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + stringWithZ := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + subject := EqualMatcher{Expected: stringWithZ} + + failureMessage := subject.FailureMessage(stringWithB) + Expect(failureMessage).To(BeEquivalentTo(expectedLongStringFailureMessage)) + }) + }) +}) + +var expectedShortStringFailureMessage = strings.TrimSpace(` +Expected + : tim +to equal + : eric +`) +var expectedLongStringFailureMessage = strings.TrimSpace(` +Expected + : "...aaaaabaaaaa..." +to equal | + : "...aaaaazaaaaa..." +`) diff --git a/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go new file mode 100644 index 000000000..8a61f2e2c --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_cap_matcher_test.go @@ -0,0 +1,50 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("HaveCap", func() { + Context("when passed a supported type", func() { + It("should do the right thing", func() { + Expect([0]int{}).Should(HaveCap(0)) + Expect([2]int{1}).Should(HaveCap(2)) + + Expect([]int{}).Should(HaveCap(0)) + Expect([]int{1, 2, 3, 4, 5}[:2]).Should(HaveCap(5)) + Expect(make([]int, 0, 5)).Should(HaveCap(5)) + + c := make(chan bool, 3) + Expect(c).Should(HaveCap(3)) + c <- true + c <- true + Expect(c).Should(HaveCap(3)) + + Expect(make(chan bool)).Should(HaveCap(0)) + }) + }) + + Context("when passed a correctly typed nil", func() { + It("should operate succesfully on the passed in value", func() { + var nilSlice []int + Expect(nilSlice).Should(HaveCap(0)) + + var nilChan chan int + Expect(nilChan).Should(HaveCap(0)) + }) + }) + + Context("when passed an unsupported type", func() { + It("should error", func() { + success, err := (&HaveCapMatcher{Count: 0}).Match(0) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&HaveCapMatcher{Count: 0}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go new file mode 100644 index 000000000..0f1561b7d --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_key_matcher_test.go @@ -0,0 +1,73 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("HaveKey", func() { + var ( + stringKeys map[string]int + intKeys map[int]string + objKeys map[*myCustomType]string + + customA *myCustomType + customB *myCustomType + ) + BeforeEach(func() { + stringKeys = map[string]int{"foo": 2, "bar": 3} + intKeys = map[int]string{2: "foo", 3: "bar"} + + customA = &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}} + customB = &myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}} + objKeys = map[*myCustomType]string{customA: "aardvark", customB: "kangaroo"} + }) + + Context("when passed a map", func() { + It("should do the right thing", func() { + Expect(stringKeys).Should(HaveKey("foo")) + Expect(stringKeys).ShouldNot(HaveKey("baz")) + + Expect(intKeys).Should(HaveKey(2)) + Expect(intKeys).ShouldNot(HaveKey(4)) + + Expect(objKeys).Should(HaveKey(customA)) + Expect(objKeys).Should(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}})) + Expect(objKeys).ShouldNot(HaveKey(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}})) + }) + }) + + Context("when passed a correctly typed nil", func() { + It("should operate succesfully on the passed in value", func() { + var nilMap map[int]string + Expect(nilMap).ShouldNot(HaveKey("foo")) + }) + }) + + Context("when the passed in key is actually a matcher", func() { + It("should pass each element through the matcher", func() { + Expect(stringKeys).Should(HaveKey(ContainSubstring("oo"))) + Expect(stringKeys).ShouldNot(HaveKey(ContainSubstring("foobar"))) + }) + + It("should fail if the matcher ever fails", func() { + actual := map[int]string{1: "a", 3: "b", 2: "c"} + success, err := (&HaveKeyMatcher{Key: ContainSubstring("ar")}).Match(actual) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed something that is not a map", func() { + It("should error", func() { + success, err := (&HaveKeyMatcher{Key: "foo"}).Match([]string{"foo"}) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&HaveKeyMatcher{Key: "foo"}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go new file mode 100644 index 000000000..0a49ec993 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_key_with_value_matcher_test.go @@ -0,0 +1,82 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("HaveKeyWithValue", func() { + var ( + stringKeys map[string]int + intKeys map[int]string + objKeys map[*myCustomType]*myCustomType + + customA *myCustomType + customB *myCustomType + ) + BeforeEach(func() { + stringKeys = map[string]int{"foo": 2, "bar": 3} + intKeys = map[int]string{2: "foo", 3: "bar"} + + customA = &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}} + customB = &myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}} + objKeys = map[*myCustomType]*myCustomType{customA: customA, customB: customA} + }) + + Context("when passed a map", func() { + It("should do the right thing", func() { + Expect(stringKeys).Should(HaveKeyWithValue("foo", 2)) + Expect(stringKeys).ShouldNot(HaveKeyWithValue("foo", 1)) + Expect(stringKeys).ShouldNot(HaveKeyWithValue("baz", 2)) + Expect(stringKeys).ShouldNot(HaveKeyWithValue("baz", 1)) + + Expect(intKeys).Should(HaveKeyWithValue(2, "foo")) + Expect(intKeys).ShouldNot(HaveKeyWithValue(4, "foo")) + Expect(intKeys).ShouldNot(HaveKeyWithValue(2, "baz")) + + Expect(objKeys).Should(HaveKeyWithValue(customA, customA)) + Expect(objKeys).Should(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"cake"}}, &myCustomType{s: "a", n: 2, f: 2.3, arr: []string{"ice", "cream"}})) + Expect(objKeys).ShouldNot(HaveKeyWithValue(&myCustomType{s: "b", n: 4, f: 3.1, arr: []string{"apple", "pie"}}, customA)) + }) + }) + + Context("when passed a correctly typed nil", func() { + It("should operate succesfully on the passed in value", func() { + var nilMap map[int]string + Expect(nilMap).ShouldNot(HaveKeyWithValue("foo", "bar")) + }) + }) + + Context("when the passed in key or value is actually a matcher", func() { + It("should pass each element through the matcher", func() { + Expect(stringKeys).Should(HaveKeyWithValue(ContainSubstring("oo"), 2)) + Expect(intKeys).Should(HaveKeyWithValue(2, ContainSubstring("oo"))) + Expect(stringKeys).ShouldNot(HaveKeyWithValue(ContainSubstring("foobar"), 2)) + }) + + It("should fail if the matcher ever fails", func() { + actual := map[int]string{1: "a", 3: "b", 2: "c"} + success, err := (&HaveKeyWithValueMatcher{Key: ContainSubstring("ar"), Value: 2}).Match(actual) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + otherActual := map[string]int{"a": 1, "b": 2, "c": 3} + success, err = (&HaveKeyWithValueMatcher{Key: "a", Value: ContainSubstring("1")}).Match(otherActual) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed something that is not a map", func() { + It("should error", func() { + success, err := (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match([]string{"foo"}) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&HaveKeyWithValueMatcher{Key: "foo", Value: "bar"}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go new file mode 100644 index 000000000..c60f63886 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_len_matcher_test.go @@ -0,0 +1,53 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("HaveLen", func() { + Context("when passed a supported type", func() { + It("should do the right thing", func() { + Expect("").Should(HaveLen(0)) + Expect("AA").Should(HaveLen(2)) + + Expect([0]int{}).Should(HaveLen(0)) + Expect([2]int{1, 2}).Should(HaveLen(2)) + + Expect([]int{}).Should(HaveLen(0)) + Expect([]int{1, 2, 3}).Should(HaveLen(3)) + + Expect(map[string]int{}).Should(HaveLen(0)) + Expect(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).Should(HaveLen(4)) + + c := make(chan bool, 3) + Expect(c).Should(HaveLen(0)) + c <- true + c <- true + Expect(c).Should(HaveLen(2)) + }) + }) + + Context("when passed a correctly typed nil", func() { + It("should operate succesfully on the passed in value", func() { + var nilSlice []int + Expect(nilSlice).Should(HaveLen(0)) + + var nilMap map[int]string + Expect(nilMap).Should(HaveLen(0)) + }) + }) + + Context("when passed an unsupported type", func() { + It("should error", func() { + success, err := (&HaveLenMatcher{Count: 0}).Match(0) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&HaveLenMatcher{Count: 0}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go new file mode 100644 index 000000000..0ad632ec1 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_occurred_matcher_test.go @@ -0,0 +1,59 @@ +package matchers_test + +import ( + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +type CustomErr struct { + msg string +} + +func (e *CustomErr) Error() string { + return e.msg +} + +var _ = Describe("HaveOccurred", func() { + It("should succeed if matching an error", func() { + Expect(errors.New("Foo")).Should(HaveOccurred()) + }) + + It("should not succeed with nil", func() { + Expect(nil).ShouldNot(HaveOccurred()) + }) + + It("should only support errors and nil", func() { + success, err := (&HaveOccurredMatcher{}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&HaveOccurredMatcher{}).Match("") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + + It("doesn't support non-error type", func() { + success, err := (&HaveOccurredMatcher{}).Match(AnyType{}) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError("Expected an error-type. Got:\n : {}")) + }) + + It("doesn't support non-error pointer type", func() { + success, err := (&HaveOccurredMatcher{}).Match(&AnyType{}) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) + }) + + It("should succeed with pointer types that conform to error interface", func() { + err := &CustomErr{"ohai"} + Expect(err).Should(HaveOccurred()) + }) + + It("should not succeed with nil pointers to types that conform to error interface", func() { + var err *CustomErr = nil + Expect(err).ShouldNot(HaveOccurred()) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go new file mode 100644 index 000000000..fe29b7b5d --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_prefix_matcher_test.go @@ -0,0 +1,36 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("HavePrefixMatcher", func() { + Context("when actual is a string", func() { + It("should match a string prefix", func() { + Expect("Ab").Should(HavePrefix("A")) + Expect("A").ShouldNot(HavePrefix("Ab")) + }) + }) + + Context("when the matcher is called with multiple arguments", func() { + It("should pass the string and arguments to sprintf", func() { + Expect("C3PO").Should(HavePrefix("C%dP", 3)) + }) + }) + + Context("when actual is a stringer", func() { + It("should call the stringer and match against the returned string", func() { + Expect(&myStringer{a: "Ab"}).Should(HavePrefix("A")) + }) + }) + + Context("when actual is neither a string nor a stringer", func() { + It("should error", func() { + success, err := (&HavePrefixMatcher{Prefix: "2"}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go new file mode 100644 index 000000000..2ae29821a --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/have_suffix_matcher_test.go @@ -0,0 +1,36 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("HaveSuffixMatcher", func() { + Context("when actual is a string", func() { + It("should match a string suffix", func() { + Expect("Ab").Should(HaveSuffix("b")) + Expect("A").ShouldNot(HaveSuffix("Ab")) + }) + }) + + Context("when the matcher is called with multiple arguments", func() { + It("should pass the string and arguments to sprintf", func() { + Expect("C3PO").Should(HaveSuffix("%dPO", 3)) + }) + }) + + Context("when actual is a stringer", func() { + It("should call the stringer and match against the returned string", func() { + Expect(&myStringer{a: "Ab"}).Should(HaveSuffix("b")) + }) + }) + + Context("when actual is neither a string nor a stringer", func() { + It("should error", func() { + success, err := (&HaveSuffixMatcher{Suffix: "2"}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go new file mode 100644 index 000000000..9bf89fc46 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher_test.go @@ -0,0 +1,107 @@ +package matchers_test + +import ( + "errors" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +type CustomError struct { +} + +func (c CustomError) Error() string { + return "an error" +} + +var _ = Describe("MatchErrorMatcher", func() { + Context("When asserting against an error", func() { + It("should succeed when matching with an error", func() { + err := errors.New("an error") + fmtErr := fmt.Errorf("an error") + customErr := CustomError{} + + Expect(err).Should(MatchError(errors.New("an error"))) + Expect(err).ShouldNot(MatchError(errors.New("another error"))) + + Expect(fmtErr).Should(MatchError(errors.New("an error"))) + Expect(customErr).Should(MatchError(CustomError{})) + }) + + It("should succeed when matching with a string", func() { + err := errors.New("an error") + fmtErr := fmt.Errorf("an error") + customErr := CustomError{} + + Expect(err).Should(MatchError("an error")) + Expect(err).ShouldNot(MatchError("another error")) + + Expect(fmtErr).Should(MatchError("an error")) + Expect(customErr).Should(MatchError("an error")) + }) + + Context("when passed a matcher", func() { + It("should pass if the matcher passes against the error string", func() { + err := errors.New("error 123 abc") + + Expect(err).Should(MatchError(MatchRegexp(`\d{3}`))) + }) + + It("should fail if the matcher fails against the error string", func() { + err := errors.New("no digits") + Expect(err).ShouldNot(MatchError(MatchRegexp(`\d`))) + }) + }) + + It("should fail when passed anything else", func() { + actualErr := errors.New("an error") + _, err := (&MatchErrorMatcher{ + Expected: []byte("an error"), + }).Match(actualErr) + Expect(err).Should(HaveOccurred()) + + _, err = (&MatchErrorMatcher{ + Expected: 3, + }).Match(actualErr) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed nil", func() { + It("should fail", func() { + _, err := (&MatchErrorMatcher{ + Expected: "an error", + }).Match(nil) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed a non-error", func() { + It("should fail", func() { + _, err := (&MatchErrorMatcher{ + Expected: "an error", + }).Match("an error") + Expect(err).Should(HaveOccurred()) + + _, err = (&MatchErrorMatcher{ + Expected: "an error", + }).Match(3) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed an error that is also a string", func() { + It("should use it as an error", func() { + var e mockErr = "mockErr" + + // this fails if the matcher casts e to a string before comparison + Expect(e).Should(MatchError(e)) + }) + }) +}) + +type mockErr string + +func (m mockErr) Error() string { return string(m) } diff --git a/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go new file mode 100644 index 000000000..690c83f9a --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/match_json_matcher_test.go @@ -0,0 +1,97 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("MatchJSONMatcher", func() { + Context("When passed stringifiables", func() { + It("should succeed if the JSON matches", func() { + Expect("{}").Should(MatchJSON("{}")) + Expect(`{"a":1}`).Should(MatchJSON(`{"a":1}`)) + Expect(`{ + "a":1 + }`).Should(MatchJSON(`{"a":1}`)) + Expect(`{"a":1, "b":2}`).Should(MatchJSON(`{"b":2, "a":1}`)) + Expect(`{"a":1}`).ShouldNot(MatchJSON(`{"b":2, "a":1}`)) + + Expect(`{"a":"a", "b":"b"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b", "c":"c"}`)) + Expect(`{"a":"a", "b":"b", "c":"c"}`).ShouldNot(MatchJSON(`{"a":"a", "b":"b"}`)) + + Expect(`{"a":null, "b":null}`).ShouldNot(MatchJSON(`{"c":"c", "d":"d"}`)) + Expect(`{"a":null, "b":null, "c":null}`).ShouldNot(MatchJSON(`{"a":null, "b":null, "d":null}`)) + }) + + It("should work with byte arrays", func() { + Expect([]byte("{}")).Should(MatchJSON([]byte("{}"))) + Expect("{}").Should(MatchJSON([]byte("{}"))) + Expect([]byte("{}")).Should(MatchJSON("{}")) + }) + }) + + Context("when a key mismatch is found", func() { + It("reports the first found mismatch", func() { + subject := MatchJSONMatcher{JSONToMatch: `5`} + actual := `7` + subject.Match(actual) + + failureMessage := subject.FailureMessage(`7`) + Expect(failureMessage).ToNot(ContainSubstring("first mismatched key")) + + subject = MatchJSONMatcher{JSONToMatch: `{"a": 1, "b.g": {"c": 2, "1": ["hello", "see ya"]}}`} + actual = `{"a": 1, "b.g": {"c": 2, "1": ["hello", "goodbye"]}}` + subject.Match(actual) + + failureMessage = subject.FailureMessage(actual) + Expect(failureMessage).To(ContainSubstring(`first mismatched key: "b.g"."1"[1]`)) + }) + }) + + Context("when the expected is not valid JSON", func() { + It("should error and explain why", func() { + success, err := (&MatchJSONMatcher{JSONToMatch: `{}`}).Match(`oops`) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid JSON")) + }) + }) + + Context("when the actual is not valid JSON", func() { + It("should error and explain why", func() { + success, err := (&MatchJSONMatcher{JSONToMatch: `oops`}).Match(`{}`) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid JSON")) + }) + }) + + Context("when the expected is neither a string nor a stringer nor a byte array", func() { + It("should error", func() { + success, err := (&MatchJSONMatcher{JSONToMatch: 2}).Match("{}") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) + + success, err = (&MatchJSONMatcher{JSONToMatch: nil}).Match("{}") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) + }) + }) + + Context("when the actual is neither a string nor a stringer nor a byte array", func() { + It("should error", func() { + success, err := (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) + + success, err = (&MatchJSONMatcher{JSONToMatch: "{}"}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchJSONMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go new file mode 100644 index 000000000..ac2538bb4 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/match_regexp_matcher_test.go @@ -0,0 +1,44 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("MatchRegexp", func() { + Context("when actual is a string", func() { + It("should match against the string", func() { + Expect(" a2!bla").Should(MatchRegexp(`\d!`)) + Expect(" a2!bla").ShouldNot(MatchRegexp(`[A-Z]`)) + }) + }) + + Context("when actual is a stringer", func() { + It("should call the stringer and match agains the returned string", func() { + Expect(&myStringer{a: "Abc3"}).Should(MatchRegexp(`[A-Z][a-z]+\d`)) + }) + }) + + Context("when the matcher is called with multiple arguments", func() { + It("should pass the string and arguments to sprintf", func() { + Expect(" a23!bla").Should(MatchRegexp(`\d%d!`, 3)) + }) + }) + + Context("when actual is neither a string nor a stringer", func() { + It("should error", func() { + success, err := (&MatchRegexpMatcher{Regexp: `\d`}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when the passed in regexp fails to compile", func() { + It("should error", func() { + success, err := (&MatchRegexpMatcher{Regexp: "("}).Match("Foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go new file mode 100644 index 000000000..0b559b22e --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/match_xml_matcher_test.go @@ -0,0 +1,97 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("MatchXMLMatcher", func() { + + var ( + sample_01 = readFileContents("test_data/xml/sample_01.xml") + sample_02 = readFileContents("test_data/xml/sample_02.xml") + sample_03 = readFileContents("test_data/xml/sample_03.xml") + sample_04 = readFileContents("test_data/xml/sample_04.xml") + sample_05 = readFileContents("test_data/xml/sample_05.xml") + sample_06 = readFileContents("test_data/xml/sample_06.xml") + sample_07 = readFileContents("test_data/xml/sample_07.xml") + sample_08 = readFileContents("test_data/xml/sample_08.xml") + sample_09 = readFileContents("test_data/xml/sample_09.xml") + sample_10 = readFileContents("test_data/xml/sample_10.xml") + sample_11 = readFileContents("test_data/xml/sample_11.xml") + ) + + Context("When passed stringifiables", func() { + It("matches documents regardless of the attribute order", func() { + a := `` + b := `` + Expect(b).Should(MatchXML(a)) + Expect(a).Should(MatchXML(b)) + }) + + It("should succeed if the XML matches", func() { + Expect(sample_01).Should(MatchXML(sample_01)) // same XML + Expect(sample_01).Should(MatchXML(sample_02)) // same XML with blank lines + Expect(sample_01).Should(MatchXML(sample_03)) // same XML with different formatting + Expect(sample_01).ShouldNot(MatchXML(sample_04)) // same structures with different values + Expect(sample_01).ShouldNot(MatchXML(sample_05)) // different structures + Expect(sample_06).ShouldNot(MatchXML(sample_07)) // same xml names with different namespaces + Expect(sample_07).ShouldNot(MatchXML(sample_08)) // same structures with different values + Expect(sample_09).ShouldNot(MatchXML(sample_10)) // same structures with different attribute values + Expect(sample_11).Should(MatchXML(sample_11)) // with non UTF-8 encoding + }) + + It("should work with byte arrays", func() { + Expect([]byte(sample_01)).Should(MatchXML([]byte(sample_01))) + Expect([]byte(sample_01)).Should(MatchXML(sample_01)) + Expect(sample_01).Should(MatchXML([]byte(sample_01))) + }) + }) + + Context("when the expected is not valid XML", func() { + It("should error and explain why", func() { + success, err := (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(`oops`) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Actual 'oops' should be valid XML")) + }) + }) + + Context("when the actual is not valid XML", func() { + It("should error and explain why", func() { + success, err := (&MatchXMLMatcher{XMLToMatch: `oops`}).Match(sample_01) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Expected 'oops' should be valid XML")) + }) + }) + + Context("when the expected is neither a string nor a stringer nor a byte array", func() { + It("should error", func() { + success, err := (&MatchXMLMatcher{XMLToMatch: 2}).Match(sample_01) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) + + success, err = (&MatchXMLMatcher{XMLToMatch: nil}).Match(sample_01) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) + }) + }) + + Context("when the actual is neither a string nor a stringer nor a byte array", func() { + It("should error", func() { + success, err := (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) + + success, err = (&MatchXMLMatcher{XMLToMatch: sample_01}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go new file mode 100644 index 000000000..8e63de19e --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/match_yaml_matcher_test.go @@ -0,0 +1,94 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("MatchYAMLMatcher", func() { + Context("When passed stringifiables", func() { + It("should succeed if the YAML matches", func() { + Expect("---").Should(MatchYAML("")) + Expect("a: 1").Should(MatchYAML(`{"a":1}`)) + Expect("a: 1\nb: 2").Should(MatchYAML(`{"b":2, "a":1}`)) + }) + + It("should explain if the YAML does not match when it should", func() { + message := (&MatchYAMLMatcher{YAMLToMatch: "a: 1"}).FailureMessage("b: 2") + Expect(message).To(MatchRegexp(`Expected\s+: b: 2\s+to match YAML of\s+: a: 1`)) + }) + + It("should normalise the expected and actual when explaining if the YAML does not match when it should", func() { + message := (&MatchYAMLMatcher{YAMLToMatch: "a: 'one'"}).FailureMessage("{b: two}") + Expect(message).To(MatchRegexp(`Expected\s+: b: two\s+to match YAML of\s+: a: one`)) + }) + + It("should explain if the YAML matches when it should not", func() { + message := (&MatchYAMLMatcher{YAMLToMatch: "a: 1"}).NegatedFailureMessage("a: 1") + Expect(message).To(MatchRegexp(`Expected\s+: a: 1\s+not to match YAML of\s+: a: 1`)) + }) + + It("should normalise the expected and actual when explaining if the YAML matches when it should not", func() { + message := (&MatchYAMLMatcher{YAMLToMatch: "a: 'one'"}).NegatedFailureMessage("{a: one}") + Expect(message).To(MatchRegexp(`Expected\s+: a: one\s+not to match YAML of\s+: a: one`)) + }) + + It("should fail if the YAML does not match", func() { + Expect("a: 1").ShouldNot(MatchYAML(`{"b":2, "a":1}`)) + }) + + It("should work with byte arrays", func() { + Expect([]byte("a: 1")).Should(MatchYAML([]byte("a: 1"))) + Expect("a: 1").Should(MatchYAML([]byte("a: 1"))) + Expect([]byte("a: 1")).Should(MatchYAML("a: 1")) + }) + }) + + Context("when the expected is not valid YAML", func() { + It("should error and explain why", func() { + success, err := (&MatchYAMLMatcher{YAMLToMatch: ""}).Match("good:\nbad") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Actual 'good:\nbad' should be valid YAML")) + }) + }) + + Context("when the actual is not valid YAML", func() { + It("should error and explain why", func() { + success, err := (&MatchYAMLMatcher{YAMLToMatch: "good:\nbad"}).Match("") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("Expected 'good:\nbad' should be valid YAML")) + }) + }) + + Context("when the expected is neither a string nor a stringer nor a byte array", func() { + It("should error", func() { + success, err := (&MatchYAMLMatcher{YAMLToMatch: 2}).Match("") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : 2")) + + success, err = (&MatchYAMLMatcher{YAMLToMatch: nil}).Match("") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n : nil")) + }) + }) + + Context("when the actual is neither a string nor a stringer nor a byte array", func() { + It("should error", func() { + success, err := (&MatchYAMLMatcher{YAMLToMatch: ""}).Match(2) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : 2")) + + success, err = (&MatchYAMLMatcher{YAMLToMatch: ""}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + Expect(err.Error()).Should(ContainSubstring("MatchYAMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n : nil")) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go b/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go new file mode 100644 index 000000000..b5f76c995 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/matcher_tests_suite_test.go @@ -0,0 +1,50 @@ +package matchers_test + +import ( + "fmt" + "io/ioutil" + "os" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type myStringer struct { + a string +} + +func (s *myStringer) String() string { + return s.a +} + +type StringAlias string + +type myCustomType struct { + s string + n int + f float32 + arr []string +} + +func Test(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Gomega Matchers") +} + +func readFileContents(filePath string) []byte { + f := openFile(filePath) + b, err := ioutil.ReadAll(f) + if err != nil { + panic(fmt.Errorf("failed to read file contents: %v", err)) + } + return b +} + +func openFile(filePath string) *os.File { + f, err := os.Open(filePath) + if err != nil { + panic(fmt.Errorf("failed to open file: %v", err)) + } + return f +} diff --git a/vendor/github.com/onsi/gomega/matchers/not_test.go b/vendor/github.com/onsi/gomega/matchers/not_test.go new file mode 100644 index 000000000..b3c1fdbf0 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/not_test.go @@ -0,0 +1,57 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("NotMatcher", func() { + Context("basic examples", func() { + It("works", func() { + Expect(input).To(Not(false1)) + Expect(input).To(Not(Not(true2))) + Expect(input).ToNot(Not(true3)) + Expect(input).ToNot(Not(Not(false1))) + Expect(input).To(Not(Not(Not(false2)))) + }) + }) + + Context("De Morgan's laws", func() { + It("~(A && B) == ~A || ~B", func() { + Expect(input).To(Not(And(false1, false2))) + Expect(input).To(Or(Not(false1), Not(false2))) + }) + It("~(A || B) == ~A && ~B", func() { + Expect(input).To(Not(Or(false1, false2))) + Expect(input).To(And(Not(false1), Not(false2))) + }) + }) + + Context("failure messages are opposite of original matchers' failure messages", func() { + Context("when match fails", func() { + It("gives a descriptive message", func() { + verifyFailureMessage(Not(HaveLen(2)), input, "not to have length 2") + }) + }) + + Context("when match succeeds, but expected it to fail", func() { + It("gives a descriptive message", func() { + verifyFailureMessage(Not(Not(HaveLen(3))), input, "to have length 3") + }) + }) + }) + + Context("MatchMayChangeInTheFuture()", func() { + It("Propagates value from wrapped matcher", func() { + m := Not(Or()) // an empty Or() always returns false, and indicates it cannot change + Expect(m.Match("anything")).To(BeTrue()) + Expect(m.(*NotMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse()) + }) + It("Defaults to true", func() { + m := Not(Equal(1)) // Equal does not have this method + Expect(m.Match(2)).To(BeTrue()) + Expect(m.(*NotMatcher).MatchMayChangeInTheFuture(2)).To(BeTrue()) // defaults to true + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/or_test.go b/vendor/github.com/onsi/gomega/matchers/or_test.go new file mode 100644 index 000000000..9589a174d --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/or_test.go @@ -0,0 +1,85 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("OrMatcher", func() { + It("works with positive cases", func() { + Expect(input).To(Or(true1)) + Expect(input).To(Or(true1, true2)) + Expect(input).To(Or(true1, false1)) + Expect(input).To(Or(false1, true2)) + Expect(input).To(Or(true1, true2, true3)) + Expect(input).To(Or(true1, true2, false3)) + Expect(input).To(Or(true1, false2, true3)) + Expect(input).To(Or(false1, true2, true3)) + Expect(input).To(Or(true1, false2, false3)) + Expect(input).To(Or(false1, false2, true3)) + + // use alias + Expect(input).To(SatisfyAny(false1, false2, true3)) + }) + + It("works with negative cases", func() { + Expect(input).ToNot(Or()) + Expect(input).ToNot(Or(false1)) + Expect(input).ToNot(Or(false1, false2)) + Expect(input).ToNot(Or(false1, false2, false3)) + }) + + Context("failure messages", func() { + Context("when match fails", func() { + It("gives a descriptive message", func() { + verifyFailureMessage(Or(false1, false2), input, + "To satisfy at least one of these matchers: [%!s(*matchers.HaveLenMatcher=&{1}) %!s(*matchers.EqualMatcher=&{hip})]") + }) + }) + + Context("when match succeeds, but expected it to fail", func() { + It("gives a descriptive message", func() { + verifyFailureMessage(Not(Or(true1, true2)), input, `not to have length 2`) + }) + }) + }) + + Context("MatchMayChangeInTheFuture", func() { + Context("Match returned false", func() { + It("returns true if any of the matchers could change", func() { + // 3 matchers, all return false, and all could change + m := Or(BeNil(), Equal("hip"), HaveLen(1)) + Expect(m.Match("hi")).To(BeFalse()) + Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // all 3 of these matchers default to 'true' + }) + It("returns false if none of the matchers could change", func() { + // empty Or() has the property of never matching, and never can change since there are no sub-matchers that could change + m := Or() + Expect(m.Match("anything")).To(BeFalse()) + Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("anything")).To(BeFalse()) + + // Or() with 3 sub-matchers that return false, and can't change + m = Or(Or(), Or(), Or()) + Expect(m.Match("hi")).To(BeFalse()) + Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) // the 3 empty Or()'s won't change + }) + }) + Context("Match returned true", func() { + Context("returns value of the successful matcher", func() { + It("false if successful matcher not going to change", func() { + // 3 matchers: 1st returns false, 2nd returns true and is not going to change, 3rd is never called + m := Or(BeNil(), And(), Equal(1)) + Expect(m.Match("hi")).To(BeTrue()) + Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeFalse()) + }) + It("true if successful matcher indicates it might change", func() { + // 3 matchers: 1st returns false, 2nd returns true and "might" change, 3rd is never called + m := Or(Not(BeNil()), Equal("hi"), Equal(1)) + Expect(m.Match("hi")).To(BeTrue()) + Expect(m.(*OrMatcher).MatchMayChangeInTheFuture("hi")).To(BeTrue()) // Equal("hi") indicates it might change + }) + }) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go new file mode 100644 index 000000000..96270d5aa --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/panic_matcher_test.go @@ -0,0 +1,45 @@ +package matchers_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("Panic", func() { + Context("when passed something that's not a function that takes zero arguments and returns nothing", func() { + It("should error", func() { + success, err := (&PanicMatcher{}).Match("foo") + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&PanicMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&PanicMatcher{}).Match(func(foo string) {}) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&PanicMatcher{}).Match(func() string { return "bar" }) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when passed a function of the correct type", func() { + It("should call the function and pass if the function panics", func() { + Expect(func() { panic("ack!") }).Should(Panic()) + Expect(func() {}).ShouldNot(Panic()) + }) + }) + + Context("when assertion fails", func() { + It("should print the object passed to Panic", func() { + failuresMessages := InterceptGomegaFailures(func() { + Expect(func() { panic("ack!") }).ShouldNot(Panic()) + }) + Expect(failuresMessages).Should(ConsistOf(MatchRegexp("not to panic, but panicked with\\s*: ack!"))) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go new file mode 100644 index 000000000..66330fb30 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/receive_matcher_test.go @@ -0,0 +1,280 @@ +package matchers_test + +import ( + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +type kungFuActor interface { + DrunkenMaster() bool +} + +type jackie struct { + name string +} + +func (j *jackie) DrunkenMaster() bool { + return true +} + +var _ = Describe("ReceiveMatcher", func() { + Context("with no argument", func() { + Context("for a buffered channel", func() { + It("should succeed", func() { + channel := make(chan bool, 1) + + Expect(channel).ShouldNot(Receive()) + + channel <- true + + Expect(channel).Should(Receive()) + }) + }) + + Context("for an unbuffered channel", func() { + It("should succeed (eventually)", func() { + channel := make(chan bool) + + Expect(channel).ShouldNot(Receive()) + + go func() { + time.Sleep(10 * time.Millisecond) + channel <- true + }() + + Eventually(channel).Should(Receive()) + }) + }) + }) + + Context("with a pointer argument", func() { + Context("of the correct type", func() { + It("should write the value received on the channel to the pointer", func() { + channel := make(chan int, 1) + + var value int + + Expect(channel).ShouldNot(Receive(&value)) + Expect(value).Should(BeZero()) + + channel <- 17 + + Expect(channel).Should(Receive(&value)) + Expect(value).Should(Equal(17)) + }) + }) + + Context("to various types of objects", func() { + It("should work", func() { + //channels of strings + stringChan := make(chan string, 1) + stringChan <- "foo" + + var s string + Expect(stringChan).Should(Receive(&s)) + Expect(s).Should(Equal("foo")) + + //channels of slices + sliceChan := make(chan []bool, 1) + sliceChan <- []bool{true, true, false} + + var sl []bool + Expect(sliceChan).Should(Receive(&sl)) + Expect(sl).Should(Equal([]bool{true, true, false})) + + //channels of channels + chanChan := make(chan chan bool, 1) + c := make(chan bool) + chanChan <- c + + var receivedC chan bool + Expect(chanChan).Should(Receive(&receivedC)) + Expect(receivedC).Should(Equal(c)) + + //channels of interfaces + jackieChan := make(chan kungFuActor, 1) + aJackie := &jackie{name: "Jackie Chan"} + jackieChan <- aJackie + + var theJackie kungFuActor + Expect(jackieChan).Should(Receive(&theJackie)) + Expect(theJackie).Should(Equal(aJackie)) + }) + }) + + Context("of the wrong type", func() { + It("should error", func() { + channel := make(chan int) + var incorrectType bool + + success, err := (&ReceiveMatcher{Arg: &incorrectType}).Match(channel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + var notAPointer int + success, err = (&ReceiveMatcher{Arg: notAPointer}).Match(channel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + }) + + Context("with a matcher", func() { + It("should defer to the underlying matcher", func() { + intChannel := make(chan int, 1) + intChannel <- 3 + Expect(intChannel).Should(Receive(Equal(3))) + + intChannel <- 2 + Expect(intChannel).ShouldNot(Receive(Equal(3))) + + stringChannel := make(chan []string, 1) + stringChannel <- []string{"foo", "bar", "baz"} + Expect(stringChannel).Should(Receive(ContainElement(ContainSubstring("fo")))) + + stringChannel <- []string{"foo", "bar", "baz"} + Expect(stringChannel).ShouldNot(Receive(ContainElement(ContainSubstring("archipelago")))) + }) + + It("should defer to the underlying matcher for the message", func() { + matcher := Receive(Equal(3)) + channel := make(chan int, 1) + channel <- 2 + matcher.Match(channel) + Expect(matcher.FailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 2\s+to equal\s+: 3`)) + + channel <- 3 + matcher.Match(channel) + Expect(matcher.NegatedFailureMessage(channel)).Should(MatchRegexp(`Expected\s+: 3\s+not to equal\s+: 3`)) + }) + + It("should work just fine with Eventually", func() { + stringChannel := make(chan string) + + go func() { + time.Sleep(5 * time.Millisecond) + stringChannel <- "A" + time.Sleep(5 * time.Millisecond) + stringChannel <- "B" + }() + + Eventually(stringChannel).Should(Receive(Equal("B"))) + }) + + Context("if the matcher errors", func() { + It("should error", func() { + channel := make(chan int, 1) + channel <- 3 + success, err := (&ReceiveMatcher{Arg: ContainSubstring("three")}).Match(channel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("if nothing is received", func() { + It("should fail", func() { + channel := make(chan int, 1) + success, err := (&ReceiveMatcher{Arg: Equal(1)}).Match(channel) + Expect(success).Should(BeFalse()) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + }) + + Context("When actual is a *closed* channel", func() { + Context("for a buffered channel", func() { + It("should work until it hits the end of the buffer", func() { + channel := make(chan bool, 1) + channel <- true + + close(channel) + + Expect(channel).Should(Receive()) + Expect(channel).ShouldNot(Receive()) + }) + }) + + Context("for an unbuffered channel", func() { + It("should always fail", func() { + channel := make(chan bool) + close(channel) + + Expect(channel).ShouldNot(Receive()) + }) + }) + }) + + Context("When actual is a send-only channel", func() { + It("should error", func() { + channel := make(chan bool) + + var writerChannel chan<- bool + writerChannel = channel + + success, err := (&ReceiveMatcher{}).Match(writerChannel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Context("when acutal is a non-channel", func() { + It("should error", func() { + var nilChannel chan bool + + success, err := (&ReceiveMatcher{}).Match(nilChannel) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&ReceiveMatcher{}).Match(nil) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + + success, err = (&ReceiveMatcher{}).Match(3) + Expect(success).Should(BeFalse()) + Expect(err).Should(HaveOccurred()) + }) + }) + + Describe("when used with eventually and a custom matcher", func() { + It("should return the matcher's error when a failing value is received on the channel, instead of the must receive something failure", func() { + failures := InterceptGomegaFailures(func() { + c := make(chan string, 0) + Eventually(c, 0.01).Should(Receive(Equal("hello"))) + }) + Expect(failures[0]).Should(ContainSubstring("When passed a matcher, ReceiveMatcher's channel *must* receive something.")) + + failures = InterceptGomegaFailures(func() { + c := make(chan string, 1) + c <- "hi" + Eventually(c, 0.01).Should(Receive(Equal("hello"))) + }) + Expect(failures[0]).Should(ContainSubstring(": hello")) + }) + }) + + Describe("Bailing early", func() { + It("should bail early when passed a closed channel", func() { + c := make(chan bool) + close(c) + + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(c).Should(Receive()) + }) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) + }) + + It("should bail early when passed a non-channel", func() { + t := time.Now() + failures := InterceptGomegaFailures(func() { + Eventually(3).Should(Receive()) + }) + Expect(time.Since(t)).Should(BeNumerically("<", 500*time.Millisecond)) + Expect(failures).Should(HaveLen(1)) + }) + }) +}) diff --git a/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go new file mode 100644 index 000000000..21ea64c80 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/succeed_matcher_test.go @@ -0,0 +1,62 @@ +package matchers_test + +import ( + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +func Erroring() error { + return errors.New("bam") +} + +func NotErroring() error { + return nil +} + +type AnyType struct{} + +func Invalid() *AnyType { + return nil +} + +var _ = Describe("Succeed", func() { + It("should succeed if the function succeeds", func() { + Expect(NotErroring()).Should(Succeed()) + }) + + It("should succeed (in the negated) if the function errored", func() { + Expect(Erroring()).ShouldNot(Succeed()) + }) + + It("should not if passed a non-error", func() { + success, err := (&SucceedMatcher{}).Match(Invalid()) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError("Expected an error-type. Got:\n <*matchers_test.AnyType | 0x0>: nil")) + }) + + It("doesn't support non-error type", func() { + success, err := (&SucceedMatcher{}).Match(AnyType{}) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError("Expected an error-type. Got:\n : {}")) + }) + + It("doesn't support non-error pointer type", func() { + success, err := (&SucceedMatcher{}).Match(&AnyType{}) + Expect(success).Should(BeFalse()) + Expect(err).Should(MatchError(MatchRegexp(`Expected an error-type. Got:\n <*matchers_test.AnyType | 0x[[:xdigit:]]+>: {}`))) + }) + + It("should not succeed with pointer types that conform to error interface", func() { + err := &CustomErr{"ohai"} + Expect(err).ShouldNot(Succeed()) + }) + + It("should succeed with nil pointers to types that conform to error interface", func() { + var err *CustomErr = nil + Expect(err).Should(Succeed()) + }) + +}) diff --git a/vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE b/vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE new file mode 100644 index 000000000..8edd8175a --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/support/goraph/MIT.LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2014 Amit Kumar Gupta + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/onsi/gomega/matchers/with_transform_test.go b/vendor/github.com/onsi/gomega/matchers/with_transform_test.go new file mode 100644 index 000000000..e52bf8e63 --- /dev/null +++ b/vendor/github.com/onsi/gomega/matchers/with_transform_test.go @@ -0,0 +1,102 @@ +package matchers_test + +import ( + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/matchers" +) + +var _ = Describe("WithTransformMatcher", func() { + + var plus1 = func(i int) int { return i + 1 } + + Context("Panic if transform function invalid", func() { + panicsWithTransformer := func(transform interface{}) { + ExpectWithOffset(1, func() { WithTransform(transform, nil) }).To(Panic()) + } + It("nil", func() { + panicsWithTransformer(nil) + }) + Context("Invalid number of args, but correct return value count", func() { + It("zero", func() { + panicsWithTransformer(func() int { return 5 }) + }) + It("two", func() { + panicsWithTransformer(func(i, j int) int { return 5 }) + }) + }) + Context("Invalid number of return values, but correct number of arguments", func() { + It("zero", func() { + panicsWithTransformer(func(i int) {}) + }) + It("two", func() { + panicsWithTransformer(func(i int) (int, int) { return 5, 6 }) + }) + }) + }) + + It("works with positive cases", func() { + Expect(1).To(WithTransform(plus1, Equal(2))) + Expect(1).To(WithTransform(plus1, WithTransform(plus1, Equal(3)))) + Expect(1).To(WithTransform(plus1, And(Equal(2), BeNumerically(">", 1)))) + + // transform expects custom type + type S struct { + A int + B string + } + transformer := func(s S) string { return s.B } + Expect(S{1, "hi"}).To(WithTransform(transformer, Equal("hi"))) + + // transform expects interface + errString := func(e error) string { return e.Error() } + Expect(errors.New("abc")).To(WithTransform(errString, Equal("abc"))) + }) + + It("works with negative cases", func() { + Expect(1).ToNot(WithTransform(plus1, Equal(3))) + Expect(1).ToNot(WithTransform(plus1, WithTransform(plus1, Equal(2)))) + }) + + Context("failure messages", func() { + Context("when match fails", func() { + It("gives a descriptive message", func() { + m := WithTransform(plus1, Equal(3)) + Expect(m.Match(1)).To(BeFalse()) + Expect(m.FailureMessage(1)).To(Equal("Expected\n : 2\nto equal\n : 3")) + }) + }) + + Context("when match succeeds, but expected it to fail", func() { + It("gives a descriptive message", func() { + m := Not(WithTransform(plus1, Equal(3))) + Expect(m.Match(2)).To(BeFalse()) + Expect(m.FailureMessage(2)).To(Equal("Expected\n : 3\nnot to equal\n : 3")) + }) + }) + + Context("actual value is incompatible with transform function's argument type", func() { + It("gracefully fails if transform cannot be performed", func() { + m := WithTransform(plus1, Equal(3)) + result, err := m.Match("hi") // give it a string but transform expects int; doesn't panic + Expect(result).To(BeFalse()) + Expect(err).To(MatchError("Transform function expects 'int' but we have 'string'")) + }) + }) + }) + + Context("MatchMayChangeInTheFuture()", func() { + It("Propagates value from wrapped matcher on the transformed value", func() { + m := WithTransform(plus1, Or()) // empty Or() always returns false, and indicates it cannot change + Expect(m.Match(1)).To(BeFalse()) + Expect(m.(*WithTransformMatcher).MatchMayChangeInTheFuture(1)).To(BeFalse()) // empty Or() indicates cannot change + }) + It("Defaults to true", func() { + m := WithTransform(plus1, Equal(2)) // Equal does not have this method + Expect(m.Match(1)).To(BeTrue()) + Expect(m.(*WithTransformMatcher).MatchMayChangeInTheFuture(1)).To(BeTrue()) // defaults to true + }) + }) +}) diff --git a/vendor/github.com/petar/GoLLRB/.gitignore b/vendor/github.com/petar/GoLLRB/.gitignore new file mode 100644 index 000000000..e333b2dbf --- /dev/null +++ b/vendor/github.com/petar/GoLLRB/.gitignore @@ -0,0 +1,23 @@ +syntax:glob +*.[568ao] +*.ao +*.so +*.pyc +*.swp +*.swo +._* +.nfs.* +[568a].out +*~ +*.orig +*.pb.go +core +_obj +_test +src/pkg/Make.deps +_testmain.go + +syntax:regexp +^pkg/ +^src/cmd/(.*)/6?\1$ +^.*/core.[0-9]*$ diff --git a/vendor/github.com/petar/GoLLRB/README.md b/vendor/github.com/petar/GoLLRB/README.md new file mode 100644 index 000000000..742ca0bd5 --- /dev/null +++ b/vendor/github.com/petar/GoLLRB/README.md @@ -0,0 +1,66 @@ +# GoLLRB + +GoLLRB is a Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary +search trees in Go Language. + +## Overview + +As of this writing and to the best of the author's knowledge, +Go still does not have a balanced binary search tree (BBST) data structure. +These data structures are quite useful in a variety of cases. A BBST maintains +elements in sorted order under dynamic updates (inserts and deletes) and can +support various order-specific queries. Furthermore, in practice one often +implements other common data structures like Priority Queues, using BBST's. + +2-3 trees (a type of BBST's), as well as the runtime-similar 2-3-4 trees, are +the de facto standard BBST algoritms found in implementations of Python, Java, +and other libraries. The LLRB method of implementing 2-3 trees is a recent +improvement over the traditional implementation. The LLRB approach was +discovered relatively recently (in 2008) by Robert Sedgewick of Princeton +University. + +GoLLRB is a Go implementation of LLRB 2-3 trees. + +## Maturity + +GoLLRB has been used in some pretty heavy-weight machine learning tasks over many gigabytes of data. +I consider it to be in stable, perhaps even production, shape. There are no known bugs. + +## Installation + +With a healthy Go Language installed, simply run `go get github.com/petar/GoLLRB/llrb` + +## Example + + package main + + import ( + "fmt" + "github.com/petar/GoLLRB/llrb" + ) + + func lessInt(a, b interface{}) bool { return a.(int) < b.(int) } + + func main() { + tree := llrb.New(lessInt) + tree.ReplaceOrInsert(1) + tree.ReplaceOrInsert(2) + tree.ReplaceOrInsert(3) + tree.ReplaceOrInsert(4) + tree.DeleteMin() + tree.Delete(4) + c := tree.IterAscend() + for { + u := <-c + if u == nil { + break + } + fmt.Printf("%d\n", int(u.(int))) + } + } + +## About + +GoLLRB was written by [Petar Maymounkov](http://pdos.csail.mit.edu/~petar/). + +Follow me on [Twitter @maymounkov](http://www.twitter.com/maymounkov)! diff --git a/vendor/github.com/petar/GoLLRB/llrb/iterator_test.go b/vendor/github.com/petar/GoLLRB/llrb/iterator_test.go new file mode 100644 index 000000000..db5e12c92 --- /dev/null +++ b/vendor/github.com/petar/GoLLRB/llrb/iterator_test.go @@ -0,0 +1,76 @@ +package llrb + +import ( + "reflect" + "testing" +) + +func TestAscendGreaterOrEqual(t *testing.T) { + tree := New() + tree.InsertNoReplace(Int(4)) + tree.InsertNoReplace(Int(6)) + tree.InsertNoReplace(Int(1)) + tree.InsertNoReplace(Int(3)) + var ary []Item + tree.AscendGreaterOrEqual(Int(-1), func(i Item) bool { + ary = append(ary, i) + return true + }) + expected := []Item{Int(1), Int(3), Int(4), Int(6)} + if !reflect.DeepEqual(ary, expected) { + t.Errorf("expected %v but got %v", expected, ary) + } + ary = nil + tree.AscendGreaterOrEqual(Int(3), func(i Item) bool { + ary = append(ary, i) + return true + }) + expected = []Item{Int(3), Int(4), Int(6)} + if !reflect.DeepEqual(ary, expected) { + t.Errorf("expected %v but got %v", expected, ary) + } + ary = nil + tree.AscendGreaterOrEqual(Int(2), func(i Item) bool { + ary = append(ary, i) + return true + }) + expected = []Item{Int(3), Int(4), Int(6)} + if !reflect.DeepEqual(ary, expected) { + t.Errorf("expected %v but got %v", expected, ary) + } +} + +func TestDescendLessOrEqual(t *testing.T) { + tree := New() + tree.InsertNoReplace(Int(4)) + tree.InsertNoReplace(Int(6)) + tree.InsertNoReplace(Int(1)) + tree.InsertNoReplace(Int(3)) + var ary []Item + tree.DescendLessOrEqual(Int(10), func(i Item) bool { + ary = append(ary, i) + return true + }) + expected := []Item{Int(6), Int(4), Int(3), Int(1)} + if !reflect.DeepEqual(ary, expected) { + t.Errorf("expected %v but got %v", expected, ary) + } + ary = nil + tree.DescendLessOrEqual(Int(4), func(i Item) bool { + ary = append(ary, i) + return true + }) + expected = []Item{Int(4), Int(3), Int(1)} + if !reflect.DeepEqual(ary, expected) { + t.Errorf("expected %v but got %v", expected, ary) + } + ary = nil + tree.DescendLessOrEqual(Int(5), func(i Item) bool { + ary = append(ary, i) + return true + }) + expected = []Item{Int(4), Int(3), Int(1)} + if !reflect.DeepEqual(ary, expected) { + t.Errorf("expected %v but got %v", expected, ary) + } +} diff --git a/vendor/github.com/petar/GoLLRB/llrb/llrb_test.go b/vendor/github.com/petar/GoLLRB/llrb/llrb_test.go new file mode 100644 index 000000000..b7bc97800 --- /dev/null +++ b/vendor/github.com/petar/GoLLRB/llrb/llrb_test.go @@ -0,0 +1,239 @@ +// Copyright 2010 Petar Maymounkov. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package llrb + +import ( + "math" + "math/rand" + "testing" +) + +func TestCases(t *testing.T) { + tree := New() + tree.ReplaceOrInsert(Int(1)) + tree.ReplaceOrInsert(Int(1)) + if tree.Len() != 1 { + t.Errorf("expecting len 1") + } + if !tree.Has(Int(1)) { + t.Errorf("expecting to find key=1") + } + + tree.Delete(Int(1)) + if tree.Len() != 0 { + t.Errorf("expecting len 0") + } + if tree.Has(Int(1)) { + t.Errorf("not expecting to find key=1") + } + + tree.Delete(Int(1)) + if tree.Len() != 0 { + t.Errorf("expecting len 0") + } + if tree.Has(Int(1)) { + t.Errorf("not expecting to find key=1") + } +} + +func TestReverseInsertOrder(t *testing.T) { + tree := New() + n := 100 + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(n - i)) + } + i := 0 + tree.AscendGreaterOrEqual(Int(0), func(item Item) bool { + i++ + if item.(Int) != Int(i) { + t.Errorf("bad order: got %d, expect %d", item.(Int), i) + } + return true + }) +} + +func TestRange(t *testing.T) { + tree := New() + order := []String{ + "ab", "aba", "abc", "a", "aa", "aaa", "b", "a-", "a!", + } + for _, i := range order { + tree.ReplaceOrInsert(i) + } + k := 0 + tree.AscendRange(String("ab"), String("ac"), func(item Item) bool { + if k > 3 { + t.Fatalf("returned more items than expected") + } + i1 := order[k] + i2 := item.(String) + if i1 != i2 { + t.Errorf("expecting %s, got %s", i1, i2) + } + k++ + return true + }) +} + +func TestRandomInsertOrder(t *testing.T) { + tree := New() + n := 1000 + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(perm[i])) + } + j := 0 + tree.AscendGreaterOrEqual(Int(0), func(item Item) bool { + if item.(Int) != Int(j) { + t.Fatalf("bad order") + } + j++ + return true + }) +} + +func TestRandomReplace(t *testing.T) { + tree := New() + n := 100 + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(perm[i])) + } + perm = rand.Perm(n) + for i := 0; i < n; i++ { + if replaced := tree.ReplaceOrInsert(Int(perm[i])); replaced == nil || replaced.(Int) != Int(perm[i]) { + t.Errorf("error replacing") + } + } +} + +func TestRandomInsertSequentialDelete(t *testing.T) { + tree := New() + n := 1000 + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(perm[i])) + } + for i := 0; i < n; i++ { + tree.Delete(Int(i)) + } +} + +func TestRandomInsertDeleteNonExistent(t *testing.T) { + tree := New() + n := 100 + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(perm[i])) + } + if tree.Delete(Int(200)) != nil { + t.Errorf("deleted non-existent item") + } + if tree.Delete(Int(-2)) != nil { + t.Errorf("deleted non-existent item") + } + for i := 0; i < n; i++ { + if u := tree.Delete(Int(i)); u == nil || u.(Int) != Int(i) { + t.Errorf("delete failed") + } + } + if tree.Delete(Int(200)) != nil { + t.Errorf("deleted non-existent item") + } + if tree.Delete(Int(-2)) != nil { + t.Errorf("deleted non-existent item") + } +} + +func TestRandomInsertPartialDeleteOrder(t *testing.T) { + tree := New() + n := 100 + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(perm[i])) + } + for i := 1; i < n-1; i++ { + tree.Delete(Int(i)) + } + j := 0 + tree.AscendGreaterOrEqual(Int(0), func(item Item) bool { + switch j { + case 0: + if item.(Int) != Int(0) { + t.Errorf("expecting 0") + } + case 1: + if item.(Int) != Int(n-1) { + t.Errorf("expecting %d", n-1) + } + } + j++ + return true + }) +} + +func TestRandomInsertStats(t *testing.T) { + tree := New() + n := 100000 + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.ReplaceOrInsert(Int(perm[i])) + } + avg, _ := tree.HeightStats() + expAvg := math.Log2(float64(n)) - 1.5 + if math.Abs(avg-expAvg) >= 2.0 { + t.Errorf("too much deviation from expected average height") + } +} + +func BenchmarkInsert(b *testing.B) { + tree := New() + for i := 0; i < b.N; i++ { + tree.ReplaceOrInsert(Int(b.N - i)) + } +} + +func BenchmarkDelete(b *testing.B) { + b.StopTimer() + tree := New() + for i := 0; i < b.N; i++ { + tree.ReplaceOrInsert(Int(b.N - i)) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + tree.Delete(Int(i)) + } +} + +func BenchmarkDeleteMin(b *testing.B) { + b.StopTimer() + tree := New() + for i := 0; i < b.N; i++ { + tree.ReplaceOrInsert(Int(b.N - i)) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + tree.DeleteMin() + } +} + +func TestInsertNoReplace(t *testing.T) { + tree := New() + n := 1000 + for q := 0; q < 2; q++ { + perm := rand.Perm(n) + for i := 0; i < n; i++ { + tree.InsertNoReplace(Int(perm[i])) + } + } + j := 0 + tree.AscendGreaterOrEqual(Int(0), func(item Item) bool { + if item.(Int) != Int(j/2) { + t.Fatalf("bad order") + } + j++ + return true + }) +} diff --git a/vendor/github.com/peterbourgon/diskv/README.md b/vendor/github.com/peterbourgon/diskv/README.md new file mode 100644 index 000000000..3474739ed --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/README.md @@ -0,0 +1,141 @@ +# What is diskv? + +Diskv (disk-vee) is a simple, persistent key-value store written in the Go +language. It starts with an incredibly simple API for storing arbitrary data on +a filesystem by key, and builds several layers of performance-enhancing +abstraction on top. The end result is a conceptually simple, but highly +performant, disk-backed storage system. + +[![Build Status][1]][2] + +[1]: https://drone.io/github.com/peterbourgon/diskv/status.png +[2]: https://drone.io/github.com/peterbourgon/diskv/latest + + +# Installing + +Install [Go 1][3], either [from source][4] or [with a prepackaged binary][5]. +Then, + +```bash +$ go get github.com/peterbourgon/diskv +``` + +[3]: http://golang.org +[4]: http://golang.org/doc/install/source +[5]: http://golang.org/doc/install + + +# Usage + +```go +package main + +import ( + "fmt" + "github.com/peterbourgon/diskv" +) + +func main() { + // Simplest transform function: put all the data files into the base dir. + flatTransform := func(s string) []string { return []string{} } + + // Initialize a new diskv store, rooted at "my-data-dir", with a 1MB cache. + d := diskv.New(diskv.Options{ + BasePath: "my-data-dir", + Transform: flatTransform, + CacheSizeMax: 1024 * 1024, + }) + + // Write three bytes to the key "alpha". + key := "alpha" + d.Write(key, []byte{'1', '2', '3'}) + + // Read the value back out of the store. + value, _ := d.Read(key) + fmt.Printf("%v\n", value) + + // Erase the key+value from the store (and the disk). + d.Erase(key) +} +``` + +More complex examples can be found in the "examples" subdirectory. + + +# Theory + +## Basic idea + +At its core, diskv is a map of a key (`string`) to arbitrary data (`[]byte`). +The data is written to a single file on disk, with the same name as the key. +The key determines where that file will be stored, via a user-provided +`TransformFunc`, which takes a key and returns a slice (`[]string`) +corresponding to a path list where the key file will be stored. The simplest +TransformFunc, + +```go +func SimpleTransform (key string) []string { + return []string{} +} +``` + +will place all keys in the same, base directory. The design is inspired by +[Redis diskstore][6]; a TransformFunc which emulates the default diskstore +behavior is available in the content-addressable-storage example. + +[6]: http://groups.google.com/group/redis-db/browse_thread/thread/d444bc786689bde9?pli=1 + +**Note** that your TransformFunc should ensure that one valid key doesn't +transform to a subset of another valid key. That is, it shouldn't be possible +to construct valid keys that resolve to directory names. As a concrete example, +if your TransformFunc splits on every 3 characters, then + +```go +d.Write("abcabc", val) // OK: written to /abc/abc/abcabc +d.Write("abc", val) // Error: attempted write to /abc/abc, but it's a directory +``` + +This will be addressed in an upcoming version of diskv. + +Probably the most important design principle behind diskv is that your data is +always flatly available on the disk. diskv will never do anything that would +prevent you from accessing, copying, backing up, or otherwise interacting with +your data via common UNIX commandline tools. + +## Adding a cache + +An in-memory caching layer is provided by combining the BasicStore +functionality with a simple map structure, and keeping it up-to-date as +appropriate. Since the map structure in Go is not threadsafe, it's combined +with a RWMutex to provide safe concurrent access. + +## Adding order + +diskv is a key-value store and therefore inherently unordered. An ordering +system can be injected into the store by passing something which satisfies the +diskv.Index interface. (A default implementation, using Google's +[btree][7] package, is provided.) Basically, diskv keeps an ordered (by a +user-provided Less function) index of the keys, which can be queried. + +[7]: https://github.com/google/btree + +## Adding compression + +Something which implements the diskv.Compression interface may be passed +during store creation, so that all Writes and Reads are filtered through +a compression/decompression pipeline. Several default implementations, +using stdlib compression algorithms, are provided. Note that data is cached +compressed; the cost of decompression is borne with each Read. + +## Streaming + +diskv also now provides ReadStream and WriteStream methods, to allow very large +data to be handled efficiently. + + +# Future plans + + * Needs plenty of robust testing: huge datasets, etc... + * More thorough benchmarking + * Your suggestions for use-cases I haven't thought of diff --git a/vendor/github.com/peterbourgon/diskv/basic_test.go b/vendor/github.com/peterbourgon/diskv/basic_test.go new file mode 100644 index 000000000..0ef0b17fe --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/basic_test.go @@ -0,0 +1,336 @@ +package diskv + +import ( + "bytes" + "errors" + "testing" + "time" +) + +func cmpBytes(a, b []byte) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +func (d *Diskv) isCached(key string) bool { + d.mu.RLock() + defer d.mu.RUnlock() + _, ok := d.cache[key] + return ok +} + +func TestWriteReadErase(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1024, + }) + defer d.EraseAll() + k, v := "a", []byte{'b'} + if err := d.Write(k, v); err != nil { + t.Fatalf("write: %s", err) + } + if readVal, err := d.Read(k); err != nil { + t.Fatalf("read: %s", err) + } else if bytes.Compare(v, readVal) != 0 { + t.Fatalf("read: expected %s, got %s", v, readVal) + } + if err := d.Erase(k); err != nil { + t.Fatalf("erase: %s", err) + } +} + +func TestWRECache(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1024, + }) + defer d.EraseAll() + k, v := "xxx", []byte{' ', ' ', ' '} + if d.isCached(k) { + t.Fatalf("key cached before Write and Read") + } + if err := d.Write(k, v); err != nil { + t.Fatalf("write: %s", err) + } + if d.isCached(k) { + t.Fatalf("key cached before Read") + } + if readVal, err := d.Read(k); err != nil { + t.Fatalf("read: %s", err) + } else if bytes.Compare(v, readVal) != 0 { + t.Fatalf("read: expected %s, got %s", v, readVal) + } + for i := 0; i < 10 && !d.isCached(k); i++ { + time.Sleep(10 * time.Millisecond) + } + if !d.isCached(k) { + t.Fatalf("key not cached after Read") + } + if err := d.Erase(k); err != nil { + t.Fatalf("erase: %s", err) + } + if d.isCached(k) { + t.Fatalf("key cached after Erase") + } +} + +func TestStrings(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1024, + }) + defer d.EraseAll() + + keys := map[string]bool{"a": false, "b": false, "c": false, "d": false} + v := []byte{'1'} + for k := range keys { + if err := d.Write(k, v); err != nil { + t.Fatalf("write: %s: %s", k, err) + } + } + + for k := range d.Keys(nil) { + if _, present := keys[k]; present { + t.Logf("got: %s", k) + keys[k] = true + } else { + t.Fatalf("strings() returns unknown key: %s", k) + } + } + + for k, found := range keys { + if !found { + t.Errorf("never got %s", k) + } + } +} + +func TestZeroByteCache(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 0, + }) + defer d.EraseAll() + + k, v := "a", []byte{'1', '2', '3'} + if err := d.Write(k, v); err != nil { + t.Fatalf("Write: %s", err) + } + + if d.isCached(k) { + t.Fatalf("key cached, expected not-cached") + } + + if _, err := d.Read(k); err != nil { + t.Fatalf("Read: %s", err) + } + + if d.isCached(k) { + t.Fatalf("key cached, expected not-cached") + } +} + +func TestOneByteCache(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1, + }) + defer d.EraseAll() + + k1, k2, v1, v2 := "a", "b", []byte{'1'}, []byte{'1', '2'} + if err := d.Write(k1, v1); err != nil { + t.Fatal(err) + } + + if v, err := d.Read(k1); err != nil { + t.Fatal(err) + } else if !cmpBytes(v, v1) { + t.Fatalf("Read: expected %s, got %s", string(v1), string(v)) + } + + for i := 0; i < 10 && !d.isCached(k1); i++ { + time.Sleep(10 * time.Millisecond) + } + if !d.isCached(k1) { + t.Fatalf("expected 1-byte value to be cached, but it wasn't") + } + + if err := d.Write(k2, v2); err != nil { + t.Fatal(err) + } + if _, err := d.Read(k2); err != nil { + t.Fatalf("--> %s", err) + } + + for i := 0; i < 10 && (!d.isCached(k1) || d.isCached(k2)); i++ { + time.Sleep(10 * time.Millisecond) // just wait for lazy-cache + } + if !d.isCached(k1) { + t.Fatalf("1-byte value was uncached for no reason") + } + + if d.isCached(k2) { + t.Fatalf("2-byte value was cached, but cache max size is 1") + } +} + +func TestStaleCache(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1, + }) + defer d.EraseAll() + + k, first, second := "a", "first", "second" + if err := d.Write(k, []byte(first)); err != nil { + t.Fatal(err) + } + + v, err := d.Read(k) + if err != nil { + t.Fatal(err) + } + if string(v) != first { + t.Errorf("expected '%s', got '%s'", first, v) + } + + if err := d.Write(k, []byte(second)); err != nil { + t.Fatal(err) + } + + v, err = d.Read(k) + if err != nil { + t.Fatal(err) + } + + if string(v) != second { + t.Errorf("expected '%s', got '%s'", second, v) + } +} + +func TestHas(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1024, + }) + defer d.EraseAll() + + for k, v := range map[string]string{ + "a": "1", + "foo": "2", + "012345": "3", + } { + d.Write(k, []byte(v)) + } + + d.Read("foo") // cache one of them + if !d.isCached("foo") { + t.Errorf("'foo' didn't get cached") + } + + for _, tuple := range []struct { + key string + expected bool + }{ + {"a", true}, + {"b", false}, + {"foo", true}, + {"bar", false}, + {"01234", false}, + {"012345", true}, + {"0123456", false}, + } { + if expected, got := tuple.expected, d.Has(tuple.key); expected != got { + t.Errorf("Has(%s): expected %v, got %v", tuple.key, expected, got) + } + } +} + +type BrokenReader struct{} + +func (BrokenReader) Read(p []byte) (n int, err error) { + return 0, errors.New("failed to read") +} + +func TestRemovesIncompleteFiles(t *testing.T) { + opts := Options{ + BasePath: "test-data", + CacheSizeMax: 1024, + } + d := New(opts) + defer d.EraseAll() + + key, stream, sync := "key", BrokenReader{}, false + + if err := d.WriteStream(key, stream, sync); err == nil { + t.Fatalf("Expected i/o copy error, none received.") + } + + if _, err := d.Read(key); err == nil { + t.Fatal("Could read the key, but it shouldn't exist") + } +} + +func TestTempDir(t *testing.T) { + opts := Options{ + BasePath: "test-data", + TempDir: "test-data-temp", + CacheSizeMax: 1024, + } + d := New(opts) + defer d.EraseAll() + + k, v := "a", []byte{'b'} + if err := d.Write(k, v); err != nil { + t.Fatalf("write: %s", err) + } + if readVal, err := d.Read(k); err != nil { + t.Fatalf("read: %s", err) + } else if bytes.Compare(v, readVal) != 0 { + t.Fatalf("read: expected %s, got %s", v, readVal) + } + if err := d.Erase(k); err != nil { + t.Fatalf("erase: %s", err) + } +} + +type CrashingReader struct{} + +func (CrashingReader) Read(p []byte) (n int, err error) { + panic("System has crashed while reading the stream") +} + +func TestAtomicWrite(t *testing.T) { + opts := Options{ + BasePath: "test-data", + // Test would fail if TempDir is not set here. + TempDir: "test-data-temp", + CacheSizeMax: 1024, + } + d := New(opts) + defer d.EraseAll() + + key := "key" + func() { + defer func() { + recover() // Ignore panicking error + }() + + stream := CrashingReader{} + d.WriteStream(key, stream, false) + }() + + if d.Has(key) { + t.Fatal("Has key, but it shouldn't exist") + } + if _, ok := <-d.Keys(nil); ok { + t.Fatal("Store isn't empty") + } +} diff --git a/vendor/github.com/peterbourgon/diskv/compression_test.go b/vendor/github.com/peterbourgon/diskv/compression_test.go new file mode 100644 index 000000000..2d6142037 --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/compression_test.go @@ -0,0 +1,72 @@ +package diskv + +import ( + "compress/flate" + "fmt" + "math/rand" + "os" + "testing" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func testCompressionWith(t *testing.T, c Compression, name string) { + d := New(Options{ + BasePath: "compression-test", + CacheSizeMax: 0, + Compression: c, + }) + defer d.EraseAll() + + sz := 4096 + val := make([]byte, sz) + for i := 0; i < sz; i++ { + val[i] = byte('a' + rand.Intn(26)) // {a-z}; should compress some + } + + key := "a" + if err := d.Write(key, val); err != nil { + t.Fatalf("write failed: %s", err) + } + + targetFile := fmt.Sprintf("%s%c%s", d.BasePath, os.PathSeparator, key) + fi, err := os.Stat(targetFile) + if err != nil { + t.Fatalf("%s: %s", targetFile, err) + } + + if fi.Size() >= int64(sz) { + t.Fatalf("%s: size=%d, expected smaller", targetFile, fi.Size()) + } + t.Logf("%s compressed %d to %d", name, sz, fi.Size()) + + readVal, err := d.Read(key) + if len(readVal) != sz { + t.Fatalf("read: expected size=%d, got size=%d", sz, len(readVal)) + } + + for i := 0; i < sz; i++ { + if readVal[i] != val[i] { + t.Fatalf("i=%d: expected %v, got %v", i, val[i], readVal[i]) + } + } +} + +func TestGzipDefault(t *testing.T) { + testCompressionWith(t, NewGzipCompression(), "gzip") +} + +func TestGzipBestCompression(t *testing.T) { + testCompressionWith(t, NewGzipCompressionLevel(flate.BestCompression), "gzip-max") +} + +func TestGzipBestSpeed(t *testing.T) { + testCompressionWith(t, NewGzipCompressionLevel(flate.BestSpeed), "gzip-min") +} + +func TestZlib(t *testing.T) { + testCompressionWith(t, NewZlibCompression(), "zlib") +} diff --git a/vendor/github.com/peterbourgon/diskv/import_test.go b/vendor/github.com/peterbourgon/diskv/import_test.go new file mode 100644 index 000000000..a08ac7c70 --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/import_test.go @@ -0,0 +1,76 @@ +package diskv_test + +import ( + "bytes" + "io/ioutil" + "os" + + "github.com/peterbourgon/diskv" + + "testing" +) + +func TestImportMove(t *testing.T) { + b := []byte(`0123456789`) + f, err := ioutil.TempFile("", "temp-test") + if err != nil { + t.Fatal(err) + } + if _, err := f.Write(b); err != nil { + t.Fatal(err) + } + f.Close() + + d := diskv.New(diskv.Options{ + BasePath: "test-import-move", + }) + defer d.EraseAll() + + key := "key" + + if err := d.Write(key, []byte(`TBD`)); err != nil { + t.Fatal(err) + } + + if err := d.Import(f.Name(), key, true); err != nil { + t.Fatal(err) + } + + if _, err := os.Stat(f.Name()); err == nil || !os.IsNotExist(err) { + t.Errorf("expected temp file to be gone, but err = %v", err) + } + + if !d.Has(key) { + t.Errorf("%q not present", key) + } + + if buf, err := d.Read(key); err != nil || bytes.Compare(b, buf) != 0 { + t.Errorf("want %q, have %q (err = %v)", string(b), string(buf), err) + } +} + +func TestImportCopy(t *testing.T) { + b := []byte(`¡åéîòü!`) + + f, err := ioutil.TempFile("", "temp-test") + if err != nil { + t.Fatal(err) + } + if _, err := f.Write(b); err != nil { + t.Fatal(err) + } + f.Close() + + d := diskv.New(diskv.Options{ + BasePath: "test-import-copy", + }) + defer d.EraseAll() + + if err := d.Import(f.Name(), "key", false); err != nil { + t.Fatal(err) + } + + if _, err := os.Stat(f.Name()); err != nil { + t.Errorf("expected temp file to remain, but got err = %v", err) + } +} diff --git a/vendor/github.com/peterbourgon/diskv/index_test.go b/vendor/github.com/peterbourgon/diskv/index_test.go new file mode 100644 index 000000000..72f52a9ff --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/index_test.go @@ -0,0 +1,148 @@ +package diskv + +import ( + "bytes" + "reflect" + "testing" + "time" +) + +func strLess(a, b string) bool { return a < b } + +func cmpStrings(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +func (d *Diskv) isIndexed(key string) bool { + if d.Index == nil { + return false + } + + for _, got := range d.Index.Keys("", 1000) { + if got == key { + return true + } + } + return false +} + +func TestIndexOrder(t *testing.T) { + d := New(Options{ + BasePath: "index-test", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: 1024, + Index: &BTreeIndex{}, + IndexLess: strLess, + }) + defer d.EraseAll() + + v := []byte{'1', '2', '3'} + d.Write("a", v) + if !d.isIndexed("a") { + t.Fatalf("'a' not indexed after write") + } + d.Write("1", v) + d.Write("m", v) + d.Write("-", v) + d.Write("A", v) + + expectedKeys := []string{"-", "1", "A", "a", "m"} + keys := []string{} + for _, key := range d.Index.Keys("", 100) { + keys = append(keys, key) + } + + if !cmpStrings(keys, expectedKeys) { + t.Fatalf("got %s, expected %s", keys, expectedKeys) + } +} + +func TestIndexLoad(t *testing.T) { + d1 := New(Options{ + BasePath: "index-test", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: 1024, + }) + defer d1.EraseAll() + + val := []byte{'1', '2', '3'} + keys := []string{"a", "b", "c", "d", "e", "f", "g"} + for _, key := range keys { + d1.Write(key, val) + } + + d2 := New(Options{ + BasePath: "index-test", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: 1024, + Index: &BTreeIndex{}, + IndexLess: strLess, + }) + defer d2.EraseAll() + + // check d2 has properly loaded existing d1 data + for _, key := range keys { + if !d2.isIndexed(key) { + t.Fatalf("key '%s' not indexed on secondary", key) + } + } + + // cache one + if readValue, err := d2.Read(keys[0]); err != nil { + t.Fatalf("%s", err) + } else if bytes.Compare(val, readValue) != 0 { + t.Fatalf("%s: got %s, expected %s", keys[0], readValue, val) + } + + // make sure it got cached + for i := 0; i < 10 && !d2.isCached(keys[0]); i++ { + time.Sleep(10 * time.Millisecond) + } + if !d2.isCached(keys[0]) { + t.Fatalf("key '%s' not cached", keys[0]) + } + + // kill the disk + d1.EraseAll() + + // cached value should still be there in the second + if readValue, err := d2.Read(keys[0]); err != nil { + t.Fatalf("%s", err) + } else if bytes.Compare(val, readValue) != 0 { + t.Fatalf("%s: got %s, expected %s", keys[0], readValue, val) + } + + // but not in the original + if _, err := d1.Read(keys[0]); err == nil { + t.Fatalf("expected error reading from flushed store") + } +} + +func TestIndexKeysEmptyFrom(t *testing.T) { + d := New(Options{ + BasePath: "index-test", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: 1024, + Index: &BTreeIndex{}, + IndexLess: strLess, + }) + defer d.EraseAll() + + for _, k := range []string{"a", "c", "z", "b", "x", "b", "y"} { + d.Write(k, []byte("1")) + } + + want := []string{"a", "b", "c", "x", "y", "z"} + have := d.Index.Keys("", 99) + if !reflect.DeepEqual(want, have) { + t.Errorf("want %v, have %v", want, have) + } +} diff --git a/vendor/github.com/peterbourgon/diskv/issues_test.go b/vendor/github.com/peterbourgon/diskv/issues_test.go new file mode 100644 index 000000000..0b0b10908 --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/issues_test.go @@ -0,0 +1,121 @@ +package diskv + +import ( + "bytes" + "io/ioutil" + "sync" + "testing" + "time" +) + +// ReadStream from cache shouldn't panic on a nil dereference from a nonexistent +// Compression :) +func TestIssue2A(t *testing.T) { + d := New(Options{ + BasePath: "test-issue-2a", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: 1024, + }) + defer d.EraseAll() + + input := "abcdefghijklmnopqrstuvwxy" + key, writeBuf, sync := "a", bytes.NewBufferString(input), false + if err := d.WriteStream(key, writeBuf, sync); err != nil { + t.Fatal(err) + } + + for i := 0; i < 2; i++ { + began := time.Now() + rc, err := d.ReadStream(key, false) + if err != nil { + t.Fatal(err) + } + buf, err := ioutil.ReadAll(rc) + if err != nil { + t.Fatal(err) + } + if !cmpBytes(buf, []byte(input)) { + t.Fatalf("read #%d: '%s' != '%s'", i+1, string(buf), input) + } + rc.Close() + t.Logf("read #%d in %s", i+1, time.Since(began)) + } +} + +// ReadStream on a key that resolves to a directory should return an error. +func TestIssue2B(t *testing.T) { + blockTransform := func(s string) []string { + transformBlockSize := 3 + sliceSize := len(s) / transformBlockSize + pathSlice := make([]string, sliceSize) + for i := 0; i < sliceSize; i++ { + from, to := i*transformBlockSize, (i*transformBlockSize)+transformBlockSize + pathSlice[i] = s[from:to] + } + return pathSlice + } + + d := New(Options{ + BasePath: "test-issue-2b", + Transform: blockTransform, + CacheSizeMax: 0, + }) + defer d.EraseAll() + + v := []byte{'1', '2', '3'} + if err := d.Write("abcabc", v); err != nil { + t.Fatal(err) + } + + _, err := d.ReadStream("abc", false) + if err == nil { + t.Fatal("ReadStream('abc') should return error") + } + t.Logf("ReadStream('abc') returned error: %v", err) +} + +// Ensure ReadStream with direct=true isn't racy. +func TestIssue17(t *testing.T) { + var ( + basePath = "test-data" + ) + + dWrite := New(Options{ + BasePath: basePath, + CacheSizeMax: 0, + }) + defer dWrite.EraseAll() + + dRead := New(Options{ + BasePath: basePath, + CacheSizeMax: 50, + }) + + cases := map[string]string{ + "a": `1234567890`, + "b": `2345678901`, + "c": `3456789012`, + "d": `4567890123`, + "e": `5678901234`, + } + + for k, v := range cases { + if err := dWrite.Write(k, []byte(v)); err != nil { + t.Fatalf("during write: %s", err) + } + dRead.Read(k) // ensure it's added to cache + } + + var wg sync.WaitGroup + start := make(chan struct{}) + for k, v := range cases { + wg.Add(1) + go func(k, v string) { + <-start + dRead.ReadStream(k, true) + wg.Done() + }(k, v) + } + close(start) + wg.Wait() +} diff --git a/vendor/github.com/peterbourgon/diskv/keys_test.go b/vendor/github.com/peterbourgon/diskv/keys_test.go new file mode 100644 index 000000000..222e1c444 --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/keys_test.go @@ -0,0 +1,231 @@ +package diskv_test + +import ( + "reflect" + "runtime" + "strings" + "testing" + + "github.com/peterbourgon/diskv" +) + +var ( + keysTestData = map[string]string{ + "ab01cd01": "When we started building CoreOS", + "ab01cd02": "we looked at all the various components available to us", + "ab01cd03": "re-using the best tools", + "ef01gh04": "and building the ones that did not exist", + "ef02gh05": "We believe strongly in the Unix philosophy", + "xxxxxxxx": "tools should be independently useful", + } + + prefixes = []string{ + "", // all + "a", + "ab", + "ab0", + "ab01", + "ab01cd0", + "ab01cd01", + "ab01cd01x", // none + "b", // none + "b0", // none + "0", // none + "01", // none + "e", + "ef", + "efx", // none + "ef01gh0", + "ef01gh04", + "ef01gh05", + "ef01gh06", // none + } +) + +func TestKeysFlat(t *testing.T) { + transform := func(s string) []string { + if s == "" { + t.Fatalf(`transform should not be called with ""`) + } + return []string{} + } + d := diskv.New(diskv.Options{ + BasePath: "test-data", + Transform: transform, + }) + defer d.EraseAll() + + for k, v := range keysTestData { + d.Write(k, []byte(v)) + } + + checkKeys(t, d.Keys(nil), keysTestData) +} + +func TestKeysNested(t *testing.T) { + d := diskv.New(diskv.Options{ + BasePath: "test-data", + Transform: blockTransform(2), + }) + defer d.EraseAll() + + for k, v := range keysTestData { + d.Write(k, []byte(v)) + } + + checkKeys(t, d.Keys(nil), keysTestData) +} + +func TestKeysPrefixFlat(t *testing.T) { + d := diskv.New(diskv.Options{ + BasePath: "test-data", + }) + defer d.EraseAll() + + for k, v := range keysTestData { + d.Write(k, []byte(v)) + } + + for _, prefix := range prefixes { + checkKeys(t, d.KeysPrefix(prefix, nil), filterPrefix(keysTestData, prefix)) + } +} + +func TestKeysPrefixNested(t *testing.T) { + d := diskv.New(diskv.Options{ + BasePath: "test-data", + Transform: blockTransform(2), + }) + defer d.EraseAll() + + for k, v := range keysTestData { + d.Write(k, []byte(v)) + } + + for _, prefix := range prefixes { + checkKeys(t, d.KeysPrefix(prefix, nil), filterPrefix(keysTestData, prefix)) + } +} + +func TestKeysCancel(t *testing.T) { + d := diskv.New(diskv.Options{ + BasePath: "test-data", + }) + defer d.EraseAll() + + for k, v := range keysTestData { + d.Write(k, []byte(v)) + } + + var ( + cancel = make(chan struct{}) + received = 0 + cancelAfter = len(keysTestData) / 2 + ) + + for key := range d.Keys(cancel) { + received++ + + if received >= cancelAfter { + close(cancel) + runtime.Gosched() // allow walker to detect cancel + } + + t.Logf("received %d: %q", received, key) + } + + if want, have := cancelAfter, received; want != have { + t.Errorf("want %d, have %d") + } +} + +func checkKeys(t *testing.T, c <-chan string, want map[string]string) { + for k := range c { + if _, ok := want[k]; !ok { + t.Errorf("%q yielded but not expected", k) + continue + } + + delete(want, k) + t.Logf("%q yielded OK", k) + } + + if len(want) != 0 { + t.Errorf("%d expected key(s) not yielded: %s", len(want), strings.Join(flattenKeys(want), ", ")) + } +} + +func blockTransform(blockSize int) func(string) []string { + return func(s string) []string { + var ( + sliceSize = len(s) / blockSize + pathSlice = make([]string, sliceSize) + ) + for i := 0; i < sliceSize; i++ { + from, to := i*blockSize, (i*blockSize)+blockSize + pathSlice[i] = s[from:to] + } + return pathSlice + } +} + +func filterPrefix(in map[string]string, prefix string) map[string]string { + out := map[string]string{} + for k, v := range in { + if strings.HasPrefix(k, prefix) { + out[k] = v + } + } + return out +} + +func TestFilterPrefix(t *testing.T) { + input := map[string]string{ + "all": "", + "and": "", + "at": "", + "available": "", + "best": "", + "building": "", + "components": "", + "coreos": "", + "did": "", + "exist": "", + "looked": "", + "not": "", + "ones": "", + "re-using": "", + "started": "", + "that": "", + "the": "", + "to": "", + "tools": "", + "us": "", + "various": "", + "we": "", + "when": "", + } + + for prefix, want := range map[string]map[string]string{ + "a": map[string]string{"all": "", "and": "", "at": "", "available": ""}, + "al": map[string]string{"all": ""}, + "all": map[string]string{"all": ""}, + "alll": map[string]string{}, + "c": map[string]string{"components": "", "coreos": ""}, + "co": map[string]string{"components": "", "coreos": ""}, + "com": map[string]string{"components": ""}, + } { + have := filterPrefix(input, prefix) + if !reflect.DeepEqual(want, have) { + t.Errorf("%q: want %v, have %v", prefix, flattenKeys(want), flattenKeys(have)) + } + } +} + +func flattenKeys(m map[string]string) []string { + a := make([]string, 0, len(m)) + for k := range m { + a = append(a, k) + } + return a +} diff --git a/vendor/github.com/peterbourgon/diskv/speed_test.go b/vendor/github.com/peterbourgon/diskv/speed_test.go new file mode 100644 index 000000000..67d05ff27 --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/speed_test.go @@ -0,0 +1,153 @@ +package diskv + +import ( + "fmt" + "math/rand" + "testing" +) + +func shuffle(keys []string) { + ints := rand.Perm(len(keys)) + for i := range keys { + keys[i], keys[ints[i]] = keys[ints[i]], keys[i] + } +} + +func genValue(size int) []byte { + v := make([]byte, size) + for i := 0; i < size; i++ { + v[i] = uint8((rand.Int() % 26) + 97) // a-z + } + return v +} + +const ( + keyCount = 1000 +) + +func genKeys() []string { + keys := make([]string, keyCount) + for i := 0; i < keyCount; i++ { + keys[i] = fmt.Sprintf("%d", i) + } + return keys +} + +func (d *Diskv) load(keys []string, val []byte) { + for _, key := range keys { + d.Write(key, val) + } +} + +func benchRead(b *testing.B, size, cachesz int) { + b.StopTimer() + d := New(Options{ + BasePath: "speed-test", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: uint64(cachesz), + }) + defer d.EraseAll() + + keys := genKeys() + value := genValue(size) + d.load(keys, value) + shuffle(keys) + b.SetBytes(int64(size)) + + b.StartTimer() + for i := 0; i < b.N; i++ { + _, _ = d.Read(keys[i%len(keys)]) + } + b.StopTimer() +} + +func benchWrite(b *testing.B, size int, withIndex bool) { + b.StopTimer() + + options := Options{ + BasePath: "speed-test", + Transform: func(string) []string { return []string{} }, + CacheSizeMax: 0, + } + if withIndex { + options.Index = &BTreeIndex{} + options.IndexLess = strLess + } + + d := New(options) + defer d.EraseAll() + keys := genKeys() + value := genValue(size) + shuffle(keys) + b.SetBytes(int64(size)) + + b.StartTimer() + for i := 0; i < b.N; i++ { + d.Write(keys[i%len(keys)], value) + } + b.StopTimer() +} + +func BenchmarkWrite__32B_NoIndex(b *testing.B) { + benchWrite(b, 32, false) +} + +func BenchmarkWrite__1KB_NoIndex(b *testing.B) { + benchWrite(b, 1024, false) +} + +func BenchmarkWrite__4KB_NoIndex(b *testing.B) { + benchWrite(b, 4096, false) +} + +func BenchmarkWrite_10KB_NoIndex(b *testing.B) { + benchWrite(b, 10240, false) +} + +func BenchmarkWrite__32B_WithIndex(b *testing.B) { + benchWrite(b, 32, true) +} + +func BenchmarkWrite__1KB_WithIndex(b *testing.B) { + benchWrite(b, 1024, true) +} + +func BenchmarkWrite__4KB_WithIndex(b *testing.B) { + benchWrite(b, 4096, true) +} + +func BenchmarkWrite_10KB_WithIndex(b *testing.B) { + benchWrite(b, 10240, true) +} + +func BenchmarkRead__32B_NoCache(b *testing.B) { + benchRead(b, 32, 0) +} + +func BenchmarkRead__1KB_NoCache(b *testing.B) { + benchRead(b, 1024, 0) +} + +func BenchmarkRead__4KB_NoCache(b *testing.B) { + benchRead(b, 4096, 0) +} + +func BenchmarkRead_10KB_NoCache(b *testing.B) { + benchRead(b, 10240, 0) +} + +func BenchmarkRead__32B_WithCache(b *testing.B) { + benchRead(b, 32, keyCount*32*2) +} + +func BenchmarkRead__1KB_WithCache(b *testing.B) { + benchRead(b, 1024, keyCount*1024*2) +} + +func BenchmarkRead__4KB_WithCache(b *testing.B) { + benchRead(b, 4096, keyCount*4096*2) +} + +func BenchmarkRead_10KB_WithCache(b *testing.B) { + benchRead(b, 10240, keyCount*4096*2) +} diff --git a/vendor/github.com/peterbourgon/diskv/stream_test.go b/vendor/github.com/peterbourgon/diskv/stream_test.go new file mode 100644 index 000000000..7991dbff2 --- /dev/null +++ b/vendor/github.com/peterbourgon/diskv/stream_test.go @@ -0,0 +1,117 @@ +package diskv + +import ( + "bytes" + "io/ioutil" + "testing" +) + +func TestBasicStreamCaching(t *testing.T) { + d := New(Options{ + BasePath: "test-data", + CacheSizeMax: 1024, + }) + defer d.EraseAll() + + input := "a1b2c3" + key, writeBuf, sync := "a", bytes.NewBufferString(input), true + if err := d.WriteStream(key, writeBuf, sync); err != nil { + t.Fatal(err) + } + + if d.isCached(key) { + t.Fatalf("'%s' cached, but shouldn't be (yet)", key) + } + + rc, err := d.ReadStream(key, false) + if err != nil { + t.Fatal(err) + } + + readBuf, err := ioutil.ReadAll(rc) + if err != nil { + t.Fatal(err) + } + + if !cmpBytes(readBuf, []byte(input)) { + t.Fatalf("'%s' != '%s'", string(readBuf), input) + } + + if !d.isCached(key) { + t.Fatalf("'%s' isn't cached, but should be", key) + } +} + +func TestReadStreamDirect(t *testing.T) { + var ( + basePath = "test-data" + ) + dWrite := New(Options{ + BasePath: basePath, + CacheSizeMax: 0, + }) + defer dWrite.EraseAll() + dRead := New(Options{ + BasePath: basePath, + CacheSizeMax: 1024, + }) + + // Write + key, val1, val2 := "a", []byte(`1234567890`), []byte(`aaaaaaaaaa`) + if err := dWrite.Write(key, val1); err != nil { + t.Fatalf("during first write: %s", err) + } + + // First, caching read. + val, err := dRead.Read(key) + if err != nil { + t.Fatalf("during initial read: %s", err) + } + t.Logf("read 1: %s => %s", key, string(val)) + if !cmpBytes(val1, val) { + t.Errorf("expected %q, got %q", string(val1), string(val)) + } + if !dRead.isCached(key) { + t.Errorf("%q should be cached, but isn't", key) + } + + // Write a different value. + if err := dWrite.Write(key, val2); err != nil { + t.Fatalf("during second write: %s", err) + } + + // Second read, should hit cache and get the old value. + val, err = dRead.Read(key) + if err != nil { + t.Fatalf("during second (cache-hit) read: %s", err) + } + t.Logf("read 2: %s => %s", key, string(val)) + if !cmpBytes(val1, val) { + t.Errorf("expected %q, got %q", string(val1), string(val)) + } + + // Third, direct read, should get the updated value. + rc, err := dRead.ReadStream(key, true) + if err != nil { + t.Fatalf("during third (direct) read, ReadStream: %s", err) + } + defer rc.Close() + val, err = ioutil.ReadAll(rc) + if err != nil { + t.Fatalf("during third (direct) read, ReadAll: %s", err) + } + t.Logf("read 3: %s => %s", key, string(val)) + if !cmpBytes(val2, val) { + t.Errorf("expected %q, got %q", string(val1), string(val)) + } + + // Fourth read, should hit cache and get the new value. + val, err = dRead.Read(key) + if err != nil { + t.Fatalf("during fourth (cache-hit) read: %s", err) + } + t.Logf("read 4: %s => %s", key, string(val)) + if !cmpBytes(val2, val) { + t.Errorf("expected %q, got %q", string(val1), string(val)) + } +} diff --git a/vendor/github.com/prometheus/client_golang/.gitignore b/vendor/github.com/prometheus/client_golang/.gitignore new file mode 100644 index 000000000..f6fc2e8eb --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/.gitignore @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +*~ +*# +.build diff --git a/vendor/github.com/prometheus/client_golang/.travis.yml b/vendor/github.com/prometheus/client_golang/.travis.yml new file mode 100644 index 000000000..85b51152e --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/.travis.yml @@ -0,0 +1,10 @@ +sudo: false +language: go + +go: + - 1.6.3 + - 1.7 + - 1.8.1 + +script: + - go test -short ./... diff --git a/vendor/github.com/prometheus/client_golang/CHANGELOG.md b/vendor/github.com/prometheus/client_golang/CHANGELOG.md new file mode 100644 index 000000000..330788a4e --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/CHANGELOG.md @@ -0,0 +1,109 @@ +## 0.8.0 / 2016-08-17 +* [CHANGE] Registry is doing more consistency checks. This might break + existing setups that used to export inconsistent metrics. +* [CHANGE] Pushing to Pushgateway moved to package `push` and changed to allow + arbitrary grouping. +* [CHANGE] Removed `SelfCollector`. +* [CHANGE] Removed `PanicOnCollectError` and `EnableCollectChecks` methods. +* [CHANGE] Moved packages to the prometheus/common repo: `text`, `model`, + `extraction`. +* [CHANGE] Deprecated a number of functions. +* [FEATURE] Allow custom registries. Added `Registerer` and `Gatherer` + interfaces. +* [FEATURE] Separated HTTP exposition, allowing custom HTTP handlers (package + `promhttp`) and enabling the creation of other exposition mechanisms. +* [FEATURE] `MustRegister` is variadic now, allowing registration of many + collectors in one call. +* [FEATURE] Added HTTP API v1 package. +* [ENHANCEMENT] Numerous documentation improvements. +* [ENHANCEMENT] Improved metric sorting. +* [ENHANCEMENT] Inlined fnv64a hashing for improved performance. +* [ENHANCEMENT] Several test improvements. +* [BUGFIX] Handle collisions in MetricVec. + +## 0.7.0 / 2015-07-27 +* [CHANGE] Rename ExporterLabelPrefix to ExportedLabelPrefix. +* [BUGFIX] Closed gaps in metric consistency check. +* [BUGFIX] Validate LabelName/LabelSet on JSON unmarshaling. +* [ENHANCEMENT] Document the possibility to create "empty" metrics in + a metric vector. +* [ENHANCEMENT] Fix and clarify various doc comments and the README.md. +* [ENHANCEMENT] (Kind of) solve "The Proxy Problem" of http.InstrumentHandler. +* [ENHANCEMENT] Change responseWriterDelegator.written to int64. + +## 0.6.0 / 2015-06-01 +* [CHANGE] Rename process_goroutines to go_goroutines. +* [ENHANCEMENT] Validate label names during YAML decoding. +* [ENHANCEMENT] Add LabelName regular expression. +* [BUGFIX] Ensure alignment of struct members for 32-bit systems. + +## 0.5.0 / 2015-05-06 +* [BUGFIX] Removed a weakness in the fingerprinting aka signature code. + This makes fingerprinting slower and more allocation-heavy, but the + weakness was too severe to be tolerated. +* [CHANGE] As a result of the above, Metric.Fingerprint is now returning + a different fingerprint. To keep the same fingerprint, the new method + Metric.FastFingerprint was introduced, which will be used by the + Prometheus server for storage purposes (implying that a collision + detection has to be added, too). +* [ENHANCEMENT] The Metric.Equal and Metric.Before do not depend on + fingerprinting anymore, removing the possibility of an undetected + fingerprint collision. +* [FEATURE] The Go collector in the exposition library includes garbage + collection stats. +* [FEATURE] The exposition library allows to create constant "throw-away" + summaries and histograms. +* [CHANGE] A number of new reserved labels and prefixes. + +## 0.4.0 / 2015-04-08 +* [CHANGE] Return NaN when Summaries have no observations yet. +* [BUGFIX] Properly handle Summary decay upon Write(). +* [BUGFIX] Fix the documentation link to the consumption library. +* [FEATURE] Allow the metric family injection hook to merge with existing + metric families. +* [ENHANCEMENT] Removed cgo dependency and conditional compilation of procfs. +* [MAINTENANCE] Adjusted to changes in matttproud/golang_protobuf_extensions. + +## 0.3.2 / 2015-03-11 +* [BUGFIX] Fixed the receiver type of COWMetric.Set(). This method is + only used by the Prometheus server internally. +* [CLEANUP] Added licenses of vendored code left out by godep. + +## 0.3.1 / 2015-03-04 +* [ENHANCEMENT] Switched fingerprinting functions from own free list to + sync.Pool. +* [CHANGE] Makefile uses Go 1.4.2 now (only relevant for examples and tests). + +## 0.3.0 / 2015-03-03 +* [CHANGE] Changed the fingerprinting for metrics. THIS WILL INVALIDATE ALL + PERSISTED FINGERPRINTS. IF YOU COMPILE THE PROMETHEUS SERVER WITH THIS + VERSION, YOU HAVE TO WIPE THE PREVIOUSLY CREATED STORAGE. +* [CHANGE] LabelValuesToSignature removed. (Nobody had used it, and it was + arguably broken.) +* [CHANGE] Vendored dependencies. Those are only used by the Makefile. If + client_golang is used as a library, the vendoring will stay out of your way. +* [BUGFIX] Remove a weakness in the fingerprinting for metrics. (This made + the fingerprinting change above necessary.) +* [FEATURE] Added new fingerprinting functions SignatureForLabels and + SignatureWithoutLabels to be used by the Prometheus server. These functions + require fewer allocations than the ones currently used by the server. + +## 0.2.0 / 2015-02-23 +* [FEATURE] Introduce new Histagram metric type. +* [CHANGE] Ignore process collector errors for now (better error handling + pending). +* [CHANGE] Use clear error interface for process pidFn. +* [BUGFIX] Fix Go download links for several archs and OSes. +* [ENHANCEMENT] Massively improve Gauge and Counter performance. +* [ENHANCEMENT] Catch illegal label names for summaries in histograms. +* [ENHANCEMENT] Reduce allocations during fingerprinting. +* [ENHANCEMENT] Remove cgo dependency. procfs package will only be included if + both cgo is available and the build is for an OS with procfs. +* [CLEANUP] Clean up code style issues. +* [CLEANUP] Mark slow test as such and exclude them from travis. +* [CLEANUP] Update protobuf library package name. +* [CLEANUP] Updated vendoring of beorn7/perks. + +## 0.1.0 / 2015-02-02 +* [CLEANUP] Introduced semantic versioning and changelog. From now on, + changes will be reported in this file. diff --git a/vendor/github.com/prometheus/client_golang/CONTRIBUTING.md b/vendor/github.com/prometheus/client_golang/CONTRIBUTING.md new file mode 100644 index 000000000..40503edbf --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Contributing + +Prometheus uses GitHub to manage reviews of pull requests. + +* If you have a trivial fix or improvement, go ahead and create a pull request, + addressing (with `@...`) the maintainer of this repository (see + [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. + +* If you plan to do something more involved, first discuss your ideas + on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). + This will avoid unnecessary work and surely give you and us a good deal + of inspiration. + +* Relevant coding style guidelines are the [Go Code Review + Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) + and the _Formatting and style_ section of Peter Bourgon's [Go: Best + Practices for Production + Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/client_golang/MAINTAINERS.md b/vendor/github.com/prometheus/client_golang/MAINTAINERS.md new file mode 100644 index 000000000..3ede55fe1 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/MAINTAINERS.md @@ -0,0 +1 @@ +* Björn Rabenstein diff --git a/vendor/github.com/prometheus/client_golang/README.md b/vendor/github.com/prometheus/client_golang/README.md new file mode 100644 index 000000000..479290d27 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/README.md @@ -0,0 +1,47 @@ +# Prometheus Go client library + +[![Build Status](https://travis-ci.org/prometheus/client_golang.svg?branch=master)](https://travis-ci.org/prometheus/client_golang) +[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/client_golang)](https://goreportcard.com/report/github.com/prometheus/client_golang) + +This is the [Go](http://golang.org) client library for +[Prometheus](http://prometheus.io). It has two separate parts, one for +instrumenting application code, and one for creating clients that talk to the +Prometheus HTTP API. + +## Instrumenting applications + +[![code-coverage](http://gocover.io/_badge/github.com/prometheus/client_golang/prometheus)](http://gocover.io/github.com/prometheus/client_golang/prometheus) [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus) + +The +[`prometheus` directory](https://github.com/prometheus/client_golang/tree/master/prometheus) +contains the instrumentation library. See the +[best practices section](http://prometheus.io/docs/practices/naming/) of the +Prometheus documentation to learn more about instrumenting applications. + +The +[`examples` directory](https://github.com/prometheus/client_golang/tree/master/examples) +contains simple examples of instrumented code. + +## Client for the Prometheus HTTP API + +[![code-coverage](http://gocover.io/_badge/github.com/prometheus/client_golang/api/prometheus)](http://gocover.io/github.com/prometheus/client_golang/api/prometheus) [![go-doc](https://godoc.org/github.com/prometheus/client_golang/api/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/api/prometheus) + +The +[`api/prometheus` directory](https://github.com/prometheus/client_golang/tree/master/api/prometheus) +contains the client for the +[Prometheus HTTP API](http://prometheus.io/docs/querying/api/). It allows you +to write Go applications that query time series data from a Prometheus +server. It is still in alpha stage. + +## Where is `model`, `extraction`, and `text`? + +The `model` packages has been moved to +[`prometheus/common/model`](https://github.com/prometheus/common/tree/master/model). + +The `extraction` and `text` packages are now contained in +[`prometheus/common/expfmt`](https://github.com/prometheus/common/tree/master/expfmt). + +## Contributing and community + +See the [contributing guidelines](CONTRIBUTING.md) and the +[Community section](http://prometheus.io/community/) of the homepage. diff --git a/vendor/github.com/prometheus/client_golang/VERSION b/vendor/github.com/prometheus/client_golang/VERSION new file mode 100644 index 000000000..a3df0a695 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/VERSION @@ -0,0 +1 @@ +0.8.0 diff --git a/vendor/github.com/prometheus/client_golang/prometheus/.gitignore b/vendor/github.com/prometheus/client_golang/prometheus/.gitignore new file mode 100644 index 000000000..3460f0346 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/.gitignore @@ -0,0 +1 @@ +command-line-arguments.test diff --git a/vendor/github.com/prometheus/client_golang/prometheus/README.md b/vendor/github.com/prometheus/client_golang/prometheus/README.md new file mode 100644 index 000000000..44986bff0 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/README.md @@ -0,0 +1 @@ +See [![go-doc](https://godoc.org/github.com/prometheus/client_golang/prometheus?status.svg)](https://godoc.org/github.com/prometheus/client_golang/prometheus). diff --git a/vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go b/vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go new file mode 100644 index 000000000..faad39b4c --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go @@ -0,0 +1,185 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import ( + "sync" + "testing" +) + +func BenchmarkCounterWithLabelValues(b *testing.B) { + m := NewCounterVec( + CounterOpts{ + Name: "benchmark_counter", + Help: "A counter to benchmark it.", + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.WithLabelValues("eins", "zwei", "drei").Inc() + } +} + +func BenchmarkCounterWithLabelValuesConcurrent(b *testing.B) { + m := NewCounterVec( + CounterOpts{ + Name: "benchmark_counter", + Help: "A counter to benchmark it.", + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + for j := 0; j < b.N/10; j++ { + m.WithLabelValues("eins", "zwei", "drei").Inc() + } + wg.Done() + }() + } + wg.Wait() +} + +func BenchmarkCounterWithMappedLabels(b *testing.B) { + m := NewCounterVec( + CounterOpts{ + Name: "benchmark_counter", + Help: "A counter to benchmark it.", + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.With(Labels{"two": "zwei", "one": "eins", "three": "drei"}).Inc() + } +} + +func BenchmarkCounterWithPreparedMappedLabels(b *testing.B) { + m := NewCounterVec( + CounterOpts{ + Name: "benchmark_counter", + Help: "A counter to benchmark it.", + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + labels := Labels{"two": "zwei", "one": "eins", "three": "drei"} + for i := 0; i < b.N; i++ { + m.With(labels).Inc() + } +} + +func BenchmarkCounterNoLabels(b *testing.B) { + m := NewCounter(CounterOpts{ + Name: "benchmark_counter", + Help: "A counter to benchmark it.", + }) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Inc() + } +} + +func BenchmarkGaugeWithLabelValues(b *testing.B) { + m := NewGaugeVec( + GaugeOpts{ + Name: "benchmark_gauge", + Help: "A gauge to benchmark it.", + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.WithLabelValues("eins", "zwei", "drei").Set(3.1415) + } +} + +func BenchmarkGaugeNoLabels(b *testing.B) { + m := NewGauge(GaugeOpts{ + Name: "benchmark_gauge", + Help: "A gauge to benchmark it.", + }) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Set(3.1415) + } +} + +func BenchmarkSummaryWithLabelValues(b *testing.B) { + m := NewSummaryVec( + SummaryOpts{ + Name: "benchmark_summary", + Help: "A summary to benchmark it.", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.WithLabelValues("eins", "zwei", "drei").Observe(3.1415) + } +} + +func BenchmarkSummaryNoLabels(b *testing.B) { + m := NewSummary(SummaryOpts{ + Name: "benchmark_summary", + Help: "A summary to benchmark it.", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Observe(3.1415) + } +} + +func BenchmarkHistogramWithLabelValues(b *testing.B) { + m := NewHistogramVec( + HistogramOpts{ + Name: "benchmark_histogram", + Help: "A histogram to benchmark it.", + }, + []string{"one", "two", "three"}, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.WithLabelValues("eins", "zwei", "drei").Observe(3.1415) + } +} + +func BenchmarkHistogramNoLabels(b *testing.B) { + m := NewHistogram(HistogramOpts{ + Name: "benchmark_histogram", + Help: "A histogram to benchmark it.", + }, + ) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m.Observe(3.1415) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter_test.go b/vendor/github.com/prometheus/client_golang/prometheus/counter_test.go new file mode 100644 index 000000000..67391a23a --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter_test.go @@ -0,0 +1,58 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import ( + "math" + "testing" + + dto "github.com/prometheus/client_model/go" +) + +func TestCounterAdd(t *testing.T) { + counter := NewCounter(CounterOpts{ + Name: "test", + Help: "test help", + ConstLabels: Labels{"a": "1", "b": "2"}, + }).(*counter) + counter.Inc() + if expected, got := 1., math.Float64frombits(counter.valBits); expected != got { + t.Errorf("Expected %f, got %f.", expected, got) + } + counter.Add(42) + if expected, got := 43., math.Float64frombits(counter.valBits); expected != got { + t.Errorf("Expected %f, got %f.", expected, got) + } + + if expected, got := "counter cannot decrease in value", decreaseCounter(counter).Error(); expected != got { + t.Errorf("Expected error %q, got %q.", expected, got) + } + + m := &dto.Metric{} + counter.Write(m) + + if expected, got := `label: label: counter: `, m.String(); expected != got { + t.Errorf("expected %q, got %q", expected, got) + } +} + +func decreaseCounter(c *counter) (err error) { + defer func() { + if e := recover(); e != nil { + err = e.(error) + } + }() + c.Add(-1) + return nil +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/example_clustermanager_test.go b/vendor/github.com/prometheus/client_golang/prometheus/example_clustermanager_test.go new file mode 100644 index 000000000..260c1b52d --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/example_clustermanager_test.go @@ -0,0 +1,118 @@ +// Copyright 2014 The Prometheus 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 prometheus_test + +import "github.com/prometheus/client_golang/prometheus" + +// ClusterManager is an example for a system that might have been built without +// Prometheus in mind. It models a central manager of jobs running in a +// cluster. To turn it into something that collects Prometheus metrics, we +// simply add the two methods required for the Collector interface. +// +// An additional challenge is that multiple instances of the ClusterManager are +// run within the same binary, each in charge of a different zone. We need to +// make use of ConstLabels to be able to register each ClusterManager instance +// with Prometheus. +type ClusterManager struct { + Zone string + OOMCountDesc *prometheus.Desc + RAMUsageDesc *prometheus.Desc + // ... many more fields +} + +// ReallyExpensiveAssessmentOfTheSystemState is a mock for the data gathering a +// real cluster manager would have to do. Since it may actually be really +// expensive, it must only be called once per collection. This implementation, +// obviously, only returns some made-up data. +func (c *ClusterManager) ReallyExpensiveAssessmentOfTheSystemState() ( + oomCountByHost map[string]int, ramUsageByHost map[string]float64, +) { + // Just example fake data. + oomCountByHost = map[string]int{ + "foo.example.org": 42, + "bar.example.org": 2001, + } + ramUsageByHost = map[string]float64{ + "foo.example.org": 6.023e23, + "bar.example.org": 3.14, + } + return +} + +// Describe simply sends the two Descs in the struct to the channel. +func (c *ClusterManager) Describe(ch chan<- *prometheus.Desc) { + ch <- c.OOMCountDesc + ch <- c.RAMUsageDesc +} + +// Collect first triggers the ReallyExpensiveAssessmentOfTheSystemState. Then it +// creates constant metrics for each host on the fly based on the returned data. +// +// Note that Collect could be called concurrently, so we depend on +// ReallyExpensiveAssessmentOfTheSystemState to be concurrency-safe. +func (c *ClusterManager) Collect(ch chan<- prometheus.Metric) { + oomCountByHost, ramUsageByHost := c.ReallyExpensiveAssessmentOfTheSystemState() + for host, oomCount := range oomCountByHost { + ch <- prometheus.MustNewConstMetric( + c.OOMCountDesc, + prometheus.CounterValue, + float64(oomCount), + host, + ) + } + for host, ramUsage := range ramUsageByHost { + ch <- prometheus.MustNewConstMetric( + c.RAMUsageDesc, + prometheus.GaugeValue, + ramUsage, + host, + ) + } +} + +// NewClusterManager creates the two Descs OOMCountDesc and RAMUsageDesc. Note +// that the zone is set as a ConstLabel. (It's different in each instance of the +// ClusterManager, but constant over the lifetime of an instance.) Then there is +// a variable label "host", since we want to partition the collected metrics by +// host. Since all Descs created in this way are consistent across instances, +// with a guaranteed distinction by the "zone" label, we can register different +// ClusterManager instances with the same registry. +func NewClusterManager(zone string) *ClusterManager { + return &ClusterManager{ + Zone: zone, + OOMCountDesc: prometheus.NewDesc( + "clustermanager_oom_crashes_total", + "Number of OOM crashes.", + []string{"host"}, + prometheus.Labels{"zone": zone}, + ), + RAMUsageDesc: prometheus.NewDesc( + "clustermanager_ram_usage_bytes", + "RAM usage as reported to the cluster manager.", + []string{"host"}, + prometheus.Labels{"zone": zone}, + ), + } +} + +func ExampleCollector() { + workerDB := NewClusterManager("db") + workerCA := NewClusterManager("ca") + + // Since we are dealing with custom Collector implementations, it might + // be a good idea to try it out with a pedantic registry. + reg := prometheus.NewPedanticRegistry() + reg.MustRegister(workerDB) + reg.MustRegister(workerCA) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go b/vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go new file mode 100644 index 000000000..763788098 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go @@ -0,0 +1,71 @@ +// Copyright 2014 The Prometheus 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 prometheus_test + +import ( + "net/http" + + "github.com/prometheus/client_golang/prometheus" +) + +var ( + // apiRequestDuration tracks the duration separate for each HTTP status + // class (1xx, 2xx, ...). This creates a fair amount of time series on + // the Prometheus server. Usually, you would track the duration of + // serving HTTP request without partitioning by outcome. Do something + // like this only if needed. Also note how only status classes are + // tracked, not every single status code. The latter would create an + // even larger amount of time series. Request counters partitioned by + // status code are usually OK as each counter only creates one time + // series. Histograms are way more expensive, so partition with care and + // only where you really need separate latency tracking. Partitioning by + // status class is only an example. In concrete cases, other partitions + // might make more sense. + apiRequestDuration = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "api_request_duration_seconds", + Help: "Histogram for the request duration of the public API, partitioned by status class.", + Buckets: prometheus.ExponentialBuckets(0.1, 1.5, 5), + }, + []string{"status_class"}, + ) +) + +func handler(w http.ResponseWriter, r *http.Request) { + status := http.StatusOK + // The ObserverFunc gets called by the deferred ObserveDuration and + // decides wich Histogram's Observe method is called. + timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) { + switch { + case status >= 500: // Server error. + apiRequestDuration.WithLabelValues("5xx").Observe(v) + case status >= 400: // Client error. + apiRequestDuration.WithLabelValues("4xx").Observe(v) + case status >= 300: // Redirection. + apiRequestDuration.WithLabelValues("3xx").Observe(v) + case status >= 200: // Success. + apiRequestDuration.WithLabelValues("2xx").Observe(v) + default: // Informational. + apiRequestDuration.WithLabelValues("1xx").Observe(v) + } + })) + defer timer.ObserveDuration() + + // Handle the request. Set status accordingly. + // ... +} + +func ExampleTimer_complex() { + http.HandleFunc("/api", handler) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go b/vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go new file mode 100644 index 000000000..7184a0d1d --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go @@ -0,0 +1,48 @@ +// Copyright 2014 The Prometheus 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 prometheus_test + +import ( + "os" + + "github.com/prometheus/client_golang/prometheus" +) + +var ( + // If a function is called rarely (i.e. not more often than scrapes + // happen) or ideally only once (like in a batch job), it can make sense + // to use a Gauge for timing the function call. For timing a batch job + // and pushing the result to a Pushgateway, see also the comprehensive + // example in the push package. + funcDuration = prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "example_function_duration_seconds", + Help: "Duration of the last call of an example function.", + }) +) + +func run() error { + // The Set method of the Gauge is used to observe the duration. + timer := prometheus.NewTimer(prometheus.ObserverFunc(funcDuration.Set)) + defer timer.ObserveDuration() + + // Do something. Return errors as encountered. The use of 'defer' above + // makes sure the function is still timed properly. + return nil +} + +func ExampleTimer_gauge() { + if err := run(); err != nil { + os.Exit(1) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go b/vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go new file mode 100644 index 000000000..bd86bb472 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go @@ -0,0 +1,40 @@ +// Copyright 2014 The Prometheus 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 prometheus_test + +import ( + "math/rand" + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +var ( + requestDuration = prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "example_request_duration_seconds", + Help: "Histogram for the runtime of a simple example function.", + Buckets: prometheus.LinearBuckets(0.01, 0.01, 10), + }) +) + +func ExampleTimer() { + // timer times this example function. It uses a Histogram, but a Summary + // would also work, as both implement Observer. Check out + // https://prometheus.io/docs/practices/histograms/ for differences. + timer := prometheus.NewTimer(requestDuration) + defer timer.ObserveDuration() + + // Do something here that takes time. + time.Sleep(time.Duration(rand.NormFloat64()*10000+50000) * time.Microsecond) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/examples_test.go b/vendor/github.com/prometheus/client_golang/prometheus/examples_test.go new file mode 100644 index 000000000..45f60650f --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/examples_test.go @@ -0,0 +1,754 @@ +// Copyright 2014 The Prometheus 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 prometheus_test + +import ( + "bytes" + "fmt" + "math" + "net/http" + "runtime" + "sort" + "strings" + + dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" + + "github.com/golang/protobuf/proto" + + "github.com/prometheus/client_golang/prometheus" +) + +func ExampleGauge() { + opsQueued := prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "our_company", + Subsystem: "blob_storage", + Name: "ops_queued", + Help: "Number of blob storage operations waiting to be processed.", + }) + prometheus.MustRegister(opsQueued) + + // 10 operations queued by the goroutine managing incoming requests. + opsQueued.Add(10) + // A worker goroutine has picked up a waiting operation. + opsQueued.Dec() + // And once more... + opsQueued.Dec() +} + +func ExampleGaugeVec() { + opsQueued := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: "our_company", + Subsystem: "blob_storage", + Name: "ops_queued", + Help: "Number of blob storage operations waiting to be processed, partitioned by user and type.", + }, + []string{ + // Which user has requested the operation? + "user", + // Of what type is the operation? + "type", + }, + ) + prometheus.MustRegister(opsQueued) + + // Increase a value using compact (but order-sensitive!) WithLabelValues(). + opsQueued.WithLabelValues("bob", "put").Add(4) + // Increase a value with a map using WithLabels. More verbose, but order + // doesn't matter anymore. + opsQueued.With(prometheus.Labels{"type": "delete", "user": "alice"}).Inc() +} + +func ExampleGaugeFunc() { + if err := prometheus.Register(prometheus.NewGaugeFunc( + prometheus.GaugeOpts{ + Subsystem: "runtime", + Name: "goroutines_count", + Help: "Number of goroutines that currently exist.", + }, + func() float64 { return float64(runtime.NumGoroutine()) }, + )); err == nil { + fmt.Println("GaugeFunc 'goroutines_count' registered.") + } + // Note that the count of goroutines is a gauge (and not a counter) as + // it can go up and down. + + // Output: + // GaugeFunc 'goroutines_count' registered. +} + +func ExampleCounter() { + pushCounter := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "repository_pushes", // Note: No help string... + }) + err := prometheus.Register(pushCounter) // ... so this will return an error. + if err != nil { + fmt.Println("Push counter couldn't be registered, no counting will happen:", err) + return + } + + // Try it once more, this time with a help string. + pushCounter = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "repository_pushes", + Help: "Number of pushes to external repository.", + }) + err = prometheus.Register(pushCounter) + if err != nil { + fmt.Println("Push counter couldn't be registered AGAIN, no counting will happen:", err) + return + } + + pushComplete := make(chan struct{}) + // TODO: Start a goroutine that performs repository pushes and reports + // each completion via the channel. + for range pushComplete { + pushCounter.Inc() + } + // Output: + // Push counter couldn't be registered, no counting will happen: descriptor Desc{fqName: "repository_pushes", help: "", constLabels: {}, variableLabels: []} is invalid: empty help string +} + +func ExampleCounterVec() { + httpReqs := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "http_requests_total", + Help: "How many HTTP requests processed, partitioned by status code and HTTP method.", + }, + []string{"code", "method"}, + ) + prometheus.MustRegister(httpReqs) + + httpReqs.WithLabelValues("404", "POST").Add(42) + + // If you have to access the same set of labels very frequently, it + // might be good to retrieve the metric only once and keep a handle to + // it. But beware of deletion of that metric, see below! + m := httpReqs.WithLabelValues("200", "GET") + for i := 0; i < 1000000; i++ { + m.Inc() + } + // Delete a metric from the vector. If you have previously kept a handle + // to that metric (as above), future updates via that handle will go + // unseen (even if you re-create a metric with the same label set + // later). + httpReqs.DeleteLabelValues("200", "GET") + // Same thing with the more verbose Labels syntax. + httpReqs.Delete(prometheus.Labels{"method": "GET", "code": "200"}) +} + +func ExampleInstrumentHandler() { + // Handle the "/doc" endpoint with the standard http.FileServer handler. + // By wrapping the handler with InstrumentHandler, request count, + // request and response sizes, and request latency are automatically + // exported to Prometheus, partitioned by HTTP status code and method + // and by the handler name (here "fileserver"). + http.Handle("/doc", prometheus.InstrumentHandler( + "fileserver", http.FileServer(http.Dir("/usr/share/doc")), + )) + // The Prometheus handler still has to be registered to handle the + // "/metrics" endpoint. The handler returned by prometheus.Handler() is + // already instrumented - with "prometheus" as the handler name. In this + // example, we want the handler name to be "metrics", so we instrument + // the uninstrumented Prometheus handler ourselves. + http.Handle("/metrics", prometheus.InstrumentHandler( + "metrics", prometheus.UninstrumentedHandler(), + )) +} + +func ExampleLabelPairSorter() { + labelPairs := []*dto.LabelPair{ + {Name: proto.String("status"), Value: proto.String("404")}, + {Name: proto.String("method"), Value: proto.String("get")}, + } + + sort.Sort(prometheus.LabelPairSorter(labelPairs)) + + fmt.Println(labelPairs) + // Output: + // [name:"method" value:"get" name:"status" value:"404" ] +} + +func ExampleRegister() { + // Imagine you have a worker pool and want to count the tasks completed. + taskCounter := prometheus.NewCounter(prometheus.CounterOpts{ + Subsystem: "worker_pool", + Name: "completed_tasks_total", + Help: "Total number of tasks completed.", + }) + // This will register fine. + if err := prometheus.Register(taskCounter); err != nil { + fmt.Println(err) + } else { + fmt.Println("taskCounter registered.") + } + // Don't forget to tell the HTTP server about the Prometheus handler. + // (In a real program, you still need to start the HTTP server...) + http.Handle("/metrics", prometheus.Handler()) + + // Now you can start workers and give every one of them a pointer to + // taskCounter and let it increment it whenever it completes a task. + taskCounter.Inc() // This has to happen somewhere in the worker code. + + // But wait, you want to see how individual workers perform. So you need + // a vector of counters, with one element for each worker. + taskCounterVec := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: "worker_pool", + Name: "completed_tasks_total", + Help: "Total number of tasks completed.", + }, + []string{"worker_id"}, + ) + + // Registering will fail because we already have a metric of that name. + if err := prometheus.Register(taskCounterVec); err != nil { + fmt.Println("taskCounterVec not registered:", err) + } else { + fmt.Println("taskCounterVec registered.") + } + + // To fix, first unregister the old taskCounter. + if prometheus.Unregister(taskCounter) { + fmt.Println("taskCounter unregistered.") + } + + // Try registering taskCounterVec again. + if err := prometheus.Register(taskCounterVec); err != nil { + fmt.Println("taskCounterVec not registered:", err) + } else { + fmt.Println("taskCounterVec registered.") + } + // Bummer! Still doesn't work. + + // Prometheus will not allow you to ever export metrics with + // inconsistent help strings or label names. After unregistering, the + // unregistered metrics will cease to show up in the /metrics HTTP + // response, but the registry still remembers that those metrics had + // been exported before. For this example, we will now choose a + // different name. (In a real program, you would obviously not export + // the obsolete metric in the first place.) + taskCounterVec = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Subsystem: "worker_pool", + Name: "completed_tasks_by_id", + Help: "Total number of tasks completed.", + }, + []string{"worker_id"}, + ) + if err := prometheus.Register(taskCounterVec); err != nil { + fmt.Println("taskCounterVec not registered:", err) + } else { + fmt.Println("taskCounterVec registered.") + } + // Finally it worked! + + // The workers have to tell taskCounterVec their id to increment the + // right element in the metric vector. + taskCounterVec.WithLabelValues("42").Inc() // Code from worker 42. + + // Each worker could also keep a reference to their own counter element + // around. Pick the counter at initialization time of the worker. + myCounter := taskCounterVec.WithLabelValues("42") // From worker 42 initialization code. + myCounter.Inc() // Somewhere in the code of that worker. + + // Note that something like WithLabelValues("42", "spurious arg") would + // panic (because you have provided too many label values). If you want + // to get an error instead, use GetMetricWithLabelValues(...) instead. + notMyCounter, err := taskCounterVec.GetMetricWithLabelValues("42", "spurious arg") + if err != nil { + fmt.Println("Worker initialization failed:", err) + } + if notMyCounter == nil { + fmt.Println("notMyCounter is nil.") + } + + // A different (and somewhat tricky) approach is to use + // ConstLabels. ConstLabels are pairs of label names and label values + // that never change. You might ask what those labels are good for (and + // rightfully so - if they never change, they could as well be part of + // the metric name). There are essentially two use-cases: The first is + // if labels are constant throughout the lifetime of a binary execution, + // but they vary over time or between different instances of a running + // binary. The second is what we have here: Each worker creates and + // registers an own Counter instance where the only difference is in the + // value of the ConstLabels. Those Counters can all be registered + // because the different ConstLabel values guarantee that each worker + // will increment a different Counter metric. + counterOpts := prometheus.CounterOpts{ + Subsystem: "worker_pool", + Name: "completed_tasks", + Help: "Total number of tasks completed.", + ConstLabels: prometheus.Labels{"worker_id": "42"}, + } + taskCounterForWorker42 := prometheus.NewCounter(counterOpts) + if err := prometheus.Register(taskCounterForWorker42); err != nil { + fmt.Println("taskCounterVForWorker42 not registered:", err) + } else { + fmt.Println("taskCounterForWorker42 registered.") + } + // Obviously, in real code, taskCounterForWorker42 would be a member + // variable of a worker struct, and the "42" would be retrieved with a + // GetId() method or something. The Counter would be created and + // registered in the initialization code of the worker. + + // For the creation of the next Counter, we can recycle + // counterOpts. Just change the ConstLabels. + counterOpts.ConstLabels = prometheus.Labels{"worker_id": "2001"} + taskCounterForWorker2001 := prometheus.NewCounter(counterOpts) + if err := prometheus.Register(taskCounterForWorker2001); err != nil { + fmt.Println("taskCounterVForWorker2001 not registered:", err) + } else { + fmt.Println("taskCounterForWorker2001 registered.") + } + + taskCounterForWorker2001.Inc() + taskCounterForWorker42.Inc() + taskCounterForWorker2001.Inc() + + // Yet another approach would be to turn the workers themselves into + // Collectors and register them. See the Collector example for details. + + // Output: + // taskCounter registered. + // taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", constLabels: {}, variableLabels: [worker_id]} has different label names or a different help string + // taskCounter unregistered. + // taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", constLabels: {}, variableLabels: [worker_id]} has different label names or a different help string + // taskCounterVec registered. + // Worker initialization failed: inconsistent label cardinality + // notMyCounter is nil. + // taskCounterForWorker42 registered. + // taskCounterForWorker2001 registered. +} + +func ExampleSummary() { + temps := prometheus.NewSummary(prometheus.SummaryOpts{ + Name: "pond_temperature_celsius", + Help: "The temperature of the frog pond.", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }) + + // Simulate some observations. + for i := 0; i < 1000; i++ { + temps.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10) + } + + // Just for demonstration, let's check the state of the summary by + // (ab)using its Write method (which is usually only used by Prometheus + // internally). + metric := &dto.Metric{} + temps.Write(metric) + fmt.Println(proto.MarshalTextString(metric)) + + // Output: + // summary: < + // sample_count: 1000 + // sample_sum: 29969.50000000001 + // quantile: < + // quantile: 0.5 + // value: 31.1 + // > + // quantile: < + // quantile: 0.9 + // value: 41.3 + // > + // quantile: < + // quantile: 0.99 + // value: 41.9 + // > + // > +} + +func ExampleSummaryVec() { + temps := prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Name: "pond_temperature_celsius", + Help: "The temperature of the frog pond.", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, + []string{"species"}, + ) + + // Simulate some observations. + for i := 0; i < 1000; i++ { + temps.WithLabelValues("litoria-caerulea").Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10) + temps.WithLabelValues("lithobates-catesbeianus").Observe(32 + math.Floor(100*math.Cos(float64(i)*0.11))/10) + } + + // Create a Summary without any observations. + temps.WithLabelValues("leiopelma-hochstetteri") + + // Just for demonstration, let's check the state of the summary vector + // by registering it with a custom registry and then let it collect the + // metrics. + reg := prometheus.NewRegistry() + reg.MustRegister(temps) + + metricFamilies, err := reg.Gather() + if err != nil || len(metricFamilies) != 1 { + panic("unexpected behavior of custom test registry") + } + fmt.Println(proto.MarshalTextString(metricFamilies[0])) + + // Output: + // name: "pond_temperature_celsius" + // help: "The temperature of the frog pond." + // type: SUMMARY + // metric: < + // label: < + // name: "species" + // value: "leiopelma-hochstetteri" + // > + // summary: < + // sample_count: 0 + // sample_sum: 0 + // quantile: < + // quantile: 0.5 + // value: nan + // > + // quantile: < + // quantile: 0.9 + // value: nan + // > + // quantile: < + // quantile: 0.99 + // value: nan + // > + // > + // > + // metric: < + // label: < + // name: "species" + // value: "lithobates-catesbeianus" + // > + // summary: < + // sample_count: 1000 + // sample_sum: 31956.100000000017 + // quantile: < + // quantile: 0.5 + // value: 32.4 + // > + // quantile: < + // quantile: 0.9 + // value: 41.4 + // > + // quantile: < + // quantile: 0.99 + // value: 41.9 + // > + // > + // > + // metric: < + // label: < + // name: "species" + // value: "litoria-caerulea" + // > + // summary: < + // sample_count: 1000 + // sample_sum: 29969.50000000001 + // quantile: < + // quantile: 0.5 + // value: 31.1 + // > + // quantile: < + // quantile: 0.9 + // value: 41.3 + // > + // quantile: < + // quantile: 0.99 + // value: 41.9 + // > + // > + // > +} + +func ExampleNewConstSummary() { + desc := prometheus.NewDesc( + "http_request_duration_seconds", + "A summary of the HTTP request durations.", + []string{"code", "method"}, + prometheus.Labels{"owner": "example"}, + ) + + // Create a constant summary from values we got from a 3rd party telemetry system. + s := prometheus.MustNewConstSummary( + desc, + 4711, 403.34, + map[float64]float64{0.5: 42.3, 0.9: 323.3}, + "200", "get", + ) + + // Just for demonstration, let's check the state of the summary by + // (ab)using its Write method (which is usually only used by Prometheus + // internally). + metric := &dto.Metric{} + s.Write(metric) + fmt.Println(proto.MarshalTextString(metric)) + + // Output: + // label: < + // name: "code" + // value: "200" + // > + // label: < + // name: "method" + // value: "get" + // > + // label: < + // name: "owner" + // value: "example" + // > + // summary: < + // sample_count: 4711 + // sample_sum: 403.34 + // quantile: < + // quantile: 0.5 + // value: 42.3 + // > + // quantile: < + // quantile: 0.9 + // value: 323.3 + // > + // > +} + +func ExampleHistogram() { + temps := prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "pond_temperature_celsius", + Help: "The temperature of the frog pond.", // Sorry, we can't measure how badly it smells. + Buckets: prometheus.LinearBuckets(20, 5, 5), // 5 buckets, each 5 centigrade wide. + }) + + // Simulate some observations. + for i := 0; i < 1000; i++ { + temps.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10) + } + + // Just for demonstration, let's check the state of the histogram by + // (ab)using its Write method (which is usually only used by Prometheus + // internally). + metric := &dto.Metric{} + temps.Write(metric) + fmt.Println(proto.MarshalTextString(metric)) + + // Output: + // histogram: < + // sample_count: 1000 + // sample_sum: 29969.50000000001 + // bucket: < + // cumulative_count: 192 + // upper_bound: 20 + // > + // bucket: < + // cumulative_count: 366 + // upper_bound: 25 + // > + // bucket: < + // cumulative_count: 501 + // upper_bound: 30 + // > + // bucket: < + // cumulative_count: 638 + // upper_bound: 35 + // > + // bucket: < + // cumulative_count: 816 + // upper_bound: 40 + // > + // > +} + +func ExampleNewConstHistogram() { + desc := prometheus.NewDesc( + "http_request_duration_seconds", + "A histogram of the HTTP request durations.", + []string{"code", "method"}, + prometheus.Labels{"owner": "example"}, + ) + + // Create a constant histogram from values we got from a 3rd party telemetry system. + h := prometheus.MustNewConstHistogram( + desc, + 4711, 403.34, + map[float64]uint64{25: 121, 50: 2403, 100: 3221, 200: 4233}, + "200", "get", + ) + + // Just for demonstration, let's check the state of the histogram by + // (ab)using its Write method (which is usually only used by Prometheus + // internally). + metric := &dto.Metric{} + h.Write(metric) + fmt.Println(proto.MarshalTextString(metric)) + + // Output: + // label: < + // name: "code" + // value: "200" + // > + // label: < + // name: "method" + // value: "get" + // > + // label: < + // name: "owner" + // value: "example" + // > + // histogram: < + // sample_count: 4711 + // sample_sum: 403.34 + // bucket: < + // cumulative_count: 121 + // upper_bound: 25 + // > + // bucket: < + // cumulative_count: 2403 + // upper_bound: 50 + // > + // bucket: < + // cumulative_count: 3221 + // upper_bound: 100 + // > + // bucket: < + // cumulative_count: 4233 + // upper_bound: 200 + // > + // > +} + +func ExampleAlreadyRegisteredError() { + reqCounter := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "requests_total", + Help: "The total number of requests served.", + }) + if err := prometheus.Register(reqCounter); err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + // A counter for that metric has been registered before. + // Use the old counter from now on. + reqCounter = are.ExistingCollector.(prometheus.Counter) + } else { + // Something else went wrong! + panic(err) + } + } + reqCounter.Inc() +} + +func ExampleGatherers() { + reg := prometheus.NewRegistry() + temp := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "temperature_kelvin", + Help: "Temperature in Kelvin.", + }, + []string{"location"}, + ) + reg.MustRegister(temp) + temp.WithLabelValues("outside").Set(273.14) + temp.WithLabelValues("inside").Set(298.44) + + var parser expfmt.TextParser + + text := ` +# TYPE humidity_percent gauge +# HELP humidity_percent Humidity in %. +humidity_percent{location="outside"} 45.4 +humidity_percent{location="inside"} 33.2 +# TYPE temperature_kelvin gauge +# HELP temperature_kelvin Temperature in Kelvin. +temperature_kelvin{location="somewhere else"} 4.5 +` + + parseText := func() ([]*dto.MetricFamily, error) { + parsed, err := parser.TextToMetricFamilies(strings.NewReader(text)) + if err != nil { + return nil, err + } + var result []*dto.MetricFamily + for _, mf := range parsed { + result = append(result, mf) + } + return result, nil + } + + gatherers := prometheus.Gatherers{ + reg, + prometheus.GathererFunc(parseText), + } + + gathering, err := gatherers.Gather() + if err != nil { + fmt.Println(err) + } + + out := &bytes.Buffer{} + for _, mf := range gathering { + if _, err := expfmt.MetricFamilyToText(out, mf); err != nil { + panic(err) + } + } + fmt.Print(out.String()) + fmt.Println("----------") + + // Note how the temperature_kelvin metric family has been merged from + // different sources. Now try + text = ` +# TYPE humidity_percent gauge +# HELP humidity_percent Humidity in %. +humidity_percent{location="outside"} 45.4 +humidity_percent{location="inside"} 33.2 +# TYPE temperature_kelvin gauge +# HELP temperature_kelvin Temperature in Kelvin. +# Duplicate metric: +temperature_kelvin{location="outside"} 265.3 + # Wrong labels: +temperature_kelvin 4.5 +` + + gathering, err = gatherers.Gather() + if err != nil { + fmt.Println(err) + } + // Note that still as many metrics as possible are returned: + out.Reset() + for _, mf := range gathering { + if _, err := expfmt.MetricFamilyToText(out, mf); err != nil { + panic(err) + } + } + fmt.Print(out.String()) + + // Output: + // # HELP humidity_percent Humidity in %. + // # TYPE humidity_percent gauge + // humidity_percent{location="inside"} 33.2 + // humidity_percent{location="outside"} 45.4 + // # HELP temperature_kelvin Temperature in Kelvin. + // # TYPE temperature_kelvin gauge + // temperature_kelvin{location="inside"} 298.44 + // temperature_kelvin{location="outside"} 273.14 + // temperature_kelvin{location="somewhere else"} 4.5 + // ---------- + // 2 error(s) occurred: + // * collected metric temperature_kelvin label: gauge: was collected before with the same name and label values + // * collected metric temperature_kelvin gauge: has label dimensions inconsistent with previously collected metrics in the same metric family + // # HELP humidity_percent Humidity in %. + // # TYPE humidity_percent gauge + // humidity_percent{location="inside"} 33.2 + // humidity_percent{location="outside"} 45.4 + // # HELP temperature_kelvin Temperature in Kelvin. + // # TYPE temperature_kelvin gauge + // temperature_kelvin{location="inside"} 298.44 + // temperature_kelvin{location="outside"} 273.14 +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector_test.go b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector_test.go new file mode 100644 index 000000000..910dac325 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/expvar_collector_test.go @@ -0,0 +1,97 @@ +// Copyright 2014 The Prometheus 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 prometheus_test + +import ( + "expvar" + "fmt" + "sort" + "strings" + + dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/client_golang/prometheus" +) + +func ExampleNewExpvarCollector() { + expvarCollector := prometheus.NewExpvarCollector(map[string]*prometheus.Desc{ + "memstats": prometheus.NewDesc( + "expvar_memstats", + "All numeric memstats as one metric family. Not a good role-model, actually... ;-)", + []string{"type"}, nil, + ), + "lone-int": prometheus.NewDesc( + "expvar_lone_int", + "Just an expvar int as an example.", + nil, nil, + ), + "http-request-map": prometheus.NewDesc( + "expvar_http_request_total", + "How many http requests processed, partitioned by status code and http method.", + []string{"code", "method"}, nil, + ), + }) + prometheus.MustRegister(expvarCollector) + + // The Prometheus part is done here. But to show that this example is + // doing anything, we have to manually export something via expvar. In + // real-life use-cases, some library would already have exported via + // expvar what we want to re-export as Prometheus metrics. + expvar.NewInt("lone-int").Set(42) + expvarMap := expvar.NewMap("http-request-map") + var ( + expvarMap1, expvarMap2 expvar.Map + expvarInt11, expvarInt12, expvarInt21, expvarInt22 expvar.Int + ) + expvarMap1.Init() + expvarMap2.Init() + expvarInt11.Set(3) + expvarInt12.Set(13) + expvarInt21.Set(11) + expvarInt22.Set(212) + expvarMap1.Set("POST", &expvarInt11) + expvarMap1.Set("GET", &expvarInt12) + expvarMap2.Set("POST", &expvarInt21) + expvarMap2.Set("GET", &expvarInt22) + expvarMap.Set("404", &expvarMap1) + expvarMap.Set("200", &expvarMap2) + // Results in the following expvar map: + // "http-request-count": {"200": {"POST": 11, "GET": 212}, "404": {"POST": 3, "GET": 13}} + + // Let's see what the scrape would yield, but exclude the memstats metrics. + metricStrings := []string{} + metric := dto.Metric{} + metricChan := make(chan prometheus.Metric) + go func() { + expvarCollector.Collect(metricChan) + close(metricChan) + }() + for m := range metricChan { + if strings.Index(m.Desc().String(), "expvar_memstats") == -1 { + metric.Reset() + m.Write(&metric) + metricStrings = append(metricStrings, metric.String()) + } + } + sort.Strings(metricStrings) + for _, s := range metricStrings { + fmt.Println(strings.TrimRight(s, " ")) + } + // Output: + // label: label: untyped: + // label: label: untyped: + // label: label: untyped: + // label: label: untyped: + // untyped: +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go new file mode 100644 index 000000000..8e5f002c9 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go @@ -0,0 +1,202 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import ( + "math" + "math/rand" + "sync" + "testing" + "testing/quick" + "time" + + dto "github.com/prometheus/client_model/go" +) + +func listenGaugeStream(vals, result chan float64, done chan struct{}) { + var sum float64 +outer: + for { + select { + case <-done: + close(vals) + for v := range vals { + sum += v + } + break outer + case v := <-vals: + sum += v + } + } + result <- sum + close(result) +} + +func TestGaugeConcurrency(t *testing.T) { + it := func(n uint32) bool { + mutations := int(n % 10000) + concLevel := int(n%15 + 1) + + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + sStream := make(chan float64, mutations*concLevel) + result := make(chan float64) + done := make(chan struct{}) + + go listenGaugeStream(sStream, result, done) + go func() { + end.Wait() + close(done) + }() + + gge := NewGauge(GaugeOpts{ + Name: "test_gauge", + Help: "no help can be found here", + }) + for i := 0; i < concLevel; i++ { + vals := make([]float64, mutations) + for j := 0; j < mutations; j++ { + vals[j] = rand.Float64() - 0.5 + } + + go func(vals []float64) { + start.Wait() + for _, v := range vals { + sStream <- v + gge.Add(v) + } + end.Done() + }(vals) + } + start.Done() + + if expected, got := <-result, math.Float64frombits(gge.(*value).valBits); math.Abs(expected-got) > 0.000001 { + t.Fatalf("expected approx. %f, got %f", expected, got) + return false + } + return true + } + + if err := quick.Check(it, nil); err != nil { + t.Fatal(err) + } +} + +func TestGaugeVecConcurrency(t *testing.T) { + it := func(n uint32) bool { + mutations := int(n % 10000) + concLevel := int(n%15 + 1) + vecLength := int(n%5 + 1) + + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + sStreams := make([]chan float64, vecLength) + results := make([]chan float64, vecLength) + done := make(chan struct{}) + + for i := 0; i < vecLength; i++ { + sStreams[i] = make(chan float64, mutations*concLevel) + results[i] = make(chan float64) + go listenGaugeStream(sStreams[i], results[i], done) + } + + go func() { + end.Wait() + close(done) + }() + + gge := NewGaugeVec( + GaugeOpts{ + Name: "test_gauge", + Help: "no help can be found here", + }, + []string{"label"}, + ) + for i := 0; i < concLevel; i++ { + vals := make([]float64, mutations) + pick := make([]int, mutations) + for j := 0; j < mutations; j++ { + vals[j] = rand.Float64() - 0.5 + pick[j] = rand.Intn(vecLength) + } + + go func(vals []float64) { + start.Wait() + for i, v := range vals { + sStreams[pick[i]] <- v + gge.WithLabelValues(string('A' + pick[i])).Add(v) + } + end.Done() + }(vals) + } + start.Done() + + for i := range sStreams { + if expected, got := <-results[i], math.Float64frombits(gge.WithLabelValues(string('A'+i)).(*value).valBits); math.Abs(expected-got) > 0.000001 { + t.Fatalf("expected approx. %f, got %f", expected, got) + return false + } + } + return true + } + + if err := quick.Check(it, nil); err != nil { + t.Fatal(err) + } +} + +func TestGaugeFunc(t *testing.T) { + gf := NewGaugeFunc( + GaugeOpts{ + Name: "test_name", + Help: "test help", + ConstLabels: Labels{"a": "1", "b": "2"}, + }, + func() float64 { return 3.1415 }, + ) + + if expected, got := `Desc{fqName: "test_name", help: "test help", constLabels: {a="1",b="2"}, variableLabels: []}`, gf.Desc().String(); expected != got { + t.Errorf("expected %q, got %q", expected, got) + } + + m := &dto.Metric{} + gf.Write(m) + + if expected, got := `label: label: gauge: `, m.String(); expected != got { + t.Errorf("expected %q, got %q", expected, got) + } +} + +func TestGaugeSetCurrentTime(t *testing.T) { + g := NewGauge(GaugeOpts{ + Name: "test_name", + Help: "test help", + }) + g.SetToCurrentTime() + unixTime := float64(time.Now().Unix()) + + m := &dto.Metric{} + g.Write(m) + + delta := unixTime - m.GetGauge().GetValue() + // This is just a smoke test to make sure SetToCurrentTime is not + // totally off. Tests with current time involved are hard... + if math.Abs(delta) > 5 { + t.Errorf("Gauge set to current time deviates from current time by more than 5s, delta is %f seconds", delta) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go new file mode 100644 index 000000000..59dabc09c --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go @@ -0,0 +1,126 @@ +package prometheus + +import ( + "runtime" + "testing" + "time" + + dto "github.com/prometheus/client_model/go" +) + +func TestGoCollector(t *testing.T) { + var ( + c = NewGoCollector() + ch = make(chan Metric) + waitc = make(chan struct{}) + closec = make(chan struct{}) + old = -1 + ) + defer close(closec) + + go func() { + c.Collect(ch) + go func(c <-chan struct{}) { + <-c + }(closec) + <-waitc + c.Collect(ch) + }() + + for { + select { + case m := <-ch: + // m can be Gauge or Counter, + // currently just test the go_goroutines Gauge + // and ignore others. + if m.Desc().fqName != "go_goroutines" { + continue + } + pb := &dto.Metric{} + m.Write(pb) + if pb.GetGauge() == nil { + continue + } + + if old == -1 { + old = int(pb.GetGauge().GetValue()) + close(waitc) + continue + } + + if diff := int(pb.GetGauge().GetValue()) - old; diff != 1 { + // TODO: This is flaky in highly concurrent situations. + t.Errorf("want 1 new goroutine, got %d", diff) + } + + // GoCollector performs three sends per call. + // On line 27 we need to receive the second send + // to shut down cleanly. + <-ch + <-ch + return + case <-time.After(1 * time.Second): + t.Fatalf("expected collect timed out") + } + } +} + +func TestGCCollector(t *testing.T) { + var ( + c = NewGoCollector() + ch = make(chan Metric) + waitc = make(chan struct{}) + closec = make(chan struct{}) + oldGC uint64 + oldPause float64 + ) + defer close(closec) + + go func() { + c.Collect(ch) + // force GC + runtime.GC() + <-waitc + c.Collect(ch) + }() + + first := true + for { + select { + case metric := <-ch: + switch m := metric.(type) { + case *constSummary, *value: + pb := &dto.Metric{} + m.Write(pb) + if pb.GetSummary() == nil { + continue + } + + if len(pb.GetSummary().Quantile) != 5 { + t.Errorf("expected 4 buckets, got %d", len(pb.GetSummary().Quantile)) + } + for idx, want := range []float64{0.0, 0.25, 0.5, 0.75, 1.0} { + if *pb.GetSummary().Quantile[idx].Quantile != want { + t.Errorf("bucket #%d is off, got %f, want %f", idx, *pb.GetSummary().Quantile[idx].Quantile, want) + } + } + if first { + first = false + oldGC = *pb.GetSummary().SampleCount + oldPause = *pb.GetSummary().SampleSum + close(waitc) + continue + } + if diff := *pb.GetSummary().SampleCount - oldGC; diff != 1 { + t.Errorf("want 1 new garbage collection run, got %d", diff) + } + if diff := *pb.GetSummary().SampleSum - oldPause; diff <= 0 { + t.Errorf("want moar pause, got %f", diff) + } + return + } + case <-time.After(1 * time.Second): + t.Fatalf("expected collect timed out") + } + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go new file mode 100644 index 000000000..5a20f4b6b --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go @@ -0,0 +1,348 @@ +// Copyright 2015 The Prometheus 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 prometheus + +import ( + "math" + "math/rand" + "reflect" + "sort" + "sync" + "testing" + "testing/quick" + + dto "github.com/prometheus/client_model/go" +) + +func benchmarkHistogramObserve(w int, b *testing.B) { + b.StopTimer() + + wg := new(sync.WaitGroup) + wg.Add(w) + + g := new(sync.WaitGroup) + g.Add(1) + + s := NewHistogram(HistogramOpts{}) + + for i := 0; i < w; i++ { + go func() { + g.Wait() + + for i := 0; i < b.N; i++ { + s.Observe(float64(i)) + } + + wg.Done() + }() + } + + b.StartTimer() + g.Done() + wg.Wait() +} + +func BenchmarkHistogramObserve1(b *testing.B) { + benchmarkHistogramObserve(1, b) +} + +func BenchmarkHistogramObserve2(b *testing.B) { + benchmarkHistogramObserve(2, b) +} + +func BenchmarkHistogramObserve4(b *testing.B) { + benchmarkHistogramObserve(4, b) +} + +func BenchmarkHistogramObserve8(b *testing.B) { + benchmarkHistogramObserve(8, b) +} + +func benchmarkHistogramWrite(w int, b *testing.B) { + b.StopTimer() + + wg := new(sync.WaitGroup) + wg.Add(w) + + g := new(sync.WaitGroup) + g.Add(1) + + s := NewHistogram(HistogramOpts{}) + + for i := 0; i < 1000000; i++ { + s.Observe(float64(i)) + } + + for j := 0; j < w; j++ { + outs := make([]dto.Metric, b.N) + + go func(o []dto.Metric) { + g.Wait() + + for i := 0; i < b.N; i++ { + s.Write(&o[i]) + } + + wg.Done() + }(outs) + } + + b.StartTimer() + g.Done() + wg.Wait() +} + +func BenchmarkHistogramWrite1(b *testing.B) { + benchmarkHistogramWrite(1, b) +} + +func BenchmarkHistogramWrite2(b *testing.B) { + benchmarkHistogramWrite(2, b) +} + +func BenchmarkHistogramWrite4(b *testing.B) { + benchmarkHistogramWrite(4, b) +} + +func BenchmarkHistogramWrite8(b *testing.B) { + benchmarkHistogramWrite(8, b) +} + +func TestHistogramNonMonotonicBuckets(t *testing.T) { + testCases := map[string][]float64{ + "not strictly monotonic": {1, 2, 2, 3}, + "not monotonic at all": {1, 2, 4, 3, 5}, + "have +Inf in the middle": {1, 2, math.Inf(+1), 3}, + } + for name, buckets := range testCases { + func() { + defer func() { + if r := recover(); r == nil { + t.Errorf("Buckets %v are %s but NewHistogram did not panic.", buckets, name) + } + }() + _ = NewHistogram(HistogramOpts{ + Name: "test_histogram", + Help: "helpless", + Buckets: buckets, + }) + }() + } +} + +// Intentionally adding +Inf here to test if that case is handled correctly. +// Also, getCumulativeCounts depends on it. +var testBuckets = []float64{-2, -1, -0.5, 0, 0.5, 1, 2, math.Inf(+1)} + +func TestHistogramConcurrency(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + + rand.Seed(42) + + it := func(n uint32) bool { + mutations := int(n%1e4 + 1e4) + concLevel := int(n%5 + 1) + total := mutations * concLevel + + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + sum := NewHistogram(HistogramOpts{ + Name: "test_histogram", + Help: "helpless", + Buckets: testBuckets, + }) + + allVars := make([]float64, total) + var sampleSum float64 + for i := 0; i < concLevel; i++ { + vals := make([]float64, mutations) + for j := 0; j < mutations; j++ { + v := rand.NormFloat64() + vals[j] = v + allVars[i*mutations+j] = v + sampleSum += v + } + + go func(vals []float64) { + start.Wait() + for _, v := range vals { + sum.Observe(v) + } + end.Done() + }(vals) + } + sort.Float64s(allVars) + start.Done() + end.Wait() + + m := &dto.Metric{} + sum.Write(m) + if got, want := int(*m.Histogram.SampleCount), total; got != want { + t.Errorf("got sample count %d, want %d", got, want) + } + if got, want := *m.Histogram.SampleSum, sampleSum; math.Abs((got-want)/want) > 0.001 { + t.Errorf("got sample sum %f, want %f", got, want) + } + + wantCounts := getCumulativeCounts(allVars) + + if got, want := len(m.Histogram.Bucket), len(testBuckets)-1; got != want { + t.Errorf("got %d buckets in protobuf, want %d", got, want) + } + for i, wantBound := range testBuckets { + if i == len(testBuckets)-1 { + break // No +Inf bucket in protobuf. + } + if gotBound := *m.Histogram.Bucket[i].UpperBound; gotBound != wantBound { + t.Errorf("got bound %f, want %f", gotBound, wantBound) + } + if gotCount, wantCount := *m.Histogram.Bucket[i].CumulativeCount, wantCounts[i]; gotCount != wantCount { + t.Errorf("got count %d, want %d", gotCount, wantCount) + } + } + return true + } + + if err := quick.Check(it, nil); err != nil { + t.Error(err) + } +} + +func TestHistogramVecConcurrency(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + + rand.Seed(42) + + objectives := make([]float64, 0, len(DefObjectives)) + for qu := range DefObjectives { + + objectives = append(objectives, qu) + } + sort.Float64s(objectives) + + it := func(n uint32) bool { + mutations := int(n%1e4 + 1e4) + concLevel := int(n%7 + 1) + vecLength := int(n%3 + 1) + + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + his := NewHistogramVec( + HistogramOpts{ + Name: "test_histogram", + Help: "helpless", + Buckets: []float64{-2, -1, -0.5, 0, 0.5, 1, 2, math.Inf(+1)}, + }, + []string{"label"}, + ) + + allVars := make([][]float64, vecLength) + sampleSums := make([]float64, vecLength) + for i := 0; i < concLevel; i++ { + vals := make([]float64, mutations) + picks := make([]int, mutations) + for j := 0; j < mutations; j++ { + v := rand.NormFloat64() + vals[j] = v + pick := rand.Intn(vecLength) + picks[j] = pick + allVars[pick] = append(allVars[pick], v) + sampleSums[pick] += v + } + + go func(vals []float64) { + start.Wait() + for i, v := range vals { + his.WithLabelValues(string('A' + picks[i])).Observe(v) + } + end.Done() + }(vals) + } + for _, vars := range allVars { + sort.Float64s(vars) + } + start.Done() + end.Wait() + + for i := 0; i < vecLength; i++ { + m := &dto.Metric{} + s := his.WithLabelValues(string('A' + i)) + s.(Histogram).Write(m) + + if got, want := len(m.Histogram.Bucket), len(testBuckets)-1; got != want { + t.Errorf("got %d buckets in protobuf, want %d", got, want) + } + if got, want := int(*m.Histogram.SampleCount), len(allVars[i]); got != want { + t.Errorf("got sample count %d, want %d", got, want) + } + if got, want := *m.Histogram.SampleSum, sampleSums[i]; math.Abs((got-want)/want) > 0.001 { + t.Errorf("got sample sum %f, want %f", got, want) + } + + wantCounts := getCumulativeCounts(allVars[i]) + + for j, wantBound := range testBuckets { + if j == len(testBuckets)-1 { + break // No +Inf bucket in protobuf. + } + if gotBound := *m.Histogram.Bucket[j].UpperBound; gotBound != wantBound { + t.Errorf("got bound %f, want %f", gotBound, wantBound) + } + if gotCount, wantCount := *m.Histogram.Bucket[j].CumulativeCount, wantCounts[j]; gotCount != wantCount { + t.Errorf("got count %d, want %d", gotCount, wantCount) + } + } + } + return true + } + + if err := quick.Check(it, nil); err != nil { + t.Error(err) + } +} + +func getCumulativeCounts(vars []float64) []uint64 { + counts := make([]uint64, len(testBuckets)) + for _, v := range vars { + for i := len(testBuckets) - 1; i >= 0; i-- { + if v > testBuckets[i] { + break + } + counts[i]++ + } + } + return counts +} + +func TestBuckets(t *testing.T) { + got := LinearBuckets(-15, 5, 6) + want := []float64{-15, -10, -5, 0, 5, 10} + if !reflect.DeepEqual(got, want) { + t.Errorf("linear buckets: got %v, want %v", got, want) + } + + got = ExponentialBuckets(100, 1.2, 3) + want = []float64{100, 120, 144} + if !reflect.DeepEqual(got, want) { + t.Errorf("linear buckets: got %v, want %v", got, want) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/http_test.go b/vendor/github.com/prometheus/client_golang/prometheus/http_test.go new file mode 100644 index 000000000..7fd4077b9 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/http_test.go @@ -0,0 +1,154 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + dto "github.com/prometheus/client_model/go" +) + +type respBody string + +func (b respBody) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusTeapot) + w.Write([]byte(b)) +} + +func TestInstrumentHandler(t *testing.T) { + defer func(n nower) { + now = n.(nower) + }(now) + + instant := time.Now() + end := instant.Add(30 * time.Second) + now = nowSeries(instant, end) + respBody := respBody("Howdy there!") + + hndlr := InstrumentHandler("test-handler", respBody) + + opts := SummaryOpts{ + Subsystem: "http", + ConstLabels: Labels{"handler": "test-handler"}, + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + } + + reqCnt := NewCounterVec( + CounterOpts{ + Namespace: opts.Namespace, + Subsystem: opts.Subsystem, + Name: "requests_total", + Help: "Total number of HTTP requests made.", + ConstLabels: opts.ConstLabels, + }, + instLabels, + ) + err := Register(reqCnt) + if err == nil { + t.Fatal("expected reqCnt to be registered already") + } + if are, ok := err.(AlreadyRegisteredError); ok { + reqCnt = are.ExistingCollector.(*CounterVec) + } else { + t.Fatal("unexpected registration error:", err) + } + + opts.Name = "request_duration_microseconds" + opts.Help = "The HTTP request latencies in microseconds." + reqDur := NewSummary(opts) + err = Register(reqDur) + if err == nil { + t.Fatal("expected reqDur to be registered already") + } + if are, ok := err.(AlreadyRegisteredError); ok { + reqDur = are.ExistingCollector.(Summary) + } else { + t.Fatal("unexpected registration error:", err) + } + + opts.Name = "request_size_bytes" + opts.Help = "The HTTP request sizes in bytes." + reqSz := NewSummary(opts) + err = Register(reqSz) + if err == nil { + t.Fatal("expected reqSz to be registered already") + } + if _, ok := err.(AlreadyRegisteredError); !ok { + t.Fatal("unexpected registration error:", err) + } + + opts.Name = "response_size_bytes" + opts.Help = "The HTTP response sizes in bytes." + resSz := NewSummary(opts) + err = Register(resSz) + if err == nil { + t.Fatal("expected resSz to be registered already") + } + if _, ok := err.(AlreadyRegisteredError); !ok { + t.Fatal("unexpected registration error:", err) + } + + reqCnt.Reset() + + resp := httptest.NewRecorder() + req := &http.Request{ + Method: "GET", + } + + hndlr.ServeHTTP(resp, req) + + if resp.Code != http.StatusTeapot { + t.Fatalf("expected status %d, got %d", http.StatusTeapot, resp.Code) + } + if string(resp.Body.Bytes()) != "Howdy there!" { + t.Fatalf("expected body %s, got %s", "Howdy there!", string(resp.Body.Bytes())) + } + + out := &dto.Metric{} + reqDur.Write(out) + if want, got := "test-handler", out.Label[0].GetValue(); want != got { + t.Errorf("want label value %q in reqDur, got %q", want, got) + } + if want, got := uint64(1), out.Summary.GetSampleCount(); want != got { + t.Errorf("want sample count %d in reqDur, got %d", want, got) + } + + out.Reset() + if want, got := 1, len(reqCnt.children); want != got { + t.Errorf("want %d children in reqCnt, got %d", want, got) + } + cnt, err := reqCnt.GetMetricWithLabelValues("get", "418") + if err != nil { + t.Fatal(err) + } + cnt.Write(out) + if want, got := "418", out.Label[0].GetValue(); want != got { + t.Errorf("want label value %q in reqCnt, got %q", want, got) + } + if want, got := "test-handler", out.Label[1].GetValue(); want != got { + t.Errorf("want label value %q in reqCnt, got %q", want, got) + } + if want, got := "get", out.Label[2].GetValue(); want != got { + t.Errorf("want label value %q in reqCnt, got %q", want, got) + } + if out.Counter == nil { + t.Fatal("expected non-nil counter in reqCnt") + } + if want, got := 1., out.Counter.GetValue(); want != got { + t.Errorf("want reqCnt of %f, got %f", want, got) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/metric_test.go b/vendor/github.com/prometheus/client_golang/prometheus/metric_test.go new file mode 100644 index 000000000..7145f5e53 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/metric_test.go @@ -0,0 +1,35 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import "testing" + +func TestBuildFQName(t *testing.T) { + scenarios := []struct{ namespace, subsystem, name, result string }{ + {"a", "b", "c", "a_b_c"}, + {"", "b", "c", "b_c"}, + {"a", "", "c", "a_c"}, + {"", "", "c", "c"}, + {"a", "b", "", ""}, + {"a", "", "", ""}, + {"", "b", "", ""}, + {" ", "", "", ""}, + } + + for i, s := range scenarios { + if want, got := s.result, BuildFQName(s.namespace, s.subsystem, s.name); want != got { + t.Errorf("%d. want %s, got %s", i, want, got) + } + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go new file mode 100644 index 000000000..c7acb47fe --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go @@ -0,0 +1,58 @@ +package prometheus + +import ( + "bytes" + "os" + "regexp" + "testing" + + "github.com/prometheus/common/expfmt" + "github.com/prometheus/procfs" +) + +func TestProcessCollector(t *testing.T) { + if _, err := procfs.Self(); err != nil { + t.Skipf("skipping TestProcessCollector, procfs not available: %s", err) + } + + registry := NewRegistry() + if err := registry.Register(NewProcessCollector(os.Getpid(), "")); err != nil { + t.Fatal(err) + } + if err := registry.Register(NewProcessCollectorPIDFn( + func() (int, error) { return os.Getpid(), nil }, "foobar"), + ); err != nil { + t.Fatal(err) + } + + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + for _, mf := range mfs { + if _, err := expfmt.MetricFamilyToText(&buf, mf); err != nil { + t.Fatal(err) + } + } + + for _, re := range []*regexp.Regexp{ + regexp.MustCompile("\nprocess_cpu_seconds_total [0-9]"), + regexp.MustCompile("\nprocess_max_fds [1-9]"), + regexp.MustCompile("\nprocess_open_fds [1-9]"), + regexp.MustCompile("\nprocess_virtual_memory_bytes [1-9]"), + regexp.MustCompile("\nprocess_resident_memory_bytes [1-9]"), + regexp.MustCompile("\nprocess_start_time_seconds [0-9.]{10,}"), + regexp.MustCompile("\nfoobar_process_cpu_seconds_total [0-9]"), + regexp.MustCompile("\nfoobar_process_max_fds [1-9]"), + regexp.MustCompile("\nfoobar_process_open_fds [1-9]"), + regexp.MustCompile("\nfoobar_process_virtual_memory_bytes [1-9]"), + regexp.MustCompile("\nfoobar_process_resident_memory_bytes [1-9]"), + regexp.MustCompile("\nfoobar_process_start_time_seconds [0-9.]{10,}"), + } { + if !re.Match(buf.Bytes()) { + t.Errorf("want body to match %s\n%s", re, buf.String()) + } + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry_test.go b/vendor/github.com/prometheus/client_golang/prometheus/registry_test.go new file mode 100644 index 000000000..d016a1560 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry_test.go @@ -0,0 +1,546 @@ +// Copyright 2014 The Prometheus 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. + +// Copyright (c) 2013, The Prometheus Authors +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package prometheus_test + +import ( + "bytes" + "net/http" + "net/http/httptest" + "testing" + + dto "github.com/prometheus/client_model/go" + + "github.com/golang/protobuf/proto" + "github.com/prometheus/common/expfmt" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func testHandler(t testing.TB) { + + metricVec := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "name", + Help: "docstring", + ConstLabels: prometheus.Labels{"constname": "constvalue"}, + }, + []string{"labelname"}, + ) + + metricVec.WithLabelValues("val1").Inc() + metricVec.WithLabelValues("val2").Inc() + + externalMetricFamily := &dto.MetricFamily{ + Name: proto.String("externalname"), + Help: proto.String("externaldocstring"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + { + Label: []*dto.LabelPair{ + { + Name: proto.String("externalconstname"), + Value: proto.String("externalconstvalue"), + }, + { + Name: proto.String("externallabelname"), + Value: proto.String("externalval1"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(1), + }, + }, + }, + } + externalBuf := &bytes.Buffer{} + enc := expfmt.NewEncoder(externalBuf, expfmt.FmtProtoDelim) + if err := enc.Encode(externalMetricFamily); err != nil { + t.Fatal(err) + } + externalMetricFamilyAsBytes := externalBuf.Bytes() + externalMetricFamilyAsText := []byte(`# HELP externalname externaldocstring +# TYPE externalname counter +externalname{externalconstname="externalconstvalue",externallabelname="externalval1"} 1 +`) + externalMetricFamilyAsProtoText := []byte(`name: "externalname" +help: "externaldocstring" +type: COUNTER +metric: < + label: < + name: "externalconstname" + value: "externalconstvalue" + > + label: < + name: "externallabelname" + value: "externalval1" + > + counter: < + value: 1 + > +> + +`) + externalMetricFamilyAsProtoCompactText := []byte(`name:"externalname" help:"externaldocstring" type:COUNTER metric: label: counter: > +`) + + expectedMetricFamily := &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("docstring"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + { + Label: []*dto.LabelPair{ + { + Name: proto.String("constname"), + Value: proto.String("constvalue"), + }, + { + Name: proto.String("labelname"), + Value: proto.String("val1"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(1), + }, + }, + { + Label: []*dto.LabelPair{ + { + Name: proto.String("constname"), + Value: proto.String("constvalue"), + }, + { + Name: proto.String("labelname"), + Value: proto.String("val2"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(1), + }, + }, + }, + } + buf := &bytes.Buffer{} + enc = expfmt.NewEncoder(buf, expfmt.FmtProtoDelim) + if err := enc.Encode(expectedMetricFamily); err != nil { + t.Fatal(err) + } + expectedMetricFamilyAsBytes := buf.Bytes() + expectedMetricFamilyAsText := []byte(`# HELP name docstring +# TYPE name counter +name{constname="constvalue",labelname="val1"} 1 +name{constname="constvalue",labelname="val2"} 1 +`) + expectedMetricFamilyAsProtoText := []byte(`name: "name" +help: "docstring" +type: COUNTER +metric: < + label: < + name: "constname" + value: "constvalue" + > + label: < + name: "labelname" + value: "val1" + > + counter: < + value: 1 + > +> +metric: < + label: < + name: "constname" + value: "constvalue" + > + label: < + name: "labelname" + value: "val2" + > + counter: < + value: 1 + > +> + +`) + expectedMetricFamilyAsProtoCompactText := []byte(`name:"name" help:"docstring" type:COUNTER metric: label: counter: > metric: label: counter: > +`) + + externalMetricFamilyWithSameName := &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("docstring"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + { + Label: []*dto.LabelPair{ + { + Name: proto.String("constname"), + Value: proto.String("constvalue"), + }, + { + Name: proto.String("labelname"), + Value: proto.String("different_val"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(42), + }, + }, + }, + } + + expectedMetricFamilyMergedWithExternalAsProtoCompactText := []byte(`name:"name" help:"docstring" type:COUNTER metric: label: counter: > metric: label: counter: > metric: label: counter: > +`) + + type output struct { + headers map[string]string + body []byte + } + + var scenarios = []struct { + headers map[string]string + out output + collector prometheus.Collector + externalMF []*dto.MetricFamily + }{ + { // 0 + headers: map[string]string{ + "Accept": "foo/bar;q=0.2, dings/bums;q=0.8", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: []byte{}, + }, + }, + { // 1 + headers: map[string]string{ + "Accept": "foo/bar;q=0.2, application/quark;q=0.8", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: []byte{}, + }, + }, + { // 2 + headers: map[string]string{ + "Accept": "foo/bar;q=0.2, application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=bla;q=0.8", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: []byte{}, + }, + }, + { // 3 + headers: map[string]string{ + "Accept": "text/plain;q=0.2, application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.8", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`, + }, + body: []byte{}, + }, + }, + { // 4 + headers: map[string]string{ + "Accept": "application/json", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: expectedMetricFamilyAsText, + }, + collector: metricVec, + }, + { // 5 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`, + }, + body: expectedMetricFamilyAsBytes, + }, + collector: metricVec, + }, + { // 6 + headers: map[string]string{ + "Accept": "application/json", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: externalMetricFamilyAsText, + }, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 7 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`, + }, + body: externalMetricFamilyAsBytes, + }, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 8 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`, + }, + body: bytes.Join( + [][]byte{ + externalMetricFamilyAsBytes, + expectedMetricFamilyAsBytes, + }, + []byte{}, + ), + }, + collector: metricVec, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 9 + headers: map[string]string{ + "Accept": "text/plain", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: []byte{}, + }, + }, + { // 10 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=bla;q=0.2, text/plain;q=0.5", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: expectedMetricFamilyAsText, + }, + collector: metricVec, + }, + { // 11 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=bla;q=0.2, text/plain;q=0.5;version=0.0.4", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `text/plain; version=0.0.4`, + }, + body: bytes.Join( + [][]byte{ + externalMetricFamilyAsText, + expectedMetricFamilyAsText, + }, + []byte{}, + ), + }, + collector: metricVec, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 12 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.2, text/plain;q=0.5;version=0.0.2", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`, + }, + body: bytes.Join( + [][]byte{ + externalMetricFamilyAsBytes, + expectedMetricFamilyAsBytes, + }, + []byte{}, + ), + }, + collector: metricVec, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 13 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=text;q=0.5, application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.4", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`, + }, + body: bytes.Join( + [][]byte{ + externalMetricFamilyAsProtoText, + expectedMetricFamilyAsProtoText, + }, + []byte{}, + ), + }, + collector: metricVec, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 14 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=compact-text", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`, + }, + body: bytes.Join( + [][]byte{ + externalMetricFamilyAsProtoCompactText, + expectedMetricFamilyAsProtoCompactText, + }, + []byte{}, + ), + }, + collector: metricVec, + externalMF: []*dto.MetricFamily{externalMetricFamily}, + }, + { // 15 + headers: map[string]string{ + "Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=compact-text", + }, + out: output{ + headers: map[string]string{ + "Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`, + }, + body: bytes.Join( + [][]byte{ + externalMetricFamilyAsProtoCompactText, + expectedMetricFamilyMergedWithExternalAsProtoCompactText, + }, + []byte{}, + ), + }, + collector: metricVec, + externalMF: []*dto.MetricFamily{ + externalMetricFamily, + externalMetricFamilyWithSameName, + }, + }, + } + for i, scenario := range scenarios { + registry := prometheus.NewPedanticRegistry() + gatherer := prometheus.Gatherer(registry) + if scenario.externalMF != nil { + gatherer = prometheus.Gatherers{ + registry, + prometheus.GathererFunc(func() ([]*dto.MetricFamily, error) { + return scenario.externalMF, nil + }), + } + } + + if scenario.collector != nil { + registry.Register(scenario.collector) + } + writer := httptest.NewRecorder() + handler := prometheus.InstrumentHandler("prometheus", promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{})) + request, _ := http.NewRequest("GET", "/", nil) + for key, value := range scenario.headers { + request.Header.Add(key, value) + } + handler(writer, request) + + for key, value := range scenario.out.headers { + if writer.HeaderMap.Get(key) != value { + t.Errorf( + "%d. expected %q for header %q, got %q", + i, value, key, writer.Header().Get(key), + ) + } + } + + if !bytes.Equal(scenario.out.body, writer.Body.Bytes()) { + t.Errorf( + "%d. expected body:\n%s\ngot body:\n%s\n", + i, scenario.out.body, writer.Body.Bytes(), + ) + } + } +} + +func TestHandler(t *testing.T) { + testHandler(t) +} + +func BenchmarkHandler(b *testing.B) { + for i := 0; i < b.N; i++ { + testHandler(b) + } +} + +func TestRegisterWithOrGet(t *testing.T) { + // Replace the default registerer just to be sure. This is bad, but this + // whole test will go away once RegisterOrGet is removed. + oldRegisterer := prometheus.DefaultRegisterer + defer func() { + prometheus.DefaultRegisterer = oldRegisterer + }() + prometheus.DefaultRegisterer = prometheus.NewRegistry() + original := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "test", + Help: "help", + }, + []string{"foo", "bar"}, + ) + equalButNotSame := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "test", + Help: "help", + }, + []string{"foo", "bar"}, + ) + var err error + if err = prometheus.Register(original); err != nil { + t.Fatal(err) + } + if err = prometheus.Register(equalButNotSame); err == nil { + t.Fatal("expected error when registringe equal collector") + } + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + if are.ExistingCollector != original { + t.Error("expected original collector but got something else") + } + if are.ExistingCollector == equalButNotSame { + t.Error("expected original callector but got new one") + } + } else { + t.Error("unexpected error:", err) + } +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary_test.go b/vendor/github.com/prometheus/client_golang/prometheus/summary_test.go new file mode 100644 index 000000000..b162ed946 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary_test.go @@ -0,0 +1,388 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import ( + "math" + "math/rand" + "sort" + "sync" + "testing" + "testing/quick" + "time" + + dto "github.com/prometheus/client_model/go" +) + +func TestSummaryWithDefaultObjectives(t *testing.T) { + reg := NewRegistry() + summaryWithDefaultObjectives := NewSummary(SummaryOpts{ + Name: "default_objectives", + Help: "Test help.", + }) + if err := reg.Register(summaryWithDefaultObjectives); err != nil { + t.Error(err) + } + + m := &dto.Metric{} + if err := summaryWithDefaultObjectives.Write(m); err != nil { + t.Error(err) + } + if len(m.GetSummary().Quantile) != len(DefObjectives) { + t.Error("expected default objectives in summary") + } +} + +func TestSummaryWithoutObjectives(t *testing.T) { + reg := NewRegistry() + summaryWithEmptyObjectives := NewSummary(SummaryOpts{ + Name: "empty_objectives", + Help: "Test help.", + Objectives: map[float64]float64{}, + }) + if err := reg.Register(summaryWithEmptyObjectives); err != nil { + t.Error(err) + } + + m := &dto.Metric{} + if err := summaryWithEmptyObjectives.Write(m); err != nil { + t.Error(err) + } + if len(m.GetSummary().Quantile) != 0 { + t.Error("expected no objectives in summary") + } +} + +func benchmarkSummaryObserve(w int, b *testing.B) { + b.StopTimer() + + wg := new(sync.WaitGroup) + wg.Add(w) + + g := new(sync.WaitGroup) + g.Add(1) + + s := NewSummary(SummaryOpts{}) + + for i := 0; i < w; i++ { + go func() { + g.Wait() + + for i := 0; i < b.N; i++ { + s.Observe(float64(i)) + } + + wg.Done() + }() + } + + b.StartTimer() + g.Done() + wg.Wait() +} + +func BenchmarkSummaryObserve1(b *testing.B) { + benchmarkSummaryObserve(1, b) +} + +func BenchmarkSummaryObserve2(b *testing.B) { + benchmarkSummaryObserve(2, b) +} + +func BenchmarkSummaryObserve4(b *testing.B) { + benchmarkSummaryObserve(4, b) +} + +func BenchmarkSummaryObserve8(b *testing.B) { + benchmarkSummaryObserve(8, b) +} + +func benchmarkSummaryWrite(w int, b *testing.B) { + b.StopTimer() + + wg := new(sync.WaitGroup) + wg.Add(w) + + g := new(sync.WaitGroup) + g.Add(1) + + s := NewSummary(SummaryOpts{}) + + for i := 0; i < 1000000; i++ { + s.Observe(float64(i)) + } + + for j := 0; j < w; j++ { + outs := make([]dto.Metric, b.N) + + go func(o []dto.Metric) { + g.Wait() + + for i := 0; i < b.N; i++ { + s.Write(&o[i]) + } + + wg.Done() + }(outs) + } + + b.StartTimer() + g.Done() + wg.Wait() +} + +func BenchmarkSummaryWrite1(b *testing.B) { + benchmarkSummaryWrite(1, b) +} + +func BenchmarkSummaryWrite2(b *testing.B) { + benchmarkSummaryWrite(2, b) +} + +func BenchmarkSummaryWrite4(b *testing.B) { + benchmarkSummaryWrite(4, b) +} + +func BenchmarkSummaryWrite8(b *testing.B) { + benchmarkSummaryWrite(8, b) +} + +func TestSummaryConcurrency(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + + rand.Seed(42) + + it := func(n uint32) bool { + mutations := int(n%1e4 + 1e4) + concLevel := int(n%5 + 1) + total := mutations * concLevel + + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + sum := NewSummary(SummaryOpts{ + Name: "test_summary", + Help: "helpless", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }) + + allVars := make([]float64, total) + var sampleSum float64 + for i := 0; i < concLevel; i++ { + vals := make([]float64, mutations) + for j := 0; j < mutations; j++ { + v := rand.NormFloat64() + vals[j] = v + allVars[i*mutations+j] = v + sampleSum += v + } + + go func(vals []float64) { + start.Wait() + for _, v := range vals { + sum.Observe(v) + } + end.Done() + }(vals) + } + sort.Float64s(allVars) + start.Done() + end.Wait() + + m := &dto.Metric{} + sum.Write(m) + if got, want := int(*m.Summary.SampleCount), total; got != want { + t.Errorf("got sample count %d, want %d", got, want) + } + if got, want := *m.Summary.SampleSum, sampleSum; math.Abs((got-want)/want) > 0.001 { + t.Errorf("got sample sum %f, want %f", got, want) + } + + objectives := make([]float64, 0, len(DefObjectives)) + for qu := range DefObjectives { + objectives = append(objectives, qu) + } + sort.Float64s(objectives) + + for i, wantQ := range objectives { + ε := DefObjectives[wantQ] + gotQ := *m.Summary.Quantile[i].Quantile + gotV := *m.Summary.Quantile[i].Value + min, max := getBounds(allVars, wantQ, ε) + if gotQ != wantQ { + t.Errorf("got quantile %f, want %f", gotQ, wantQ) + } + if gotV < min || gotV > max { + t.Errorf("got %f for quantile %f, want [%f,%f]", gotV, gotQ, min, max) + } + } + return true + } + + if err := quick.Check(it, nil); err != nil { + t.Error(err) + } +} + +func TestSummaryVecConcurrency(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + + rand.Seed(42) + + objectives := make([]float64, 0, len(DefObjectives)) + for qu := range DefObjectives { + + objectives = append(objectives, qu) + } + sort.Float64s(objectives) + + it := func(n uint32) bool { + mutations := int(n%1e4 + 1e4) + concLevel := int(n%7 + 1) + vecLength := int(n%3 + 1) + + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + sum := NewSummaryVec( + SummaryOpts{ + Name: "test_summary", + Help: "helpless", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, + []string{"label"}, + ) + + allVars := make([][]float64, vecLength) + sampleSums := make([]float64, vecLength) + for i := 0; i < concLevel; i++ { + vals := make([]float64, mutations) + picks := make([]int, mutations) + for j := 0; j < mutations; j++ { + v := rand.NormFloat64() + vals[j] = v + pick := rand.Intn(vecLength) + picks[j] = pick + allVars[pick] = append(allVars[pick], v) + sampleSums[pick] += v + } + + go func(vals []float64) { + start.Wait() + for i, v := range vals { + sum.WithLabelValues(string('A' + picks[i])).Observe(v) + } + end.Done() + }(vals) + } + for _, vars := range allVars { + sort.Float64s(vars) + } + start.Done() + end.Wait() + + for i := 0; i < vecLength; i++ { + m := &dto.Metric{} + s := sum.WithLabelValues(string('A' + i)) + s.(Summary).Write(m) + if got, want := int(*m.Summary.SampleCount), len(allVars[i]); got != want { + t.Errorf("got sample count %d for label %c, want %d", got, 'A'+i, want) + } + if got, want := *m.Summary.SampleSum, sampleSums[i]; math.Abs((got-want)/want) > 0.001 { + t.Errorf("got sample sum %f for label %c, want %f", got, 'A'+i, want) + } + for j, wantQ := range objectives { + ε := DefObjectives[wantQ] + gotQ := *m.Summary.Quantile[j].Quantile + gotV := *m.Summary.Quantile[j].Value + min, max := getBounds(allVars[i], wantQ, ε) + if gotQ != wantQ { + t.Errorf("got quantile %f for label %c, want %f", gotQ, 'A'+i, wantQ) + } + if gotV < min || gotV > max { + t.Errorf("got %f for quantile %f for label %c, want [%f,%f]", gotV, gotQ, 'A'+i, min, max) + } + } + } + return true + } + + if err := quick.Check(it, nil); err != nil { + t.Error(err) + } +} + +func TestSummaryDecay(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + // More because it depends on timing than because it is particularly long... + } + + sum := NewSummary(SummaryOpts{ + Name: "test_summary", + Help: "helpless", + MaxAge: 100 * time.Millisecond, + Objectives: map[float64]float64{0.1: 0.001}, + AgeBuckets: 10, + }) + + m := &dto.Metric{} + i := 0 + tick := time.NewTicker(time.Millisecond) + for range tick.C { + i++ + sum.Observe(float64(i)) + if i%10 == 0 { + sum.Write(m) + if got, want := *m.Summary.Quantile[0].Value, math.Max(float64(i)/10, float64(i-90)); math.Abs(got-want) > 20 { + t.Errorf("%d. got %f, want %f", i, got, want) + } + m.Reset() + } + if i >= 1000 { + break + } + } + tick.Stop() + // Wait for MaxAge without observations and make sure quantiles are NaN. + time.Sleep(100 * time.Millisecond) + sum.Write(m) + if got := *m.Summary.Quantile[0].Value; !math.IsNaN(got) { + t.Errorf("got %f, want NaN after expiration", got) + } +} + +func getBounds(vars []float64, q, ε float64) (min, max float64) { + // TODO(beorn7): This currently tolerates an error of up to 2*ε. The + // error must be at most ε, but for some reason, it's sometimes slightly + // higher. That's a bug. + n := float64(len(vars)) + lower := int((q - 2*ε) * n) + upper := int(math.Ceil((q + 2*ε) * n)) + min = vars[0] + if lower > 1 { + min = vars[lower-1] + } + max = vars[len(vars)-1] + if upper < len(vars) { + max = vars[upper-1] + } + return +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer_test.go b/vendor/github.com/prometheus/client_golang/prometheus/timer_test.go new file mode 100644 index 000000000..294902068 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer_test.go @@ -0,0 +1,152 @@ +// Copyright 2016 The Prometheus 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 prometheus + +import ( + "testing" + + dto "github.com/prometheus/client_model/go" +) + +func TestTimerObserve(t *testing.T) { + var ( + his = NewHistogram(HistogramOpts{Name: "test_histogram"}) + sum = NewSummary(SummaryOpts{Name: "test_summary"}) + gauge = NewGauge(GaugeOpts{Name: "test_gauge"}) + ) + + func() { + hisTimer := NewTimer(his) + sumTimer := NewTimer(sum) + gaugeTimer := NewTimer(ObserverFunc(gauge.Set)) + defer hisTimer.ObserveDuration() + defer sumTimer.ObserveDuration() + defer gaugeTimer.ObserveDuration() + }() + + m := &dto.Metric{} + his.Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for histogram, got %d", want, got) + } + m.Reset() + sum.Write(m) + if want, got := uint64(1), m.GetSummary().GetSampleCount(); want != got { + t.Errorf("want %d observations for summary, got %d", want, got) + } + m.Reset() + gauge.Write(m) + if got := m.GetGauge().GetValue(); got <= 0 { + t.Errorf("want value > 0 for gauge, got %f", got) + } +} + +func TestTimerEmpty(t *testing.T) { + emptyTimer := NewTimer(nil) + emptyTimer.ObserveDuration() + // Do nothing, just demonstrate it works without panic. +} + +func TestTimerConditionalTiming(t *testing.T) { + var ( + his = NewHistogram(HistogramOpts{ + Name: "test_histogram", + }) + timeMe = true + m = &dto.Metric{} + ) + + timedFunc := func() { + timer := NewTimer(ObserverFunc(func(v float64) { + if timeMe { + his.Observe(v) + } + })) + defer timer.ObserveDuration() + } + + timedFunc() // This will time. + his.Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for histogram, got %d", want, got) + } + + timeMe = false + timedFunc() // This will not time again. + m.Reset() + his.Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for histogram, got %d", want, got) + } +} + +func TestTimerByOutcome(t *testing.T) { + var ( + his = NewHistogramVec( + HistogramOpts{Name: "test_histogram"}, + []string{"outcome"}, + ) + outcome = "foo" + m = &dto.Metric{} + ) + + timedFunc := func() { + timer := NewTimer(ObserverFunc(func(v float64) { + his.WithLabelValues(outcome).Observe(v) + })) + defer timer.ObserveDuration() + + if outcome == "foo" { + outcome = "bar" + return + } + outcome = "foo" + } + + timedFunc() + his.WithLabelValues("foo").(Histogram).Write(m) + if want, got := uint64(0), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for 'foo' histogram, got %d", want, got) + } + m.Reset() + his.WithLabelValues("bar").(Histogram).Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for 'bar' histogram, got %d", want, got) + } + + timedFunc() + m.Reset() + his.WithLabelValues("foo").(Histogram).Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for 'foo' histogram, got %d", want, got) + } + m.Reset() + his.WithLabelValues("bar").(Histogram).Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for 'bar' histogram, got %d", want, got) + } + + timedFunc() + m.Reset() + his.WithLabelValues("foo").(Histogram).Write(m) + if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for 'foo' histogram, got %d", want, got) + } + m.Reset() + his.WithLabelValues("bar").(Histogram).Write(m) + if want, got := uint64(2), m.GetHistogram().GetSampleCount(); want != got { + t.Errorf("want %d observations for 'bar' histogram, got %d", want, got) + } + +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/vec_test.go b/vendor/github.com/prometheus/client_golang/prometheus/vec_test.go new file mode 100644 index 000000000..e3c5aeba0 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/vec_test.go @@ -0,0 +1,312 @@ +// Copyright 2014 The Prometheus 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 prometheus + +import ( + "fmt" + "testing" + + dto "github.com/prometheus/client_model/go" +) + +func TestDelete(t *testing.T) { + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + []string{"l1", "l2"}, + ) + testDelete(t, vec) +} + +func TestDeleteWithCollisions(t *testing.T) { + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + []string{"l1", "l2"}, + ) + vec.hashAdd = func(h uint64, s string) uint64 { return 1 } + vec.hashAddByte = func(h uint64, b byte) uint64 { return 1 } + testDelete(t, vec) +} + +func testDelete(t *testing.T, vec *UntypedVec) { + if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + + vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42) + if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), true; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + + vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42) + if got, want := vec.Delete(Labels{"l2": "v2", "l1": "v1"}), true; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := vec.Delete(Labels{"l2": "v2", "l1": "v1"}), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + + vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42) + if got, want := vec.Delete(Labels{"l2": "v1", "l1": "v2"}), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := vec.Delete(Labels{"l1": "v1"}), false; got != want { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestDeleteLabelValues(t *testing.T) { + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + []string{"l1", "l2"}, + ) + testDeleteLabelValues(t, vec) +} + +func TestDeleteLabelValuesWithCollisions(t *testing.T) { + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + []string{"l1", "l2"}, + ) + vec.hashAdd = func(h uint64, s string) uint64 { return 1 } + vec.hashAddByte = func(h uint64, b byte) uint64 { return 1 } + testDeleteLabelValues(t, vec) +} + +func testDeleteLabelValues(t *testing.T, vec *UntypedVec) { + if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + + vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42) + vec.With(Labels{"l1": "v1", "l2": "v3"}).(Untyped).Set(42) // Add junk data for collision. + if got, want := vec.DeleteLabelValues("v1", "v2"), true; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := vec.DeleteLabelValues("v1", "v3"), true; got != want { + t.Errorf("got %v, want %v", got, want) + } + + vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42) + // Delete out of order. + if got, want := vec.DeleteLabelValues("v2", "v1"), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := vec.DeleteLabelValues("v1"), false; got != want { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestMetricVec(t *testing.T) { + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + []string{"l1", "l2"}, + ) + testMetricVec(t, vec) +} + +func TestMetricVecWithCollisions(t *testing.T) { + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + []string{"l1", "l2"}, + ) + vec.hashAdd = func(h uint64, s string) uint64 { return 1 } + vec.hashAddByte = func(h uint64, b byte) uint64 { return 1 } + testMetricVec(t, vec) +} + +func testMetricVec(t *testing.T, vec *UntypedVec) { + vec.Reset() // Actually test Reset now! + + var pair [2]string + // Keep track of metrics. + expected := map[[2]string]int{} + + for i := 0; i < 1000; i++ { + pair[0], pair[1] = fmt.Sprint(i%4), fmt.Sprint(i%5) // Varying combinations multiples. + expected[pair]++ + vec.WithLabelValues(pair[0], pair[1]).Inc() + + expected[[2]string{"v1", "v2"}]++ + vec.WithLabelValues("v1", "v2").(Untyped).Inc() + } + + var total int + for _, metrics := range vec.children { + for _, metric := range metrics { + total++ + copy(pair[:], metric.values) + + var metricOut dto.Metric + if err := metric.metric.Write(&metricOut); err != nil { + t.Fatal(err) + } + actual := *metricOut.Untyped.Value + + var actualPair [2]string + for i, label := range metricOut.Label { + actualPair[i] = *label.Value + } + + // Test output pair against metric.values to ensure we've selected + // the right one. We check this to ensure the below check means + // anything at all. + if actualPair != pair { + t.Fatalf("unexpected pair association in metric map: %v != %v", actualPair, pair) + } + + if actual != float64(expected[pair]) { + t.Fatalf("incorrect counter value for %v: %v != %v", pair, actual, expected[pair]) + } + } + } + + if total != len(expected) { + t.Fatalf("unexpected number of metrics: %v != %v", total, len(expected)) + } + + vec.Reset() + + if len(vec.children) > 0 { + t.Fatalf("reset failed") + } +} + +func TestCounterVecEndToEndWithCollision(t *testing.T) { + vec := NewCounterVec( + CounterOpts{ + Name: "test", + Help: "helpless", + }, + []string{"labelname"}, + ) + vec.WithLabelValues("77kepQFQ8Kl").Inc() + vec.WithLabelValues("!0IC=VloaY").Add(2) + + m := &dto.Metric{} + if err := vec.WithLabelValues("77kepQFQ8Kl").Write(m); err != nil { + t.Fatal(err) + } + if got, want := m.GetLabel()[0].GetValue(), "77kepQFQ8Kl"; got != want { + t.Errorf("got label value %q, want %q", got, want) + } + if got, want := m.GetCounter().GetValue(), 1.; got != want { + t.Errorf("got value %f, want %f", got, want) + } + m.Reset() + if err := vec.WithLabelValues("!0IC=VloaY").Write(m); err != nil { + t.Fatal(err) + } + if got, want := m.GetLabel()[0].GetValue(), "!0IC=VloaY"; got != want { + t.Errorf("got label value %q, want %q", got, want) + } + if got, want := m.GetCounter().GetValue(), 2.; got != want { + t.Errorf("got value %f, want %f", got, want) + } +} + +func BenchmarkMetricVecWithLabelValuesBasic(b *testing.B) { + benchmarkMetricVecWithLabelValues(b, map[string][]string{ + "l1": {"onevalue"}, + "l2": {"twovalue"}, + }) +} + +func BenchmarkMetricVecWithLabelValues2Keys10ValueCardinality(b *testing.B) { + benchmarkMetricVecWithLabelValuesCardinality(b, 2, 10) +} + +func BenchmarkMetricVecWithLabelValues4Keys10ValueCardinality(b *testing.B) { + benchmarkMetricVecWithLabelValuesCardinality(b, 4, 10) +} + +func BenchmarkMetricVecWithLabelValues2Keys100ValueCardinality(b *testing.B) { + benchmarkMetricVecWithLabelValuesCardinality(b, 2, 100) +} + +func BenchmarkMetricVecWithLabelValues10Keys100ValueCardinality(b *testing.B) { + benchmarkMetricVecWithLabelValuesCardinality(b, 10, 100) +} + +func BenchmarkMetricVecWithLabelValues10Keys1000ValueCardinality(b *testing.B) { + benchmarkMetricVecWithLabelValuesCardinality(b, 10, 1000) +} + +func benchmarkMetricVecWithLabelValuesCardinality(b *testing.B, nkeys, nvalues int) { + labels := map[string][]string{} + + for i := 0; i < nkeys; i++ { + var ( + k = fmt.Sprintf("key-%v", i) + vs = make([]string, 0, nvalues) + ) + for j := 0; j < nvalues; j++ { + vs = append(vs, fmt.Sprintf("value-%v", j)) + } + labels[k] = vs + } + + benchmarkMetricVecWithLabelValues(b, labels) +} + +func benchmarkMetricVecWithLabelValues(b *testing.B, labels map[string][]string) { + var keys []string + for k := range labels { // Map order dependent, who cares though. + keys = append(keys, k) + } + + values := make([]string, len(labels)) // Value cache for permutations. + vec := NewUntypedVec( + UntypedOpts{ + Name: "test", + Help: "helpless", + }, + keys, + ) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Varies input across provide map entries based on key size. + for j, k := range keys { + candidates := labels[k] + values[j] = candidates[i%len(candidates)] + } + + vec.WithLabelValues(values...) + } +} diff --git a/vendor/github.com/prometheus/client_model/.gitignore b/vendor/github.com/prometheus/client_model/.gitignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/vendor/github.com/prometheus/client_model/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/vendor/github.com/prometheus/client_model/CONTRIBUTING.md b/vendor/github.com/prometheus/client_model/CONTRIBUTING.md new file mode 100644 index 000000000..40503edbf --- /dev/null +++ b/vendor/github.com/prometheus/client_model/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Contributing + +Prometheus uses GitHub to manage reviews of pull requests. + +* If you have a trivial fix or improvement, go ahead and create a pull request, + addressing (with `@...`) the maintainer of this repository (see + [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. + +* If you plan to do something more involved, first discuss your ideas + on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). + This will avoid unnecessary work and surely give you and us a good deal + of inspiration. + +* Relevant coding style guidelines are the [Go Code Review + Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) + and the _Formatting and style_ section of Peter Bourgon's [Go: Best + Practices for Production + Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/client_model/MAINTAINERS.md b/vendor/github.com/prometheus/client_model/MAINTAINERS.md new file mode 100644 index 000000000..3ede55fe1 --- /dev/null +++ b/vendor/github.com/prometheus/client_model/MAINTAINERS.md @@ -0,0 +1 @@ +* Björn Rabenstein diff --git a/vendor/github.com/prometheus/client_model/Makefile b/vendor/github.com/prometheus/client_model/Makefile new file mode 100644 index 000000000..e147c69da --- /dev/null +++ b/vendor/github.com/prometheus/client_model/Makefile @@ -0,0 +1,62 @@ +# Copyright 2013 Prometheus Team +# 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. + +KEY_ID ?= _DEFINE_ME_ + +all: cpp go java python ruby + +SUFFIXES: + +cpp: cpp/metrics.pb.cc cpp/metrics.pb.h + +cpp/metrics.pb.cc: metrics.proto + protoc $< --cpp_out=cpp/ + +cpp/metrics.pb.h: metrics.proto + protoc $< --cpp_out=cpp/ + +go: go/metrics.pb.go + +go/metrics.pb.go: metrics.proto + protoc $< --go_out=go/ + +java: src/main/java/io/prometheus/client/Metrics.java pom.xml + mvn clean compile package + +src/main/java/io/prometheus/client/Metrics.java: metrics.proto + protoc $< --java_out=src/main/java + +python: python/prometheus/client/model/metrics_pb2.py + +python/prometheus/client/model/metrics_pb2.py: metrics.proto + mkdir -p python/prometheus/client/model + protoc $< --python_out=python/prometheus/client/model + +ruby: + $(MAKE) -C ruby build + +clean: + -rm -rf cpp/* + -rm -rf go/* + -rm -rf java/* + -rm -rf python/* + -$(MAKE) -C ruby clean + -mvn clean + +maven-deploy-snapshot: java + mvn clean deploy -Dgpg.keyname=$(KEY_ID) -DperformRelease=true + +maven-deploy-release: java + mvn clean release:clean release:prepare release:perform -Dgpg.keyname=$(KEY_ID) -DperformRelease=true + +.PHONY: all clean cpp go java maven-deploy-snapshot maven-deploy-release python ruby diff --git a/vendor/github.com/prometheus/client_model/README.md b/vendor/github.com/prometheus/client_model/README.md new file mode 100644 index 000000000..a710042db --- /dev/null +++ b/vendor/github.com/prometheus/client_model/README.md @@ -0,0 +1,26 @@ +# Background +Under most circumstances, manually downloading this repository should never +be required. + +# Prerequisites +# Base +* [Google Protocol Buffers](https://developers.google.com/protocol-buffers) + +## Java +* [Apache Maven](http://maven.apache.org) +* [Prometheus Maven Repository](https://github.com/prometheus/io.prometheus-maven-repository) checked out into ../io.prometheus-maven-repository + +## Go +* [Go](http://golang.org) +* [goprotobuf](https://code.google.com/p/goprotobuf) + +## Ruby +* [Ruby](https://www.ruby-lang.org) +* [bundler](https://rubygems.org/gems/bundler) + +# Building + $ make + +# Getting Started + * The Go source code is periodically indexed: [Go Protocol Buffer Model](http://godoc.org/github.com/prometheus/client_model/go). + * All of the core developers are accessible via the [Prometheus Developers Mailinglist](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). diff --git a/vendor/github.com/prometheus/client_model/metrics.proto b/vendor/github.com/prometheus/client_model/metrics.proto new file mode 100644 index 000000000..0b84af920 --- /dev/null +++ b/vendor/github.com/prometheus/client_model/metrics.proto @@ -0,0 +1,81 @@ +// Copyright 2013 Prometheus Team +// 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. + +syntax = "proto2"; + +package io.prometheus.client; +option java_package = "io.prometheus.client"; + +message LabelPair { + optional string name = 1; + optional string value = 2; +} + +enum MetricType { + COUNTER = 0; + GAUGE = 1; + SUMMARY = 2; + UNTYPED = 3; + HISTOGRAM = 4; +} + +message Gauge { + optional double value = 1; +} + +message Counter { + optional double value = 1; +} + +message Quantile { + optional double quantile = 1; + optional double value = 2; +} + +message Summary { + optional uint64 sample_count = 1; + optional double sample_sum = 2; + repeated Quantile quantile = 3; +} + +message Untyped { + optional double value = 1; +} + +message Histogram { + optional uint64 sample_count = 1; + optional double sample_sum = 2; + repeated Bucket bucket = 3; // Ordered in increasing order of upper_bound, +Inf bucket is optional. +} + +message Bucket { + optional uint64 cumulative_count = 1; // Cumulative in increasing order. + optional double upper_bound = 2; // Inclusive. +} + +message Metric { + repeated LabelPair label = 1; + optional Gauge gauge = 2; + optional Counter counter = 3; + optional Summary summary = 4; + optional Untyped untyped = 5; + optional Histogram histogram = 7; + optional int64 timestamp_ms = 6; +} + +message MetricFamily { + optional string name = 1; + optional string help = 2; + optional MetricType type = 3; + repeated Metric metric = 4; +} diff --git a/vendor/github.com/prometheus/client_model/pom.xml b/vendor/github.com/prometheus/client_model/pom.xml new file mode 100644 index 000000000..4d34c9015 --- /dev/null +++ b/vendor/github.com/prometheus/client_model/pom.xml @@ -0,0 +1,130 @@ + + + 4.0.0 + + io.prometheus.client + model + 0.0.3-SNAPSHOT + + + org.sonatype.oss + oss-parent + 7 + + + Prometheus Client Data Model + http://github.com/prometheus/client_model + + Prometheus Client Data Model: Generated Protocol Buffer Assets + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + scm:git:git@github.com:prometheus/client_model.git + scm:git:git@github.com:prometheus/client_model.git + git@github.com:prometheus/client_model.git + + + + + mtp + Matt T. Proud + matt.proud@gmail.com + + + + + + com.google.protobuf + protobuf-java + 2.5.0 + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + UTF-8 + UTF-8 + true + + + + generate-javadoc-site-report + site + + javadoc + + + + attach-javadocs + + jar + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + + 3.1 + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar + + + + + + + + + release-sign-artifacts + + + performRelease + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.4 + + + sign-artifacts + verify + + sign + + + + + + + + + diff --git a/vendor/github.com/prometheus/client_model/ruby/LICENSE b/vendor/github.com/prometheus/client_model/ruby/LICENSE deleted file mode 100644 index 11069edd7..000000000 --- a/vendor/github.com/prometheus/client_model/ruby/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - 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/prometheus/client_model/setup.py b/vendor/github.com/prometheus/client_model/setup.py new file mode 100644 index 000000000..67b9f20e3 --- /dev/null +++ b/vendor/github.com/prometheus/client_model/setup.py @@ -0,0 +1,23 @@ +#!/usr/bin/python + +from setuptools import setup + +setup( + name = 'prometheus_client_model', + version = '0.0.1', + author = 'Matt T. Proud', + author_email = 'matt.proud@gmail.com', + description = 'Data model artifacts for the Prometheus client.', + license = 'Apache License 2.0', + url = 'http://github.com/prometheus/client_model', + packages = ['prometheus', 'prometheus/client', 'prometheus/client/model'], + package_dir = {'': 'python'}, + requires = ['protobuf(==2.4.1)'], + platforms = 'Platform Independent', + classifiers = ['Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Topic :: Software Development :: Testing', + 'Topic :: System :: Monitoring']) diff --git a/vendor/github.com/prometheus/common/.travis.yml b/vendor/github.com/prometheus/common/.travis.yml new file mode 100644 index 000000000..2fe8e9ad7 --- /dev/null +++ b/vendor/github.com/prometheus/common/.travis.yml @@ -0,0 +1,6 @@ +sudo: false + +language: go +go: + - 1.7.5 + - tip diff --git a/vendor/github.com/prometheus/common/CONTRIBUTING.md b/vendor/github.com/prometheus/common/CONTRIBUTING.md new file mode 100644 index 000000000..40503edbf --- /dev/null +++ b/vendor/github.com/prometheus/common/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Contributing + +Prometheus uses GitHub to manage reviews of pull requests. + +* If you have a trivial fix or improvement, go ahead and create a pull request, + addressing (with `@...`) the maintainer of this repository (see + [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. + +* If you plan to do something more involved, first discuss your ideas + on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). + This will avoid unnecessary work and surely give you and us a good deal + of inspiration. + +* Relevant coding style guidelines are the [Go Code Review + Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) + and the _Formatting and style_ section of Peter Bourgon's [Go: Best + Practices for Production + Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/common/MAINTAINERS.md b/vendor/github.com/prometheus/common/MAINTAINERS.md new file mode 100644 index 000000000..1b3152161 --- /dev/null +++ b/vendor/github.com/prometheus/common/MAINTAINERS.md @@ -0,0 +1 @@ +* Fabian Reinartz diff --git a/vendor/github.com/prometheus/common/README.md b/vendor/github.com/prometheus/common/README.md new file mode 100644 index 000000000..47985e4ad --- /dev/null +++ b/vendor/github.com/prometheus/common/README.md @@ -0,0 +1,12 @@ +# Common +[![Build Status](https://travis-ci.org/prometheus/common.svg)](https://travis-ci.org/prometheus/common) + +This repository contains Go libraries that are shared across Prometheus +components and libraries. + +* **config**: Common configuration structures +* **expfmt**: Decoding and encoding for the exposition format +* **log**: A logging wrapper around [logrus](https://github.com/sirupsen/logrus) +* **model**: Shared data structures +* **route**: A routing wrapper around [httprouter](https://github.com/julienschmidt/httprouter) using `context.Context` +* **version**: Version information and metrics diff --git a/vendor/github.com/prometheus/common/expfmt/bench_test.go b/vendor/github.com/prometheus/common/expfmt/bench_test.go new file mode 100644 index 000000000..e539bfc13 --- /dev/null +++ b/vendor/github.com/prometheus/common/expfmt/bench_test.go @@ -0,0 +1,167 @@ +// Copyright 2015 The Prometheus 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 expfmt + +import ( + "bytes" + "compress/gzip" + "io" + "io/ioutil" + "testing" + + "github.com/matttproud/golang_protobuf_extensions/pbutil" + + dto "github.com/prometheus/client_model/go" +) + +var parser TextParser + +// Benchmarks to show how much penalty text format parsing actually inflicts. +// +// Example results on Linux 3.13.0, Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz, go1.4. +// +// BenchmarkParseText 1000 1188535 ns/op 205085 B/op 6135 allocs/op +// BenchmarkParseTextGzip 1000 1376567 ns/op 246224 B/op 6151 allocs/op +// BenchmarkParseProto 10000 172790 ns/op 52258 B/op 1160 allocs/op +// BenchmarkParseProtoGzip 5000 324021 ns/op 94931 B/op 1211 allocs/op +// BenchmarkParseProtoMap 10000 187946 ns/op 58714 B/op 1203 allocs/op +// +// CONCLUSION: The overhead for the map is negligible. Text format needs ~5x more allocations. +// Without compression, it needs ~7x longer, but with compression (the more relevant scenario), +// the difference becomes less relevant, only ~4x. +// +// The test data contains 248 samples. + +// BenchmarkParseText benchmarks the parsing of a text-format scrape into metric +// family DTOs. +func BenchmarkParseText(b *testing.B) { + b.StopTimer() + data, err := ioutil.ReadFile("testdata/text") + if err != nil { + b.Fatal(err) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + if _, err := parser.TextToMetricFamilies(bytes.NewReader(data)); err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkParseTextGzip benchmarks the parsing of a gzipped text-format scrape +// into metric family DTOs. +func BenchmarkParseTextGzip(b *testing.B) { + b.StopTimer() + data, err := ioutil.ReadFile("testdata/text.gz") + if err != nil { + b.Fatal(err) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + in, err := gzip.NewReader(bytes.NewReader(data)) + if err != nil { + b.Fatal(err) + } + if _, err := parser.TextToMetricFamilies(in); err != nil { + b.Fatal(err) + } + } +} + +// BenchmarkParseProto benchmarks the parsing of a protobuf-format scrape into +// metric family DTOs. Note that this does not build a map of metric families +// (as the text version does), because it is not required for Prometheus +// ingestion either. (However, it is required for the text-format parsing, as +// the metric family might be sprinkled all over the text, while the +// protobuf-format guarantees bundling at one place.) +func BenchmarkParseProto(b *testing.B) { + b.StopTimer() + data, err := ioutil.ReadFile("testdata/protobuf") + if err != nil { + b.Fatal(err) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + family := &dto.MetricFamily{} + in := bytes.NewReader(data) + for { + family.Reset() + if _, err := pbutil.ReadDelimited(in, family); err != nil { + if err == io.EOF { + break + } + b.Fatal(err) + } + } + } +} + +// BenchmarkParseProtoGzip is like BenchmarkParseProto above, but parses gzipped +// protobuf format. +func BenchmarkParseProtoGzip(b *testing.B) { + b.StopTimer() + data, err := ioutil.ReadFile("testdata/protobuf.gz") + if err != nil { + b.Fatal(err) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + family := &dto.MetricFamily{} + in, err := gzip.NewReader(bytes.NewReader(data)) + if err != nil { + b.Fatal(err) + } + for { + family.Reset() + if _, err := pbutil.ReadDelimited(in, family); err != nil { + if err == io.EOF { + break + } + b.Fatal(err) + } + } + } +} + +// BenchmarkParseProtoMap is like BenchmarkParseProto but DOES put the parsed +// metric family DTOs into a map. This is not happening during Prometheus +// ingestion. It is just here to measure the overhead of that map creation and +// separate it from the overhead of the text format parsing. +func BenchmarkParseProtoMap(b *testing.B) { + b.StopTimer() + data, err := ioutil.ReadFile("testdata/protobuf") + if err != nil { + b.Fatal(err) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + families := map[string]*dto.MetricFamily{} + in := bytes.NewReader(data) + for { + family := &dto.MetricFamily{} + if _, err := pbutil.ReadDelimited(in, family); err != nil { + if err == io.EOF { + break + } + b.Fatal(err) + } + families[family.GetName()] = family + } + } +} diff --git a/vendor/github.com/prometheus/common/expfmt/decode_test.go b/vendor/github.com/prometheus/common/expfmt/decode_test.go new file mode 100644 index 000000000..82c1130c9 --- /dev/null +++ b/vendor/github.com/prometheus/common/expfmt/decode_test.go @@ -0,0 +1,435 @@ +// Copyright 2015 The Prometheus 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 expfmt + +import ( + "io" + "net/http" + "reflect" + "sort" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + dto "github.com/prometheus/client_model/go" + + "github.com/prometheus/common/model" +) + +func TestTextDecoder(t *testing.T) { + var ( + ts = model.Now() + in = ` +# Only a quite simple scenario with two metric families. +# More complicated tests of the parser itself can be found in the text package. +# TYPE mf2 counter +mf2 3 +mf1{label="value1"} -3.14 123456 +mf1{label="value2"} 42 +mf2 4 +` + out = model.Vector{ + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "mf1", + "label": "value1", + }, + Value: -3.14, + Timestamp: 123456, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "mf1", + "label": "value2", + }, + Value: 42, + Timestamp: ts, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "mf2", + }, + Value: 3, + Timestamp: ts, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "mf2", + }, + Value: 4, + Timestamp: ts, + }, + } + ) + + dec := &SampleDecoder{ + Dec: &textDecoder{r: strings.NewReader(in)}, + Opts: &DecodeOptions{ + Timestamp: ts, + }, + } + var all model.Vector + for { + var smpls model.Vector + err := dec.Decode(&smpls) + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } + all = append(all, smpls...) + } + sort.Sort(all) + sort.Sort(out) + if !reflect.DeepEqual(all, out) { + t.Fatalf("output does not match") + } +} + +func TestProtoDecoder(t *testing.T) { + + var testTime = model.Now() + + scenarios := []struct { + in string + expected model.Vector + fail bool + }{ + { + in: "", + }, + { + in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_!abel_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@", + fail: true, + }, + { + in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_label_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@", + expected: model.Vector{ + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count", + "some_label_name": "some_label_value", + }, + Value: -42, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count", + "another_label_name": "another_label_value", + }, + Value: 84, + Timestamp: testTime, + }, + }, + }, + { + in: "\xb9\x01\n\rrequest_count\x12\x12Number of requests\x18\x02\"O\n#\n\x0fsome_label_name\x12\x10some_label_value\"(\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00\x00\x00\x00E\xc0\x1a\x12\t+\x87\x16\xd9\xce\xf7\xef?\x11\x00\x00\x00\x00\x00\x00U\xc0\"A\n)\n\x12another_label_name\x12\x13another_label_value\"\x14\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00\x00\x00\x00\x00\x00$@", + expected: model.Vector{ + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count_count", + "some_label_name": "some_label_value", + }, + Value: 0, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count_sum", + "some_label_name": "some_label_value", + }, + Value: 0, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count", + "some_label_name": "some_label_value", + "quantile": "0.99", + }, + Value: -42, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count", + "some_label_name": "some_label_value", + "quantile": "0.999", + }, + Value: -84, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count_count", + "another_label_name": "another_label_value", + }, + Value: 0, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count_sum", + "another_label_name": "another_label_value", + }, + Value: 0, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count", + "another_label_name": "another_label_value", + "quantile": "0.5", + }, + Value: 10, + Timestamp: testTime, + }, + }, + }, + { + in: "\x8d\x01\n\x1drequest_duration_microseconds\x12\x15The response latency.\x18\x04\"S:Q\b\x85\x15\x11\xcd\xcc\xccL\x8f\xcb:A\x1a\v\b{\x11\x00\x00\x00\x00\x00\x00Y@\x1a\f\b\x9c\x03\x11\x00\x00\x00\x00\x00\x00^@\x1a\f\b\xd0\x04\x11\x00\x00\x00\x00\x00\x00b@\x1a\f\b\xf4\v\x11\x9a\x99\x99\x99\x99\x99e@\x1a\f\b\x85\x15\x11\x00\x00\x00\x00\x00\x00\xf0\u007f", + expected: model.Vector{ + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_bucket", + "le": "100", + }, + Value: 123, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_bucket", + "le": "120", + }, + Value: 412, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_bucket", + "le": "144", + }, + Value: 592, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_bucket", + "le": "172.8", + }, + Value: 1524, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_bucket", + "le": "+Inf", + }, + Value: 2693, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_sum", + }, + Value: 1756047.3, + Timestamp: testTime, + }, + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_duration_microseconds_count", + }, + Value: 2693, + Timestamp: testTime, + }, + }, + }, + { + // The metric type is unset in this protobuf, which needs to be handled + // correctly by the decoder. + in: "\x1c\n\rrequest_count\"\v\x1a\t\t\x00\x00\x00\x00\x00\x00\xf0?", + expected: model.Vector{ + &model.Sample{ + Metric: model.Metric{ + model.MetricNameLabel: "request_count", + }, + Value: 1, + Timestamp: testTime, + }, + }, + }, + } + + for i, scenario := range scenarios { + dec := &SampleDecoder{ + Dec: &protoDecoder{r: strings.NewReader(scenario.in)}, + Opts: &DecodeOptions{ + Timestamp: testTime, + }, + } + + var all model.Vector + for { + var smpls model.Vector + err := dec.Decode(&smpls) + if err == io.EOF { + break + } + if scenario.fail { + if err == nil { + t.Fatal("Expected error but got none") + } + break + } + if err != nil { + t.Fatal(err) + } + all = append(all, smpls...) + } + sort.Sort(all) + sort.Sort(scenario.expected) + if !reflect.DeepEqual(all, scenario.expected) { + t.Fatalf("%d. output does not match, want: %#v, got %#v", i, scenario.expected, all) + } + } +} + +func testDiscriminatorHTTPHeader(t testing.TB) { + var scenarios = []struct { + input map[string]string + output Format + err error + }{ + { + input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`}, + output: FmtProtoDelim, + }, + { + input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`}, + output: FmtUnknown, + }, + { + input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`}, + output: FmtUnknown, + }, + { + input: map[string]string{"Content-Type": `text/plain; version=0.0.4`}, + output: FmtText, + }, + { + input: map[string]string{"Content-Type": `text/plain`}, + output: FmtText, + }, + { + input: map[string]string{"Content-Type": `text/plain; version=0.0.3`}, + output: FmtUnknown, + }, + } + + for i, scenario := range scenarios { + var header http.Header + + if len(scenario.input) > 0 { + header = http.Header{} + } + + for key, value := range scenario.input { + header.Add(key, value) + } + + actual := ResponseFormat(header) + + if scenario.output != actual { + t.Errorf("%d. expected %s, got %s", i, scenario.output, actual) + } + } +} + +func TestDiscriminatorHTTPHeader(t *testing.T) { + testDiscriminatorHTTPHeader(t) +} + +func BenchmarkDiscriminatorHTTPHeader(b *testing.B) { + for i := 0; i < b.N; i++ { + testDiscriminatorHTTPHeader(b) + } +} + +func TestExtractSamples(t *testing.T) { + var ( + goodMetricFamily1 = &dto.MetricFamily{ + Name: proto.String("foo"), + Help: proto.String("Help for foo."), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Counter: &dto.Counter{ + Value: proto.Float64(4711), + }, + }, + }, + } + goodMetricFamily2 = &dto.MetricFamily{ + Name: proto.String("bar"), + Help: proto.String("Help for bar."), + Type: dto.MetricType_GAUGE.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Gauge: &dto.Gauge{ + Value: proto.Float64(3.14), + }, + }, + }, + } + badMetricFamily = &dto.MetricFamily{ + Name: proto.String("bad"), + Help: proto.String("Help for bad."), + Type: dto.MetricType(42).Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Gauge: &dto.Gauge{ + Value: proto.Float64(2.7), + }, + }, + }, + } + + opts = &DecodeOptions{ + Timestamp: 42, + } + ) + + got, err := ExtractSamples(opts, goodMetricFamily1, goodMetricFamily2) + if err != nil { + t.Error("Unexpected error from ExtractSamples:", err) + } + want := model.Vector{ + &model.Sample{Metric: model.Metric{model.MetricNameLabel: "foo"}, Value: 4711, Timestamp: 42}, + &model.Sample{Metric: model.Metric{model.MetricNameLabel: "bar"}, Value: 3.14, Timestamp: 42}, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want) + } + + got, err = ExtractSamples(opts, goodMetricFamily1, badMetricFamily, goodMetricFamily2) + if err == nil { + t.Error("Expected error from ExtractSamples") + } + if !reflect.DeepEqual(got, want) { + t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want) + } +} diff --git a/vendor/github.com/prometheus/common/expfmt/text_create_test.go b/vendor/github.com/prometheus/common/expfmt/text_create_test.go new file mode 100644 index 000000000..e4cc5d803 --- /dev/null +++ b/vendor/github.com/prometheus/common/expfmt/text_create_test.go @@ -0,0 +1,443 @@ +// Copyright 2014 The Prometheus 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 expfmt + +import ( + "bytes" + "math" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + + dto "github.com/prometheus/client_model/go" +) + +func testCreate(t testing.TB) { + var scenarios = []struct { + in *dto.MetricFamily + out string + }{ + // 0: Counter, NaN as value, timestamp given. + { + in: &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("two-line\n doc str\\ing"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("labelname"), + Value: proto.String("val1"), + }, + &dto.LabelPair{ + Name: proto.String("basename"), + Value: proto.String("basevalue"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(math.NaN()), + }, + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("labelname"), + Value: proto.String("val2"), + }, + &dto.LabelPair{ + Name: proto.String("basename"), + Value: proto.String("basevalue"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(.23), + }, + TimestampMs: proto.Int64(1234567890), + }, + }, + }, + out: `# HELP name two-line\n doc str\\ing +# TYPE name counter +name{labelname="val1",basename="basevalue"} NaN +name{labelname="val2",basename="basevalue"} 0.23 1234567890 +`, + }, + // 1: Gauge, some escaping required, +Inf as value, multi-byte characters in label values. + { + in: &dto.MetricFamily{ + Name: proto.String("gauge_name"), + Help: proto.String("gauge\ndoc\nstr\"ing"), + Type: dto.MetricType_GAUGE.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("name_1"), + Value: proto.String("val with\nnew line"), + }, + &dto.LabelPair{ + Name: proto.String("name_2"), + Value: proto.String("val with \\backslash and \"quotes\""), + }, + }, + Gauge: &dto.Gauge{ + Value: proto.Float64(math.Inf(+1)), + }, + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("name_1"), + Value: proto.String("Björn"), + }, + &dto.LabelPair{ + Name: proto.String("name_2"), + Value: proto.String("佖佥"), + }, + }, + Gauge: &dto.Gauge{ + Value: proto.Float64(3.14E42), + }, + }, + }, + }, + out: `# HELP gauge_name gauge\ndoc\nstr"ing +# TYPE gauge_name gauge +gauge_name{name_1="val with\nnew line",name_2="val with \\backslash and \"quotes\""} +Inf +gauge_name{name_1="Björn",name_2="佖佥"} 3.14e+42 +`, + }, + // 2: Untyped, no help, one sample with no labels and -Inf as value, another sample with one label. + { + in: &dto.MetricFamily{ + Name: proto.String("untyped_name"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(math.Inf(-1)), + }, + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("name_1"), + Value: proto.String("value 1"), + }, + }, + Untyped: &dto.Untyped{ + Value: proto.Float64(-1.23e-45), + }, + }, + }, + }, + out: `# TYPE untyped_name untyped +untyped_name -Inf +untyped_name{name_1="value 1"} -1.23e-45 +`, + }, + // 3: Summary. + { + in: &dto.MetricFamily{ + Name: proto.String("summary_name"), + Help: proto.String("summary docstring"), + Type: dto.MetricType_SUMMARY.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Summary: &dto.Summary{ + SampleCount: proto.Uint64(42), + SampleSum: proto.Float64(-3.4567), + Quantile: []*dto.Quantile{ + &dto.Quantile{ + Quantile: proto.Float64(0.5), + Value: proto.Float64(-1.23), + }, + &dto.Quantile{ + Quantile: proto.Float64(0.9), + Value: proto.Float64(.2342354), + }, + &dto.Quantile{ + Quantile: proto.Float64(0.99), + Value: proto.Float64(0), + }, + }, + }, + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("name_1"), + Value: proto.String("value 1"), + }, + &dto.LabelPair{ + Name: proto.String("name_2"), + Value: proto.String("value 2"), + }, + }, + Summary: &dto.Summary{ + SampleCount: proto.Uint64(4711), + SampleSum: proto.Float64(2010.1971), + Quantile: []*dto.Quantile{ + &dto.Quantile{ + Quantile: proto.Float64(0.5), + Value: proto.Float64(1), + }, + &dto.Quantile{ + Quantile: proto.Float64(0.9), + Value: proto.Float64(2), + }, + &dto.Quantile{ + Quantile: proto.Float64(0.99), + Value: proto.Float64(3), + }, + }, + }, + }, + }, + }, + out: `# HELP summary_name summary docstring +# TYPE summary_name summary +summary_name{quantile="0.5"} -1.23 +summary_name{quantile="0.9"} 0.2342354 +summary_name{quantile="0.99"} 0 +summary_name_sum -3.4567 +summary_name_count 42 +summary_name{name_1="value 1",name_2="value 2",quantile="0.5"} 1 +summary_name{name_1="value 1",name_2="value 2",quantile="0.9"} 2 +summary_name{name_1="value 1",name_2="value 2",quantile="0.99"} 3 +summary_name_sum{name_1="value 1",name_2="value 2"} 2010.1971 +summary_name_count{name_1="value 1",name_2="value 2"} 4711 +`, + }, + // 4: Histogram + { + in: &dto.MetricFamily{ + Name: proto.String("request_duration_microseconds"), + Help: proto.String("The response latency."), + Type: dto.MetricType_HISTOGRAM.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Histogram: &dto.Histogram{ + SampleCount: proto.Uint64(2693), + SampleSum: proto.Float64(1756047.3), + Bucket: []*dto.Bucket{ + &dto.Bucket{ + UpperBound: proto.Float64(100), + CumulativeCount: proto.Uint64(123), + }, + &dto.Bucket{ + UpperBound: proto.Float64(120), + CumulativeCount: proto.Uint64(412), + }, + &dto.Bucket{ + UpperBound: proto.Float64(144), + CumulativeCount: proto.Uint64(592), + }, + &dto.Bucket{ + UpperBound: proto.Float64(172.8), + CumulativeCount: proto.Uint64(1524), + }, + &dto.Bucket{ + UpperBound: proto.Float64(math.Inf(+1)), + CumulativeCount: proto.Uint64(2693), + }, + }, + }, + }, + }, + }, + out: `# HELP request_duration_microseconds The response latency. +# TYPE request_duration_microseconds histogram +request_duration_microseconds_bucket{le="100"} 123 +request_duration_microseconds_bucket{le="120"} 412 +request_duration_microseconds_bucket{le="144"} 592 +request_duration_microseconds_bucket{le="172.8"} 1524 +request_duration_microseconds_bucket{le="+Inf"} 2693 +request_duration_microseconds_sum 1.7560473e+06 +request_duration_microseconds_count 2693 +`, + }, + // 5: Histogram with missing +Inf bucket. + { + in: &dto.MetricFamily{ + Name: proto.String("request_duration_microseconds"), + Help: proto.String("The response latency."), + Type: dto.MetricType_HISTOGRAM.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Histogram: &dto.Histogram{ + SampleCount: proto.Uint64(2693), + SampleSum: proto.Float64(1756047.3), + Bucket: []*dto.Bucket{ + &dto.Bucket{ + UpperBound: proto.Float64(100), + CumulativeCount: proto.Uint64(123), + }, + &dto.Bucket{ + UpperBound: proto.Float64(120), + CumulativeCount: proto.Uint64(412), + }, + &dto.Bucket{ + UpperBound: proto.Float64(144), + CumulativeCount: proto.Uint64(592), + }, + &dto.Bucket{ + UpperBound: proto.Float64(172.8), + CumulativeCount: proto.Uint64(1524), + }, + }, + }, + }, + }, + }, + out: `# HELP request_duration_microseconds The response latency. +# TYPE request_duration_microseconds histogram +request_duration_microseconds_bucket{le="100"} 123 +request_duration_microseconds_bucket{le="120"} 412 +request_duration_microseconds_bucket{le="144"} 592 +request_duration_microseconds_bucket{le="172.8"} 1524 +request_duration_microseconds_bucket{le="+Inf"} 2693 +request_duration_microseconds_sum 1.7560473e+06 +request_duration_microseconds_count 2693 +`, + }, + // 6: No metric type, should result in default type Counter. + { + in: &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("doc string"), + Metric: []*dto.Metric{ + &dto.Metric{ + Counter: &dto.Counter{ + Value: proto.Float64(math.Inf(-1)), + }, + }, + }, + }, + out: `# HELP name doc string +# TYPE name counter +name -Inf +`, + }, + } + + for i, scenario := range scenarios { + out := bytes.NewBuffer(make([]byte, 0, len(scenario.out))) + n, err := MetricFamilyToText(out, scenario.in) + if err != nil { + t.Errorf("%d. error: %s", i, err) + continue + } + if expected, got := len(scenario.out), n; expected != got { + t.Errorf( + "%d. expected %d bytes written, got %d", + i, expected, got, + ) + } + if expected, got := scenario.out, out.String(); expected != got { + t.Errorf( + "%d. expected out=%q, got %q", + i, expected, got, + ) + } + } + +} + +func TestCreate(t *testing.T) { + testCreate(t) +} + +func BenchmarkCreate(b *testing.B) { + for i := 0; i < b.N; i++ { + testCreate(b) + } +} + +func testCreateError(t testing.TB) { + var scenarios = []struct { + in *dto.MetricFamily + err string + }{ + // 0: No metric. + { + in: &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("doc string"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{}, + }, + err: "MetricFamily has no metrics", + }, + // 1: No metric name. + { + in: &dto.MetricFamily{ + Help: proto.String("doc string"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(math.Inf(-1)), + }, + }, + }, + }, + err: "MetricFamily has no name", + }, + // 2: Wrong type. + { + in: &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("doc string"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(math.Inf(-1)), + }, + }, + }, + }, + err: "expected counter in metric", + }, + } + + for i, scenario := range scenarios { + var out bytes.Buffer + _, err := MetricFamilyToText(&out, scenario.in) + if err == nil { + t.Errorf("%d. expected error, got nil", i) + continue + } + if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 { + t.Errorf( + "%d. expected error starting with %q, got %q", + i, expected, got, + ) + } + } + +} + +func TestCreateError(t *testing.T) { + testCreateError(t) +} + +func BenchmarkCreateError(b *testing.B) { + for i := 0; i < b.N; i++ { + testCreateError(b) + } +} diff --git a/vendor/github.com/prometheus/common/expfmt/text_parse_test.go b/vendor/github.com/prometheus/common/expfmt/text_parse_test.go new file mode 100644 index 000000000..76c951185 --- /dev/null +++ b/vendor/github.com/prometheus/common/expfmt/text_parse_test.go @@ -0,0 +1,593 @@ +// Copyright 2014 The Prometheus 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 expfmt + +import ( + "math" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + dto "github.com/prometheus/client_model/go" +) + +func testTextParse(t testing.TB) { + var scenarios = []struct { + in string + out []*dto.MetricFamily + }{ + // 0: Empty lines as input. + { + in: ` + +`, + out: []*dto.MetricFamily{}, + }, + // 1: Minimal case. + { + in: ` +minimal_metric 1.234 +another_metric -3e3 103948 +# Even that: +no_labels{} 3 +# HELP line for non-existing metric will be ignored. +`, + out: []*dto.MetricFamily{ + &dto.MetricFamily{ + Name: proto.String("minimal_metric"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(1.234), + }, + }, + }, + }, + &dto.MetricFamily{ + Name: proto.String("another_metric"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(-3e3), + }, + TimestampMs: proto.Int64(103948), + }, + }, + }, + &dto.MetricFamily{ + Name: proto.String("no_labels"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(3), + }, + }, + }, + }, + }, + }, + // 2: Counters & gauges, docstrings, various whitespace, escape sequences. + { + in: ` +# A normal comment. +# +# TYPE name counter +name{labelname="val1",basename="basevalue"} NaN +name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890 +# HELP name two-line\n doc str\\ing + + # HELP name2 doc str"ing 2 + # TYPE name2 gauge +name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321 +name2{ labelname = "val1" , }-Inf +`, + out: []*dto.MetricFamily{ + &dto.MetricFamily{ + Name: proto.String("name"), + Help: proto.String("two-line\n doc str\\ing"), + Type: dto.MetricType_COUNTER.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("labelname"), + Value: proto.String("val1"), + }, + &dto.LabelPair{ + Name: proto.String("basename"), + Value: proto.String("basevalue"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(math.NaN()), + }, + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("labelname"), + Value: proto.String("val2"), + }, + &dto.LabelPair{ + Name: proto.String("basename"), + Value: proto.String("base\"v\\al\nue"), + }, + }, + Counter: &dto.Counter{ + Value: proto.Float64(.23), + }, + TimestampMs: proto.Int64(1234567890), + }, + }, + }, + &dto.MetricFamily{ + Name: proto.String("name2"), + Help: proto.String("doc str\"ing 2"), + Type: dto.MetricType_GAUGE.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("labelname"), + Value: proto.String("val2"), + }, + &dto.LabelPair{ + Name: proto.String("basename"), + Value: proto.String("basevalue2"), + }, + }, + Gauge: &dto.Gauge{ + Value: proto.Float64(math.Inf(+1)), + }, + TimestampMs: proto.Int64(54321), + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("labelname"), + Value: proto.String("val1"), + }, + }, + Gauge: &dto.Gauge{ + Value: proto.Float64(math.Inf(-1)), + }, + }, + }, + }, + }, + }, + // 3: The evil summary, mixed with other types and funny comments. + { + in: ` +# TYPE my_summary summary +my_summary{n1="val1",quantile="0.5"} 110 +decoy -1 -2 +my_summary{n1="val1",quantile="0.9"} 140 1 +my_summary_count{n1="val1"} 42 +# Latest timestamp wins in case of a summary. +my_summary_sum{n1="val1"} 4711 2 +fake_sum{n1="val1"} 2001 +# TYPE another_summary summary +another_summary_count{n2="val2",n1="val1"} 20 +my_summary_count{n2="val2",n1="val1"} 5 5 +another_summary{n1="val1",n2="val2",quantile=".3"} -1.2 +my_summary_sum{n1="val2"} 08 15 +my_summary{n1="val3", quantile="0.2"} 4711 + my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN +# some +# funny comments +# HELP +# HELP +# HELP my_summary +# HELP my_summary +`, + out: []*dto.MetricFamily{ + &dto.MetricFamily{ + Name: proto.String("fake_sum"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("n1"), + Value: proto.String("val1"), + }, + }, + Untyped: &dto.Untyped{ + Value: proto.Float64(2001), + }, + }, + }, + }, + &dto.MetricFamily{ + Name: proto.String("decoy"), + Type: dto.MetricType_UNTYPED.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Untyped: &dto.Untyped{ + Value: proto.Float64(-1), + }, + TimestampMs: proto.Int64(-2), + }, + }, + }, + &dto.MetricFamily{ + Name: proto.String("my_summary"), + Type: dto.MetricType_SUMMARY.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("n1"), + Value: proto.String("val1"), + }, + }, + Summary: &dto.Summary{ + SampleCount: proto.Uint64(42), + SampleSum: proto.Float64(4711), + Quantile: []*dto.Quantile{ + &dto.Quantile{ + Quantile: proto.Float64(0.5), + Value: proto.Float64(110), + }, + &dto.Quantile{ + Quantile: proto.Float64(0.9), + Value: proto.Float64(140), + }, + }, + }, + TimestampMs: proto.Int64(2), + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("n2"), + Value: proto.String("val2"), + }, + &dto.LabelPair{ + Name: proto.String("n1"), + Value: proto.String("val1"), + }, + }, + Summary: &dto.Summary{ + SampleCount: proto.Uint64(5), + Quantile: []*dto.Quantile{ + &dto.Quantile{ + Quantile: proto.Float64(-12.34), + Value: proto.Float64(math.NaN()), + }, + }, + }, + TimestampMs: proto.Int64(5), + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("n1"), + Value: proto.String("val2"), + }, + }, + Summary: &dto.Summary{ + SampleSum: proto.Float64(8), + }, + TimestampMs: proto.Int64(15), + }, + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("n1"), + Value: proto.String("val3"), + }, + }, + Summary: &dto.Summary{ + Quantile: []*dto.Quantile{ + &dto.Quantile{ + Quantile: proto.Float64(0.2), + Value: proto.Float64(4711), + }, + }, + }, + }, + }, + }, + &dto.MetricFamily{ + Name: proto.String("another_summary"), + Type: dto.MetricType_SUMMARY.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Label: []*dto.LabelPair{ + &dto.LabelPair{ + Name: proto.String("n2"), + Value: proto.String("val2"), + }, + &dto.LabelPair{ + Name: proto.String("n1"), + Value: proto.String("val1"), + }, + }, + Summary: &dto.Summary{ + SampleCount: proto.Uint64(20), + Quantile: []*dto.Quantile{ + &dto.Quantile{ + Quantile: proto.Float64(0.3), + Value: proto.Float64(-1.2), + }, + }, + }, + }, + }, + }, + }, + }, + // 4: The histogram. + { + in: ` +# HELP request_duration_microseconds The response latency. +# TYPE request_duration_microseconds histogram +request_duration_microseconds_bucket{le="100"} 123 +request_duration_microseconds_bucket{le="120"} 412 +request_duration_microseconds_bucket{le="144"} 592 +request_duration_microseconds_bucket{le="172.8"} 1524 +request_duration_microseconds_bucket{le="+Inf"} 2693 +request_duration_microseconds_sum 1.7560473e+06 +request_duration_microseconds_count 2693 +`, + out: []*dto.MetricFamily{ + { + Name: proto.String("request_duration_microseconds"), + Help: proto.String("The response latency."), + Type: dto.MetricType_HISTOGRAM.Enum(), + Metric: []*dto.Metric{ + &dto.Metric{ + Histogram: &dto.Histogram{ + SampleCount: proto.Uint64(2693), + SampleSum: proto.Float64(1756047.3), + Bucket: []*dto.Bucket{ + &dto.Bucket{ + UpperBound: proto.Float64(100), + CumulativeCount: proto.Uint64(123), + }, + &dto.Bucket{ + UpperBound: proto.Float64(120), + CumulativeCount: proto.Uint64(412), + }, + &dto.Bucket{ + UpperBound: proto.Float64(144), + CumulativeCount: proto.Uint64(592), + }, + &dto.Bucket{ + UpperBound: proto.Float64(172.8), + CumulativeCount: proto.Uint64(1524), + }, + &dto.Bucket{ + UpperBound: proto.Float64(math.Inf(+1)), + CumulativeCount: proto.Uint64(2693), + }, + }, + }, + }, + }, + }, + }, + }, + } + + for i, scenario := range scenarios { + out, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in)) + if err != nil { + t.Errorf("%d. error: %s", i, err) + continue + } + if expected, got := len(scenario.out), len(out); expected != got { + t.Errorf( + "%d. expected %d MetricFamilies, got %d", + i, expected, got, + ) + } + for _, expected := range scenario.out { + got, ok := out[expected.GetName()] + if !ok { + t.Errorf( + "%d. expected MetricFamily %q, found none", + i, expected.GetName(), + ) + continue + } + if expected.String() != got.String() { + t.Errorf( + "%d. expected MetricFamily %s, got %s", + i, expected, got, + ) + } + } + } +} + +func TestTextParse(t *testing.T) { + testTextParse(t) +} + +func BenchmarkTextParse(b *testing.B) { + for i := 0; i < b.N; i++ { + testTextParse(b) + } +} + +func testTextParseError(t testing.TB) { + var scenarios = []struct { + in string + err string + }{ + // 0: No new-line at end of input. + { + in: ` +bla 3.14 +blubber 42`, + err: "text format parsing error in line 3: unexpected end of input stream", + }, + // 1: Invalid escape sequence in label value. + { + in: `metric{label="\t"} 3.14`, + err: "text format parsing error in line 1: invalid escape sequence", + }, + // 2: Newline in label value. + { + in: ` +metric{label="new +line"} 3.14 +`, + err: `text format parsing error in line 2: label value "new" contains unescaped new-line`, + }, + // 3: + { + in: `metric{@="bla"} 3.14`, + err: "text format parsing error in line 1: invalid label name for metric", + }, + // 4: + { + in: `metric{__name__="bla"} 3.14`, + err: `text format parsing error in line 1: label name "__name__" is reserved`, + }, + // 5: + { + in: `metric{label+="bla"} 3.14`, + err: "text format parsing error in line 1: expected '=' after label name", + }, + // 6: + { + in: `metric{label=bla} 3.14`, + err: "text format parsing error in line 1: expected '\"' at start of label value", + }, + // 7: + { + in: ` +# TYPE metric summary +metric{quantile="bla"} 3.14 +`, + err: "text format parsing error in line 3: expected float as value for 'quantile' label", + }, + // 8: + { + in: `metric{label="bla"+} 3.14`, + err: "text format parsing error in line 1: unexpected end of label value", + }, + // 9: + { + in: `metric{label="bla"} 3.14 2.72 +`, + err: "text format parsing error in line 1: expected integer as timestamp", + }, + // 10: + { + in: `metric{label="bla"} 3.14 2 3 +`, + err: "text format parsing error in line 1: spurious string after timestamp", + }, + // 11: + { + in: `metric{label="bla"} blubb +`, + err: "text format parsing error in line 1: expected float as value", + }, + // 12: + { + in: ` +# HELP metric one +# HELP metric two +`, + err: "text format parsing error in line 3: second HELP line for metric name", + }, + // 13: + { + in: ` +# TYPE metric counter +# TYPE metric untyped +`, + err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`, + }, + // 14: + { + in: ` +metric 4.12 +# TYPE metric counter +`, + err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`, + }, + // 14: + { + in: ` +# TYPE metric bla +`, + err: "text format parsing error in line 2: unknown metric type", + }, + // 15: + { + in: ` +# TYPE met-ric +`, + err: "text format parsing error in line 2: invalid metric name in comment", + }, + // 16: + { + in: `@invalidmetric{label="bla"} 3.14 2`, + err: "text format parsing error in line 1: invalid metric name", + }, + // 17: + { + in: `{label="bla"} 3.14 2`, + err: "text format parsing error in line 1: invalid metric name", + }, + // 18: + { + in: ` +# TYPE metric histogram +metric_bucket{le="bla"} 3.14 +`, + err: "text format parsing error in line 3: expected float as value for 'le' label", + }, + // 19: Invalid UTF-8 in label value. + { + in: "metric{l=\"\xbd\"} 3.14\n", + err: "text format parsing error in line 1: invalid label value \"\\xbd\"", + }, + } + + for i, scenario := range scenarios { + _, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in)) + if err == nil { + t.Errorf("%d. expected error, got nil", i) + continue + } + if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 { + t.Errorf( + "%d. expected error starting with %q, got %q", + i, expected, got, + ) + } + } + +} + +func TestTextParseError(t *testing.T) { + testTextParseError(t) +} + +func BenchmarkParseError(b *testing.B) { + for i := 0; i < b.N; i++ { + testTextParseError(b) + } +} diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt new file mode 100644 index 000000000..7723656d5 --- /dev/null +++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt @@ -0,0 +1,67 @@ +PACKAGE + +package goautoneg +import "bitbucket.org/ww/goautoneg" + +HTTP Content-Type Autonegotiation. + +The functions in this package implement the behaviour specified in +http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + +Copyright (c) 2011, Open Knowledge Foundation Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + Neither the name of the Open Knowledge Foundation Ltd. nor the + names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +FUNCTIONS + +func Negotiate(header string, alternatives []string) (content_type string) +Negotiate the most appropriate content_type given the accept header +and a list of alternatives. + +func ParseAccept(header string) (accept []Accept) +Parse an Accept Header string returning a sorted list +of clauses + + +TYPES + +type Accept struct { + Type, SubType string + Q float32 + Params map[string]string +} +Structure to represent a clause in an HTTP Accept Header + + +SUBDIRECTORIES + + .hg diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg_test.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg_test.go new file mode 100644 index 000000000..41d328f1d --- /dev/null +++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg_test.go @@ -0,0 +1,33 @@ +package goautoneg + +import ( + "testing" +) + +var chrome = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" + +func TestParseAccept(t *testing.T) { + alternatives := []string{"text/html", "image/png"} + content_type := Negotiate(chrome, alternatives) + if content_type != "image/png" { + t.Errorf("got %s expected image/png", content_type) + } + + alternatives = []string{"text/html", "text/plain", "text/n3"} + content_type = Negotiate(chrome, alternatives) + if content_type != "text/html" { + t.Errorf("got %s expected text/html", content_type) + } + + alternatives = []string{"text/n3", "text/plain"} + content_type = Negotiate(chrome, alternatives) + if content_type != "text/plain" { + t.Errorf("got %s expected text/plain", content_type) + } + + alternatives = []string{"text/n3", "application/rdf+xml"} + content_type = Negotiate(chrome, alternatives) + if content_type != "text/n3" { + t.Errorf("got %s expected text/n3", content_type) + } +} diff --git a/vendor/github.com/prometheus/common/model/alert_test.go b/vendor/github.com/prometheus/common/model/alert_test.go new file mode 100644 index 000000000..9692bca21 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/alert_test.go @@ -0,0 +1,118 @@ +// Copyright 2013 The Prometheus 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 model + +import ( + "strings" + "testing" + "time" +) + +func TestAlertValidate(t *testing.T) { + ts := time.Now() + + var cases = []struct { + alert *Alert + err string + }{ + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + StartsAt: ts, + }, + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + }, + err: "start time missing", + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + StartsAt: ts, + EndsAt: ts, + }, + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + StartsAt: ts, + EndsAt: ts.Add(1 * time.Minute), + }, + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + StartsAt: ts, + EndsAt: ts.Add(-1 * time.Minute), + }, + err: "start time must be before end time", + }, + { + alert: &Alert{ + StartsAt: ts, + }, + err: "at least one label pair required", + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b", "!bad": "label"}, + StartsAt: ts, + }, + err: "invalid label set: invalid name", + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b", "bad": "\xfflabel"}, + StartsAt: ts, + }, + err: "invalid label set: invalid value", + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + Annotations: LabelSet{"!bad": "label"}, + StartsAt: ts, + }, + err: "invalid annotations: invalid name", + }, + { + alert: &Alert{ + Labels: LabelSet{"a": "b"}, + Annotations: LabelSet{"bad": "\xfflabel"}, + StartsAt: ts, + }, + err: "invalid annotations: invalid value", + }, + } + + for i, c := range cases { + err := c.alert.Validate() + if err == nil { + if c.err == "" { + continue + } + t.Errorf("%d. Expected error %q but got none", i, c.err) + continue + } + if c.err == "" && err != nil { + t.Errorf("%d. Expected no error but got %q", i, err) + continue + } + if !strings.Contains(err.Error(), c.err) { + t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err) + } + } +} diff --git a/vendor/github.com/prometheus/common/model/labels_test.go b/vendor/github.com/prometheus/common/model/labels_test.go new file mode 100644 index 000000000..e8df28ffa --- /dev/null +++ b/vendor/github.com/prometheus/common/model/labels_test.go @@ -0,0 +1,140 @@ +// Copyright 2013 The Prometheus 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 model + +import ( + "sort" + "testing" +) + +func testLabelNames(t testing.TB) { + var scenarios = []struct { + in LabelNames + out LabelNames + }{ + { + in: LabelNames{"ZZZ", "zzz"}, + out: LabelNames{"ZZZ", "zzz"}, + }, + { + in: LabelNames{"aaa", "AAA"}, + out: LabelNames{"AAA", "aaa"}, + }, + } + + for i, scenario := range scenarios { + sort.Sort(scenario.in) + + for j, expected := range scenario.out { + if expected != scenario.in[j] { + t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j]) + } + } + } +} + +func TestLabelNames(t *testing.T) { + testLabelNames(t) +} + +func BenchmarkLabelNames(b *testing.B) { + for i := 0; i < b.N; i++ { + testLabelNames(b) + } +} + +func testLabelValues(t testing.TB) { + var scenarios = []struct { + in LabelValues + out LabelValues + }{ + { + in: LabelValues{"ZZZ", "zzz"}, + out: LabelValues{"ZZZ", "zzz"}, + }, + { + in: LabelValues{"aaa", "AAA"}, + out: LabelValues{"AAA", "aaa"}, + }, + } + + for i, scenario := range scenarios { + sort.Sort(scenario.in) + + for j, expected := range scenario.out { + if expected != scenario.in[j] { + t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j]) + } + } + } +} + +func TestLabelValues(t *testing.T) { + testLabelValues(t) +} + +func BenchmarkLabelValues(b *testing.B) { + for i := 0; i < b.N; i++ { + testLabelValues(b) + } +} + +func TestLabelNameIsValid(t *testing.T) { + var scenarios = []struct { + ln LabelName + valid bool + }{ + { + ln: "Avalid_23name", + valid: true, + }, + { + ln: "_Avalid_23name", + valid: true, + }, + { + ln: "1valid_23name", + valid: false, + }, + { + ln: "avalid_23name", + valid: true, + }, + { + ln: "Ava:lid_23name", + valid: false, + }, + { + ln: "a lid_23name", + valid: false, + }, + { + ln: ":leading_colon", + valid: false, + }, + { + ln: "colon:in:the:middle", + valid: false, + }, + } + + for _, s := range scenarios { + if s.ln.IsValid() != s.valid { + t.Errorf("Expected %v for %q using IsValid method", s.valid, s.ln) + } + if LabelNameRE.MatchString(string(s.ln)) != s.valid { + t.Errorf("Expected %v for %q using regexp match", s.valid, s.ln) + } + } +} diff --git a/vendor/github.com/prometheus/common/model/metric_test.go b/vendor/github.com/prometheus/common/model/metric_test.go new file mode 100644 index 000000000..06f9de525 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/metric_test.go @@ -0,0 +1,132 @@ +// Copyright 2013 The Prometheus 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 model + +import "testing" + +func testMetric(t testing.TB) { + var scenarios = []struct { + input LabelSet + fingerprint Fingerprint + fastFingerprint Fingerprint + }{ + { + input: LabelSet{}, + fingerprint: 14695981039346656037, + fastFingerprint: 14695981039346656037, + }, + { + input: LabelSet{ + "first_name": "electro", + "occupation": "robot", + "manufacturer": "westinghouse", + }, + fingerprint: 5911716720268894962, + fastFingerprint: 11310079640881077873, + }, + { + input: LabelSet{ + "x": "y", + }, + fingerprint: 8241431561484471700, + fastFingerprint: 13948396922932177635, + }, + { + input: LabelSet{ + "a": "bb", + "b": "c", + }, + fingerprint: 3016285359649981711, + fastFingerprint: 3198632812309449502, + }, + { + input: LabelSet{ + "a": "b", + "bb": "c", + }, + fingerprint: 7122421792099404749, + fastFingerprint: 5774953389407657638, + }, + } + + for i, scenario := range scenarios { + input := Metric(scenario.input) + + if scenario.fingerprint != input.Fingerprint() { + t.Errorf("%d. expected %d, got %d", i, scenario.fingerprint, input.Fingerprint()) + } + if scenario.fastFingerprint != input.FastFingerprint() { + t.Errorf("%d. expected %d, got %d", i, scenario.fastFingerprint, input.FastFingerprint()) + } + } +} + +func TestMetric(t *testing.T) { + testMetric(t) +} + +func BenchmarkMetric(b *testing.B) { + for i := 0; i < b.N; i++ { + testMetric(b) + } +} + +func TestMetricNameIsValid(t *testing.T) { + var scenarios = []struct { + mn LabelValue + valid bool + }{ + { + mn: "Avalid_23name", + valid: true, + }, + { + mn: "_Avalid_23name", + valid: true, + }, + { + mn: "1valid_23name", + valid: false, + }, + { + mn: "avalid_23name", + valid: true, + }, + { + mn: "Ava:lid_23name", + valid: true, + }, + { + mn: "a lid_23name", + valid: false, + }, + { + mn: ":leading_colon", + valid: true, + }, + { + mn: "colon:in:the:middle", + valid: true, + }, + } + + for _, s := range scenarios { + if IsValidMetricName(s.mn) != s.valid { + t.Errorf("Expected %v for %q using IsValidMetricName function", s.valid, s.mn) + } + if MetricNameRE.MatchString(string(s.mn)) != s.valid { + t.Errorf("Expected %v for %q using regexp matching", s.valid, s.mn) + } + } +} diff --git a/vendor/github.com/prometheus/common/model/signature_test.go b/vendor/github.com/prometheus/common/model/signature_test.go new file mode 100644 index 000000000..d59c8a8c3 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/signature_test.go @@ -0,0 +1,314 @@ +// Copyright 2014 The Prometheus 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 model + +import ( + "runtime" + "sync" + "testing" +) + +func TestLabelsToSignature(t *testing.T) { + var scenarios = []struct { + in map[string]string + out uint64 + }{ + { + in: map[string]string{}, + out: 14695981039346656037, + }, + { + in: map[string]string{"name": "garland, briggs", "fear": "love is not enough"}, + out: 5799056148416392346, + }, + } + + for i, scenario := range scenarios { + actual := LabelsToSignature(scenario.in) + + if actual != scenario.out { + t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) + } + } +} + +func TestMetricToFingerprint(t *testing.T) { + var scenarios = []struct { + in LabelSet + out Fingerprint + }{ + { + in: LabelSet{}, + out: 14695981039346656037, + }, + { + in: LabelSet{"name": "garland, briggs", "fear": "love is not enough"}, + out: 5799056148416392346, + }, + } + + for i, scenario := range scenarios { + actual := labelSetToFingerprint(scenario.in) + + if actual != scenario.out { + t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) + } + } +} + +func TestMetricToFastFingerprint(t *testing.T) { + var scenarios = []struct { + in LabelSet + out Fingerprint + }{ + { + in: LabelSet{}, + out: 14695981039346656037, + }, + { + in: LabelSet{"name": "garland, briggs", "fear": "love is not enough"}, + out: 12952432476264840823, + }, + } + + for i, scenario := range scenarios { + actual := labelSetToFastFingerprint(scenario.in) + + if actual != scenario.out { + t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) + } + } +} + +func TestSignatureForLabels(t *testing.T) { + var scenarios = []struct { + in Metric + labels LabelNames + out uint64 + }{ + { + in: Metric{}, + labels: nil, + out: 14695981039346656037, + }, + { + in: Metric{}, + labels: LabelNames{"empty"}, + out: 7187873163539638612, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: LabelNames{"empty"}, + out: 7187873163539638612, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: LabelNames{"fear", "name"}, + out: 5799056148416392346, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"}, + labels: LabelNames{"fear", "name"}, + out: 5799056148416392346, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: LabelNames{}, + out: 14695981039346656037, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: nil, + out: 14695981039346656037, + }, + } + + for i, scenario := range scenarios { + actual := SignatureForLabels(scenario.in, scenario.labels...) + + if actual != scenario.out { + t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) + } + } +} + +func TestSignatureWithoutLabels(t *testing.T) { + var scenarios = []struct { + in Metric + labels map[LabelName]struct{} + out uint64 + }{ + { + in: Metric{}, + labels: nil, + out: 14695981039346656037, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: map[LabelName]struct{}{"fear": struct{}{}, "name": struct{}{}}, + out: 14695981039346656037, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"}, + labels: map[LabelName]struct{}{"foo": struct{}{}}, + out: 5799056148416392346, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: map[LabelName]struct{}{}, + out: 5799056148416392346, + }, + { + in: Metric{"name": "garland, briggs", "fear": "love is not enough"}, + labels: nil, + out: 5799056148416392346, + }, + } + + for i, scenario := range scenarios { + actual := SignatureWithoutLabels(scenario.in, scenario.labels) + + if actual != scenario.out { + t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) + } + } +} + +func benchmarkLabelToSignature(b *testing.B, l map[string]string, e uint64) { + for i := 0; i < b.N; i++ { + if a := LabelsToSignature(l); a != e { + b.Fatalf("expected signature of %d for %s, got %d", e, l, a) + } + } +} + +func BenchmarkLabelToSignatureScalar(b *testing.B) { + benchmarkLabelToSignature(b, nil, 14695981039346656037) +} + +func BenchmarkLabelToSignatureSingle(b *testing.B) { + benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5146282821936882169) +} + +func BenchmarkLabelToSignatureDouble(b *testing.B) { + benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717) +} + +func BenchmarkLabelToSignatureTriple(b *testing.B) { + benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121) +} + +func benchmarkMetricToFingerprint(b *testing.B, ls LabelSet, e Fingerprint) { + for i := 0; i < b.N; i++ { + if a := labelSetToFingerprint(ls); a != e { + b.Fatalf("expected signature of %d for %s, got %d", e, ls, a) + } + } +} + +func BenchmarkMetricToFingerprintScalar(b *testing.B) { + benchmarkMetricToFingerprint(b, nil, 14695981039346656037) +} + +func BenchmarkMetricToFingerprintSingle(b *testing.B) { + benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5146282821936882169) +} + +func BenchmarkMetricToFingerprintDouble(b *testing.B) { + benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717) +} + +func BenchmarkMetricToFingerprintTriple(b *testing.B) { + benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121) +} + +func benchmarkMetricToFastFingerprint(b *testing.B, ls LabelSet, e Fingerprint) { + for i := 0; i < b.N; i++ { + if a := labelSetToFastFingerprint(ls); a != e { + b.Fatalf("expected signature of %d for %s, got %d", e, ls, a) + } + } +} + +func BenchmarkMetricToFastFingerprintScalar(b *testing.B) { + benchmarkMetricToFastFingerprint(b, nil, 14695981039346656037) +} + +func BenchmarkMetricToFastFingerprintSingle(b *testing.B) { + benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5147259542624943964) +} + +func BenchmarkMetricToFastFingerprintDouble(b *testing.B) { + benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528) +} + +func BenchmarkMetricToFastFingerprintTriple(b *testing.B) { + benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676) +} + +func BenchmarkEmptyLabelSignature(b *testing.B) { + input := []map[string]string{nil, {}} + + var ms runtime.MemStats + runtime.ReadMemStats(&ms) + + alloc := ms.Alloc + + for _, labels := range input { + LabelsToSignature(labels) + } + + runtime.ReadMemStats(&ms) + + if got := ms.Alloc; alloc != got { + b.Fatal("expected LabelsToSignature with empty labels not to perform allocations") + } +} + +func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerprint, concLevel int) { + var start, end sync.WaitGroup + start.Add(1) + end.Add(concLevel) + + for i := 0; i < concLevel; i++ { + go func() { + start.Wait() + for j := b.N / concLevel; j >= 0; j-- { + if a := labelSetToFastFingerprint(ls); a != e { + b.Fatalf("expected signature of %d for %s, got %d", e, ls, a) + } + } + end.Done() + }() + } + b.ResetTimer() + start.Done() + end.Wait() +} + +func BenchmarkMetricToFastFingerprintTripleConc1(b *testing.B) { + benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1) +} + +func BenchmarkMetricToFastFingerprintTripleConc2(b *testing.B) { + benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2) +} + +func BenchmarkMetricToFastFingerprintTripleConc4(b *testing.B) { + benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4) +} + +func BenchmarkMetricToFastFingerprintTripleConc8(b *testing.B) { + benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8) +} diff --git a/vendor/github.com/prometheus/common/model/silence_test.go b/vendor/github.com/prometheus/common/model/silence_test.go new file mode 100644 index 000000000..8eaaf0744 --- /dev/null +++ b/vendor/github.com/prometheus/common/model/silence_test.go @@ -0,0 +1,228 @@ +// Copyright 2015 The Prometheus 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 model + +import ( + "strings" + "testing" + "time" +) + +func TestMatcherValidate(t *testing.T) { + var cases = []struct { + matcher *Matcher + err string + }{ + { + matcher: &Matcher{ + Name: "name", + Value: "value", + }, + }, + { + matcher: &Matcher{ + Name: "name", + Value: "value", + IsRegex: true, + }, + }, + { + matcher: &Matcher{ + Name: "name!", + Value: "value", + }, + err: "invalid name", + }, + { + matcher: &Matcher{ + Name: "", + Value: "value", + }, + err: "invalid name", + }, + { + matcher: &Matcher{ + Name: "name", + Value: "value\xff", + }, + err: "invalid value", + }, + { + matcher: &Matcher{ + Name: "name", + Value: "", + }, + err: "invalid value", + }, + } + + for i, c := range cases { + err := c.matcher.Validate() + if err == nil { + if c.err == "" { + continue + } + t.Errorf("%d. Expected error %q but got none", i, c.err) + continue + } + if c.err == "" && err != nil { + t.Errorf("%d. Expected no error but got %q", i, err) + continue + } + if !strings.Contains(err.Error(), c.err) { + t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err) + } + } +} + +func TestSilenceValidate(t *testing.T) { + ts := time.Now() + + var cases = []struct { + sil *Silence + err string + }{ + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + StartsAt: ts, + EndsAt: ts, + CreatedAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + {Name: "name", Value: "value"}, + {Name: "name", Value: "value"}, + {Name: "name", Value: "value", IsRegex: true}, + }, + StartsAt: ts, + EndsAt: ts, + CreatedAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + StartsAt: ts, + EndsAt: ts.Add(-1 * time.Minute), + CreatedAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + err: "start time must be before end time", + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + StartsAt: ts, + CreatedAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + err: "end time missing", + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + EndsAt: ts, + CreatedAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + err: "start time missing", + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "!name", Value: "value"}, + }, + StartsAt: ts, + EndsAt: ts, + CreatedAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + err: "invalid matcher", + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + StartsAt: ts, + EndsAt: ts, + CreatedAt: ts, + CreatedBy: "name", + }, + err: "comment missing", + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + StartsAt: ts, + EndsAt: ts, + CreatedBy: "name", + Comment: "comment", + }, + err: "creation timestamp missing", + }, + { + sil: &Silence{ + Matchers: []*Matcher{ + {Name: "name", Value: "value"}, + }, + StartsAt: ts, + EndsAt: ts, + CreatedAt: ts, + Comment: "comment", + }, + err: "creator information missing", + }, + } + + for i, c := range cases { + err := c.sil.Validate() + if err == nil { + if c.err == "" { + continue + } + t.Errorf("%d. Expected error %q but got none", i, c.err) + continue + } + if c.err == "" && err != nil { + t.Errorf("%d. Expected no error but got %q", i, err) + continue + } + if !strings.Contains(err.Error(), c.err) { + t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err) + } + } +} diff --git a/vendor/github.com/prometheus/common/model/time_test.go b/vendor/github.com/prometheus/common/model/time_test.go new file mode 100644 index 000000000..3efdd65ff --- /dev/null +++ b/vendor/github.com/prometheus/common/model/time_test.go @@ -0,0 +1,132 @@ +// Copyright 2013 The Prometheus 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 model + +import ( + "testing" + "time" +) + +func TestComparators(t *testing.T) { + t1a := TimeFromUnix(0) + t1b := TimeFromUnix(0) + t2 := TimeFromUnix(2*second - 1) + + if !t1a.Equal(t1b) { + t.Fatalf("Expected %s to be equal to %s", t1a, t1b) + } + if t1a.Equal(t2) { + t.Fatalf("Expected %s to not be equal to %s", t1a, t2) + } + + if !t1a.Before(t2) { + t.Fatalf("Expected %s to be before %s", t1a, t2) + } + if t1a.Before(t1b) { + t.Fatalf("Expected %s to not be before %s", t1a, t1b) + } + + if !t2.After(t1a) { + t.Fatalf("Expected %s to be after %s", t2, t1a) + } + if t1b.After(t1a) { + t.Fatalf("Expected %s to not be after %s", t1b, t1a) + } +} + +func TestTimeConversions(t *testing.T) { + unixSecs := int64(1136239445) + unixNsecs := int64(123456789) + unixNano := unixSecs*1e9 + unixNsecs + + t1 := time.Unix(unixSecs, unixNsecs-unixNsecs%nanosPerTick) + t2 := time.Unix(unixSecs, unixNsecs) + + ts := TimeFromUnixNano(unixNano) + if !ts.Time().Equal(t1) { + t.Fatalf("Expected %s, got %s", t1, ts.Time()) + } + + // Test available precision. + ts = TimeFromUnixNano(t2.UnixNano()) + if !ts.Time().Equal(t1) { + t.Fatalf("Expected %s, got %s", t1, ts.Time()) + } + + if ts.UnixNano() != unixNano-unixNano%nanosPerTick { + t.Fatalf("Expected %d, got %d", unixNano, ts.UnixNano()) + } +} + +func TestDuration(t *testing.T) { + duration := time.Second + time.Minute + time.Hour + goTime := time.Unix(1136239445, 0) + + ts := TimeFromUnix(goTime.Unix()) + if !goTime.Add(duration).Equal(ts.Add(duration).Time()) { + t.Fatalf("Expected %s to be equal to %s", goTime.Add(duration), ts.Add(duration)) + } + + earlier := ts.Add(-duration) + delta := ts.Sub(earlier) + if delta != duration { + t.Fatalf("Expected %s to be equal to %s", delta, duration) + } +} + +func TestParseDuration(t *testing.T) { + var cases = []struct { + in string + out time.Duration + }{ + { + in: "0s", + out: 0, + }, { + in: "324ms", + out: 324 * time.Millisecond, + }, { + in: "3s", + out: 3 * time.Second, + }, { + in: "5m", + out: 5 * time.Minute, + }, { + in: "1h", + out: time.Hour, + }, { + in: "4d", + out: 4 * 24 * time.Hour, + }, { + in: "3w", + out: 3 * 7 * 24 * time.Hour, + }, { + in: "10y", + out: 10 * 365 * 24 * time.Hour, + }, + } + + for _, c := range cases { + d, err := ParseDuration(c.in) + if err != nil { + t.Errorf("Unexpected error on input %q", c.in) + } + if time.Duration(d) != c.out { + t.Errorf("Expected %v but got %v", c.out, d) + } + if d.String() != c.in { + t.Errorf("Expected duration string %q but got %q", c.in, d.String()) + } + } +} diff --git a/vendor/github.com/prometheus/common/model/value_test.go b/vendor/github.com/prometheus/common/model/value_test.go new file mode 100644 index 000000000..b97dcf84c --- /dev/null +++ b/vendor/github.com/prometheus/common/model/value_test.go @@ -0,0 +1,468 @@ +// Copyright 2013 The Prometheus 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 model + +import ( + "encoding/json" + "math" + "reflect" + "sort" + "testing" +) + +func TestEqualValues(t *testing.T) { + tests := map[string]struct { + in1, in2 SampleValue + want bool + }{ + "equal floats": { + in1: 3.14, + in2: 3.14, + want: true, + }, + "unequal floats": { + in1: 3.14, + in2: 3.1415, + want: false, + }, + "positive inifinities": { + in1: SampleValue(math.Inf(+1)), + in2: SampleValue(math.Inf(+1)), + want: true, + }, + "negative inifinities": { + in1: SampleValue(math.Inf(-1)), + in2: SampleValue(math.Inf(-1)), + want: true, + }, + "different inifinities": { + in1: SampleValue(math.Inf(+1)), + in2: SampleValue(math.Inf(-1)), + want: false, + }, + "number and infinity": { + in1: 42, + in2: SampleValue(math.Inf(+1)), + want: false, + }, + "number and NaN": { + in1: 42, + in2: SampleValue(math.NaN()), + want: false, + }, + "NaNs": { + in1: SampleValue(math.NaN()), + in2: SampleValue(math.NaN()), + want: true, // !!! + }, + } + + for name, test := range tests { + got := test.in1.Equal(test.in2) + if got != test.want { + t.Errorf("Comparing %s, %f and %f: got %t, want %t", name, test.in1, test.in2, got, test.want) + } + } +} + +func TestEqualSamples(t *testing.T) { + testSample := &Sample{} + + tests := map[string]struct { + in1, in2 *Sample + want bool + }{ + "equal pointers": { + in1: testSample, + in2: testSample, + want: true, + }, + "different metrics": { + in1: &Sample{Metric: Metric{"foo": "bar"}}, + in2: &Sample{Metric: Metric{"foo": "biz"}}, + want: false, + }, + "different timestamp": { + in1: &Sample{Timestamp: 0}, + in2: &Sample{Timestamp: 1}, + want: false, + }, + "different value": { + in1: &Sample{Value: 0}, + in2: &Sample{Value: 1}, + want: false, + }, + "equal samples": { + in1: &Sample{ + Metric: Metric{"foo": "bar"}, + Timestamp: 0, + Value: 1, + }, + in2: &Sample{ + Metric: Metric{"foo": "bar"}, + Timestamp: 0, + Value: 1, + }, + want: true, + }, + } + + for name, test := range tests { + got := test.in1.Equal(test.in2) + if got != test.want { + t.Errorf("Comparing %s, %v and %v: got %t, want %t", name, test.in1, test.in2, got, test.want) + } + } + +} + +func TestSamplePairJSON(t *testing.T) { + input := []struct { + plain string + value SamplePair + }{ + { + plain: `[1234.567,"123.1"]`, + value: SamplePair{ + Value: 123.1, + Timestamp: 1234567, + }, + }, + } + + for _, test := range input { + b, err := json.Marshal(test.value) + if err != nil { + t.Error(err) + continue + } + + if string(b) != test.plain { + t.Errorf("encoding error: expected %q, got %q", test.plain, b) + continue + } + + var sp SamplePair + err = json.Unmarshal(b, &sp) + if err != nil { + t.Error(err) + continue + } + + if sp != test.value { + t.Errorf("decoding error: expected %v, got %v", test.value, sp) + } + } +} + +func TestSampleJSON(t *testing.T) { + input := []struct { + plain string + value Sample + }{ + { + plain: `{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}`, + value: Sample{ + Metric: Metric{ + MetricNameLabel: "test_metric", + }, + Value: 123.1, + Timestamp: 1234567, + }, + }, + } + + for _, test := range input { + b, err := json.Marshal(test.value) + if err != nil { + t.Error(err) + continue + } + + if string(b) != test.plain { + t.Errorf("encoding error: expected %q, got %q", test.plain, b) + continue + } + + var sv Sample + err = json.Unmarshal(b, &sv) + if err != nil { + t.Error(err) + continue + } + + if !reflect.DeepEqual(sv, test.value) { + t.Errorf("decoding error: expected %v, got %v", test.value, sv) + } + } +} + +func TestVectorJSON(t *testing.T) { + input := []struct { + plain string + value Vector + }{ + { + plain: `[]`, + value: Vector{}, + }, + { + plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}]`, + value: Vector{&Sample{ + Metric: Metric{ + MetricNameLabel: "test_metric", + }, + Value: 123.1, + Timestamp: 1234567, + }}, + }, + { + plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]},{"metric":{"foo":"bar"},"value":[1.234,"+Inf"]}]`, + value: Vector{ + &Sample{ + Metric: Metric{ + MetricNameLabel: "test_metric", + }, + Value: 123.1, + Timestamp: 1234567, + }, + &Sample{ + Metric: Metric{ + "foo": "bar", + }, + Value: SampleValue(math.Inf(1)), + Timestamp: 1234, + }, + }, + }, + } + + for _, test := range input { + b, err := json.Marshal(test.value) + if err != nil { + t.Error(err) + continue + } + + if string(b) != test.plain { + t.Errorf("encoding error: expected %q, got %q", test.plain, b) + continue + } + + var vec Vector + err = json.Unmarshal(b, &vec) + if err != nil { + t.Error(err) + continue + } + + if !reflect.DeepEqual(vec, test.value) { + t.Errorf("decoding error: expected %v, got %v", test.value, vec) + } + } +} + +func TestScalarJSON(t *testing.T) { + input := []struct { + plain string + value Scalar + }{ + { + plain: `[123.456,"456"]`, + value: Scalar{ + Timestamp: 123456, + Value: 456, + }, + }, + { + plain: `[123123.456,"+Inf"]`, + value: Scalar{ + Timestamp: 123123456, + Value: SampleValue(math.Inf(1)), + }, + }, + { + plain: `[123123.456,"-Inf"]`, + value: Scalar{ + Timestamp: 123123456, + Value: SampleValue(math.Inf(-1)), + }, + }, + } + + for _, test := range input { + b, err := json.Marshal(test.value) + if err != nil { + t.Error(err) + continue + } + + if string(b) != test.plain { + t.Errorf("encoding error: expected %q, got %q", test.plain, b) + continue + } + + var sv Scalar + err = json.Unmarshal(b, &sv) + if err != nil { + t.Error(err) + continue + } + + if sv != test.value { + t.Errorf("decoding error: expected %v, got %v", test.value, sv) + } + } +} + +func TestStringJSON(t *testing.T) { + input := []struct { + plain string + value String + }{ + { + plain: `[123.456,"test"]`, + value: String{ + Timestamp: 123456, + Value: "test", + }, + }, + { + plain: `[123123.456,"台北"]`, + value: String{ + Timestamp: 123123456, + Value: "台北", + }, + }, + } + + for _, test := range input { + b, err := json.Marshal(test.value) + if err != nil { + t.Error(err) + continue + } + + if string(b) != test.plain { + t.Errorf("encoding error: expected %q, got %q", test.plain, b) + continue + } + + var sv String + err = json.Unmarshal(b, &sv) + if err != nil { + t.Error(err) + continue + } + + if sv != test.value { + t.Errorf("decoding error: expected %v, got %v", test.value, sv) + } + } +} + +func TestVectorSort(t *testing.T) { + input := Vector{ + &Sample{ + Metric: Metric{ + MetricNameLabel: "A", + }, + Timestamp: 1, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "A", + }, + Timestamp: 2, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "C", + }, + Timestamp: 1, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "C", + }, + Timestamp: 2, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "B", + }, + Timestamp: 1, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "B", + }, + Timestamp: 2, + }, + } + + expected := Vector{ + &Sample{ + Metric: Metric{ + MetricNameLabel: "A", + }, + Timestamp: 1, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "A", + }, + Timestamp: 2, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "B", + }, + Timestamp: 1, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "B", + }, + Timestamp: 2, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "C", + }, + Timestamp: 1, + }, + &Sample{ + Metric: Metric{ + MetricNameLabel: "C", + }, + Timestamp: 2, + }, + } + + sort.Sort(input) + + for i, actual := range input { + actualFp := actual.Metric.Fingerprint() + expectedFp := expected[i].Metric.Fingerprint() + + if actualFp != expectedFp { + t.Fatalf("%d. Incorrect fingerprint. Got %s; want %s", i, actualFp.String(), expectedFp.String()) + } + + if actual.Timestamp != expected[i].Timestamp { + t.Fatalf("%d. Incorrect timestamp. Got %s; want %s", i, actual.Timestamp, expected[i].Timestamp) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/.gitignore b/vendor/github.com/prometheus/procfs/.gitignore new file mode 100644 index 000000000..25e3659ab --- /dev/null +++ b/vendor/github.com/prometheus/procfs/.gitignore @@ -0,0 +1 @@ +/fixtures/ diff --git a/vendor/github.com/prometheus/procfs/.travis.yml b/vendor/github.com/prometheus/procfs/.travis.yml new file mode 100644 index 000000000..5416cf8a2 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/.travis.yml @@ -0,0 +1,15 @@ +sudo: false + +language: go + +go: +- 1.7.x +- 1.8.x +- 1.9.x +- 1.10.x +- 1.x + +go_import_path: github.com/prometheus/procfs + +script: +- make style check_license vet test staticcheck diff --git a/vendor/github.com/prometheus/procfs/CONTRIBUTING.md b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md new file mode 100644 index 000000000..40503edbf --- /dev/null +++ b/vendor/github.com/prometheus/procfs/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Contributing + +Prometheus uses GitHub to manage reviews of pull requests. + +* If you have a trivial fix or improvement, go ahead and create a pull request, + addressing (with `@...`) the maintainer of this repository (see + [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. + +* If you plan to do something more involved, first discuss your ideas + on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). + This will avoid unnecessary work and surely give you and us a good deal + of inspiration. + +* Relevant coding style guidelines are the [Go Code Review + Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments) + and the _Formatting and style_ section of Peter Bourgon's [Go: Best + Practices for Production + Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style). diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md new file mode 100644 index 000000000..35993c41c --- /dev/null +++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md @@ -0,0 +1 @@ +* Tobias Schmidt diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile new file mode 100644 index 000000000..5c8f72625 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/Makefile @@ -0,0 +1,71 @@ +# Copyright 2018 The Prometheus 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. + +# Ensure GOBIN is not set during build so that promu is installed to the correct path +unexport GOBIN + +GO ?= go +GOFMT ?= $(GO)fmt +FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) +STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck +pkgs = $(shell $(GO) list ./... | grep -v /vendor/) + +PREFIX ?= $(shell pwd) +BIN_DIR ?= $(shell pwd) + +ifdef DEBUG + bindata_flags = -debug +endif + +STATICCHECK_IGNORE = + +all: format staticcheck build test + +style: + @echo ">> checking code style" + @! $(GOFMT) -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' + +check_license: + @echo ">> checking license header" + @./scripts/check_license.sh + +test: fixtures/.unpacked sysfs/fixtures/.unpacked + @echo ">> running all tests" + @$(GO) test -race $(shell $(GO) list ./... | grep -v /vendor/ | grep -v examples) + +format: + @echo ">> formatting code" + @$(GO) fmt $(pkgs) + +vet: + @echo ">> vetting code" + @$(GO) vet $(pkgs) + +staticcheck: $(STATICCHECK) + @echo ">> running staticcheck" + @$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) + +%/.unpacked: %.ttar + ./ttar -C $(dir $*) -x -f $*.ttar + touch $@ + +$(FIRST_GOPATH)/bin/staticcheck: + @GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck + +.PHONY: all style check_license format test vet staticcheck + +# Declaring the binaries at their default locations as PHONY targets is a hack +# to ensure the latest version is downloaded on every make execution. +# If this is not desired, copy/symlink these binaries to a different path and +# set the respective environment variables. +.PHONY: $(GOPATH)/bin/staticcheck diff --git a/vendor/github.com/prometheus/procfs/README.md b/vendor/github.com/prometheus/procfs/README.md new file mode 100644 index 000000000..209549471 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/README.md @@ -0,0 +1,11 @@ +# procfs + +This procfs package provides functions to retrieve system, kernel and process +metrics from the pseudo-filesystem proc. + +*WARNING*: This package is a work in progress. Its API may still break in +backwards-incompatible ways without warnings. Use it at your own risk. + +[![GoDoc](https://godoc.org/github.com/prometheus/procfs?status.png)](https://godoc.org/github.com/prometheus/procfs) +[![Build Status](https://travis-ci.org/prometheus/procfs.svg?branch=master)](https://travis-ci.org/prometheus/procfs) +[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus/procfs)](https://goreportcard.com/report/github.com/prometheus/procfs) diff --git a/vendor/github.com/prometheus/procfs/buddyinfo_test.go b/vendor/github.com/prometheus/procfs/buddyinfo_test.go new file mode 100644 index 000000000..bcf9355ca --- /dev/null +++ b/vendor/github.com/prometheus/procfs/buddyinfo_test.go @@ -0,0 +1,64 @@ +// Copyright 2017 The Prometheus 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 procfs + +import ( + "strings" + "testing" +) + +func TestBuddyInfo(t *testing.T) { + buddyInfo, err := FS("fixtures/buddyinfo/valid").NewBuddyInfo() + if err != nil { + t.Fatal(err) + } + + if want, got := "DMA", buddyInfo[0].Zone; want != got { + t.Errorf("want Node 0, Zone %s, got %s", want, got) + } + + if want, got := "Normal", buddyInfo[2].Zone; want != got { + t.Errorf("want Node 0, Zone %s, got %s", want, got) + } + + if want, got := 4381.0, buddyInfo[2].Sizes[0]; want != got { + t.Errorf("want Node 0, Zone Normal %f, got %f", want, got) + } + + if want, got := 572.0, buddyInfo[1].Sizes[1]; want != got { + t.Errorf("want Node 0, Zone DMA32 %f, got %f", want, got) + } +} + +func TestBuddyInfoShort(t *testing.T) { + _, err := FS("fixtures/buddyinfo/short").NewBuddyInfo() + if err == nil { + t.Errorf("expected error, but none occurred") + } + + if want, got := "invalid number of fields when parsing buddyinfo", err.Error(); want != got { + t.Errorf("wrong error returned, wanted %q, got %q", want, got) + } +} + +func TestBuddyInfoSizeMismatch(t *testing.T) { + _, err := FS("fixtures/buddyinfo/sizemismatch").NewBuddyInfo() + if err == nil { + t.Errorf("expected error, but none occurred") + } + + if want, got := "mismatch in number of buddyinfo buckets", err.Error(); !strings.HasPrefix(got, want) { + t.Errorf("wrong error returned, wanted prefix %q, got %q", want, got) + } +} diff --git a/vendor/github.com/prometheus/procfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/fixtures.ttar new file mode 100644 index 000000000..3ee8291e8 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fixtures.ttar @@ -0,0 +1,446 @@ +# Archive created by ttar -c -f fixtures.ttar fixtures/ +Directory: fixtures +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26231 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/cmdline +Lines: 1 +vimNULLBYTEtest.goNULLBYTE+10NULLBYTEEOF +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/comm +Lines: 1 +vim +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/exe +SymlinkTo: /usr/bin/vim +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26231/fd +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/fd/0 +SymlinkTo: ../../symlinktargets/abc +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/fd/1 +SymlinkTo: ../../symlinktargets/def +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/fd/10 +SymlinkTo: ../../symlinktargets/xyz +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/fd/2 +SymlinkTo: ../../symlinktargets/ghi +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/fd/3 +SymlinkTo: ../../symlinktargets/uvw +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/io +Lines: 7 +rchar: 750339 +wchar: 818609 +syscr: 7405 +syscw: 5245 +read_bytes: 1024 +write_bytes: 2048 +cancelled_write_bytes: -1024 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/limits +Lines: 17 +Limit Soft Limit Hard Limit Units +Max cpu time unlimited unlimited seconds +Max file size unlimited unlimited bytes +Max data size unlimited unlimited bytes +Max stack size 8388608 unlimited bytes +Max core file size 0 unlimited bytes +Max resident set unlimited unlimited bytes +Max processes 62898 62898 processes +Max open files 2048 4096 files +Max locked memory 65536 65536 bytes +Max address space 8589934592 unlimited bytes +Max file locks unlimited unlimited locks +Max pending signals 62898 62898 signals +Max msgqueue size 819200 819200 bytes +Max nice priority 0 0 +Max realtime priority 0 0 +Max realtime timeout unlimited unlimited us +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/mountstats +Lines: 19 +device rootfs mounted on / with fstype rootfs +device sysfs mounted on /sys with fstype sysfs +device proc mounted on /proc with fstype proc +device /dev/sda1 mounted on / with fstype ext4 +device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers=1.1 + opts: rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.5,local_lock=none + age: 13968 + caps: caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255 + nfsv4: bm0=0xfdffafff,bm1=0xf9be3e,bm2=0x0,acl=0x0,pnfs=not configured + sec: flavor=1,pseudoflavor=1 + events: 52 226 0 0 1 13 398 0 0 331 0 47 0 0 77 0 0 77 0 0 0 0 0 0 0 0 0 + bytes: 1207640230 0 0 0 1210214218 0 295483 0 + RPC iostats version: 1.0 p/v: 100003/4 (nfs) + xprt: tcp 832 0 1 0 11 6428 6428 0 12154 0 24 26 5726 + per-op statistics + NULL: 0 0 0 0 0 0 0 0 + READ: 1298 1298 0 207680 1210292152 6 79386 79407 + WRITE: 0 0 0 0 0 0 0 0 + +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26231/net +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/net/dev +Lines: 4 +Inter-| Receive | Transmit + face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed + lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + eth0: 438 5 0 0 0 0 0 0 648 8 0 0 0 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26231/ns +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/ns/mnt +SymlinkTo: mnt:[4026531840] +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/ns/net +SymlinkTo: net:[4026531993] +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26231/stat +Lines: 1 +26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26232 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/cmdline +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/comm +Lines: 1 +ata_sff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26232/fd +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/fd/0 +SymlinkTo: ../../symlinktargets/abc +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/fd/1 +SymlinkTo: ../../symlinktargets/def +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/fd/2 +SymlinkTo: ../../symlinktargets/ghi +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/fd/3 +SymlinkTo: ../../symlinktargets/uvw +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/fd/4 +SymlinkTo: ../../symlinktargets/xyz +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/limits +Lines: 17 +Limit Soft Limit Hard Limit Units +Max cpu time unlimited unlimited seconds +Max file size unlimited unlimited bytes +Max data size unlimited unlimited bytes +Max stack size 8388608 unlimited bytes +Max core file size 0 unlimited bytes +Max resident set unlimited unlimited bytes +Max processes 29436 29436 processes +Max open files 1024 4096 files +Max locked memory 65536 65536 bytes +Max address space unlimited unlimited bytes +Max file locks unlimited unlimited locks +Max pending signals 29436 29436 signals +Max msgqueue size 819200 819200 bytes +Max nice priority 0 0 +Max realtime priority 0 0 +Max realtime timeout unlimited unlimited us +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26232/stat +Lines: 1 +33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/26233 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/26233/cmdline +Lines: 1 +com.github.uiautomatorNULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTEEOF +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/584 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/584/stat +Lines: 2 +1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0 +#!/bin/cat /proc/self/stat +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/buddyinfo +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/buddyinfo/short +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/buddyinfo/short/buddyinfo +Lines: 3 +Node 0, zone +Node 0, zone +Node 0, zone +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/buddyinfo/sizemismatch +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/buddyinfo/sizemismatch/buddyinfo +Lines: 3 +Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3 +Node 0, zone DMA32 759 572 791 475 194 45 12 0 0 0 0 0 +Node 0, zone Normal 4381 1093 185 1530 567 102 4 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/buddyinfo/valid +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/buddyinfo/valid/buddyinfo +Lines: 3 +Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3 +Node 0, zone DMA32 759 572 791 475 194 45 12 0 0 0 0 +Node 0, zone Normal 4381 1093 185 1530 567 102 4 0 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/fs +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/fs/xfs +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/fs/xfs/stat +Lines: 23 +extent_alloc 92447 97589 92448 93751 +abt 0 0 0 0 +blk_map 1767055 188820 184891 92447 92448 2140766 0 +bmbt 0 0 0 0 +dir 185039 92447 92444 136422 +trans 706 944304 0 +ig 185045 58807 0 126238 0 33637 22 +log 2883 113448 9 17360 739 +push_ail 945014 0 134260 15483 0 3940 464 159985 0 40 +xstrat 92447 0 +rw 107739 94045 +attr 4 0 0 0 +icluster 8677 7849 135802 +vnodes 92601 0 0 0 92444 92444 92444 0 +buf 2666287 7122 2659202 3599 2 7085 0 10297 7085 +abtb2 184941 1277345 13257 13278 0 0 0 0 0 0 0 0 0 0 2746147 +abtc2 345295 2416764 172637 172658 0 0 0 0 0 0 0 0 0 0 21406023 +bmbt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +ibt2 343004 1358467 0 0 0 0 0 0 0 0 0 0 0 0 0 +fibt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +qm 0 0 0 0 0 0 0 0 +xpc 399724544 92823103 86219234 +debug 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/mdstat +Lines: 26 +Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10] +md3 : active raid6 sda1[8] sdh1[7] sdg1[6] sdf1[5] sde1[11] sdd1[3] sdc1[10] sdb1[9] + 5853468288 blocks super 1.2 level 6, 64k chunk, algorithm 2 [8/8] [UUUUUUUU] + +md127 : active raid1 sdi2[0] sdj2[1] + 312319552 blocks [2/2] [UU] + +md0 : active raid1 sdk[2](S) sdi1[0] sdj1[1] + 248896 blocks [2/2] [UU] + +md4 : inactive raid1 sda3[0] sdb3[1] + 4883648 blocks [2/2] [UU] + +md6 : active raid1 sdb2[2] sda2[0] + 195310144 blocks [2/1] [U_] + [=>...................] recovery = 8.5% (16775552/195310144) finish=17.0min speed=259783K/sec + +md8 : active raid1 sdb1[1] sda1[0] + 195310144 blocks [2/2] [UU] + [=>...................] resync = 8.5% (16775552/195310144) finish=17.0min speed=259783K/sec + +md7 : active raid6 sdb1[0] sde1[3] sdd1[2] sdc1[1] + 7813735424 blocks super 1.2 level 6, 512k chunk, algorithm 2 [4/3] [U_UU] + bitmap: 0/30 pages [0KB], 65536KB chunk + +unused devices: +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/net +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/net/dev +Lines: 6 +Inter-| Receive | Transmit + face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed +vethf345468: 648 8 0 0 0 0 0 0 438 5 0 0 0 0 0 0 + lo: 1664039048 1566805 0 0 0 0 0 0 1664039048 1566805 0 0 0 0 0 0 +docker0: 2568 38 0 0 0 0 0 0 438 5 0 0 0 0 0 0 + eth0: 874354587 1036395 0 0 0 0 0 0 563352563 732147 0 0 0 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/net/ip_vs +Lines: 21 +IP Virtual Server version 1.2.1 (size=4096) +Prot LocalAddress:Port Scheduler Flags + -> RemoteAddress:Port Forward Weight ActiveConn InActConn +TCP C0A80016:0CEA wlc + -> C0A85216:0CEA Tunnel 100 248 2 + -> C0A85318:0CEA Tunnel 100 248 2 + -> C0A85315:0CEA Tunnel 100 248 1 +TCP C0A80039:0CEA wlc + -> C0A85416:0CEA Tunnel 0 0 0 + -> C0A85215:0CEA Tunnel 100 1499 0 + -> C0A83215:0CEA Tunnel 100 1498 0 +TCP C0A80037:0CEA wlc + -> C0A8321A:0CEA Tunnel 0 0 0 + -> C0A83120:0CEA Tunnel 100 0 0 +TCP [2620:0000:0000:0000:0000:0000:0000:0001]:0050 sh + -> [2620:0000:0000:0000:0000:0000:0000:0002]:0050 Route 1 0 0 + -> [2620:0000:0000:0000:0000:0000:0000:0003]:0050 Route 1 0 0 + -> [2620:0000:0000:0000:0000:0000:0000:0004]:0050 Route 1 1 1 +FWM 10001000 wlc + -> C0A8321A:0CEA Route 0 0 1 + -> C0A83215:0CEA Route 0 0 2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/net/ip_vs_stats +Lines: 6 + Total Incoming Outgoing Incoming Outgoing + Conns Packets Packets Bytes Bytes + 16AA370 E33656E5 0 51D8C8883AB3 0 + + Conns/s Pkts/s Pkts/s Bytes/s Bytes/s + 4 1FB3C 0 1282A8F 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/net/rpc +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/net/rpc/nfs +Lines: 5 +net 18628 0 18628 6 +rpc 4329785 0 4338291 +proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 +proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 0 241 4 4 2 39 +proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/net/rpc/nfsd +Lines: 11 +rc 0 6 18622 +fh 0 0 0 0 0 +io 157286400 0 +th 8 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 +ra 32 0 0 0 0 0 0 0 0 0 0 0 +net 18628 0 18628 6 +rpc 18628 0 0 0 0 +proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 +proc3 22 2 112 0 2719 111 0 0 0 0 0 0 0 0 0 0 0 27 216 0 2 1 0 +proc4 2 2 10853 +proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/net/xfrm_stat +Lines: 28 +XfrmInError 1 +XfrmInBufferError 2 +XfrmInHdrError 4 +XfrmInNoStates 3 +XfrmInStateProtoError 40 +XfrmInStateModeError 100 +XfrmInStateSeqError 6000 +XfrmInStateExpired 4 +XfrmInStateMismatch 23451 +XfrmInStateInvalid 55555 +XfrmInTmplMismatch 51 +XfrmInNoPols 65432 +XfrmInPolBlock 100 +XfrmInPolError 10000 +XfrmOutError 1000000 +XfrmOutBundleGenError 43321 +XfrmOutBundleCheckError 555 +XfrmOutNoStates 869 +XfrmOutStateProtoError 4542 +XfrmOutStateModeError 4 +XfrmOutStateSeqError 543 +XfrmOutStateExpired 565 +XfrmOutPolBlock 43456 +XfrmOutPolDead 7656 +XfrmOutPolError 1454 +XfrmFwdHdrError 6654 +XfrmOutStateInvalid 28765 +XfrmAcquireError 24532 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/self +SymlinkTo: 26231 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/stat +Lines: 16 +cpu 301854 612 111922 8979004 3552 2 3944 0 0 0 +cpu0 44490 19 21045 1087069 220 1 3410 0 0 0 +cpu1 47869 23 16474 1110787 591 0 46 0 0 0 +cpu2 46504 36 15916 1112321 441 0 326 0 0 0 +cpu3 47054 102 15683 1113230 533 0 60 0 0 0 +cpu4 28413 25 10776 1140321 217 0 8 0 0 0 +cpu5 29271 101 11586 1136270 672 0 30 0 0 0 +cpu6 29152 36 10276 1139721 319 0 29 0 0 0 +cpu7 29098 268 10164 1139282 555 0 31 0 0 0 +intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 0 0 0 231237 0 0 0 0 250586 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223424 190745 13 906 1283803 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +ctxt 38014093 +btime 1418183276 +processes 26442 +procs_running 2 +procs_blocked 1 +softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/symlinktargets +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/symlinktargets/README +Lines: 2 +This directory contains some empty files that are the symlinks the files in the "fd" directory point to. +They are otherwise ignored by the tests +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/symlinktargets/abc +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/symlinktargets/def +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/symlinktargets/ghi +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/symlinktargets/uvw +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/symlinktargets/xyz +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/github.com/prometheus/procfs/fs_test.go b/vendor/github.com/prometheus/procfs/fs_test.go new file mode 100644 index 000000000..a4e07f5c8 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/fs_test.go @@ -0,0 +1,39 @@ +// Copyright 2018 The Prometheus 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 procfs + +import "testing" + +func TestNewFS(t *testing.T) { + if _, err := NewFS("foobar"); err == nil { + t.Error("want NewFS to fail for non-existing mount point") + } + + if _, err := NewFS("procfs.go"); err == nil { + t.Error("want NewFS to fail if mount point is not a directory") + } +} + +func TestFSXFSStats(t *testing.T) { + stats, err := FS("fixtures").XFSStats() + if err != nil { + t.Fatalf("failed to parse XFS stats: %v", err) + } + + // Very lightweight test just to sanity check the path used + // to open XFS stats. Heavier tests in package xfs. + if want, got := uint32(92447), stats.ExtentAllocation.ExtentsAllocated; want != got { + t.Errorf("unexpected extents allocated:\nwant: %d\nhave: %d", want, got) + } +} diff --git a/vendor/github.com/prometheus/procfs/ipvs_test.go b/vendor/github.com/prometheus/procfs/ipvs_test.go new file mode 100644 index 000000000..9c34e6d0d --- /dev/null +++ b/vendor/github.com/prometheus/procfs/ipvs_test.go @@ -0,0 +1,250 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "net" + "testing" +) + +var ( + expectedIPVSStats = IPVSStats{ + Connections: 23765872, + IncomingPackets: 3811989221, + OutgoingPackets: 0, + IncomingBytes: 89991519156915, + OutgoingBytes: 0, + } + expectedIPVSBackendStatuses = []IPVSBackendStatus{ + { + LocalAddress: net.ParseIP("192.168.0.22"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.82.22"), + RemotePort: 3306, + Proto: "TCP", + Weight: 100, + ActiveConn: 248, + InactConn: 2, + }, + { + LocalAddress: net.ParseIP("192.168.0.22"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.83.24"), + RemotePort: 3306, + Proto: "TCP", + Weight: 100, + ActiveConn: 248, + InactConn: 2, + }, + { + LocalAddress: net.ParseIP("192.168.0.22"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.83.21"), + RemotePort: 3306, + Proto: "TCP", + Weight: 100, + ActiveConn: 248, + InactConn: 1, + }, + { + LocalAddress: net.ParseIP("192.168.0.57"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.84.22"), + RemotePort: 3306, + Proto: "TCP", + Weight: 0, + ActiveConn: 0, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("192.168.0.57"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.82.21"), + RemotePort: 3306, + Proto: "TCP", + Weight: 100, + ActiveConn: 1499, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("192.168.0.57"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.50.21"), + RemotePort: 3306, + Proto: "TCP", + Weight: 100, + ActiveConn: 1498, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("192.168.0.55"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.50.26"), + RemotePort: 3306, + Proto: "TCP", + Weight: 0, + ActiveConn: 0, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("192.168.0.55"), + LocalPort: 3306, + RemoteAddress: net.ParseIP("192.168.49.32"), + RemotePort: 3306, + Proto: "TCP", + Weight: 100, + ActiveConn: 0, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("2620::1"), + LocalPort: 80, + RemoteAddress: net.ParseIP("2620::2"), + RemotePort: 80, + Proto: "TCP", + Weight: 1, + ActiveConn: 0, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("2620::1"), + LocalPort: 80, + RemoteAddress: net.ParseIP("2620::3"), + RemotePort: 80, + Proto: "TCP", + Weight: 1, + ActiveConn: 0, + InactConn: 0, + }, + { + LocalAddress: net.ParseIP("2620::1"), + LocalPort: 80, + RemoteAddress: net.ParseIP("2620::4"), + RemotePort: 80, + Proto: "TCP", + Weight: 1, + ActiveConn: 1, + InactConn: 1, + }, + { + LocalMark: "10001000", + RemoteAddress: net.ParseIP("192.168.50.26"), + RemotePort: 3306, + Proto: "FWM", + Weight: 0, + ActiveConn: 0, + InactConn: 1, + }, + { + LocalMark: "10001000", + RemoteAddress: net.ParseIP("192.168.50.21"), + RemotePort: 3306, + Proto: "FWM", + Weight: 0, + ActiveConn: 0, + InactConn: 2, + }, + } +) + +func TestIPVSStats(t *testing.T) { + stats, err := FS("fixtures").NewIPVSStats() + if err != nil { + t.Fatal(err) + } + + if stats != expectedIPVSStats { + t.Errorf("want %+v, have %+v", expectedIPVSStats, stats) + } +} + +func TestParseIPPort(t *testing.T) { + ip := net.ParseIP("192.168.0.22") + port := uint16(3306) + + gotIP, gotPort, err := parseIPPort("C0A80016:0CEA") + if err != nil { + t.Fatal(err) + } + if !(gotIP.Equal(ip) && port == gotPort) { + t.Errorf("want %s:%d, have %s:%d", ip, port, gotIP, gotPort) + } +} + +func TestParseIPPortInvalid(t *testing.T) { + testcases := []string{ + "", + "C0A80016", + "C0A800:1234", + "FOOBARBA:1234", + "C0A80016:0CEA:1234", + } + + for _, s := range testcases { + ip, port, err := parseIPPort(s) + if ip != nil || port != uint16(0) || err == nil { + t.Errorf("Expected error for input %s, have ip = %s, port = %v, err = %v", s, ip, port, err) + } + } +} + +func TestParseIPPortIPv6(t *testing.T) { + ip := net.ParseIP("dead:beef::1") + port := uint16(8080) + + gotIP, gotPort, err := parseIPPort("[DEAD:BEEF:0000:0000:0000:0000:0000:0001]:1F90") + if err != nil { + t.Fatal(err) + } + if !(gotIP.Equal(ip) && port == gotPort) { + t.Errorf("want %s:%d, have %s:%d", ip, port, gotIP, gotPort) + } +} + +func TestIPVSBackendStatus(t *testing.T) { + backendStats, err := FS("fixtures").NewIPVSBackendStatus() + if err != nil { + t.Fatal(err) + } + if want, have := len(expectedIPVSBackendStatuses), len(backendStats); want != have { + t.Fatalf("want %d backend statuses, have %d", want, have) + } + + for idx, expect := range expectedIPVSBackendStatuses { + if !backendStats[idx].LocalAddress.Equal(expect.LocalAddress) { + t.Errorf("want LocalAddress %s, have %s", expect.LocalAddress, backendStats[idx].LocalAddress) + } + if backendStats[idx].LocalPort != expect.LocalPort { + t.Errorf("want LocalPort %d, have %d", expect.LocalPort, backendStats[idx].LocalPort) + } + if !backendStats[idx].RemoteAddress.Equal(expect.RemoteAddress) { + t.Errorf("want RemoteAddress %s, have %s", expect.RemoteAddress, backendStats[idx].RemoteAddress) + } + if backendStats[idx].RemotePort != expect.RemotePort { + t.Errorf("want RemotePort %d, have %d", expect.RemotePort, backendStats[idx].RemotePort) + } + if backendStats[idx].Proto != expect.Proto { + t.Errorf("want Proto %s, have %s", expect.Proto, backendStats[idx].Proto) + } + if backendStats[idx].Weight != expect.Weight { + t.Errorf("want Weight %d, have %d", expect.Weight, backendStats[idx].Weight) + } + if backendStats[idx].ActiveConn != expect.ActiveConn { + t.Errorf("want ActiveConn %d, have %d", expect.ActiveConn, backendStats[idx].ActiveConn) + } + if backendStats[idx].InactConn != expect.InactConn { + t.Errorf("want InactConn %d, have %d", expect.InactConn, backendStats[idx].InactConn) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/mdstat_test.go b/vendor/github.com/prometheus/procfs/mdstat_test.go new file mode 100644 index 000000000..8819228f1 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/mdstat_test.go @@ -0,0 +1,44 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "testing" +) + +func TestMDStat(t *testing.T) { + mdStates, err := FS("fixtures").ParseMDStat() + if err != nil { + t.Fatalf("parsing of reference-file failed entirely: %s", err) + } + + refs := map[string]MDStat{ + "md3": {"md3", "active", 8, 8, 5853468288, 5853468288}, + "md127": {"md127", "active", 2, 2, 312319552, 312319552}, + "md0": {"md0", "active", 2, 2, 248896, 248896}, + "md4": {"md4", "inactive", 2, 2, 4883648, 4883648}, + "md6": {"md6", "active", 1, 2, 195310144, 16775552}, + "md8": {"md8", "active", 2, 2, 195310144, 16775552}, + "md7": {"md7", "active", 3, 4, 7813735424, 7813735424}, + } + + if want, have := len(refs), len(mdStates); want != have { + t.Errorf("want %d parsed md-devices, have %d", want, have) + } + for _, md := range mdStates { + if want, have := refs[md.Name], md; want != have { + t.Errorf("%s: want %v, have %v", md.Name, want, have) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/mountstats_test.go b/vendor/github.com/prometheus/procfs/mountstats_test.go new file mode 100644 index 000000000..7df1d15f4 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/mountstats_test.go @@ -0,0 +1,286 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "fmt" + "reflect" + "strings" + "testing" + "time" +) + +func TestMountStats(t *testing.T) { + tests := []struct { + name string + s string + mounts []*Mount + invalid bool + }{ + { + name: "no devices", + s: `hello`, + }, + { + name: "device has too few fields", + s: `device foo`, + invalid: true, + }, + { + name: "device incorrect format", + s: `device rootfs BAD on / with fstype rootfs`, + invalid: true, + }, + { + name: "device incorrect format", + s: `device rootfs mounted BAD / with fstype rootfs`, + invalid: true, + }, + { + name: "device incorrect format", + s: `device rootfs mounted on / BAD fstype rootfs`, + invalid: true, + }, + { + name: "device incorrect format", + s: `device rootfs mounted on / with BAD rootfs`, + invalid: true, + }, + { + name: "device rootfs cannot have stats", + s: `device rootfs mounted on / with fstype rootfs stats`, + invalid: true, + }, + { + name: "NFSv4 device with too little info", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nhello", + invalid: true, + }, + { + name: "NFSv4 device with bad bytes", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nbytes: 0", + invalid: true, + }, + { + name: "NFSv4 device with bad events", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nevents: 0", + invalid: true, + }, + { + name: "NFSv4 device with bad per-op stats", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nper-op statistics\nFOO 0", + invalid: true, + }, + { + name: "NFSv4 device with bad transport stats", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcp", + invalid: true, + }, + { + name: "NFSv4 device with bad transport version", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=foo\nxprt: tcp 0", + invalid: true, + }, + { + name: "NFSv4 device with bad transport stats version 1.0", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.0\nxprt: tcp 0 0 0 0 0 0 0 0 0 0 0 0 0", + invalid: true, + }, + { + name: "NFSv4 device with bad transport stats version 1.1", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs4 statvers=1.1\nxprt: tcp 0 0 0 0 0 0 0 0 0 0", + invalid: true, + }, + { + name: "NFSv3 device with transport stats version 1.0 OK", + s: "device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.0\nxprt: tcp 1 2 3 4 5 6 7 8 9 10", + mounts: []*Mount{{ + Device: "192.168.1.1:/srv", + Mount: "/mnt/nfs", + Type: "nfs", + Stats: &MountStatsNFS{ + StatVersion: "1.0", + Transport: NFSTransportStats{ + Port: 1, + Bind: 2, + Connect: 3, + ConnectIdleTime: 4, + IdleTime: 5 * time.Second, + Sends: 6, + Receives: 7, + BadTransactionIDs: 8, + CumulativeActiveRequests: 9, + CumulativeBacklog: 10, + }, + }, + }}, + }, + { + name: "device rootfs OK", + s: `device rootfs mounted on / with fstype rootfs`, + mounts: []*Mount{{ + Device: "rootfs", + Mount: "/", + Type: "rootfs", + }}, + }, + { + name: "NFSv3 device with minimal stats OK", + s: `device 192.168.1.1:/srv mounted on /mnt/nfs with fstype nfs statvers=1.1`, + mounts: []*Mount{{ + Device: "192.168.1.1:/srv", + Mount: "/mnt/nfs", + Type: "nfs", + Stats: &MountStatsNFS{ + StatVersion: "1.1", + }, + }}, + }, + { + name: "fixtures OK", + mounts: []*Mount{ + { + Device: "rootfs", + Mount: "/", + Type: "rootfs", + }, + { + Device: "sysfs", + Mount: "/sys", + Type: "sysfs", + }, + { + Device: "proc", + Mount: "/proc", + Type: "proc", + }, + { + Device: "/dev/sda1", + Mount: "/", + Type: "ext4", + }, + { + Device: "192.168.1.1:/srv/test", + Mount: "/mnt/nfs/test", + Type: "nfs4", + Stats: &MountStatsNFS{ + StatVersion: "1.1", + Age: 13968 * time.Second, + Bytes: NFSBytesStats{ + Read: 1207640230, + ReadTotal: 1210214218, + ReadPages: 295483, + }, + Events: NFSEventsStats{ + InodeRevalidate: 52, + DnodeRevalidate: 226, + VFSOpen: 1, + VFSLookup: 13, + VFSAccess: 398, + VFSReadPages: 331, + VFSWritePages: 47, + VFSFlush: 77, + VFSFileRelease: 77, + }, + Operations: []NFSOperationStats{ + { + Operation: "NULL", + }, + { + Operation: "READ", + Requests: 1298, + Transmissions: 1298, + BytesSent: 207680, + BytesReceived: 1210292152, + CumulativeQueueTime: 6 * time.Millisecond, + CumulativeTotalResponseTime: 79386 * time.Millisecond, + CumulativeTotalRequestTime: 79407 * time.Millisecond, + }, + { + Operation: "WRITE", + }, + }, + Transport: NFSTransportStats{ + Port: 832, + Connect: 1, + IdleTime: 11 * time.Second, + Sends: 6428, + Receives: 6428, + CumulativeActiveRequests: 12154, + MaximumRPCSlotsUsed: 24, + CumulativeSendingQueue: 26, + CumulativePendingQueue: 5726, + }, + }, + }, + }, + }, + } + + for i, tt := range tests { + t.Logf("[%02d] test %q", i, tt.name) + + var mounts []*Mount + var err error + + if tt.s != "" { + mounts, err = parseMountStats(strings.NewReader(tt.s)) + } else { + proc, e := FS("fixtures").NewProc(26231) + if e != nil { + t.Fatalf("failed to create proc: %v", err) + } + + mounts, err = proc.MountStats() + } + + if tt.invalid && err == nil { + t.Error("expected an error, but none occurred") + } + if !tt.invalid && err != nil { + t.Errorf("unexpected error: %v", err) + } + + if want, have := tt.mounts, mounts; !reflect.DeepEqual(want, have) { + t.Errorf("mounts:\nwant:\n%v\nhave:\n%v", mountsStr(want), mountsStr(have)) + } + } +} + +func mountsStr(mounts []*Mount) string { + var out string + for i, m := range mounts { + out += fmt.Sprintf("[%d] %q on %q (%q)", i, m.Device, m.Mount, m.Type) + + stats, ok := m.Stats.(*MountStatsNFS) + if !ok { + out += "\n" + continue + } + + out += fmt.Sprintf("\n\t- v%s, age: %s", stats.StatVersion, stats.Age) + out += fmt.Sprintf("\n\t- bytes: %v", stats.Bytes) + out += fmt.Sprintf("\n\t- events: %v", stats.Events) + out += fmt.Sprintf("\n\t- transport: %v", stats.Transport) + out += fmt.Sprintf("\n\t- per-operation stats:") + + for _, o := range stats.Operations { + out += fmt.Sprintf("\n\t\t- %v", o) + } + + out += "\n" + } + + return out +} diff --git a/vendor/github.com/prometheus/procfs/net_dev_test.go b/vendor/github.com/prometheus/procfs/net_dev_test.go new file mode 100644 index 000000000..b162e9c95 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/net_dev_test.go @@ -0,0 +1,86 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "testing" +) + +func TestNetDevParseLine(t *testing.T) { + const rawLine = ` eth0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16` + + have, err := NetDev{}.parseLine(rawLine) + if err != nil { + t.Fatal(err) + } + + want := NetDevLine{"eth0", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + if want != *have { + t.Errorf("want %v, have %v", want, have) + } +} + +func TestNewNetDev(t *testing.T) { + fs, err := NewFS("fixtures") + if err != nil { + t.Fatal(err) + } + + nd, err := fs.NewNetDev() + if err != nil { + t.Fatal(err) + } + + lines := map[string]NetDevLine{ + "vethf345468": {Name: "vethf345468", RxBytes: 648, RxPackets: 8, TxBytes: 438, TxPackets: 5}, + "lo": {Name: "lo", RxBytes: 1664039048, RxPackets: 1566805, TxBytes: 1664039048, TxPackets: 1566805}, + "docker0": {Name: "docker0", RxBytes: 2568, RxPackets: 38, TxBytes: 438, TxPackets: 5}, + "eth0": {Name: "eth0", RxBytes: 874354587, RxPackets: 1036395, TxBytes: 563352563, TxPackets: 732147}, + } + + if want, have := len(lines), len(nd); want != have { + t.Errorf("want %d parsed net/dev lines, have %d", want, have) + } + for _, line := range nd { + if want, have := lines[line.Name], line; want != have { + t.Errorf("%s: want %v, have %v", line.Name, want, have) + } + } +} + +func TestProcNewNetDev(t *testing.T) { + p, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + + nd, err := p.NewNetDev() + if err != nil { + t.Fatal(err) + } + + lines := map[string]NetDevLine{ + "lo": {Name: "lo"}, + "eth0": {Name: "eth0", RxBytes: 438, RxPackets: 5, TxBytes: 648, TxPackets: 8}, + } + + if want, have := len(lines), len(nd); want != have { + t.Errorf("want %d parsed net/dev lines, have %d", want, have) + } + for _, line := range nd { + if want, have := lines[line.Name], line; want != have { + t.Errorf("%s: want %v, have %v", line.Name, want, have) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse_nfs_test.go b/vendor/github.com/prometheus/procfs/nfs/parse_nfs_test.go new file mode 100644 index 000000000..8ebcfd16e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/nfs/parse_nfs_test.go @@ -0,0 +1,305 @@ +// Copyright 2018 The Prometheus 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 nfs_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/prometheus/procfs/nfs" +) + +func TestNewNFSClientRPCStats(t *testing.T) { + tests := []struct { + name string + content string + stats *nfs.ClientRPCStats + invalid bool + }{ + { + name: "invalid file", + content: "invalid", + invalid: true, + }, { + name: "good old kernel version file", + content: `net 70 70 69 45 +rpc 1218785755 374636 1218815394 +proc2 18 16 57 74 52 71 73 45 86 0 52 83 61 17 53 50 23 70 82 +proc3 22 0 1061909262 48906 4077635 117661341 5 29391916 2570425 2993289 590 0 0 7815 15 1130 0 3983 92385 13332 2 1 23729 +proc4 48 98 51 54 83 85 23 24 1 28 73 68 83 12 84 39 68 59 58 88 29 74 69 96 21 84 15 53 86 54 66 56 97 36 49 32 85 81 11 58 32 67 13 28 35 90 1 26 1337 +`, + stats: &nfs.ClientRPCStats{ + Network: nfs.Network{ + NetCount: 70, + UDPCount: 70, + TCPCount: 69, + TCPConnect: 45, + }, + ClientRPC: nfs.ClientRPC{ + RPCCount: 1218785755, + Retransmissions: 374636, + AuthRefreshes: 1218815394, + }, + V2Stats: nfs.V2Stats{ + Null: 16, + GetAttr: 57, + SetAttr: 74, + Root: 52, + Lookup: 71, + ReadLink: 73, + Read: 45, + WrCache: 86, + Write: 0, + Create: 52, + Remove: 83, + Rename: 61, + Link: 17, + SymLink: 53, + MkDir: 50, + RmDir: 23, + ReadDir: 70, + FsStat: 82, + }, + V3Stats: nfs.V3Stats{ + Null: 0, + GetAttr: 1061909262, + SetAttr: 48906, + Lookup: 4077635, + Access: 117661341, + ReadLink: 5, + Read: 29391916, + Write: 2570425, + Create: 2993289, + MkDir: 590, + SymLink: 0, + MkNod: 0, + Remove: 7815, + RmDir: 15, + Rename: 1130, + Link: 0, + ReadDir: 3983, + ReadDirPlus: 92385, + FsStat: 13332, + FsInfo: 2, + PathConf: 1, + Commit: 23729}, + ClientV4Stats: nfs.ClientV4Stats{ + Null: 98, + Read: 51, + Write: 54, + Commit: 83, + Open: 85, + OpenConfirm: 23, + OpenNoattr: 24, + OpenDowngrade: 1, + Close: 28, + Setattr: 73, + FsInfo: 68, + Renew: 83, + SetClientID: 12, + SetClientIDConfirm: 84, + Lock: 39, + Lockt: 68, + Locku: 59, + Access: 58, + Getattr: 88, + Lookup: 29, + LookupRoot: 74, + Remove: 69, + Rename: 96, + Link: 21, + Symlink: 84, + Create: 15, + Pathconf: 53, + StatFs: 86, + ReadLink: 54, + ReadDir: 66, + ServerCaps: 56, + DelegReturn: 97, + GetACL: 36, + SetACL: 49, + FsLocations: 32, + ReleaseLockowner: 85, + Secinfo: 81, + FsidPresent: 11, + ExchangeID: 58, + CreateSession: 32, + DestroySession: 67, + Sequence: 13, + GetLeaseTime: 28, + ReclaimComplete: 35, + LayoutGet: 90, + GetDeviceInfo: 1, + LayoutCommit: 26, + LayoutReturn: 1337, + SecinfoNoName: 0, + TestStateID: 0, + FreeStateID: 0, + GetDeviceList: 0, + BindConnToSession: 0, + DestroyClientID: 0, + Seek: 0, + Allocate: 0, + DeAllocate: 0, + LayoutStats: 0, + Clone: 0, + }, + }, + }, { + name: "good file", + content: `net 18628 0 18628 6 +rpc 4329785 0 4338291 +proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 +proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 0 241 4 4 2 39 +proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +`, + stats: &nfs.ClientRPCStats{ + Network: nfs.Network{ + NetCount: 18628, + UDPCount: 0, + TCPCount: 18628, + TCPConnect: 6, + }, + ClientRPC: nfs.ClientRPC{ + RPCCount: 4329785, + Retransmissions: 0, + AuthRefreshes: 4338291, + }, + V2Stats: nfs.V2Stats{ + Null: 2, + GetAttr: 69, + SetAttr: 0, + Root: 0, + Lookup: 4410, + ReadLink: 0, + Read: 0, + WrCache: 0, + Write: 0, + Create: 0, + Remove: 0, + Rename: 0, + Link: 0, + SymLink: 0, + MkDir: 0, + RmDir: 0, + ReadDir: 99, + FsStat: 2, + }, + V3Stats: nfs.V3Stats{ + Null: 1, + GetAttr: 4084749, + SetAttr: 29200, + Lookup: 94754, + Access: 32580, + ReadLink: 186, + Read: 47747, + Write: 7981, + Create: 8639, + MkDir: 0, + SymLink: 6356, + MkNod: 0, + Remove: 6962, + RmDir: 0, + Rename: 7958, + Link: 0, + ReadDir: 0, + ReadDirPlus: 241, + FsStat: 4, + FsInfo: 4, + PathConf: 2, + Commit: 39, + }, + ClientV4Stats: nfs.ClientV4Stats{ + Null: 1, + Read: 0, + Write: 0, + Commit: 0, + Open: 0, + OpenConfirm: 0, + OpenNoattr: 0, + OpenDowngrade: 0, + Close: 0, + Setattr: 0, + FsInfo: 0, + Renew: 0, + SetClientID: 1, + SetClientIDConfirm: 1, + Lock: 0, + Lockt: 0, + Locku: 0, + Access: 0, + Getattr: 0, + Lookup: 0, + LookupRoot: 0, + Remove: 2, + Rename: 0, + Link: 0, + Symlink: 0, + Create: 0, + Pathconf: 0, + StatFs: 0, + ReadLink: 0, + ReadDir: 0, + ServerCaps: 0, + DelegReturn: 0, + GetACL: 0, + SetACL: 0, + FsLocations: 0, + ReleaseLockowner: 0, + Secinfo: 0, + FsidPresent: 0, + ExchangeID: 0, + CreateSession: 0, + DestroySession: 0, + Sequence: 0, + GetLeaseTime: 0, + ReclaimComplete: 0, + LayoutGet: 0, + GetDeviceInfo: 0, + LayoutCommit: 0, + LayoutReturn: 0, + SecinfoNoName: 0, + TestStateID: 0, + FreeStateID: 0, + GetDeviceList: 0, + BindConnToSession: 0, + DestroyClientID: 0, + Seek: 0, + Allocate: 0, + DeAllocate: 0, + LayoutStats: 0, + Clone: 0, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stats, err := nfs.ParseClientRPCStats(strings.NewReader(tt.content)) + + if tt.invalid && err == nil { + t.Fatal("expected an error, but none occurred") + } + if !tt.invalid && err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if want, have := tt.stats, stats; !reflect.DeepEqual(want, have) { + t.Fatalf("unexpected NFS stats:\nwant:\n%v\nhave:\n%v", want, have) + } + }) + } +} diff --git a/vendor/github.com/prometheus/procfs/nfs/parse_nfsd_test.go b/vendor/github.com/prometheus/procfs/nfs/parse_nfsd_test.go new file mode 100644 index 000000000..b09b3b580 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/nfs/parse_nfsd_test.go @@ -0,0 +1,196 @@ +// Copyright 2018 The Prometheus 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 nfs_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/prometheus/procfs/nfs" +) + +func TestNewNFSdServerRPCStats(t *testing.T) { + tests := []struct { + name string + content string + stats *nfs.ServerRPCStats + invalid bool + }{ + { + name: "invalid file", + content: "invalid", + invalid: true, + }, { + name: "good file", + content: `rc 0 6 18622 +fh 0 0 0 0 0 +io 157286400 0 +th 8 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 +ra 32 0 0 0 0 0 0 0 0 0 0 0 +net 18628 0 18628 6 +rpc 18628 0 0 0 0 +proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 +proc3 22 2 112 0 2719 111 0 0 0 0 0 0 0 0 0 0 0 27 216 0 2 1 0 +proc4 2 2 10853 +proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +`, + stats: &nfs.ServerRPCStats{ + ReplyCache: nfs.ReplyCache{ + Hits: 0, + Misses: 6, + NoCache: 18622, + }, + FileHandles: nfs.FileHandles{ + Stale: 0, + TotalLookups: 0, + AnonLookups: 0, + DirNoCache: 0, + NoDirNoCache: 0, + }, + InputOutput: nfs.InputOutput{ + Read: 157286400, + Write: 0, + }, + Threads: nfs.Threads{ + Threads: 8, + FullCnt: 0, + }, + ReadAheadCache: nfs.ReadAheadCache{ + CacheSize: 32, + CacheHistogram: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + NotFound: 0, + }, + Network: nfs.Network{ + NetCount: 18628, + UDPCount: 0, + TCPCount: 18628, + TCPConnect: 6, + }, + ServerRPC: nfs.ServerRPC{ + RPCCount: 18628, + BadCnt: 0, + BadFmt: 0, + BadAuth: 0, + BadcInt: 0, + }, + V2Stats: nfs.V2Stats{ + Null: 2, + GetAttr: 69, + SetAttr: 0, + Root: 0, + Lookup: 4410, + ReadLink: 0, + Read: 0, + WrCache: 0, + Write: 0, + Create: 0, + Remove: 0, + Rename: 0, + Link: 0, + SymLink: 0, + MkDir: 0, + RmDir: 0, + ReadDir: 99, + FsStat: 2, + }, + V3Stats: nfs.V3Stats{ + Null: 2, + GetAttr: 112, + SetAttr: 0, + Lookup: 2719, + Access: 111, + ReadLink: 0, + Read: 0, + Write: 0, + Create: 0, + MkDir: 0, + SymLink: 0, + MkNod: 0, + Remove: 0, + RmDir: 0, + Rename: 0, + Link: 0, + ReadDir: 27, + ReadDirPlus: 216, + FsStat: 0, + FsInfo: 2, + PathConf: 1, + Commit: 0, + }, + ServerV4Stats: nfs.ServerV4Stats{ + Null: 2, + Compound: 10853, + }, + V4Ops: nfs.V4Ops{ + Op0Unused: 0, + Op1Unused: 0, + Op2Future: 0, + Access: 1098, + Close: 2, + Commit: 0, + Create: 0, + DelegPurge: 0, + DelegReturn: 0, + GetAttr: 8179, + GetFH: 5896, + Link: 0, + Lock: 0, + Lockt: 0, + Locku: 0, + Lookup: 5900, + LookupRoot: 0, + Nverify: 0, + Open: 2, + OpenAttr: 0, + OpenConfirm: 2, + OpenDgrd: 0, + PutFH: 9609, + PutPubFH: 0, + PutRootFH: 2, + Read: 150, + ReadDir: 1272, + ReadLink: 0, + Remove: 0, + Rename: 0, + Renew: 1236, + RestoreFH: 0, + SaveFH: 0, + SecInfo: 0, + SetAttr: 0, + Verify: 3, + Write: 3, + RelLockOwner: 0, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stats, err := nfs.ParseServerRPCStats(strings.NewReader(tt.content)) + + if tt.invalid && err == nil { + t.Fatal("expected an error, but none occurred") + } + if !tt.invalid && err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if want, have := tt.stats, stats; !reflect.DeepEqual(want, have) { + t.Fatalf("unexpected NFS stats:\nwant:\n%v\nhave:\n%v", want, have) + } + }) + } +} diff --git a/vendor/github.com/prometheus/procfs/proc_io_test.go b/vendor/github.com/prometheus/procfs/proc_io_test.go new file mode 100644 index 000000000..1afdbd463 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_io_test.go @@ -0,0 +1,46 @@ +// Copyright 2018 The Prometheus 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 procfs + +import "testing" + +func TestProcIO(t *testing.T) { + p, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + + s, err := p.NewIO() + if err != nil { + t.Fatal(err) + } + + for _, test := range []struct { + name string + want int64 + have int64 + }{ + {name: "RChar", want: 750339, have: int64(s.RChar)}, + {name: "WChar", want: 818609, have: int64(s.WChar)}, + {name: "SyscR", want: 7405, have: int64(s.SyscR)}, + {name: "SyscW", want: 5245, have: int64(s.SyscW)}, + {name: "ReadBytes", want: 1024, have: int64(s.ReadBytes)}, + {name: "WriteBytes", want: 2048, have: int64(s.WriteBytes)}, + {name: "CancelledWriteBytes", want: -1024, have: s.CancelledWriteBytes}, + } { + if test.want != test.have { + t.Errorf("want %s %d, have %d", test.name, test.want, test.have) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/proc_limits_test.go b/vendor/github.com/prometheus/procfs/proc_limits_test.go new file mode 100644 index 000000000..ebb43ae74 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_limits_test.go @@ -0,0 +1,44 @@ +// Copyright 2018 The Prometheus 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 procfs + +import "testing" + +func TestNewLimits(t *testing.T) { + p, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + + l, err := p.NewLimits() + if err != nil { + t.Fatal(err) + } + + for _, test := range []struct { + name string + want int64 + have int64 + }{ + {name: "cpu time", want: -1, have: l.CPUTime}, + {name: "open files", want: 2048, have: l.OpenFiles}, + {name: "msgqueue size", want: 819200, have: l.MsqqueueSize}, + {name: "nice priority", want: 0, have: l.NicePriority}, + {name: "address space", want: 8589934592, have: l.AddressSpace}, + } { + if test.want != test.have { + t.Errorf("want %s %d, have %d", test.name, test.want, test.have) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/proc_ns_test.go b/vendor/github.com/prometheus/procfs/proc_ns_test.go new file mode 100644 index 000000000..abfd63e5f --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_ns_test.go @@ -0,0 +1,44 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "testing" +) + +func TestNewNamespaces(t *testing.T) { + p, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + + namespaces, err := p.NewNamespaces() + if err != nil { + t.Fatal(err) + } + + expectedNamespaces := map[string]Namespace{ + "mnt": {"mnt", 4026531840}, + "net": {"net", 4026531993}, + } + + if want, have := len(expectedNamespaces), len(namespaces); want != have { + t.Errorf("want %d parsed namespaces, have %d", want, have) + } + for _, ns := range namespaces { + if want, have := expectedNamespaces[ns.Type], ns; want != have { + t.Errorf("%s: want %v, have %v", ns.Type, want, have) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/proc_stat_test.go b/vendor/github.com/prometheus/procfs/proc_stat_test.go new file mode 100644 index 000000000..e2df8845f --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_stat_test.go @@ -0,0 +1,123 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "os" + "testing" +) + +func TestProcStat(t *testing.T) { + p, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + + s, err := p.NewStat() + if err != nil { + t.Fatal(err) + } + + for _, test := range []struct { + name string + want int + have int + }{ + {name: "pid", want: 26231, have: s.PID}, + {name: "user time", want: 1677, have: int(s.UTime)}, + {name: "system time", want: 44, have: int(s.STime)}, + {name: "start time", want: 82375, have: int(s.Starttime)}, + {name: "virtual memory size", want: 56274944, have: s.VSize}, + {name: "resident set size", want: 1981, have: s.RSS}, + } { + if test.want != test.have { + t.Errorf("want %s %d, have %d", test.name, test.want, test.have) + } + } +} + +func TestProcStatComm(t *testing.T) { + s1, err := testProcStat(26231) + if err != nil { + t.Fatal(err) + } + if want, have := "vim", s1.Comm; want != have { + t.Errorf("want comm %s, have %s", want, have) + } + + s2, err := testProcStat(584) + if err != nil { + t.Fatal(err) + } + if want, have := "(a b ) ( c d) ", s2.Comm; want != have { + t.Errorf("want comm %s, have %s", want, have) + } +} + +func TestProcStatVirtualMemory(t *testing.T) { + s, err := testProcStat(26231) + if err != nil { + t.Fatal(err) + } + + if want, have := 56274944, s.VirtualMemory(); want != have { + t.Errorf("want virtual memory %d, have %d", want, have) + } +} + +func TestProcStatResidentMemory(t *testing.T) { + s, err := testProcStat(26231) + if err != nil { + t.Fatal(err) + } + + if want, have := 1981*os.Getpagesize(), s.ResidentMemory(); want != have { + t.Errorf("want resident memory %d, have %d", want, have) + } +} + +func TestProcStatStartTime(t *testing.T) { + s, err := testProcStat(26231) + if err != nil { + t.Fatal(err) + } + + time, err := s.StartTime() + if err != nil { + t.Fatal(err) + } + if want, have := 1418184099.75, time; want != have { + t.Errorf("want start time %f, have %f", want, have) + } +} + +func TestProcStatCPUTime(t *testing.T) { + s, err := testProcStat(26231) + if err != nil { + t.Fatal(err) + } + + if want, have := 17.21, s.CPUTime(); want != have { + t.Errorf("want cpu time %f, have %f", want, have) + } +} + +func testProcStat(pid int) (ProcStat, error) { + p, err := FS("fixtures").NewProc(pid) + if err != nil { + return ProcStat{}, err + } + + return p.NewStat() +} diff --git a/vendor/github.com/prometheus/procfs/proc_test.go b/vendor/github.com/prometheus/procfs/proc_test.go new file mode 100644 index 000000000..ee7e69d6b --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_test.go @@ -0,0 +1,174 @@ +// Copyright 2018 The Prometheus 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 procfs + +import ( + "reflect" + "sort" + "testing" +) + +func TestSelf(t *testing.T) { + fs := FS("fixtures") + + p1, err := fs.NewProc(26231) + if err != nil { + t.Fatal(err) + } + p2, err := fs.Self() + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(p1, p2) { + t.Errorf("want process %v, have %v", p1, p2) + } +} + +func TestAllProcs(t *testing.T) { + procs, err := FS("fixtures").AllProcs() + if err != nil { + t.Fatal(err) + } + sort.Sort(procs) + for i, p := range []*Proc{{PID: 584}, {PID: 26231}} { + if want, have := p.PID, procs[i].PID; want != have { + t.Errorf("want processes %d, have %d", want, have) + } + } +} + +func TestCmdLine(t *testing.T) { + for _, tt := range []struct { + process int + want []string + }{ + {process: 26231, want: []string{"vim", "test.go", "+10"}}, + {process: 26232, want: []string{}}, + {process: 26233, want: []string{"com.github.uiautomator"}}, + } { + p1, err := FS("fixtures").NewProc(tt.process) + if err != nil { + t.Fatal(err) + } + c1, err := p1.CmdLine() + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(tt.want, c1) { + t.Errorf("want cmdline %v, have %v", tt.want, c1) + } + } +} + +func TestComm(t *testing.T) { + for _, tt := range []struct { + process int + want string + }{ + {process: 26231, want: "vim"}, + {process: 26232, want: "ata_sff"}, + } { + p1, err := FS("fixtures").NewProc(tt.process) + if err != nil { + t.Fatal(err) + } + c1, err := p1.Comm() + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(tt.want, c1) { + t.Errorf("want comm %v, have %v", tt.want, c1) + } + } +} + +func TestExecutable(t *testing.T) { + for _, tt := range []struct { + process int + want string + }{ + {process: 26231, want: "/usr/bin/vim"}, + {process: 26232, want: ""}, + } { + p, err := FS("fixtures").NewProc(tt.process) + if err != nil { + t.Fatal(err) + } + exe, err := p.Executable() + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(tt.want, exe) { + t.Errorf("want absolute path to cmdline %v, have %v", tt.want, exe) + } + } +} + +func TestFileDescriptors(t *testing.T) { + p1, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + fds, err := p1.FileDescriptors() + if err != nil { + t.Fatal(err) + } + sort.Sort(byUintptr(fds)) + if want := []uintptr{0, 1, 2, 3, 10}; !reflect.DeepEqual(want, fds) { + t.Errorf("want fds %v, have %v", want, fds) + } +} + +func TestFileDescriptorTargets(t *testing.T) { + p1, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + fds, err := p1.FileDescriptorTargets() + if err != nil { + t.Fatal(err) + } + sort.Strings(fds) + var want = []string{ + "../../symlinktargets/abc", + "../../symlinktargets/def", + "../../symlinktargets/ghi", + "../../symlinktargets/uvw", + "../../symlinktargets/xyz", + } + if !reflect.DeepEqual(want, fds) { + t.Errorf("want fds %v, have %v", want, fds) + } +} + +func TestFileDescriptorsLen(t *testing.T) { + p1, err := FS("fixtures").NewProc(26231) + if err != nil { + t.Fatal(err) + } + l, err := p1.FileDescriptorsLen() + if err != nil { + t.Fatal(err) + } + if want, have := 5, l; want != have { + t.Errorf("want fds %d, have %d", want, have) + } +} + +type byUintptr []uintptr + +func (a byUintptr) Len() int { return len(a) } +func (a byUintptr) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byUintptr) Less(i, j int) bool { return a[i] < a[j] } diff --git a/vendor/github.com/prometheus/procfs/stat_test.go b/vendor/github.com/prometheus/procfs/stat_test.go new file mode 100644 index 000000000..2043b5e43 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/stat_test.go @@ -0,0 +1,74 @@ +// Copyright 2018 The Prometheus 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 procfs + +import "testing" + +func TestStat(t *testing.T) { + s, err := FS("fixtures").NewStat() + if err != nil { + t.Fatal(err) + } + + // cpu + if want, have := float64(301854)/userHZ, s.CPUTotal.User; want != have { + t.Errorf("want cpu/user %v, have %v", want, have) + } + if want, have := float64(31)/userHZ, s.CPU[7].SoftIRQ; want != have { + t.Errorf("want cpu7/softirq %v, have %v", want, have) + } + + // intr + if want, have := uint64(8885917), s.IRQTotal; want != have { + t.Errorf("want irq/total %d, have %d", want, have) + } + if want, have := uint64(1), s.IRQ[8]; want != have { + t.Errorf("want irq8 %d, have %d", want, have) + } + + // ctxt + if want, have := uint64(38014093), s.ContextSwitches; want != have { + t.Errorf("want context switches (ctxt) %d, have %d", want, have) + } + + // btime + if want, have := uint64(1418183276), s.BootTime; want != have { + t.Errorf("want boot time (btime) %d, have %d", want, have) + } + + // processes + if want, have := uint64(26442), s.ProcessCreated; want != have { + t.Errorf("want process created (processes) %d, have %d", want, have) + } + + // procs_running + if want, have := uint64(2), s.ProcessesRunning; want != have { + t.Errorf("want processes running (procs_running) %d, have %d", want, have) + } + + // procs_blocked + if want, have := uint64(1), s.ProcessesBlocked; want != have { + t.Errorf("want processes blocked (procs_blocked) %d, have %d", want, have) + } + + // softirq + if want, have := uint64(5057579), s.SoftIRQTotal; want != have { + t.Errorf("want softirq total %d, have %d", want, have) + } + + if want, have := uint64(508444), s.SoftIRQ.Rcu; want != have { + t.Errorf("want softirq RCU %d, have %d", want, have) + } + +} diff --git a/vendor/github.com/prometheus/procfs/ttar b/vendor/github.com/prometheus/procfs/ttar new file mode 100755 index 000000000..b0171a12b --- /dev/null +++ b/vendor/github.com/prometheus/procfs/ttar @@ -0,0 +1,389 @@ +#!/usr/bin/env bash + +# Purpose: plain text tar format +# Limitations: - only suitable for text files, directories, and symlinks +# - stores only filename, content, and mode +# - not designed for untrusted input +# +# Note: must work with bash version 3.2 (macOS) + +# Copyright 2017 Roger Luethi +# +# 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. + +set -o errexit -o nounset + +# Sanitize environment (for instance, standard sorting of glob matches) +export LC_ALL=C + +path="" +CMD="" +ARG_STRING="$*" + +#------------------------------------------------------------------------------ +# Not all sed implementations can work on null bytes. In order to make ttar +# work out of the box on macOS, use Python as a stream editor. + +USE_PYTHON=0 + +PYTHON_CREATE_FILTER=$(cat << 'PCF' +#!/usr/bin/env python + +import re +import sys + +for line in sys.stdin: + line = re.sub(r'EOF', r'\EOF', line) + line = re.sub(r'NULLBYTE', r'\NULLBYTE', line) + line = re.sub('\x00', r'NULLBYTE', line) + sys.stdout.write(line) +PCF +) + +PYTHON_EXTRACT_FILTER=$(cat << 'PEF' +#!/usr/bin/env python + +import re +import sys + +for line in sys.stdin: + line = re.sub(r'(?/dev/null; then + echo "ERROR Python not found. Aborting." + exit 2 + fi + USE_PYTHON=1 + fi +} + +#------------------------------------------------------------------------------ + +function usage { + bname=$(basename "$0") + cat << USAGE +Usage: $bname [-C ] -c -f (create archive) + $bname -t -f (list archive contents) + $bname [-C ] -x -f (extract archive) + +Options: + -C (change directory) + -v (verbose) + +Example: Change to sysfs directory, create ttar file from fixtures directory + $bname -C sysfs -c -f sysfs/fixtures.ttar fixtures/ +USAGE +exit "$1" +} + +function vecho { + if [ "${VERBOSE:-}" == "yes" ]; then + echo >&7 "$@" + fi +} + +function set_cmd { + if [ -n "$CMD" ]; then + echo "ERROR: more than one command given" + echo + usage 2 + fi + CMD=$1 +} + +unset VERBOSE + +while getopts :cf:htxvC: opt; do + case $opt in + c) + set_cmd "create" + ;; + f) + ARCHIVE=$OPTARG + ;; + h) + usage 0 + ;; + t) + set_cmd "list" + ;; + x) + set_cmd "extract" + ;; + v) + VERBOSE=yes + exec 7>&1 + ;; + C) + CDIR=$OPTARG + ;; + *) + echo >&2 "ERROR: invalid option -$OPTARG" + echo + usage 1 + ;; + esac +done + +# Remove processed options from arguments +shift $(( OPTIND - 1 )); + +if [ "${CMD:-}" == "" ]; then + echo >&2 "ERROR: no command given" + echo + usage 1 +elif [ "${ARCHIVE:-}" == "" ]; then + echo >&2 "ERROR: no archive name given" + echo + usage 1 +fi + +function list { + local path="" + local size=0 + local line_no=0 + local ttar_file=$1 + if [ -n "${2:-}" ]; then + echo >&2 "ERROR: too many arguments." + echo + usage 1 + fi + if [ ! -e "$ttar_file" ]; then + echo >&2 "ERROR: file not found ($ttar_file)" + echo + usage 1 + fi + while read -r line; do + line_no=$(( line_no + 1 )) + if [ $size -gt 0 ]; then + size=$(( size - 1 )) + continue + fi + if [[ $line =~ ^Path:\ (.*)$ ]]; then + path=${BASH_REMATCH[1]} + elif [[ $line =~ ^Lines:\ (.*)$ ]]; then + size=${BASH_REMATCH[1]} + echo "$path" + elif [[ $line =~ ^Directory:\ (.*)$ ]]; then + path=${BASH_REMATCH[1]} + echo "$path/" + elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then + echo "$path -> ${BASH_REMATCH[1]}" + fi + done < "$ttar_file" +} + +function extract { + local path="" + local size=0 + local line_no=0 + local ttar_file=$1 + if [ -n "${2:-}" ]; then + echo >&2 "ERROR: too many arguments." + echo + usage 1 + fi + if [ ! -e "$ttar_file" ]; then + echo >&2 "ERROR: file not found ($ttar_file)" + echo + usage 1 + fi + while IFS= read -r line; do + line_no=$(( line_no + 1 )) + local eof_without_newline + if [ "$size" -gt 0 ]; then + if [[ "$line" =~ [^\\]EOF ]]; then + # An EOF not preceeded by a backslash indicates that the line + # does not end with a newline + eof_without_newline=1 + else + eof_without_newline=0 + fi + # Replace NULLBYTE with null byte if at beginning of line + # Replace NULLBYTE with null byte unless preceeded by backslash + # Remove one backslash in front of NULLBYTE (if any) + # Remove EOF unless preceeded by backslash + # Remove one backslash in front of EOF + if [ $USE_PYTHON -eq 1 ]; then + echo -n "$line" | python -c "$PYTHON_EXTRACT_FILTER" >> "$path" + else + # The repeated pattern makes up for sed's lack of negative + # lookbehind assertions (for consecutive null bytes). + echo -n "$line" | \ + sed -e 's/^NULLBYTE/\x0/g; + s/\([^\\]\)NULLBYTE/\1\x0/g; + s/\([^\\]\)NULLBYTE/\1\x0/g; + s/\\NULLBYTE/NULLBYTE/g; + s/\([^\\]\)EOF/\1/g; + s/\\EOF/EOF/g; + ' >> "$path" + fi + if [[ "$eof_without_newline" -eq 0 ]]; then + echo >> "$path" + fi + size=$(( size - 1 )) + continue + fi + if [[ $line =~ ^Path:\ (.*)$ ]]; then + path=${BASH_REMATCH[1]} + if [ -e "$path" ] || [ -L "$path" ]; then + rm "$path" + fi + elif [[ $line =~ ^Lines:\ (.*)$ ]]; then + size=${BASH_REMATCH[1]} + # Create file even if it is zero-length. + touch "$path" + vecho " $path" + elif [[ $line =~ ^Mode:\ (.*)$ ]]; then + mode=${BASH_REMATCH[1]} + chmod "$mode" "$path" + vecho "$mode" + elif [[ $line =~ ^Directory:\ (.*)$ ]]; then + path=${BASH_REMATCH[1]} + mkdir -p "$path" + vecho " $path/" + elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then + ln -s "${BASH_REMATCH[1]}" "$path" + vecho " $path -> ${BASH_REMATCH[1]}" + elif [[ $line =~ ^# ]]; then + # Ignore comments between files + continue + else + echo >&2 "ERROR: Unknown keyword on line $line_no: $line" + exit 1 + fi + done < "$ttar_file" +} + +function div { + echo "# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" \ + "- - - - - -" +} + +function get_mode { + local mfile=$1 + if [ -z "${STAT_OPTION:-}" ]; then + if stat -c '%a' "$mfile" >/dev/null 2>&1; then + # GNU stat + STAT_OPTION='-c' + STAT_FORMAT='%a' + else + # BSD stat + STAT_OPTION='-f' + # Octal output, user/group/other (omit file type, sticky bit) + STAT_FORMAT='%OLp' + fi + fi + stat "${STAT_OPTION}" "${STAT_FORMAT}" "$mfile" +} + +function _create { + shopt -s nullglob + local mode + local eof_without_newline + while (( "$#" )); do + file=$1 + if [ -L "$file" ]; then + echo "Path: $file" + symlinkTo=$(readlink "$file") + echo "SymlinkTo: $symlinkTo" + vecho " $file -> $symlinkTo" + div + elif [ -d "$file" ]; then + # Strip trailing slash (if there is one) + file=${file%/} + echo "Directory: $file" + mode=$(get_mode "$file") + echo "Mode: $mode" + vecho "$mode $file/" + div + # Find all files and dirs, including hidden/dot files + for x in "$file/"{*,.[^.]*}; do + _create "$x" + done + elif [ -f "$file" ]; then + echo "Path: $file" + lines=$(wc -l "$file"|awk '{print $1}') + eof_without_newline=0 + if [[ "$(wc -c "$file"|awk '{print $1}')" -gt 0 ]] && \ + [[ "$(tail -c 1 "$file" | wc -l)" -eq 0 ]]; then + eof_without_newline=1 + lines=$((lines+1)) + fi + echo "Lines: $lines" + # Add backslash in front of EOF + # Add backslash in front of NULLBYTE + # Replace null byte with NULLBYTE + if [ $USE_PYTHON -eq 1 ]; then + < "$file" python -c "$PYTHON_CREATE_FILTER" + else + < "$file" \ + sed 's/EOF/\\EOF/g; + s/NULLBYTE/\\NULLBYTE/g; + s/\x0/NULLBYTE/g; + ' + fi + if [[ "$eof_without_newline" -eq 1 ]]; then + # Finish line with EOF to indicate that the original line did + # not end with a linefeed + echo "EOF" + fi + mode=$(get_mode "$file") + echo "Mode: $mode" + vecho "$mode $file" + div + else + echo >&2 "ERROR: file not found ($file in $(pwd))" + exit 2 + fi + shift + done +} + +function create { + ttar_file=$1 + shift + if [ -z "${1:-}" ]; then + echo >&2 "ERROR: missing arguments." + echo + usage 1 + fi + if [ -e "$ttar_file" ]; then + rm "$ttar_file" + fi + exec > "$ttar_file" + echo "# Archive created by ttar $ARG_STRING" + _create "$@" +} + +test_environment + +if [ -n "${CDIR:-}" ]; then + if [[ "$ARCHIVE" != /* ]]; then + # Relative path: preserve the archive's location before changing + # directory + ARCHIVE="$(pwd)/$ARCHIVE" + fi + cd "$CDIR" +fi + +"$CMD" "$ARCHIVE" "$@" diff --git a/vendor/github.com/prometheus/procfs/xfrm_test.go b/vendor/github.com/prometheus/procfs/xfrm_test.go new file mode 100644 index 000000000..5918c390e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/xfrm_test.go @@ -0,0 +1,66 @@ +// Copyright 2017 Prometheus Team +// 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 procfs + +import ( + "testing" +) + +func TestXfrmStats(t *testing.T) { + xfrmStats, err := FS("fixtures").NewXfrmStat() + if err != nil { + t.Fatal(err) + } + + for _, test := range []struct { + name string + want int + got int + }{ + {name: "XfrmInError", want: 1, got: xfrmStats.XfrmInError}, + {name: "XfrmInBufferError", want: 2, got: xfrmStats.XfrmInBufferError}, + {name: "XfrmInHdrError", want: 4, got: xfrmStats.XfrmInHdrError}, + {name: "XfrmInNoStates", want: 3, got: xfrmStats.XfrmInNoStates}, + {name: "XfrmInStateProtoError", want: 40, got: xfrmStats.XfrmInStateProtoError}, + {name: "XfrmInStateModeError", want: 100, got: xfrmStats.XfrmInStateModeError}, + {name: "XfrmInStateSeqError", want: 6000, got: xfrmStats.XfrmInStateSeqError}, + {name: "XfrmInStateExpired", want: 4, got: xfrmStats.XfrmInStateExpired}, + {name: "XfrmInStateMismatch", want: 23451, got: xfrmStats.XfrmInStateMismatch}, + {name: "XfrmInStateInvalid", want: 55555, got: xfrmStats.XfrmInStateInvalid}, + {name: "XfrmInTmplMismatch", want: 51, got: xfrmStats.XfrmInTmplMismatch}, + {name: "XfrmInNoPols", want: 65432, got: xfrmStats.XfrmInNoPols}, + {name: "XfrmInPolBlock", want: 100, got: xfrmStats.XfrmInPolBlock}, + {name: "XfrmInPolError", want: 10000, got: xfrmStats.XfrmInPolError}, + {name: "XfrmOutError", want: 1000000, got: xfrmStats.XfrmOutError}, + {name: "XfrmOutBundleGenError", want: 43321, got: xfrmStats.XfrmOutBundleGenError}, + {name: "XfrmOutBundleCheckError", want: 555, got: xfrmStats.XfrmOutBundleCheckError}, + {name: "XfrmOutNoStates", want: 869, got: xfrmStats.XfrmOutNoStates}, + {name: "XfrmOutStateProtoError", want: 4542, got: xfrmStats.XfrmOutStateProtoError}, + {name: "XfrmOutStateModeError", want: 4, got: xfrmStats.XfrmOutStateModeError}, + {name: "XfrmOutStateSeqError", want: 543, got: xfrmStats.XfrmOutStateSeqError}, + {name: "XfrmOutStateExpired", want: 565, got: xfrmStats.XfrmOutStateExpired}, + {name: "XfrmOutPolBlock", want: 43456, got: xfrmStats.XfrmOutPolBlock}, + {name: "XfrmOutPolDead", want: 7656, got: xfrmStats.XfrmOutPolDead}, + {name: "XfrmOutPolError", want: 1454, got: xfrmStats.XfrmOutPolError}, + {name: "XfrmFwdHdrError", want: 6654, got: xfrmStats.XfrmFwdHdrError}, + {name: "XfrmOutStateInvaliad", want: 28765, got: xfrmStats.XfrmOutStateInvalid}, + {name: "XfrmAcquireError", want: 24532, got: xfrmStats.XfrmAcquireError}, + {name: "XfrmInStateInvalid", want: 55555, got: xfrmStats.XfrmInStateInvalid}, + {name: "XfrmOutError", want: 1000000, got: xfrmStats.XfrmOutError}, + } { + if test.want != test.got { + t.Errorf("Want %s %d, have %d", test.name, test.want, test.got) + } + } +} diff --git a/vendor/github.com/prometheus/procfs/xfs/parse_test.go b/vendor/github.com/prometheus/procfs/xfs/parse_test.go new file mode 100644 index 000000000..2e946c2c5 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/xfs/parse_test.go @@ -0,0 +1,442 @@ +// Copyright 2017 The Prometheus 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 xfs_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/prometheus/procfs" + "github.com/prometheus/procfs/xfs" +) + +func TestParseStats(t *testing.T) { + tests := []struct { + name string + s string + fs bool + stats *xfs.Stats + invalid bool + }{ + { + name: "empty file OK", + }, + { + name: "short or empty lines and unknown labels ignored", + s: "one\n\ntwo 1 2 3\n", + stats: &xfs.Stats{}, + }, + { + name: "bad uint32", + s: "extent_alloc XXX", + invalid: true, + }, + { + name: "bad uint64", + s: "xpc XXX", + invalid: true, + }, + { + name: "extent_alloc bad", + s: "extent_alloc 1", + invalid: true, + }, + { + name: "extent_alloc OK", + s: "extent_alloc 1 2 3 4", + stats: &xfs.Stats{ + ExtentAllocation: xfs.ExtentAllocationStats{ + ExtentsAllocated: 1, + BlocksAllocated: 2, + ExtentsFreed: 3, + BlocksFreed: 4, + }, + }, + }, + { + name: "abt bad", + s: "abt 1", + invalid: true, + }, + { + name: "abt OK", + s: "abt 1 2 3 4", + stats: &xfs.Stats{ + AllocationBTree: xfs.BTreeStats{ + Lookups: 1, + Compares: 2, + RecordsInserted: 3, + RecordsDeleted: 4, + }, + }, + }, + { + name: "blk_map bad", + s: "blk_map 1", + invalid: true, + }, + { + name: "blk_map OK", + s: "blk_map 1 2 3 4 5 6 7", + stats: &xfs.Stats{ + BlockMapping: xfs.BlockMappingStats{ + Reads: 1, + Writes: 2, + Unmaps: 3, + ExtentListInsertions: 4, + ExtentListDeletions: 5, + ExtentListLookups: 6, + ExtentListCompares: 7, + }, + }, + }, + { + name: "bmbt bad", + s: "bmbt 1", + invalid: true, + }, + { + name: "bmbt OK", + s: "bmbt 1 2 3 4", + stats: &xfs.Stats{ + BlockMapBTree: xfs.BTreeStats{ + Lookups: 1, + Compares: 2, + RecordsInserted: 3, + RecordsDeleted: 4, + }, + }, + }, + { + name: "dir bad", + s: "dir 1", + invalid: true, + }, + { + name: "dir OK", + s: "dir 1 2 3 4", + stats: &xfs.Stats{ + DirectoryOperation: xfs.DirectoryOperationStats{ + Lookups: 1, + Creates: 2, + Removes: 3, + Getdents: 4, + }, + }, + }, + { + name: "trans bad", + s: "trans 1", + invalid: true, + }, + { + name: "trans OK", + s: "trans 1 2 3", + stats: &xfs.Stats{ + Transaction: xfs.TransactionStats{ + Sync: 1, + Async: 2, + Empty: 3, + }, + }, + }, + { + name: "ig bad", + s: "ig 1", + invalid: true, + }, + { + name: "ig OK", + s: "ig 1 2 3 4 5 6 7", + stats: &xfs.Stats{ + InodeOperation: xfs.InodeOperationStats{ + Attempts: 1, + Found: 2, + Recycle: 3, + Missed: 4, + Duplicate: 5, + Reclaims: 6, + AttributeChange: 7, + }, + }, + }, + { + name: "log bad", + s: "log 1", + invalid: true, + }, + { + name: "log OK", + s: "log 1 2 3 4 5", + stats: &xfs.Stats{ + LogOperation: xfs.LogOperationStats{ + Writes: 1, + Blocks: 2, + NoInternalBuffers: 3, + Force: 4, + ForceSleep: 5, + }, + }, + }, + { + name: "rw bad", + s: "rw 1", + invalid: true, + }, + { + name: "rw OK", + s: "rw 1 2", + stats: &xfs.Stats{ + ReadWrite: xfs.ReadWriteStats{ + Read: 1, + Write: 2, + }, + }, + }, + { + name: "attr bad", + s: "attr 1", + invalid: true, + }, + { + name: "attr OK", + s: "attr 1 2 3 4", + stats: &xfs.Stats{ + AttributeOperation: xfs.AttributeOperationStats{ + Get: 1, + Set: 2, + Remove: 3, + List: 4, + }, + }, + }, + { + name: "icluster bad", + s: "icluster 1", + invalid: true, + }, + { + name: "icluster OK", + s: "icluster 1 2 3", + stats: &xfs.Stats{ + InodeClustering: xfs.InodeClusteringStats{ + Iflush: 1, + Flush: 2, + FlushInode: 3, + }, + }, + }, + { + name: "vnodes bad", + s: "vnodes 1", + invalid: true, + }, + { + name: "vnodes (missing free) OK", + s: "vnodes 1 2 3 4 5 6 7", + stats: &xfs.Stats{ + Vnode: xfs.VnodeStats{ + Active: 1, + Allocate: 2, + Get: 3, + Hold: 4, + Release: 5, + Reclaim: 6, + Remove: 7, + }, + }, + }, + { + name: "vnodes (with free) OK", + s: "vnodes 1 2 3 4 5 6 7 8", + stats: &xfs.Stats{ + Vnode: xfs.VnodeStats{ + Active: 1, + Allocate: 2, + Get: 3, + Hold: 4, + Release: 5, + Reclaim: 6, + Remove: 7, + Free: 8, + }, + }, + }, + { + name: "buf bad", + s: "buf 1", + invalid: true, + }, + { + name: "buf OK", + s: "buf 1 2 3 4 5 6 7 8 9", + stats: &xfs.Stats{ + Buffer: xfs.BufferStats{ + Get: 1, + Create: 2, + GetLocked: 3, + GetLockedWaited: 4, + BusyLocked: 5, + MissLocked: 6, + PageRetries: 7, + PageFound: 8, + GetRead: 9, + }, + }, + }, + { + name: "xpc bad", + s: "xpc 1", + invalid: true, + }, + { + name: "xpc OK", + s: "xpc 1 2 3", + stats: &xfs.Stats{ + ExtendedPrecision: xfs.ExtendedPrecisionStats{ + FlushBytes: 1, + WriteBytes: 2, + ReadBytes: 3, + }, + }, + }, + { + name: "fixtures OK", + fs: true, + stats: &xfs.Stats{ + ExtentAllocation: xfs.ExtentAllocationStats{ + ExtentsAllocated: 92447, + BlocksAllocated: 97589, + ExtentsFreed: 92448, + BlocksFreed: 93751, + }, + AllocationBTree: xfs.BTreeStats{ + Lookups: 0, + Compares: 0, + RecordsInserted: 0, + RecordsDeleted: 0, + }, + BlockMapping: xfs.BlockMappingStats{ + Reads: 1767055, + Writes: 188820, + Unmaps: 184891, + ExtentListInsertions: 92447, + ExtentListDeletions: 92448, + ExtentListLookups: 2140766, + ExtentListCompares: 0, + }, + BlockMapBTree: xfs.BTreeStats{ + Lookups: 0, + Compares: 0, + RecordsInserted: 0, + RecordsDeleted: 0, + }, + DirectoryOperation: xfs.DirectoryOperationStats{ + Lookups: 185039, + Creates: 92447, + Removes: 92444, + Getdents: 136422, + }, + Transaction: xfs.TransactionStats{ + Sync: 706, + Async: 944304, + Empty: 0, + }, + InodeOperation: xfs.InodeOperationStats{ + Attempts: 185045, + Found: 58807, + Recycle: 0, + Missed: 126238, + Duplicate: 0, + Reclaims: 33637, + AttributeChange: 22, + }, + LogOperation: xfs.LogOperationStats{ + Writes: 2883, + Blocks: 113448, + NoInternalBuffers: 9, + Force: 17360, + ForceSleep: 739, + }, + ReadWrite: xfs.ReadWriteStats{ + Read: 107739, + Write: 94045, + }, + AttributeOperation: xfs.AttributeOperationStats{ + Get: 4, + Set: 0, + Remove: 0, + List: 0, + }, + InodeClustering: xfs.InodeClusteringStats{ + Iflush: 8677, + Flush: 7849, + FlushInode: 135802, + }, + Vnode: xfs.VnodeStats{ + Active: 92601, + Allocate: 0, + Get: 0, + Hold: 0, + Release: 92444, + Reclaim: 92444, + Remove: 92444, + Free: 0, + }, + Buffer: xfs.BufferStats{ + Get: 2666287, + Create: 7122, + GetLocked: 2659202, + GetLockedWaited: 3599, + BusyLocked: 2, + MissLocked: 7085, + PageRetries: 0, + PageFound: 10297, + GetRead: 7085, + }, + ExtendedPrecision: xfs.ExtendedPrecisionStats{ + FlushBytes: 399724544, + WriteBytes: 92823103, + ReadBytes: 86219234, + }, + }, + }, + } + + for _, tt := range tests { + var ( + stats *xfs.Stats + err error + ) + + if tt.s != "" { + stats, err = xfs.ParseStats(strings.NewReader(tt.s)) + } + if tt.fs { + stats, err = procfs.FS("../fixtures").XFSStats() + } + + if tt.invalid && err == nil { + t.Error("expected an error, but none occurred") + } + if !tt.invalid && err != nil { + t.Errorf("unexpected error: %v", err) + } + + if want, have := tt.stats, stats; !reflect.DeepEqual(want, have) { + t.Errorf("unexpected XFS stats:\nwant:\n%v\nhave:\n%v", want, have) + } + } +} diff --git a/vendor/github.com/satori/go.uuid/.travis.yml b/vendor/github.com/satori/go.uuid/.travis.yml new file mode 100644 index 000000000..20dd53b8d --- /dev/null +++ b/vendor/github.com/satori/go.uuid/.travis.yml @@ -0,0 +1,23 @@ +language: go +sudo: false +go: + - 1.2 + - 1.3 + - 1.4 + - 1.5 + - 1.6 + - 1.7 + - 1.8 + - 1.9 + - tip +matrix: + allow_failures: + - go: tip + fast_finish: true +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -service=travis-ci +notifications: + email: false diff --git a/vendor/github.com/satori/go.uuid/README.md b/vendor/github.com/satori/go.uuid/README.md new file mode 100644 index 000000000..7b1a722df --- /dev/null +++ b/vendor/github.com/satori/go.uuid/README.md @@ -0,0 +1,65 @@ +# UUID package for Go language + +[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid) +[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid) +[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid) + +This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs. + +With 100% test coverage and benchmarks out of box. + +Supported versions: +* Version 1, based on timestamp and MAC address (RFC 4122) +* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1) +* Version 3, based on MD5 hashing (RFC 4122) +* Version 4, based on random numbers (RFC 4122) +* Version 5, based on SHA-1 hashing (RFC 4122) + +## Installation + +Use the `go` command: + + $ go get github.com/satori/go.uuid + +## Requirements + +UUID package requires Go >= 1.2. + +## Example + +```go +package main + +import ( + "fmt" + "github.com/satori/go.uuid" +) + +func main() { + // Creating UUID Version 4 + u1 := uuid.NewV4() + fmt.Printf("UUIDv4: %s\n", u1) + + // Parsing UUID from string input + u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + if err != nil { + fmt.Printf("Something gone wrong: %s", err) + } + fmt.Printf("Successfully parsed: %s", u2) +} +``` + +## Documentation + +[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project. + +## Links +* [RFC 4122](http://tools.ietf.org/html/rfc4122) +* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) + +## Copyright + +Copyright (C) 2013-2018 by Maxim Bublis . + +UUID package released under MIT License. +See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details. diff --git a/vendor/github.com/satori/go.uuid/codec_test.go b/vendor/github.com/satori/go.uuid/codec_test.go new file mode 100644 index 000000000..101ec521c --- /dev/null +++ b/vendor/github.com/satori/go.uuid/codec_test.go @@ -0,0 +1,248 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "bytes" + + . "gopkg.in/check.v1" +) + +type codecTestSuite struct{} + +var _ = Suite(&codecTestSuite{}) + +func (s *codecTestSuite) TestFromBytes(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + u1, err := FromBytes(b1) + c.Assert(err, IsNil) + c.Assert(u1, Equals, u) + + b2 := []byte{} + _, err = FromBytes(b2) + c.Assert(err, NotNil) +} + +func (s *codecTestSuite) BenchmarkFromBytes(c *C) { + bytes := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + for i := 0; i < c.N; i++ { + FromBytes(bytes) + } +} + +func (s *codecTestSuite) TestMarshalBinary(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + b2, err := u.MarshalBinary() + c.Assert(err, IsNil) + c.Assert(bytes.Equal(b1, b2), Equals, true) +} + +func (s *codecTestSuite) BenchmarkMarshalBinary(c *C) { + u := NewV4() + for i := 0; i < c.N; i++ { + u.MarshalBinary() + } +} + +func (s *codecTestSuite) TestUnmarshalBinary(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + u1 := UUID{} + err := u1.UnmarshalBinary(b1) + c.Assert(err, IsNil) + c.Assert(u1, Equals, u) + + b2 := []byte{} + u2 := UUID{} + err = u2.UnmarshalBinary(b2) + c.Assert(err, NotNil) +} + +func (s *codecTestSuite) TestFromString(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + s2 := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" + s3 := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" + s4 := "6ba7b8109dad11d180b400c04fd430c8" + s5 := "urn:uuid:6ba7b8109dad11d180b400c04fd430c8" + + _, err := FromString("") + c.Assert(err, NotNil) + + u1, err := FromString(s1) + c.Assert(err, IsNil) + c.Assert(u1, Equals, u) + + u2, err := FromString(s2) + c.Assert(err, IsNil) + c.Assert(u2, Equals, u) + + u3, err := FromString(s3) + c.Assert(err, IsNil) + c.Assert(u3, Equals, u) + + u4, err := FromString(s4) + c.Assert(err, IsNil) + c.Assert(u4, Equals, u) + + u5, err := FromString(s5) + c.Assert(err, IsNil) + c.Assert(u5, Equals, u) +} + +func (s *codecTestSuite) BenchmarkFromString(c *C) { + str := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + for i := 0; i < c.N; i++ { + FromString(str) + } +} + +func (s *codecTestSuite) BenchmarkFromStringUrn(c *C) { + str := "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" + for i := 0; i < c.N; i++ { + FromString(str) + } +} + +func (s *codecTestSuite) BenchmarkFromStringWithBrackets(c *C) { + str := "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}" + for i := 0; i < c.N; i++ { + FromString(str) + } +} + +func (s *codecTestSuite) TestFromStringShort(c *C) { + // Invalid 35-character UUID string + s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c" + + for i := len(s1); i >= 0; i-- { + _, err := FromString(s1[:i]) + c.Assert(err, NotNil) + } +} + +func (s *codecTestSuite) TestFromStringLong(c *C) { + // Invalid 37+ character UUID string + strings := []string{ + "6ba7b810-9dad-11d1-80b4-00c04fd430c8=", + "6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}f", + "6ba7b810-9dad-11d1-80b4-00c04fd430c800c04fd430c8", + } + + for _, str := range strings { + _, err := FromString(str) + c.Assert(err, NotNil) + } +} + +func (s *codecTestSuite) TestFromStringInvalid(c *C) { + // Invalid UUID string formats + strings := []string{ + "6ba7b8109dad11d180b400c04fd430c86ba7b8109dad11d180b400c04fd430c8", + "urn:uuid:{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + "uuid:urn:6ba7b810-9dad-11d1-80b4-00c04fd430c8", + "uuid:urn:6ba7b8109dad11d180b400c04fd430c8", + "6ba7b8109-dad-11d1-80b4-00c04fd430c8", + "6ba7b810-9dad1-1d1-80b4-00c04fd430c8", + "6ba7b810-9dad-11d18-0b4-00c04fd430c8", + "6ba7b810-9dad-11d1-80b40-0c04fd430c8", + "6ba7b810+9dad+11d1+80b4+00c04fd430c8", + "(6ba7b810-9dad-11d1-80b4-00c04fd430c8}", + "{6ba7b810-9dad-11d1-80b4-00c04fd430c8>", + "zba7b810-9dad-11d1-80b4-00c04fd430c8", + "6ba7b810-9dad11d180b400c04fd430c8", + "6ba7b8109dad-11d180b400c04fd430c8", + "6ba7b8109dad11d1-80b400c04fd430c8", + "6ba7b8109dad11d180b4-00c04fd430c8", + } + + for _, str := range strings { + _, err := FromString(str) + c.Assert(err, NotNil) + } +} + +func (s *codecTestSuite) TestFromStringOrNil(c *C) { + u := FromStringOrNil("") + c.Assert(u, Equals, Nil) +} + +func (s *codecTestSuite) TestFromBytesOrNil(c *C) { + b := []byte{} + u := FromBytesOrNil(b) + c.Assert(u, Equals, Nil) +} + +func (s *codecTestSuite) TestMarshalText(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + + b2, err := u.MarshalText() + c.Assert(err, IsNil) + c.Assert(bytes.Equal(b1, b2), Equals, true) +} + +func (s *codecTestSuite) BenchmarkMarshalText(c *C) { + u := NewV4() + for i := 0; i < c.N; i++ { + u.MarshalText() + } +} + +func (s *codecTestSuite) TestUnmarshalText(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + + u1 := UUID{} + err := u1.UnmarshalText(b1) + c.Assert(err, IsNil) + c.Assert(u1, Equals, u) + + b2 := []byte("") + u2 := UUID{} + err = u2.UnmarshalText(b2) + c.Assert(err, NotNil) +} + +func (s *codecTestSuite) BenchmarkUnmarshalText(c *C) { + bytes := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + u := UUID{} + for i := 0; i < c.N; i++ { + u.UnmarshalText(bytes) + } +} + +var sink string + +func (s *codecTestSuite) BenchmarkMarshalToString(c *C) { + u := NewV4() + for i := 0; i < c.N; i++ { + sink = u.String() + } +} diff --git a/vendor/github.com/satori/go.uuid/generator_test.go b/vendor/github.com/satori/go.uuid/generator_test.go new file mode 100644 index 000000000..cd69e2efb --- /dev/null +++ b/vendor/github.com/satori/go.uuid/generator_test.go @@ -0,0 +1,134 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + . "gopkg.in/check.v1" +) + +type genTestSuite struct{} + +var _ = Suite(&genTestSuite{}) + +func (s *genTestSuite) TestNewV1(c *C) { + u := NewV1() + c.Assert(u.Version(), Equals, V1) + c.Assert(u.Variant(), Equals, VariantRFC4122) + + u1 := NewV1() + u2 := NewV1() + c.Assert(u1, Not(Equals), u2) + + oldFunc := epochFunc + epochFunc = func() uint64 { return 0 } + + u3 := NewV1() + u4 := NewV1() + c.Assert(u3, Not(Equals), u4) + + epochFunc = oldFunc +} + +func (s *genTestSuite) BenchmarkNewV1(c *C) { + for i := 0; i < c.N; i++ { + NewV1() + } +} + +func (s *genTestSuite) TestNewV2(c *C) { + u1 := NewV2(DomainPerson) + c.Assert(u1.Version(), Equals, V2) + c.Assert(u1.Variant(), Equals, VariantRFC4122) + + u2 := NewV2(DomainGroup) + c.Assert(u2.Version(), Equals, V2) + c.Assert(u2.Variant(), Equals, VariantRFC4122) +} + +func (s *genTestSuite) BenchmarkNewV2(c *C) { + for i := 0; i < c.N; i++ { + NewV2(DomainPerson) + } +} + +func (s *genTestSuite) TestNewV3(c *C) { + u := NewV3(NamespaceDNS, "www.example.com") + c.Assert(u.Version(), Equals, V3) + c.Assert(u.Variant(), Equals, VariantRFC4122) + c.Assert(u.String(), Equals, "5df41881-3aed-3515-88a7-2f4a814cf09e") + + u = NewV3(NamespaceDNS, "python.org") + c.Assert(u.String(), Equals, "6fa459ea-ee8a-3ca4-894e-db77e160355e") + + u1 := NewV3(NamespaceDNS, "golang.org") + u2 := NewV3(NamespaceDNS, "golang.org") + c.Assert(u1, Equals, u2) + + u3 := NewV3(NamespaceDNS, "example.com") + c.Assert(u1, Not(Equals), u3) + + u4 := NewV3(NamespaceURL, "golang.org") + c.Assert(u1, Not(Equals), u4) +} + +func (s *genTestSuite) BenchmarkNewV3(c *C) { + for i := 0; i < c.N; i++ { + NewV3(NamespaceDNS, "www.example.com") + } +} + +func (s *genTestSuite) TestNewV4(c *C) { + u := NewV4() + c.Assert(u.Version(), Equals, V4) + c.Assert(u.Variant(), Equals, VariantRFC4122) +} + +func (s *genTestSuite) BenchmarkNewV4(c *C) { + for i := 0; i < c.N; i++ { + NewV4() + } +} + +func (s *genTestSuite) TestNewV5(c *C) { + u := NewV5(NamespaceDNS, "www.example.com") + c.Assert(u.Version(), Equals, V5) + c.Assert(u.Variant(), Equals, VariantRFC4122) + + u = NewV5(NamespaceDNS, "python.org") + c.Assert(u.String(), Equals, "886313e1-3b8a-5372-9b90-0c9aee199e5d") + + u1 := NewV5(NamespaceDNS, "golang.org") + u2 := NewV5(NamespaceDNS, "golang.org") + c.Assert(u1, Equals, u2) + + u3 := NewV5(NamespaceDNS, "example.com") + c.Assert(u1, Not(Equals), u3) + + u4 := NewV5(NamespaceURL, "golang.org") + c.Assert(u1, Not(Equals), u4) +} + +func (s *genTestSuite) BenchmarkNewV5(c *C) { + for i := 0; i < c.N; i++ { + NewV5(NamespaceDNS, "www.example.com") + } +} diff --git a/vendor/github.com/satori/go.uuid/sql_test.go b/vendor/github.com/satori/go.uuid/sql_test.go new file mode 100644 index 000000000..74255f50d --- /dev/null +++ b/vendor/github.com/satori/go.uuid/sql_test.go @@ -0,0 +1,136 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + . "gopkg.in/check.v1" +) + +type sqlTestSuite struct{} + +var _ = Suite(&sqlTestSuite{}) + +func (s *sqlTestSuite) TestValue(c *C) { + u, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + c.Assert(err, IsNil) + + val, err := u.Value() + c.Assert(err, IsNil) + c.Assert(val, Equals, u.String()) +} + +func (s *sqlTestSuite) TestValueNil(c *C) { + u := UUID{} + + val, err := u.Value() + c.Assert(err, IsNil) + c.Assert(val, Equals, Nil.String()) +} + +func (s *sqlTestSuite) TestNullUUIDValueNil(c *C) { + u := NullUUID{} + + val, err := u.Value() + c.Assert(err, IsNil) + c.Assert(val, IsNil) +} + +func (s *sqlTestSuite) TestScanBinary(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + u1 := UUID{} + err := u1.Scan(b1) + c.Assert(err, IsNil) + c.Assert(u, Equals, u1) + + b2 := []byte{} + u2 := UUID{} + + err = u2.Scan(b2) + c.Assert(err, NotNil) +} + +func (s *sqlTestSuite) TestScanString(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + + u1 := UUID{} + err := u1.Scan(s1) + c.Assert(err, IsNil) + c.Assert(u, Equals, u1) + + s2 := "" + u2 := UUID{} + + err = u2.Scan(s2) + c.Assert(err, NotNil) +} + +func (s *sqlTestSuite) TestScanText(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") + + u1 := UUID{} + err := u1.Scan(b1) + c.Assert(err, IsNil) + c.Assert(u, Equals, u1) + + b2 := []byte("") + u2 := UUID{} + err = u2.Scan(b2) + c.Assert(err, NotNil) +} + +func (s *sqlTestSuite) TestScanUnsupported(c *C) { + u := UUID{} + + err := u.Scan(true) + c.Assert(err, NotNil) +} + +func (s *sqlTestSuite) TestScanNil(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + err := u.Scan(nil) + c.Assert(err, NotNil) +} + +func (s *sqlTestSuite) TestNullUUIDScanValid(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + + u1 := NullUUID{} + err := u1.Scan(s1) + c.Assert(err, IsNil) + c.Assert(u1.Valid, Equals, true) + c.Assert(u1.UUID, Equals, u) +} + +func (s *sqlTestSuite) TestNullUUIDScanNil(c *C) { + u := NullUUID{UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}, true} + + err := u.Scan(nil) + c.Assert(err, IsNil) + c.Assert(u.Valid, Equals, false) + c.Assert(u.UUID, Equals, Nil) +} diff --git a/vendor/github.com/satori/go.uuid/uuid_test.go b/vendor/github.com/satori/go.uuid/uuid_test.go new file mode 100644 index 000000000..beb336d57 --- /dev/null +++ b/vendor/github.com/satori/go.uuid/uuid_test.go @@ -0,0 +1,90 @@ +// Copyright (C) 2013-2018 by Maxim Bublis +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package uuid + +import ( + "bytes" + "testing" + + . "gopkg.in/check.v1" +) + +// Hook up gocheck into the "go test" runner. +func TestUUID(t *testing.T) { TestingT(t) } + +type testSuite struct{} + +var _ = Suite(&testSuite{}) + +func (s *testSuite) TestBytes(c *C) { + u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + bytes1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} + + c.Assert(bytes.Equal(u.Bytes(), bytes1), Equals, true) +} + +func (s *testSuite) TestString(c *C) { + c.Assert(NamespaceDNS.String(), Equals, "6ba7b810-9dad-11d1-80b4-00c04fd430c8") +} + +func (s *testSuite) TestEqual(c *C) { + c.Assert(Equal(NamespaceDNS, NamespaceDNS), Equals, true) + c.Assert(Equal(NamespaceDNS, NamespaceURL), Equals, false) +} + +func (s *testSuite) TestVersion(c *C) { + u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + c.Assert(u.Version(), Equals, V1) +} + +func (s *testSuite) TestSetVersion(c *C) { + u := UUID{} + u.SetVersion(4) + c.Assert(u.Version(), Equals, V4) +} + +func (s *testSuite) TestVariant(c *C) { + u1 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + c.Assert(u1.Variant(), Equals, VariantNCS) + + u2 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + c.Assert(u2.Variant(), Equals, VariantRFC4122) + + u3 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + c.Assert(u3.Variant(), Equals, VariantMicrosoft) + + u4 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + c.Assert(u4.Variant(), Equals, VariantFuture) +} + +func (s *testSuite) TestSetVariant(c *C) { + u := UUID{} + u.SetVariant(VariantNCS) + c.Assert(u.Variant(), Equals, VariantNCS) + u.SetVariant(VariantRFC4122) + c.Assert(u.Variant(), Equals, VariantRFC4122) + u.SetVariant(VariantMicrosoft) + c.Assert(u.Variant(), Equals, VariantMicrosoft) + u.SetVariant(VariantFuture) + c.Assert(u.Variant(), Equals, VariantFuture) +} diff --git a/vendor/github.com/spf13/pflag/.gitignore b/vendor/github.com/spf13/pflag/.gitignore new file mode 100644 index 000000000..c3da29013 --- /dev/null +++ b/vendor/github.com/spf13/pflag/.gitignore @@ -0,0 +1,2 @@ +.idea/* + diff --git a/vendor/github.com/spf13/pflag/.travis.yml b/vendor/github.com/spf13/pflag/.travis.yml new file mode 100644 index 000000000..f8a63b308 --- /dev/null +++ b/vendor/github.com/spf13/pflag/.travis.yml @@ -0,0 +1,21 @@ +sudo: false + +language: go + +go: + - 1.7.3 + - 1.8.1 + - tip + +matrix: + allow_failures: + - go: tip + +install: + - go get github.com/golang/lint/golint + - export PATH=$GOPATH/bin:$PATH + - go install ./... + +script: + - verify/all.sh -v + - go test ./... diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md new file mode 100644 index 000000000..b052414d1 --- /dev/null +++ b/vendor/github.com/spf13/pflag/README.md @@ -0,0 +1,296 @@ +[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag) +[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag) +[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag) + +## Description + +pflag is a drop-in replacement for Go's flag package, implementing +POSIX/GNU-style --flags. + +pflag is compatible with the [GNU extensions to the POSIX recommendations +for command-line options][1]. For a more precise description, see the +"Command-line flag syntax" section below. + +[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + +pflag is available under the same style of BSD license as the Go language, +which can be found in the LICENSE file. + +## Installation + +pflag is available using the standard `go get` command. + +Install by running: + + go get github.com/spf13/pflag + +Run tests by running: + + go test github.com/spf13/pflag + +## Usage + +pflag is a drop-in replacement of Go's native flag package. If you import +pflag under the name "flag" then all code should continue to function +with no changes. + +``` go +import flag "github.com/spf13/pflag" +``` + +There is one exception to this: if you directly instantiate the Flag struct +there is one more field "Shorthand" that you will need to set. +Most code never instantiates this struct directly, and instead uses +functions such as String(), BoolVar(), and Var(), and is therefore +unaffected. + +Define flags using flag.String(), Bool(), Int(), etc. + +This declares an integer flag, -flagname, stored in the pointer ip, with type *int. + +``` go +var ip *int = flag.Int("flagname", 1234, "help message for flagname") +``` + +If you like, you can bind the flag to a variable using the Var() functions. + +``` go +var flagvar int +func init() { + flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") +} +``` + +Or you can create custom flags that satisfy the Value interface (with +pointer receivers) and couple them to flag parsing by + +``` go +flag.Var(&flagVal, "name", "help message for flagname") +``` + +For such flags, the default value is just the initial value of the variable. + +After all flags are defined, call + +``` go +flag.Parse() +``` + +to parse the command line into the defined flags. + +Flags may then be used directly. If you're using the flags themselves, +they are all pointers; if you bind to variables, they're values. + +``` go +fmt.Println("ip has value ", *ip) +fmt.Println("flagvar has value ", flagvar) +``` + +There are helpers function to get values later if you have the FlagSet but +it was difficult to keep up with all of the flag pointers in your code. +If you have a pflag.FlagSet with a flag called 'flagname' of type int you +can use GetInt() to get the int value. But notice that 'flagname' must exist +and it must be an int. GetString("flagname") will fail. + +``` go +i, err := flagset.GetInt("flagname") +``` + +After parsing, the arguments after the flag are available as the +slice flag.Args() or individually as flag.Arg(i). +The arguments are indexed from 0 through flag.NArg()-1. + +The pflag package also defines some new functions that are not in flag, +that give one-letter shorthands for flags. You can use these by appending +'P' to the name of any function that defines a flag. + +``` go +var ip = flag.IntP("flagname", "f", 1234, "help message") +var flagvar bool +func init() { + flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") +} +flag.VarP(&flagVal, "varname", "v", "help message") +``` + +Shorthand letters can be used with single dashes on the command line. +Boolean shorthand flags can be combined with other shorthand flags. + +The default set of command-line flags is controlled by +top-level functions. The FlagSet type allows one to define +independent sets of flags, such as to implement subcommands +in a command-line interface. The methods of FlagSet are +analogous to the top-level functions for the command-line +flag set. + +## Setting no option default values for flags + +After you create a flag it is possible to set the pflag.NoOptDefVal for +the given flag. Doing this changes the meaning of the flag slightly. If +a flag has a NoOptDefVal and the flag is set on the command line without +an option the flag will be set to the NoOptDefVal. For example given: + +``` go +var ip = flag.IntP("flagname", "f", 1234, "help message") +flag.Lookup("flagname").NoOptDefVal = "4321" +``` + +Would result in something like + +| Parsed Arguments | Resulting Value | +| ------------- | ------------- | +| --flagname=1357 | ip=1357 | +| --flagname | ip=4321 | +| [nothing] | ip=1234 | + +## Command line flag syntax + +``` +--flag // boolean flags, or flags with no option default values +--flag x // only on flags without a default value +--flag=x +``` + +Unlike the flag package, a single dash before an option means something +different than a double dash. Single dashes signify a series of shorthand +letters for flags. All but the last shorthand letter must be boolean flags +or a flag with a default value + +``` +// boolean or flags where the 'no option default value' is set +-f +-f=true +-abc +but +-b true is INVALID + +// non-boolean and flags without a 'no option default value' +-n 1234 +-n=1234 +-n1234 + +// mixed +-abcs "hello" +-absd="hello" +-abcs1234 +``` + +Flag parsing stops after the terminator "--". Unlike the flag package, +flags can be interspersed with arguments anywhere on the command line +before this terminator. + +Integer flags accept 1234, 0664, 0x1234 and may be negative. +Boolean flags (in their long form) accept 1, 0, t, f, true, false, +TRUE, FALSE, True, False. +Duration flags accept any input valid for time.ParseDuration. + +## Mutating or "Normalizing" Flag names + +It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow. + +**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag + +``` go +func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + from := []string{"-", "_"} + to := "." + for _, sep := range from { + name = strings.Replace(name, sep, to, -1) + } + return pflag.NormalizedName(name) +} + +myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc) +``` + +**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name + +``` go +func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + switch name { + case "old-flag-name": + name = "new-flag-name" + break + } + return pflag.NormalizedName(name) +} + +myFlagSet.SetNormalizeFunc(aliasNormalizeFunc) +``` + +## Deprecating a flag or its shorthand +It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used. + +**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead. +```go +// deprecate a flag by specifying its name and a usage message +flags.MarkDeprecated("badflag", "please use --good-flag instead") +``` +This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used. + +**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n". +```go +// deprecate a flag shorthand by specifying its flag name and a usage message +flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only") +``` +This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used. + +Note that usage message is essential here, and it should not be empty. + +## Hidden flags +It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text. + +**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available. +```go +// hide a flag by specifying its name +flags.MarkHidden("secretFlag") +``` + +## Disable sorting of flags +`pflag` allows you to disable sorting of flags for help and usage message. + +**Example**: +```go +flags.BoolP("verbose", "v", false, "verbose output") +flags.String("coolflag", "yeaah", "it's really cool flag") +flags.Int("usefulflag", 777, "sometimes it's very useful") +flags.SortFlags = false +flags.PrintDefaults() +``` +**Output**: +``` + -v, --verbose verbose output + --coolflag string it's really cool flag (default "yeaah") + --usefulflag int sometimes it's very useful (default 777) +``` + + +## Supporting Go flags when using pflag +In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary +to support flags defined by third-party dependencies (e.g. `golang/glog`). + +**Example**: You want to add the Go flags to the `CommandLine` flagset +```go +import ( + goflag "flag" + flag "github.com/spf13/pflag" +) + +var ip *int = flag.Int("flagname", 1234, "help message for flagname") + +func main() { + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) + flag.Parse() +} +``` + +## More info + +You can see the full reference documentation of the pflag package +[at godoc.org][3], or through go's standard documentation system by +running `godoc -http=:6060` and browsing to +[http://localhost:6060/pkg/github.com/spf13/pflag][2] after +installation. + +[2]: http://localhost:6060/pkg/github.com/spf13/pflag +[3]: http://godoc.org/github.com/spf13/pflag diff --git a/vendor/github.com/spf13/pflag/bool_slice_test.go b/vendor/github.com/spf13/pflag/bool_slice_test.go new file mode 100644 index 000000000..b617dd237 --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool_slice_test.go @@ -0,0 +1,215 @@ +package pflag + +import ( + "fmt" + "strconv" + "strings" + "testing" +) + +func setUpBSFlagSet(bsp *[]bool) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.BoolSliceVar(bsp, "bs", []bool{}, "Command separated list!") + return f +} + +func setUpBSFlagSetWithDefault(bsp *[]bool) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.BoolSliceVar(bsp, "bs", []bool{false, true}, "Command separated list!") + return f +} + +func TestEmptyBS(t *testing.T) { + var bs []bool + f := setUpBSFlagSet(&bs) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getBS, err := f.GetBoolSlice("bs") + if err != nil { + t.Fatal("got an error from GetBoolSlice():", err) + } + if len(getBS) != 0 { + t.Fatalf("got bs %v with len=%d but expected length=0", getBS, len(getBS)) + } +} + +func TestBS(t *testing.T) { + var bs []bool + f := setUpBSFlagSet(&bs) + + vals := []string{"1", "F", "TRUE", "0"} + arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range bs { + b, err := strconv.ParseBool(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if b != v { + t.Fatalf("expected is[%d] to be %s but got: %t", i, vals[i], v) + } + } + getBS, err := f.GetBoolSlice("bs") + if err != nil { + t.Fatalf("got error: %v", err) + } + for i, v := range getBS { + b, err := strconv.ParseBool(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if b != v { + t.Fatalf("expected bs[%d] to be %s but got: %t from GetBoolSlice", i, vals[i], v) + } + } +} + +func TestBSDefault(t *testing.T) { + var bs []bool + f := setUpBSFlagSetWithDefault(&bs) + + vals := []string{"false", "T"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range bs { + b, err := strconv.ParseBool(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if b != v { + t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) + } + } + + getBS, err := f.GetBoolSlice("bs") + if err != nil { + t.Fatal("got an error from GetBoolSlice():", err) + } + for i, v := range getBS { + b, err := strconv.ParseBool(vals[i]) + if err != nil { + t.Fatal("got an error from GetBoolSlice():", err) + } + if b != v { + t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) + } + } +} + +func TestBSWithDefault(t *testing.T) { + var bs []bool + f := setUpBSFlagSetWithDefault(&bs) + + vals := []string{"FALSE", "1"} + arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range bs { + b, err := strconv.ParseBool(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if b != v { + t.Fatalf("expected bs[%d] to be %t but got: %t", i, b, v) + } + } + + getBS, err := f.GetBoolSlice("bs") + if err != nil { + t.Fatal("got an error from GetBoolSlice():", err) + } + for i, v := range getBS { + b, err := strconv.ParseBool(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if b != v { + t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) + } + } +} + +func TestBSCalledTwice(t *testing.T) { + var bs []bool + f := setUpBSFlagSet(&bs) + + in := []string{"T,F", "T"} + expected := []bool{true, false, true} + argfmt := "--bs=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range bs { + if expected[i] != v { + t.Fatalf("expected bs[%d] to be %t but got %t", i, expected[i], v) + } + } +} + +func TestBSBadQuoting(t *testing.T) { + + tests := []struct { + Want []bool + FlagArg []string + }{ + { + Want: []bool{true, false, true}, + FlagArg: []string{"1", "0", "true"}, + }, + { + Want: []bool{true, false}, + FlagArg: []string{"True", "F"}, + }, + { + Want: []bool{true, false}, + FlagArg: []string{"T", "0"}, + }, + { + Want: []bool{true, false}, + FlagArg: []string{"1", "0"}, + }, + { + Want: []bool{true, false, false}, + FlagArg: []string{"true,false", "false"}, + }, + { + Want: []bool{true, false, false, true, false, true, false}, + FlagArg: []string{`"true,false,false,1,0, T"`, " false "}, + }, + { + Want: []bool{false, false, true, false, true, false, true}, + FlagArg: []string{`"0, False, T,false , true,F"`, "true"}, + }, + } + + for i, test := range tests { + + var bs []bool + f := setUpBSFlagSet(&bs) + + if err := f.Parse([]string{fmt.Sprintf("--bs=%s", strings.Join(test.FlagArg, ","))}); err != nil { + t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%#v", + err, test.FlagArg, test.Want[i]) + } + + for j, b := range bs { + if b != test.Want[j] { + t.Fatalf("bad value parsed for test %d on bool %d:\nwant:\t%t\ngot:\t%t", i, j, test.Want[j], b) + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/bool_test.go b/vendor/github.com/spf13/pflag/bool_test.go new file mode 100644 index 000000000..a4319e79f --- /dev/null +++ b/vendor/github.com/spf13/pflag/bool_test.go @@ -0,0 +1,179 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "bytes" + "strconv" + "testing" +) + +// This value can be a boolean ("true", "false") or "maybe" +type triStateValue int + +const ( + triStateFalse triStateValue = 0 + triStateTrue triStateValue = 1 + triStateMaybe triStateValue = 2 +) + +const strTriStateMaybe = "maybe" + +func (v *triStateValue) IsBoolFlag() bool { + return true +} + +func (v *triStateValue) Get() interface{} { + return triStateValue(*v) +} + +func (v *triStateValue) Set(s string) error { + if s == strTriStateMaybe { + *v = triStateMaybe + return nil + } + boolVal, err := strconv.ParseBool(s) + if boolVal { + *v = triStateTrue + } else { + *v = triStateFalse + } + return err +} + +func (v *triStateValue) String() string { + if *v == triStateMaybe { + return strTriStateMaybe + } + return strconv.FormatBool(*v == triStateTrue) +} + +// The type of the flag as required by the pflag.Value interface +func (v *triStateValue) Type() string { + return "version" +} + +func setUpFlagSet(tristate *triStateValue) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + *tristate = triStateFalse + flag := f.VarPF(tristate, "tristate", "t", "tristate value (true, maybe or false)") + flag.NoOptDefVal = "true" + return f +} + +func TestExplicitTrue(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + err := f.Parse([]string{"--tristate=true"}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateTrue { + t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") + } +} + +func TestImplicitTrue(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + err := f.Parse([]string{"--tristate"}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateTrue { + t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") + } +} + +func TestShortFlag(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + err := f.Parse([]string{"-t"}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateTrue { + t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") + } +} + +func TestShortFlagExtraArgument(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + // The"maybe"turns into an arg, since short boolean options will only do true/false + err := f.Parse([]string{"-t", "maybe"}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateTrue { + t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") + } + args := f.Args() + if len(args) != 1 || args[0] != "maybe" { + t.Fatal("expected an extra 'maybe' argument to stick around") + } +} + +func TestExplicitMaybe(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + err := f.Parse([]string{"--tristate=maybe"}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateMaybe { + t.Fatal("expected", triStateMaybe, "(triStateMaybe) but got", tristate, "instead") + } +} + +func TestExplicitFalse(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + err := f.Parse([]string{"--tristate=false"}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateFalse { + t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead") + } +} + +func TestImplicitFalse(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + if tristate != triStateFalse { + t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead") + } +} + +func TestInvalidValue(t *testing.T) { + var tristate triStateValue + f := setUpFlagSet(&tristate) + var buf bytes.Buffer + f.SetOutput(&buf) + err := f.Parse([]string{"--tristate=invalid"}) + if err == nil { + t.Fatal("expected an error but did not get any, tristate has value", tristate) + } +} + +func TestBoolP(t *testing.T) { + b := BoolP("bool", "b", false, "bool value in CommandLine") + c := BoolP("c", "c", false, "other bool value") + args := []string{"--bool"} + if err := CommandLine.Parse(args); err != nil { + t.Error("expected no error, got ", err) + } + if *b != true { + t.Errorf("expected b=true got b=%v", *b) + } + if *c != false { + t.Errorf("expect c=false got c=%v", *c) + } +} diff --git a/vendor/github.com/spf13/pflag/bytes_test.go b/vendor/github.com/spf13/pflag/bytes_test.go new file mode 100644 index 000000000..cc4a769d9 --- /dev/null +++ b/vendor/github.com/spf13/pflag/bytes_test.go @@ -0,0 +1,72 @@ +package pflag + +import ( + "fmt" + "os" + "testing" +) + +func setUpBytesHex(bytesHex *[]byte) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.BytesHexVar(bytesHex, "bytes", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in HEX") + f.BytesHexVarP(bytesHex, "bytes2", "B", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in HEX") + return f +} + +func TestBytesHex(t *testing.T) { + testCases := []struct { + input string + success bool + expected string + }{ + /// Positive cases + {"", true, ""}, // Is empty string OK ? + {"01", true, "01"}, + {"0101", true, "0101"}, + {"1234567890abcdef", true, "1234567890ABCDEF"}, + {"1234567890ABCDEF", true, "1234567890ABCDEF"}, + + // Negative cases + {"0", false, ""}, // Short string + {"000", false, ""}, /// Odd-length string + {"qq", false, ""}, /// non-hex character + } + + devnull, _ := os.Open(os.DevNull) + os.Stderr = devnull + + for i := range testCases { + var bytesHex []byte + f := setUpBytesHex(&bytesHex) + + tc := &testCases[i] + + // --bytes + args := []string{ + fmt.Sprintf("--bytes=%s", tc.input), + fmt.Sprintf("-B %s", tc.input), + fmt.Sprintf("--bytes2=%s", tc.input), + } + + for _, arg := range args { + err := f.Parse([]string{arg}) + + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + // bytesHex, err := f.GetBytesHex("bytes") + t.Errorf("expected failure while processing %q", tc.input) + continue + } else if tc.success { + bytesHex, err := f.GetBytesHex("bytes") + if err != nil { + t.Errorf("Got error trying to fetch the IP flag: %v", err) + } + if fmt.Sprintf("%X", bytesHex) != tc.expected { + t.Errorf("expected %q, got '%X'", tc.expected, bytesHex) + } + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/count_test.go b/vendor/github.com/spf13/pflag/count_test.go new file mode 100644 index 000000000..3785d375a --- /dev/null +++ b/vendor/github.com/spf13/pflag/count_test.go @@ -0,0 +1,56 @@ +package pflag + +import ( + "os" + "testing" +) + +func setUpCount(c *int) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.CountVarP(c, "verbose", "v", "a counter") + return f +} + +func TestCount(t *testing.T) { + testCases := []struct { + input []string + success bool + expected int + }{ + {[]string{}, true, 0}, + {[]string{"-v"}, true, 1}, + {[]string{"-vvv"}, true, 3}, + {[]string{"-v", "-v", "-v"}, true, 3}, + {[]string{"-v", "--verbose", "-v"}, true, 3}, + {[]string{"-v=3", "-v"}, true, 4}, + {[]string{"--verbose=0"}, true, 0}, + {[]string{"-v=0"}, true, 0}, + {[]string{"-v=a"}, false, 0}, + } + + devnull, _ := os.Open(os.DevNull) + os.Stderr = devnull + for i := range testCases { + var count int + f := setUpCount(&count) + + tc := &testCases[i] + + err := f.Parse(tc.input) + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + t.Errorf("expected failure, got success") + continue + } else if tc.success { + c, err := f.GetCount("verbose") + if err != nil { + t.Errorf("Got error trying to fetch the counter flag") + } + if c != tc.expected { + t.Errorf("expected %d, got %d", tc.expected, c) + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/duration_slice_test.go b/vendor/github.com/spf13/pflag/duration_slice_test.go new file mode 100644 index 000000000..489b012ff --- /dev/null +++ b/vendor/github.com/spf13/pflag/duration_slice_test.go @@ -0,0 +1,165 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code ds governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "fmt" + "strings" + "testing" + "time" +) + +func setUpDSFlagSet(dsp *[]time.Duration) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.DurationSliceVar(dsp, "ds", []time.Duration{}, "Command separated list!") + return f +} + +func setUpDSFlagSetWithDefault(dsp *[]time.Duration) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.DurationSliceVar(dsp, "ds", []time.Duration{0, 1}, "Command separated list!") + return f +} + +func TestEmptyDS(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSet(&ds) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + if len(getDS) != 0 { + t.Fatalf("got ds %v with len=%d but expected length=0", getDS, len(getDS)) + } +} + +func TestDS(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSet(&ds) + + vals := []string{"1ns", "2ms", "3m", "4h"} + arg := fmt.Sprintf("--ds=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %s but got: %d", i, vals[i], v) + } + } + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatalf("got error: %v", err) + } + for i, v := range getDS { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %s but got: %d from GetDurationSlice", i, vals[i], v) + } + } +} + +func TestDSDefault(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSetWithDefault(&ds) + + vals := []string{"0s", "1ns"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d but got: %d", i, d, v) + } + } + + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + for i, v := range getDS { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d from GetDurationSlice but got: %d", i, d, v) + } + } +} + +func TestDSWithDefault(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSetWithDefault(&ds) + + vals := []string{"1ns", "2ns"} + arg := fmt.Sprintf("--ds=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d but got: %d", i, d, v) + } + } + + getDS, err := f.GetDurationSlice("ds") + if err != nil { + t.Fatal("got an error from GetDurationSlice():", err) + } + for i, v := range getDS { + d, err := time.ParseDuration(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected ds[%d] to be %d from GetDurationSlice but got: %d", i, d, v) + } + } +} + +func TestDSCalledTwice(t *testing.T) { + var ds []time.Duration + f := setUpDSFlagSet(&ds) + + in := []string{"1ns,2ns", "3ns"} + expected := []time.Duration{1, 2, 3} + argfmt := "--ds=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ds { + if expected[i] != v { + t.Fatalf("expected ds[%d] to be %d but got: %d", i, expected[i], v) + } + } +} diff --git a/vendor/github.com/spf13/pflag/example_test.go b/vendor/github.com/spf13/pflag/example_test.go new file mode 100644 index 000000000..abd7806fa --- /dev/null +++ b/vendor/github.com/spf13/pflag/example_test.go @@ -0,0 +1,36 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag_test + +import ( + "fmt" + + "github.com/spf13/pflag" +) + +func ExampleShorthandLookup() { + name := "verbose" + short := name[:1] + + pflag.BoolP(name, short, false, "verbose output") + + // len(short) must be == 1 + flag := pflag.ShorthandLookup(short) + + fmt.Println(flag.Name) +} + +func ExampleFlagSet_ShorthandLookup() { + name := "verbose" + short := name[:1] + + fs := pflag.NewFlagSet("Example", pflag.ContinueOnError) + fs.BoolP(name, short, false, "verbose output") + + // len(short) must be == 1 + flag := fs.ShorthandLookup(short) + + fmt.Println(flag.Name) +} diff --git a/vendor/github.com/spf13/pflag/export_test.go b/vendor/github.com/spf13/pflag/export_test.go new file mode 100644 index 000000000..9318fee00 --- /dev/null +++ b/vendor/github.com/spf13/pflag/export_test.go @@ -0,0 +1,29 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "io/ioutil" + "os" +) + +// Additional routines compiled into the package only during testing. + +// ResetForTesting clears all flag state and sets the usage function as directed. +// After calling ResetForTesting, parse errors in flag handling will not +// exit the program. +func ResetForTesting(usage func()) { + CommandLine = &FlagSet{ + name: os.Args[0], + errorHandling: ContinueOnError, + output: ioutil.Discard, + } + Usage = usage +} + +// GetCommandLine returns the default FlagSet. +func GetCommandLine() *FlagSet { + return CommandLine +} diff --git a/vendor/github.com/spf13/pflag/flag_test.go b/vendor/github.com/spf13/pflag/flag_test.go new file mode 100644 index 000000000..f600f0aeb --- /dev/null +++ b/vendor/github.com/spf13/pflag/flag_test.go @@ -0,0 +1,1259 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "reflect" + "sort" + "strconv" + "strings" + "testing" + "time" +) + +var ( + testBool = Bool("test_bool", false, "bool value") + testInt = Int("test_int", 0, "int value") + testInt64 = Int64("test_int64", 0, "int64 value") + testUint = Uint("test_uint", 0, "uint value") + testUint64 = Uint64("test_uint64", 0, "uint64 value") + testString = String("test_string", "0", "string value") + testFloat = Float64("test_float64", 0, "float64 value") + testDuration = Duration("test_duration", 0, "time.Duration value") + testOptionalInt = Int("test_optional_int", 0, "optional int value") + normalizeFlagNameInvocations = 0 +) + +func boolString(s string) string { + if s == "0" { + return "false" + } + return "true" +} + +func TestEverything(t *testing.T) { + m := make(map[string]*Flag) + desired := "0" + visitor := func(f *Flag) { + if len(f.Name) > 5 && f.Name[0:5] == "test_" { + m[f.Name] = f + ok := false + switch { + case f.Value.String() == desired: + ok = true + case f.Name == "test_bool" && f.Value.String() == boolString(desired): + ok = true + case f.Name == "test_duration" && f.Value.String() == desired+"s": + ok = true + } + if !ok { + t.Error("Visit: bad value", f.Value.String(), "for", f.Name) + } + } + } + VisitAll(visitor) + if len(m) != 9 { + t.Error("VisitAll misses some flags") + for k, v := range m { + t.Log(k, *v) + } + } + m = make(map[string]*Flag) + Visit(visitor) + if len(m) != 0 { + t.Errorf("Visit sees unset flags") + for k, v := range m { + t.Log(k, *v) + } + } + // Now set all flags + Set("test_bool", "true") + Set("test_int", "1") + Set("test_int64", "1") + Set("test_uint", "1") + Set("test_uint64", "1") + Set("test_string", "1") + Set("test_float64", "1") + Set("test_duration", "1s") + Set("test_optional_int", "1") + desired = "1" + Visit(visitor) + if len(m) != 9 { + t.Error("Visit fails after set") + for k, v := range m { + t.Log(k, *v) + } + } + // Now test they're visited in sort order. + var flagNames []string + Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) }) + if !sort.StringsAreSorted(flagNames) { + t.Errorf("flag names not sorted: %v", flagNames) + } +} + +func TestUsage(t *testing.T) { + called := false + ResetForTesting(func() { called = true }) + if GetCommandLine().Parse([]string{"--x"}) == nil { + t.Error("parse did not fail for unknown flag") + } + if called { + t.Error("did call Usage while using ContinueOnError") + } +} + +func TestAddFlagSet(t *testing.T) { + oldSet := NewFlagSet("old", ContinueOnError) + newSet := NewFlagSet("new", ContinueOnError) + + oldSet.String("flag1", "flag1", "flag1") + oldSet.String("flag2", "flag2", "flag2") + + newSet.String("flag2", "flag2", "flag2") + newSet.String("flag3", "flag3", "flag3") + + oldSet.AddFlagSet(newSet) + + if len(oldSet.formal) != 3 { + t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet) + } +} + +func TestAnnotation(t *testing.T) { + f := NewFlagSet("shorthand", ContinueOnError) + + if err := f.SetAnnotation("missing-flag", "key", nil); err == nil { + t.Errorf("Expected error setting annotation on non-existent flag") + } + + f.StringP("stringa", "a", "", "string value") + if err := f.SetAnnotation("stringa", "key", nil); err != nil { + t.Errorf("Unexpected error setting new nil annotation: %v", err) + } + if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil { + t.Errorf("Unexpected annotation: %v", annotation) + } + + f.StringP("stringb", "b", "", "string2 value") + if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil { + t.Errorf("Unexpected error setting new annotation: %v", err) + } + if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) { + t.Errorf("Unexpected annotation: %v", annotation) + } + + if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil { + t.Errorf("Unexpected error updating annotation: %v", err) + } + if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) { + t.Errorf("Unexpected annotation: %v", annotation) + } +} + +func testParse(f *FlagSet, t *testing.T) { + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + boolFlag := f.Bool("bool", false, "bool value") + bool2Flag := f.Bool("bool2", false, "bool2 value") + bool3Flag := f.Bool("bool3", false, "bool3 value") + intFlag := f.Int("int", 0, "int value") + int8Flag := f.Int8("int8", 0, "int value") + int16Flag := f.Int16("int16", 0, "int value") + int32Flag := f.Int32("int32", 0, "int value") + int64Flag := f.Int64("int64", 0, "int64 value") + uintFlag := f.Uint("uint", 0, "uint value") + uint8Flag := f.Uint8("uint8", 0, "uint value") + uint16Flag := f.Uint16("uint16", 0, "uint value") + uint32Flag := f.Uint32("uint32", 0, "uint value") + uint64Flag := f.Uint64("uint64", 0, "uint64 value") + stringFlag := f.String("string", "0", "string value") + float32Flag := f.Float32("float32", 0, "float32 value") + float64Flag := f.Float64("float64", 0, "float64 value") + ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value") + maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value") + durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value") + optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value") + f.Lookup("optional-int-no-value").NoOptDefVal = "9" + optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value") + f.Lookup("optional-int-no-value").NoOptDefVal = "9" + extra := "one-extra-argument" + args := []string{ + "--bool", + "--bool2=true", + "--bool3=false", + "--int=22", + "--int8=-8", + "--int16=-16", + "--int32=-32", + "--int64=0x23", + "--uint", "24", + "--uint8=8", + "--uint16=16", + "--uint32=32", + "--uint64=25", + "--string=hello", + "--float32=-172e12", + "--float64=2718e28", + "--ip=10.11.12.13", + "--mask=255.255.255.0", + "--duration=2m", + "--optional-int-no-value", + "--optional-int-with-value=42", + extra, + } + if err := f.Parse(args); err != nil { + t.Fatal(err) + } + if !f.Parsed() { + t.Error("f.Parse() = false after Parse") + } + if *boolFlag != true { + t.Error("bool flag should be true, is ", *boolFlag) + } + if v, err := f.GetBool("bool"); err != nil || v != *boolFlag { + t.Error("GetBool does not work.") + } + if *bool2Flag != true { + t.Error("bool2 flag should be true, is ", *bool2Flag) + } + if *bool3Flag != false { + t.Error("bool3 flag should be false, is ", *bool2Flag) + } + if *intFlag != 22 { + t.Error("int flag should be 22, is ", *intFlag) + } + if v, err := f.GetInt("int"); err != nil || v != *intFlag { + t.Error("GetInt does not work.") + } + if *int8Flag != -8 { + t.Error("int8 flag should be 0x23, is ", *int8Flag) + } + if *int16Flag != -16 { + t.Error("int16 flag should be -16, is ", *int16Flag) + } + if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag { + t.Error("GetInt8 does not work.") + } + if v, err := f.GetInt16("int16"); err != nil || v != *int16Flag { + t.Error("GetInt16 does not work.") + } + if *int32Flag != -32 { + t.Error("int32 flag should be 0x23, is ", *int32Flag) + } + if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag { + t.Error("GetInt32 does not work.") + } + if *int64Flag != 0x23 { + t.Error("int64 flag should be 0x23, is ", *int64Flag) + } + if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag { + t.Error("GetInt64 does not work.") + } + if *uintFlag != 24 { + t.Error("uint flag should be 24, is ", *uintFlag) + } + if v, err := f.GetUint("uint"); err != nil || v != *uintFlag { + t.Error("GetUint does not work.") + } + if *uint8Flag != 8 { + t.Error("uint8 flag should be 8, is ", *uint8Flag) + } + if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag { + t.Error("GetUint8 does not work.") + } + if *uint16Flag != 16 { + t.Error("uint16 flag should be 16, is ", *uint16Flag) + } + if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag { + t.Error("GetUint16 does not work.") + } + if *uint32Flag != 32 { + t.Error("uint32 flag should be 32, is ", *uint32Flag) + } + if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag { + t.Error("GetUint32 does not work.") + } + if *uint64Flag != 25 { + t.Error("uint64 flag should be 25, is ", *uint64Flag) + } + if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag { + t.Error("GetUint64 does not work.") + } + if *stringFlag != "hello" { + t.Error("string flag should be `hello`, is ", *stringFlag) + } + if v, err := f.GetString("string"); err != nil || v != *stringFlag { + t.Error("GetString does not work.") + } + if *float32Flag != -172e12 { + t.Error("float32 flag should be -172e12, is ", *float32Flag) + } + if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag { + t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag) + } + if *float64Flag != 2718e28 { + t.Error("float64 flag should be 2718e28, is ", *float64Flag) + } + if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag { + t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag) + } + if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) { + t.Error("ip flag should be 10.11.12.13, is ", *ipFlag) + } + if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) { + t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag) + } + if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() { + t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String()) + } + if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() { + t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err) + } + if *durationFlag != 2*time.Minute { + t.Error("duration flag should be 2m, is ", *durationFlag) + } + if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag { + t.Error("GetDuration does not work.") + } + if _, err := f.GetInt("duration"); err == nil { + t.Error("GetInt parsed a time.Duration?!?!") + } + if *optionalIntNoValueFlag != 9 { + t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag) + } + if *optionalIntWithValueFlag != 42 { + t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag) + } + if len(f.Args()) != 1 { + t.Error("expected one argument, got", len(f.Args())) + } else if f.Args()[0] != extra { + t.Errorf("expected argument %q got %q", extra, f.Args()[0]) + } +} + +func testParseAll(f *FlagSet, t *testing.T) { + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + f.BoolP("boola", "a", false, "bool value") + f.BoolP("boolb", "b", false, "bool2 value") + f.BoolP("boolc", "c", false, "bool3 value") + f.BoolP("boold", "d", false, "bool4 value") + f.StringP("stringa", "s", "0", "string value") + f.StringP("stringz", "z", "0", "string value") + f.StringP("stringx", "x", "0", "string value") + f.StringP("stringy", "y", "0", "string value") + f.Lookup("stringx").NoOptDefVal = "1" + args := []string{ + "-ab", + "-cs=xx", + "--stringz=something", + "-d=true", + "-x", + "-y", + "ee", + } + want := []string{ + "boola", "true", + "boolb", "true", + "boolc", "true", + "stringa", "xx", + "stringz", "something", + "boold", "true", + "stringx", "1", + "stringy", "ee", + } + got := []string{} + store := func(flag *Flag, value string) error { + got = append(got, flag.Name) + if len(value) > 0 { + got = append(got, value) + } + return nil + } + if err := f.ParseAll(args, store); err != nil { + t.Errorf("expected no error, got %s", err) + } + if !f.Parsed() { + t.Errorf("f.Parse() = false after Parse") + } + if !reflect.DeepEqual(got, want) { + t.Errorf("f.ParseAll() fail to restore the args") + t.Errorf("Got: %v", got) + t.Errorf("Want: %v", want) + } +} + +func testParseWithUnknownFlags(f *FlagSet, t *testing.T) { + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + f.ParseErrorsWhitelist.UnknownFlags = true + + f.BoolP("boola", "a", false, "bool value") + f.BoolP("boolb", "b", false, "bool2 value") + f.BoolP("boolc", "c", false, "bool3 value") + f.BoolP("boold", "d", false, "bool4 value") + f.BoolP("boole", "e", false, "bool4 value") + f.StringP("stringa", "s", "0", "string value") + f.StringP("stringz", "z", "0", "string value") + f.StringP("stringx", "x", "0", "string value") + f.StringP("stringy", "y", "0", "string value") + f.StringP("stringo", "o", "0", "string value") + f.Lookup("stringx").NoOptDefVal = "1" + args := []string{ + "-ab", + "-cs=xx", + "--stringz=something", + "--unknown1", + "unknown1Value", + "-d=true", + "-x", + "--unknown2=unknown2Value", + "-u=unknown3Value", + "-p", + "unknown4Value", + "-q", //another unknown with bool value + "-y", + "ee", + "--unknown7=unknown7value", + "--stringo=ovalue", + "--unknown8=unknown8value", + "--boole", + "--unknown6", + } + want := []string{ + "boola", "true", + "boolb", "true", + "boolc", "true", + "stringa", "xx", + "stringz", "something", + "boold", "true", + "stringx", "1", + "stringy", "ee", + "stringo", "ovalue", + "boole", "true", + } + got := []string{} + store := func(flag *Flag, value string) error { + got = append(got, flag.Name) + if len(value) > 0 { + got = append(got, value) + } + return nil + } + if err := f.ParseAll(args, store); err != nil { + t.Errorf("expected no error, got %s", err) + } + if !f.Parsed() { + t.Errorf("f.Parse() = false after Parse") + } + if !reflect.DeepEqual(got, want) { + t.Errorf("f.ParseAll() fail to restore the args") + t.Errorf("Got: %v", got) + t.Errorf("Want: %v", want) + } +} + +func TestShorthand(t *testing.T) { + f := NewFlagSet("shorthand", ContinueOnError) + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + boolaFlag := f.BoolP("boola", "a", false, "bool value") + boolbFlag := f.BoolP("boolb", "b", false, "bool2 value") + boolcFlag := f.BoolP("boolc", "c", false, "bool3 value") + booldFlag := f.BoolP("boold", "d", false, "bool4 value") + stringaFlag := f.StringP("stringa", "s", "0", "string value") + stringzFlag := f.StringP("stringz", "z", "0", "string value") + extra := "interspersed-argument" + notaflag := "--i-look-like-a-flag" + args := []string{ + "-ab", + extra, + "-cs", + "hello", + "-z=something", + "-d=true", + "--", + notaflag, + } + f.SetOutput(ioutil.Discard) + if err := f.Parse(args); err != nil { + t.Error("expected no error, got ", err) + } + if !f.Parsed() { + t.Error("f.Parse() = false after Parse") + } + if *boolaFlag != true { + t.Error("boola flag should be true, is ", *boolaFlag) + } + if *boolbFlag != true { + t.Error("boolb flag should be true, is ", *boolbFlag) + } + if *boolcFlag != true { + t.Error("boolc flag should be true, is ", *boolcFlag) + } + if *booldFlag != true { + t.Error("boold flag should be true, is ", *booldFlag) + } + if *stringaFlag != "hello" { + t.Error("stringa flag should be `hello`, is ", *stringaFlag) + } + if *stringzFlag != "something" { + t.Error("stringz flag should be `something`, is ", *stringzFlag) + } + if len(f.Args()) != 2 { + t.Error("expected one argument, got", len(f.Args())) + } else if f.Args()[0] != extra { + t.Errorf("expected argument %q got %q", extra, f.Args()[0]) + } else if f.Args()[1] != notaflag { + t.Errorf("expected argument %q got %q", notaflag, f.Args()[1]) + } + if f.ArgsLenAtDash() != 1 { + t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1) + } +} + +func TestShorthandLookup(t *testing.T) { + f := NewFlagSet("shorthand", ContinueOnError) + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + f.BoolP("boola", "a", false, "bool value") + f.BoolP("boolb", "b", false, "bool2 value") + args := []string{ + "-ab", + } + f.SetOutput(ioutil.Discard) + if err := f.Parse(args); err != nil { + t.Error("expected no error, got ", err) + } + if !f.Parsed() { + t.Error("f.Parse() = false after Parse") + } + flag := f.ShorthandLookup("a") + if flag == nil { + t.Errorf("f.ShorthandLookup(\"a\") returned nil") + } + if flag.Name != "boola" { + t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name) + } + flag = f.ShorthandLookup("") + if flag != nil { + t.Errorf("f.ShorthandLookup(\"\") did not return nil") + } + defer func() { + recover() + }() + flag = f.ShorthandLookup("ab") + // should NEVER get here. lookup should panic. defer'd func should recover it. + t.Errorf("f.ShorthandLookup(\"ab\") did not panic") +} + +func TestParse(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + testParse(GetCommandLine(), t) +} + +func TestParseAll(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + testParseAll(GetCommandLine(), t) +} + +func TestIgnoreUnknownFlags(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + testParseWithUnknownFlags(GetCommandLine(), t) +} + +func TestFlagSetParse(t *testing.T) { + testParse(NewFlagSet("test", ContinueOnError), t) +} + +func TestChangedHelper(t *testing.T) { + f := NewFlagSet("changedtest", ContinueOnError) + f.Bool("changed", false, "changed bool") + f.Bool("settrue", true, "true to true") + f.Bool("setfalse", false, "false to false") + f.Bool("unchanged", false, "unchanged bool") + + args := []string{"--changed", "--settrue", "--setfalse=false"} + if err := f.Parse(args); err != nil { + t.Error("f.Parse() = false after Parse") + } + if !f.Changed("changed") { + t.Errorf("--changed wasn't changed!") + } + if !f.Changed("settrue") { + t.Errorf("--settrue wasn't changed!") + } + if !f.Changed("setfalse") { + t.Errorf("--setfalse wasn't changed!") + } + if f.Changed("unchanged") { + t.Errorf("--unchanged was changed!") + } + if f.Changed("invalid") { + t.Errorf("--invalid was changed!") + } + if f.ArgsLenAtDash() != -1 { + t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash()) + } +} + +func replaceSeparators(name string, from []string, to string) string { + result := name + for _, sep := range from { + result = strings.Replace(result, sep, to, -1) + } + // Type convert to indicate normalization has been done. + return result +} + +func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName { + seps := []string{"-", "_"} + name = replaceSeparators(name, seps, ".") + normalizeFlagNameInvocations++ + + return NormalizedName(name) +} + +func testWordSepNormalizedNames(args []string, t *testing.T) { + f := NewFlagSet("normalized", ContinueOnError) + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + withDashFlag := f.Bool("with-dash-flag", false, "bool value") + // Set this after some flags have been added and before others. + f.SetNormalizeFunc(wordSepNormalizeFunc) + withUnderFlag := f.Bool("with_under_flag", false, "bool value") + withBothFlag := f.Bool("with-both_flag", false, "bool value") + if err := f.Parse(args); err != nil { + t.Fatal(err) + } + if !f.Parsed() { + t.Error("f.Parse() = false after Parse") + } + if *withDashFlag != true { + t.Error("withDashFlag flag should be true, is ", *withDashFlag) + } + if *withUnderFlag != true { + t.Error("withUnderFlag flag should be true, is ", *withUnderFlag) + } + if *withBothFlag != true { + t.Error("withBothFlag flag should be true, is ", *withBothFlag) + } +} + +func TestWordSepNormalizedNames(t *testing.T) { + args := []string{ + "--with-dash-flag", + "--with-under-flag", + "--with-both-flag", + } + testWordSepNormalizedNames(args, t) + + args = []string{ + "--with_dash_flag", + "--with_under_flag", + "--with_both_flag", + } + testWordSepNormalizedNames(args, t) + + args = []string{ + "--with-dash_flag", + "--with-under_flag", + "--with-both_flag", + } + testWordSepNormalizedNames(args, t) +} + +func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName { + seps := []string{"-", "_"} + + oldName := replaceSeparators("old-valid_flag", seps, ".") + newName := replaceSeparators("valid-flag", seps, ".") + + name = replaceSeparators(name, seps, ".") + switch name { + case oldName: + name = newName + } + + return NormalizedName(name) +} + +func TestCustomNormalizedNames(t *testing.T) { + f := NewFlagSet("normalized", ContinueOnError) + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + + validFlag := f.Bool("valid-flag", false, "bool value") + f.SetNormalizeFunc(aliasAndWordSepFlagNames) + someOtherFlag := f.Bool("some-other-flag", false, "bool value") + + args := []string{"--old_valid_flag", "--some-other_flag"} + if err := f.Parse(args); err != nil { + t.Fatal(err) + } + + if *validFlag != true { + t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag) + } + if *someOtherFlag != true { + t.Error("someOtherFlag should be true, is ", *someOtherFlag) + } +} + +// Every flag we add, the name (displayed also in usage) should normalized +func TestNormalizationFuncShouldChangeFlagName(t *testing.T) { + // Test normalization after addition + f := NewFlagSet("normalized", ContinueOnError) + + f.Bool("valid_flag", false, "bool value") + if f.Lookup("valid_flag").Name != "valid_flag" { + t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name) + } + + f.SetNormalizeFunc(wordSepNormalizeFunc) + if f.Lookup("valid_flag").Name != "valid.flag" { + t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name) + } + + // Test normalization before addition + f = NewFlagSet("normalized", ContinueOnError) + f.SetNormalizeFunc(wordSepNormalizeFunc) + + f.Bool("valid_flag", false, "bool value") + if f.Lookup("valid_flag").Name != "valid.flag" { + t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name) + } +} + +// Related to https://github.com/spf13/cobra/issues/521. +func TestNormalizationSharedFlags(t *testing.T) { + f := NewFlagSet("set f", ContinueOnError) + g := NewFlagSet("set g", ContinueOnError) + nfunc := wordSepNormalizeFunc + testName := "valid_flag" + normName := nfunc(nil, testName) + if testName == string(normName) { + t.Error("TestNormalizationSharedFlags meaningless: the original and normalized flag names are identical:", testName) + } + + f.Bool(testName, false, "bool value") + g.AddFlagSet(f) + + f.SetNormalizeFunc(nfunc) + g.SetNormalizeFunc(nfunc) + + if len(f.formal) != 1 { + t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal) + } + if f.orderedFormal[0].Name != string(normName) { + t.Error("Flag name not normalized") + } + for k := range f.formal { + if k != "valid.flag" { + t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k) + } + } + + if !reflect.DeepEqual(f.formal, g.formal) || !reflect.DeepEqual(f.orderedFormal, g.orderedFormal) { + t.Error("Two flag sets sharing the same flags should stay consistent after being normalized. Original set:", f.formal, "Duplicate set:", g.formal) + } +} + +func TestNormalizationSetFlags(t *testing.T) { + f := NewFlagSet("normalized", ContinueOnError) + nfunc := wordSepNormalizeFunc + testName := "valid_flag" + normName := nfunc(nil, testName) + if testName == string(normName) { + t.Error("TestNormalizationSetFlags meaningless: the original and normalized flag names are identical:", testName) + } + + f.Bool(testName, false, "bool value") + f.Set(testName, "true") + f.SetNormalizeFunc(nfunc) + + if len(f.formal) != 1 { + t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal) + } + if f.orderedFormal[0].Name != string(normName) { + t.Error("Flag name not normalized") + } + for k := range f.formal { + if k != "valid.flag" { + t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k) + } + } + + if !reflect.DeepEqual(f.formal, f.actual) { + t.Error("The map of set flags should get normalized. Formal:", f.formal, "Actual:", f.actual) + } +} + +// Declare a user-defined flag type. +type flagVar []string + +func (f *flagVar) String() string { + return fmt.Sprint([]string(*f)) +} + +func (f *flagVar) Set(value string) error { + *f = append(*f, value) + return nil +} + +func (f *flagVar) Type() string { + return "flagVar" +} + +func TestUserDefined(t *testing.T) { + var flags FlagSet + flags.Init("test", ContinueOnError) + var v flagVar + flags.VarP(&v, "v", "v", "usage") + if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil { + t.Error(err) + } + if len(v) != 3 { + t.Fatal("expected 3 args; got ", len(v)) + } + expect := "[1 2 3]" + if v.String() != expect { + t.Errorf("expected value %q got %q", expect, v.String()) + } +} + +func TestSetOutput(t *testing.T) { + var flags FlagSet + var buf bytes.Buffer + flags.SetOutput(&buf) + flags.Init("test", ContinueOnError) + flags.Parse([]string{"--unknown"}) + if out := buf.String(); !strings.Contains(out, "--unknown") { + t.Logf("expected output mentioning unknown; got %q", out) + } +} + +// This tests that one can reset the flags. This still works but not well, and is +// superseded by FlagSet. +func TestChangingArgs(t *testing.T) { + ResetForTesting(func() { t.Fatal("bad parse") }) + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + os.Args = []string{"cmd", "--before", "subcmd"} + before := Bool("before", false, "") + if err := GetCommandLine().Parse(os.Args[1:]); err != nil { + t.Fatal(err) + } + cmd := Arg(0) + os.Args = []string{"subcmd", "--after", "args"} + after := Bool("after", false, "") + Parse() + args := Args() + + if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" { + t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args) + } +} + +// Test that -help invokes the usage message and returns ErrHelp. +func TestHelp(t *testing.T) { + var helpCalled = false + fs := NewFlagSet("help test", ContinueOnError) + fs.Usage = func() { helpCalled = true } + var flag bool + fs.BoolVar(&flag, "flag", false, "regular flag") + // Regular flag invocation should work + err := fs.Parse([]string{"--flag=true"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + if !flag { + t.Error("flag was not set by --flag") + } + if helpCalled { + t.Error("help called for regular flag") + helpCalled = false // reset for next test + } + // Help flag should work as expected. + err = fs.Parse([]string{"--help"}) + if err == nil { + t.Fatal("error expected") + } + if err != ErrHelp { + t.Fatal("expected ErrHelp; got ", err) + } + if !helpCalled { + t.Fatal("help was not called") + } + // If we define a help flag, that should override. + var help bool + fs.BoolVar(&help, "help", false, "help flag") + helpCalled = false + err = fs.Parse([]string{"--help"}) + if err != nil { + t.Fatal("expected no error for defined --help; got ", err) + } + if helpCalled { + t.Fatal("help was called; should not have been for defined help flag") + } +} + +func TestNoInterspersed(t *testing.T) { + f := NewFlagSet("test", ContinueOnError) + f.SetInterspersed(false) + f.Bool("true", true, "always true") + f.Bool("false", false, "always false") + err := f.Parse([]string{"--true", "break", "--false"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + args := f.Args() + if len(args) != 2 || args[0] != "break" || args[1] != "--false" { + t.Fatal("expected interspersed options/non-options to fail") + } +} + +func TestTermination(t *testing.T) { + f := NewFlagSet("termination", ContinueOnError) + boolFlag := f.BoolP("bool", "l", false, "bool value") + if f.Parsed() { + t.Error("f.Parse() = true before Parse") + } + arg1 := "ls" + arg2 := "-l" + args := []string{ + "--", + arg1, + arg2, + } + f.SetOutput(ioutil.Discard) + if err := f.Parse(args); err != nil { + t.Fatal("expected no error; got ", err) + } + if !f.Parsed() { + t.Error("f.Parse() = false after Parse") + } + if *boolFlag { + t.Error("expected boolFlag=false, got true") + } + if len(f.Args()) != 2 { + t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args()) + } + if f.Args()[0] != arg1 { + t.Errorf("expected argument %q got %q", arg1, f.Args()[0]) + } + if f.Args()[1] != arg2 { + t.Errorf("expected argument %q got %q", arg2, f.Args()[1]) + } + if f.ArgsLenAtDash() != 0 { + t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash()) + } +} + +func getDeprecatedFlagSet() *FlagSet { + f := NewFlagSet("bob", ContinueOnError) + f.Bool("badflag", true, "always true") + f.MarkDeprecated("badflag", "use --good-flag instead") + return f +} +func TestDeprecatedFlagInDocs(t *testing.T) { + f := getDeprecatedFlagSet() + + out := new(bytes.Buffer) + f.SetOutput(out) + f.PrintDefaults() + + if strings.Contains(out.String(), "badflag") { + t.Errorf("found deprecated flag in usage!") + } +} + +func TestUnHiddenDeprecatedFlagInDocs(t *testing.T) { + f := getDeprecatedFlagSet() + flg := f.Lookup("badflag") + if flg == nil { + t.Fatalf("Unable to lookup 'bob' in TestUnHiddenDeprecatedFlagInDocs") + } + flg.Hidden = false + + out := new(bytes.Buffer) + f.SetOutput(out) + f.PrintDefaults() + + defaults := out.String() + if !strings.Contains(defaults, "badflag") { + t.Errorf("Did not find deprecated flag in usage!") + } + if !strings.Contains(defaults, "use --good-flag instead") { + t.Errorf("Did not find 'use --good-flag instead' in defaults") + } +} + +func TestDeprecatedFlagShorthandInDocs(t *testing.T) { + f := NewFlagSet("bob", ContinueOnError) + name := "noshorthandflag" + f.BoolP(name, "n", true, "always true") + f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name)) + + out := new(bytes.Buffer) + f.SetOutput(out) + f.PrintDefaults() + + if strings.Contains(out.String(), "-n,") { + t.Errorf("found deprecated flag shorthand in usage!") + } +} + +func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) { + oldStderr := os.Stderr + r, w, _ := os.Pipe() + os.Stderr = w + + err := f.Parse(args) + + outC := make(chan string) + // copy the output in a separate goroutine so printing can't block indefinitely + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + w.Close() + os.Stderr = oldStderr + out := <-outC + + return out, err +} + +func TestDeprecatedFlagUsage(t *testing.T) { + f := NewFlagSet("bob", ContinueOnError) + f.Bool("badflag", true, "always true") + usageMsg := "use --good-flag instead" + f.MarkDeprecated("badflag", usageMsg) + + args := []string{"--badflag"} + out, err := parseReturnStderr(t, f, args) + if err != nil { + t.Fatal("expected no error; got ", err) + } + + if !strings.Contains(out, usageMsg) { + t.Errorf("usageMsg not printed when using a deprecated flag!") + } +} + +func TestDeprecatedFlagShorthandUsage(t *testing.T) { + f := NewFlagSet("bob", ContinueOnError) + name := "noshorthandflag" + f.BoolP(name, "n", true, "always true") + usageMsg := fmt.Sprintf("use --%s instead", name) + f.MarkShorthandDeprecated(name, usageMsg) + + args := []string{"-n"} + out, err := parseReturnStderr(t, f, args) + if err != nil { + t.Fatal("expected no error; got ", err) + } + + if !strings.Contains(out, usageMsg) { + t.Errorf("usageMsg not printed when using a deprecated flag!") + } +} + +func TestDeprecatedFlagUsageNormalized(t *testing.T) { + f := NewFlagSet("bob", ContinueOnError) + f.Bool("bad-double_flag", true, "always true") + f.SetNormalizeFunc(wordSepNormalizeFunc) + usageMsg := "use --good-flag instead" + f.MarkDeprecated("bad_double-flag", usageMsg) + + args := []string{"--bad_double_flag"} + out, err := parseReturnStderr(t, f, args) + if err != nil { + t.Fatal("expected no error; got ", err) + } + + if !strings.Contains(out, usageMsg) { + t.Errorf("usageMsg not printed when using a deprecated flag!") + } +} + +// Name normalization function should be called only once on flag addition +func TestMultipleNormalizeFlagNameInvocations(t *testing.T) { + normalizeFlagNameInvocations = 0 + + f := NewFlagSet("normalized", ContinueOnError) + f.SetNormalizeFunc(wordSepNormalizeFunc) + f.Bool("with_under_flag", false, "bool value") + + if normalizeFlagNameInvocations != 1 { + t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations) + } +} + +// +func TestHiddenFlagInUsage(t *testing.T) { + f := NewFlagSet("bob", ContinueOnError) + f.Bool("secretFlag", true, "shhh") + f.MarkHidden("secretFlag") + + out := new(bytes.Buffer) + f.SetOutput(out) + f.PrintDefaults() + + if strings.Contains(out.String(), "secretFlag") { + t.Errorf("found hidden flag in usage!") + } +} + +// +func TestHiddenFlagUsage(t *testing.T) { + f := NewFlagSet("bob", ContinueOnError) + f.Bool("secretFlag", true, "shhh") + f.MarkHidden("secretFlag") + + args := []string{"--secretFlag"} + out, err := parseReturnStderr(t, f, args) + if err != nil { + t.Fatal("expected no error; got ", err) + } + + if strings.Contains(out, "shhh") { + t.Errorf("usage message printed when using a hidden flag!") + } +} + +const defaultOutput = ` --A for bootstrapping, allow 'any' type + --Alongflagname disable bounds checking + -C, --CCC a boolean defaulting to true (default true) + --D path set relative path for local imports + -E, --EEE num[=1234] a num with NoOptDefVal (default 4321) + --F number a non-zero number (default 2.7) + --G float a float that defaults to zero + --IP ip IP address with no default + --IPMask ipMask Netmask address with no default + --IPNet ipNet IP network with no default + --Ints ints int slice with zero default + --N int a non-zero int (default 27) + --ND1 string[="bar"] a string with NoOptDefVal (default "foo") + --ND2 num[=4321] a num with NoOptDefVal (default 1234) + --StringArray stringArray string array with zero default + --StringSlice strings string slice with zero default + --Z int an int that defaults to zero + --custom custom custom Value implementation + --customP custom a VarP with default (default 10) + --maxT timeout set timeout for dial + -v, --verbose count verbosity +` + +// Custom value that satisfies the Value interface. +type customValue int + +func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) } + +func (cv *customValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *cv = customValue(v) + return err +} + +func (cv *customValue) Type() string { return "custom" } + +func TestPrintDefaults(t *testing.T) { + fs := NewFlagSet("print defaults test", ContinueOnError) + var buf bytes.Buffer + fs.SetOutput(&buf) + fs.Bool("A", false, "for bootstrapping, allow 'any' type") + fs.Bool("Alongflagname", false, "disable bounds checking") + fs.BoolP("CCC", "C", true, "a boolean defaulting to true") + fs.String("D", "", "set relative `path` for local imports") + fs.Float64("F", 2.7, "a non-zero `number`") + fs.Float64("G", 0, "a float that defaults to zero") + fs.Int("N", 27, "a non-zero int") + fs.IntSlice("Ints", []int{}, "int slice with zero default") + fs.IP("IP", nil, "IP address with no default") + fs.IPMask("IPMask", nil, "Netmask address with no default") + fs.IPNet("IPNet", net.IPNet{}, "IP network with no default") + fs.Int("Z", 0, "an int that defaults to zero") + fs.Duration("maxT", 0, "set `timeout` for dial") + fs.String("ND1", "foo", "a string with NoOptDefVal") + fs.Lookup("ND1").NoOptDefVal = "bar" + fs.Int("ND2", 1234, "a `num` with NoOptDefVal") + fs.Lookup("ND2").NoOptDefVal = "4321" + fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal") + fs.ShorthandLookup("E").NoOptDefVal = "1234" + fs.StringSlice("StringSlice", []string{}, "string slice with zero default") + fs.StringArray("StringArray", []string{}, "string array with zero default") + fs.CountP("verbose", "v", "verbosity") + + var cv customValue + fs.Var(&cv, "custom", "custom Value implementation") + + cv2 := customValue(10) + fs.VarP(&cv2, "customP", "", "a VarP with default") + + fs.PrintDefaults() + got := buf.String() + if got != defaultOutput { + fmt.Println("\n" + got) + fmt.Println("\n" + defaultOutput) + t.Errorf("got %q want %q\n", got, defaultOutput) + } +} + +func TestVisitAllFlagOrder(t *testing.T) { + fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError) + fs.SortFlags = false + // https://github.com/spf13/pflag/issues/120 + fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName { + return NormalizedName(name) + }) + + names := []string{"C", "B", "A", "D"} + for _, name := range names { + fs.Bool(name, false, "") + } + + i := 0 + fs.VisitAll(func(f *Flag) { + if names[i] != f.Name { + t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) + } + i++ + }) +} + +func TestVisitFlagOrder(t *testing.T) { + fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError) + fs.SortFlags = false + names := []string{"C", "B", "A", "D"} + for _, name := range names { + fs.Bool(name, false, "") + fs.Set(name, "true") + } + + i := 0 + fs.Visit(func(f *Flag) { + if names[i] != f.Name { + t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) + } + i++ + }) +} diff --git a/vendor/github.com/spf13/pflag/golangflag_test.go b/vendor/github.com/spf13/pflag/golangflag_test.go new file mode 100644 index 000000000..5bd831bf9 --- /dev/null +++ b/vendor/github.com/spf13/pflag/golangflag_test.go @@ -0,0 +1,47 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + goflag "flag" + "testing" +) + +func TestGoflags(t *testing.T) { + goflag.String("stringFlag", "stringFlag", "stringFlag") + goflag.Bool("boolFlag", false, "boolFlag") + + f := NewFlagSet("test", ContinueOnError) + + f.AddGoFlagSet(goflag.CommandLine) + err := f.Parse([]string{"--stringFlag=bob", "--boolFlag"}) + if err != nil { + t.Fatal("expected no error; get", err) + } + + getString, err := f.GetString("stringFlag") + if err != nil { + t.Fatal("expected no error; get", err) + } + if getString != "bob" { + t.Fatalf("expected getString=bob but got getString=%s", getString) + } + + getBool, err := f.GetBool("boolFlag") + if err != nil { + t.Fatal("expected no error; get", err) + } + if getBool != true { + t.Fatalf("expected getBool=true but got getBool=%v", getBool) + } + if !f.Parsed() { + t.Fatal("f.Parsed() return false after f.Parse() called") + } + + // in fact it is useless. because `go test` called flag.Parse() + if !goflag.CommandLine.Parsed() { + t.Fatal("goflag.CommandLine.Parsed() return false after f.Parse() called") + } +} diff --git a/vendor/github.com/spf13/pflag/int_slice_test.go b/vendor/github.com/spf13/pflag/int_slice_test.go new file mode 100644 index 000000000..745aecb95 --- /dev/null +++ b/vendor/github.com/spf13/pflag/int_slice_test.go @@ -0,0 +1,165 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "fmt" + "strconv" + "strings" + "testing" +) + +func setUpISFlagSet(isp *[]int) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.IntSliceVar(isp, "is", []int{}, "Command separated list!") + return f +} + +func setUpISFlagSetWithDefault(isp *[]int) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.IntSliceVar(isp, "is", []int{0, 1}, "Command separated list!") + return f +} + +func TestEmptyIS(t *testing.T) { + var is []int + f := setUpISFlagSet(&is) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getIS, err := f.GetIntSlice("is") + if err != nil { + t.Fatal("got an error from GetIntSlice():", err) + } + if len(getIS) != 0 { + t.Fatalf("got is %v with len=%d but expected length=0", getIS, len(getIS)) + } +} + +func TestIS(t *testing.T) { + var is []int + f := setUpISFlagSet(&is) + + vals := []string{"1", "2", "4", "3"} + arg := fmt.Sprintf("--is=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range is { + d, err := strconv.Atoi(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected is[%d] to be %s but got: %d", i, vals[i], v) + } + } + getIS, err := f.GetIntSlice("is") + if err != nil { + t.Fatalf("got error: %v", err) + } + for i, v := range getIS { + d, err := strconv.Atoi(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected is[%d] to be %s but got: %d from GetIntSlice", i, vals[i], v) + } + } +} + +func TestISDefault(t *testing.T) { + var is []int + f := setUpISFlagSetWithDefault(&is) + + vals := []string{"0", "1"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range is { + d, err := strconv.Atoi(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v) + } + } + + getIS, err := f.GetIntSlice("is") + if err != nil { + t.Fatal("got an error from GetIntSlice():", err) + } + for i, v := range getIS { + d, err := strconv.Atoi(vals[i]) + if err != nil { + t.Fatal("got an error from GetIntSlice():", err) + } + if d != v { + t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v) + } + } +} + +func TestISWithDefault(t *testing.T) { + var is []int + f := setUpISFlagSetWithDefault(&is) + + vals := []string{"1", "2"} + arg := fmt.Sprintf("--is=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range is { + d, err := strconv.Atoi(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v) + } + } + + getIS, err := f.GetIntSlice("is") + if err != nil { + t.Fatal("got an error from GetIntSlice():", err) + } + for i, v := range getIS { + d, err := strconv.Atoi(vals[i]) + if err != nil { + t.Fatalf("got error: %v", err) + } + if d != v { + t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v) + } + } +} + +func TestISCalledTwice(t *testing.T) { + var is []int + f := setUpISFlagSet(&is) + + in := []string{"1,2", "3"} + expected := []int{1, 2, 3} + argfmt := "--is=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range is { + if expected[i] != v { + t.Fatalf("expected is[%d] to be %d but got: %d", i, expected[i], v) + } + } +} diff --git a/vendor/github.com/spf13/pflag/ip_slice_test.go b/vendor/github.com/spf13/pflag/ip_slice_test.go new file mode 100644 index 000000000..b0c681c5b --- /dev/null +++ b/vendor/github.com/spf13/pflag/ip_slice_test.go @@ -0,0 +1,222 @@ +package pflag + +import ( + "fmt" + "net" + "strings" + "testing" +) + +func setUpIPSFlagSet(ipsp *[]net.IP) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.IPSliceVar(ipsp, "ips", []net.IP{}, "Command separated list!") + return f +} + +func setUpIPSFlagSetWithDefault(ipsp *[]net.IP) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.IPSliceVar(ipsp, "ips", + []net.IP{ + net.ParseIP("192.168.1.1"), + net.ParseIP("0:0:0:0:0:0:0:1"), + }, + "Command separated list!") + return f +} + +func TestEmptyIP(t *testing.T) { + var ips []net.IP + f := setUpIPSFlagSet(&ips) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getIPS, err := f.GetIPSlice("ips") + if err != nil { + t.Fatal("got an error from GetIPSlice():", err) + } + if len(getIPS) != 0 { + t.Fatalf("got ips %v with len=%d but expected length=0", getIPS, len(getIPS)) + } +} + +func TestIPS(t *testing.T) { + var ips []net.IP + f := setUpIPSFlagSet(&ips) + + vals := []string{"192.168.1.1", "10.0.0.1", "0:0:0:0:0:0:0:2"} + arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ips { + if ip := net.ParseIP(vals[i]); ip == nil { + t.Fatalf("invalid string being converted to IP address: %s", vals[i]) + } else if !ip.Equal(v) { + t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v) + } + } +} + +func TestIPSDefault(t *testing.T) { + var ips []net.IP + f := setUpIPSFlagSetWithDefault(&ips) + + vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"} + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ips { + if ip := net.ParseIP(vals[i]); ip == nil { + t.Fatalf("invalid string being converted to IP address: %s", vals[i]) + } else if !ip.Equal(v) { + t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) + } + } + + getIPS, err := f.GetIPSlice("ips") + if err != nil { + t.Fatal("got an error from GetIPSlice") + } + for i, v := range getIPS { + if ip := net.ParseIP(vals[i]); ip == nil { + t.Fatalf("invalid string being converted to IP address: %s", vals[i]) + } else if !ip.Equal(v) { + t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) + } + } +} + +func TestIPSWithDefault(t *testing.T) { + var ips []net.IP + f := setUpIPSFlagSetWithDefault(&ips) + + vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"} + arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ips { + if ip := net.ParseIP(vals[i]); ip == nil { + t.Fatalf("invalid string being converted to IP address: %s", vals[i]) + } else if !ip.Equal(v) { + t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) + } + } + + getIPS, err := f.GetIPSlice("ips") + if err != nil { + t.Fatal("got an error from GetIPSlice") + } + for i, v := range getIPS { + if ip := net.ParseIP(vals[i]); ip == nil { + t.Fatalf("invalid string being converted to IP address: %s", vals[i]) + } else if !ip.Equal(v) { + t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) + } + } +} + +func TestIPSCalledTwice(t *testing.T) { + var ips []net.IP + f := setUpIPSFlagSet(&ips) + + in := []string{"192.168.1.2,0:0:0:0:0:0:0:1", "10.0.0.1"} + expected := []net.IP{net.ParseIP("192.168.1.2"), net.ParseIP("0:0:0:0:0:0:0:1"), net.ParseIP("10.0.0.1")} + argfmt := "ips=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ips { + if !expected[i].Equal(v) { + t.Fatalf("expected ips[%d] to be %s but got: %s", i, expected[i], v) + } + } +} + +func TestIPSBadQuoting(t *testing.T) { + + tests := []struct { + Want []net.IP + FlagArg []string + }{ + { + Want: []net.IP{ + net.ParseIP("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568"), + net.ParseIP("203.107.49.208"), + net.ParseIP("14.57.204.90"), + }, + FlagArg: []string{ + "a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568", + "203.107.49.208", + "14.57.204.90", + }, + }, + { + Want: []net.IP{ + net.ParseIP("204.228.73.195"), + net.ParseIP("86.141.15.94"), + }, + FlagArg: []string{ + "204.228.73.195", + "86.141.15.94", + }, + }, + { + Want: []net.IP{ + net.ParseIP("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f"), + net.ParseIP("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472"), + }, + FlagArg: []string{ + "c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f", + "4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472", + }, + }, + { + Want: []net.IP{ + net.ParseIP("5170:f971:cfac:7be3:512a:af37:952c:bc33"), + net.ParseIP("93.21.145.140"), + net.ParseIP("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca"), + }, + FlagArg: []string{ + " 5170:f971:cfac:7be3:512a:af37:952c:bc33 , 93.21.145.140 ", + "2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca", + }, + }, + { + Want: []net.IP{ + net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), + net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), + net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), + net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), + }, + FlagArg: []string{ + `"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b "`, + " 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"}, + }, + } + + for i, test := range tests { + + var ips []net.IP + f := setUpIPSFlagSet(&ips) + + if err := f.Parse([]string{fmt.Sprintf("--ips=%s", strings.Join(test.FlagArg, ","))}); err != nil { + t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s", + err, test.FlagArg, test.Want[i]) + } + + for j, b := range ips { + if !b.Equal(test.Want[j]) { + t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b) + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/ip_test.go b/vendor/github.com/spf13/pflag/ip_test.go new file mode 100644 index 000000000..1fec50e42 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ip_test.go @@ -0,0 +1,63 @@ +package pflag + +import ( + "fmt" + "net" + "os" + "testing" +) + +func setUpIP(ip *net.IP) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.IPVar(ip, "address", net.ParseIP("0.0.0.0"), "IP Address") + return f +} + +func TestIP(t *testing.T) { + testCases := []struct { + input string + success bool + expected string + }{ + {"0.0.0.0", true, "0.0.0.0"}, + {" 0.0.0.0 ", true, "0.0.0.0"}, + {"1.2.3.4", true, "1.2.3.4"}, + {"127.0.0.1", true, "127.0.0.1"}, + {"255.255.255.255", true, "255.255.255.255"}, + {"", false, ""}, + {"0", false, ""}, + {"localhost", false, ""}, + {"0.0.0", false, ""}, + {"0.0.0.", false, ""}, + {"0.0.0.0.", false, ""}, + {"0.0.0.256", false, ""}, + {"0 . 0 . 0 . 0", false, ""}, + } + + devnull, _ := os.Open(os.DevNull) + os.Stderr = devnull + for i := range testCases { + var addr net.IP + f := setUpIP(&addr) + + tc := &testCases[i] + + arg := fmt.Sprintf("--address=%s", tc.input) + err := f.Parse([]string{arg}) + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + t.Errorf("expected failure") + continue + } else if tc.success { + ip, err := f.GetIP("address") + if err != nil { + t.Errorf("Got error trying to fetch the IP flag: %v", err) + } + if ip.String() != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, ip.String()) + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/ipnet_test.go b/vendor/github.com/spf13/pflag/ipnet_test.go new file mode 100644 index 000000000..335b6fa15 --- /dev/null +++ b/vendor/github.com/spf13/pflag/ipnet_test.go @@ -0,0 +1,70 @@ +package pflag + +import ( + "fmt" + "net" + "os" + "testing" +) + +func setUpIPNet(ip *net.IPNet) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + _, def, _ := net.ParseCIDR("0.0.0.0/0") + f.IPNetVar(ip, "address", *def, "IP Address") + return f +} + +func TestIPNet(t *testing.T) { + testCases := []struct { + input string + success bool + expected string + }{ + {"0.0.0.0/0", true, "0.0.0.0/0"}, + {" 0.0.0.0/0 ", true, "0.0.0.0/0"}, + {"1.2.3.4/8", true, "1.0.0.0/8"}, + {"127.0.0.1/16", true, "127.0.0.0/16"}, + {"255.255.255.255/19", true, "255.255.224.0/19"}, + {"255.255.255.255/32", true, "255.255.255.255/32"}, + {"", false, ""}, + {"/0", false, ""}, + {"0", false, ""}, + {"0/0", false, ""}, + {"localhost/0", false, ""}, + {"0.0.0/4", false, ""}, + {"0.0.0./8", false, ""}, + {"0.0.0.0./12", false, ""}, + {"0.0.0.256/16", false, ""}, + {"0.0.0.0 /20", false, ""}, + {"0.0.0.0/ 24", false, ""}, + {"0 . 0 . 0 . 0 / 28", false, ""}, + {"0.0.0.0/33", false, ""}, + } + + devnull, _ := os.Open(os.DevNull) + os.Stderr = devnull + for i := range testCases { + var addr net.IPNet + f := setUpIPNet(&addr) + + tc := &testCases[i] + + arg := fmt.Sprintf("--address=%s", tc.input) + err := f.Parse([]string{arg}) + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + t.Errorf("expected failure") + continue + } else if tc.success { + ip, err := f.GetIPNet("address") + if err != nil { + t.Errorf("Got error trying to fetch the IP flag: %v", err) + } + if ip.String() != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, ip.String()) + } + } + } +} diff --git a/vendor/github.com/spf13/pflag/printusage_test.go b/vendor/github.com/spf13/pflag/printusage_test.go new file mode 100644 index 000000000..df982aab4 --- /dev/null +++ b/vendor/github.com/spf13/pflag/printusage_test.go @@ -0,0 +1,74 @@ +package pflag + +import ( + "bytes" + "io" + "testing" +) + +const expectedOutput = ` --long-form Some description + --long-form2 Some description + with multiline + -s, --long-name Some description + -t, --long-name2 Some description with + multiline +` + +func setUpPFlagSet(buf io.Writer) *FlagSet { + f := NewFlagSet("test", ExitOnError) + f.Bool("long-form", false, "Some description") + f.Bool("long-form2", false, "Some description\n with multiline") + f.BoolP("long-name", "s", false, "Some description") + f.BoolP("long-name2", "t", false, "Some description with\n multiline") + f.SetOutput(buf) + return f +} + +func TestPrintUsage(t *testing.T) { + buf := bytes.Buffer{} + f := setUpPFlagSet(&buf) + f.PrintDefaults() + res := buf.String() + if res != expectedOutput { + t.Errorf("Expected \n%s \nActual \n%s", expectedOutput, res) + } +} + +func setUpPFlagSet2(buf io.Writer) *FlagSet { + f := NewFlagSet("test", ExitOnError) + f.Bool("long-form", false, "Some description") + f.Bool("long-form2", false, "Some description\n with multiline") + f.BoolP("long-name", "s", false, "Some description") + f.BoolP("long-name2", "t", false, "Some description with\n multiline") + f.StringP("some-very-long-arg", "l", "test", "Some very long description having break the limit") + f.StringP("other-very-long-arg", "o", "long-default-value", "Some very long description having break the limit") + f.String("some-very-long-arg2", "very long default value", "Some very long description\nwith line break\nmultiple") + f.SetOutput(buf) + return f +} + +const expectedOutput2 = ` --long-form Some description + --long-form2 Some description + with multiline + -s, --long-name Some description + -t, --long-name2 Some description with + multiline + -o, --other-very-long-arg string Some very long description having + break the limit (default + "long-default-value") + -l, --some-very-long-arg string Some very long description having + break the limit (default "test") + --some-very-long-arg2 string Some very long description + with line break + multiple (default "very long default + value") +` + +func TestPrintUsage_2(t *testing.T) { + buf := bytes.Buffer{} + f := setUpPFlagSet2(&buf) + res := f.FlagUsagesWrapped(80) + if res != expectedOutput2 { + t.Errorf("Expected \n%q \nActual \n%q", expectedOutput2, res) + } +} diff --git a/vendor/github.com/spf13/pflag/string_array_test.go b/vendor/github.com/spf13/pflag/string_array_test.go new file mode 100644 index 000000000..1ceac8c6c --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_array_test.go @@ -0,0 +1,233 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "fmt" + "testing" +) + +func setUpSAFlagSet(sap *[]string) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.StringArrayVar(sap, "sa", []string{}, "Command separated list!") + return f +} + +func setUpSAFlagSetWithDefault(sap *[]string) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.StringArrayVar(sap, "sa", []string{"default", "values"}, "Command separated list!") + return f +} + +func TestEmptySA(t *testing.T) { + var sa []string + f := setUpSAFlagSet(&sa) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getSA, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("got an error from GetStringArray():", err) + } + if len(getSA) != 0 { + t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA)) + } +} + +func TestEmptySAValue(t *testing.T) { + var sa []string + f := setUpSAFlagSet(&sa) + err := f.Parse([]string{"--sa="}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getSA, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("got an error from GetStringArray():", err) + } + if len(getSA) != 0 { + t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA)) + } +} + +func TestSADefault(t *testing.T) { + var sa []string + f := setUpSAFlagSetWithDefault(&sa) + + vals := []string{"default", "values"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range sa { + if vals[i] != v { + t.Fatalf("expected sa[%d] to be %s but got: %s", i, vals[i], v) + } + } + + getSA, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("got an error from GetStringArray():", err) + } + for i, v := range getSA { + if vals[i] != v { + t.Fatalf("expected sa[%d] to be %s from GetStringArray but got: %s", i, vals[i], v) + } + } +} + +func TestSAWithDefault(t *testing.T) { + var sa []string + f := setUpSAFlagSetWithDefault(&sa) + + val := "one" + arg := fmt.Sprintf("--sa=%s", val) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(sa) != 1 { + t.Fatalf("expected number of values to be %d but %d", 1, len(sa)) + } + + if sa[0] != val { + t.Fatalf("expected value to be %s but got: %s", sa[0], val) + } + + getSA, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("got an error from GetStringArray():", err) + } + + if len(getSA) != 1 { + t.Fatalf("expected number of values to be %d but %d", 1, len(getSA)) + } + + if getSA[0] != val { + t.Fatalf("expected value to be %s but got: %s", getSA[0], val) + } +} + +func TestSACalledTwice(t *testing.T) { + var sa []string + f := setUpSAFlagSet(&sa) + + in := []string{"one", "two"} + expected := []string{"one", "two"} + argfmt := "--sa=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(sa) { + t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) + } + for i, v := range sa { + if expected[i] != v { + t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) + } + } + + values, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(values) { + t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(sa)) + } + for i, v := range values { + if expected[i] != v { + t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) + } + } +} + +func TestSAWithSpecialChar(t *testing.T) { + var sa []string + f := setUpSAFlagSet(&sa) + + in := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"} + expected := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"} + argfmt := "--sa=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + arg3 := fmt.Sprintf(argfmt, in[2]) + arg4 := fmt.Sprintf(argfmt, in[3]) + err := f.Parse([]string{arg1, arg2, arg3, arg4}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(sa) { + t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) + } + for i, v := range sa { + if expected[i] != v { + t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) + } + } + + values, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(values) { + t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) + } + for i, v := range values { + if expected[i] != v { + t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) + } + } +} + +func TestSAWithSquareBrackets(t *testing.T) { + var sa []string + f := setUpSAFlagSet(&sa) + + in := []string{"][]-[", "[a-z]", "[a-z]+"} + expected := []string{"][]-[", "[a-z]", "[a-z]+"} + argfmt := "--sa=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + arg3 := fmt.Sprintf(argfmt, in[2]) + err := f.Parse([]string{arg1, arg2, arg3}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(sa) { + t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) + } + for i, v := range sa { + if expected[i] != v { + t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) + } + } + + values, err := f.GetStringArray("sa") + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(values) { + t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) + } + for i, v := range values { + if expected[i] != v { + t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) + } + } +} diff --git a/vendor/github.com/spf13/pflag/string_slice_test.go b/vendor/github.com/spf13/pflag/string_slice_test.go new file mode 100644 index 000000000..c41f3bd66 --- /dev/null +++ b/vendor/github.com/spf13/pflag/string_slice_test.go @@ -0,0 +1,253 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pflag + +import ( + "fmt" + "strings" + "testing" +) + +func setUpSSFlagSet(ssp *[]string) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.StringSliceVar(ssp, "ss", []string{}, "Command separated list!") + return f +} + +func setUpSSFlagSetWithDefault(ssp *[]string) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.StringSliceVar(ssp, "ss", []string{"default", "values"}, "Command separated list!") + return f +} + +func TestEmptySS(t *testing.T) { + var ss []string + f := setUpSSFlagSet(&ss) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getSS, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("got an error from GetStringSlice():", err) + } + if len(getSS) != 0 { + t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS)) + } +} + +func TestEmptySSValue(t *testing.T) { + var ss []string + f := setUpSSFlagSet(&ss) + err := f.Parse([]string{"--ss="}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getSS, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("got an error from GetStringSlice():", err) + } + if len(getSS) != 0 { + t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS)) + } +} + +func TestSS(t *testing.T) { + var ss []string + f := setUpSSFlagSet(&ss) + + vals := []string{"one", "two", "4", "3"} + arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ss { + if vals[i] != v { + t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) + } + } + + getSS, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("got an error from GetStringSlice():", err) + } + for i, v := range getSS { + if vals[i] != v { + t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) + } + } +} + +func TestSSDefault(t *testing.T) { + var ss []string + f := setUpSSFlagSetWithDefault(&ss) + + vals := []string{"default", "values"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ss { + if vals[i] != v { + t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) + } + } + + getSS, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("got an error from GetStringSlice():", err) + } + for i, v := range getSS { + if vals[i] != v { + t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) + } + } +} + +func TestSSWithDefault(t *testing.T) { + var ss []string + f := setUpSSFlagSetWithDefault(&ss) + + vals := []string{"one", "two", "4", "3"} + arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range ss { + if vals[i] != v { + t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) + } + } + + getSS, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("got an error from GetStringSlice():", err) + } + for i, v := range getSS { + if vals[i] != v { + t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) + } + } +} + +func TestSSCalledTwice(t *testing.T) { + var ss []string + f := setUpSSFlagSet(&ss) + + in := []string{"one,two", "three"} + expected := []string{"one", "two", "three"} + argfmt := "--ss=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(ss) { + t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) + } + for i, v := range ss { + if expected[i] != v { + t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) + } + } + + values, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(values) { + t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(ss)) + } + for i, v := range values { + if expected[i] != v { + t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) + } + } +} + +func TestSSWithComma(t *testing.T) { + var ss []string + f := setUpSSFlagSet(&ss) + + in := []string{`"one,two"`, `"three"`, `"four,five",six`} + expected := []string{"one,two", "three", "four,five", "six"} + argfmt := "--ss=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + arg3 := fmt.Sprintf(argfmt, in[2]) + err := f.Parse([]string{arg1, arg2, arg3}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(ss) { + t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) + } + for i, v := range ss { + if expected[i] != v { + t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) + } + } + + values, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(values) { + t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) + } + for i, v := range values { + if expected[i] != v { + t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) + } + } +} + +func TestSSWithSquareBrackets(t *testing.T) { + var ss []string + f := setUpSSFlagSet(&ss) + + in := []string{`"[a-z]"`, `"[a-z]+"`} + expected := []string{"[a-z]", "[a-z]+"} + argfmt := "--ss=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(ss) { + t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) + } + for i, v := range ss { + if expected[i] != v { + t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) + } + } + + values, err := f.GetStringSlice("ss") + if err != nil { + t.Fatal("expected no error; got", err) + } + + if len(expected) != len(values) { + t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) + } + for i, v := range values { + if expected[i] != v { + t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) + } + } +} diff --git a/vendor/github.com/spf13/pflag/uint_slice_test.go b/vendor/github.com/spf13/pflag/uint_slice_test.go new file mode 100644 index 000000000..db1a19dc2 --- /dev/null +++ b/vendor/github.com/spf13/pflag/uint_slice_test.go @@ -0,0 +1,161 @@ +package pflag + +import ( + "fmt" + "strconv" + "strings" + "testing" +) + +func setUpUISFlagSet(uisp *[]uint) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.UintSliceVar(uisp, "uis", []uint{}, "Command separated list!") + return f +} + +func setUpUISFlagSetWithDefault(uisp *[]uint) *FlagSet { + f := NewFlagSet("test", ContinueOnError) + f.UintSliceVar(uisp, "uis", []uint{0, 1}, "Command separated list!") + return f +} + +func TestEmptyUIS(t *testing.T) { + var uis []uint + f := setUpUISFlagSet(&uis) + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + + getUIS, err := f.GetUintSlice("uis") + if err != nil { + t.Fatal("got an error from GetUintSlice():", err) + } + if len(getUIS) != 0 { + t.Fatalf("got is %v with len=%d but expected length=0", getUIS, len(getUIS)) + } +} + +func TestUIS(t *testing.T) { + var uis []uint + f := setUpUISFlagSet(&uis) + + vals := []string{"1", "2", "4", "3"} + arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range uis { + u, err := strconv.ParseUint(vals[i], 10, 0) + if err != nil { + t.Fatalf("got error: %v", err) + } + if uint(u) != v { + t.Fatalf("expected uis[%d] to be %s but got %d", i, vals[i], v) + } + } + getUIS, err := f.GetUintSlice("uis") + if err != nil { + t.Fatalf("got error: %v", err) + } + for i, v := range getUIS { + u, err := strconv.ParseUint(vals[i], 10, 0) + if err != nil { + t.Fatalf("got error: %v", err) + } + if uint(u) != v { + t.Fatalf("expected uis[%d] to be %s but got: %d from GetUintSlice", i, vals[i], v) + } + } +} + +func TestUISDefault(t *testing.T) { + var uis []uint + f := setUpUISFlagSetWithDefault(&uis) + + vals := []string{"0", "1"} + + err := f.Parse([]string{}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range uis { + u, err := strconv.ParseUint(vals[i], 10, 0) + if err != nil { + t.Fatalf("got error: %v", err) + } + if uint(u) != v { + t.Fatalf("expect uis[%d] to be %d but got: %d", i, u, v) + } + } + + getUIS, err := f.GetUintSlice("uis") + if err != nil { + t.Fatal("got an error from GetUintSlice():", err) + } + for i, v := range getUIS { + u, err := strconv.ParseUint(vals[i], 10, 0) + if err != nil { + t.Fatal("got an error from GetIntSlice():", err) + } + if uint(u) != v { + t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) + } + } +} + +func TestUISWithDefault(t *testing.T) { + var uis []uint + f := setUpUISFlagSetWithDefault(&uis) + + vals := []string{"1", "2"} + arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ",")) + err := f.Parse([]string{arg}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range uis { + u, err := strconv.ParseUint(vals[i], 10, 0) + if err != nil { + t.Fatalf("got error: %v", err) + } + if uint(u) != v { + t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) + } + } + + getUIS, err := f.GetUintSlice("uis") + if err != nil { + t.Fatal("got an error from GetUintSlice():", err) + } + for i, v := range getUIS { + u, err := strconv.ParseUint(vals[i], 10, 0) + if err != nil { + t.Fatalf("got error: %v", err) + } + if uint(u) != v { + t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) + } + } +} + +func TestUISCalledTwice(t *testing.T) { + var uis []uint + f := setUpUISFlagSet(&uis) + + in := []string{"1,2", "3"} + expected := []int{1, 2, 3} + argfmt := "--uis=%s" + arg1 := fmt.Sprintf(argfmt, in[0]) + arg2 := fmt.Sprintf(argfmt, in[1]) + err := f.Parse([]string{arg1, arg2}) + if err != nil { + t.Fatal("expected no error; got", err) + } + for i, v := range uis { + if uint(expected[i]) != v { + t.Fatalf("expected uis[%d] to be %d but got: %d", i, expected[i], v) + } + } +} diff --git a/vendor/golang.org/x/crypto/.gitattributes b/vendor/golang.org/x/crypto/.gitattributes new file mode 100644 index 000000000..d2f212e5d --- /dev/null +++ b/vendor/golang.org/x/crypto/.gitattributes @@ -0,0 +1,10 @@ +# Treat all files in this repo as binary, with no git magic updating +# line endings. Windows users contributing to Go will need to use a +# modern version of git and editors capable of LF line endings. +# +# We'll prevent accidental CRLF line endings from entering the repo +# via the git-review gofmt checks. +# +# See golang.org/issue/9281 + +* -text diff --git a/vendor/golang.org/x/crypto/.gitignore b/vendor/golang.org/x/crypto/.gitignore new file mode 100644 index 000000000..8339fd61d --- /dev/null +++ b/vendor/golang.org/x/crypto/.gitignore @@ -0,0 +1,2 @@ +# Add no patterns to .hgignore except for files generated by the build. +last-change diff --git a/vendor/golang.org/x/crypto/CONTRIBUTING.md b/vendor/golang.org/x/crypto/CONTRIBUTING.md new file mode 100644 index 000000000..d0485e887 --- /dev/null +++ b/vendor/golang.org/x/crypto/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/crypto/README.md b/vendor/golang.org/x/crypto/README.md new file mode 100644 index 000000000..c9d6fecd1 --- /dev/null +++ b/vendor/golang.org/x/crypto/README.md @@ -0,0 +1,21 @@ +# Go Cryptography + +This repository holds supplementary Go cryptography libraries. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/crypto/...`. You +can also manually git clone the repository to `$GOPATH/src/golang.org/x/crypto`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the crypto repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/crypto:" in the +subject line, so it is easy to find. + +Note that contributions to the cryptography package receive additional scrutiny +due to their sensitive nature. Patches may take longer than normal to receive +feedback. diff --git a/vendor/golang.org/x/crypto/codereview.cfg b/vendor/golang.org/x/crypto/codereview.cfg new file mode 100644 index 000000000..3f8b14b64 --- /dev/null +++ b/vendor/golang.org/x/crypto/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/crypto/ssh/benchmark_test.go b/vendor/golang.org/x/crypto/ssh/benchmark_test.go new file mode 100644 index 000000000..20c330773 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/benchmark_test.go @@ -0,0 +1,123 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "errors" + "io" + "net" + "testing" +) + +type server struct { + *ServerConn + chans <-chan NewChannel +} + +func newServer(c net.Conn, conf *ServerConfig) (*server, error) { + sconn, chans, reqs, err := NewServerConn(c, conf) + if err != nil { + return nil, err + } + go DiscardRequests(reqs) + return &server{sconn, chans}, nil +} + +func (s *server) Accept() (NewChannel, error) { + n, ok := <-s.chans + if !ok { + return nil, io.EOF + } + return n, nil +} + +func sshPipe() (Conn, *server, error) { + c1, c2, err := netPipe() + if err != nil { + return nil, nil, err + } + + clientConf := ClientConfig{ + User: "user", + HostKeyCallback: InsecureIgnoreHostKey(), + } + serverConf := ServerConfig{ + NoClientAuth: true, + } + serverConf.AddHostKey(testSigners["ecdsa"]) + done := make(chan *server, 1) + go func() { + server, err := newServer(c2, &serverConf) + if err != nil { + done <- nil + } + done <- server + }() + + client, _, reqs, err := NewClientConn(c1, "", &clientConf) + if err != nil { + return nil, nil, err + } + + server := <-done + if server == nil { + return nil, nil, errors.New("server handshake failed.") + } + go DiscardRequests(reqs) + + return client, server, nil +} + +func BenchmarkEndToEnd(b *testing.B) { + b.StopTimer() + + client, server, err := sshPipe() + if err != nil { + b.Fatalf("sshPipe: %v", err) + } + + defer client.Close() + defer server.Close() + + size := (1 << 20) + input := make([]byte, size) + output := make([]byte, size) + b.SetBytes(int64(size)) + done := make(chan int, 1) + + go func() { + newCh, err := server.Accept() + if err != nil { + b.Fatalf("Client: %v", err) + } + ch, incoming, err := newCh.Accept() + go DiscardRequests(incoming) + for i := 0; i < b.N; i++ { + if _, err := io.ReadFull(ch, output); err != nil { + b.Fatalf("ReadFull: %v", err) + } + } + ch.Close() + done <- 1 + }() + + ch, in, err := client.OpenChannel("speed", nil) + if err != nil { + b.Fatalf("OpenChannel: %v", err) + } + go DiscardRequests(in) + + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + if _, err := ch.Write(input); err != nil { + b.Fatalf("WriteFull: %v", err) + } + } + ch.Close() + b.StopTimer() + + <-done +} diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go new file mode 100644 index 000000000..1ab07d078 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/buffer.go @@ -0,0 +1,97 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "io" + "sync" +) + +// buffer provides a linked list buffer for data exchange +// between producer and consumer. Theoretically the buffer is +// of unlimited capacity as it does no allocation of its own. +type buffer struct { + // protects concurrent access to head, tail and closed + *sync.Cond + + head *element // the buffer that will be read first + tail *element // the buffer that will be read last + + closed bool +} + +// An element represents a single link in a linked list. +type element struct { + buf []byte + next *element +} + +// newBuffer returns an empty buffer that is not closed. +func newBuffer() *buffer { + e := new(element) + b := &buffer{ + Cond: newCond(), + head: e, + tail: e, + } + return b +} + +// write makes buf available for Read to receive. +// buf must not be modified after the call to write. +func (b *buffer) write(buf []byte) { + b.Cond.L.Lock() + e := &element{buf: buf} + b.tail.next = e + b.tail = e + b.Cond.Signal() + b.Cond.L.Unlock() +} + +// eof closes the buffer. Reads from the buffer once all +// the data has been consumed will receive io.EOF. +func (b *buffer) eof() { + b.Cond.L.Lock() + b.closed = true + b.Cond.Signal() + b.Cond.L.Unlock() +} + +// Read reads data from the internal buffer in buf. Reads will block +// if no data is available, or until the buffer is closed. +func (b *buffer) Read(buf []byte) (n int, err error) { + b.Cond.L.Lock() + defer b.Cond.L.Unlock() + + for len(buf) > 0 { + // if there is data in b.head, copy it + if len(b.head.buf) > 0 { + r := copy(buf, b.head.buf) + buf, b.head.buf = buf[r:], b.head.buf[r:] + n += r + continue + } + // if there is a next buffer, make it the head + if len(b.head.buf) == 0 && b.head != b.tail { + b.head = b.head.next + continue + } + + // if at least one byte has been copied, return + if n > 0 { + break + } + + // if nothing was read, and there is nothing outstanding + // check to see if the buffer is closed. + if b.closed { + err = io.EOF + break + } + // out of buffers, wait for producer + b.Cond.Wait() + } + return +} diff --git a/vendor/golang.org/x/crypto/ssh/buffer_test.go b/vendor/golang.org/x/crypto/ssh/buffer_test.go new file mode 100644 index 000000000..d5781cb3d --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/buffer_test.go @@ -0,0 +1,87 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "io" + "testing" +) + +var alphabet = []byte("abcdefghijklmnopqrstuvwxyz") + +func TestBufferReadwrite(t *testing.T) { + b := newBuffer() + b.write(alphabet[:10]) + r, _ := b.Read(make([]byte, 10)) + if r != 10 { + t.Fatalf("Expected written == read == 10, written: 10, read %d", r) + } + + b = newBuffer() + b.write(alphabet[:5]) + r, _ = b.Read(make([]byte, 10)) + if r != 5 { + t.Fatalf("Expected written == read == 5, written: 5, read %d", r) + } + + b = newBuffer() + b.write(alphabet[:10]) + r, _ = b.Read(make([]byte, 5)) + if r != 5 { + t.Fatalf("Expected written == 10, read == 5, written: 10, read %d", r) + } + + b = newBuffer() + b.write(alphabet[:5]) + b.write(alphabet[5:15]) + r, _ = b.Read(make([]byte, 10)) + r2, _ := b.Read(make([]byte, 10)) + if r != 10 || r2 != 5 || 15 != r+r2 { + t.Fatal("Expected written == read == 15") + } +} + +func TestBufferClose(t *testing.T) { + b := newBuffer() + b.write(alphabet[:10]) + b.eof() + _, err := b.Read(make([]byte, 5)) + if err != nil { + t.Fatal("expected read of 5 to not return EOF") + } + b = newBuffer() + b.write(alphabet[:10]) + b.eof() + r, err := b.Read(make([]byte, 5)) + r2, err2 := b.Read(make([]byte, 10)) + if r != 5 || r2 != 5 || err != nil || err2 != nil { + t.Fatal("expected reads of 5 and 5") + } + + b = newBuffer() + b.write(alphabet[:10]) + b.eof() + r, err = b.Read(make([]byte, 5)) + r2, err2 = b.Read(make([]byte, 10)) + r3, err3 := b.Read(make([]byte, 10)) + if r != 5 || r2 != 5 || r3 != 0 || err != nil || err2 != nil || err3 != io.EOF { + t.Fatal("expected reads of 5 and 5 and 0, with EOF") + } + + b = newBuffer() + b.write(make([]byte, 5)) + b.write(make([]byte, 10)) + b.eof() + r, err = b.Read(make([]byte, 9)) + r2, err2 = b.Read(make([]byte, 3)) + r3, err3 = b.Read(make([]byte, 3)) + r4, err4 := b.Read(make([]byte, 10)) + if err != nil || err2 != nil || err3 != nil || err4 != io.EOF { + t.Fatalf("Expected EOF on forth read only, err=%v, err2=%v, err3=%v, err4=%v", err, err2, err3, err4) + } + if r != 9 || r2 != 3 || r3 != 3 || r4 != 0 { + t.Fatal("Expected written == read == 15", r, r2, r3, r4) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go new file mode 100644 index 000000000..42106f3f2 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -0,0 +1,521 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "errors" + "fmt" + "io" + "net" + "sort" + "time" +) + +// These constants from [PROTOCOL.certkeys] represent the algorithm names +// for certificate types supported by this package. +const ( + CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" + CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" + CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" + CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" + CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" + CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com" +) + +// Certificate types distinguish between host and user +// certificates. The values can be set in the CertType field of +// Certificate. +const ( + UserCert = 1 + HostCert = 2 +) + +// Signature represents a cryptographic signature. +type Signature struct { + Format string + Blob []byte +} + +// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that +// a certificate does not expire. +const CertTimeInfinity = 1<<64 - 1 + +// An Certificate represents an OpenSSH certificate as defined in +// [PROTOCOL.certkeys]?rev=1.8. The Certificate type implements the +// PublicKey interface, so it can be unmarshaled using +// ParsePublicKey. +type Certificate struct { + Nonce []byte + Key PublicKey + Serial uint64 + CertType uint32 + KeyId string + ValidPrincipals []string + ValidAfter uint64 + ValidBefore uint64 + Permissions + Reserved []byte + SignatureKey PublicKey + Signature *Signature +} + +// genericCertData holds the key-independent part of the certificate data. +// Overall, certificates contain an nonce, public key fields and +// key-independent fields. +type genericCertData struct { + Serial uint64 + CertType uint32 + KeyId string + ValidPrincipals []byte + ValidAfter uint64 + ValidBefore uint64 + CriticalOptions []byte + Extensions []byte + Reserved []byte + SignatureKey []byte + Signature []byte +} + +func marshalStringList(namelist []string) []byte { + var to []byte + for _, name := range namelist { + s := struct{ N string }{name} + to = append(to, Marshal(&s)...) + } + return to +} + +type optionsTuple struct { + Key string + Value []byte +} + +type optionsTupleValue struct { + Value string +} + +// serialize a map of critical options or extensions +// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, +// we need two length prefixes for a non-empty string value +func marshalTuples(tups map[string]string) []byte { + keys := make([]string, 0, len(tups)) + for key := range tups { + keys = append(keys, key) + } + sort.Strings(keys) + + var ret []byte + for _, key := range keys { + s := optionsTuple{Key: key} + if value := tups[key]; len(value) > 0 { + s.Value = Marshal(&optionsTupleValue{value}) + } + ret = append(ret, Marshal(&s)...) + } + return ret +} + +// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, +// we need two length prefixes for a non-empty option value +func parseTuples(in []byte) (map[string]string, error) { + tups := map[string]string{} + var lastKey string + var haveLastKey bool + + for len(in) > 0 { + var key, val, extra []byte + var ok bool + + if key, in, ok = parseString(in); !ok { + return nil, errShortRead + } + keyStr := string(key) + // according to [PROTOCOL.certkeys], the names must be in + // lexical order. + if haveLastKey && keyStr <= lastKey { + return nil, fmt.Errorf("ssh: certificate options are not in lexical order") + } + lastKey, haveLastKey = keyStr, true + // the next field is a data field, which if non-empty has a string embedded + if val, in, ok = parseString(in); !ok { + return nil, errShortRead + } + if len(val) > 0 { + val, extra, ok = parseString(val) + if !ok { + return nil, errShortRead + } + if len(extra) > 0 { + return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") + } + tups[keyStr] = string(val) + } else { + tups[keyStr] = "" + } + } + return tups, nil +} + +func parseCert(in []byte, privAlgo string) (*Certificate, error) { + nonce, rest, ok := parseString(in) + if !ok { + return nil, errShortRead + } + + key, rest, err := parsePubKey(rest, privAlgo) + if err != nil { + return nil, err + } + + var g genericCertData + if err := Unmarshal(rest, &g); err != nil { + return nil, err + } + + c := &Certificate{ + Nonce: nonce, + Key: key, + Serial: g.Serial, + CertType: g.CertType, + KeyId: g.KeyId, + ValidAfter: g.ValidAfter, + ValidBefore: g.ValidBefore, + } + + for principals := g.ValidPrincipals; len(principals) > 0; { + principal, rest, ok := parseString(principals) + if !ok { + return nil, errShortRead + } + c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) + principals = rest + } + + c.CriticalOptions, err = parseTuples(g.CriticalOptions) + if err != nil { + return nil, err + } + c.Extensions, err = parseTuples(g.Extensions) + if err != nil { + return nil, err + } + c.Reserved = g.Reserved + k, err := ParsePublicKey(g.SignatureKey) + if err != nil { + return nil, err + } + + c.SignatureKey = k + c.Signature, rest, ok = parseSignatureBody(g.Signature) + if !ok || len(rest) > 0 { + return nil, errors.New("ssh: signature parse error") + } + + return c, nil +} + +type openSSHCertSigner struct { + pub *Certificate + signer Signer +} + +// NewCertSigner returns a Signer that signs with the given Certificate, whose +// private key is held by signer. It returns an error if the public key in cert +// doesn't match the key used by signer. +func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { + if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { + return nil, errors.New("ssh: signer and cert have different public key") + } + + return &openSSHCertSigner{cert, signer}, nil +} + +func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.signer.Sign(rand, data) +} + +func (s *openSSHCertSigner) PublicKey() PublicKey { + return s.pub +} + +const sourceAddressCriticalOption = "source-address" + +// CertChecker does the work of verifying a certificate. Its methods +// can be plugged into ClientConfig.HostKeyCallback and +// ServerConfig.PublicKeyCallback. For the CertChecker to work, +// minimally, the IsAuthority callback should be set. +type CertChecker struct { + // SupportedCriticalOptions lists the CriticalOptions that the + // server application layer understands. These are only used + // for user certificates. + SupportedCriticalOptions []string + + // IsUserAuthority should return true if the key is recognized as an + // authority for the given user certificate. This allows for + // certificates to be signed by other certificates. This must be set + // if this CertChecker will be checking user certificates. + IsUserAuthority func(auth PublicKey) bool + + // IsHostAuthority should report whether the key is recognized as + // an authority for this host. This allows for certificates to be + // signed by other keys, and for those other keys to only be valid + // signers for particular hostnames. This must be set if this + // CertChecker will be checking host certificates. + IsHostAuthority func(auth PublicKey, address string) bool + + // Clock is used for verifying time stamps. If nil, time.Now + // is used. + Clock func() time.Time + + // UserKeyFallback is called when CertChecker.Authenticate encounters a + // public key that is not a certificate. It must implement validation + // of user keys or else, if nil, all such keys are rejected. + UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) + + // HostKeyFallback is called when CertChecker.CheckHostKey encounters a + // public key that is not a certificate. It must implement host key + // validation or else, if nil, all such keys are rejected. + HostKeyFallback HostKeyCallback + + // IsRevoked is called for each certificate so that revocation checking + // can be implemented. It should return true if the given certificate + // is revoked and false otherwise. If nil, no certificates are + // considered to have been revoked. + IsRevoked func(cert *Certificate) bool +} + +// CheckHostKey checks a host key certificate. This method can be +// plugged into ClientConfig.HostKeyCallback. +func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { + cert, ok := key.(*Certificate) + if !ok { + if c.HostKeyFallback != nil { + return c.HostKeyFallback(addr, remote, key) + } + return errors.New("ssh: non-certificate host key") + } + if cert.CertType != HostCert { + return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) + } + if !c.IsHostAuthority(cert.SignatureKey, addr) { + return fmt.Errorf("ssh: no authorities for hostname: %v", addr) + } + + hostname, _, err := net.SplitHostPort(addr) + if err != nil { + return err + } + + // Pass hostname only as principal for host certificates (consistent with OpenSSH) + return c.CheckCert(hostname, cert) +} + +// Authenticate checks a user certificate. Authenticate can be used as +// a value for ServerConfig.PublicKeyCallback. +func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { + cert, ok := pubKey.(*Certificate) + if !ok { + if c.UserKeyFallback != nil { + return c.UserKeyFallback(conn, pubKey) + } + return nil, errors.New("ssh: normal key pairs not accepted") + } + + if cert.CertType != UserCert { + return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) + } + if !c.IsUserAuthority(cert.SignatureKey) { + return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") + } + + if err := c.CheckCert(conn.User(), cert); err != nil { + return nil, err + } + + return &cert.Permissions, nil +} + +// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and +// the signature of the certificate. +func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { + if c.IsRevoked != nil && c.IsRevoked(cert) { + return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial) + } + + for opt := range cert.CriticalOptions { + // sourceAddressCriticalOption will be enforced by + // serverAuthenticate + if opt == sourceAddressCriticalOption { + continue + } + + found := false + for _, supp := range c.SupportedCriticalOptions { + if supp == opt { + found = true + break + } + } + if !found { + return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) + } + } + + if len(cert.ValidPrincipals) > 0 { + // By default, certs are valid for all users/hosts. + found := false + for _, p := range cert.ValidPrincipals { + if p == principal { + found = true + break + } + } + if !found { + return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) + } + } + + clock := c.Clock + if clock == nil { + clock = time.Now + } + + unixNow := clock().Unix() + if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { + return fmt.Errorf("ssh: cert is not yet valid") + } + if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { + return fmt.Errorf("ssh: cert has expired") + } + if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { + return fmt.Errorf("ssh: certificate signature does not verify") + } + + return nil +} + +// SignCert sets c.SignatureKey to the authority's public key and stores a +// Signature, by authority, in the certificate. +func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { + c.Nonce = make([]byte, 32) + if _, err := io.ReadFull(rand, c.Nonce); err != nil { + return err + } + c.SignatureKey = authority.PublicKey() + + sig, err := authority.Sign(rand, c.bytesForSigning()) + if err != nil { + return err + } + c.Signature = sig + return nil +} + +var certAlgoNames = map[string]string{ + KeyAlgoRSA: CertAlgoRSAv01, + KeyAlgoDSA: CertAlgoDSAv01, + KeyAlgoECDSA256: CertAlgoECDSA256v01, + KeyAlgoECDSA384: CertAlgoECDSA384v01, + KeyAlgoECDSA521: CertAlgoECDSA521v01, + KeyAlgoED25519: CertAlgoED25519v01, +} + +// certToPrivAlgo returns the underlying algorithm for a certificate algorithm. +// Panics if a non-certificate algorithm is passed. +func certToPrivAlgo(algo string) string { + for privAlgo, pubAlgo := range certAlgoNames { + if pubAlgo == algo { + return privAlgo + } + } + panic("unknown cert algorithm") +} + +func (cert *Certificate) bytesForSigning() []byte { + c2 := *cert + c2.Signature = nil + out := c2.Marshal() + // Drop trailing signature length. + return out[:len(out)-4] +} + +// Marshal serializes c into OpenSSH's wire format. It is part of the +// PublicKey interface. +func (c *Certificate) Marshal() []byte { + generic := genericCertData{ + Serial: c.Serial, + CertType: c.CertType, + KeyId: c.KeyId, + ValidPrincipals: marshalStringList(c.ValidPrincipals), + ValidAfter: uint64(c.ValidAfter), + ValidBefore: uint64(c.ValidBefore), + CriticalOptions: marshalTuples(c.CriticalOptions), + Extensions: marshalTuples(c.Extensions), + Reserved: c.Reserved, + SignatureKey: c.SignatureKey.Marshal(), + } + if c.Signature != nil { + generic.Signature = Marshal(c.Signature) + } + genericBytes := Marshal(&generic) + keyBytes := c.Key.Marshal() + _, keyBytes, _ = parseString(keyBytes) + prefix := Marshal(&struct { + Name string + Nonce []byte + Key []byte `ssh:"rest"` + }{c.Type(), c.Nonce, keyBytes}) + + result := make([]byte, 0, len(prefix)+len(genericBytes)) + result = append(result, prefix...) + result = append(result, genericBytes...) + return result +} + +// Type returns the key name. It is part of the PublicKey interface. +func (c *Certificate) Type() string { + algo, ok := certAlgoNames[c.Key.Type()] + if !ok { + panic("unknown cert key type " + c.Key.Type()) + } + return algo +} + +// Verify verifies a signature against the certificate's public +// key. It is part of the PublicKey interface. +func (c *Certificate) Verify(data []byte, sig *Signature) error { + return c.Key.Verify(data, sig) +} + +func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { + format, in, ok := parseString(in) + if !ok { + return + } + + out = &Signature{ + Format: string(format), + } + + if out.Blob, in, ok = parseString(in); !ok { + return + } + + return out, in, ok +} + +func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { + sigBytes, rest, ok := parseString(in) + if !ok { + return + } + + out, trailing, ok := parseSignatureBody(sigBytes) + if !ok || len(trailing) > 0 { + return nil, nil, false + } + return +} diff --git a/vendor/golang.org/x/crypto/ssh/certs_test.go b/vendor/golang.org/x/crypto/ssh/certs_test.go new file mode 100644 index 000000000..c8e7cf585 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/certs_test.go @@ -0,0 +1,335 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "net" + "reflect" + "testing" + "time" + + "golang.org/x/crypto/ssh/testdata" +) + +// Cert generated by ssh-keygen 6.0p1 Debian-4. +// % ssh-keygen -s ca-key -I test user-key +const exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=` + +func TestParseCert(t *testing.T) { + authKeyBytes := []byte(exampleSSHCert) + + key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes) + if err != nil { + t.Fatalf("ParseAuthorizedKey: %v", err) + } + if len(rest) > 0 { + t.Errorf("rest: got %q, want empty", rest) + } + + if _, ok := key.(*Certificate); !ok { + t.Fatalf("got %v (%T), want *Certificate", key, key) + } + + marshaled := MarshalAuthorizedKey(key) + // Before comparison, remove the trailing newline that + // MarshalAuthorizedKey adds. + marshaled = marshaled[:len(marshaled)-1] + if !bytes.Equal(authKeyBytes, marshaled) { + t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes) + } +} + +// Cert generated by ssh-keygen OpenSSH_6.8p1 OS X 10.10.3 +// % ssh-keygen -s ca -I testcert -O source-address=192.168.1.0/24 -O force-command=/bin/sleep user.pub +// user.pub key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDACh1rt2DXfV3hk6fszSQcQ/rueMId0kVD9U7nl8cfEnFxqOCrNT92g4laQIGl2mn8lsGZfTLg8ksHq3gkvgO3oo/0wHy4v32JeBOHTsN5AL4gfHNEhWeWb50ev47hnTsRIt9P4dxogeUo/hTu7j9+s9lLpEQXCvq6xocXQt0j8MV9qZBBXFLXVT3cWIkSqOdwt/5ZBg+1GSrc7WfCXVWgTk4a20uPMuJPxU4RQwZW6X3+O8Pqo8C3cW0OzZRFP6gUYUKUsTI5WntlS+LAxgw1mZNsozFGdbiOPRnEryE3SRldh9vjDR3tin1fGpA5P7+CEB/bqaXtG3V+F2OkqaMN +// Critical Options: +// force-command /bin/sleep +// source-address 192.168.1.0/24 +// Extensions: +// permit-X11-forwarding +// permit-agent-forwarding +// permit-port-forwarding +// permit-pty +// permit-user-rc +const exampleSSHCertWithOptions = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgDyysCJY0XrO1n03EeRRoITnTPdjENFmWDs9X58PP3VUAAAADAQABAAABAQDACh1rt2DXfV3hk6fszSQcQ/rueMId0kVD9U7nl8cfEnFxqOCrNT92g4laQIGl2mn8lsGZfTLg8ksHq3gkvgO3oo/0wHy4v32JeBOHTsN5AL4gfHNEhWeWb50ev47hnTsRIt9P4dxogeUo/hTu7j9+s9lLpEQXCvq6xocXQt0j8MV9qZBBXFLXVT3cWIkSqOdwt/5ZBg+1GSrc7WfCXVWgTk4a20uPMuJPxU4RQwZW6X3+O8Pqo8C3cW0OzZRFP6gUYUKUsTI5WntlS+LAxgw1mZNsozFGdbiOPRnEryE3SRldh9vjDR3tin1fGpA5P7+CEB/bqaXtG3V+F2OkqaMNAAAAAAAAAAAAAAABAAAACHRlc3RjZXJ0AAAAAAAAAAAAAAAA//////////8AAABLAAAADWZvcmNlLWNvbW1hbmQAAAAOAAAACi9iaW4vc2xlZXAAAAAOc291cmNlLWFkZHJlc3MAAAASAAAADjE5Mi4xNjguMS4wLzI0AAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAwU+c5ui5A8+J/CFpjW8wCa52bEODA808WWQDCSuTG/eMXNf59v9Y8Pk0F1E9dGCosSNyVcB/hacUrc6He+i97+HJCyKavBsE6GDxrjRyxYqAlfcOXi/IVmaUGiO8OQ39d4GHrjToInKvExSUeleQyH4Y4/e27T/pILAqPFL3fyrvMLT5qU9QyIt6zIpa7GBP5+urouNavMprV3zsfIqNBbWypinOQAw823a5wN+zwXnhZrgQiHZ/USG09Y6k98y1dTVz8YHlQVR4D3lpTAsKDKJ5hCH9WU4fdf+lU8OyNGaJ/vz0XNqxcToe1l4numLTnaoSuH89pHryjqurB7lJKwAAAQ8AAAAHc3NoLXJzYQAAAQCaHvUIoPL1zWUHIXLvu96/HU1s/i4CAW2IIEuGgxCUCiFj6vyTyYtgxQxcmbfZf6eaITlS6XJZa7Qq4iaFZh75C1DXTX8labXhRSD4E2t//AIP9MC1rtQC5xo6FmbQ+BoKcDskr+mNACcbRSxs3IL3bwCfWDnIw2WbVox9ZdcthJKk4UoCW4ix4QwdHw7zlddlz++fGEEVhmTbll1SUkycGApPFBsAYRTMupUJcYPIeReBI/m8XfkoMk99bV8ZJQTAd7OekHY2/48Ff53jLmyDjP7kNw1F8OaPtkFs6dGJXta4krmaekPy87j+35In5hFj7yoOqvSbmYUkeX70/GGQ` + +func TestParseCertWithOptions(t *testing.T) { + opts := map[string]string{ + "source-address": "192.168.1.0/24", + "force-command": "/bin/sleep", + } + exts := map[string]string{ + "permit-X11-forwarding": "", + "permit-agent-forwarding": "", + "permit-port-forwarding": "", + "permit-pty": "", + "permit-user-rc": "", + } + authKeyBytes := []byte(exampleSSHCertWithOptions) + + key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes) + if err != nil { + t.Fatalf("ParseAuthorizedKey: %v", err) + } + if len(rest) > 0 { + t.Errorf("rest: got %q, want empty", rest) + } + cert, ok := key.(*Certificate) + if !ok { + t.Fatalf("got %v (%T), want *Certificate", key, key) + } + if !reflect.DeepEqual(cert.CriticalOptions, opts) { + t.Errorf("unexpected critical options - got %v, want %v", cert.CriticalOptions, opts) + } + if !reflect.DeepEqual(cert.Extensions, exts) { + t.Errorf("unexpected Extensions - got %v, want %v", cert.Extensions, exts) + } + marshaled := MarshalAuthorizedKey(key) + // Before comparison, remove the trailing newline that + // MarshalAuthorizedKey adds. + marshaled = marshaled[:len(marshaled)-1] + if !bytes.Equal(authKeyBytes, marshaled) { + t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes) + } +} + +func TestValidateCert(t *testing.T) { + key, _, _, _, err := ParseAuthorizedKey([]byte(exampleSSHCert)) + if err != nil { + t.Fatalf("ParseAuthorizedKey: %v", err) + } + validCert, ok := key.(*Certificate) + if !ok { + t.Fatalf("got %v (%T), want *Certificate", key, key) + } + checker := CertChecker{} + checker.IsUserAuthority = func(k PublicKey) bool { + return bytes.Equal(k.Marshal(), validCert.SignatureKey.Marshal()) + } + + if err := checker.CheckCert("user", validCert); err != nil { + t.Errorf("Unable to validate certificate: %v", err) + } + invalidCert := &Certificate{ + Key: testPublicKeys["rsa"], + SignatureKey: testPublicKeys["ecdsa"], + ValidBefore: CertTimeInfinity, + Signature: &Signature{}, + } + if err := checker.CheckCert("user", invalidCert); err == nil { + t.Error("Invalid cert signature passed validation") + } +} + +func TestValidateCertTime(t *testing.T) { + cert := Certificate{ + ValidPrincipals: []string{"user"}, + Key: testPublicKeys["rsa"], + ValidAfter: 50, + ValidBefore: 100, + } + + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + + for ts, ok := range map[int64]bool{ + 25: false, + 50: true, + 99: true, + 100: false, + 125: false, + } { + checker := CertChecker{ + Clock: func() time.Time { return time.Unix(ts, 0) }, + } + checker.IsUserAuthority = func(k PublicKey) bool { + return bytes.Equal(k.Marshal(), + testPublicKeys["ecdsa"].Marshal()) + } + + if v := checker.CheckCert("user", &cert); (v == nil) != ok { + t.Errorf("Authenticate(%d): %v", ts, v) + } + } +} + +// TODO(hanwen): tests for +// +// host keys: +// * fallbacks + +func TestHostKeyCert(t *testing.T) { + cert := &Certificate{ + ValidPrincipals: []string{"hostname", "hostname.domain", "otherhost"}, + Key: testPublicKeys["rsa"], + ValidBefore: CertTimeInfinity, + CertType: HostCert, + } + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + + checker := &CertChecker{ + IsHostAuthority: func(p PublicKey, addr string) bool { + return addr == "hostname:22" && bytes.Equal(testPublicKeys["ecdsa"].Marshal(), p.Marshal()) + }, + } + + certSigner, err := NewCertSigner(cert, testSigners["rsa"]) + if err != nil { + t.Errorf("NewCertSigner: %v", err) + } + + for _, test := range []struct { + addr string + succeed bool + }{ + {addr: "hostname:22", succeed: true}, + {addr: "otherhost:22", succeed: false}, // The certificate is valid for 'otherhost' as hostname, but we only recognize the authority of the signer for the address 'hostname:22' + {addr: "lasthost:22", succeed: false}, + } { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + errc := make(chan error) + + go func() { + conf := ServerConfig{ + NoClientAuth: true, + } + conf.AddHostKey(certSigner) + _, _, _, err := NewServerConn(c1, &conf) + errc <- err + }() + + config := &ClientConfig{ + User: "user", + HostKeyCallback: checker.CheckHostKey, + } + _, _, _, err = NewClientConn(c2, test.addr, config) + + if (err == nil) != test.succeed { + t.Fatalf("NewClientConn(%q): %v", test.addr, err) + } + + err = <-errc + if (err == nil) != test.succeed { + t.Fatalf("NewServerConn(%q): %v", test.addr, err) + } + } +} + +func TestCertTypes(t *testing.T) { + var testVars = []struct { + name string + keys func() Signer + }{ + { + name: CertAlgoECDSA256v01, + keys: func() Signer { + s, _ := ParsePrivateKey(testdata.PEMBytes["ecdsap256"]) + return s + }, + }, + { + name: CertAlgoECDSA384v01, + keys: func() Signer { + s, _ := ParsePrivateKey(testdata.PEMBytes["ecdsap384"]) + return s + }, + }, + { + name: CertAlgoECDSA521v01, + keys: func() Signer { + s, _ := ParsePrivateKey(testdata.PEMBytes["ecdsap521"]) + return s + }, + }, + { + name: CertAlgoED25519v01, + keys: func() Signer { + s, _ := ParsePrivateKey(testdata.PEMBytes["ed25519"]) + return s + }, + }, + { + name: CertAlgoRSAv01, + keys: func() Signer { + s, _ := ParsePrivateKey(testdata.PEMBytes["rsa"]) + return s + }, + }, + { + name: CertAlgoDSAv01, + keys: func() Signer { + s, _ := ParsePrivateKey(testdata.PEMBytes["dsa"]) + return s + }, + }, + } + + k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("error generating host key: %v", err) + } + + signer, err := NewSignerFromKey(k) + if err != nil { + t.Fatalf("error generating signer for ssh listener: %v", err) + } + + conf := &ServerConfig{ + PublicKeyCallback: func(c ConnMetadata, k PublicKey) (*Permissions, error) { + return new(Permissions), nil + }, + } + conf.AddHostKey(signer) + + for _, m := range testVars { + t.Run(m.name, func(t *testing.T) { + + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go NewServerConn(c1, conf) + + priv := m.keys() + if err != nil { + t.Fatalf("error generating ssh pubkey: %v", err) + } + + cert := &Certificate{ + CertType: UserCert, + Key: priv.PublicKey(), + } + cert.SignCert(rand.Reader, priv) + + certSigner, err := NewCertSigner(cert, priv) + if err != nil { + t.Fatalf("error generating cert signer: %v", err) + } + + config := &ClientConfig{ + User: "user", + HostKeyCallback: func(h string, r net.Addr, k PublicKey) error { return nil }, + Auth: []AuthMethod{PublicKeys(certSigner)}, + } + + _, _, _, err = NewClientConn(c2, "", config) + if err != nil { + t.Fatalf("error connecting: %v", err) + } + }) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go new file mode 100644 index 000000000..c0834c00d --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/channel.go @@ -0,0 +1,633 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "log" + "sync" +) + +const ( + minPacketLength = 9 + // channelMaxPacket contains the maximum number of bytes that will be + // sent in a single packet. As per RFC 4253, section 6.1, 32k is also + // the minimum. + channelMaxPacket = 1 << 15 + // We follow OpenSSH here. + channelWindowSize = 64 * channelMaxPacket +) + +// NewChannel represents an incoming request to a channel. It must either be +// accepted for use by calling Accept, or rejected by calling Reject. +type NewChannel interface { + // Accept accepts the channel creation request. It returns the Channel + // and a Go channel containing SSH requests. The Go channel must be + // serviced otherwise the Channel will hang. + Accept() (Channel, <-chan *Request, error) + + // Reject rejects the channel creation request. After calling + // this, no other methods on the Channel may be called. + Reject(reason RejectionReason, message string) error + + // ChannelType returns the type of the channel, as supplied by the + // client. + ChannelType() string + + // ExtraData returns the arbitrary payload for this channel, as supplied + // by the client. This data is specific to the channel type. + ExtraData() []byte +} + +// A Channel is an ordered, reliable, flow-controlled, duplex stream +// that is multiplexed over an SSH connection. +type Channel interface { + // Read reads up to len(data) bytes from the channel. + Read(data []byte) (int, error) + + // Write writes len(data) bytes to the channel. + Write(data []byte) (int, error) + + // Close signals end of channel use. No data may be sent after this + // call. + Close() error + + // CloseWrite signals the end of sending in-band + // data. Requests may still be sent, and the other side may + // still send data + CloseWrite() error + + // SendRequest sends a channel request. If wantReply is true, + // it will wait for a reply and return the result as a + // boolean, otherwise the return value will be false. Channel + // requests are out-of-band messages so they may be sent even + // if the data stream is closed or blocked by flow control. + // If the channel is closed before a reply is returned, io.EOF + // is returned. + SendRequest(name string, wantReply bool, payload []byte) (bool, error) + + // Stderr returns an io.ReadWriter that writes to this channel + // with the extended data type set to stderr. Stderr may + // safely be read and written from a different goroutine than + // Read and Write respectively. + Stderr() io.ReadWriter +} + +// Request is a request sent outside of the normal stream of +// data. Requests can either be specific to an SSH channel, or they +// can be global. +type Request struct { + Type string + WantReply bool + Payload []byte + + ch *channel + mux *mux +} + +// Reply sends a response to a request. It must be called for all requests +// where WantReply is true and is a no-op otherwise. The payload argument is +// ignored for replies to channel-specific requests. +func (r *Request) Reply(ok bool, payload []byte) error { + if !r.WantReply { + return nil + } + + if r.ch == nil { + return r.mux.ackRequest(ok, payload) + } + + return r.ch.ackRequest(ok) +} + +// RejectionReason is an enumeration used when rejecting channel creation +// requests. See RFC 4254, section 5.1. +type RejectionReason uint32 + +const ( + Prohibited RejectionReason = iota + 1 + ConnectionFailed + UnknownChannelType + ResourceShortage +) + +// String converts the rejection reason to human readable form. +func (r RejectionReason) String() string { + switch r { + case Prohibited: + return "administratively prohibited" + case ConnectionFailed: + return "connect failed" + case UnknownChannelType: + return "unknown channel type" + case ResourceShortage: + return "resource shortage" + } + return fmt.Sprintf("unknown reason %d", int(r)) +} + +func min(a uint32, b int) uint32 { + if a < uint32(b) { + return a + } + return uint32(b) +} + +type channelDirection uint8 + +const ( + channelInbound channelDirection = iota + channelOutbound +) + +// channel is an implementation of the Channel interface that works +// with the mux class. +type channel struct { + // R/O after creation + chanType string + extraData []byte + localId, remoteId uint32 + + // maxIncomingPayload and maxRemotePayload are the maximum + // payload sizes of normal and extended data packets for + // receiving and sending, respectively. The wire packet will + // be 9 or 13 bytes larger (excluding encryption overhead). + maxIncomingPayload uint32 + maxRemotePayload uint32 + + mux *mux + + // decided is set to true if an accept or reject message has been sent + // (for outbound channels) or received (for inbound channels). + decided bool + + // direction contains either channelOutbound, for channels created + // locally, or channelInbound, for channels created by the peer. + direction channelDirection + + // Pending internal channel messages. + msg chan interface{} + + // Since requests have no ID, there can be only one request + // with WantReply=true outstanding. This lock is held by a + // goroutine that has such an outgoing request pending. + sentRequestMu sync.Mutex + + incomingRequests chan *Request + + sentEOF bool + + // thread-safe data + remoteWin window + pending *buffer + extPending *buffer + + // windowMu protects myWindow, the flow-control window. + windowMu sync.Mutex + myWindow uint32 + + // writeMu serializes calls to mux.conn.writePacket() and + // protects sentClose and packetPool. This mutex must be + // different from windowMu, as writePacket can block if there + // is a key exchange pending. + writeMu sync.Mutex + sentClose bool + + // packetPool has a buffer for each extended channel ID to + // save allocations during writes. + packetPool map[uint32][]byte +} + +// writePacket sends a packet. If the packet is a channel close, it updates +// sentClose. This method takes the lock c.writeMu. +func (ch *channel) writePacket(packet []byte) error { + ch.writeMu.Lock() + if ch.sentClose { + ch.writeMu.Unlock() + return io.EOF + } + ch.sentClose = (packet[0] == msgChannelClose) + err := ch.mux.conn.writePacket(packet) + ch.writeMu.Unlock() + return err +} + +func (ch *channel) sendMessage(msg interface{}) error { + if debugMux { + log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg) + } + + p := Marshal(msg) + binary.BigEndian.PutUint32(p[1:], ch.remoteId) + return ch.writePacket(p) +} + +// WriteExtended writes data to a specific extended stream. These streams are +// used, for example, for stderr. +func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { + if ch.sentEOF { + return 0, io.EOF + } + // 1 byte message type, 4 bytes remoteId, 4 bytes data length + opCode := byte(msgChannelData) + headerLength := uint32(9) + if extendedCode > 0 { + headerLength += 4 + opCode = msgChannelExtendedData + } + + ch.writeMu.Lock() + packet := ch.packetPool[extendedCode] + // We don't remove the buffer from packetPool, so + // WriteExtended calls from different goroutines will be + // flagged as errors by the race detector. + ch.writeMu.Unlock() + + for len(data) > 0 { + space := min(ch.maxRemotePayload, len(data)) + if space, err = ch.remoteWin.reserve(space); err != nil { + return n, err + } + if want := headerLength + space; uint32(cap(packet)) < want { + packet = make([]byte, want) + } else { + packet = packet[:want] + } + + todo := data[:space] + + packet[0] = opCode + binary.BigEndian.PutUint32(packet[1:], ch.remoteId) + if extendedCode > 0 { + binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) + } + binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) + copy(packet[headerLength:], todo) + if err = ch.writePacket(packet); err != nil { + return n, err + } + + n += len(todo) + data = data[len(todo):] + } + + ch.writeMu.Lock() + ch.packetPool[extendedCode] = packet + ch.writeMu.Unlock() + + return n, err +} + +func (ch *channel) handleData(packet []byte) error { + headerLen := 9 + isExtendedData := packet[0] == msgChannelExtendedData + if isExtendedData { + headerLen = 13 + } + if len(packet) < headerLen { + // malformed data packet + return parseError(packet[0]) + } + + var extended uint32 + if isExtendedData { + extended = binary.BigEndian.Uint32(packet[5:]) + } + + length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) + if length == 0 { + return nil + } + if length > ch.maxIncomingPayload { + // TODO(hanwen): should send Disconnect? + return errors.New("ssh: incoming packet exceeds maximum payload size") + } + + data := packet[headerLen:] + if length != uint32(len(data)) { + return errors.New("ssh: wrong packet length") + } + + ch.windowMu.Lock() + if ch.myWindow < length { + ch.windowMu.Unlock() + // TODO(hanwen): should send Disconnect with reason? + return errors.New("ssh: remote side wrote too much") + } + ch.myWindow -= length + ch.windowMu.Unlock() + + if extended == 1 { + ch.extPending.write(data) + } else if extended > 0 { + // discard other extended data. + } else { + ch.pending.write(data) + } + return nil +} + +func (c *channel) adjustWindow(n uint32) error { + c.windowMu.Lock() + // Since myWindow is managed on our side, and can never exceed + // the initial window setting, we don't worry about overflow. + c.myWindow += uint32(n) + c.windowMu.Unlock() + return c.sendMessage(windowAdjustMsg{ + AdditionalBytes: uint32(n), + }) +} + +func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { + switch extended { + case 1: + n, err = c.extPending.Read(data) + case 0: + n, err = c.pending.Read(data) + default: + return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) + } + + if n > 0 { + err = c.adjustWindow(uint32(n)) + // sendWindowAdjust can return io.EOF if the remote + // peer has closed the connection, however we want to + // defer forwarding io.EOF to the caller of Read until + // the buffer has been drained. + if n > 0 && err == io.EOF { + err = nil + } + } + + return n, err +} + +func (c *channel) close() { + c.pending.eof() + c.extPending.eof() + close(c.msg) + close(c.incomingRequests) + c.writeMu.Lock() + // This is not necessary for a normal channel teardown, but if + // there was another error, it is. + c.sentClose = true + c.writeMu.Unlock() + // Unblock writers. + c.remoteWin.close() +} + +// responseMessageReceived is called when a success or failure message is +// received on a channel to check that such a message is reasonable for the +// given channel. +func (ch *channel) responseMessageReceived() error { + if ch.direction == channelInbound { + return errors.New("ssh: channel response message received on inbound channel") + } + if ch.decided { + return errors.New("ssh: duplicate response received for channel") + } + ch.decided = true + return nil +} + +func (ch *channel) handlePacket(packet []byte) error { + switch packet[0] { + case msgChannelData, msgChannelExtendedData: + return ch.handleData(packet) + case msgChannelClose: + ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId}) + ch.mux.chanList.remove(ch.localId) + ch.close() + return nil + case msgChannelEOF: + // RFC 4254 is mute on how EOF affects dataExt messages but + // it is logical to signal EOF at the same time. + ch.extPending.eof() + ch.pending.eof() + return nil + } + + decoded, err := decode(packet) + if err != nil { + return err + } + + switch msg := decoded.(type) { + case *channelOpenFailureMsg: + if err := ch.responseMessageReceived(); err != nil { + return err + } + ch.mux.chanList.remove(msg.PeersID) + ch.msg <- msg + case *channelOpenConfirmMsg: + if err := ch.responseMessageReceived(); err != nil { + return err + } + if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { + return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) + } + ch.remoteId = msg.MyID + ch.maxRemotePayload = msg.MaxPacketSize + ch.remoteWin.add(msg.MyWindow) + ch.msg <- msg + case *windowAdjustMsg: + if !ch.remoteWin.add(msg.AdditionalBytes) { + return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) + } + case *channelRequestMsg: + req := Request{ + Type: msg.Request, + WantReply: msg.WantReply, + Payload: msg.RequestSpecificData, + ch: ch, + } + + ch.incomingRequests <- &req + default: + ch.msg <- msg + } + return nil +} + +func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { + ch := &channel{ + remoteWin: window{Cond: newCond()}, + myWindow: channelWindowSize, + pending: newBuffer(), + extPending: newBuffer(), + direction: direction, + incomingRequests: make(chan *Request, chanSize), + msg: make(chan interface{}, chanSize), + chanType: chanType, + extraData: extraData, + mux: m, + packetPool: make(map[uint32][]byte), + } + ch.localId = m.chanList.add(ch) + return ch +} + +var errUndecided = errors.New("ssh: must Accept or Reject channel") +var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") + +type extChannel struct { + code uint32 + ch *channel +} + +func (e *extChannel) Write(data []byte) (n int, err error) { + return e.ch.WriteExtended(data, e.code) +} + +func (e *extChannel) Read(data []byte) (n int, err error) { + return e.ch.ReadExtended(data, e.code) +} + +func (ch *channel) Accept() (Channel, <-chan *Request, error) { + if ch.decided { + return nil, nil, errDecidedAlready + } + ch.maxIncomingPayload = channelMaxPacket + confirm := channelOpenConfirmMsg{ + PeersID: ch.remoteId, + MyID: ch.localId, + MyWindow: ch.myWindow, + MaxPacketSize: ch.maxIncomingPayload, + } + ch.decided = true + if err := ch.sendMessage(confirm); err != nil { + return nil, nil, err + } + + return ch, ch.incomingRequests, nil +} + +func (ch *channel) Reject(reason RejectionReason, message string) error { + if ch.decided { + return errDecidedAlready + } + reject := channelOpenFailureMsg{ + PeersID: ch.remoteId, + Reason: reason, + Message: message, + Language: "en", + } + ch.decided = true + return ch.sendMessage(reject) +} + +func (ch *channel) Read(data []byte) (int, error) { + if !ch.decided { + return 0, errUndecided + } + return ch.ReadExtended(data, 0) +} + +func (ch *channel) Write(data []byte) (int, error) { + if !ch.decided { + return 0, errUndecided + } + return ch.WriteExtended(data, 0) +} + +func (ch *channel) CloseWrite() error { + if !ch.decided { + return errUndecided + } + ch.sentEOF = true + return ch.sendMessage(channelEOFMsg{ + PeersID: ch.remoteId}) +} + +func (ch *channel) Close() error { + if !ch.decided { + return errUndecided + } + + return ch.sendMessage(channelCloseMsg{ + PeersID: ch.remoteId}) +} + +// Extended returns an io.ReadWriter that sends and receives data on the given, +// SSH extended stream. Such streams are used, for example, for stderr. +func (ch *channel) Extended(code uint32) io.ReadWriter { + if !ch.decided { + return nil + } + return &extChannel{code, ch} +} + +func (ch *channel) Stderr() io.ReadWriter { + return ch.Extended(1) +} + +func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { + if !ch.decided { + return false, errUndecided + } + + if wantReply { + ch.sentRequestMu.Lock() + defer ch.sentRequestMu.Unlock() + } + + msg := channelRequestMsg{ + PeersID: ch.remoteId, + Request: name, + WantReply: wantReply, + RequestSpecificData: payload, + } + + if err := ch.sendMessage(msg); err != nil { + return false, err + } + + if wantReply { + m, ok := (<-ch.msg) + if !ok { + return false, io.EOF + } + switch m.(type) { + case *channelRequestFailureMsg: + return false, nil + case *channelRequestSuccessMsg: + return true, nil + default: + return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) + } + } + + return false, nil +} + +// ackRequest either sends an ack or nack to the channel request. +func (ch *channel) ackRequest(ok bool) error { + if !ch.decided { + return errUndecided + } + + var msg interface{} + if !ok { + msg = channelRequestFailureMsg{ + PeersID: ch.remoteId, + } + } else { + msg = channelRequestSuccessMsg{ + PeersID: ch.remoteId, + } + } + return ch.sendMessage(msg) +} + +func (ch *channel) ChannelType() string { + return ch.chanType +} + +func (ch *channel) ExtraData() []byte { + return ch.extraData +} diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go new file mode 100644 index 000000000..67b012610 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/cipher.go @@ -0,0 +1,770 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/rc4" + "crypto/subtle" + "encoding/binary" + "errors" + "fmt" + "hash" + "io" + "io/ioutil" + "math/bits" + + "golang.org/x/crypto/internal/chacha20" + "golang.org/x/crypto/poly1305" +) + +const ( + packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. + + // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations + // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC + // indicates implementations SHOULD be able to handle larger packet sizes, but then + // waffles on about reasonable limits. + // + // OpenSSH caps their maxPacket at 256kB so we choose to do + // the same. maxPacket is also used to ensure that uint32 + // length fields do not overflow, so it should remain well + // below 4G. + maxPacket = 256 * 1024 +) + +// noneCipher implements cipher.Stream and provides no encryption. It is used +// by the transport before the first key-exchange. +type noneCipher struct{} + +func (c noneCipher) XORKeyStream(dst, src []byte) { + copy(dst, src) +} + +func newAESCTR(key, iv []byte) (cipher.Stream, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + return cipher.NewCTR(c, iv), nil +} + +func newRC4(key, iv []byte) (cipher.Stream, error) { + return rc4.NewCipher(key) +} + +type cipherMode struct { + keySize int + ivSize int + create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) +} + +func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + stream, err := createFunc(key, iv) + if err != nil { + return nil, err + } + + var streamDump []byte + if skip > 0 { + streamDump = make([]byte, 512) + } + + for remainingToDump := skip; remainingToDump > 0; { + dumpThisTime := remainingToDump + if dumpThisTime > len(streamDump) { + dumpThisTime = len(streamDump) + } + stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) + remainingToDump -= dumpThisTime + } + + mac := macModes[algs.MAC].new(macKey) + return &streamPacketCipher{ + mac: mac, + etm: macModes[algs.MAC].etm, + macResult: make([]byte, mac.Size()), + cipher: stream, + }, nil + } +} + +// cipherModes documents properties of supported ciphers. Ciphers not included +// are not supported and will not be negotiated, even if explicitly requested in +// ClientConfig.Crypto.Ciphers. +var cipherModes = map[string]*cipherMode{ + // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms + // are defined in the order specified in the RFC. + "aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + "aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + "aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, + + // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. + // They are defined in the order specified in the RFC. + "arcfour128": {16, 0, streamCipherMode(1536, newRC4)}, + "arcfour256": {32, 0, streamCipherMode(1536, newRC4)}, + + // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. + // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and + // RC4) has problems with weak keys, and should be used with caution." + // RFC4345 introduces improved versions of Arcfour. + "arcfour": {16, 0, streamCipherMode(0, newRC4)}, + + // AEAD ciphers + gcmCipherID: {16, 12, newGCMCipher}, + chacha20Poly1305ID: {64, 0, newChaCha20Cipher}, + + // CBC mode is insecure and so is not included in the default config. + // (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely + // needed, it's possible to specify a custom Config to enable it. + // You should expect that an active attacker can recover plaintext if + // you do. + aes128cbcID: {16, aes.BlockSize, newAESCBCCipher}, + + // 3des-cbc is insecure and is not included in the default + // config. + tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher}, +} + +// prefixLen is the length of the packet prefix that contains the packet length +// and number of padding bytes. +const prefixLen = 5 + +// streamPacketCipher is a packetCipher using a stream cipher. +type streamPacketCipher struct { + mac hash.Hash + cipher cipher.Stream + etm bool + + // The following members are to avoid per-packet allocations. + prefix [prefixLen]byte + seqNumBytes [4]byte + padding [2 * packetSizeMultiple]byte + packetData []byte + macResult []byte +} + +// readPacket reads and decrypt a single packet from the reader argument. +func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { + if _, err := io.ReadFull(r, s.prefix[:]); err != nil { + return nil, err + } + + var encryptedPaddingLength [1]byte + if s.mac != nil && s.etm { + copy(encryptedPaddingLength[:], s.prefix[4:5]) + s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) + } else { + s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + } + + length := binary.BigEndian.Uint32(s.prefix[0:4]) + paddingLength := uint32(s.prefix[4]) + + var macSize uint32 + if s.mac != nil { + s.mac.Reset() + binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) + s.mac.Write(s.seqNumBytes[:]) + if s.etm { + s.mac.Write(s.prefix[:4]) + s.mac.Write(encryptedPaddingLength[:]) + } else { + s.mac.Write(s.prefix[:]) + } + macSize = uint32(s.mac.Size()) + } + + if length <= paddingLength+1 { + return nil, errors.New("ssh: invalid packet length, packet too small") + } + + if length > maxPacket { + return nil, errors.New("ssh: invalid packet length, packet too large") + } + + // the maxPacket check above ensures that length-1+macSize + // does not overflow. + if uint32(cap(s.packetData)) < length-1+macSize { + s.packetData = make([]byte, length-1+macSize) + } else { + s.packetData = s.packetData[:length-1+macSize] + } + + if _, err := io.ReadFull(r, s.packetData); err != nil { + return nil, err + } + mac := s.packetData[length-1:] + data := s.packetData[:length-1] + + if s.mac != nil && s.etm { + s.mac.Write(data) + } + + s.cipher.XORKeyStream(data, data) + + if s.mac != nil { + if !s.etm { + s.mac.Write(data) + } + s.macResult = s.mac.Sum(s.macResult[:0]) + if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { + return nil, errors.New("ssh: MAC failure") + } + } + + return s.packetData[:length-paddingLength-1], nil +} + +// writePacket encrypts and sends a packet of data to the writer argument +func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { + if len(packet) > maxPacket { + return errors.New("ssh: packet too large") + } + + aadlen := 0 + if s.mac != nil && s.etm { + // packet length is not encrypted for EtM modes + aadlen = 4 + } + + paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple + if paddingLength < 4 { + paddingLength += packetSizeMultiple + } + + length := len(packet) + 1 + paddingLength + binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) + s.prefix[4] = byte(paddingLength) + padding := s.padding[:paddingLength] + if _, err := io.ReadFull(rand, padding); err != nil { + return err + } + + if s.mac != nil { + s.mac.Reset() + binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) + s.mac.Write(s.seqNumBytes[:]) + + if s.etm { + // For EtM algorithms, the packet length must stay unencrypted, + // but the following data (padding length) must be encrypted + s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) + } + + s.mac.Write(s.prefix[:]) + + if !s.etm { + // For non-EtM algorithms, the algorithm is applied on unencrypted data + s.mac.Write(packet) + s.mac.Write(padding) + } + } + + if !(s.mac != nil && s.etm) { + // For EtM algorithms, the padding length has already been encrypted + // and the packet length must remain unencrypted + s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + } + + s.cipher.XORKeyStream(packet, packet) + s.cipher.XORKeyStream(padding, padding) + + if s.mac != nil && s.etm { + // For EtM algorithms, packet and padding must be encrypted + s.mac.Write(packet) + s.mac.Write(padding) + } + + if _, err := w.Write(s.prefix[:]); err != nil { + return err + } + if _, err := w.Write(packet); err != nil { + return err + } + if _, err := w.Write(padding); err != nil { + return err + } + + if s.mac != nil { + s.macResult = s.mac.Sum(s.macResult[:0]) + if _, err := w.Write(s.macResult); err != nil { + return err + } + } + + return nil +} + +type gcmCipher struct { + aead cipher.AEAD + prefix [4]byte + iv []byte + buf []byte +} + +func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aead, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + return &gcmCipher{ + aead: aead, + iv: iv, + }, nil +} + +const gcmTagSize = 16 + +func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { + // Pad out to multiple of 16 bytes. This is different from the + // stream cipher because that encrypts the length too. + padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) + if padding < 4 { + padding += packetSizeMultiple + } + + length := uint32(len(packet) + int(padding) + 1) + binary.BigEndian.PutUint32(c.prefix[:], length) + if _, err := w.Write(c.prefix[:]); err != nil { + return err + } + + if cap(c.buf) < int(length) { + c.buf = make([]byte, length) + } else { + c.buf = c.buf[:length] + } + + c.buf[0] = padding + copy(c.buf[1:], packet) + if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { + return err + } + c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) + if _, err := w.Write(c.buf); err != nil { + return err + } + c.incIV() + + return nil +} + +func (c *gcmCipher) incIV() { + for i := 4 + 7; i >= 4; i-- { + c.iv[i]++ + if c.iv[i] != 0 { + break + } + } +} + +func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { + if _, err := io.ReadFull(r, c.prefix[:]); err != nil { + return nil, err + } + length := binary.BigEndian.Uint32(c.prefix[:]) + if length > maxPacket { + return nil, errors.New("ssh: max packet length exceeded") + } + + if cap(c.buf) < int(length+gcmTagSize) { + c.buf = make([]byte, length+gcmTagSize) + } else { + c.buf = c.buf[:length+gcmTagSize] + } + + if _, err := io.ReadFull(r, c.buf); err != nil { + return nil, err + } + + plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) + if err != nil { + return nil, err + } + c.incIV() + + padding := plain[0] + if padding < 4 { + // padding is a byte, so it automatically satisfies + // the maximum size, which is 255. + return nil, fmt.Errorf("ssh: illegal padding %d", padding) + } + + if int(padding+1) >= len(plain) { + return nil, fmt.Errorf("ssh: padding %d too large", padding) + } + plain = plain[1 : length-uint32(padding)] + return plain, nil +} + +// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 +type cbcCipher struct { + mac hash.Hash + macSize uint32 + decrypter cipher.BlockMode + encrypter cipher.BlockMode + + // The following members are to avoid per-packet allocations. + seqNumBytes [4]byte + packetData []byte + macResult []byte + + // Amount of data we should still read to hide which + // verification error triggered. + oracleCamouflage uint32 +} + +func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + cbc := &cbcCipher{ + mac: macModes[algs.MAC].new(macKey), + decrypter: cipher.NewCBCDecrypter(c, iv), + encrypter: cipher.NewCBCEncrypter(c, iv), + packetData: make([]byte, 1024), + } + if cbc.mac != nil { + cbc.macSize = uint32(cbc.mac.Size()) + } + + return cbc, nil +} + +func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + cbc, err := newCBCCipher(c, key, iv, macKey, algs) + if err != nil { + return nil, err + } + + return cbc, nil +} + +func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + c, err := des.NewTripleDESCipher(key) + if err != nil { + return nil, err + } + + cbc, err := newCBCCipher(c, key, iv, macKey, algs) + if err != nil { + return nil, err + } + + return cbc, nil +} + +func maxUInt32(a, b int) uint32 { + if a > b { + return uint32(a) + } + return uint32(b) +} + +const ( + cbcMinPacketSizeMultiple = 8 + cbcMinPacketSize = 16 + cbcMinPaddingSize = 4 +) + +// cbcError represents a verification error that may leak information. +type cbcError string + +func (e cbcError) Error() string { return string(e) } + +func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { + p, err := c.readPacketLeaky(seqNum, r) + if err != nil { + if _, ok := err.(cbcError); ok { + // Verification error: read a fixed amount of + // data, to make distinguishing between + // failing MAC and failing length check more + // difficult. + io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) + } + } + return p, err +} + +func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { + blockSize := c.decrypter.BlockSize() + + // Read the header, which will include some of the subsequent data in the + // case of block ciphers - this is copied back to the payload later. + // How many bytes of payload/padding will be read with this first read. + firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) + firstBlock := c.packetData[:firstBlockLength] + if _, err := io.ReadFull(r, firstBlock); err != nil { + return nil, err + } + + c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength + + c.decrypter.CryptBlocks(firstBlock, firstBlock) + length := binary.BigEndian.Uint32(firstBlock[:4]) + if length > maxPacket { + return nil, cbcError("ssh: packet too large") + } + if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { + // The minimum size of a packet is 16 (or the cipher block size, whichever + // is larger) bytes. + return nil, cbcError("ssh: packet too small") + } + // The length of the packet (including the length field but not the MAC) must + // be a multiple of the block size or 8, whichever is larger. + if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { + return nil, cbcError("ssh: invalid packet length multiple") + } + + paddingLength := uint32(firstBlock[4]) + if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { + return nil, cbcError("ssh: invalid packet length") + } + + // Positions within the c.packetData buffer: + macStart := 4 + length + paddingStart := macStart - paddingLength + + // Entire packet size, starting before length, ending at end of mac. + entirePacketSize := macStart + c.macSize + + // Ensure c.packetData is large enough for the entire packet data. + if uint32(cap(c.packetData)) < entirePacketSize { + // Still need to upsize and copy, but this should be rare at runtime, only + // on upsizing the packetData buffer. + c.packetData = make([]byte, entirePacketSize) + copy(c.packetData, firstBlock) + } else { + c.packetData = c.packetData[:entirePacketSize] + } + + n, err := io.ReadFull(r, c.packetData[firstBlockLength:]) + if err != nil { + return nil, err + } + c.oracleCamouflage -= uint32(n) + + remainingCrypted := c.packetData[firstBlockLength:macStart] + c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) + + mac := c.packetData[macStart:] + if c.mac != nil { + c.mac.Reset() + binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) + c.mac.Write(c.seqNumBytes[:]) + c.mac.Write(c.packetData[:macStart]) + c.macResult = c.mac.Sum(c.macResult[:0]) + if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { + return nil, cbcError("ssh: MAC failure") + } + } + + return c.packetData[prefixLen:paddingStart], nil +} + +func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { + effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) + + // Length of encrypted portion of the packet (header, payload, padding). + // Enforce minimum padding and packet size. + encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) + // Enforce block size. + encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize + + length := encLength - 4 + paddingLength := int(length) - (1 + len(packet)) + + // Overall buffer contains: header, payload, padding, mac. + // Space for the MAC is reserved in the capacity but not the slice length. + bufferSize := encLength + c.macSize + if uint32(cap(c.packetData)) < bufferSize { + c.packetData = make([]byte, encLength, bufferSize) + } else { + c.packetData = c.packetData[:encLength] + } + + p := c.packetData + + // Packet header. + binary.BigEndian.PutUint32(p, length) + p = p[4:] + p[0] = byte(paddingLength) + + // Payload. + p = p[1:] + copy(p, packet) + + // Padding. + p = p[len(packet):] + if _, err := io.ReadFull(rand, p); err != nil { + return err + } + + if c.mac != nil { + c.mac.Reset() + binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) + c.mac.Write(c.seqNumBytes[:]) + c.mac.Write(c.packetData) + // The MAC is now appended into the capacity reserved for it earlier. + c.packetData = c.mac.Sum(c.packetData) + } + + c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) + + if _, err := w.Write(c.packetData); err != nil { + return err + } + + return nil +} + +const chacha20Poly1305ID = "chacha20-poly1305@openssh.com" + +// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com +// AEAD, which is described here: +// +// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 +// +// the methods here also implement padding, which RFC4253 Section 6 +// also requires of stream ciphers. +type chacha20Poly1305Cipher struct { + lengthKey [8]uint32 + contentKey [8]uint32 + buf []byte +} + +func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) { + if len(key) != 64 { + panic(len(key)) + } + + c := &chacha20Poly1305Cipher{ + buf: make([]byte, 256), + } + + for i := range c.contentKey { + c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4]) + } + for i := range c.lengthKey { + c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4]) + } + return c, nil +} + +func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { + nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} + s := chacha20.New(c.contentKey, nonce) + var polyKey [32]byte + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip next 32 bytes + + encryptedLength := c.buf[:4] + if _, err := io.ReadFull(r, encryptedLength); err != nil { + return nil, err + } + + var lenBytes [4]byte + chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength) + + length := binary.BigEndian.Uint32(lenBytes[:]) + if length > maxPacket { + return nil, errors.New("ssh: invalid packet length, packet too large") + } + + contentEnd := 4 + length + packetEnd := contentEnd + poly1305.TagSize + if uint32(cap(c.buf)) < packetEnd { + c.buf = make([]byte, packetEnd) + copy(c.buf[:], encryptedLength) + } else { + c.buf = c.buf[:packetEnd] + } + + if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil { + return nil, err + } + + var mac [poly1305.TagSize]byte + copy(mac[:], c.buf[contentEnd:packetEnd]) + if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) { + return nil, errors.New("ssh: MAC failure") + } + + plain := c.buf[4:contentEnd] + s.XORKeyStream(plain, plain) + + padding := plain[0] + if padding < 4 { + // padding is a byte, so it automatically satisfies + // the maximum size, which is 255. + return nil, fmt.Errorf("ssh: illegal padding %d", padding) + } + + if int(padding)+1 >= len(plain) { + return nil, fmt.Errorf("ssh: padding %d too large", padding) + } + + plain = plain[1 : len(plain)-int(padding)] + + return plain, nil +} + +func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { + nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} + s := chacha20.New(c.contentKey, nonce) + var polyKey [32]byte + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip next 32 bytes + + // There is no blocksize, so fall back to multiple of 8 byte + // padding, as described in RFC 4253, Sec 6. + const packetSizeMultiple = 8 + + padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple + if padding < 4 { + padding += packetSizeMultiple + } + + // size (4 bytes), padding (1), payload, padding, tag. + totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize + if cap(c.buf) < totalLength { + c.buf = make([]byte, totalLength) + } else { + c.buf = c.buf[:totalLength] + } + + binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) + chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4]) + c.buf[4] = byte(padding) + copy(c.buf[5:], payload) + packetEnd := 5 + len(payload) + padding + if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil { + return err + } + + s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) + + var mac [poly1305.TagSize]byte + poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) + + copy(c.buf[packetEnd:], mac[:]) + + if _, err := w.Write(c.buf); err != nil { + return err + } + return nil +} diff --git a/vendor/golang.org/x/crypto/ssh/cipher_test.go b/vendor/golang.org/x/crypto/ssh/cipher_test.go new file mode 100644 index 000000000..a52d6e486 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/cipher_test.go @@ -0,0 +1,131 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto" + "crypto/rand" + "testing" +) + +func TestDefaultCiphersExist(t *testing.T) { + for _, cipherAlgo := range supportedCiphers { + if _, ok := cipherModes[cipherAlgo]; !ok { + t.Errorf("supported cipher %q is unknown", cipherAlgo) + } + } + for _, cipherAlgo := range preferredCiphers { + if _, ok := cipherModes[cipherAlgo]; !ok { + t.Errorf("preferred cipher %q is unknown", cipherAlgo) + } + } +} + +func TestPacketCiphers(t *testing.T) { + defaultMac := "hmac-sha2-256" + defaultCipher := "aes128-ctr" + for cipher := range cipherModes { + t.Run("cipher="+cipher, + func(t *testing.T) { testPacketCipher(t, cipher, defaultMac) }) + } + for mac := range macModes { + t.Run("mac="+mac, + func(t *testing.T) { testPacketCipher(t, defaultCipher, mac) }) + } +} + +func testPacketCipher(t *testing.T, cipher, mac string) { + kr := &kexResult{Hash: crypto.SHA1} + algs := directionAlgorithms{ + Cipher: cipher, + MAC: mac, + Compression: "none", + } + client, err := newPacketCipher(clientKeys, algs, kr) + if err != nil { + t.Fatalf("newPacketCipher(client, %q, %q): %v", cipher, mac, err) + } + server, err := newPacketCipher(clientKeys, algs, kr) + if err != nil { + t.Fatalf("newPacketCipher(client, %q, %q): %v", cipher, mac, err) + } + + want := "bla bla" + input := []byte(want) + buf := &bytes.Buffer{} + if err := client.writePacket(0, buf, rand.Reader, input); err != nil { + t.Fatalf("writePacket(%q, %q): %v", cipher, mac, err) + } + + packet, err := server.readPacket(0, buf) + if err != nil { + t.Fatalf("readPacket(%q, %q): %v", cipher, mac, err) + } + + if string(packet) != want { + t.Errorf("roundtrip(%q, %q): got %q, want %q", cipher, mac, packet, want) + } +} + +func TestCBCOracleCounterMeasure(t *testing.T) { + kr := &kexResult{Hash: crypto.SHA1} + algs := directionAlgorithms{ + Cipher: aes128cbcID, + MAC: "hmac-sha1", + Compression: "none", + } + client, err := newPacketCipher(clientKeys, algs, kr) + if err != nil { + t.Fatalf("newPacketCipher(client): %v", err) + } + + want := "bla bla" + input := []byte(want) + buf := &bytes.Buffer{} + if err := client.writePacket(0, buf, rand.Reader, input); err != nil { + t.Errorf("writePacket: %v", err) + } + + packetSize := buf.Len() + buf.Write(make([]byte, 2*maxPacket)) + + // We corrupt each byte, but this usually will only test the + // 'packet too large' or 'MAC failure' cases. + lastRead := -1 + for i := 0; i < packetSize; i++ { + server, err := newPacketCipher(clientKeys, algs, kr) + if err != nil { + t.Fatalf("newPacketCipher(client): %v", err) + } + + fresh := &bytes.Buffer{} + fresh.Write(buf.Bytes()) + fresh.Bytes()[i] ^= 0x01 + + before := fresh.Len() + _, err = server.readPacket(0, fresh) + if err == nil { + t.Errorf("corrupt byte %d: readPacket succeeded ", i) + continue + } + if _, ok := err.(cbcError); !ok { + t.Errorf("corrupt byte %d: got %v (%T), want cbcError", i, err, err) + continue + } + + after := fresh.Len() + bytesRead := before - after + if bytesRead < maxPacket { + t.Errorf("corrupt byte %d: read %d bytes, want more than %d", i, bytesRead, maxPacket) + continue + } + + if i > 0 && bytesRead != lastRead { + t.Errorf("corrupt byte %d: read %d bytes, want %d bytes read", i, bytesRead, lastRead) + } + lastRead = bytesRead + } +} diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go new file mode 100644 index 000000000..ae6ca775e --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -0,0 +1,278 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "errors" + "fmt" + "net" + "os" + "sync" + "time" +) + +// Client implements a traditional SSH client that supports shells, +// subprocesses, TCP port/streamlocal forwarding and tunneled dialing. +type Client struct { + Conn + + handleForwardsOnce sync.Once // guards calling (*Client).handleForwards + + forwards forwardList // forwarded tcpip connections from the remote side + mu sync.Mutex + channelHandlers map[string]chan NewChannel +} + +// HandleChannelOpen returns a channel on which NewChannel requests +// for the given type are sent. If the type already is being handled, +// nil is returned. The channel is closed when the connection is closed. +func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { + c.mu.Lock() + defer c.mu.Unlock() + if c.channelHandlers == nil { + // The SSH channel has been closed. + c := make(chan NewChannel) + close(c) + return c + } + + ch := c.channelHandlers[channelType] + if ch != nil { + return nil + } + + ch = make(chan NewChannel, chanSize) + c.channelHandlers[channelType] = ch + return ch +} + +// NewClient creates a Client on top of the given connection. +func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { + conn := &Client{ + Conn: c, + channelHandlers: make(map[string]chan NewChannel, 1), + } + + go conn.handleGlobalRequests(reqs) + go conn.handleChannelOpens(chans) + go func() { + conn.Wait() + conn.forwards.closeAll() + }() + return conn +} + +// NewClientConn establishes an authenticated SSH connection using c +// as the underlying transport. The Request and NewChannel channels +// must be serviced or the connection will hang. +func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { + fullConf := *config + fullConf.SetDefaults() + if fullConf.HostKeyCallback == nil { + c.Close() + return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback") + } + + conn := &connection{ + sshConn: sshConn{conn: c}, + } + + if err := conn.clientHandshake(addr, &fullConf); err != nil { + c.Close() + return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) + } + conn.mux = newMux(conn.transport) + return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil +} + +// clientHandshake performs the client side key exchange. See RFC 4253 Section +// 7. +func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { + if config.ClientVersion != "" { + c.clientVersion = []byte(config.ClientVersion) + } else { + c.clientVersion = []byte(packageVersion) + } + var err error + c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) + if err != nil { + return err + } + + c.transport = newClientTransport( + newTransport(c.sshConn.conn, config.Rand, true /* is client */), + c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) + if err := c.transport.waitSession(); err != nil { + return err + } + + c.sessionID = c.transport.getSessionID() + return c.clientAuthenticate(config) +} + +// verifyHostKeySignature verifies the host key obtained in the key +// exchange. +func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { + sig, rest, ok := parseSignatureBody(result.Signature) + if len(rest) > 0 || !ok { + return errors.New("ssh: signature parse error") + } + + return hostKey.Verify(result.H, sig) +} + +// NewSession opens a new Session for this client. (A session is a remote +// execution of a program.) +func (c *Client) NewSession() (*Session, error) { + ch, in, err := c.OpenChannel("session", nil) + if err != nil { + return nil, err + } + return newSession(ch, in) +} + +func (c *Client) handleGlobalRequests(incoming <-chan *Request) { + for r := range incoming { + // This handles keepalive messages and matches + // the behaviour of OpenSSH. + r.Reply(false, nil) + } +} + +// handleChannelOpens channel open messages from the remote side. +func (c *Client) handleChannelOpens(in <-chan NewChannel) { + for ch := range in { + c.mu.Lock() + handler := c.channelHandlers[ch.ChannelType()] + c.mu.Unlock() + + if handler != nil { + handler <- ch + } else { + ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) + } + } + + c.mu.Lock() + for _, ch := range c.channelHandlers { + close(ch) + } + c.channelHandlers = nil + c.mu.Unlock() +} + +// Dial starts a client connection to the given SSH server. It is a +// convenience function that connects to the given network address, +// initiates the SSH handshake, and then sets up a Client. For access +// to incoming channels and requests, use net.Dial with NewClientConn +// instead. +func Dial(network, addr string, config *ClientConfig) (*Client, error) { + conn, err := net.DialTimeout(network, addr, config.Timeout) + if err != nil { + return nil, err + } + c, chans, reqs, err := NewClientConn(conn, addr, config) + if err != nil { + return nil, err + } + return NewClient(c, chans, reqs), nil +} + +// HostKeyCallback is the function type used for verifying server +// keys. A HostKeyCallback must return nil if the host key is OK, or +// an error to reject it. It receives the hostname as passed to Dial +// or NewClientConn. The remote address is the RemoteAddr of the +// net.Conn underlying the the SSH connection. +type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error + +// BannerCallback is the function type used for treat the banner sent by +// the server. A BannerCallback receives the message sent by the remote server. +type BannerCallback func(message string) error + +// A ClientConfig structure is used to configure a Client. It must not be +// modified after having been passed to an SSH function. +type ClientConfig struct { + // Config contains configuration that is shared between clients and + // servers. + Config + + // User contains the username to authenticate as. + User string + + // Auth contains possible authentication methods to use with the + // server. Only the first instance of a particular RFC 4252 method will + // be used during authentication. + Auth []AuthMethod + + // HostKeyCallback is called during the cryptographic + // handshake to validate the server's host key. The client + // configuration must supply this callback for the connection + // to succeed. The functions InsecureIgnoreHostKey or + // FixedHostKey can be used for simplistic host key checks. + HostKeyCallback HostKeyCallback + + // BannerCallback is called during the SSH dance to display a custom + // server's message. The client configuration can supply this callback to + // handle it as wished. The function BannerDisplayStderr can be used for + // simplistic display on Stderr. + BannerCallback BannerCallback + + // ClientVersion contains the version identification string that will + // be used for the connection. If empty, a reasonable default is used. + ClientVersion string + + // HostKeyAlgorithms lists the key types that the client will + // accept from the server as host key, in order of + // preference. If empty, a reasonable default is used. Any + // string returned from PublicKey.Type method may be used, or + // any of the CertAlgoXxxx and KeyAlgoXxxx constants. + HostKeyAlgorithms []string + + // Timeout is the maximum amount of time for the TCP connection to establish. + // + // A Timeout of zero means no timeout. + Timeout time.Duration +} + +// InsecureIgnoreHostKey returns a function that can be used for +// ClientConfig.HostKeyCallback to accept any host key. It should +// not be used for production code. +func InsecureIgnoreHostKey() HostKeyCallback { + return func(hostname string, remote net.Addr, key PublicKey) error { + return nil + } +} + +type fixedHostKey struct { + key PublicKey +} + +func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error { + if f.key == nil { + return fmt.Errorf("ssh: required host key was nil") + } + if !bytes.Equal(key.Marshal(), f.key.Marshal()) { + return fmt.Errorf("ssh: host key mismatch") + } + return nil +} + +// FixedHostKey returns a function for use in +// ClientConfig.HostKeyCallback to accept only a specific host key. +func FixedHostKey(key PublicKey) HostKeyCallback { + hk := &fixedHostKey{key} + return hk.check +} + +// BannerDisplayStderr returns a function that can be used for +// ClientConfig.BannerCallback to display banners on os.Stderr. +func BannerDisplayStderr() BannerCallback { + return func(banner string) error { + _, err := os.Stderr.WriteString(banner) + + return err + } +} diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go new file mode 100644 index 000000000..5f44b7740 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -0,0 +1,525 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "errors" + "fmt" + "io" +) + +type authResult int + +const ( + authFailure authResult = iota + authPartialSuccess + authSuccess +) + +// clientAuthenticate authenticates with the remote server. See RFC 4252. +func (c *connection) clientAuthenticate(config *ClientConfig) error { + // initiate user auth session + if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { + return err + } + packet, err := c.transport.readPacket() + if err != nil { + return err + } + var serviceAccept serviceAcceptMsg + if err := Unmarshal(packet, &serviceAccept); err != nil { + return err + } + + // during the authentication phase the client first attempts the "none" method + // then any untried methods suggested by the server. + tried := make(map[string]bool) + var lastMethods []string + + sessionID := c.transport.getSessionID() + for auth := AuthMethod(new(noneAuth)); auth != nil; { + ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) + if err != nil { + return err + } + if ok == authSuccess { + // success + return nil + } else if ok == authFailure { + tried[auth.method()] = true + } + if methods == nil { + methods = lastMethods + } + lastMethods = methods + + auth = nil + + findNext: + for _, a := range config.Auth { + candidateMethod := a.method() + if tried[candidateMethod] { + continue + } + for _, meth := range methods { + if meth == candidateMethod { + auth = a + break findNext + } + } + } + } + return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried)) +} + +func keys(m map[string]bool) []string { + s := make([]string, 0, len(m)) + + for key := range m { + s = append(s, key) + } + return s +} + +// An AuthMethod represents an instance of an RFC 4252 authentication method. +type AuthMethod interface { + // auth authenticates user over transport t. + // Returns true if authentication is successful. + // If authentication is not successful, a []string of alternative + // method names is returned. If the slice is nil, it will be ignored + // and the previous set of possible methods will be reused. + auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error) + + // method returns the RFC 4252 method name. + method() string +} + +// "none" authentication, RFC 4252 section 5.2. +type noneAuth int + +func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { + if err := c.writePacket(Marshal(&userAuthRequestMsg{ + User: user, + Service: serviceSSH, + Method: "none", + })); err != nil { + return authFailure, nil, err + } + + return handleAuthResponse(c) +} + +func (n *noneAuth) method() string { + return "none" +} + +// passwordCallback is an AuthMethod that fetches the password through +// a function call, e.g. by prompting the user. +type passwordCallback func() (password string, err error) + +func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { + type passwordAuthMsg struct { + User string `sshtype:"50"` + Service string + Method string + Reply bool + Password string + } + + pw, err := cb() + // REVIEW NOTE: is there a need to support skipping a password attempt? + // The program may only find out that the user doesn't have a password + // when prompting. + if err != nil { + return authFailure, nil, err + } + + if err := c.writePacket(Marshal(&passwordAuthMsg{ + User: user, + Service: serviceSSH, + Method: cb.method(), + Reply: false, + Password: pw, + })); err != nil { + return authFailure, nil, err + } + + return handleAuthResponse(c) +} + +func (cb passwordCallback) method() string { + return "password" +} + +// Password returns an AuthMethod using the given password. +func Password(secret string) AuthMethod { + return passwordCallback(func() (string, error) { return secret, nil }) +} + +// PasswordCallback returns an AuthMethod that uses a callback for +// fetching a password. +func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { + return passwordCallback(prompt) +} + +type publickeyAuthMsg struct { + User string `sshtype:"50"` + Service string + Method string + // HasSig indicates to the receiver packet that the auth request is signed and + // should be used for authentication of the request. + HasSig bool + Algoname string + PubKey []byte + // Sig is tagged with "rest" so Marshal will exclude it during + // validateKey + Sig []byte `ssh:"rest"` +} + +// publicKeyCallback is an AuthMethod that uses a set of key +// pairs for authentication. +type publicKeyCallback func() ([]Signer, error) + +func (cb publicKeyCallback) method() string { + return "publickey" +} + +func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { + // Authentication is performed by sending an enquiry to test if a key is + // acceptable to the remote. If the key is acceptable, the client will + // attempt to authenticate with the valid key. If not the client will repeat + // the process with the remaining keys. + + signers, err := cb() + if err != nil { + return authFailure, nil, err + } + var methods []string + for _, signer := range signers { + ok, err := validateKey(signer.PublicKey(), user, c) + if err != nil { + return authFailure, nil, err + } + if !ok { + continue + } + + pub := signer.PublicKey() + pubKey := pub.Marshal() + sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ + User: user, + Service: serviceSSH, + Method: cb.method(), + }, []byte(pub.Type()), pubKey)) + if err != nil { + return authFailure, nil, err + } + + // manually wrap the serialized signature in a string + s := Marshal(sign) + sig := make([]byte, stringLength(len(s))) + marshalString(sig, s) + msg := publickeyAuthMsg{ + User: user, + Service: serviceSSH, + Method: cb.method(), + HasSig: true, + Algoname: pub.Type(), + PubKey: pubKey, + Sig: sig, + } + p := Marshal(&msg) + if err := c.writePacket(p); err != nil { + return authFailure, nil, err + } + var success authResult + success, methods, err = handleAuthResponse(c) + if err != nil { + return authFailure, nil, err + } + + // If authentication succeeds or the list of available methods does not + // contain the "publickey" method, do not attempt to authenticate with any + // other keys. According to RFC 4252 Section 7, the latter can occur when + // additional authentication methods are required. + if success == authSuccess || !containsMethod(methods, cb.method()) { + return success, methods, err + } + } + + return authFailure, methods, nil +} + +func containsMethod(methods []string, method string) bool { + for _, m := range methods { + if m == method { + return true + } + } + + return false +} + +// validateKey validates the key provided is acceptable to the server. +func validateKey(key PublicKey, user string, c packetConn) (bool, error) { + pubKey := key.Marshal() + msg := publickeyAuthMsg{ + User: user, + Service: serviceSSH, + Method: "publickey", + HasSig: false, + Algoname: key.Type(), + PubKey: pubKey, + } + if err := c.writePacket(Marshal(&msg)); err != nil { + return false, err + } + + return confirmKeyAck(key, c) +} + +func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { + pubKey := key.Marshal() + algoname := key.Type() + + for { + packet, err := c.readPacket() + if err != nil { + return false, err + } + switch packet[0] { + case msgUserAuthBanner: + if err := handleBannerResponse(c, packet); err != nil { + return false, err + } + case msgUserAuthPubKeyOk: + var msg userAuthPubKeyOkMsg + if err := Unmarshal(packet, &msg); err != nil { + return false, err + } + if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { + return false, nil + } + return true, nil + case msgUserAuthFailure: + return false, nil + default: + return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) + } + } +} + +// PublicKeys returns an AuthMethod that uses the given key +// pairs. +func PublicKeys(signers ...Signer) AuthMethod { + return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) +} + +// PublicKeysCallback returns an AuthMethod that runs the given +// function to obtain a list of key pairs. +func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { + return publicKeyCallback(getSigners) +} + +// handleAuthResponse returns whether the preceding authentication request succeeded +// along with a list of remaining authentication methods to try next and +// an error if an unexpected response was received. +func handleAuthResponse(c packetConn) (authResult, []string, error) { + for { + packet, err := c.readPacket() + if err != nil { + return authFailure, nil, err + } + + switch packet[0] { + case msgUserAuthBanner: + if err := handleBannerResponse(c, packet); err != nil { + return authFailure, nil, err + } + case msgUserAuthFailure: + var msg userAuthFailureMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil + case msgUserAuthSuccess: + return authSuccess, nil, nil + default: + return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) + } + } +} + +func handleBannerResponse(c packetConn, packet []byte) error { + var msg userAuthBannerMsg + if err := Unmarshal(packet, &msg); err != nil { + return err + } + + transport, ok := c.(*handshakeTransport) + if !ok { + return nil + } + + if transport.bannerCallback != nil { + return transport.bannerCallback(msg.Message) + } + + return nil +} + +// KeyboardInteractiveChallenge should print questions, optionally +// disabling echoing (e.g. for passwords), and return all the answers. +// Challenge may be called multiple times in a single session. After +// successful authentication, the server may send a challenge with no +// questions, for which the user and instruction messages should be +// printed. RFC 4256 section 3.3 details how the UI should behave for +// both CLI and GUI environments. +type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) + +// KeyboardInteractive returns an AuthMethod using a prompt/response +// sequence controlled by the server. +func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { + return challenge +} + +func (cb KeyboardInteractiveChallenge) method() string { + return "keyboard-interactive" +} + +func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { + type initiateMsg struct { + User string `sshtype:"50"` + Service string + Method string + Language string + Submethods string + } + + if err := c.writePacket(Marshal(&initiateMsg{ + User: user, + Service: serviceSSH, + Method: "keyboard-interactive", + })); err != nil { + return authFailure, nil, err + } + + for { + packet, err := c.readPacket() + if err != nil { + return authFailure, nil, err + } + + // like handleAuthResponse, but with less options. + switch packet[0] { + case msgUserAuthBanner: + if err := handleBannerResponse(c, packet); err != nil { + return authFailure, nil, err + } + continue + case msgUserAuthInfoRequest: + // OK + case msgUserAuthFailure: + var msg userAuthFailureMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + if msg.PartialSuccess { + return authPartialSuccess, msg.Methods, nil + } + return authFailure, msg.Methods, nil + case msgUserAuthSuccess: + return authSuccess, nil, nil + default: + return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) + } + + var msg userAuthInfoRequestMsg + if err := Unmarshal(packet, &msg); err != nil { + return authFailure, nil, err + } + + // Manually unpack the prompt/echo pairs. + rest := msg.Prompts + var prompts []string + var echos []bool + for i := 0; i < int(msg.NumPrompts); i++ { + prompt, r, ok := parseString(rest) + if !ok || len(r) == 0 { + return authFailure, nil, errors.New("ssh: prompt format error") + } + prompts = append(prompts, string(prompt)) + echos = append(echos, r[0] != 0) + rest = r[1:] + } + + if len(rest) != 0 { + return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") + } + + answers, err := cb(msg.User, msg.Instruction, prompts, echos) + if err != nil { + return authFailure, nil, err + } + + if len(answers) != len(prompts) { + return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") + } + responseLength := 1 + 4 + for _, a := range answers { + responseLength += stringLength(len(a)) + } + serialized := make([]byte, responseLength) + p := serialized + p[0] = msgUserAuthInfoResponse + p = p[1:] + p = marshalUint32(p, uint32(len(answers))) + for _, a := range answers { + p = marshalString(p, []byte(a)) + } + + if err := c.writePacket(serialized); err != nil { + return authFailure, nil, err + } + } +} + +type retryableAuthMethod struct { + authMethod AuthMethod + maxTries int +} + +func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) { + for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { + ok, methods, err = r.authMethod.auth(session, user, c, rand) + if ok != authFailure || err != nil { // either success, partial success or error terminate + return ok, methods, err + } + } + return ok, methods, err +} + +func (r *retryableAuthMethod) method() string { + return r.authMethod.method() +} + +// RetryableAuthMethod is a decorator for other auth methods enabling them to +// be retried up to maxTries before considering that AuthMethod itself failed. +// If maxTries is <= 0, will retry indefinitely +// +// This is useful for interactive clients using challenge/response type +// authentication (e.g. Keyboard-Interactive, Password, etc) where the user +// could mistype their response resulting in the server issuing a +// SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 +// [keyboard-interactive]); Without this decorator, the non-retryable +// AuthMethod would be removed from future consideration, and never tried again +// (and so the user would never be able to retry their entry). +func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { + return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} +} diff --git a/vendor/golang.org/x/crypto/ssh/client_auth_test.go b/vendor/golang.org/x/crypto/ssh/client_auth_test.go new file mode 100644 index 000000000..5fbb20d85 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client_auth_test.go @@ -0,0 +1,628 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + "os" + "strings" + "testing" +) + +type keyboardInteractive map[string]string + +func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) { + var answers []string + for _, q := range questions { + answers = append(answers, cr[q]) + } + return answers, nil +} + +// reused internally by tests +var clientPassword = "tiger" + +// tryAuth runs a handshake with a given config against an SSH server +// with config serverConfig +func tryAuth(t *testing.T, config *ClientConfig) error { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + certChecker := CertChecker{ + IsUserAuthority: func(k PublicKey) bool { + return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal()) + }, + UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { + return nil, nil + } + + return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User()) + }, + IsRevoked: func(c *Certificate) bool { + return c.Serial == 666 + }, + } + + serverConfig := &ServerConfig{ + PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) { + if conn.User() == "testuser" && string(pass) == clientPassword { + return nil, nil + } + return nil, errors.New("password auth failed") + }, + PublicKeyCallback: certChecker.Authenticate, + KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) { + ans, err := challenge("user", + "instruction", + []string{"question1", "question2"}, + []bool{true, true}) + if err != nil { + return nil, err + } + ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2" + if ok { + challenge("user", "motd", nil, nil) + return nil, nil + } + return nil, errors.New("keyboard-interactive failed") + }, + } + serverConfig.AddHostKey(testSigners["rsa"]) + + go newServer(c1, serverConfig) + _, _, _, err = NewClientConn(c2, "", config) + return err +} + +func TestClientAuthPublicKey(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } +} + +func TestAuthMethodPassword(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + Password(clientPassword), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } +} + +func TestAuthMethodFallback(t *testing.T) { + var passwordCalled bool + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + PasswordCallback( + func() (string, error) { + passwordCalled = true + return "WRONG", nil + }), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } + + if passwordCalled { + t.Errorf("password auth tried before public-key auth.") + } +} + +func TestAuthMethodWrongPassword(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + Password("wrong"), + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } +} + +func TestAuthMethodKeyboardInteractive(t *testing.T) { + answers := keyboardInteractive(map[string]string{ + "question1": "answer1", + "question2": "answer2", + }) + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + KeyboardInteractive(answers.Challenge), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } +} + +func TestAuthMethodWrongKeyboardInteractive(t *testing.T) { + answers := keyboardInteractive(map[string]string{ + "question1": "answer1", + "question2": "WRONG", + }) + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + KeyboardInteractive(answers.Challenge), + }, + } + + if err := tryAuth(t, config); err == nil { + t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive") + } +} + +// the mock server will only authenticate ssh-rsa keys +func TestAuthMethodInvalidPublicKey(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(testSigners["dsa"]), + }, + } + + if err := tryAuth(t, config); err == nil { + t.Fatalf("dsa private key should not have authenticated with rsa public key") + } +} + +// the client should authenticate with the second key +func TestAuthMethodRSAandDSA(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(testSigners["dsa"], testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if err := tryAuth(t, config); err != nil { + t.Fatalf("client could not authenticate with rsa key: %v", err) + } +} + +func TestClientHMAC(t *testing.T) { + for _, mac := range supportedMACs { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + Config: Config{ + MACs: []string{mac}, + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if err := tryAuth(t, config); err != nil { + t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err) + } + } +} + +// issue 4285. +func TestClientUnsupportedCipher(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(), + }, + Config: Config{ + Ciphers: []string{"aes128-cbc"}, // not currently supported + }, + } + if err := tryAuth(t, config); err == nil { + t.Errorf("expected no ciphers in common") + } +} + +func TestClientUnsupportedKex(t *testing.T) { + if os.Getenv("GO_BUILDER_NAME") != "" { + t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198") + } + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(), + }, + Config: Config{ + KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") { + t.Errorf("got %v, expected 'common algorithm'", err) + } +} + +func TestClientLoginCert(t *testing.T) { + cert := &Certificate{ + Key: testPublicKeys["rsa"], + ValidBefore: CertTimeInfinity, + CertType: UserCert, + } + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + certSigner, err := NewCertSigner(cert, testSigners["rsa"]) + if err != nil { + t.Fatalf("NewCertSigner: %v", err) + } + + clientConfig := &ClientConfig{ + User: "user", + HostKeyCallback: InsecureIgnoreHostKey(), + } + clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner)) + + // should succeed + if err := tryAuth(t, clientConfig); err != nil { + t.Errorf("cert login failed: %v", err) + } + + // corrupted signature + cert.Signature.Blob[0]++ + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("cert login passed with corrupted sig") + } + + // revoked + cert.Serial = 666 + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("revoked cert login succeeded") + } + cert.Serial = 1 + + // sign with wrong key + cert.SignCert(rand.Reader, testSigners["dsa"]) + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("cert login passed with non-authoritative key") + } + + // host cert + cert.CertType = HostCert + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("cert login passed with wrong type") + } + cert.CertType = UserCert + + // principal specified + cert.ValidPrincipals = []string{"user"} + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err != nil { + t.Errorf("cert login failed: %v", err) + } + + // wrong principal specified + cert.ValidPrincipals = []string{"fred"} + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("cert login passed with wrong principal") + } + cert.ValidPrincipals = nil + + // added critical option + cert.CriticalOptions = map[string]string{"root-access": "yes"} + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("cert login passed with unrecognized critical option") + } + + // allowed source address + cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"} + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err != nil { + t.Errorf("cert login with source-address failed: %v", err) + } + + // disallowed source address + cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"} + cert.SignCert(rand.Reader, testSigners["ecdsa"]) + if err := tryAuth(t, clientConfig); err == nil { + t.Errorf("cert login with source-address succeeded") + } +} + +func testPermissionsPassing(withPermissions bool, t *testing.T) { + serverConfig := &ServerConfig{ + PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { + if conn.User() == "nopermissions" { + return nil, nil + } + return &Permissions{}, nil + }, + } + serverConfig.AddHostKey(testSigners["rsa"]) + + clientConfig := &ClientConfig{ + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if withPermissions { + clientConfig.User = "permissions" + } else { + clientConfig.User = "nopermissions" + } + + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go NewClientConn(c2, "", clientConfig) + serverConn, err := newServer(c1, serverConfig) + if err != nil { + t.Fatal(err) + } + if p := serverConn.Permissions; (p != nil) != withPermissions { + t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p) + } +} + +func TestPermissionsPassing(t *testing.T) { + testPermissionsPassing(true, t) +} + +func TestNoPermissionsPassing(t *testing.T) { + testPermissionsPassing(false, t) +} + +func TestRetryableAuth(t *testing.T) { + n := 0 + passwords := []string{"WRONG1", "WRONG2"} + + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + RetryableAuthMethod(PasswordCallback(func() (string, error) { + p := passwords[n] + n++ + return p, nil + }), 2), + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } + if n != 2 { + t.Fatalf("Did not try all passwords") + } +} + +func ExampleRetryableAuthMethod(t *testing.T) { + user := "testuser" + NumberOfPrompts := 3 + + // Normally this would be a callback that prompts the user to answer the + // provided questions + Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { + return []string{"answer1", "answer2"}, nil + } + + config := &ClientConfig{ + HostKeyCallback: InsecureIgnoreHostKey(), + User: user, + Auth: []AuthMethod{ + RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts), + }, + } + + if err := tryAuth(t, config); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } +} + +// Test if username is received on server side when NoClientAuth is used +func TestClientAuthNone(t *testing.T) { + user := "testuser" + serverConfig := &ServerConfig{ + NoClientAuth: true, + } + serverConfig.AddHostKey(testSigners["rsa"]) + + clientConfig := &ClientConfig{ + User: user, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go NewClientConn(c2, "", clientConfig) + serverConn, err := newServer(c1, serverConfig) + if err != nil { + t.Fatalf("newServer: %v", err) + } + if serverConn.User() != user { + t.Fatalf("server: got %q, want %q", serverConn.User(), user) + } +} + +// Test if authentication attempts are limited on server when MaxAuthTries is set +func TestClientAuthMaxAuthTries(t *testing.T) { + user := "testuser" + + serverConfig := &ServerConfig{ + MaxAuthTries: 2, + PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) { + if conn.User() == "testuser" && string(pass) == "right" { + return nil, nil + } + return nil, errors.New("password auth failed") + }, + } + serverConfig.AddHostKey(testSigners["rsa"]) + + expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{ + Reason: 2, + Message: "too many authentication failures", + }) + + for tries := 2; tries < 4; tries++ { + n := tries + clientConfig := &ClientConfig{ + User: user, + Auth: []AuthMethod{ + RetryableAuthMethod(PasswordCallback(func() (string, error) { + n-- + if n == 0 { + return "right", nil + } + return "wrong", nil + }), tries), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go newServer(c1, serverConfig) + _, _, _, err = NewClientConn(c2, "", clientConfig) + if tries > 2 { + if err == nil { + t.Fatalf("client: got no error, want %s", expectedErr) + } else if err.Error() != expectedErr.Error() { + t.Fatalf("client: got %s, want %s", err, expectedErr) + } + } else { + if err != nil { + t.Fatalf("client: got %s, want no error", err) + } + } + } +} + +// Test if authentication attempts are correctly limited on server +// when more public keys are provided then MaxAuthTries +func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) { + signers := []Signer{} + for i := 0; i < 6; i++ { + signers = append(signers, testSigners["dsa"]) + } + + validConfig := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if err := tryAuth(t, validConfig); err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } + + expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{ + Reason: 2, + Message: "too many authentication failures", + }) + invalidConfig := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(append(signers, testSigners["rsa"])...), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + if err := tryAuth(t, invalidConfig); err == nil { + t.Fatalf("client: got no error, want %s", expectedErr) + } else if err.Error() != expectedErr.Error() { + t.Fatalf("client: got %s, want %s", err, expectedErr) + } +} + +// Test whether authentication errors are being properly logged if all +// authentication methods have been exhausted +func TestClientAuthErrorList(t *testing.T) { + publicKeyErr := errors.New("This is an error from PublicKeyCallback") + + clientConfig := &ClientConfig{ + Auth: []AuthMethod{ + PublicKeys(testSigners["rsa"]), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + serverConfig := &ServerConfig{ + PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) { + return nil, publicKeyErr + }, + } + serverConfig.AddHostKey(testSigners["rsa"]) + + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go NewClientConn(c2, "", clientConfig) + _, err = newServer(c1, serverConfig) + if err == nil { + t.Fatal("newServer: got nil, expected errors") + } + + authErrs, ok := err.(*ServerAuthError) + if !ok { + t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err) + } + for i, e := range authErrs.Errors { + switch i { + case 0: + if e != ErrNoAuth { + t.Fatalf("errors: got error %v, want ErrNoAuth", e) + } + case 1: + if e != publicKeyErr { + t.Fatalf("errors: got %v, want %v", e, publicKeyErr) + } + default: + t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors) + } + } +} diff --git a/vendor/golang.org/x/crypto/ssh/client_test.go b/vendor/golang.org/x/crypto/ssh/client_test.go new file mode 100644 index 000000000..81f9599e1 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client_test.go @@ -0,0 +1,166 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "strings" + "testing" +) + +func TestClientVersion(t *testing.T) { + for _, tt := range []struct { + name string + version string + multiLine string + wantErr bool + }{ + { + name: "default version", + version: packageVersion, + }, + { + name: "custom version", + version: "SSH-2.0-CustomClientVersionString", + }, + { + name: "good multi line version", + version: packageVersion, + multiLine: strings.Repeat("ignored\r\n", 20), + }, + { + name: "bad multi line version", + version: packageVersion, + multiLine: "bad multi line version", + wantErr: true, + }, + { + name: "long multi line version", + version: packageVersion, + multiLine: strings.Repeat("long multi line version\r\n", 50)[:256], + wantErr: true, + }, + } { + t.Run(tt.name, func(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + go func() { + if tt.multiLine != "" { + c1.Write([]byte(tt.multiLine)) + } + NewClientConn(c1, "", &ClientConfig{ + ClientVersion: tt.version, + HostKeyCallback: InsecureIgnoreHostKey(), + }) + c1.Close() + }() + conf := &ServerConfig{NoClientAuth: true} + conf.AddHostKey(testSigners["rsa"]) + conn, _, _, err := NewServerConn(c2, conf) + if err == nil == tt.wantErr { + t.Fatalf("got err %v; wantErr %t", err, tt.wantErr) + } + if tt.wantErr { + // Don't verify the version on an expected error. + return + } + if got := string(conn.ClientVersion()); got != tt.version { + t.Fatalf("got %q; want %q", got, tt.version) + } + }) + } +} + +func TestHostKeyCheck(t *testing.T) { + for _, tt := range []struct { + name string + wantError string + key PublicKey + }{ + {"no callback", "must specify HostKeyCallback", nil}, + {"correct key", "", testSigners["rsa"].PublicKey()}, + {"mismatch", "mismatch", testSigners["ecdsa"].PublicKey()}, + } { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + serverConf := &ServerConfig{ + NoClientAuth: true, + } + serverConf.AddHostKey(testSigners["rsa"]) + + go NewServerConn(c1, serverConf) + clientConf := ClientConfig{ + User: "user", + } + if tt.key != nil { + clientConf.HostKeyCallback = FixedHostKey(tt.key) + } + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err != nil { + if tt.wantError == "" || !strings.Contains(err.Error(), tt.wantError) { + t.Errorf("%s: got error %q, missing %q", tt.name, err.Error(), tt.wantError) + } + } else if tt.wantError != "" { + t.Errorf("%s: succeeded, but want error string %q", tt.name, tt.wantError) + } + } +} + +func TestBannerCallback(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverConf := &ServerConfig{ + PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { + return &Permissions{}, nil + }, + BannerCallback: func(conn ConnMetadata) string { + return "Hello World" + }, + } + serverConf.AddHostKey(testSigners["rsa"]) + go NewServerConn(c1, serverConf) + + var receivedBanner string + var bannerCount int + clientConf := ClientConfig{ + Auth: []AuthMethod{ + Password("123"), + }, + User: "user", + HostKeyCallback: InsecureIgnoreHostKey(), + BannerCallback: func(message string) error { + bannerCount++ + receivedBanner = message + return nil + }, + } + + _, _, _, err = NewClientConn(c2, "", &clientConf) + if err != nil { + t.Fatal(err) + } + + if bannerCount != 1 { + t.Errorf("got %d banners; want 1", bannerCount) + } + + expected := "Hello World" + if receivedBanner != expected { + t.Fatalf("got %s; want %s", receivedBanner, expected) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go new file mode 100644 index 000000000..04f3620b3 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -0,0 +1,383 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "crypto" + "crypto/rand" + "fmt" + "io" + "math" + "sync" + + _ "crypto/sha1" + _ "crypto/sha256" + _ "crypto/sha512" +) + +// These are string constants in the SSH protocol. +const ( + compressionNone = "none" + serviceUserAuth = "ssh-userauth" + serviceSSH = "ssh-connection" +) + +// supportedCiphers lists ciphers we support but might not recommend. +var supportedCiphers = []string{ + "aes128-ctr", "aes192-ctr", "aes256-ctr", + "aes128-gcm@openssh.com", + chacha20Poly1305ID, + "arcfour256", "arcfour128", "arcfour", + aes128cbcID, + tripledescbcID, +} + +// preferredCiphers specifies the default preference for ciphers. +var preferredCiphers = []string{ + "aes128-gcm@openssh.com", + chacha20Poly1305ID, + "aes128-ctr", "aes192-ctr", "aes256-ctr", +} + +// supportedKexAlgos specifies the supported key-exchange algorithms in +// preference order. +var supportedKexAlgos = []string{ + kexAlgoCurve25519SHA256, + // P384 and P521 are not constant-time yet, but since we don't + // reuse ephemeral keys, using them for ECDH should be OK. + kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, + kexAlgoDH14SHA1, kexAlgoDH1SHA1, +} + +// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods +// of authenticating servers) in preference order. +var supportedHostKeyAlgos = []string{ + CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, + CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, + + KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, + KeyAlgoRSA, KeyAlgoDSA, + + KeyAlgoED25519, +} + +// supportedMACs specifies a default set of MAC algorithms in preference order. +// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed +// because they have reached the end of their useful life. +var supportedMACs = []string{ + "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", +} + +var supportedCompressions = []string{compressionNone} + +// hashFuncs keeps the mapping of supported algorithms to their respective +// hashes needed for signature verification. +var hashFuncs = map[string]crypto.Hash{ + KeyAlgoRSA: crypto.SHA1, + KeyAlgoDSA: crypto.SHA1, + KeyAlgoECDSA256: crypto.SHA256, + KeyAlgoECDSA384: crypto.SHA384, + KeyAlgoECDSA521: crypto.SHA512, + CertAlgoRSAv01: crypto.SHA1, + CertAlgoDSAv01: crypto.SHA1, + CertAlgoECDSA256v01: crypto.SHA256, + CertAlgoECDSA384v01: crypto.SHA384, + CertAlgoECDSA521v01: crypto.SHA512, +} + +// unexpectedMessageError results when the SSH message that we received didn't +// match what we wanted. +func unexpectedMessageError(expected, got uint8) error { + return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) +} + +// parseError results from a malformed SSH message. +func parseError(tag uint8) error { + return fmt.Errorf("ssh: parse error in message type %d", tag) +} + +func findCommon(what string, client []string, server []string) (common string, err error) { + for _, c := range client { + for _, s := range server { + if c == s { + return c, nil + } + } + } + return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) +} + +type directionAlgorithms struct { + Cipher string + MAC string + Compression string +} + +// rekeyBytes returns a rekeying intervals in bytes. +func (a *directionAlgorithms) rekeyBytes() int64 { + // According to RFC4344 block ciphers should rekey after + // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is + // 128. + switch a.Cipher { + case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID: + return 16 * (1 << 32) + + } + + // For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. + return 1 << 30 +} + +type algorithms struct { + kex string + hostKey string + w directionAlgorithms + r directionAlgorithms +} + +func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { + result := &algorithms{} + + result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) + if err != nil { + return + } + + result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) + if err != nil { + return + } + + result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) + if err != nil { + return + } + + result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) + if err != nil { + return + } + + result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) + if err != nil { + return + } + + result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) + if err != nil { + return + } + + result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) + if err != nil { + return + } + + result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) + if err != nil { + return + } + + return result, nil +} + +// If rekeythreshold is too small, we can't make any progress sending +// stuff. +const minRekeyThreshold uint64 = 256 + +// Config contains configuration data common to both ServerConfig and +// ClientConfig. +type Config struct { + // Rand provides the source of entropy for cryptographic + // primitives. If Rand is nil, the cryptographic random reader + // in package crypto/rand will be used. + Rand io.Reader + + // The maximum number of bytes sent or received after which a + // new key is negotiated. It must be at least 256. If + // unspecified, a size suitable for the chosen cipher is used. + RekeyThreshold uint64 + + // The allowed key exchanges algorithms. If unspecified then a + // default set of algorithms is used. + KeyExchanges []string + + // The allowed cipher algorithms. If unspecified then a sensible + // default is used. + Ciphers []string + + // The allowed MAC algorithms. If unspecified then a sensible default + // is used. + MACs []string +} + +// SetDefaults sets sensible values for unset fields in config. This is +// exported for testing: Configs passed to SSH functions are copied and have +// default values set automatically. +func (c *Config) SetDefaults() { + if c.Rand == nil { + c.Rand = rand.Reader + } + if c.Ciphers == nil { + c.Ciphers = preferredCiphers + } + var ciphers []string + for _, c := range c.Ciphers { + if cipherModes[c] != nil { + // reject the cipher if we have no cipherModes definition + ciphers = append(ciphers, c) + } + } + c.Ciphers = ciphers + + if c.KeyExchanges == nil { + c.KeyExchanges = supportedKexAlgos + } + + if c.MACs == nil { + c.MACs = supportedMACs + } + + if c.RekeyThreshold == 0 { + // cipher specific default + } else if c.RekeyThreshold < minRekeyThreshold { + c.RekeyThreshold = minRekeyThreshold + } else if c.RekeyThreshold >= math.MaxInt64 { + // Avoid weirdness if somebody uses -1 as a threshold. + c.RekeyThreshold = math.MaxInt64 + } +} + +// buildDataSignedForAuth returns the data that is signed in order to prove +// possession of a private key. See RFC 4252, section 7. +func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { + data := struct { + Session []byte + Type byte + User string + Service string + Method string + Sign bool + Algo []byte + PubKey []byte + }{ + sessionID, + msgUserAuthRequest, + req.User, + req.Service, + req.Method, + true, + algo, + pubKey, + } + return Marshal(data) +} + +func appendU16(buf []byte, n uint16) []byte { + return append(buf, byte(n>>8), byte(n)) +} + +func appendU32(buf []byte, n uint32) []byte { + return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) +} + +func appendU64(buf []byte, n uint64) []byte { + return append(buf, + byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), + byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) +} + +func appendInt(buf []byte, n int) []byte { + return appendU32(buf, uint32(n)) +} + +func appendString(buf []byte, s string) []byte { + buf = appendU32(buf, uint32(len(s))) + buf = append(buf, s...) + return buf +} + +func appendBool(buf []byte, b bool) []byte { + if b { + return append(buf, 1) + } + return append(buf, 0) +} + +// newCond is a helper to hide the fact that there is no usable zero +// value for sync.Cond. +func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } + +// window represents the buffer available to clients +// wishing to write to a channel. +type window struct { + *sync.Cond + win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 + writeWaiters int + closed bool +} + +// add adds win to the amount of window available +// for consumers. +func (w *window) add(win uint32) bool { + // a zero sized window adjust is a noop. + if win == 0 { + return true + } + w.L.Lock() + if w.win+win < win { + w.L.Unlock() + return false + } + w.win += win + // It is unusual that multiple goroutines would be attempting to reserve + // window space, but not guaranteed. Use broadcast to notify all waiters + // that additional window is available. + w.Broadcast() + w.L.Unlock() + return true +} + +// close sets the window to closed, so all reservations fail +// immediately. +func (w *window) close() { + w.L.Lock() + w.closed = true + w.Broadcast() + w.L.Unlock() +} + +// reserve reserves win from the available window capacity. +// If no capacity remains, reserve will block. reserve may +// return less than requested. +func (w *window) reserve(win uint32) (uint32, error) { + var err error + w.L.Lock() + w.writeWaiters++ + w.Broadcast() + for w.win == 0 && !w.closed { + w.Wait() + } + w.writeWaiters-- + if w.win < win { + win = w.win + } + w.win -= win + if w.closed { + err = io.EOF + } + w.L.Unlock() + return win, err +} + +// waitWriterBlocked waits until some goroutine is blocked for further +// writes. It is used in tests only. +func (w *window) waitWriterBlocked() { + w.Cond.L.Lock() + for w.writeWaiters == 0 { + w.Cond.Wait() + } + w.Cond.L.Unlock() +} diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go new file mode 100644 index 000000000..fd6b0681b --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/connection.go @@ -0,0 +1,143 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "fmt" + "net" +) + +// OpenChannelError is returned if the other side rejects an +// OpenChannel request. +type OpenChannelError struct { + Reason RejectionReason + Message string +} + +func (e *OpenChannelError) Error() string { + return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) +} + +// ConnMetadata holds metadata for the connection. +type ConnMetadata interface { + // User returns the user ID for this connection. + User() string + + // SessionID returns the session hash, also denoted by H. + SessionID() []byte + + // ClientVersion returns the client's version string as hashed + // into the session ID. + ClientVersion() []byte + + // ServerVersion returns the server's version string as hashed + // into the session ID. + ServerVersion() []byte + + // RemoteAddr returns the remote address for this connection. + RemoteAddr() net.Addr + + // LocalAddr returns the local address for this connection. + LocalAddr() net.Addr +} + +// Conn represents an SSH connection for both server and client roles. +// Conn is the basis for implementing an application layer, such +// as ClientConn, which implements the traditional shell access for +// clients. +type Conn interface { + ConnMetadata + + // SendRequest sends a global request, and returns the + // reply. If wantReply is true, it returns the response status + // and payload. See also RFC4254, section 4. + SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) + + // OpenChannel tries to open an channel. If the request is + // rejected, it returns *OpenChannelError. On success it returns + // the SSH Channel and a Go channel for incoming, out-of-band + // requests. The Go channel must be serviced, or the + // connection will hang. + OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) + + // Close closes the underlying network connection + Close() error + + // Wait blocks until the connection has shut down, and returns the + // error causing the shutdown. + Wait() error + + // TODO(hanwen): consider exposing: + // RequestKeyChange + // Disconnect +} + +// DiscardRequests consumes and rejects all requests from the +// passed-in channel. +func DiscardRequests(in <-chan *Request) { + for req := range in { + if req.WantReply { + req.Reply(false, nil) + } + } +} + +// A connection represents an incoming connection. +type connection struct { + transport *handshakeTransport + sshConn + + // The connection protocol. + *mux +} + +func (c *connection) Close() error { + return c.sshConn.conn.Close() +} + +// sshconn provides net.Conn metadata, but disallows direct reads and +// writes. +type sshConn struct { + conn net.Conn + + user string + sessionID []byte + clientVersion []byte + serverVersion []byte +} + +func dup(src []byte) []byte { + dst := make([]byte, len(src)) + copy(dst, src) + return dst +} + +func (c *sshConn) User() string { + return c.user +} + +func (c *sshConn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +func (c *sshConn) Close() error { + return c.conn.Close() +} + +func (c *sshConn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +func (c *sshConn) SessionID() []byte { + return dup(c.sessionID) +} + +func (c *sshConn) ClientVersion() []byte { + return dup(c.clientVersion) +} + +func (c *sshConn) ServerVersion() []byte { + return dup(c.serverVersion) +} diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go new file mode 100644 index 000000000..67b7322c0 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/doc.go @@ -0,0 +1,21 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package ssh implements an SSH client and server. + +SSH is a transport security protocol, an authentication protocol and a +family of application protocols. The most typical application level +protocol is a remote shell and this is specifically implemented. However, +the multiplexed nature of SSH is exposed to users that wish to support +others. + +References: + [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD + [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 + +This package does not fall under the stability promise of the Go language itself, +so its API may be changed when pressing needs arise. +*/ +package ssh // import "golang.org/x/crypto/ssh" diff --git a/vendor/golang.org/x/crypto/ssh/example_test.go b/vendor/golang.org/x/crypto/ssh/example_test.go new file mode 100644 index 000000000..b910c7bf6 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/example_test.go @@ -0,0 +1,320 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh_test + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "path/filepath" + "strings" + + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/terminal" +) + +func ExampleNewServerConn() { + // Public key authentication is done by comparing + // the public key of a received connection + // with the entries in the authorized_keys file. + authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys") + if err != nil { + log.Fatalf("Failed to load authorized_keys, err: %v", err) + } + + authorizedKeysMap := map[string]bool{} + for len(authorizedKeysBytes) > 0 { + pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes) + if err != nil { + log.Fatal(err) + } + + authorizedKeysMap[string(pubKey.Marshal())] = true + authorizedKeysBytes = rest + } + + // An SSH server is represented by a ServerConfig, which holds + // certificate details and handles authentication of ServerConns. + config := &ssh.ServerConfig{ + // Remove to disable password auth. + PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { + // Should use constant-time compare (or better, salt+hash) in + // a production setting. + if c.User() == "testuser" && string(pass) == "tiger" { + return nil, nil + } + return nil, fmt.Errorf("password rejected for %q", c.User()) + }, + + // Remove to disable public key auth. + PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) { + if authorizedKeysMap[string(pubKey.Marshal())] { + return &ssh.Permissions{ + // Record the public key used for authentication. + Extensions: map[string]string{ + "pubkey-fp": ssh.FingerprintSHA256(pubKey), + }, + }, nil + } + return nil, fmt.Errorf("unknown public key for %q", c.User()) + }, + } + + privateBytes, err := ioutil.ReadFile("id_rsa") + if err != nil { + log.Fatal("Failed to load private key: ", err) + } + + private, err := ssh.ParsePrivateKey(privateBytes) + if err != nil { + log.Fatal("Failed to parse private key: ", err) + } + + config.AddHostKey(private) + + // Once a ServerConfig has been configured, connections can be + // accepted. + listener, err := net.Listen("tcp", "0.0.0.0:2022") + if err != nil { + log.Fatal("failed to listen for connection: ", err) + } + nConn, err := listener.Accept() + if err != nil { + log.Fatal("failed to accept incoming connection: ", err) + } + + // Before use, a handshake must be performed on the incoming + // net.Conn. + conn, chans, reqs, err := ssh.NewServerConn(nConn, config) + if err != nil { + log.Fatal("failed to handshake: ", err) + } + log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"]) + + // The incoming Request channel must be serviced. + go ssh.DiscardRequests(reqs) + + // Service the incoming Channel channel. + for newChannel := range chans { + // Channels have a type, depending on the application level + // protocol intended. In the case of a shell, the type is + // "session" and ServerShell may be used to present a simple + // terminal interface. + if newChannel.ChannelType() != "session" { + newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") + continue + } + channel, requests, err := newChannel.Accept() + if err != nil { + log.Fatalf("Could not accept channel: %v", err) + } + + // Sessions have out-of-band requests such as "shell", + // "pty-req" and "env". Here we handle only the + // "shell" request. + go func(in <-chan *ssh.Request) { + for req := range in { + req.Reply(req.Type == "shell", nil) + } + }(requests) + + term := terminal.NewTerminal(channel, "> ") + + go func() { + defer channel.Close() + for { + line, err := term.ReadLine() + if err != nil { + break + } + fmt.Println(line) + } + }() + } +} + +func ExampleHostKeyCheck() { + // Every client must provide a host key check. Here is a + // simple-minded parse of OpenSSH's known_hosts file + host := "hostname" + file, err := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts")) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + var hostKey ssh.PublicKey + for scanner.Scan() { + fields := strings.Split(scanner.Text(), " ") + if len(fields) != 3 { + continue + } + if strings.Contains(fields[0], host) { + var err error + hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes()) + if err != nil { + log.Fatalf("error parsing %q: %v", fields[2], err) + } + break + } + } + + if hostKey == nil { + log.Fatalf("no hostkey for %s", host) + } + + config := ssh.ClientConfig{ + User: os.Getenv("USER"), + HostKeyCallback: ssh.FixedHostKey(hostKey), + } + + _, err = ssh.Dial("tcp", host+":22", &config) + log.Println(err) +} + +func ExampleDial() { + var hostKey ssh.PublicKey + // An SSH client is represented with a ClientConn. + // + // To authenticate with the remote server you must pass at least one + // implementation of AuthMethod via the Auth field in ClientConfig, + // and provide a HostKeyCallback. + config := &ssh.ClientConfig{ + User: "username", + Auth: []ssh.AuthMethod{ + ssh.Password("yourpassword"), + }, + HostKeyCallback: ssh.FixedHostKey(hostKey), + } + client, err := ssh.Dial("tcp", "yourserver.com:22", config) + if err != nil { + log.Fatal("Failed to dial: ", err) + } + + // Each ClientConn can support multiple interactive sessions, + // represented by a Session. + session, err := client.NewSession() + if err != nil { + log.Fatal("Failed to create session: ", err) + } + defer session.Close() + + // Once a Session is created, you can execute a single command on + // the remote side using the Run method. + var b bytes.Buffer + session.Stdout = &b + if err := session.Run("/usr/bin/whoami"); err != nil { + log.Fatal("Failed to run: " + err.Error()) + } + fmt.Println(b.String()) +} + +func ExamplePublicKeys() { + var hostKey ssh.PublicKey + // A public key may be used to authenticate against the remote + // server by using an unencrypted PEM-encoded private key file. + // + // If you have an encrypted private key, the crypto/x509 package + // can be used to decrypt it. + key, err := ioutil.ReadFile("/home/user/.ssh/id_rsa") + if err != nil { + log.Fatalf("unable to read private key: %v", err) + } + + // Create the Signer for this private key. + signer, err := ssh.ParsePrivateKey(key) + if err != nil { + log.Fatalf("unable to parse private key: %v", err) + } + + config := &ssh.ClientConfig{ + User: "user", + Auth: []ssh.AuthMethod{ + // Use the PublicKeys method for remote authentication. + ssh.PublicKeys(signer), + }, + HostKeyCallback: ssh.FixedHostKey(hostKey), + } + + // Connect to the remote server and perform the SSH handshake. + client, err := ssh.Dial("tcp", "host.com:22", config) + if err != nil { + log.Fatalf("unable to connect: %v", err) + } + defer client.Close() +} + +func ExampleClient_Listen() { + var hostKey ssh.PublicKey + config := &ssh.ClientConfig{ + User: "username", + Auth: []ssh.AuthMethod{ + ssh.Password("password"), + }, + HostKeyCallback: ssh.FixedHostKey(hostKey), + } + // Dial your ssh server. + conn, err := ssh.Dial("tcp", "localhost:22", config) + if err != nil { + log.Fatal("unable to connect: ", err) + } + defer conn.Close() + + // Request the remote side to open port 8080 on all interfaces. + l, err := conn.Listen("tcp", "0.0.0.0:8080") + if err != nil { + log.Fatal("unable to register tcp forward: ", err) + } + defer l.Close() + + // Serve HTTP with your SSH server acting as a reverse proxy. + http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { + fmt.Fprintf(resp, "Hello world!\n") + })) +} + +func ExampleSession_RequestPty() { + var hostKey ssh.PublicKey + // Create client config + config := &ssh.ClientConfig{ + User: "username", + Auth: []ssh.AuthMethod{ + ssh.Password("password"), + }, + HostKeyCallback: ssh.FixedHostKey(hostKey), + } + // Connect to ssh server + conn, err := ssh.Dial("tcp", "localhost:22", config) + if err != nil { + log.Fatal("unable to connect: ", err) + } + defer conn.Close() + // Create a session + session, err := conn.NewSession() + if err != nil { + log.Fatal("unable to create session: ", err) + } + defer session.Close() + // Set up terminal modes + modes := ssh.TerminalModes{ + ssh.ECHO: 0, // disable echoing + ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud + ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud + } + // Request pseudo terminal + if err := session.RequestPty("xterm", 40, 80, modes); err != nil { + log.Fatal("request for pseudo terminal failed: ", err) + } + // Start remote shell + if err := session.Shell(); err != nil { + log.Fatal("failed to start shell: ", err) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go new file mode 100644 index 000000000..4f7912ecd --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/handshake.go @@ -0,0 +1,646 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "crypto/rand" + "errors" + "fmt" + "io" + "log" + "net" + "sync" +) + +// debugHandshake, if set, prints messages sent and received. Key +// exchange messages are printed as if DH were used, so the debug +// messages are wrong when using ECDH. +const debugHandshake = false + +// chanSize sets the amount of buffering SSH connections. This is +// primarily for testing: setting chanSize=0 uncovers deadlocks more +// quickly. +const chanSize = 16 + +// keyingTransport is a packet based transport that supports key +// changes. It need not be thread-safe. It should pass through +// msgNewKeys in both directions. +type keyingTransport interface { + packetConn + + // prepareKeyChange sets up a key change. The key change for a + // direction will be effected if a msgNewKeys message is sent + // or received. + prepareKeyChange(*algorithms, *kexResult) error +} + +// handshakeTransport implements rekeying on top of a keyingTransport +// and offers a thread-safe writePacket() interface. +type handshakeTransport struct { + conn keyingTransport + config *Config + + serverVersion []byte + clientVersion []byte + + // hostKeys is non-empty if we are the server. In that case, + // it contains all host keys that can be used to sign the + // connection. + hostKeys []Signer + + // hostKeyAlgorithms is non-empty if we are the client. In that case, + // we accept these key types from the server as host key. + hostKeyAlgorithms []string + + // On read error, incoming is closed, and readError is set. + incoming chan []byte + readError error + + mu sync.Mutex + writeError error + sentInitPacket []byte + sentInitMsg *kexInitMsg + pendingPackets [][]byte // Used when a key exchange is in progress. + + // If the read loop wants to schedule a kex, it pings this + // channel, and the write loop will send out a kex + // message. + requestKex chan struct{} + + // If the other side requests or confirms a kex, its kexInit + // packet is sent here for the write loop to find it. + startKex chan *pendingKex + + // data for host key checking + hostKeyCallback HostKeyCallback + dialAddress string + remoteAddr net.Addr + + // bannerCallback is non-empty if we are the client and it has been set in + // ClientConfig. In that case it is called during the user authentication + // dance to handle a custom server's message. + bannerCallback BannerCallback + + // Algorithms agreed in the last key exchange. + algorithms *algorithms + + readPacketsLeft uint32 + readBytesLeft int64 + + writePacketsLeft uint32 + writeBytesLeft int64 + + // The session ID or nil if first kex did not complete yet. + sessionID []byte +} + +type pendingKex struct { + otherInit []byte + done chan error +} + +func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { + t := &handshakeTransport{ + conn: conn, + serverVersion: serverVersion, + clientVersion: clientVersion, + incoming: make(chan []byte, chanSize), + requestKex: make(chan struct{}, 1), + startKex: make(chan *pendingKex, 1), + + config: config, + } + t.resetReadThresholds() + t.resetWriteThresholds() + + // We always start with a mandatory key exchange. + t.requestKex <- struct{}{} + return t +} + +func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { + t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) + t.dialAddress = dialAddr + t.remoteAddr = addr + t.hostKeyCallback = config.HostKeyCallback + t.bannerCallback = config.BannerCallback + if config.HostKeyAlgorithms != nil { + t.hostKeyAlgorithms = config.HostKeyAlgorithms + } else { + t.hostKeyAlgorithms = supportedHostKeyAlgos + } + go t.readLoop() + go t.kexLoop() + return t +} + +func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { + t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) + t.hostKeys = config.hostKeys + go t.readLoop() + go t.kexLoop() + return t +} + +func (t *handshakeTransport) getSessionID() []byte { + return t.sessionID +} + +// waitSession waits for the session to be established. This should be +// the first thing to call after instantiating handshakeTransport. +func (t *handshakeTransport) waitSession() error { + p, err := t.readPacket() + if err != nil { + return err + } + if p[0] != msgNewKeys { + return fmt.Errorf("ssh: first packet should be msgNewKeys") + } + + return nil +} + +func (t *handshakeTransport) id() string { + if len(t.hostKeys) > 0 { + return "server" + } + return "client" +} + +func (t *handshakeTransport) printPacket(p []byte, write bool) { + action := "got" + if write { + action = "sent" + } + + if p[0] == msgChannelData || p[0] == msgChannelExtendedData { + log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) + } else { + msg, err := decode(p) + log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) + } +} + +func (t *handshakeTransport) readPacket() ([]byte, error) { + p, ok := <-t.incoming + if !ok { + return nil, t.readError + } + return p, nil +} + +func (t *handshakeTransport) readLoop() { + first := true + for { + p, err := t.readOnePacket(first) + first = false + if err != nil { + t.readError = err + close(t.incoming) + break + } + if p[0] == msgIgnore || p[0] == msgDebug { + continue + } + t.incoming <- p + } + + // Stop writers too. + t.recordWriteError(t.readError) + + // Unblock the writer should it wait for this. + close(t.startKex) + + // Don't close t.requestKex; it's also written to from writePacket. +} + +func (t *handshakeTransport) pushPacket(p []byte) error { + if debugHandshake { + t.printPacket(p, true) + } + return t.conn.writePacket(p) +} + +func (t *handshakeTransport) getWriteError() error { + t.mu.Lock() + defer t.mu.Unlock() + return t.writeError +} + +func (t *handshakeTransport) recordWriteError(err error) { + t.mu.Lock() + defer t.mu.Unlock() + if t.writeError == nil && err != nil { + t.writeError = err + } +} + +func (t *handshakeTransport) requestKeyExchange() { + select { + case t.requestKex <- struct{}{}: + default: + // something already requested a kex, so do nothing. + } +} + +func (t *handshakeTransport) resetWriteThresholds() { + t.writePacketsLeft = packetRekeyThreshold + if t.config.RekeyThreshold > 0 { + t.writeBytesLeft = int64(t.config.RekeyThreshold) + } else if t.algorithms != nil { + t.writeBytesLeft = t.algorithms.w.rekeyBytes() + } else { + t.writeBytesLeft = 1 << 30 + } +} + +func (t *handshakeTransport) kexLoop() { + +write: + for t.getWriteError() == nil { + var request *pendingKex + var sent bool + + for request == nil || !sent { + var ok bool + select { + case request, ok = <-t.startKex: + if !ok { + break write + } + case <-t.requestKex: + break + } + + if !sent { + if err := t.sendKexInit(); err != nil { + t.recordWriteError(err) + break + } + sent = true + } + } + + if err := t.getWriteError(); err != nil { + if request != nil { + request.done <- err + } + break + } + + // We're not servicing t.requestKex, but that is OK: + // we never block on sending to t.requestKex. + + // We're not servicing t.startKex, but the remote end + // has just sent us a kexInitMsg, so it can't send + // another key change request, until we close the done + // channel on the pendingKex request. + + err := t.enterKeyExchange(request.otherInit) + + t.mu.Lock() + t.writeError = err + t.sentInitPacket = nil + t.sentInitMsg = nil + + t.resetWriteThresholds() + + // we have completed the key exchange. Since the + // reader is still blocked, it is safe to clear out + // the requestKex channel. This avoids the situation + // where: 1) we consumed our own request for the + // initial kex, and 2) the kex from the remote side + // caused another send on the requestKex channel, + clear: + for { + select { + case <-t.requestKex: + // + default: + break clear + } + } + + request.done <- t.writeError + + // kex finished. Push packets that we received while + // the kex was in progress. Don't look at t.startKex + // and don't increment writtenSinceKex: if we trigger + // another kex while we are still busy with the last + // one, things will become very confusing. + for _, p := range t.pendingPackets { + t.writeError = t.pushPacket(p) + if t.writeError != nil { + break + } + } + t.pendingPackets = t.pendingPackets[:0] + t.mu.Unlock() + } + + // drain startKex channel. We don't service t.requestKex + // because nobody does blocking sends there. + go func() { + for init := range t.startKex { + init.done <- t.writeError + } + }() + + // Unblock reader. + t.conn.Close() +} + +// The protocol uses uint32 for packet counters, so we can't let them +// reach 1<<32. We will actually read and write more packets than +// this, though: the other side may send more packets, and after we +// hit this limit on writing we will send a few more packets for the +// key exchange itself. +const packetRekeyThreshold = (1 << 31) + +func (t *handshakeTransport) resetReadThresholds() { + t.readPacketsLeft = packetRekeyThreshold + if t.config.RekeyThreshold > 0 { + t.readBytesLeft = int64(t.config.RekeyThreshold) + } else if t.algorithms != nil { + t.readBytesLeft = t.algorithms.r.rekeyBytes() + } else { + t.readBytesLeft = 1 << 30 + } +} + +func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { + p, err := t.conn.readPacket() + if err != nil { + return nil, err + } + + if t.readPacketsLeft > 0 { + t.readPacketsLeft-- + } else { + t.requestKeyExchange() + } + + if t.readBytesLeft > 0 { + t.readBytesLeft -= int64(len(p)) + } else { + t.requestKeyExchange() + } + + if debugHandshake { + t.printPacket(p, false) + } + + if first && p[0] != msgKexInit { + return nil, fmt.Errorf("ssh: first packet should be msgKexInit") + } + + if p[0] != msgKexInit { + return p, nil + } + + firstKex := t.sessionID == nil + + kex := pendingKex{ + done: make(chan error, 1), + otherInit: p, + } + t.startKex <- &kex + err = <-kex.done + + if debugHandshake { + log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) + } + + if err != nil { + return nil, err + } + + t.resetReadThresholds() + + // By default, a key exchange is hidden from higher layers by + // translating it into msgIgnore. + successPacket := []byte{msgIgnore} + if firstKex { + // sendKexInit() for the first kex waits for + // msgNewKeys so the authentication process is + // guaranteed to happen over an encrypted transport. + successPacket = []byte{msgNewKeys} + } + + return successPacket, nil +} + +// sendKexInit sends a key change message. +func (t *handshakeTransport) sendKexInit() error { + t.mu.Lock() + defer t.mu.Unlock() + if t.sentInitMsg != nil { + // kexInits may be sent either in response to the other side, + // or because our side wants to initiate a key change, so we + // may have already sent a kexInit. In that case, don't send a + // second kexInit. + return nil + } + + msg := &kexInitMsg{ + KexAlgos: t.config.KeyExchanges, + CiphersClientServer: t.config.Ciphers, + CiphersServerClient: t.config.Ciphers, + MACsClientServer: t.config.MACs, + MACsServerClient: t.config.MACs, + CompressionClientServer: supportedCompressions, + CompressionServerClient: supportedCompressions, + } + io.ReadFull(rand.Reader, msg.Cookie[:]) + + if len(t.hostKeys) > 0 { + for _, k := range t.hostKeys { + msg.ServerHostKeyAlgos = append( + msg.ServerHostKeyAlgos, k.PublicKey().Type()) + } + } else { + msg.ServerHostKeyAlgos = t.hostKeyAlgorithms + } + packet := Marshal(msg) + + // writePacket destroys the contents, so save a copy. + packetCopy := make([]byte, len(packet)) + copy(packetCopy, packet) + + if err := t.pushPacket(packetCopy); err != nil { + return err + } + + t.sentInitMsg = msg + t.sentInitPacket = packet + + return nil +} + +func (t *handshakeTransport) writePacket(p []byte) error { + switch p[0] { + case msgKexInit: + return errors.New("ssh: only handshakeTransport can send kexInit") + case msgNewKeys: + return errors.New("ssh: only handshakeTransport can send newKeys") + } + + t.mu.Lock() + defer t.mu.Unlock() + if t.writeError != nil { + return t.writeError + } + + if t.sentInitMsg != nil { + // Copy the packet so the writer can reuse the buffer. + cp := make([]byte, len(p)) + copy(cp, p) + t.pendingPackets = append(t.pendingPackets, cp) + return nil + } + + if t.writeBytesLeft > 0 { + t.writeBytesLeft -= int64(len(p)) + } else { + t.requestKeyExchange() + } + + if t.writePacketsLeft > 0 { + t.writePacketsLeft-- + } else { + t.requestKeyExchange() + } + + if err := t.pushPacket(p); err != nil { + t.writeError = err + } + + return nil +} + +func (t *handshakeTransport) Close() error { + return t.conn.Close() +} + +func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { + if debugHandshake { + log.Printf("%s entered key exchange", t.id()) + } + + otherInit := &kexInitMsg{} + if err := Unmarshal(otherInitPacket, otherInit); err != nil { + return err + } + + magics := handshakeMagics{ + clientVersion: t.clientVersion, + serverVersion: t.serverVersion, + clientKexInit: otherInitPacket, + serverKexInit: t.sentInitPacket, + } + + clientInit := otherInit + serverInit := t.sentInitMsg + if len(t.hostKeys) == 0 { + clientInit, serverInit = serverInit, clientInit + + magics.clientKexInit = t.sentInitPacket + magics.serverKexInit = otherInitPacket + } + + var err error + t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) + if err != nil { + return err + } + + // We don't send FirstKexFollows, but we handle receiving it. + // + // RFC 4253 section 7 defines the kex and the agreement method for + // first_kex_packet_follows. It states that the guessed packet + // should be ignored if the "kex algorithm and/or the host + // key algorithm is guessed wrong (server and client have + // different preferred algorithm), or if any of the other + // algorithms cannot be agreed upon". The other algorithms have + // already been checked above so the kex algorithm and host key + // algorithm are checked here. + if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) { + // other side sent a kex message for the wrong algorithm, + // which we have to ignore. + if _, err := t.conn.readPacket(); err != nil { + return err + } + } + + kex, ok := kexAlgoMap[t.algorithms.kex] + if !ok { + return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) + } + + var result *kexResult + if len(t.hostKeys) > 0 { + result, err = t.server(kex, t.algorithms, &magics) + } else { + result, err = t.client(kex, t.algorithms, &magics) + } + + if err != nil { + return err + } + + if t.sessionID == nil { + t.sessionID = result.H + } + result.SessionID = t.sessionID + + if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil { + return err + } + if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { + return err + } + if packet, err := t.conn.readPacket(); err != nil { + return err + } else if packet[0] != msgNewKeys { + return unexpectedMessageError(msgNewKeys, packet[0]) + } + + return nil +} + +func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { + var hostKey Signer + for _, k := range t.hostKeys { + if algs.hostKey == k.PublicKey().Type() { + hostKey = k + } + } + + r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) + return r, err +} + +func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { + result, err := kex.Client(t.conn, t.config.Rand, magics) + if err != nil { + return nil, err + } + + hostKey, err := ParsePublicKey(result.HostKey) + if err != nil { + return nil, err + } + + if err := verifyHostKeySignature(hostKey, result); err != nil { + return nil, err + } + + err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/handshake_test.go b/vendor/golang.org/x/crypto/ssh/handshake_test.go new file mode 100644 index 000000000..91d493568 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/handshake_test.go @@ -0,0 +1,559 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + "io" + "net" + "reflect" + "runtime" + "strings" + "sync" + "testing" +) + +type testChecker struct { + calls []string +} + +func (t *testChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error { + if dialAddr == "bad" { + return fmt.Errorf("dialAddr is bad") + } + + if tcpAddr, ok := addr.(*net.TCPAddr); !ok || tcpAddr == nil { + return fmt.Errorf("testChecker: got %T want *net.TCPAddr", addr) + } + + t.calls = append(t.calls, fmt.Sprintf("%s %v %s %x", dialAddr, addr, key.Type(), key.Marshal())) + + return nil +} + +// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and +// therefore is buffered (net.Pipe deadlocks if both sides start with +// a write.) +func netPipe() (net.Conn, net.Conn, error) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + listener, err = net.Listen("tcp", "[::1]:0") + if err != nil { + return nil, nil, err + } + } + defer listener.Close() + c1, err := net.Dial("tcp", listener.Addr().String()) + if err != nil { + return nil, nil, err + } + + c2, err := listener.Accept() + if err != nil { + c1.Close() + return nil, nil, err + } + + return c1, c2, nil +} + +// noiseTransport inserts ignore messages to check that the read loop +// and the key exchange filters out these messages. +type noiseTransport struct { + keyingTransport +} + +func (t *noiseTransport) writePacket(p []byte) error { + ignore := []byte{msgIgnore} + if err := t.keyingTransport.writePacket(ignore); err != nil { + return err + } + debug := []byte{msgDebug, 1, 2, 3} + if err := t.keyingTransport.writePacket(debug); err != nil { + return err + } + + return t.keyingTransport.writePacket(p) +} + +func addNoiseTransport(t keyingTransport) keyingTransport { + return &noiseTransport{t} +} + +// handshakePair creates two handshakeTransports connected with each +// other. If the noise argument is true, both transports will try to +// confuse the other side by sending ignore and debug messages. +func handshakePair(clientConf *ClientConfig, addr string, noise bool) (client *handshakeTransport, server *handshakeTransport, err error) { + a, b, err := netPipe() + if err != nil { + return nil, nil, err + } + + var trC, trS keyingTransport + + trC = newTransport(a, rand.Reader, true) + trS = newTransport(b, rand.Reader, false) + if noise { + trC = addNoiseTransport(trC) + trS = addNoiseTransport(trS) + } + clientConf.SetDefaults() + + v := []byte("version") + client = newClientTransport(trC, v, v, clientConf, addr, a.RemoteAddr()) + + serverConf := &ServerConfig{} + serverConf.AddHostKey(testSigners["ecdsa"]) + serverConf.AddHostKey(testSigners["rsa"]) + serverConf.SetDefaults() + server = newServerTransport(trS, v, v, serverConf) + + if err := server.waitSession(); err != nil { + return nil, nil, fmt.Errorf("server.waitSession: %v", err) + } + if err := client.waitSession(); err != nil { + return nil, nil, fmt.Errorf("client.waitSession: %v", err) + } + + return client, server, nil +} + +func TestHandshakeBasic(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("see golang.org/issue/7237") + } + + checker := &syncChecker{ + waitCall: make(chan int, 10), + called: make(chan int, 10), + } + + checker.waitCall <- 1 + trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr", false) + if err != nil { + t.Fatalf("handshakePair: %v", err) + } + + defer trC.Close() + defer trS.Close() + + // Let first kex complete normally. + <-checker.called + + clientDone := make(chan int, 0) + gotHalf := make(chan int, 0) + const N = 20 + + go func() { + defer close(clientDone) + // Client writes a bunch of stuff, and does a key + // change in the middle. This should not confuse the + // handshake in progress. We do this twice, so we test + // that the packet buffer is reset correctly. + for i := 0; i < N; i++ { + p := []byte{msgRequestSuccess, byte(i)} + if err := trC.writePacket(p); err != nil { + t.Fatalf("sendPacket: %v", err) + } + if (i % 10) == 5 { + <-gotHalf + // halfway through, we request a key change. + trC.requestKeyExchange() + + // Wait until we can be sure the key + // change has really started before we + // write more. + <-checker.called + } + if (i % 10) == 7 { + // write some packets until the kex + // completes, to test buffering of + // packets. + checker.waitCall <- 1 + } + } + }() + + // Server checks that client messages come in cleanly + i := 0 + err = nil + for ; i < N; i++ { + var p []byte + p, err = trS.readPacket() + if err != nil { + break + } + if (i % 10) == 5 { + gotHalf <- 1 + } + + want := []byte{msgRequestSuccess, byte(i)} + if bytes.Compare(p, want) != 0 { + t.Errorf("message %d: got %v, want %v", i, p, want) + } + } + <-clientDone + if err != nil && err != io.EOF { + t.Fatalf("server error: %v", err) + } + if i != N { + t.Errorf("received %d messages, want 10.", i) + } + + close(checker.called) + if _, ok := <-checker.called; ok { + // If all went well, we registered exactly 2 key changes: one + // that establishes the session, and one that we requested + // additionally. + t.Fatalf("got another host key checks after 2 handshakes") + } +} + +func TestForceFirstKex(t *testing.T) { + // like handshakePair, but must access the keyingTransport. + checker := &testChecker{} + clientConf := &ClientConfig{HostKeyCallback: checker.Check} + a, b, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + + var trC, trS keyingTransport + + trC = newTransport(a, rand.Reader, true) + + // This is the disallowed packet: + trC.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})) + + // Rest of the setup. + trS = newTransport(b, rand.Reader, false) + clientConf.SetDefaults() + + v := []byte("version") + client := newClientTransport(trC, v, v, clientConf, "addr", a.RemoteAddr()) + + serverConf := &ServerConfig{} + serverConf.AddHostKey(testSigners["ecdsa"]) + serverConf.AddHostKey(testSigners["rsa"]) + serverConf.SetDefaults() + server := newServerTransport(trS, v, v, serverConf) + + defer client.Close() + defer server.Close() + + // We setup the initial key exchange, but the remote side + // tries to send serviceRequestMsg in cleartext, which is + // disallowed. + + if err := server.waitSession(); err == nil { + t.Errorf("server first kex init should reject unexpected packet") + } +} + +func TestHandshakeAutoRekeyWrite(t *testing.T) { + checker := &syncChecker{ + called: make(chan int, 10), + waitCall: nil, + } + clientConf := &ClientConfig{HostKeyCallback: checker.Check} + clientConf.RekeyThreshold = 500 + trC, trS, err := handshakePair(clientConf, "addr", false) + if err != nil { + t.Fatalf("handshakePair: %v", err) + } + defer trC.Close() + defer trS.Close() + + input := make([]byte, 251) + input[0] = msgRequestSuccess + + done := make(chan int, 1) + const numPacket = 5 + go func() { + defer close(done) + j := 0 + for ; j < numPacket; j++ { + if p, err := trS.readPacket(); err != nil { + break + } else if !bytes.Equal(input, p) { + t.Errorf("got packet type %d, want %d", p[0], input[0]) + } + } + + if j != numPacket { + t.Errorf("got %d, want 5 messages", j) + } + }() + + <-checker.called + + for i := 0; i < numPacket; i++ { + p := make([]byte, len(input)) + copy(p, input) + if err := trC.writePacket(p); err != nil { + t.Errorf("writePacket: %v", err) + } + if i == 2 { + // Make sure the kex is in progress. + <-checker.called + } + + } + <-done +} + +type syncChecker struct { + waitCall chan int + called chan int +} + +func (c *syncChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error { + c.called <- 1 + if c.waitCall != nil { + <-c.waitCall + } + return nil +} + +func TestHandshakeAutoRekeyRead(t *testing.T) { + sync := &syncChecker{ + called: make(chan int, 2), + waitCall: nil, + } + clientConf := &ClientConfig{ + HostKeyCallback: sync.Check, + } + clientConf.RekeyThreshold = 500 + + trC, trS, err := handshakePair(clientConf, "addr", false) + if err != nil { + t.Fatalf("handshakePair: %v", err) + } + defer trC.Close() + defer trS.Close() + + packet := make([]byte, 501) + packet[0] = msgRequestSuccess + if err := trS.writePacket(packet); err != nil { + t.Fatalf("writePacket: %v", err) + } + + // While we read out the packet, a key change will be + // initiated. + done := make(chan int, 1) + go func() { + defer close(done) + if _, err := trC.readPacket(); err != nil { + t.Fatalf("readPacket(client): %v", err) + } + + }() + + <-done + <-sync.called +} + +// errorKeyingTransport generates errors after a given number of +// read/write operations. +type errorKeyingTransport struct { + packetConn + readLeft, writeLeft int +} + +func (n *errorKeyingTransport) prepareKeyChange(*algorithms, *kexResult) error { + return nil +} + +func (n *errorKeyingTransport) getSessionID() []byte { + return nil +} + +func (n *errorKeyingTransport) writePacket(packet []byte) error { + if n.writeLeft == 0 { + n.Close() + return errors.New("barf") + } + + n.writeLeft-- + return n.packetConn.writePacket(packet) +} + +func (n *errorKeyingTransport) readPacket() ([]byte, error) { + if n.readLeft == 0 { + n.Close() + return nil, errors.New("barf") + } + + n.readLeft-- + return n.packetConn.readPacket() +} + +func TestHandshakeErrorHandlingRead(t *testing.T) { + for i := 0; i < 20; i++ { + testHandshakeErrorHandlingN(t, i, -1, false) + } +} + +func TestHandshakeErrorHandlingWrite(t *testing.T) { + for i := 0; i < 20; i++ { + testHandshakeErrorHandlingN(t, -1, i, false) + } +} + +func TestHandshakeErrorHandlingReadCoupled(t *testing.T) { + for i := 0; i < 20; i++ { + testHandshakeErrorHandlingN(t, i, -1, true) + } +} + +func TestHandshakeErrorHandlingWriteCoupled(t *testing.T) { + for i := 0; i < 20; i++ { + testHandshakeErrorHandlingN(t, -1, i, true) + } +} + +// testHandshakeErrorHandlingN runs handshakes, injecting errors. If +// handshakeTransport deadlocks, the go runtime will detect it and +// panic. +func testHandshakeErrorHandlingN(t *testing.T, readLimit, writeLimit int, coupled bool) { + msg := Marshal(&serviceRequestMsg{strings.Repeat("x", int(minRekeyThreshold)/4)}) + + a, b := memPipe() + defer a.Close() + defer b.Close() + + key := testSigners["ecdsa"] + serverConf := Config{RekeyThreshold: minRekeyThreshold} + serverConf.SetDefaults() + serverConn := newHandshakeTransport(&errorKeyingTransport{a, readLimit, writeLimit}, &serverConf, []byte{'a'}, []byte{'b'}) + serverConn.hostKeys = []Signer{key} + go serverConn.readLoop() + go serverConn.kexLoop() + + clientConf := Config{RekeyThreshold: 10 * minRekeyThreshold} + clientConf.SetDefaults() + clientConn := newHandshakeTransport(&errorKeyingTransport{b, -1, -1}, &clientConf, []byte{'a'}, []byte{'b'}) + clientConn.hostKeyAlgorithms = []string{key.PublicKey().Type()} + clientConn.hostKeyCallback = InsecureIgnoreHostKey() + go clientConn.readLoop() + go clientConn.kexLoop() + + var wg sync.WaitGroup + + for _, hs := range []packetConn{serverConn, clientConn} { + if !coupled { + wg.Add(2) + go func(c packetConn) { + for i := 0; ; i++ { + str := fmt.Sprintf("%08x", i) + strings.Repeat("x", int(minRekeyThreshold)/4-8) + err := c.writePacket(Marshal(&serviceRequestMsg{str})) + if err != nil { + break + } + } + wg.Done() + c.Close() + }(hs) + go func(c packetConn) { + for { + _, err := c.readPacket() + if err != nil { + break + } + } + wg.Done() + }(hs) + } else { + wg.Add(1) + go func(c packetConn) { + for { + _, err := c.readPacket() + if err != nil { + break + } + if err := c.writePacket(msg); err != nil { + break + } + + } + wg.Done() + }(hs) + } + } + wg.Wait() +} + +func TestDisconnect(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("see golang.org/issue/7237") + } + checker := &testChecker{} + trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr", false) + if err != nil { + t.Fatalf("handshakePair: %v", err) + } + + defer trC.Close() + defer trS.Close() + + trC.writePacket([]byte{msgRequestSuccess, 0, 0}) + errMsg := &disconnectMsg{ + Reason: 42, + Message: "such is life", + } + trC.writePacket(Marshal(errMsg)) + trC.writePacket([]byte{msgRequestSuccess, 0, 0}) + + packet, err := trS.readPacket() + if err != nil { + t.Fatalf("readPacket 1: %v", err) + } + if packet[0] != msgRequestSuccess { + t.Errorf("got packet %v, want packet type %d", packet, msgRequestSuccess) + } + + _, err = trS.readPacket() + if err == nil { + t.Errorf("readPacket 2 succeeded") + } else if !reflect.DeepEqual(err, errMsg) { + t.Errorf("got error %#v, want %#v", err, errMsg) + } + + _, err = trS.readPacket() + if err == nil { + t.Errorf("readPacket 3 succeeded") + } +} + +func TestHandshakeRekeyDefault(t *testing.T) { + clientConf := &ClientConfig{ + Config: Config{ + Ciphers: []string{"aes128-ctr"}, + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + trC, trS, err := handshakePair(clientConf, "addr", false) + if err != nil { + t.Fatalf("handshakePair: %v", err) + } + defer trC.Close() + defer trS.Close() + + trC.writePacket([]byte{msgRequestSuccess, 0, 0}) + trC.Close() + + rgb := (1024 + trC.readBytesLeft) >> 30 + wgb := (1024 + trC.writeBytesLeft) >> 30 + + if rgb != 64 { + t.Errorf("got rekey after %dG read, want 64G", rgb) + } + if wgb != 64 { + t.Errorf("got rekey after %dG write, want 64G", wgb) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go new file mode 100644 index 000000000..f34bcc013 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/kex.go @@ -0,0 +1,540 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/subtle" + "errors" + "io" + "math/big" + + "golang.org/x/crypto/curve25519" +) + +const ( + kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" + kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" + kexAlgoECDH256 = "ecdh-sha2-nistp256" + kexAlgoECDH384 = "ecdh-sha2-nistp384" + kexAlgoECDH521 = "ecdh-sha2-nistp521" + kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" +) + +// kexResult captures the outcome of a key exchange. +type kexResult struct { + // Session hash. See also RFC 4253, section 8. + H []byte + + // Shared secret. See also RFC 4253, section 8. + K []byte + + // Host key as hashed into H. + HostKey []byte + + // Signature of H. + Signature []byte + + // A cryptographic hash function that matches the security + // level of the key exchange algorithm. It is used for + // calculating H, and for deriving keys from H and K. + Hash crypto.Hash + + // The session ID, which is the first H computed. This is used + // to derive key material inside the transport. + SessionID []byte +} + +// handshakeMagics contains data that is always included in the +// session hash. +type handshakeMagics struct { + clientVersion, serverVersion []byte + clientKexInit, serverKexInit []byte +} + +func (m *handshakeMagics) write(w io.Writer) { + writeString(w, m.clientVersion) + writeString(w, m.serverVersion) + writeString(w, m.clientKexInit) + writeString(w, m.serverKexInit) +} + +// kexAlgorithm abstracts different key exchange algorithms. +type kexAlgorithm interface { + // Server runs server-side key agreement, signing the result + // with a hostkey. + Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) + + // Client runs the client-side key agreement. Caller is + // responsible for verifying the host key signature. + Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) +} + +// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. +type dhGroup struct { + g, p, pMinus1 *big.Int +} + +func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { + if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { + return nil, errors.New("ssh: DH parameter out of bounds") + } + return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil +} + +func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { + hashFunc := crypto.SHA1 + + var x *big.Int + for { + var err error + if x, err = rand.Int(randSource, group.pMinus1); err != nil { + return nil, err + } + if x.Sign() > 0 { + break + } + } + + X := new(big.Int).Exp(group.g, x, group.p) + kexDHInit := kexDHInitMsg{ + X: X, + } + if err := c.writePacket(Marshal(&kexDHInit)); err != nil { + return nil, err + } + + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var kexDHReply kexDHReplyMsg + if err = Unmarshal(packet, &kexDHReply); err != nil { + return nil, err + } + + ki, err := group.diffieHellman(kexDHReply.Y, x) + if err != nil { + return nil, err + } + + h := hashFunc.New() + magics.write(h) + writeString(h, kexDHReply.HostKey) + writeInt(h, X) + writeInt(h, kexDHReply.Y) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: kexDHReply.HostKey, + Signature: kexDHReply.Signature, + Hash: crypto.SHA1, + }, nil +} + +func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { + hashFunc := crypto.SHA1 + packet, err := c.readPacket() + if err != nil { + return + } + var kexDHInit kexDHInitMsg + if err = Unmarshal(packet, &kexDHInit); err != nil { + return + } + + var y *big.Int + for { + if y, err = rand.Int(randSource, group.pMinus1); err != nil { + return + } + if y.Sign() > 0 { + break + } + } + + Y := new(big.Int).Exp(group.g, y, group.p) + ki, err := group.diffieHellman(kexDHInit.X, y) + if err != nil { + return nil, err + } + + hostKeyBytes := priv.PublicKey().Marshal() + + h := hashFunc.New() + magics.write(h) + writeString(h, hostKeyBytes) + writeInt(h, kexDHInit.X) + writeInt(h, Y) + + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + H := h.Sum(nil) + + // H is already a hash, but the hostkey signing will apply its + // own key-specific hash algorithm. + sig, err := signAndMarshal(priv, randSource, H) + if err != nil { + return nil, err + } + + kexDHReply := kexDHReplyMsg{ + HostKey: hostKeyBytes, + Y: Y, + Signature: sig, + } + packet = Marshal(&kexDHReply) + + err = c.writePacket(packet) + return &kexResult{ + H: H, + K: K, + HostKey: hostKeyBytes, + Signature: sig, + Hash: crypto.SHA1, + }, nil +} + +// ecdh performs Elliptic Curve Diffie-Hellman key exchange as +// described in RFC 5656, section 4. +type ecdh struct { + curve elliptic.Curve +} + +func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { + ephKey, err := ecdsa.GenerateKey(kex.curve, rand) + if err != nil { + return nil, err + } + + kexInit := kexECDHInitMsg{ + ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), + } + + serialized := Marshal(&kexInit) + if err := c.writePacket(serialized); err != nil { + return nil, err + } + + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var reply kexECDHReplyMsg + if err = Unmarshal(packet, &reply); err != nil { + return nil, err + } + + x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) + if err != nil { + return nil, err + } + + // generate shared secret + secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) + + h := ecHash(kex.curve).New() + magics.write(h) + writeString(h, reply.HostKey) + writeString(h, kexInit.ClientPubKey) + writeString(h, reply.EphemeralPubKey) + K := make([]byte, intLength(secret)) + marshalInt(K, secret) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: reply.HostKey, + Signature: reply.Signature, + Hash: ecHash(kex.curve), + }, nil +} + +// unmarshalECKey parses and checks an EC key. +func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { + x, y = elliptic.Unmarshal(curve, pubkey) + if x == nil { + return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") + } + if !validateECPublicKey(curve, x, y) { + return nil, nil, errors.New("ssh: public key not on curve") + } + return x, y, nil +} + +// validateECPublicKey checks that the point is a valid public key for +// the given curve. See [SEC1], 3.2.2 +func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { + if x.Sign() == 0 && y.Sign() == 0 { + return false + } + + if x.Cmp(curve.Params().P) >= 0 { + return false + } + + if y.Cmp(curve.Params().P) >= 0 { + return false + } + + if !curve.IsOnCurve(x, y) { + return false + } + + // We don't check if N * PubKey == 0, since + // + // - the NIST curves have cofactor = 1, so this is implicit. + // (We don't foresee an implementation that supports non NIST + // curves) + // + // - for ephemeral keys, we don't need to worry about small + // subgroup attacks. + return true +} + +func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var kexECDHInit kexECDHInitMsg + if err = Unmarshal(packet, &kexECDHInit); err != nil { + return nil, err + } + + clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) + if err != nil { + return nil, err + } + + // We could cache this key across multiple users/multiple + // connection attempts, but the benefit is small. OpenSSH + // generates a new key for each incoming connection. + ephKey, err := ecdsa.GenerateKey(kex.curve, rand) + if err != nil { + return nil, err + } + + hostKeyBytes := priv.PublicKey().Marshal() + + serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) + + // generate shared secret + secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) + + h := ecHash(kex.curve).New() + magics.write(h) + writeString(h, hostKeyBytes) + writeString(h, kexECDHInit.ClientPubKey) + writeString(h, serializedEphKey) + + K := make([]byte, intLength(secret)) + marshalInt(K, secret) + h.Write(K) + + H := h.Sum(nil) + + // H is already a hash, but the hostkey signing will apply its + // own key-specific hash algorithm. + sig, err := signAndMarshal(priv, rand, H) + if err != nil { + return nil, err + } + + reply := kexECDHReplyMsg{ + EphemeralPubKey: serializedEphKey, + HostKey: hostKeyBytes, + Signature: sig, + } + + serialized := Marshal(&reply) + if err := c.writePacket(serialized); err != nil { + return nil, err + } + + return &kexResult{ + H: H, + K: K, + HostKey: reply.HostKey, + Signature: sig, + Hash: ecHash(kex.curve), + }, nil +} + +var kexAlgoMap = map[string]kexAlgorithm{} + +func init() { + // This is the group called diffie-hellman-group1-sha1 in RFC + // 4253 and Oakley Group 2 in RFC 2409. + p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) + kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ + g: new(big.Int).SetInt64(2), + p: p, + pMinus1: new(big.Int).Sub(p, bigOne), + } + + // This is the group called diffie-hellman-group14-sha1 in RFC + // 4253 and Oakley Group 14 in RFC 3526. + p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) + + kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ + g: new(big.Int).SetInt64(2), + p: p, + pMinus1: new(big.Int).Sub(p, bigOne), + } + + kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} + kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} + kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} + kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} +} + +// curve25519sha256 implements the curve25519-sha256@libssh.org key +// agreement protocol, as described in +// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt +type curve25519sha256 struct{} + +type curve25519KeyPair struct { + priv [32]byte + pub [32]byte +} + +func (kp *curve25519KeyPair) generate(rand io.Reader) error { + if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { + return err + } + curve25519.ScalarBaseMult(&kp.pub, &kp.priv) + return nil +} + +// curve25519Zeros is just an array of 32 zero bytes so that we have something +// convenient to compare against in order to reject curve25519 points with the +// wrong order. +var curve25519Zeros [32]byte + +func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { + var kp curve25519KeyPair + if err := kp.generate(rand); err != nil { + return nil, err + } + if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { + return nil, err + } + + packet, err := c.readPacket() + if err != nil { + return nil, err + } + + var reply kexECDHReplyMsg + if err = Unmarshal(packet, &reply); err != nil { + return nil, err + } + if len(reply.EphemeralPubKey) != 32 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong length") + } + + var servPub, secret [32]byte + copy(servPub[:], reply.EphemeralPubKey) + curve25519.ScalarMult(&secret, &kp.priv, &servPub) + if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + } + + h := crypto.SHA256.New() + magics.write(h) + writeString(h, reply.HostKey) + writeString(h, kp.pub[:]) + writeString(h, reply.EphemeralPubKey) + + ki := new(big.Int).SetBytes(secret[:]) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + return &kexResult{ + H: h.Sum(nil), + K: K, + HostKey: reply.HostKey, + Signature: reply.Signature, + Hash: crypto.SHA256, + }, nil +} + +func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { + packet, err := c.readPacket() + if err != nil { + return + } + var kexInit kexECDHInitMsg + if err = Unmarshal(packet, &kexInit); err != nil { + return + } + + if len(kexInit.ClientPubKey) != 32 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong length") + } + + var kp curve25519KeyPair + if err := kp.generate(rand); err != nil { + return nil, err + } + + var clientPub, secret [32]byte + copy(clientPub[:], kexInit.ClientPubKey) + curve25519.ScalarMult(&secret, &kp.priv, &clientPub) + if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { + return nil, errors.New("ssh: peer's curve25519 public value has wrong order") + } + + hostKeyBytes := priv.PublicKey().Marshal() + + h := crypto.SHA256.New() + magics.write(h) + writeString(h, hostKeyBytes) + writeString(h, kexInit.ClientPubKey) + writeString(h, kp.pub[:]) + + ki := new(big.Int).SetBytes(secret[:]) + K := make([]byte, intLength(ki)) + marshalInt(K, ki) + h.Write(K) + + H := h.Sum(nil) + + sig, err := signAndMarshal(priv, rand, H) + if err != nil { + return nil, err + } + + reply := kexECDHReplyMsg{ + EphemeralPubKey: kp.pub[:], + HostKey: hostKeyBytes, + Signature: sig, + } + if err := c.writePacket(Marshal(&reply)); err != nil { + return nil, err + } + return &kexResult{ + H: H, + K: K, + HostKey: hostKeyBytes, + Signature: sig, + Hash: crypto.SHA256, + }, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/kex_test.go b/vendor/golang.org/x/crypto/ssh/kex_test.go new file mode 100644 index 000000000..12ca0acd3 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/kex_test.go @@ -0,0 +1,50 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +// Key exchange tests. + +import ( + "crypto/rand" + "reflect" + "testing" +) + +func TestKexes(t *testing.T) { + type kexResultErr struct { + result *kexResult + err error + } + + for name, kex := range kexAlgoMap { + a, b := memPipe() + + s := make(chan kexResultErr, 1) + c := make(chan kexResultErr, 1) + var magics handshakeMagics + go func() { + r, e := kex.Client(a, rand.Reader, &magics) + a.Close() + c <- kexResultErr{r, e} + }() + go func() { + r, e := kex.Server(b, rand.Reader, &magics, testSigners["ecdsa"]) + b.Close() + s <- kexResultErr{r, e} + }() + + clientRes := <-c + serverRes := <-s + if clientRes.err != nil { + t.Errorf("client: %v", clientRes.err) + } + if serverRes.err != nil { + t.Errorf("server: %v", serverRes.err) + } + if !reflect.DeepEqual(clientRes.result, serverRes.result) { + t.Errorf("kex %q: mismatch %#v, %#v", name, clientRes.result, serverRes.result) + } + } +} diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go new file mode 100644 index 000000000..73697deda --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -0,0 +1,1032 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/md5" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/asn1" + "encoding/base64" + "encoding/hex" + "encoding/pem" + "errors" + "fmt" + "io" + "math/big" + "strings" + + "golang.org/x/crypto/ed25519" +) + +// These constants represent the algorithm names for key types supported by this +// package. +const ( + KeyAlgoRSA = "ssh-rsa" + KeyAlgoDSA = "ssh-dss" + KeyAlgoECDSA256 = "ecdsa-sha2-nistp256" + KeyAlgoECDSA384 = "ecdsa-sha2-nistp384" + KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" + KeyAlgoED25519 = "ssh-ed25519" +) + +// parsePubKey parses a public key of the given algorithm. +// Use ParsePublicKey for keys with prepended algorithm. +func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { + switch algo { + case KeyAlgoRSA: + return parseRSA(in) + case KeyAlgoDSA: + return parseDSA(in) + case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: + return parseECDSA(in) + case KeyAlgoED25519: + return parseED25519(in) + case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01: + cert, err := parseCert(in, certToPrivAlgo(algo)) + if err != nil { + return nil, nil, err + } + return cert, nil, nil + } + return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) +} + +// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format +// (see sshd(8) manual page) once the options and key type fields have been +// removed. +func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) { + in = bytes.TrimSpace(in) + + i := bytes.IndexAny(in, " \t") + if i == -1 { + i = len(in) + } + base64Key := in[:i] + + key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key))) + n, err := base64.StdEncoding.Decode(key, base64Key) + if err != nil { + return nil, "", err + } + key = key[:n] + out, err = ParsePublicKey(key) + if err != nil { + return nil, "", err + } + comment = string(bytes.TrimSpace(in[i:])) + return out, comment, nil +} + +// ParseKnownHosts parses an entry in the format of the known_hosts file. +// +// The known_hosts format is documented in the sshd(8) manual page. This +// function will parse a single entry from in. On successful return, marker +// will contain the optional marker value (i.e. "cert-authority" or "revoked") +// or else be empty, hosts will contain the hosts that this entry matches, +// pubKey will contain the public key and comment will contain any trailing +// comment at the end of the line. See the sshd(8) manual page for the various +// forms that a host string can take. +// +// The unparsed remainder of the input will be returned in rest. This function +// can be called repeatedly to parse multiple entries. +// +// If no entries were found in the input then err will be io.EOF. Otherwise a +// non-nil err value indicates a parse error. +func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) { + for len(in) > 0 { + end := bytes.IndexByte(in, '\n') + if end != -1 { + rest = in[end+1:] + in = in[:end] + } else { + rest = nil + } + + end = bytes.IndexByte(in, '\r') + if end != -1 { + in = in[:end] + } + + in = bytes.TrimSpace(in) + if len(in) == 0 || in[0] == '#' { + in = rest + continue + } + + i := bytes.IndexAny(in, " \t") + if i == -1 { + in = rest + continue + } + + // Strip out the beginning of the known_host key. + // This is either an optional marker or a (set of) hostname(s). + keyFields := bytes.Fields(in) + if len(keyFields) < 3 || len(keyFields) > 5 { + return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data") + } + + // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated + // list of hosts + marker := "" + if keyFields[0][0] == '@' { + marker = string(keyFields[0][1:]) + keyFields = keyFields[1:] + } + + hosts := string(keyFields[0]) + // keyFields[1] contains the key type (e.g. “ssh-rsa”). + // However, that information is duplicated inside the + // base64-encoded key and so is ignored here. + + key := bytes.Join(keyFields[2:], []byte(" ")) + if pubKey, comment, err = parseAuthorizedKey(key); err != nil { + return "", nil, nil, "", nil, err + } + + return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil + } + + return "", nil, nil, "", nil, io.EOF +} + +// ParseAuthorizedKeys parses a public key from an authorized_keys +// file used in OpenSSH according to the sshd(8) manual page. +func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { + for len(in) > 0 { + end := bytes.IndexByte(in, '\n') + if end != -1 { + rest = in[end+1:] + in = in[:end] + } else { + rest = nil + } + + end = bytes.IndexByte(in, '\r') + if end != -1 { + in = in[:end] + } + + in = bytes.TrimSpace(in) + if len(in) == 0 || in[0] == '#' { + in = rest + continue + } + + i := bytes.IndexAny(in, " \t") + if i == -1 { + in = rest + continue + } + + if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { + return out, comment, options, rest, nil + } + + // No key type recognised. Maybe there's an options field at + // the beginning. + var b byte + inQuote := false + var candidateOptions []string + optionStart := 0 + for i, b = range in { + isEnd := !inQuote && (b == ' ' || b == '\t') + if (b == ',' && !inQuote) || isEnd { + if i-optionStart > 0 { + candidateOptions = append(candidateOptions, string(in[optionStart:i])) + } + optionStart = i + 1 + } + if isEnd { + break + } + if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) { + inQuote = !inQuote + } + } + for i < len(in) && (in[i] == ' ' || in[i] == '\t') { + i++ + } + if i == len(in) { + // Invalid line: unmatched quote + in = rest + continue + } + + in = in[i:] + i = bytes.IndexAny(in, " \t") + if i == -1 { + in = rest + continue + } + + if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { + options = candidateOptions + return out, comment, options, rest, nil + } + + in = rest + continue + } + + return nil, "", nil, nil, errors.New("ssh: no key found") +} + +// ParsePublicKey parses an SSH public key formatted for use in +// the SSH wire protocol according to RFC 4253, section 6.6. +func ParsePublicKey(in []byte) (out PublicKey, err error) { + algo, in, ok := parseString(in) + if !ok { + return nil, errShortRead + } + var rest []byte + out, rest, err = parsePubKey(in, string(algo)) + if len(rest) > 0 { + return nil, errors.New("ssh: trailing junk in public key") + } + + return out, err +} + +// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH +// authorized_keys file. The return value ends with newline. +func MarshalAuthorizedKey(key PublicKey) []byte { + b := &bytes.Buffer{} + b.WriteString(key.Type()) + b.WriteByte(' ') + e := base64.NewEncoder(base64.StdEncoding, b) + e.Write(key.Marshal()) + e.Close() + b.WriteByte('\n') + return b.Bytes() +} + +// PublicKey is an abstraction of different types of public keys. +type PublicKey interface { + // Type returns the key's type, e.g. "ssh-rsa". + Type() string + + // Marshal returns the serialized key data in SSH wire format, + // with the name prefix. To unmarshal the returned data, use + // the ParsePublicKey function. + Marshal() []byte + + // Verify that sig is a signature on the given data using this + // key. This function will hash the data appropriately first. + Verify(data []byte, sig *Signature) error +} + +// CryptoPublicKey, if implemented by a PublicKey, +// returns the underlying crypto.PublicKey form of the key. +type CryptoPublicKey interface { + CryptoPublicKey() crypto.PublicKey +} + +// A Signer can create signatures that verify against a public key. +type Signer interface { + // PublicKey returns an associated PublicKey instance. + PublicKey() PublicKey + + // Sign returns raw signature for the given data. This method + // will apply the hash specified for the keytype to the data. + Sign(rand io.Reader, data []byte) (*Signature, error) +} + +type rsaPublicKey rsa.PublicKey + +func (r *rsaPublicKey) Type() string { + return "ssh-rsa" +} + +// parseRSA parses an RSA key according to RFC 4253, section 6.6. +func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + E *big.Int + N *big.Int + Rest []byte `ssh:"rest"` + } + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + if w.E.BitLen() > 24 { + return nil, nil, errors.New("ssh: exponent too large") + } + e := w.E.Int64() + if e < 3 || e&1 == 0 { + return nil, nil, errors.New("ssh: incorrect exponent") + } + + var key rsa.PublicKey + key.E = int(e) + key.N = w.N + return (*rsaPublicKey)(&key), w.Rest, nil +} + +func (r *rsaPublicKey) Marshal() []byte { + e := new(big.Int).SetInt64(int64(r.E)) + // RSA publickey struct layout should match the struct used by + // parseRSACert in the x/crypto/ssh/agent package. + wirekey := struct { + Name string + E *big.Int + N *big.Int + }{ + KeyAlgoRSA, + e, + r.N, + } + return Marshal(&wirekey) +} + +func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != r.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) + } + h := crypto.SHA1.New() + h.Write(data) + digest := h.Sum(nil) + return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) +} + +func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { + return (*rsa.PublicKey)(r) +} + +type dsaPublicKey dsa.PublicKey + +func (k *dsaPublicKey) Type() string { + return "ssh-dss" +} + +func checkDSAParams(param *dsa.Parameters) error { + // SSH specifies FIPS 186-2, which only provided a single size + // (1024 bits) DSA key. FIPS 186-3 allows for larger key + // sizes, which would confuse SSH. + if l := param.P.BitLen(); l != 1024 { + return fmt.Errorf("ssh: unsupported DSA key size %d", l) + } + + return nil +} + +// parseDSA parses an DSA key according to RFC 4253, section 6.6. +func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + P, Q, G, Y *big.Int + Rest []byte `ssh:"rest"` + } + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + param := dsa.Parameters{ + P: w.P, + Q: w.Q, + G: w.G, + } + if err := checkDSAParams(¶m); err != nil { + return nil, nil, err + } + + key := &dsaPublicKey{ + Parameters: param, + Y: w.Y, + } + return key, w.Rest, nil +} + +func (k *dsaPublicKey) Marshal() []byte { + // DSA publickey struct layout should match the struct used by + // parseDSACert in the x/crypto/ssh/agent package. + w := struct { + Name string + P, Q, G, Y *big.Int + }{ + k.Type(), + k.P, + k.Q, + k.G, + k.Y, + } + + return Marshal(&w) +} + +func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + h := crypto.SHA1.New() + h.Write(data) + digest := h.Sum(nil) + + // Per RFC 4253, section 6.6, + // The value for 'dss_signature_blob' is encoded as a string containing + // r, followed by s (which are 160-bit integers, without lengths or + // padding, unsigned, and in network byte order). + // For DSS purposes, sig.Blob should be exactly 40 bytes in length. + if len(sig.Blob) != 40 { + return errors.New("ssh: DSA signature parse error") + } + r := new(big.Int).SetBytes(sig.Blob[:20]) + s := new(big.Int).SetBytes(sig.Blob[20:]) + if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) { + return nil + } + return errors.New("ssh: signature did not verify") +} + +func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { + return (*dsa.PublicKey)(k) +} + +type dsaPrivateKey struct { + *dsa.PrivateKey +} + +func (k *dsaPrivateKey) PublicKey() PublicKey { + return (*dsaPublicKey)(&k.PrivateKey.PublicKey) +} + +func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { + h := crypto.SHA1.New() + h.Write(data) + digest := h.Sum(nil) + r, s, err := dsa.Sign(rand, k.PrivateKey, digest) + if err != nil { + return nil, err + } + + sig := make([]byte, 40) + rb := r.Bytes() + sb := s.Bytes() + + copy(sig[20-len(rb):20], rb) + copy(sig[40-len(sb):], sb) + + return &Signature{ + Format: k.PublicKey().Type(), + Blob: sig, + }, nil +} + +type ecdsaPublicKey ecdsa.PublicKey + +func (k *ecdsaPublicKey) Type() string { + return "ecdsa-sha2-" + k.nistID() +} + +func (k *ecdsaPublicKey) nistID() string { + switch k.Params().BitSize { + case 256: + return "nistp256" + case 384: + return "nistp384" + case 521: + return "nistp521" + } + panic("ssh: unsupported ecdsa key size") +} + +type ed25519PublicKey ed25519.PublicKey + +func (k ed25519PublicKey) Type() string { + return KeyAlgoED25519 +} + +func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + KeyBytes []byte + Rest []byte `ssh:"rest"` + } + + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + key := ed25519.PublicKey(w.KeyBytes) + + return (ed25519PublicKey)(key), w.Rest, nil +} + +func (k ed25519PublicKey) Marshal() []byte { + w := struct { + Name string + KeyBytes []byte + }{ + KeyAlgoED25519, + []byte(k), + } + return Marshal(&w) +} + +func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + + edKey := (ed25519.PublicKey)(k) + if ok := ed25519.Verify(edKey, b, sig.Blob); !ok { + return errors.New("ssh: signature did not verify") + } + + return nil +} + +func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { + return ed25519.PublicKey(k) +} + +func supportedEllipticCurve(curve elliptic.Curve) bool { + return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() +} + +// ecHash returns the hash to match the given elliptic curve, see RFC +// 5656, section 6.2.1 +func ecHash(curve elliptic.Curve) crypto.Hash { + bitSize := curve.Params().BitSize + switch { + case bitSize <= 256: + return crypto.SHA256 + case bitSize <= 384: + return crypto.SHA384 + } + return crypto.SHA512 +} + +// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. +func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { + var w struct { + Curve string + KeyBytes []byte + Rest []byte `ssh:"rest"` + } + + if err := Unmarshal(in, &w); err != nil { + return nil, nil, err + } + + key := new(ecdsa.PublicKey) + + switch w.Curve { + case "nistp256": + key.Curve = elliptic.P256() + case "nistp384": + key.Curve = elliptic.P384() + case "nistp521": + key.Curve = elliptic.P521() + default: + return nil, nil, errors.New("ssh: unsupported curve") + } + + key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) + if key.X == nil || key.Y == nil { + return nil, nil, errors.New("ssh: invalid curve point") + } + return (*ecdsaPublicKey)(key), w.Rest, nil +} + +func (k *ecdsaPublicKey) Marshal() []byte { + // See RFC 5656, section 3.1. + keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) + // ECDSA publickey struct layout should match the struct used by + // parseECDSACert in the x/crypto/ssh/agent package. + w := struct { + Name string + ID string + Key []byte + }{ + k.Type(), + k.nistID(), + keyBytes, + } + + return Marshal(&w) +} + +func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { + if sig.Format != k.Type() { + return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) + } + + h := ecHash(k.Curve).New() + h.Write(data) + digest := h.Sum(nil) + + // Per RFC 5656, section 3.1.2, + // The ecdsa_signature_blob value has the following specific encoding: + // mpint r + // mpint s + var ecSig struct { + R *big.Int + S *big.Int + } + + if err := Unmarshal(sig.Blob, &ecSig); err != nil { + return err + } + + if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) { + return nil + } + return errors.New("ssh: signature did not verify") +} + +func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { + return (*ecdsa.PublicKey)(k) +} + +// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, +// *ecdsa.PrivateKey or any other crypto.Signer and returns a +// corresponding Signer instance. ECDSA keys must use P-256, P-384 or +// P-521. DSA keys must use parameter size L1024N160. +func NewSignerFromKey(key interface{}) (Signer, error) { + switch key := key.(type) { + case crypto.Signer: + return NewSignerFromSigner(key) + case *dsa.PrivateKey: + return newDSAPrivateKey(key) + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } +} + +func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) { + if err := checkDSAParams(&key.PublicKey.Parameters); err != nil { + return nil, err + } + + return &dsaPrivateKey{key}, nil +} + +type wrappedSigner struct { + signer crypto.Signer + pubKey PublicKey +} + +// NewSignerFromSigner takes any crypto.Signer implementation and +// returns a corresponding Signer interface. This can be used, for +// example, with keys kept in hardware modules. +func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { + pubKey, err := NewPublicKey(signer.Public()) + if err != nil { + return nil, err + } + + return &wrappedSigner{signer, pubKey}, nil +} + +func (s *wrappedSigner) PublicKey() PublicKey { + return s.pubKey +} + +func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + var hashFunc crypto.Hash + + switch key := s.pubKey.(type) { + case *rsaPublicKey, *dsaPublicKey: + hashFunc = crypto.SHA1 + case *ecdsaPublicKey: + hashFunc = ecHash(key.Curve) + case ed25519PublicKey: + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } + + var digest []byte + if hashFunc != 0 { + h := hashFunc.New() + h.Write(data) + digest = h.Sum(nil) + } else { + digest = data + } + + signature, err := s.signer.Sign(rand, digest, hashFunc) + if err != nil { + return nil, err + } + + // crypto.Signer.Sign is expected to return an ASN.1-encoded signature + // for ECDSA and DSA, but that's not the encoding expected by SSH, so + // re-encode. + switch s.pubKey.(type) { + case *ecdsaPublicKey, *dsaPublicKey: + type asn1Signature struct { + R, S *big.Int + } + asn1Sig := new(asn1Signature) + _, err := asn1.Unmarshal(signature, asn1Sig) + if err != nil { + return nil, err + } + + switch s.pubKey.(type) { + case *ecdsaPublicKey: + signature = Marshal(asn1Sig) + + case *dsaPublicKey: + signature = make([]byte, 40) + r := asn1Sig.R.Bytes() + s := asn1Sig.S.Bytes() + copy(signature[20-len(r):20], r) + copy(signature[40-len(s):40], s) + } + } + + return &Signature{ + Format: s.pubKey.Type(), + Blob: signature, + }, nil +} + +// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, +// or ed25519.PublicKey returns a corresponding PublicKey instance. +// ECDSA keys must use P-256, P-384 or P-521. +func NewPublicKey(key interface{}) (PublicKey, error) { + switch key := key.(type) { + case *rsa.PublicKey: + return (*rsaPublicKey)(key), nil + case *ecdsa.PublicKey: + if !supportedEllipticCurve(key.Curve) { + return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported") + } + return (*ecdsaPublicKey)(key), nil + case *dsa.PublicKey: + return (*dsaPublicKey)(key), nil + case ed25519.PublicKey: + return (ed25519PublicKey)(key), nil + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } +} + +// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports +// the same keys as ParseRawPrivateKey. +func ParsePrivateKey(pemBytes []byte) (Signer, error) { + key, err := ParseRawPrivateKey(pemBytes) + if err != nil { + return nil, err + } + + return NewSignerFromKey(key) +} + +// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private +// key and passphrase. It supports the same keys as +// ParseRawPrivateKeyWithPassphrase. +func ParsePrivateKeyWithPassphrase(pemBytes, passPhrase []byte) (Signer, error) { + key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passPhrase) + if err != nil { + return nil, err + } + + return NewSignerFromKey(key) +} + +// encryptedBlock tells whether a private key is +// encrypted by examining its Proc-Type header +// for a mention of ENCRYPTED +// according to RFC 1421 Section 4.6.1.1. +func encryptedBlock(block *pem.Block) bool { + return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") +} + +// ParseRawPrivateKey returns a private key from a PEM encoded private key. It +// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys. +func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("ssh: no key found") + } + + if encryptedBlock(block) { + return nil, errors.New("ssh: cannot decode encrypted private keys") + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + case "DSA PRIVATE KEY": + return ParseDSAPrivateKey(block.Bytes) + case "OPENSSH PRIVATE KEY": + return parseOpenSSHPrivateKey(block.Bytes) + default: + return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) + } +} + +// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with +// passphrase from a PEM encoded private key. If wrong passphrase, return +// x509.IncorrectPasswordError. +func ParseRawPrivateKeyWithPassphrase(pemBytes, passPhrase []byte) (interface{}, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("ssh: no key found") + } + buf := block.Bytes + + if encryptedBlock(block) { + if x509.IsEncryptedPEMBlock(block) { + var err error + buf, err = x509.DecryptPEMBlock(block, passPhrase) + if err != nil { + if err == x509.IncorrectPasswordError { + return nil, err + } + return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err) + } + } + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(buf) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(buf) + case "DSA PRIVATE KEY": + return ParseDSAPrivateKey(buf) + case "OPENSSH PRIVATE KEY": + return parseOpenSSHPrivateKey(buf) + default: + return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) + } +} + +// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as +// specified by the OpenSSL DSA man page. +func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { + var k struct { + Version int + P *big.Int + Q *big.Int + G *big.Int + Pub *big.Int + Priv *big.Int + } + rest, err := asn1.Unmarshal(der, &k) + if err != nil { + return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) + } + if len(rest) > 0 { + return nil, errors.New("ssh: garbage after DSA key") + } + + return &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: k.P, + Q: k.Q, + G: k.G, + }, + Y: k.Pub, + }, + X: k.Priv, + }, nil +} + +// Implemented based on the documentation at +// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key +func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) { + magic := append([]byte("openssh-key-v1"), 0) + if !bytes.Equal(magic, key[0:len(magic)]) { + return nil, errors.New("ssh: invalid openssh private key format") + } + remaining := key[len(magic):] + + var w struct { + CipherName string + KdfName string + KdfOpts string + NumKeys uint32 + PubKey []byte + PrivKeyBlock []byte + } + + if err := Unmarshal(remaining, &w); err != nil { + return nil, err + } + + if w.KdfName != "none" || w.CipherName != "none" { + return nil, errors.New("ssh: cannot decode encrypted private keys") + } + + pk1 := struct { + Check1 uint32 + Check2 uint32 + Keytype string + Rest []byte `ssh:"rest"` + }{} + + if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil { + return nil, err + } + + if pk1.Check1 != pk1.Check2 { + return nil, errors.New("ssh: checkint mismatch") + } + + // we only handle ed25519 and rsa keys currently + switch pk1.Keytype { + case KeyAlgoRSA: + // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773 + key := struct { + N *big.Int + E *big.Int + D *big.Int + Iqmp *big.Int + P *big.Int + Q *big.Int + Comment string + Pad []byte `ssh:"rest"` + }{} + + if err := Unmarshal(pk1.Rest, &key); err != nil { + return nil, err + } + + for i, b := range key.Pad { + if int(b) != i+1 { + return nil, errors.New("ssh: padding not as expected") + } + } + + pk := &rsa.PrivateKey{ + PublicKey: rsa.PublicKey{ + N: key.N, + E: int(key.E.Int64()), + }, + D: key.D, + Primes: []*big.Int{key.P, key.Q}, + } + + if err := pk.Validate(); err != nil { + return nil, err + } + + pk.Precompute() + + return pk, nil + case KeyAlgoED25519: + key := struct { + Pub []byte + Priv []byte + Comment string + Pad []byte `ssh:"rest"` + }{} + + if err := Unmarshal(pk1.Rest, &key); err != nil { + return nil, err + } + + if len(key.Priv) != ed25519.PrivateKeySize { + return nil, errors.New("ssh: private key unexpected length") + } + + for i, b := range key.Pad { + if int(b) != i+1 { + return nil, errors.New("ssh: padding not as expected") + } + } + + pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) + copy(pk, key.Priv) + return &pk, nil + default: + return nil, errors.New("ssh: unhandled key type") + } +} + +// FingerprintLegacyMD5 returns the user presentation of the key's +// fingerprint as described by RFC 4716 section 4. +func FingerprintLegacyMD5(pubKey PublicKey) string { + md5sum := md5.Sum(pubKey.Marshal()) + hexarray := make([]string, len(md5sum)) + for i, c := range md5sum { + hexarray[i] = hex.EncodeToString([]byte{c}) + } + return strings.Join(hexarray, ":") +} + +// FingerprintSHA256 returns the user presentation of the key's +// fingerprint as unpadded base64 encoded sha256 hash. +// This format was introduced from OpenSSH 6.8. +// https://www.openssh.com/txt/release-6.8 +// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding) +func FingerprintSHA256(pubKey PublicKey) string { + sha256sum := sha256.Sum256(pubKey.Marshal()) + hash := base64.RawStdEncoding.EncodeToString(sha256sum[:]) + return "SHA256:" + hash +} diff --git a/vendor/golang.org/x/crypto/ssh/keys_test.go b/vendor/golang.org/x/crypto/ssh/keys_test.go new file mode 100644 index 000000000..9a90abc0c --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/keys_test.go @@ -0,0 +1,500 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "fmt" + "reflect" + "strings" + "testing" + + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ssh/testdata" +) + +func rawKey(pub PublicKey) interface{} { + switch k := pub.(type) { + case *rsaPublicKey: + return (*rsa.PublicKey)(k) + case *dsaPublicKey: + return (*dsa.PublicKey)(k) + case *ecdsaPublicKey: + return (*ecdsa.PublicKey)(k) + case ed25519PublicKey: + return (ed25519.PublicKey)(k) + case *Certificate: + return k + } + panic("unknown key type") +} + +func TestKeyMarshalParse(t *testing.T) { + for _, priv := range testSigners { + pub := priv.PublicKey() + roundtrip, err := ParsePublicKey(pub.Marshal()) + if err != nil { + t.Errorf("ParsePublicKey(%T): %v", pub, err) + } + + k1 := rawKey(pub) + k2 := rawKey(roundtrip) + + if !reflect.DeepEqual(k1, k2) { + t.Errorf("got %#v in roundtrip, want %#v", k2, k1) + } + } +} + +func TestUnsupportedCurves(t *testing.T) { + raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + if err != nil { + t.Fatalf("GenerateKey: %v", err) + } + + if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P-256") { + t.Fatalf("NewPrivateKey should not succeed with P-224, got: %v", err) + } + + if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P-256") { + t.Fatalf("NewPublicKey should not succeed with P-224, got: %v", err) + } +} + +func TestNewPublicKey(t *testing.T) { + for _, k := range testSigners { + raw := rawKey(k.PublicKey()) + // Skip certificates, as NewPublicKey does not support them. + if _, ok := raw.(*Certificate); ok { + continue + } + pub, err := NewPublicKey(raw) + if err != nil { + t.Errorf("NewPublicKey(%#v): %v", raw, err) + } + if !reflect.DeepEqual(k.PublicKey(), pub) { + t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey()) + } + } +} + +func TestKeySignVerify(t *testing.T) { + for _, priv := range testSigners { + pub := priv.PublicKey() + + data := []byte("sign me") + sig, err := priv.Sign(rand.Reader, data) + if err != nil { + t.Fatalf("Sign(%T): %v", priv, err) + } + + if err := pub.Verify(data, sig); err != nil { + t.Errorf("publicKey.Verify(%T): %v", priv, err) + } + sig.Blob[5]++ + if err := pub.Verify(data, sig); err == nil { + t.Errorf("publicKey.Verify on broken sig did not fail") + } + } +} + +func TestParseRSAPrivateKey(t *testing.T) { + key := testPrivateKeys["rsa"] + + rsa, ok := key.(*rsa.PrivateKey) + if !ok { + t.Fatalf("got %T, want *rsa.PrivateKey", rsa) + } + + if err := rsa.Validate(); err != nil { + t.Errorf("Validate: %v", err) + } +} + +func TestParseECPrivateKey(t *testing.T) { + key := testPrivateKeys["ecdsa"] + + ecKey, ok := key.(*ecdsa.PrivateKey) + if !ok { + t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey) + } + + if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) { + t.Fatalf("public key does not validate.") + } +} + +// See Issue https://github.com/golang/go/issues/6650. +func TestParseEncryptedPrivateKeysFails(t *testing.T) { + const wantSubstring = "encrypted" + for i, tt := range testdata.PEMEncryptedKeys { + _, err := ParsePrivateKey(tt.PEMBytes) + if err == nil { + t.Errorf("#%d key %s: ParsePrivateKey successfully parsed, expected an error", i, tt.Name) + continue + } + + if !strings.Contains(err.Error(), wantSubstring) { + t.Errorf("#%d key %s: got error %q, want substring %q", i, tt.Name, err, wantSubstring) + } + } +} + +// Parse encrypted private keys with passphrase +func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) { + data := []byte("sign me") + for _, tt := range testdata.PEMEncryptedKeys { + s, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey)) + if err != nil { + t.Fatalf("ParsePrivateKeyWithPassphrase returned error: %s", err) + continue + } + sig, err := s.Sign(rand.Reader, data) + if err != nil { + t.Fatalf("dsa.Sign: %v", err) + } + if err := s.PublicKey().Verify(data, sig); err != nil { + t.Errorf("Verify failed: %v", err) + } + } + + tt := testdata.PEMEncryptedKeys[0] + _, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte("incorrect")) + if err != x509.IncorrectPasswordError { + t.Fatalf("got %v want IncorrectPasswordError", err) + } +} + +func TestParseDSA(t *testing.T) { + // We actually exercise the ParsePrivateKey codepath here, as opposed to + // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go + // uses. + s, err := ParsePrivateKey(testdata.PEMBytes["dsa"]) + if err != nil { + t.Fatalf("ParsePrivateKey returned error: %s", err) + } + + data := []byte("sign me") + sig, err := s.Sign(rand.Reader, data) + if err != nil { + t.Fatalf("dsa.Sign: %v", err) + } + + if err := s.PublicKey().Verify(data, sig); err != nil { + t.Errorf("Verify failed: %v", err) + } +} + +// Tests for authorized_keys parsing. + +// getTestKey returns a public key, and its base64 encoding. +func getTestKey() (PublicKey, string) { + k := testPublicKeys["rsa"] + + b := &bytes.Buffer{} + e := base64.NewEncoder(base64.StdEncoding, b) + e.Write(k.Marshal()) + e.Close() + + return k, b.String() +} + +func TestMarshalParsePublicKey(t *testing.T) { + pub, pubSerialized := getTestKey() + line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized) + + authKeys := MarshalAuthorizedKey(pub) + actualFields := strings.Fields(string(authKeys)) + if len(actualFields) == 0 { + t.Fatalf("failed authKeys: %v", authKeys) + } + + // drop the comment + expectedFields := strings.Fields(line)[0:2] + + if !reflect.DeepEqual(actualFields, expectedFields) { + t.Errorf("got %v, expected %v", actualFields, expectedFields) + } + + actPub, _, _, _, err := ParseAuthorizedKey([]byte(line)) + if err != nil { + t.Fatalf("cannot parse %v: %v", line, err) + } + if !reflect.DeepEqual(actPub, pub) { + t.Errorf("got %v, expected %v", actPub, pub) + } +} + +type testAuthResult struct { + pubKey PublicKey + options []string + comments string + rest string + ok bool +} + +func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []testAuthResult) { + rest := authKeys + var values []testAuthResult + for len(rest) > 0 { + var r testAuthResult + var err error + r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest) + r.ok = (err == nil) + t.Log(err) + r.rest = string(rest) + values = append(values, r) + } + + if !reflect.DeepEqual(values, expected) { + t.Errorf("got %#v, expected %#v", values, expected) + } +} + +func TestAuthorizedKeyBasic(t *testing.T) { + pub, pubSerialized := getTestKey() + line := "ssh-rsa " + pubSerialized + " user@host" + testAuthorizedKeys(t, []byte(line), + []testAuthResult{ + {pub, nil, "user@host", "", true}, + }) +} + +func TestAuth(t *testing.T) { + pub, pubSerialized := getTestKey() + authWithOptions := []string{ + `# comments to ignore before any keys...`, + ``, + `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`, + `# comments to ignore, along with a blank line`, + ``, + `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`, + ``, + `# more comments, plus a invalid entry`, + `ssh-rsa data-that-will-not-parse user@host3`, + } + for _, eol := range []string{"\n", "\r\n"} { + authOptions := strings.Join(authWithOptions, eol) + rest2 := strings.Join(authWithOptions[3:], eol) + rest3 := strings.Join(authWithOptions[6:], eol) + testAuthorizedKeys(t, []byte(authOptions), []testAuthResult{ + {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true}, + {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true}, + {nil, nil, "", "", false}, + }) + } +} + +func TestAuthWithQuotedSpaceInEnv(t *testing.T) { + pub, pubSerialized := getTestKey() + authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`) + testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []testAuthResult{ + {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true}, + }) +} + +func TestAuthWithQuotedCommaInEnv(t *testing.T) { + pub, pubSerialized := getTestKey() + authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`) + testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []testAuthResult{ + {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true}, + }) +} + +func TestAuthWithQuotedQuoteInEnv(t *testing.T) { + pub, pubSerialized := getTestKey() + authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`) + authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`) + testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []testAuthResult{ + {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true}, + }) + + testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []testAuthResult{ + {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true}, + }) +} + +func TestAuthWithInvalidSpace(t *testing.T) { + _, pubSerialized := getTestKey() + authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host +#more to follow but still no valid keys`) + testAuthorizedKeys(t, []byte(authWithInvalidSpace), []testAuthResult{ + {nil, nil, "", "", false}, + }) +} + +func TestAuthWithMissingQuote(t *testing.T) { + pub, pubSerialized := getTestKey() + authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host +env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`) + + testAuthorizedKeys(t, []byte(authWithMissingQuote), []testAuthResult{ + {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true}, + }) +} + +func TestInvalidEntry(t *testing.T) { + authInvalid := []byte(`ssh-rsa`) + _, _, _, _, err := ParseAuthorizedKey(authInvalid) + if err == nil { + t.Errorf("got valid entry for %q", authInvalid) + } +} + +var knownHostsParseTests = []struct { + input string + err string + + marker string + comment string + hosts []string + rest string +}{ + { + "", + "EOF", + + "", "", nil, "", + }, + { + "# Just a comment", + "EOF", + + "", "", nil, "", + }, + { + " \t ", + "EOF", + + "", "", nil, "", + }, + { + "localhost ssh-rsa {RSAPUB}", + "", + + "", "", []string{"localhost"}, "", + }, + { + "localhost\tssh-rsa {RSAPUB}", + "", + + "", "", []string{"localhost"}, "", + }, + { + "localhost\tssh-rsa {RSAPUB}\tcomment comment", + "", + + "", "comment comment", []string{"localhost"}, "", + }, + { + "localhost\tssh-rsa {RSAPUB}\tcomment comment\n", + "", + + "", "comment comment", []string{"localhost"}, "", + }, + { + "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n", + "", + + "", "comment comment", []string{"localhost"}, "", + }, + { + "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line", + "", + + "", "comment comment", []string{"localhost"}, "next line", + }, + { + "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment", + "", + + "", "comment comment", []string{"localhost", "[host2:123]"}, "", + }, + { + "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}", + "", + + "marker", "", []string{"localhost", "[host2:123]"}, "", + }, + { + "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd", + "short read", + + "", "", nil, "", + }, +} + +func TestKnownHostsParsing(t *testing.T) { + rsaPub, rsaPubSerialized := getTestKey() + + for i, test := range knownHostsParseTests { + var expectedKey PublicKey + const rsaKeyToken = "{RSAPUB}" + + input := test.input + if strings.Contains(input, rsaKeyToken) { + expectedKey = rsaPub + input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1) + } + + marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input)) + if err != nil { + if len(test.err) == 0 { + t.Errorf("#%d: unexpectedly failed with %q", i, err) + } else if !strings.Contains(err.Error(), test.err) { + t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err) + } + continue + } else if len(test.err) != 0 { + t.Errorf("#%d: succeeded but expected error including %q", i, test.err) + continue + } + + if !reflect.DeepEqual(expectedKey, pubKey) { + t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey) + } + + if marker != test.marker { + t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker) + } + + if comment != test.comment { + t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment) + } + + if !reflect.DeepEqual(test.hosts, hosts) { + t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts) + } + + if rest := string(rest); rest != test.rest { + t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest) + } + } +} + +func TestFingerprintLegacyMD5(t *testing.T) { + pub, _ := getTestKey() + fingerprint := FingerprintLegacyMD5(pub) + want := "fb:61:6d:1a:e3:f0:95:45:3c:a0:79:be:4a:93:63:66" // ssh-keygen -lf -E md5 rsa + if fingerprint != want { + t.Errorf("got fingerprint %q want %q", fingerprint, want) + } +} + +func TestFingerprintSHA256(t *testing.T) { + pub, _ := getTestKey() + fingerprint := FingerprintSHA256(pub) + want := "SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8" // ssh-keygen -lf rsa + if fingerprint != want { + t.Errorf("got fingerprint %q want %q", fingerprint, want) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go new file mode 100644 index 000000000..c07a06285 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mac.go @@ -0,0 +1,61 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +// Message authentication support + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "hash" +) + +type macMode struct { + keySize int + etm bool + new func(key []byte) hash.Hash +} + +// truncatingMAC wraps around a hash.Hash and truncates the output digest to +// a given size. +type truncatingMAC struct { + length int + hmac hash.Hash +} + +func (t truncatingMAC) Write(data []byte) (int, error) { + return t.hmac.Write(data) +} + +func (t truncatingMAC) Sum(in []byte) []byte { + out := t.hmac.Sum(in) + return out[:len(in)+t.length] +} + +func (t truncatingMAC) Reset() { + t.hmac.Reset() +} + +func (t truncatingMAC) Size() int { + return t.length +} + +func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } + +var macModes = map[string]*macMode{ + "hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { + return hmac.New(sha256.New, key) + }}, + "hmac-sha2-256": {32, false, func(key []byte) hash.Hash { + return hmac.New(sha256.New, key) + }}, + "hmac-sha1": {20, false, func(key []byte) hash.Hash { + return hmac.New(sha1.New, key) + }}, + "hmac-sha1-96": {20, false, func(key []byte) hash.Hash { + return truncatingMAC{12, hmac.New(sha1.New, key)} + }}, +} diff --git a/vendor/golang.org/x/crypto/ssh/mempipe_test.go b/vendor/golang.org/x/crypto/ssh/mempipe_test.go new file mode 100644 index 000000000..8697cd614 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mempipe_test.go @@ -0,0 +1,110 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "io" + "sync" + "testing" +) + +// An in-memory packetConn. It is safe to call Close and writePacket +// from different goroutines. +type memTransport struct { + eof bool + pending [][]byte + write *memTransport + sync.Mutex + *sync.Cond +} + +func (t *memTransport) readPacket() ([]byte, error) { + t.Lock() + defer t.Unlock() + for { + if len(t.pending) > 0 { + r := t.pending[0] + t.pending = t.pending[1:] + return r, nil + } + if t.eof { + return nil, io.EOF + } + t.Cond.Wait() + } +} + +func (t *memTransport) closeSelf() error { + t.Lock() + defer t.Unlock() + if t.eof { + return io.EOF + } + t.eof = true + t.Cond.Broadcast() + return nil +} + +func (t *memTransport) Close() error { + err := t.write.closeSelf() + t.closeSelf() + return err +} + +func (t *memTransport) writePacket(p []byte) error { + t.write.Lock() + defer t.write.Unlock() + if t.write.eof { + return io.EOF + } + c := make([]byte, len(p)) + copy(c, p) + t.write.pending = append(t.write.pending, c) + t.write.Cond.Signal() + return nil +} + +func memPipe() (a, b packetConn) { + t1 := memTransport{} + t2 := memTransport{} + t1.write = &t2 + t2.write = &t1 + t1.Cond = sync.NewCond(&t1.Mutex) + t2.Cond = sync.NewCond(&t2.Mutex) + return &t1, &t2 +} + +func TestMemPipe(t *testing.T) { + a, b := memPipe() + if err := a.writePacket([]byte{42}); err != nil { + t.Fatalf("writePacket: %v", err) + } + if err := a.Close(); err != nil { + t.Fatal("Close: ", err) + } + p, err := b.readPacket() + if err != nil { + t.Fatal("readPacket: ", err) + } + if len(p) != 1 || p[0] != 42 { + t.Fatalf("got %v, want {42}", p) + } + p, err = b.readPacket() + if err != io.EOF { + t.Fatalf("got %v, %v, want EOF", p, err) + } +} + +func TestDoubleClose(t *testing.T) { + a, _ := memPipe() + err := a.Close() + if err != nil { + t.Errorf("Close: %v", err) + } + err = a.Close() + if err != io.EOF { + t.Errorf("expect EOF on double close.") + } +} diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go new file mode 100644 index 000000000..08d281173 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/messages.go @@ -0,0 +1,766 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math/big" + "reflect" + "strconv" + "strings" +) + +// These are SSH message type numbers. They are scattered around several +// documents but many were taken from [SSH-PARAMETERS]. +const ( + msgIgnore = 2 + msgUnimplemented = 3 + msgDebug = 4 + msgNewKeys = 21 +) + +// SSH messages: +// +// These structures mirror the wire format of the corresponding SSH messages. +// They are marshaled using reflection with the marshal and unmarshal functions +// in this file. The only wrinkle is that a final member of type []byte with a +// ssh tag of "rest" receives the remainder of a packet when unmarshaling. + +// See RFC 4253, section 11.1. +const msgDisconnect = 1 + +// disconnectMsg is the message that signals a disconnect. It is also +// the error type returned from mux.Wait() +type disconnectMsg struct { + Reason uint32 `sshtype:"1"` + Message string + Language string +} + +func (d *disconnectMsg) Error() string { + return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message) +} + +// See RFC 4253, section 7.1. +const msgKexInit = 20 + +type kexInitMsg struct { + Cookie [16]byte `sshtype:"20"` + KexAlgos []string + ServerHostKeyAlgos []string + CiphersClientServer []string + CiphersServerClient []string + MACsClientServer []string + MACsServerClient []string + CompressionClientServer []string + CompressionServerClient []string + LanguagesClientServer []string + LanguagesServerClient []string + FirstKexFollows bool + Reserved uint32 +} + +// See RFC 4253, section 8. + +// Diffie-Helman +const msgKexDHInit = 30 + +type kexDHInitMsg struct { + X *big.Int `sshtype:"30"` +} + +const msgKexECDHInit = 30 + +type kexECDHInitMsg struct { + ClientPubKey []byte `sshtype:"30"` +} + +const msgKexECDHReply = 31 + +type kexECDHReplyMsg struct { + HostKey []byte `sshtype:"31"` + EphemeralPubKey []byte + Signature []byte +} + +const msgKexDHReply = 31 + +type kexDHReplyMsg struct { + HostKey []byte `sshtype:"31"` + Y *big.Int + Signature []byte +} + +// See RFC 4253, section 10. +const msgServiceRequest = 5 + +type serviceRequestMsg struct { + Service string `sshtype:"5"` +} + +// See RFC 4253, section 10. +const msgServiceAccept = 6 + +type serviceAcceptMsg struct { + Service string `sshtype:"6"` +} + +// See RFC 4252, section 5. +const msgUserAuthRequest = 50 + +type userAuthRequestMsg struct { + User string `sshtype:"50"` + Service string + Method string + Payload []byte `ssh:"rest"` +} + +// Used for debug printouts of packets. +type userAuthSuccessMsg struct { +} + +// See RFC 4252, section 5.1 +const msgUserAuthFailure = 51 + +type userAuthFailureMsg struct { + Methods []string `sshtype:"51"` + PartialSuccess bool +} + +// See RFC 4252, section 5.1 +const msgUserAuthSuccess = 52 + +// See RFC 4252, section 5.4 +const msgUserAuthBanner = 53 + +type userAuthBannerMsg struct { + Message string `sshtype:"53"` + // unused, but required to allow message parsing + Language string +} + +// See RFC 4256, section 3.2 +const msgUserAuthInfoRequest = 60 +const msgUserAuthInfoResponse = 61 + +type userAuthInfoRequestMsg struct { + User string `sshtype:"60"` + Instruction string + DeprecatedLanguage string + NumPrompts uint32 + Prompts []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.1. +const msgChannelOpen = 90 + +type channelOpenMsg struct { + ChanType string `sshtype:"90"` + PeersID uint32 + PeersWindow uint32 + MaxPacketSize uint32 + TypeSpecificData []byte `ssh:"rest"` +} + +const msgChannelExtendedData = 95 +const msgChannelData = 94 + +// Used for debug print outs of packets. +type channelDataMsg struct { + PeersID uint32 `sshtype:"94"` + Length uint32 + Rest []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.1. +const msgChannelOpenConfirm = 91 + +type channelOpenConfirmMsg struct { + PeersID uint32 `sshtype:"91"` + MyID uint32 + MyWindow uint32 + MaxPacketSize uint32 + TypeSpecificData []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.1. +const msgChannelOpenFailure = 92 + +type channelOpenFailureMsg struct { + PeersID uint32 `sshtype:"92"` + Reason RejectionReason + Message string + Language string +} + +const msgChannelRequest = 98 + +type channelRequestMsg struct { + PeersID uint32 `sshtype:"98"` + Request string + WantReply bool + RequestSpecificData []byte `ssh:"rest"` +} + +// See RFC 4254, section 5.4. +const msgChannelSuccess = 99 + +type channelRequestSuccessMsg struct { + PeersID uint32 `sshtype:"99"` +} + +// See RFC 4254, section 5.4. +const msgChannelFailure = 100 + +type channelRequestFailureMsg struct { + PeersID uint32 `sshtype:"100"` +} + +// See RFC 4254, section 5.3 +const msgChannelClose = 97 + +type channelCloseMsg struct { + PeersID uint32 `sshtype:"97"` +} + +// See RFC 4254, section 5.3 +const msgChannelEOF = 96 + +type channelEOFMsg struct { + PeersID uint32 `sshtype:"96"` +} + +// See RFC 4254, section 4 +const msgGlobalRequest = 80 + +type globalRequestMsg struct { + Type string `sshtype:"80"` + WantReply bool + Data []byte `ssh:"rest"` +} + +// See RFC 4254, section 4 +const msgRequestSuccess = 81 + +type globalRequestSuccessMsg struct { + Data []byte `ssh:"rest" sshtype:"81"` +} + +// See RFC 4254, section 4 +const msgRequestFailure = 82 + +type globalRequestFailureMsg struct { + Data []byte `ssh:"rest" sshtype:"82"` +} + +// See RFC 4254, section 5.2 +const msgChannelWindowAdjust = 93 + +type windowAdjustMsg struct { + PeersID uint32 `sshtype:"93"` + AdditionalBytes uint32 +} + +// See RFC 4252, section 7 +const msgUserAuthPubKeyOk = 60 + +type userAuthPubKeyOkMsg struct { + Algo string `sshtype:"60"` + PubKey []byte +} + +// typeTags returns the possible type bytes for the given reflect.Type, which +// should be a struct. The possible values are separated by a '|' character. +func typeTags(structType reflect.Type) (tags []byte) { + tagStr := structType.Field(0).Tag.Get("sshtype") + + for _, tag := range strings.Split(tagStr, "|") { + i, err := strconv.Atoi(tag) + if err == nil { + tags = append(tags, byte(i)) + } + } + + return tags +} + +func fieldError(t reflect.Type, field int, problem string) error { + if problem != "" { + problem = ": " + problem + } + return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem) +} + +var errShortRead = errors.New("ssh: short read") + +// Unmarshal parses data in SSH wire format into a structure. The out +// argument should be a pointer to struct. If the first member of the +// struct has the "sshtype" tag set to a '|'-separated set of numbers +// in decimal, the packet must start with one of those numbers. In +// case of error, Unmarshal returns a ParseError or +// UnexpectedMessageError. +func Unmarshal(data []byte, out interface{}) error { + v := reflect.ValueOf(out).Elem() + structType := v.Type() + expectedTypes := typeTags(structType) + + var expectedType byte + if len(expectedTypes) > 0 { + expectedType = expectedTypes[0] + } + + if len(data) == 0 { + return parseError(expectedType) + } + + if len(expectedTypes) > 0 { + goodType := false + for _, e := range expectedTypes { + if e > 0 && data[0] == e { + goodType = true + break + } + } + if !goodType { + return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes) + } + data = data[1:] + } + + var ok bool + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + t := field.Type() + switch t.Kind() { + case reflect.Bool: + if len(data) < 1 { + return errShortRead + } + field.SetBool(data[0] != 0) + data = data[1:] + case reflect.Array: + if t.Elem().Kind() != reflect.Uint8 { + return fieldError(structType, i, "array of unsupported type") + } + if len(data) < t.Len() { + return errShortRead + } + for j, n := 0, t.Len(); j < n; j++ { + field.Index(j).Set(reflect.ValueOf(data[j])) + } + data = data[t.Len():] + case reflect.Uint64: + var u64 uint64 + if u64, data, ok = parseUint64(data); !ok { + return errShortRead + } + field.SetUint(u64) + case reflect.Uint32: + var u32 uint32 + if u32, data, ok = parseUint32(data); !ok { + return errShortRead + } + field.SetUint(uint64(u32)) + case reflect.Uint8: + if len(data) < 1 { + return errShortRead + } + field.SetUint(uint64(data[0])) + data = data[1:] + case reflect.String: + var s []byte + if s, data, ok = parseString(data); !ok { + return fieldError(structType, i, "") + } + field.SetString(string(s)) + case reflect.Slice: + switch t.Elem().Kind() { + case reflect.Uint8: + if structType.Field(i).Tag.Get("ssh") == "rest" { + field.Set(reflect.ValueOf(data)) + data = nil + } else { + var s []byte + if s, data, ok = parseString(data); !ok { + return errShortRead + } + field.Set(reflect.ValueOf(s)) + } + case reflect.String: + var nl []string + if nl, data, ok = parseNameList(data); !ok { + return errShortRead + } + field.Set(reflect.ValueOf(nl)) + default: + return fieldError(structType, i, "slice of unsupported type") + } + case reflect.Ptr: + if t == bigIntType { + var n *big.Int + if n, data, ok = parseInt(data); !ok { + return errShortRead + } + field.Set(reflect.ValueOf(n)) + } else { + return fieldError(structType, i, "pointer to unsupported type") + } + default: + return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t)) + } + } + + if len(data) != 0 { + return parseError(expectedType) + } + + return nil +} + +// Marshal serializes the message in msg to SSH wire format. The msg +// argument should be a struct or pointer to struct. If the first +// member has the "sshtype" tag set to a number in decimal, that +// number is prepended to the result. If the last of member has the +// "ssh" tag set to "rest", its contents are appended to the output. +func Marshal(msg interface{}) []byte { + out := make([]byte, 0, 64) + return marshalStruct(out, msg) +} + +func marshalStruct(out []byte, msg interface{}) []byte { + v := reflect.Indirect(reflect.ValueOf(msg)) + msgTypes := typeTags(v.Type()) + if len(msgTypes) > 0 { + out = append(out, msgTypes[0]) + } + + for i, n := 0, v.NumField(); i < n; i++ { + field := v.Field(i) + switch t := field.Type(); t.Kind() { + case reflect.Bool: + var v uint8 + if field.Bool() { + v = 1 + } + out = append(out, v) + case reflect.Array: + if t.Elem().Kind() != reflect.Uint8 { + panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface())) + } + for j, l := 0, t.Len(); j < l; j++ { + out = append(out, uint8(field.Index(j).Uint())) + } + case reflect.Uint32: + out = appendU32(out, uint32(field.Uint())) + case reflect.Uint64: + out = appendU64(out, uint64(field.Uint())) + case reflect.Uint8: + out = append(out, uint8(field.Uint())) + case reflect.String: + s := field.String() + out = appendInt(out, len(s)) + out = append(out, s...) + case reflect.Slice: + switch t.Elem().Kind() { + case reflect.Uint8: + if v.Type().Field(i).Tag.Get("ssh") != "rest" { + out = appendInt(out, field.Len()) + } + out = append(out, field.Bytes()...) + case reflect.String: + offset := len(out) + out = appendU32(out, 0) + if n := field.Len(); n > 0 { + for j := 0; j < n; j++ { + f := field.Index(j) + if j != 0 { + out = append(out, ',') + } + out = append(out, f.String()...) + } + // overwrite length value + binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4)) + } + default: + panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface())) + } + case reflect.Ptr: + if t == bigIntType { + var n *big.Int + nValue := reflect.ValueOf(&n) + nValue.Elem().Set(field) + needed := intLength(n) + oldLength := len(out) + + if cap(out)-len(out) < needed { + newOut := make([]byte, len(out), 2*(len(out)+needed)) + copy(newOut, out) + out = newOut + } + out = out[:oldLength+needed] + marshalInt(out[oldLength:], n) + } else { + panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface())) + } + } + } + + return out +} + +var bigOne = big.NewInt(1) + +func parseString(in []byte) (out, rest []byte, ok bool) { + if len(in) < 4 { + return + } + length := binary.BigEndian.Uint32(in) + in = in[4:] + if uint32(len(in)) < length { + return + } + out = in[:length] + rest = in[length:] + ok = true + return +} + +var ( + comma = []byte{','} + emptyNameList = []string{} +) + +func parseNameList(in []byte) (out []string, rest []byte, ok bool) { + contents, rest, ok := parseString(in) + if !ok { + return + } + if len(contents) == 0 { + out = emptyNameList + return + } + parts := bytes.Split(contents, comma) + out = make([]string, len(parts)) + for i, part := range parts { + out[i] = string(part) + } + return +} + +func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { + contents, rest, ok := parseString(in) + if !ok { + return + } + out = new(big.Int) + + if len(contents) > 0 && contents[0]&0x80 == 0x80 { + // This is a negative number + notBytes := make([]byte, len(contents)) + for i := range notBytes { + notBytes[i] = ^contents[i] + } + out.SetBytes(notBytes) + out.Add(out, bigOne) + out.Neg(out) + } else { + // Positive number + out.SetBytes(contents) + } + ok = true + return +} + +func parseUint32(in []byte) (uint32, []byte, bool) { + if len(in) < 4 { + return 0, nil, false + } + return binary.BigEndian.Uint32(in), in[4:], true +} + +func parseUint64(in []byte) (uint64, []byte, bool) { + if len(in) < 8 { + return 0, nil, false + } + return binary.BigEndian.Uint64(in), in[8:], true +} + +func intLength(n *big.Int) int { + length := 4 /* length bytes */ + if n.Sign() < 0 { + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bitLen := nMinus1.BitLen() + if bitLen%8 == 0 { + // The number will need 0xff padding + length++ + } + length += (bitLen + 7) / 8 + } else if n.Sign() == 0 { + // A zero is the zero length string + } else { + bitLen := n.BitLen() + if bitLen%8 == 0 { + // The number will need 0x00 padding + length++ + } + length += (bitLen + 7) / 8 + } + + return length +} + +func marshalUint32(to []byte, n uint32) []byte { + binary.BigEndian.PutUint32(to, n) + return to[4:] +} + +func marshalUint64(to []byte, n uint64) []byte { + binary.BigEndian.PutUint64(to, n) + return to[8:] +} + +func marshalInt(to []byte, n *big.Int) []byte { + lengthBytes := to + to = to[4:] + length := 0 + + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement + // form. So we'll subtract 1 and invert. If the + // most-significant-bit isn't set then we'll need to pad the + // beginning with 0xff in order to keep the number negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if len(bytes) == 0 || bytes[0]&0x80 == 0 { + to[0] = 0xff + to = to[1:] + length++ + } + nBytes := copy(to, bytes) + to = to[nBytes:] + length += nBytes + } else if n.Sign() == 0 { + // A zero is the zero length string + } else { + bytes := n.Bytes() + if len(bytes) > 0 && bytes[0]&0x80 != 0 { + // We'll have to pad this with a 0x00 in order to + // stop it looking like a negative number. + to[0] = 0 + to = to[1:] + length++ + } + nBytes := copy(to, bytes) + to = to[nBytes:] + length += nBytes + } + + lengthBytes[0] = byte(length >> 24) + lengthBytes[1] = byte(length >> 16) + lengthBytes[2] = byte(length >> 8) + lengthBytes[3] = byte(length) + return to +} + +func writeInt(w io.Writer, n *big.Int) { + length := intLength(n) + buf := make([]byte, length) + marshalInt(buf, n) + w.Write(buf) +} + +func writeString(w io.Writer, s []byte) { + var lengthBytes [4]byte + lengthBytes[0] = byte(len(s) >> 24) + lengthBytes[1] = byte(len(s) >> 16) + lengthBytes[2] = byte(len(s) >> 8) + lengthBytes[3] = byte(len(s)) + w.Write(lengthBytes[:]) + w.Write(s) +} + +func stringLength(n int) int { + return 4 + n +} + +func marshalString(to []byte, s []byte) []byte { + to[0] = byte(len(s) >> 24) + to[1] = byte(len(s) >> 16) + to[2] = byte(len(s) >> 8) + to[3] = byte(len(s)) + to = to[4:] + copy(to, s) + return to[len(s):] +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)) + +// Decode a packet into its corresponding message. +func decode(packet []byte) (interface{}, error) { + var msg interface{} + switch packet[0] { + case msgDisconnect: + msg = new(disconnectMsg) + case msgServiceRequest: + msg = new(serviceRequestMsg) + case msgServiceAccept: + msg = new(serviceAcceptMsg) + case msgKexInit: + msg = new(kexInitMsg) + case msgKexDHInit: + msg = new(kexDHInitMsg) + case msgKexDHReply: + msg = new(kexDHReplyMsg) + case msgUserAuthRequest: + msg = new(userAuthRequestMsg) + case msgUserAuthSuccess: + return new(userAuthSuccessMsg), nil + case msgUserAuthFailure: + msg = new(userAuthFailureMsg) + case msgUserAuthPubKeyOk: + msg = new(userAuthPubKeyOkMsg) + case msgGlobalRequest: + msg = new(globalRequestMsg) + case msgRequestSuccess: + msg = new(globalRequestSuccessMsg) + case msgRequestFailure: + msg = new(globalRequestFailureMsg) + case msgChannelOpen: + msg = new(channelOpenMsg) + case msgChannelData: + msg = new(channelDataMsg) + case msgChannelOpenConfirm: + msg = new(channelOpenConfirmMsg) + case msgChannelOpenFailure: + msg = new(channelOpenFailureMsg) + case msgChannelWindowAdjust: + msg = new(windowAdjustMsg) + case msgChannelEOF: + msg = new(channelEOFMsg) + case msgChannelClose: + msg = new(channelCloseMsg) + case msgChannelRequest: + msg = new(channelRequestMsg) + case msgChannelSuccess: + msg = new(channelRequestSuccessMsg) + case msgChannelFailure: + msg = new(channelRequestFailureMsg) + default: + return nil, unexpectedMessageError(0, packet[0]) + } + if err := Unmarshal(packet, msg); err != nil { + return nil, err + } + return msg, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/messages_test.go b/vendor/golang.org/x/crypto/ssh/messages_test.go new file mode 100644 index 000000000..e79076412 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/messages_test.go @@ -0,0 +1,288 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "math/big" + "math/rand" + "reflect" + "testing" + "testing/quick" +) + +var intLengthTests = []struct { + val, length int +}{ + {0, 4 + 0}, + {1, 4 + 1}, + {127, 4 + 1}, + {128, 4 + 2}, + {-1, 4 + 1}, +} + +func TestIntLength(t *testing.T) { + for _, test := range intLengthTests { + v := new(big.Int).SetInt64(int64(test.val)) + length := intLength(v) + if length != test.length { + t.Errorf("For %d, got length %d but expected %d", test.val, length, test.length) + } + } +} + +type msgAllTypes struct { + Bool bool `sshtype:"21"` + Array [16]byte + Uint64 uint64 + Uint32 uint32 + Uint8 uint8 + String string + Strings []string + Bytes []byte + Int *big.Int + Rest []byte `ssh:"rest"` +} + +func (t *msgAllTypes) Generate(rand *rand.Rand, size int) reflect.Value { + m := &msgAllTypes{} + m.Bool = rand.Intn(2) == 1 + randomBytes(m.Array[:], rand) + m.Uint64 = uint64(rand.Int63n(1<<63 - 1)) + m.Uint32 = uint32(rand.Intn((1 << 31) - 1)) + m.Uint8 = uint8(rand.Intn(1 << 8)) + m.String = string(m.Array[:]) + m.Strings = randomNameList(rand) + m.Bytes = m.Array[:] + m.Int = randomInt(rand) + m.Rest = m.Array[:] + return reflect.ValueOf(m) +} + +func TestMarshalUnmarshal(t *testing.T) { + rand := rand.New(rand.NewSource(0)) + iface := &msgAllTypes{} + ty := reflect.ValueOf(iface).Type() + + n := 100 + if testing.Short() { + n = 5 + } + for j := 0; j < n; j++ { + v, ok := quick.Value(ty, rand) + if !ok { + t.Errorf("failed to create value") + break + } + + m1 := v.Elem().Interface() + m2 := iface + + marshaled := Marshal(m1) + if err := Unmarshal(marshaled, m2); err != nil { + t.Errorf("Unmarshal %#v: %s", m1, err) + break + } + + if !reflect.DeepEqual(v.Interface(), m2) { + t.Errorf("got: %#v\nwant:%#v\n%x", m2, m1, marshaled) + break + } + } +} + +func TestUnmarshalEmptyPacket(t *testing.T) { + var b []byte + var m channelRequestSuccessMsg + if err := Unmarshal(b, &m); err == nil { + t.Fatalf("unmarshal of empty slice succeeded") + } +} + +func TestUnmarshalUnexpectedPacket(t *testing.T) { + type S struct { + I uint32 `sshtype:"43"` + S string + B bool + } + + s := S{11, "hello", true} + packet := Marshal(s) + packet[0] = 42 + roundtrip := S{} + err := Unmarshal(packet, &roundtrip) + if err == nil { + t.Fatal("expected error, not nil") + } +} + +func TestMarshalPtr(t *testing.T) { + s := struct { + S string + }{"hello"} + + m1 := Marshal(s) + m2 := Marshal(&s) + if !bytes.Equal(m1, m2) { + t.Errorf("got %q, want %q for marshaled pointer", m2, m1) + } +} + +func TestBareMarshalUnmarshal(t *testing.T) { + type S struct { + I uint32 + S string + B bool + } + + s := S{42, "hello", true} + packet := Marshal(s) + roundtrip := S{} + Unmarshal(packet, &roundtrip) + + if !reflect.DeepEqual(s, roundtrip) { + t.Errorf("got %#v, want %#v", roundtrip, s) + } +} + +func TestBareMarshal(t *testing.T) { + type S2 struct { + I uint32 + } + s := S2{42} + packet := Marshal(s) + i, rest, ok := parseUint32(packet) + if len(rest) > 0 || !ok { + t.Errorf("parseInt(%q): parse error", packet) + } + if i != s.I { + t.Errorf("got %d, want %d", i, s.I) + } +} + +func TestUnmarshalShortKexInitPacket(t *testing.T) { + // This used to panic. + // Issue 11348 + packet := []byte{0x14, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xff, 0xff, 0xff} + kim := &kexInitMsg{} + if err := Unmarshal(packet, kim); err == nil { + t.Error("truncated packet unmarshaled without error") + } +} + +func TestMarshalMultiTag(t *testing.T) { + var res struct { + A uint32 `sshtype:"1|2"` + } + + good1 := struct { + A uint32 `sshtype:"1"` + }{ + 1, + } + good2 := struct { + A uint32 `sshtype:"2"` + }{ + 1, + } + + if e := Unmarshal(Marshal(good1), &res); e != nil { + t.Errorf("error unmarshaling multipart tag: %v", e) + } + + if e := Unmarshal(Marshal(good2), &res); e != nil { + t.Errorf("error unmarshaling multipart tag: %v", e) + } + + bad1 := struct { + A uint32 `sshtype:"3"` + }{ + 1, + } + if e := Unmarshal(Marshal(bad1), &res); e == nil { + t.Errorf("bad struct unmarshaled without error") + } +} + +func randomBytes(out []byte, rand *rand.Rand) { + for i := 0; i < len(out); i++ { + out[i] = byte(rand.Int31()) + } +} + +func randomNameList(rand *rand.Rand) []string { + ret := make([]string, rand.Int31()&15) + for i := range ret { + s := make([]byte, 1+(rand.Int31()&15)) + for j := range s { + s[j] = 'a' + uint8(rand.Int31()&15) + } + ret[i] = string(s) + } + return ret +} + +func randomInt(rand *rand.Rand) *big.Int { + return new(big.Int).SetInt64(int64(int32(rand.Uint32()))) +} + +func (*kexInitMsg) Generate(rand *rand.Rand, size int) reflect.Value { + ki := &kexInitMsg{} + randomBytes(ki.Cookie[:], rand) + ki.KexAlgos = randomNameList(rand) + ki.ServerHostKeyAlgos = randomNameList(rand) + ki.CiphersClientServer = randomNameList(rand) + ki.CiphersServerClient = randomNameList(rand) + ki.MACsClientServer = randomNameList(rand) + ki.MACsServerClient = randomNameList(rand) + ki.CompressionClientServer = randomNameList(rand) + ki.CompressionServerClient = randomNameList(rand) + ki.LanguagesClientServer = randomNameList(rand) + ki.LanguagesServerClient = randomNameList(rand) + if rand.Int31()&1 == 1 { + ki.FirstKexFollows = true + } + return reflect.ValueOf(ki) +} + +func (*kexDHInitMsg) Generate(rand *rand.Rand, size int) reflect.Value { + dhi := &kexDHInitMsg{} + dhi.X = randomInt(rand) + return reflect.ValueOf(dhi) +} + +var ( + _kexInitMsg = new(kexInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface() + _kexDHInitMsg = new(kexDHInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface() + + _kexInit = Marshal(_kexInitMsg) + _kexDHInit = Marshal(_kexDHInitMsg) +) + +func BenchmarkMarshalKexInitMsg(b *testing.B) { + for i := 0; i < b.N; i++ { + Marshal(_kexInitMsg) + } +} + +func BenchmarkUnmarshalKexInitMsg(b *testing.B) { + m := new(kexInitMsg) + for i := 0; i < b.N; i++ { + Unmarshal(_kexInit, m) + } +} + +func BenchmarkMarshalKexDHInitMsg(b *testing.B) { + for i := 0; i < b.N; i++ { + Marshal(_kexDHInitMsg) + } +} + +func BenchmarkUnmarshalKexDHInitMsg(b *testing.B) { + m := new(kexDHInitMsg) + for i := 0; i < b.N; i++ { + Unmarshal(_kexDHInit, m) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go new file mode 100644 index 000000000..f19016270 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mux.go @@ -0,0 +1,330 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "encoding/binary" + "fmt" + "io" + "log" + "sync" + "sync/atomic" +) + +// debugMux, if set, causes messages in the connection protocol to be +// logged. +const debugMux = false + +// chanList is a thread safe channel list. +type chanList struct { + // protects concurrent access to chans + sync.Mutex + + // chans are indexed by the local id of the channel, which the + // other side should send in the PeersId field. + chans []*channel + + // This is a debugging aid: it offsets all IDs by this + // amount. This helps distinguish otherwise identical + // server/client muxes + offset uint32 +} + +// Assigns a channel ID to the given channel. +func (c *chanList) add(ch *channel) uint32 { + c.Lock() + defer c.Unlock() + for i := range c.chans { + if c.chans[i] == nil { + c.chans[i] = ch + return uint32(i) + c.offset + } + } + c.chans = append(c.chans, ch) + return uint32(len(c.chans)-1) + c.offset +} + +// getChan returns the channel for the given ID. +func (c *chanList) getChan(id uint32) *channel { + id -= c.offset + + c.Lock() + defer c.Unlock() + if id < uint32(len(c.chans)) { + return c.chans[id] + } + return nil +} + +func (c *chanList) remove(id uint32) { + id -= c.offset + c.Lock() + if id < uint32(len(c.chans)) { + c.chans[id] = nil + } + c.Unlock() +} + +// dropAll forgets all channels it knows, returning them in a slice. +func (c *chanList) dropAll() []*channel { + c.Lock() + defer c.Unlock() + var r []*channel + + for _, ch := range c.chans { + if ch == nil { + continue + } + r = append(r, ch) + } + c.chans = nil + return r +} + +// mux represents the state for the SSH connection protocol, which +// multiplexes many channels onto a single packet transport. +type mux struct { + conn packetConn + chanList chanList + + incomingChannels chan NewChannel + + globalSentMu sync.Mutex + globalResponses chan interface{} + incomingRequests chan *Request + + errCond *sync.Cond + err error +} + +// When debugging, each new chanList instantiation has a different +// offset. +var globalOff uint32 + +func (m *mux) Wait() error { + m.errCond.L.Lock() + defer m.errCond.L.Unlock() + for m.err == nil { + m.errCond.Wait() + } + return m.err +} + +// newMux returns a mux that runs over the given connection. +func newMux(p packetConn) *mux { + m := &mux{ + conn: p, + incomingChannels: make(chan NewChannel, chanSize), + globalResponses: make(chan interface{}, 1), + incomingRequests: make(chan *Request, chanSize), + errCond: newCond(), + } + if debugMux { + m.chanList.offset = atomic.AddUint32(&globalOff, 1) + } + + go m.loop() + return m +} + +func (m *mux) sendMessage(msg interface{}) error { + p := Marshal(msg) + if debugMux { + log.Printf("send global(%d): %#v", m.chanList.offset, msg) + } + return m.conn.writePacket(p) +} + +func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { + if wantReply { + m.globalSentMu.Lock() + defer m.globalSentMu.Unlock() + } + + if err := m.sendMessage(globalRequestMsg{ + Type: name, + WantReply: wantReply, + Data: payload, + }); err != nil { + return false, nil, err + } + + if !wantReply { + return false, nil, nil + } + + msg, ok := <-m.globalResponses + if !ok { + return false, nil, io.EOF + } + switch msg := msg.(type) { + case *globalRequestFailureMsg: + return false, msg.Data, nil + case *globalRequestSuccessMsg: + return true, msg.Data, nil + default: + return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) + } +} + +// ackRequest must be called after processing a global request that +// has WantReply set. +func (m *mux) ackRequest(ok bool, data []byte) error { + if ok { + return m.sendMessage(globalRequestSuccessMsg{Data: data}) + } + return m.sendMessage(globalRequestFailureMsg{Data: data}) +} + +func (m *mux) Close() error { + return m.conn.Close() +} + +// loop runs the connection machine. It will process packets until an +// error is encountered. To synchronize on loop exit, use mux.Wait. +func (m *mux) loop() { + var err error + for err == nil { + err = m.onePacket() + } + + for _, ch := range m.chanList.dropAll() { + ch.close() + } + + close(m.incomingChannels) + close(m.incomingRequests) + close(m.globalResponses) + + m.conn.Close() + + m.errCond.L.Lock() + m.err = err + m.errCond.Broadcast() + m.errCond.L.Unlock() + + if debugMux { + log.Println("loop exit", err) + } +} + +// onePacket reads and processes one packet. +func (m *mux) onePacket() error { + packet, err := m.conn.readPacket() + if err != nil { + return err + } + + if debugMux { + if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { + log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) + } else { + p, _ := decode(packet) + log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) + } + } + + switch packet[0] { + case msgChannelOpen: + return m.handleChannelOpen(packet) + case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: + return m.handleGlobalPacket(packet) + } + + // assume a channel packet. + if len(packet) < 5 { + return parseError(packet[0]) + } + id := binary.BigEndian.Uint32(packet[1:]) + ch := m.chanList.getChan(id) + if ch == nil { + return fmt.Errorf("ssh: invalid channel %d", id) + } + + return ch.handlePacket(packet) +} + +func (m *mux) handleGlobalPacket(packet []byte) error { + msg, err := decode(packet) + if err != nil { + return err + } + + switch msg := msg.(type) { + case *globalRequestMsg: + m.incomingRequests <- &Request{ + Type: msg.Type, + WantReply: msg.WantReply, + Payload: msg.Data, + mux: m, + } + case *globalRequestSuccessMsg, *globalRequestFailureMsg: + m.globalResponses <- msg + default: + panic(fmt.Sprintf("not a global message %#v", msg)) + } + + return nil +} + +// handleChannelOpen schedules a channel to be Accept()ed. +func (m *mux) handleChannelOpen(packet []byte) error { + var msg channelOpenMsg + if err := Unmarshal(packet, &msg); err != nil { + return err + } + + if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { + failMsg := channelOpenFailureMsg{ + PeersID: msg.PeersID, + Reason: ConnectionFailed, + Message: "invalid request", + Language: "en_US.UTF-8", + } + return m.sendMessage(failMsg) + } + + c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) + c.remoteId = msg.PeersID + c.maxRemotePayload = msg.MaxPacketSize + c.remoteWin.add(msg.PeersWindow) + m.incomingChannels <- c + return nil +} + +func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { + ch, err := m.openChannel(chanType, extra) + if err != nil { + return nil, nil, err + } + + return ch, ch.incomingRequests, nil +} + +func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { + ch := m.newChannel(chanType, channelOutbound, extra) + + ch.maxIncomingPayload = channelMaxPacket + + open := channelOpenMsg{ + ChanType: chanType, + PeersWindow: ch.myWindow, + MaxPacketSize: ch.maxIncomingPayload, + TypeSpecificData: extra, + PeersID: ch.localId, + } + if err := m.sendMessage(open); err != nil { + return nil, err + } + + switch msg := (<-ch.msg).(type) { + case *channelOpenConfirmMsg: + return ch, nil + case *channelOpenFailureMsg: + return nil, &OpenChannelError{msg.Reason, msg.Message} + default: + return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/mux_test.go b/vendor/golang.org/x/crypto/ssh/mux_test.go new file mode 100644 index 000000000..d88b64e43 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mux_test.go @@ -0,0 +1,501 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "io" + "io/ioutil" + "sync" + "testing" +) + +func muxPair() (*mux, *mux) { + a, b := memPipe() + + s := newMux(a) + c := newMux(b) + + return s, c +} + +// Returns both ends of a channel, and the mux for the the 2nd +// channel. +func channelPair(t *testing.T) (*channel, *channel, *mux) { + c, s := muxPair() + + res := make(chan *channel, 1) + go func() { + newCh, ok := <-s.incomingChannels + if !ok { + t.Fatalf("No incoming channel") + } + if newCh.ChannelType() != "chan" { + t.Fatalf("got type %q want chan", newCh.ChannelType()) + } + ch, _, err := newCh.Accept() + if err != nil { + t.Fatalf("Accept %v", err) + } + res <- ch.(*channel) + }() + + ch, err := c.openChannel("chan", nil) + if err != nil { + t.Fatalf("OpenChannel: %v", err) + } + + return <-res, ch, c +} + +// Test that stderr and stdout can be addressed from different +// goroutines. This is intended for use with the race detector. +func TestMuxChannelExtendedThreadSafety(t *testing.T) { + writer, reader, mux := channelPair(t) + defer writer.Close() + defer reader.Close() + defer mux.Close() + + var wr, rd sync.WaitGroup + magic := "hello world" + + wr.Add(2) + go func() { + io.WriteString(writer, magic) + wr.Done() + }() + go func() { + io.WriteString(writer.Stderr(), magic) + wr.Done() + }() + + rd.Add(2) + go func() { + c, err := ioutil.ReadAll(reader) + if string(c) != magic { + t.Fatalf("stdout read got %q, want %q (error %s)", c, magic, err) + } + rd.Done() + }() + go func() { + c, err := ioutil.ReadAll(reader.Stderr()) + if string(c) != magic { + t.Fatalf("stderr read got %q, want %q (error %s)", c, magic, err) + } + rd.Done() + }() + + wr.Wait() + writer.CloseWrite() + rd.Wait() +} + +func TestMuxReadWrite(t *testing.T) { + s, c, mux := channelPair(t) + defer s.Close() + defer c.Close() + defer mux.Close() + + magic := "hello world" + magicExt := "hello stderr" + go func() { + _, err := s.Write([]byte(magic)) + if err != nil { + t.Fatalf("Write: %v", err) + } + _, err = s.Extended(1).Write([]byte(magicExt)) + if err != nil { + t.Fatalf("Write: %v", err) + } + }() + + var buf [1024]byte + n, err := c.Read(buf[:]) + if err != nil { + t.Fatalf("server Read: %v", err) + } + got := string(buf[:n]) + if got != magic { + t.Fatalf("server: got %q want %q", got, magic) + } + + n, err = c.Extended(1).Read(buf[:]) + if err != nil { + t.Fatalf("server Read: %v", err) + } + + got = string(buf[:n]) + if got != magicExt { + t.Fatalf("server: got %q want %q", got, magic) + } +} + +func TestMuxChannelOverflow(t *testing.T) { + reader, writer, mux := channelPair(t) + defer reader.Close() + defer writer.Close() + defer mux.Close() + + wDone := make(chan int, 1) + go func() { + if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil { + t.Errorf("could not fill window: %v", err) + } + writer.Write(make([]byte, 1)) + wDone <- 1 + }() + writer.remoteWin.waitWriterBlocked() + + // Send 1 byte. + packet := make([]byte, 1+4+4+1) + packet[0] = msgChannelData + marshalUint32(packet[1:], writer.remoteId) + marshalUint32(packet[5:], uint32(1)) + packet[9] = 42 + + if err := writer.mux.conn.writePacket(packet); err != nil { + t.Errorf("could not send packet") + } + if _, err := reader.SendRequest("hello", true, nil); err == nil { + t.Errorf("SendRequest succeeded.") + } + <-wDone +} + +func TestMuxChannelCloseWriteUnblock(t *testing.T) { + reader, writer, mux := channelPair(t) + defer reader.Close() + defer writer.Close() + defer mux.Close() + + wDone := make(chan int, 1) + go func() { + if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil { + t.Errorf("could not fill window: %v", err) + } + if _, err := writer.Write(make([]byte, 1)); err != io.EOF { + t.Errorf("got %v, want EOF for unblock write", err) + } + wDone <- 1 + }() + + writer.remoteWin.waitWriterBlocked() + reader.Close() + <-wDone +} + +func TestMuxConnectionCloseWriteUnblock(t *testing.T) { + reader, writer, mux := channelPair(t) + defer reader.Close() + defer writer.Close() + defer mux.Close() + + wDone := make(chan int, 1) + go func() { + if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil { + t.Errorf("could not fill window: %v", err) + } + if _, err := writer.Write(make([]byte, 1)); err != io.EOF { + t.Errorf("got %v, want EOF for unblock write", err) + } + wDone <- 1 + }() + + writer.remoteWin.waitWriterBlocked() + mux.Close() + <-wDone +} + +func TestMuxReject(t *testing.T) { + client, server := muxPair() + defer server.Close() + defer client.Close() + + go func() { + ch, ok := <-server.incomingChannels + if !ok { + t.Fatalf("Accept") + } + if ch.ChannelType() != "ch" || string(ch.ExtraData()) != "extra" { + t.Fatalf("unexpected channel: %q, %q", ch.ChannelType(), ch.ExtraData()) + } + ch.Reject(RejectionReason(42), "message") + }() + + ch, err := client.openChannel("ch", []byte("extra")) + if ch != nil { + t.Fatal("openChannel not rejected") + } + + ocf, ok := err.(*OpenChannelError) + if !ok { + t.Errorf("got %#v want *OpenChannelError", err) + } else if ocf.Reason != 42 || ocf.Message != "message" { + t.Errorf("got %#v, want {Reason: 42, Message: %q}", ocf, "message") + } + + want := "ssh: rejected: unknown reason 42 (message)" + if err.Error() != want { + t.Errorf("got %q, want %q", err.Error(), want) + } +} + +func TestMuxChannelRequest(t *testing.T) { + client, server, mux := channelPair(t) + defer server.Close() + defer client.Close() + defer mux.Close() + + var received int + var wg sync.WaitGroup + wg.Add(1) + go func() { + for r := range server.incomingRequests { + received++ + r.Reply(r.Type == "yes", nil) + } + wg.Done() + }() + _, err := client.SendRequest("yes", false, nil) + if err != nil { + t.Fatalf("SendRequest: %v", err) + } + ok, err := client.SendRequest("yes", true, nil) + if err != nil { + t.Fatalf("SendRequest: %v", err) + } + + if !ok { + t.Errorf("SendRequest(yes): %v", ok) + + } + + ok, err = client.SendRequest("no", true, nil) + if err != nil { + t.Fatalf("SendRequest: %v", err) + } + if ok { + t.Errorf("SendRequest(no): %v", ok) + + } + + client.Close() + wg.Wait() + + if received != 3 { + t.Errorf("got %d requests, want %d", received, 3) + } +} + +func TestMuxGlobalRequest(t *testing.T) { + clientMux, serverMux := muxPair() + defer serverMux.Close() + defer clientMux.Close() + + var seen bool + go func() { + for r := range serverMux.incomingRequests { + seen = seen || r.Type == "peek" + if r.WantReply { + err := r.Reply(r.Type == "yes", + append([]byte(r.Type), r.Payload...)) + if err != nil { + t.Errorf("AckRequest: %v", err) + } + } + } + }() + + _, _, err := clientMux.SendRequest("peek", false, nil) + if err != nil { + t.Errorf("SendRequest: %v", err) + } + + ok, data, err := clientMux.SendRequest("yes", true, []byte("a")) + if !ok || string(data) != "yesa" || err != nil { + t.Errorf("SendRequest(\"yes\", true, \"a\"): %v %v %v", + ok, data, err) + } + if ok, data, err := clientMux.SendRequest("yes", true, []byte("a")); !ok || string(data) != "yesa" || err != nil { + t.Errorf("SendRequest(\"yes\", true, \"a\"): %v %v %v", + ok, data, err) + } + + if ok, data, err := clientMux.SendRequest("no", true, []byte("a")); ok || string(data) != "noa" || err != nil { + t.Errorf("SendRequest(\"no\", true, \"a\"): %v %v %v", + ok, data, err) + } + + if !seen { + t.Errorf("never saw 'peek' request") + } +} + +func TestMuxGlobalRequestUnblock(t *testing.T) { + clientMux, serverMux := muxPair() + defer serverMux.Close() + defer clientMux.Close() + + result := make(chan error, 1) + go func() { + _, _, err := clientMux.SendRequest("hello", true, nil) + result <- err + }() + + <-serverMux.incomingRequests + serverMux.conn.Close() + err := <-result + + if err != io.EOF { + t.Errorf("want EOF, got %v", io.EOF) + } +} + +func TestMuxChannelRequestUnblock(t *testing.T) { + a, b, connB := channelPair(t) + defer a.Close() + defer b.Close() + defer connB.Close() + + result := make(chan error, 1) + go func() { + _, err := a.SendRequest("hello", true, nil) + result <- err + }() + + <-b.incomingRequests + connB.conn.Close() + err := <-result + + if err != io.EOF { + t.Errorf("want EOF, got %v", err) + } +} + +func TestMuxCloseChannel(t *testing.T) { + r, w, mux := channelPair(t) + defer mux.Close() + defer r.Close() + defer w.Close() + + result := make(chan error, 1) + go func() { + var b [1024]byte + _, err := r.Read(b[:]) + result <- err + }() + if err := w.Close(); err != nil { + t.Errorf("w.Close: %v", err) + } + + if _, err := w.Write([]byte("hello")); err != io.EOF { + t.Errorf("got err %v, want io.EOF after Close", err) + } + + if err := <-result; err != io.EOF { + t.Errorf("got %v (%T), want io.EOF", err, err) + } +} + +func TestMuxCloseWriteChannel(t *testing.T) { + r, w, mux := channelPair(t) + defer mux.Close() + + result := make(chan error, 1) + go func() { + var b [1024]byte + _, err := r.Read(b[:]) + result <- err + }() + if err := w.CloseWrite(); err != nil { + t.Errorf("w.CloseWrite: %v", err) + } + + if _, err := w.Write([]byte("hello")); err != io.EOF { + t.Errorf("got err %v, want io.EOF after CloseWrite", err) + } + + if err := <-result; err != io.EOF { + t.Errorf("got %v (%T), want io.EOF", err, err) + } +} + +func TestMuxInvalidRecord(t *testing.T) { + a, b := muxPair() + defer a.Close() + defer b.Close() + + packet := make([]byte, 1+4+4+1) + packet[0] = msgChannelData + marshalUint32(packet[1:], 29348723 /* invalid channel id */) + marshalUint32(packet[5:], 1) + packet[9] = 42 + + a.conn.writePacket(packet) + go a.SendRequest("hello", false, nil) + // 'a' wrote an invalid packet, so 'b' has exited. + req, ok := <-b.incomingRequests + if ok { + t.Errorf("got request %#v after receiving invalid packet", req) + } +} + +func TestZeroWindowAdjust(t *testing.T) { + a, b, mux := channelPair(t) + defer a.Close() + defer b.Close() + defer mux.Close() + + go func() { + io.WriteString(a, "hello") + // bogus adjust. + a.sendMessage(windowAdjustMsg{}) + io.WriteString(a, "world") + a.Close() + }() + + want := "helloworld" + c, _ := ioutil.ReadAll(b) + if string(c) != want { + t.Errorf("got %q want %q", c, want) + } +} + +func TestMuxMaxPacketSize(t *testing.T) { + a, b, mux := channelPair(t) + defer a.Close() + defer b.Close() + defer mux.Close() + + large := make([]byte, a.maxRemotePayload+1) + packet := make([]byte, 1+4+4+1+len(large)) + packet[0] = msgChannelData + marshalUint32(packet[1:], a.remoteId) + marshalUint32(packet[5:], uint32(len(large))) + packet[9] = 42 + + if err := a.mux.conn.writePacket(packet); err != nil { + t.Errorf("could not send packet") + } + + go a.SendRequest("hello", false, nil) + + _, ok := <-b.incomingRequests + if ok { + t.Errorf("connection still alive after receiving large packet.") + } +} + +// Don't ship code with debug=true. +func TestDebug(t *testing.T) { + if debugMux { + t.Error("mux debug switched on") + } + if debugHandshake { + t.Error("handshake debug switched on") + } + if debugTransport { + t.Error("transport debug switched on") + } +} diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go new file mode 100644 index 000000000..d0f482531 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -0,0 +1,593 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "errors" + "fmt" + "io" + "net" + "strings" +) + +// The Permissions type holds fine-grained permissions that are +// specific to a user or a specific authentication method for a user. +// The Permissions value for a successful authentication attempt is +// available in ServerConn, so it can be used to pass information from +// the user-authentication phase to the application layer. +type Permissions struct { + // CriticalOptions indicate restrictions to the default + // permissions, and are typically used in conjunction with + // user certificates. The standard for SSH certificates + // defines "force-command" (only allow the given command to + // execute) and "source-address" (only allow connections from + // the given address). The SSH package currently only enforces + // the "source-address" critical option. It is up to server + // implementations to enforce other critical options, such as + // "force-command", by checking them after the SSH handshake + // is successful. In general, SSH servers should reject + // connections that specify critical options that are unknown + // or not supported. + CriticalOptions map[string]string + + // Extensions are extra functionality that the server may + // offer on authenticated connections. Lack of support for an + // extension does not preclude authenticating a user. Common + // extensions are "permit-agent-forwarding", + // "permit-X11-forwarding". The Go SSH library currently does + // not act on any extension, and it is up to server + // implementations to honor them. Extensions can be used to + // pass data from the authentication callbacks to the server + // application layer. + Extensions map[string]string +} + +// ServerConfig holds server specific configuration data. +type ServerConfig struct { + // Config contains configuration shared between client and server. + Config + + hostKeys []Signer + + // NoClientAuth is true if clients are allowed to connect without + // authenticating. + NoClientAuth bool + + // MaxAuthTries specifies the maximum number of authentication attempts + // permitted per connection. If set to a negative number, the number of + // attempts are unlimited. If set to zero, the number of attempts are limited + // to 6. + MaxAuthTries int + + // PasswordCallback, if non-nil, is called when a user + // attempts to authenticate using a password. + PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) + + // PublicKeyCallback, if non-nil, is called when a client + // offers a public key for authentication. It must return a nil error + // if the given public key can be used to authenticate the + // given user. For example, see CertChecker.Authenticate. A + // call to this function does not guarantee that the key + // offered is in fact used to authenticate. To record any data + // depending on the public key, store it inside a + // Permissions.Extensions entry. + PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) + + // KeyboardInteractiveCallback, if non-nil, is called when + // keyboard-interactive authentication is selected (RFC + // 4256). The client object's Challenge function should be + // used to query the user. The callback may offer multiple + // Challenge rounds. To avoid information leaks, the client + // should be presented a challenge even if the user is + // unknown. + KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) + + // AuthLogCallback, if non-nil, is called to log all authentication + // attempts. + AuthLogCallback func(conn ConnMetadata, method string, err error) + + // ServerVersion is the version identification string to announce in + // the public handshake. + // If empty, a reasonable default is used. + // Note that RFC 4253 section 4.2 requires that this string start with + // "SSH-2.0-". + ServerVersion string + + // BannerCallback, if present, is called and the return string is sent to + // the client after key exchange completed but before authentication. + BannerCallback func(conn ConnMetadata) string +} + +// AddHostKey adds a private key as a host key. If an existing host +// key exists with the same algorithm, it is overwritten. Each server +// config must have at least one host key. +func (s *ServerConfig) AddHostKey(key Signer) { + for i, k := range s.hostKeys { + if k.PublicKey().Type() == key.PublicKey().Type() { + s.hostKeys[i] = key + return + } + } + + s.hostKeys = append(s.hostKeys, key) +} + +// cachedPubKey contains the results of querying whether a public key is +// acceptable for a user. +type cachedPubKey struct { + user string + pubKeyData []byte + result error + perms *Permissions +} + +const maxCachedPubKeys = 16 + +// pubKeyCache caches tests for public keys. Since SSH clients +// will query whether a public key is acceptable before attempting to +// authenticate with it, we end up with duplicate queries for public +// key validity. The cache only applies to a single ServerConn. +type pubKeyCache struct { + keys []cachedPubKey +} + +// get returns the result for a given user/algo/key tuple. +func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { + for _, k := range c.keys { + if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { + return k, true + } + } + return cachedPubKey{}, false +} + +// add adds the given tuple to the cache. +func (c *pubKeyCache) add(candidate cachedPubKey) { + if len(c.keys) < maxCachedPubKeys { + c.keys = append(c.keys, candidate) + } +} + +// ServerConn is an authenticated SSH connection, as seen from the +// server +type ServerConn struct { + Conn + + // If the succeeding authentication callback returned a + // non-nil Permissions pointer, it is stored here. + Permissions *Permissions +} + +// NewServerConn starts a new SSH server with c as the underlying +// transport. It starts with a handshake and, if the handshake is +// unsuccessful, it closes the connection and returns an error. The +// Request and NewChannel channels must be serviced, or the connection +// will hang. +// +// The returned error may be of type *ServerAuthError for +// authentication errors. +func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { + fullConf := *config + fullConf.SetDefaults() + if fullConf.MaxAuthTries == 0 { + fullConf.MaxAuthTries = 6 + } + + s := &connection{ + sshConn: sshConn{conn: c}, + } + perms, err := s.serverHandshake(&fullConf) + if err != nil { + c.Close() + return nil, nil, nil, err + } + return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil +} + +// signAndMarshal signs the data with the appropriate algorithm, +// and serializes the result in SSH wire format. +func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { + sig, err := k.Sign(rand, data) + if err != nil { + return nil, err + } + + return Marshal(sig), nil +} + +// handshake performs key exchange and user authentication. +func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { + if len(config.hostKeys) == 0 { + return nil, errors.New("ssh: server has no host keys") + } + + if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { + return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") + } + + if config.ServerVersion != "" { + s.serverVersion = []byte(config.ServerVersion) + } else { + s.serverVersion = []byte(packageVersion) + } + var err error + s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) + if err != nil { + return nil, err + } + + tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) + s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) + + if err := s.transport.waitSession(); err != nil { + return nil, err + } + + // We just did the key change, so the session ID is established. + s.sessionID = s.transport.getSessionID() + + var packet []byte + if packet, err = s.transport.readPacket(); err != nil { + return nil, err + } + + var serviceRequest serviceRequestMsg + if err = Unmarshal(packet, &serviceRequest); err != nil { + return nil, err + } + if serviceRequest.Service != serviceUserAuth { + return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") + } + serviceAccept := serviceAcceptMsg{ + Service: serviceUserAuth, + } + if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { + return nil, err + } + + perms, err := s.serverAuthenticate(config) + if err != nil { + return nil, err + } + s.mux = newMux(s.transport) + return perms, err +} + +func isAcceptableAlgo(algo string) bool { + switch algo { + case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519, + CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01: + return true + } + return false +} + +func checkSourceAddress(addr net.Addr, sourceAddrs string) error { + if addr == nil { + return errors.New("ssh: no address known for client, but source-address match required") + } + + tcpAddr, ok := addr.(*net.TCPAddr) + if !ok { + return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) + } + + for _, sourceAddr := range strings.Split(sourceAddrs, ",") { + if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { + if allowedIP.Equal(tcpAddr.IP) { + return nil + } + } else { + _, ipNet, err := net.ParseCIDR(sourceAddr) + if err != nil { + return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) + } + + if ipNet.Contains(tcpAddr.IP) { + return nil + } + } + } + + return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) +} + +// ServerAuthError represents server authentication errors and is +// sometimes returned by NewServerConn. It appends any authentication +// errors that may occur, and is returned if all of the authentication +// methods provided by the user failed to authenticate. +type ServerAuthError struct { + // Errors contains authentication errors returned by the authentication + // callback methods. The first entry is typically ErrNoAuth. + Errors []error +} + +func (l ServerAuthError) Error() string { + var errs []string + for _, err := range l.Errors { + errs = append(errs, err.Error()) + } + return "[" + strings.Join(errs, ", ") + "]" +} + +// ErrNoAuth is the error value returned if no +// authentication method has been passed yet. This happens as a normal +// part of the authentication loop, since the client first tries +// 'none' authentication to discover available methods. +// It is returned in ServerAuthError.Errors from NewServerConn. +var ErrNoAuth = errors.New("ssh: no auth passed yet") + +func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { + sessionID := s.transport.getSessionID() + var cache pubKeyCache + var perms *Permissions + + authFailures := 0 + var authErrs []error + var displayedBanner bool + +userAuthLoop: + for { + if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { + discMsg := &disconnectMsg{ + Reason: 2, + Message: "too many authentication failures", + } + + if err := s.transport.writePacket(Marshal(discMsg)); err != nil { + return nil, err + } + + return nil, discMsg + } + + var userAuthReq userAuthRequestMsg + if packet, err := s.transport.readPacket(); err != nil { + if err == io.EOF { + return nil, &ServerAuthError{Errors: authErrs} + } + return nil, err + } else if err = Unmarshal(packet, &userAuthReq); err != nil { + return nil, err + } + + if userAuthReq.Service != serviceSSH { + return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) + } + + s.user = userAuthReq.User + + if !displayedBanner && config.BannerCallback != nil { + displayedBanner = true + msg := config.BannerCallback(s) + if msg != "" { + bannerMsg := &userAuthBannerMsg{ + Message: msg, + } + if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil { + return nil, err + } + } + } + + perms = nil + authErr := ErrNoAuth + + switch userAuthReq.Method { + case "none": + if config.NoClientAuth { + authErr = nil + } + + // allow initial attempt of 'none' without penalty + if authFailures == 0 { + authFailures-- + } + case "password": + if config.PasswordCallback == nil { + authErr = errors.New("ssh: password auth not configured") + break + } + payload := userAuthReq.Payload + if len(payload) < 1 || payload[0] != 0 { + return nil, parseError(msgUserAuthRequest) + } + payload = payload[1:] + password, payload, ok := parseString(payload) + if !ok || len(payload) > 0 { + return nil, parseError(msgUserAuthRequest) + } + + perms, authErr = config.PasswordCallback(s, password) + case "keyboard-interactive": + if config.KeyboardInteractiveCallback == nil { + authErr = errors.New("ssh: keyboard-interactive auth not configubred") + break + } + + prompter := &sshClientKeyboardInteractive{s} + perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) + case "publickey": + if config.PublicKeyCallback == nil { + authErr = errors.New("ssh: publickey auth not configured") + break + } + payload := userAuthReq.Payload + if len(payload) < 1 { + return nil, parseError(msgUserAuthRequest) + } + isQuery := payload[0] == 0 + payload = payload[1:] + algoBytes, payload, ok := parseString(payload) + if !ok { + return nil, parseError(msgUserAuthRequest) + } + algo := string(algoBytes) + if !isAcceptableAlgo(algo) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) + break + } + + pubKeyData, payload, ok := parseString(payload) + if !ok { + return nil, parseError(msgUserAuthRequest) + } + + pubKey, err := ParsePublicKey(pubKeyData) + if err != nil { + return nil, err + } + + candidate, ok := cache.get(s.user, pubKeyData) + if !ok { + candidate.user = s.user + candidate.pubKeyData = pubKeyData + candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) + if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { + candidate.result = checkSourceAddress( + s.RemoteAddr(), + candidate.perms.CriticalOptions[sourceAddressCriticalOption]) + } + cache.add(candidate) + } + + if isQuery { + // The client can query if the given public key + // would be okay. + + if len(payload) > 0 { + return nil, parseError(msgUserAuthRequest) + } + + if candidate.result == nil { + okMsg := userAuthPubKeyOkMsg{ + Algo: algo, + PubKey: pubKeyData, + } + if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { + return nil, err + } + continue userAuthLoop + } + authErr = candidate.result + } else { + sig, payload, ok := parseSignature(payload) + if !ok || len(payload) > 0 { + return nil, parseError(msgUserAuthRequest) + } + // Ensure the public key algo and signature algo + // are supported. Compare the private key + // algorithm name that corresponds to algo with + // sig.Format. This is usually the same, but + // for certs, the names differ. + if !isAcceptableAlgo(sig.Format) { + break + } + signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) + + if err := pubKey.Verify(signedData, sig); err != nil { + return nil, err + } + + authErr = candidate.result + perms = candidate.perms + } + default: + authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) + } + + authErrs = append(authErrs, authErr) + + if config.AuthLogCallback != nil { + config.AuthLogCallback(s, userAuthReq.Method, authErr) + } + + if authErr == nil { + break userAuthLoop + } + + authFailures++ + + var failureMsg userAuthFailureMsg + if config.PasswordCallback != nil { + failureMsg.Methods = append(failureMsg.Methods, "password") + } + if config.PublicKeyCallback != nil { + failureMsg.Methods = append(failureMsg.Methods, "publickey") + } + if config.KeyboardInteractiveCallback != nil { + failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") + } + + if len(failureMsg.Methods) == 0 { + return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") + } + + if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { + return nil, err + } + } + + if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { + return nil, err + } + return perms, nil +} + +// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by +// asking the client on the other side of a ServerConn. +type sshClientKeyboardInteractive struct { + *connection +} + +func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { + if len(questions) != len(echos) { + return nil, errors.New("ssh: echos and questions must have equal length") + } + + var prompts []byte + for i := range questions { + prompts = appendString(prompts, questions[i]) + prompts = appendBool(prompts, echos[i]) + } + + if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ + Instruction: instruction, + NumPrompts: uint32(len(questions)), + Prompts: prompts, + })); err != nil { + return nil, err + } + + packet, err := c.transport.readPacket() + if err != nil { + return nil, err + } + if packet[0] != msgUserAuthInfoResponse { + return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) + } + packet = packet[1:] + + n, packet, ok := parseUint32(packet) + if !ok || int(n) != len(questions) { + return nil, parseError(msgUserAuthInfoResponse) + } + + for i := uint32(0); i < n; i++ { + ans, rest, ok := parseString(packet) + if !ok { + return nil, parseError(msgUserAuthInfoResponse) + } + + answers = append(answers, string(ans)) + packet = rest + } + if len(packet) != 0 { + return nil, errors.New("ssh: junk at end of message") + } + + return answers, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go new file mode 100644 index 000000000..d3321f6b7 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/session.go @@ -0,0 +1,647 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +// Session implements an interactive session described in +// "RFC 4254, section 6". + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "sync" +) + +type Signal string + +// POSIX signals as listed in RFC 4254 Section 6.10. +const ( + SIGABRT Signal = "ABRT" + SIGALRM Signal = "ALRM" + SIGFPE Signal = "FPE" + SIGHUP Signal = "HUP" + SIGILL Signal = "ILL" + SIGINT Signal = "INT" + SIGKILL Signal = "KILL" + SIGPIPE Signal = "PIPE" + SIGQUIT Signal = "QUIT" + SIGSEGV Signal = "SEGV" + SIGTERM Signal = "TERM" + SIGUSR1 Signal = "USR1" + SIGUSR2 Signal = "USR2" +) + +var signals = map[Signal]int{ + SIGABRT: 6, + SIGALRM: 14, + SIGFPE: 8, + SIGHUP: 1, + SIGILL: 4, + SIGINT: 2, + SIGKILL: 9, + SIGPIPE: 13, + SIGQUIT: 3, + SIGSEGV: 11, + SIGTERM: 15, +} + +type TerminalModes map[uint8]uint32 + +// POSIX terminal mode flags as listed in RFC 4254 Section 8. +const ( + tty_OP_END = 0 + VINTR = 1 + VQUIT = 2 + VERASE = 3 + VKILL = 4 + VEOF = 5 + VEOL = 6 + VEOL2 = 7 + VSTART = 8 + VSTOP = 9 + VSUSP = 10 + VDSUSP = 11 + VREPRINT = 12 + VWERASE = 13 + VLNEXT = 14 + VFLUSH = 15 + VSWTCH = 16 + VSTATUS = 17 + VDISCARD = 18 + IGNPAR = 30 + PARMRK = 31 + INPCK = 32 + ISTRIP = 33 + INLCR = 34 + IGNCR = 35 + ICRNL = 36 + IUCLC = 37 + IXON = 38 + IXANY = 39 + IXOFF = 40 + IMAXBEL = 41 + ISIG = 50 + ICANON = 51 + XCASE = 52 + ECHO = 53 + ECHOE = 54 + ECHOK = 55 + ECHONL = 56 + NOFLSH = 57 + TOSTOP = 58 + IEXTEN = 59 + ECHOCTL = 60 + ECHOKE = 61 + PENDIN = 62 + OPOST = 70 + OLCUC = 71 + ONLCR = 72 + OCRNL = 73 + ONOCR = 74 + ONLRET = 75 + CS7 = 90 + CS8 = 91 + PARENB = 92 + PARODD = 93 + TTY_OP_ISPEED = 128 + TTY_OP_OSPEED = 129 +) + +// A Session represents a connection to a remote command or shell. +type Session struct { + // Stdin specifies the remote process's standard input. + // If Stdin is nil, the remote process reads from an empty + // bytes.Buffer. + Stdin io.Reader + + // Stdout and Stderr specify the remote process's standard + // output and error. + // + // If either is nil, Run connects the corresponding file + // descriptor to an instance of ioutil.Discard. There is a + // fixed amount of buffering that is shared for the two streams. + // If either blocks it may eventually cause the remote + // command to block. + Stdout io.Writer + Stderr io.Writer + + ch Channel // the channel backing this session + started bool // true once Start, Run or Shell is invoked. + copyFuncs []func() error + errors chan error // one send per copyFunc + + // true if pipe method is active + stdinpipe, stdoutpipe, stderrpipe bool + + // stdinPipeWriter is non-nil if StdinPipe has not been called + // and Stdin was specified by the user; it is the write end of + // a pipe connecting Session.Stdin to the stdin channel. + stdinPipeWriter io.WriteCloser + + exitStatus chan error +} + +// SendRequest sends an out-of-band channel request on the SSH channel +// underlying the session. +func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { + return s.ch.SendRequest(name, wantReply, payload) +} + +func (s *Session) Close() error { + return s.ch.Close() +} + +// RFC 4254 Section 6.4. +type setenvRequest struct { + Name string + Value string +} + +// Setenv sets an environment variable that will be applied to any +// command executed by Shell or Run. +func (s *Session) Setenv(name, value string) error { + msg := setenvRequest{ + Name: name, + Value: value, + } + ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) + if err == nil && !ok { + err = errors.New("ssh: setenv failed") + } + return err +} + +// RFC 4254 Section 6.2. +type ptyRequestMsg struct { + Term string + Columns uint32 + Rows uint32 + Width uint32 + Height uint32 + Modelist string +} + +// RequestPty requests the association of a pty with the session on the remote host. +func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { + var tm []byte + for k, v := range termmodes { + kv := struct { + Key byte + Val uint32 + }{k, v} + + tm = append(tm, Marshal(&kv)...) + } + tm = append(tm, tty_OP_END) + req := ptyRequestMsg{ + Term: term, + Columns: uint32(w), + Rows: uint32(h), + Width: uint32(w * 8), + Height: uint32(h * 8), + Modelist: string(tm), + } + ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) + if err == nil && !ok { + err = errors.New("ssh: pty-req failed") + } + return err +} + +// RFC 4254 Section 6.5. +type subsystemRequestMsg struct { + Subsystem string +} + +// RequestSubsystem requests the association of a subsystem with the session on the remote host. +// A subsystem is a predefined command that runs in the background when the ssh session is initiated +func (s *Session) RequestSubsystem(subsystem string) error { + msg := subsystemRequestMsg{ + Subsystem: subsystem, + } + ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) + if err == nil && !ok { + err = errors.New("ssh: subsystem request failed") + } + return err +} + +// RFC 4254 Section 6.7. +type ptyWindowChangeMsg struct { + Columns uint32 + Rows uint32 + Width uint32 + Height uint32 +} + +// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. +func (s *Session) WindowChange(h, w int) error { + req := ptyWindowChangeMsg{ + Columns: uint32(w), + Rows: uint32(h), + Width: uint32(w * 8), + Height: uint32(h * 8), + } + _, err := s.ch.SendRequest("window-change", false, Marshal(&req)) + return err +} + +// RFC 4254 Section 6.9. +type signalMsg struct { + Signal string +} + +// Signal sends the given signal to the remote process. +// sig is one of the SIG* constants. +func (s *Session) Signal(sig Signal) error { + msg := signalMsg{ + Signal: string(sig), + } + + _, err := s.ch.SendRequest("signal", false, Marshal(&msg)) + return err +} + +// RFC 4254 Section 6.5. +type execMsg struct { + Command string +} + +// Start runs cmd on the remote host. Typically, the remote +// server passes cmd to the shell for interpretation. +// A Session only accepts one call to Run, Start or Shell. +func (s *Session) Start(cmd string) error { + if s.started { + return errors.New("ssh: session already started") + } + req := execMsg{ + Command: cmd, + } + + ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) + if err == nil && !ok { + err = fmt.Errorf("ssh: command %v failed", cmd) + } + if err != nil { + return err + } + return s.start() +} + +// Run runs cmd on the remote host. Typically, the remote +// server passes cmd to the shell for interpretation. +// A Session only accepts one call to Run, Start, Shell, Output, +// or CombinedOutput. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the remote server does not send an exit status, an error of type +// *ExitMissingError is returned. If the command completes +// unsuccessfully or is interrupted by a signal, the error is of type +// *ExitError. Other error types may be returned for I/O problems. +func (s *Session) Run(cmd string) error { + err := s.Start(cmd) + if err != nil { + return err + } + return s.Wait() +} + +// Output runs cmd on the remote host and returns its standard output. +func (s *Session) Output(cmd string) ([]byte, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + var b bytes.Buffer + s.Stdout = &b + err := s.Run(cmd) + return b.Bytes(), err +} + +type singleWriter struct { + b bytes.Buffer + mu sync.Mutex +} + +func (w *singleWriter) Write(p []byte) (int, error) { + w.mu.Lock() + defer w.mu.Unlock() + return w.b.Write(p) +} + +// CombinedOutput runs cmd on the remote host and returns its combined +// standard output and standard error. +func (s *Session) CombinedOutput(cmd string) ([]byte, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + if s.Stderr != nil { + return nil, errors.New("ssh: Stderr already set") + } + var b singleWriter + s.Stdout = &b + s.Stderr = &b + err := s.Run(cmd) + return b.b.Bytes(), err +} + +// Shell starts a login shell on the remote host. A Session only +// accepts one call to Run, Start, Shell, Output, or CombinedOutput. +func (s *Session) Shell() error { + if s.started { + return errors.New("ssh: session already started") + } + + ok, err := s.ch.SendRequest("shell", true, nil) + if err == nil && !ok { + return errors.New("ssh: could not start shell") + } + if err != nil { + return err + } + return s.start() +} + +func (s *Session) start() error { + s.started = true + + type F func(*Session) + for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { + setupFd(s) + } + + s.errors = make(chan error, len(s.copyFuncs)) + for _, fn := range s.copyFuncs { + go func(fn func() error) { + s.errors <- fn() + }(fn) + } + return nil +} + +// Wait waits for the remote command to exit. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the remote server does not send an exit status, an error of type +// *ExitMissingError is returned. If the command completes +// unsuccessfully or is interrupted by a signal, the error is of type +// *ExitError. Other error types may be returned for I/O problems. +func (s *Session) Wait() error { + if !s.started { + return errors.New("ssh: session not started") + } + waitErr := <-s.exitStatus + + if s.stdinPipeWriter != nil { + s.stdinPipeWriter.Close() + } + var copyError error + for range s.copyFuncs { + if err := <-s.errors; err != nil && copyError == nil { + copyError = err + } + } + if waitErr != nil { + return waitErr + } + return copyError +} + +func (s *Session) wait(reqs <-chan *Request) error { + wm := Waitmsg{status: -1} + // Wait for msg channel to be closed before returning. + for msg := range reqs { + switch msg.Type { + case "exit-status": + wm.status = int(binary.BigEndian.Uint32(msg.Payload)) + case "exit-signal": + var sigval struct { + Signal string + CoreDumped bool + Error string + Lang string + } + if err := Unmarshal(msg.Payload, &sigval); err != nil { + return err + } + + // Must sanitize strings? + wm.signal = sigval.Signal + wm.msg = sigval.Error + wm.lang = sigval.Lang + default: + // This handles keepalives and matches + // OpenSSH's behaviour. + if msg.WantReply { + msg.Reply(false, nil) + } + } + } + if wm.status == 0 { + return nil + } + if wm.status == -1 { + // exit-status was never sent from server + if wm.signal == "" { + // signal was not sent either. RFC 4254 + // section 6.10 recommends against this + // behavior, but it is allowed, so we let + // clients handle it. + return &ExitMissingError{} + } + wm.status = 128 + if _, ok := signals[Signal(wm.signal)]; ok { + wm.status += signals[Signal(wm.signal)] + } + } + + return &ExitError{wm} +} + +// ExitMissingError is returned if a session is torn down cleanly, but +// the server sends no confirmation of the exit status. +type ExitMissingError struct{} + +func (e *ExitMissingError) Error() string { + return "wait: remote command exited without exit status or exit signal" +} + +func (s *Session) stdin() { + if s.stdinpipe { + return + } + var stdin io.Reader + if s.Stdin == nil { + stdin = new(bytes.Buffer) + } else { + r, w := io.Pipe() + go func() { + _, err := io.Copy(w, s.Stdin) + w.CloseWithError(err) + }() + stdin, s.stdinPipeWriter = r, w + } + s.copyFuncs = append(s.copyFuncs, func() error { + _, err := io.Copy(s.ch, stdin) + if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { + err = err1 + } + return err + }) +} + +func (s *Session) stdout() { + if s.stdoutpipe { + return + } + if s.Stdout == nil { + s.Stdout = ioutil.Discard + } + s.copyFuncs = append(s.copyFuncs, func() error { + _, err := io.Copy(s.Stdout, s.ch) + return err + }) +} + +func (s *Session) stderr() { + if s.stderrpipe { + return + } + if s.Stderr == nil { + s.Stderr = ioutil.Discard + } + s.copyFuncs = append(s.copyFuncs, func() error { + _, err := io.Copy(s.Stderr, s.ch.Stderr()) + return err + }) +} + +// sessionStdin reroutes Close to CloseWrite. +type sessionStdin struct { + io.Writer + ch Channel +} + +func (s *sessionStdin) Close() error { + return s.ch.CloseWrite() +} + +// StdinPipe returns a pipe that will be connected to the +// remote command's standard input when the command starts. +func (s *Session) StdinPipe() (io.WriteCloser, error) { + if s.Stdin != nil { + return nil, errors.New("ssh: Stdin already set") + } + if s.started { + return nil, errors.New("ssh: StdinPipe after process started") + } + s.stdinpipe = true + return &sessionStdin{s.ch, s.ch}, nil +} + +// StdoutPipe returns a pipe that will be connected to the +// remote command's standard output when the command starts. +// There is a fixed amount of buffering that is shared between +// stdout and stderr streams. If the StdoutPipe reader is +// not serviced fast enough it may eventually cause the +// remote command to block. +func (s *Session) StdoutPipe() (io.Reader, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + if s.started { + return nil, errors.New("ssh: StdoutPipe after process started") + } + s.stdoutpipe = true + return s.ch, nil +} + +// StderrPipe returns a pipe that will be connected to the +// remote command's standard error when the command starts. +// There is a fixed amount of buffering that is shared between +// stdout and stderr streams. If the StderrPipe reader is +// not serviced fast enough it may eventually cause the +// remote command to block. +func (s *Session) StderrPipe() (io.Reader, error) { + if s.Stderr != nil { + return nil, errors.New("ssh: Stderr already set") + } + if s.started { + return nil, errors.New("ssh: StderrPipe after process started") + } + s.stderrpipe = true + return s.ch.Stderr(), nil +} + +// newSession returns a new interactive session on the remote host. +func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { + s := &Session{ + ch: ch, + } + s.exitStatus = make(chan error, 1) + go func() { + s.exitStatus <- s.wait(reqs) + }() + + return s, nil +} + +// An ExitError reports unsuccessful completion of a remote command. +type ExitError struct { + Waitmsg +} + +func (e *ExitError) Error() string { + return e.Waitmsg.String() +} + +// Waitmsg stores the information about an exited remote command +// as reported by Wait. +type Waitmsg struct { + status int + signal string + msg string + lang string +} + +// ExitStatus returns the exit status of the remote command. +func (w Waitmsg) ExitStatus() int { + return w.status +} + +// Signal returns the exit signal of the remote command if +// it was terminated violently. +func (w Waitmsg) Signal() string { + return w.signal +} + +// Msg returns the exit message given by the remote command +func (w Waitmsg) Msg() string { + return w.msg +} + +// Lang returns the language tag. See RFC 3066 +func (w Waitmsg) Lang() string { + return w.lang +} + +func (w Waitmsg) String() string { + str := fmt.Sprintf("Process exited with status %v", w.status) + if w.signal != "" { + str += fmt.Sprintf(" from signal %v", w.signal) + } + if w.msg != "" { + str += fmt.Sprintf(". Reason was: %v", w.msg) + } + return str +} diff --git a/vendor/golang.org/x/crypto/ssh/session_test.go b/vendor/golang.org/x/crypto/ssh/session_test.go new file mode 100644 index 000000000..7dce6dd69 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/session_test.go @@ -0,0 +1,774 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +// Session tests. + +import ( + "bytes" + crypto_rand "crypto/rand" + "errors" + "io" + "io/ioutil" + "math/rand" + "net" + "testing" + + "golang.org/x/crypto/ssh/terminal" +) + +type serverType func(Channel, <-chan *Request, *testing.T) + +// dial constructs a new test server and returns a *ClientConn. +func dial(handler serverType, t *testing.T) *Client { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + + go func() { + defer c1.Close() + conf := ServerConfig{ + NoClientAuth: true, + } + conf.AddHostKey(testSigners["rsa"]) + + _, chans, reqs, err := NewServerConn(c1, &conf) + if err != nil { + t.Fatalf("Unable to handshake: %v", err) + } + go DiscardRequests(reqs) + + for newCh := range chans { + if newCh.ChannelType() != "session" { + newCh.Reject(UnknownChannelType, "unknown channel type") + continue + } + + ch, inReqs, err := newCh.Accept() + if err != nil { + t.Errorf("Accept: %v", err) + continue + } + go func() { + handler(ch, inReqs, t) + }() + } + }() + + config := &ClientConfig{ + User: "testuser", + HostKeyCallback: InsecureIgnoreHostKey(), + } + + conn, chans, reqs, err := NewClientConn(c2, "", config) + if err != nil { + t.Fatalf("unable to dial remote side: %v", err) + } + + return NewClient(conn, chans, reqs) +} + +// Test a simple string is returned to session.Stdout. +func TestSessionShell(t *testing.T) { + conn := dial(shellHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + stdout := new(bytes.Buffer) + session.Stdout = stdout + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %s", err) + } + if err := session.Wait(); err != nil { + t.Fatalf("Remote command did not exit cleanly: %v", err) + } + actual := stdout.String() + if actual != "golang" { + t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual) + } +} + +// TODO(dfc) add support for Std{in,err}Pipe when the Server supports it. + +// Test a simple string is returned via StdoutPipe. +func TestSessionStdoutPipe(t *testing.T) { + conn := dial(shellHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + stdout, err := session.StdoutPipe() + if err != nil { + t.Fatalf("Unable to request StdoutPipe(): %v", err) + } + var buf bytes.Buffer + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + done := make(chan bool, 1) + go func() { + if _, err := io.Copy(&buf, stdout); err != nil { + t.Errorf("Copy of stdout failed: %v", err) + } + done <- true + }() + if err := session.Wait(); err != nil { + t.Fatalf("Remote command did not exit cleanly: %v", err) + } + <-done + actual := buf.String() + if actual != "golang" { + t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual) + } +} + +// Test that a simple string is returned via the Output helper, +// and that stderr is discarded. +func TestSessionOutput(t *testing.T) { + conn := dial(fixedOutputHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + + buf, err := session.Output("") // cmd is ignored by fixedOutputHandler + if err != nil { + t.Error("Remote command did not exit cleanly:", err) + } + w := "this-is-stdout." + g := string(buf) + if g != w { + t.Error("Remote command did not return expected string:") + t.Logf("want %q", w) + t.Logf("got %q", g) + } +} + +// Test that both stdout and stderr are returned +// via the CombinedOutput helper. +func TestSessionCombinedOutput(t *testing.T) { + conn := dial(fixedOutputHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + + buf, err := session.CombinedOutput("") // cmd is ignored by fixedOutputHandler + if err != nil { + t.Error("Remote command did not exit cleanly:", err) + } + const stdout = "this-is-stdout." + const stderr = "this-is-stderr." + g := string(buf) + if g != stdout+stderr && g != stderr+stdout { + t.Error("Remote command did not return expected string:") + t.Logf("want %q, or %q", stdout+stderr, stderr+stdout) + t.Logf("got %q", g) + } +} + +// Test non-0 exit status is returned correctly. +func TestExitStatusNonZero(t *testing.T) { + conn := dial(exitStatusNonZeroHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err == nil { + t.Fatalf("expected command to fail but it didn't") + } + e, ok := err.(*ExitError) + if !ok { + t.Fatalf("expected *ExitError but got %T", err) + } + if e.ExitStatus() != 15 { + t.Fatalf("expected command to exit with 15 but got %v", e.ExitStatus()) + } +} + +// Test 0 exit status is returned correctly. +func TestExitStatusZero(t *testing.T) { + conn := dial(exitStatusZeroHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err != nil { + t.Fatalf("expected nil but got %v", err) + } +} + +// Test exit signal and status are both returned correctly. +func TestExitSignalAndStatus(t *testing.T) { + conn := dial(exitSignalAndStatusHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err == nil { + t.Fatalf("expected command to fail but it didn't") + } + e, ok := err.(*ExitError) + if !ok { + t.Fatalf("expected *ExitError but got %T", err) + } + if e.Signal() != "TERM" || e.ExitStatus() != 15 { + t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus()) + } +} + +// Test exit signal and status are both returned correctly. +func TestKnownExitSignalOnly(t *testing.T) { + conn := dial(exitSignalHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err == nil { + t.Fatalf("expected command to fail but it didn't") + } + e, ok := err.(*ExitError) + if !ok { + t.Fatalf("expected *ExitError but got %T", err) + } + if e.Signal() != "TERM" || e.ExitStatus() != 143 { + t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus()) + } +} + +// Test exit signal and status are both returned correctly. +func TestUnknownExitSignal(t *testing.T) { + conn := dial(exitSignalUnknownHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err == nil { + t.Fatalf("expected command to fail but it didn't") + } + e, ok := err.(*ExitError) + if !ok { + t.Fatalf("expected *ExitError but got %T", err) + } + if e.Signal() != "SYS" || e.ExitStatus() != 128 { + t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus()) + } +} + +func TestExitWithoutStatusOrSignal(t *testing.T) { + conn := dial(exitWithoutSignalOrStatus, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %v", err) + } + defer session.Close() + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err == nil { + t.Fatalf("expected command to fail but it didn't") + } + if _, ok := err.(*ExitMissingError); !ok { + t.Fatalf("got %T want *ExitMissingError", err) + } +} + +// windowTestBytes is the number of bytes that we'll send to the SSH server. +const windowTestBytes = 16000 * 200 + +// TestServerWindow writes random data to the server. The server is expected to echo +// the same data back, which is compared against the original. +func TestServerWindow(t *testing.T) { + origBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes)) + io.CopyN(origBuf, crypto_rand.Reader, windowTestBytes) + origBytes := origBuf.Bytes() + + conn := dial(echoHandler, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatal(err) + } + defer session.Close() + result := make(chan []byte) + + go func() { + defer close(result) + echoedBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes)) + serverStdout, err := session.StdoutPipe() + if err != nil { + t.Errorf("StdoutPipe failed: %v", err) + return + } + n, err := copyNRandomly("stdout", echoedBuf, serverStdout, windowTestBytes) + if err != nil && err != io.EOF { + t.Errorf("Read only %d bytes from server, expected %d: %v", n, windowTestBytes, err) + } + result <- echoedBuf.Bytes() + }() + + serverStdin, err := session.StdinPipe() + if err != nil { + t.Fatalf("StdinPipe failed: %v", err) + } + written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes) + if err != nil { + t.Fatalf("failed to copy origBuf to serverStdin: %v", err) + } + if written != windowTestBytes { + t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes) + } + + echoedBytes := <-result + + if !bytes.Equal(origBytes, echoedBytes) { + t.Fatalf("Echoed buffer differed from original, orig %d, echoed %d", len(origBytes), len(echoedBytes)) + } +} + +// Verify the client can handle a keepalive packet from the server. +func TestClientHandlesKeepalives(t *testing.T) { + conn := dial(channelKeepaliveSender, t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatal(err) + } + defer session.Close() + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %v", err) + } + err = session.Wait() + if err != nil { + t.Fatalf("expected nil but got: %v", err) + } +} + +type exitStatusMsg struct { + Status uint32 +} + +type exitSignalMsg struct { + Signal string + CoreDumped bool + Errmsg string + Lang string +} + +func handleTerminalRequests(in <-chan *Request) { + for req := range in { + ok := false + switch req.Type { + case "shell": + ok = true + if len(req.Payload) > 0 { + // We don't accept any commands, only the default shell. + ok = false + } + case "env": + ok = true + } + req.Reply(ok, nil) + } +} + +func newServerShell(ch Channel, in <-chan *Request, prompt string) *terminal.Terminal { + term := terminal.NewTerminal(ch, prompt) + go handleTerminalRequests(in) + return term +} + +func exitStatusZeroHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + // this string is returned to stdout + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + sendStatus(0, ch, t) +} + +func exitStatusNonZeroHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + sendStatus(15, ch, t) +} + +func exitSignalAndStatusHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + sendStatus(15, ch, t) + sendSignal("TERM", ch, t) +} + +func exitSignalHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + sendSignal("TERM", ch, t) +} + +func exitSignalUnknownHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + sendSignal("SYS", ch, t) +} + +func exitWithoutSignalOrStatus(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) +} + +func shellHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + // this string is returned to stdout + shell := newServerShell(ch, in, "golang") + readLine(shell, t) + sendStatus(0, ch, t) +} + +// Ignores the command, writes fixed strings to stderr and stdout. +// Strings are "this-is-stdout." and "this-is-stderr.". +func fixedOutputHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + _, err := ch.Read(nil) + + req, ok := <-in + if !ok { + t.Fatalf("error: expected channel request, got: %#v", err) + return + } + + // ignore request, always send some text + req.Reply(true, nil) + + _, err = io.WriteString(ch, "this-is-stdout.") + if err != nil { + t.Fatalf("error writing on server: %v", err) + } + _, err = io.WriteString(ch.Stderr(), "this-is-stderr.") + if err != nil { + t.Fatalf("error writing on server: %v", err) + } + sendStatus(0, ch, t) +} + +func readLine(shell *terminal.Terminal, t *testing.T) { + if _, err := shell.ReadLine(); err != nil && err != io.EOF { + t.Errorf("unable to read line: %v", err) + } +} + +func sendStatus(status uint32, ch Channel, t *testing.T) { + msg := exitStatusMsg{ + Status: status, + } + if _, err := ch.SendRequest("exit-status", false, Marshal(&msg)); err != nil { + t.Errorf("unable to send status: %v", err) + } +} + +func sendSignal(signal string, ch Channel, t *testing.T) { + sig := exitSignalMsg{ + Signal: signal, + CoreDumped: false, + Errmsg: "Process terminated", + Lang: "en-GB-oed", + } + if _, err := ch.SendRequest("exit-signal", false, Marshal(&sig)); err != nil { + t.Errorf("unable to send signal: %v", err) + } +} + +func discardHandler(ch Channel, t *testing.T) { + defer ch.Close() + io.Copy(ioutil.Discard, ch) +} + +func echoHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err != nil { + t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTestBytes, err) + } +} + +// copyNRandomly copies n bytes from src to dst. It uses a variable, and random, +// buffer size to exercise more code paths. +func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, error) { + var ( + buf = make([]byte, 32*1024) + written int + remaining = n + ) + for remaining > 0 { + l := rand.Intn(1 << 15) + if remaining < l { + l = remaining + } + nr, er := src.Read(buf[:l]) + nw, ew := dst.Write(buf[:nr]) + remaining -= nw + written += nw + if ew != nil { + return written, ew + } + if nr != nw { + return written, io.ErrShortWrite + } + if er != nil && er != io.EOF { + return written, er + } + } + return written, nil +} + +func channelKeepaliveSender(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + shell := newServerShell(ch, in, "> ") + readLine(shell, t) + if _, err := ch.SendRequest("keepalive@openssh.com", true, nil); err != nil { + t.Errorf("unable to send channel keepalive request: %v", err) + } + sendStatus(0, ch, t) +} + +func TestClientWriteEOF(t *testing.T) { + conn := dial(simpleEchoHandler, t) + defer conn.Close() + + session, err := conn.NewSession() + if err != nil { + t.Fatal(err) + } + defer session.Close() + stdin, err := session.StdinPipe() + if err != nil { + t.Fatalf("StdinPipe failed: %v", err) + } + stdout, err := session.StdoutPipe() + if err != nil { + t.Fatalf("StdoutPipe failed: %v", err) + } + + data := []byte(`0000`) + _, err = stdin.Write(data) + if err != nil { + t.Fatalf("Write failed: %v", err) + } + stdin.Close() + + res, err := ioutil.ReadAll(stdout) + if err != nil { + t.Fatalf("Read failed: %v", err) + } + + if !bytes.Equal(data, res) { + t.Fatalf("Read differed from write, wrote: %v, read: %v", data, res) + } +} + +func simpleEchoHandler(ch Channel, in <-chan *Request, t *testing.T) { + defer ch.Close() + data, err := ioutil.ReadAll(ch) + if err != nil { + t.Errorf("handler read error: %v", err) + } + _, err = ch.Write(data) + if err != nil { + t.Errorf("handler write error: %v", err) + } +} + +func TestSessionID(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serverID := make(chan []byte, 1) + clientID := make(chan []byte, 1) + + serverConf := &ServerConfig{ + NoClientAuth: true, + } + serverConf.AddHostKey(testSigners["ecdsa"]) + clientConf := &ClientConfig{ + HostKeyCallback: InsecureIgnoreHostKey(), + User: "user", + } + + go func() { + conn, chans, reqs, err := NewServerConn(c1, serverConf) + if err != nil { + t.Fatalf("server handshake: %v", err) + } + serverID <- conn.SessionID() + go DiscardRequests(reqs) + for ch := range chans { + ch.Reject(Prohibited, "") + } + }() + + go func() { + conn, chans, reqs, err := NewClientConn(c2, "", clientConf) + if err != nil { + t.Fatalf("client handshake: %v", err) + } + clientID <- conn.SessionID() + go DiscardRequests(reqs) + for ch := range chans { + ch.Reject(Prohibited, "") + } + }() + + s := <-serverID + c := <-clientID + if bytes.Compare(s, c) != 0 { + t.Errorf("server session ID (%x) != client session ID (%x)", s, c) + } else if len(s) == 0 { + t.Errorf("client and server SessionID were empty.") + } +} + +type noReadConn struct { + readSeen bool + net.Conn +} + +func (c *noReadConn) Close() error { + return nil +} + +func (c *noReadConn) Read(b []byte) (int, error) { + c.readSeen = true + return 0, errors.New("noReadConn error") +} + +func TestInvalidServerConfiguration(t *testing.T) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + serveConn := noReadConn{Conn: c1} + serverConf := &ServerConfig{} + + NewServerConn(&serveConn, serverConf) + if serveConn.readSeen { + t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing host key") + } + + serverConf.AddHostKey(testSigners["ecdsa"]) + + NewServerConn(&serveConn, serverConf) + if serveConn.readSeen { + t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing authentication method") + } +} + +func TestHostKeyAlgorithms(t *testing.T) { + serverConf := &ServerConfig{ + NoClientAuth: true, + } + serverConf.AddHostKey(testSigners["rsa"]) + serverConf.AddHostKey(testSigners["ecdsa"]) + + connect := func(clientConf *ClientConfig, want string) { + var alg string + clientConf.HostKeyCallback = func(h string, a net.Addr, key PublicKey) error { + alg = key.Type() + return nil + } + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go NewServerConn(c1, serverConf) + _, _, _, err = NewClientConn(c2, "", clientConf) + if err != nil { + t.Fatalf("NewClientConn: %v", err) + } + if alg != want { + t.Errorf("selected key algorithm %s, want %s", alg, want) + } + } + + // By default, we get the preferred algorithm, which is ECDSA 256. + + clientConf := &ClientConfig{ + HostKeyCallback: InsecureIgnoreHostKey(), + } + connect(clientConf, KeyAlgoECDSA256) + + // Client asks for RSA explicitly. + clientConf.HostKeyAlgorithms = []string{KeyAlgoRSA} + connect(clientConf, KeyAlgoRSA) + + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + defer c1.Close() + defer c2.Close() + + go NewServerConn(c1, serverConf) + clientConf.HostKeyAlgorithms = []string{"nonexistent-hostkey-algo"} + _, _, _, err = NewClientConn(c2, "", clientConf) + if err == nil { + t.Fatal("succeeded connecting with unknown hostkey algorithm") + } +} diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go new file mode 100644 index 000000000..b171b330b --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go @@ -0,0 +1,116 @@ +package ssh + +import ( + "errors" + "io" + "net" +) + +// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message +// with "direct-streamlocal@openssh.com" string. +// +// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding +// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235 +type streamLocalChannelOpenDirectMsg struct { + socketPath string + reserved0 string + reserved1 uint32 +} + +// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message +// with "forwarded-streamlocal@openssh.com" string. +type forwardedStreamLocalPayload struct { + SocketPath string + Reserved0 string +} + +// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message +// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string. +type streamLocalChannelForwardMsg struct { + socketPath string +} + +// ListenUnix is similar to ListenTCP but uses a Unix domain socket. +func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) + m := streamLocalChannelForwardMsg{ + socketPath, + } + // send message + ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m)) + if err != nil { + return nil, err + } + if !ok { + return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") + } + ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) + + return &unixListener{socketPath, c, ch}, nil +} + +func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { + msg := streamLocalChannelOpenDirectMsg{ + socketPath: socketPath, + } + ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg)) + if err != nil { + return nil, err + } + go DiscardRequests(in) + return ch, err +} + +type unixListener struct { + socketPath string + + conn *Client + in <-chan forward +} + +// Accept waits for and returns the next connection to the listener. +func (l *unixListener) Accept() (net.Conn, error) { + s, ok := <-l.in + if !ok { + return nil, io.EOF + } + ch, incoming, err := s.newCh.Accept() + if err != nil { + return nil, err + } + go DiscardRequests(incoming) + + return &chanConn{ + Channel: ch, + laddr: &net.UnixAddr{ + Name: l.socketPath, + Net: "unix", + }, + raddr: &net.UnixAddr{ + Name: "@", + Net: "unix", + }, + }, nil +} + +// Close closes the listener. +func (l *unixListener) Close() error { + // this also closes the listener. + l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) + m := streamLocalChannelForwardMsg{ + l.socketPath, + } + ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m)) + if err == nil && !ok { + err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed") + } + return err +} + +// Addr returns the listener's network address. +func (l *unixListener) Addr() net.Addr { + return &net.UnixAddr{ + Name: l.socketPath, + Net: "unix", + } +} diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go new file mode 100644 index 000000000..80d35f5ec --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/tcpip.go @@ -0,0 +1,474 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "errors" + "fmt" + "io" + "math/rand" + "net" + "strconv" + "strings" + "sync" + "time" +) + +// Listen requests the remote peer open a listening socket on +// addr. Incoming connections will be available by calling Accept on +// the returned net.Listener. The listener must be serviced, or the +// SSH connection may hang. +// N must be "tcp", "tcp4", "tcp6", or "unix". +func (c *Client) Listen(n, addr string) (net.Listener, error) { + switch n { + case "tcp", "tcp4", "tcp6": + laddr, err := net.ResolveTCPAddr(n, addr) + if err != nil { + return nil, err + } + return c.ListenTCP(laddr) + case "unix": + return c.ListenUnix(addr) + default: + return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) + } +} + +// Automatic port allocation is broken with OpenSSH before 6.0. See +// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In +// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, +// rather than the actual port number. This means you can never open +// two different listeners with auto allocated ports. We work around +// this by trying explicit ports until we succeed. + +const openSSHPrefix = "OpenSSH_" + +var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) + +// isBrokenOpenSSHVersion returns true if the given version string +// specifies a version of OpenSSH that is known to have a bug in port +// forwarding. +func isBrokenOpenSSHVersion(versionStr string) bool { + i := strings.Index(versionStr, openSSHPrefix) + if i < 0 { + return false + } + i += len(openSSHPrefix) + j := i + for ; j < len(versionStr); j++ { + if versionStr[j] < '0' || versionStr[j] > '9' { + break + } + } + version, _ := strconv.Atoi(versionStr[i:j]) + return version < 6 +} + +// autoPortListenWorkaround simulates automatic port allocation by +// trying random ports repeatedly. +func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { + var sshListener net.Listener + var err error + const tries = 10 + for i := 0; i < tries; i++ { + addr := *laddr + addr.Port = 1024 + portRandomizer.Intn(60000) + sshListener, err = c.ListenTCP(&addr) + if err == nil { + laddr.Port = addr.Port + return sshListener, err + } + } + return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) +} + +// RFC 4254 7.1 +type channelForwardMsg struct { + addr string + rport uint32 +} + +// handleForwards starts goroutines handling forwarded connections. +// It's called on first use by (*Client).ListenTCP to not launch +// goroutines until needed. +func (c *Client) handleForwards() { + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip")) + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com")) +} + +// ListenTCP requests the remote peer open a listening socket +// on laddr. Incoming connections will be available by calling +// Accept on the returned net.Listener. +func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) + if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { + return c.autoPortListenWorkaround(laddr) + } + + m := channelForwardMsg{ + laddr.IP.String(), + uint32(laddr.Port), + } + // send message + ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) + if err != nil { + return nil, err + } + if !ok { + return nil, errors.New("ssh: tcpip-forward request denied by peer") + } + + // If the original port was 0, then the remote side will + // supply a real port number in the response. + if laddr.Port == 0 { + var p struct { + Port uint32 + } + if err := Unmarshal(resp, &p); err != nil { + return nil, err + } + laddr.Port = int(p.Port) + } + + // Register this forward, using the port number we obtained. + ch := c.forwards.add(laddr) + + return &tcpListener{laddr, c, ch}, nil +} + +// forwardList stores a mapping between remote +// forward requests and the tcpListeners. +type forwardList struct { + sync.Mutex + entries []forwardEntry +} + +// forwardEntry represents an established mapping of a laddr on a +// remote ssh server to a channel connected to a tcpListener. +type forwardEntry struct { + laddr net.Addr + c chan forward +} + +// forward represents an incoming forwarded tcpip connection. The +// arguments to add/remove/lookup should be address as specified in +// the original forward-request. +type forward struct { + newCh NewChannel // the ssh client channel underlying this forward + raddr net.Addr // the raddr of the incoming connection +} + +func (l *forwardList) add(addr net.Addr) chan forward { + l.Lock() + defer l.Unlock() + f := forwardEntry{ + laddr: addr, + c: make(chan forward, 1), + } + l.entries = append(l.entries, f) + return f.c +} + +// See RFC 4254, section 7.2 +type forwardedTCPPayload struct { + Addr string + Port uint32 + OriginAddr string + OriginPort uint32 +} + +// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. +func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { + if port == 0 || port > 65535 { + return nil, fmt.Errorf("ssh: port number out of range: %d", port) + } + ip := net.ParseIP(string(addr)) + if ip == nil { + return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) + } + return &net.TCPAddr{IP: ip, Port: int(port)}, nil +} + +func (l *forwardList) handleChannels(in <-chan NewChannel) { + for ch := range in { + var ( + laddr net.Addr + raddr net.Addr + err error + ) + switch channelType := ch.ChannelType(); channelType { + case "forwarded-tcpip": + var payload forwardedTCPPayload + if err = Unmarshal(ch.ExtraData(), &payload); err != nil { + ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) + continue + } + + // RFC 4254 section 7.2 specifies that incoming + // addresses should list the address, in string + // format. It is implied that this should be an IP + // address, as it would be impossible to connect to it + // otherwise. + laddr, err = parseTCPAddr(payload.Addr, payload.Port) + if err != nil { + ch.Reject(ConnectionFailed, err.Error()) + continue + } + raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort) + if err != nil { + ch.Reject(ConnectionFailed, err.Error()) + continue + } + + case "forwarded-streamlocal@openssh.com": + var payload forwardedStreamLocalPayload + if err = Unmarshal(ch.ExtraData(), &payload); err != nil { + ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error()) + continue + } + laddr = &net.UnixAddr{ + Name: payload.SocketPath, + Net: "unix", + } + raddr = &net.UnixAddr{ + Name: "@", + Net: "unix", + } + default: + panic(fmt.Errorf("ssh: unknown channel type %s", channelType)) + } + if ok := l.forward(laddr, raddr, ch); !ok { + // Section 7.2, implementations MUST reject spurious incoming + // connections. + ch.Reject(Prohibited, "no forward for address") + continue + } + + } +} + +// remove removes the forward entry, and the channel feeding its +// listener. +func (l *forwardList) remove(addr net.Addr) { + l.Lock() + defer l.Unlock() + for i, f := range l.entries { + if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() { + l.entries = append(l.entries[:i], l.entries[i+1:]...) + close(f.c) + return + } + } +} + +// closeAll closes and clears all forwards. +func (l *forwardList) closeAll() { + l.Lock() + defer l.Unlock() + for _, f := range l.entries { + close(f.c) + } + l.entries = nil +} + +func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { + l.Lock() + defer l.Unlock() + for _, f := range l.entries { + if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() { + f.c <- forward{newCh: ch, raddr: raddr} + return true + } + } + return false +} + +type tcpListener struct { + laddr *net.TCPAddr + + conn *Client + in <-chan forward +} + +// Accept waits for and returns the next connection to the listener. +func (l *tcpListener) Accept() (net.Conn, error) { + s, ok := <-l.in + if !ok { + return nil, io.EOF + } + ch, incoming, err := s.newCh.Accept() + if err != nil { + return nil, err + } + go DiscardRequests(incoming) + + return &chanConn{ + Channel: ch, + laddr: l.laddr, + raddr: s.raddr, + }, nil +} + +// Close closes the listener. +func (l *tcpListener) Close() error { + m := channelForwardMsg{ + l.laddr.IP.String(), + uint32(l.laddr.Port), + } + + // this also closes the listener. + l.conn.forwards.remove(l.laddr) + ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) + if err == nil && !ok { + err = errors.New("ssh: cancel-tcpip-forward failed") + } + return err +} + +// Addr returns the listener's network address. +func (l *tcpListener) Addr() net.Addr { + return l.laddr +} + +// Dial initiates a connection to the addr from the remote host. +// The resulting connection has a zero LocalAddr() and RemoteAddr(). +func (c *Client) Dial(n, addr string) (net.Conn, error) { + var ch Channel + switch n { + case "tcp", "tcp4", "tcp6": + // Parse the address into host and numeric port. + host, portString, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + port, err := strconv.ParseUint(portString, 10, 16) + if err != nil { + return nil, err + } + ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port)) + if err != nil { + return nil, err + } + // Use a zero address for local and remote address. + zeroAddr := &net.TCPAddr{ + IP: net.IPv4zero, + Port: 0, + } + return &chanConn{ + Channel: ch, + laddr: zeroAddr, + raddr: zeroAddr, + }, nil + case "unix": + var err error + ch, err = c.dialStreamLocal(addr) + if err != nil { + return nil, err + } + return &chanConn{ + Channel: ch, + laddr: &net.UnixAddr{ + Name: "@", + Net: "unix", + }, + raddr: &net.UnixAddr{ + Name: addr, + Net: "unix", + }, + }, nil + default: + return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) + } +} + +// DialTCP connects to the remote address raddr on the network net, +// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used +// as the local address for the connection. +func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { + if laddr == nil { + laddr = &net.TCPAddr{ + IP: net.IPv4zero, + Port: 0, + } + } + ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) + if err != nil { + return nil, err + } + return &chanConn{ + Channel: ch, + laddr: laddr, + raddr: raddr, + }, nil +} + +// RFC 4254 7.2 +type channelOpenDirectMsg struct { + raddr string + rport uint32 + laddr string + lport uint32 +} + +func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { + msg := channelOpenDirectMsg{ + raddr: raddr, + rport: uint32(rport), + laddr: laddr, + lport: uint32(lport), + } + ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) + if err != nil { + return nil, err + } + go DiscardRequests(in) + return ch, err +} + +type tcpChan struct { + Channel // the backing channel +} + +// chanConn fulfills the net.Conn interface without +// the tcpChan having to hold laddr or raddr directly. +type chanConn struct { + Channel + laddr, raddr net.Addr +} + +// LocalAddr returns the local network address. +func (t *chanConn) LocalAddr() net.Addr { + return t.laddr +} + +// RemoteAddr returns the remote network address. +func (t *chanConn) RemoteAddr() net.Addr { + return t.raddr +} + +// SetDeadline sets the read and write deadlines associated +// with the connection. +func (t *chanConn) SetDeadline(deadline time.Time) error { + if err := t.SetReadDeadline(deadline); err != nil { + return err + } + return t.SetWriteDeadline(deadline) +} + +// SetReadDeadline sets the read deadline. +// A zero value for t means Read will not time out. +// After the deadline, the error from Read will implement net.Error +// with Timeout() == true. +func (t *chanConn) SetReadDeadline(deadline time.Time) error { + // for compatibility with previous version, + // the error message contains "tcpChan" + return errors.New("ssh: tcpChan: deadline not supported") +} + +// SetWriteDeadline exists to satisfy the net.Conn interface +// but is not implemented by this type. It always returns an error. +func (t *chanConn) SetWriteDeadline(deadline time.Time) error { + return errors.New("ssh: tcpChan: deadline not supported") +} diff --git a/vendor/golang.org/x/crypto/ssh/tcpip_test.go b/vendor/golang.org/x/crypto/ssh/tcpip_test.go new file mode 100644 index 000000000..f1265cb49 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/tcpip_test.go @@ -0,0 +1,20 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "testing" +) + +func TestAutoPortListenBroken(t *testing.T) { + broken := "SSH-2.0-OpenSSH_5.9hh11" + works := "SSH-2.0-OpenSSH_6.1" + if !isBrokenOpenSSHVersion(broken) { + t.Errorf("version %q not marked as broken", broken) + } + if isBrokenOpenSSHVersion(works) { + t.Errorf("version %q marked as broken", works) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go new file mode 100644 index 000000000..d9b77c1c5 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go @@ -0,0 +1,358 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd windows plan9 solaris + +package terminal + +import ( + "bytes" + "io" + "os" + "runtime" + "testing" +) + +type MockTerminal struct { + toSend []byte + bytesPerRead int + received []byte +} + +func (c *MockTerminal) Read(data []byte) (n int, err error) { + n = len(data) + if n == 0 { + return + } + if n > len(c.toSend) { + n = len(c.toSend) + } + if n == 0 { + return 0, io.EOF + } + if c.bytesPerRead > 0 && n > c.bytesPerRead { + n = c.bytesPerRead + } + copy(data, c.toSend[:n]) + c.toSend = c.toSend[n:] + return +} + +func (c *MockTerminal) Write(data []byte) (n int, err error) { + c.received = append(c.received, data...) + return len(data), nil +} + +func TestClose(t *testing.T) { + c := &MockTerminal{} + ss := NewTerminal(c, "> ") + line, err := ss.ReadLine() + if line != "" { + t.Errorf("Expected empty line but got: %s", line) + } + if err != io.EOF { + t.Errorf("Error should have been EOF but got: %s", err) + } +} + +var keyPressTests = []struct { + in string + line string + err error + throwAwayLines int +}{ + { + err: io.EOF, + }, + { + in: "\r", + line: "", + }, + { + in: "foo\r", + line: "foo", + }, + { + in: "a\x1b[Cb\r", // right + line: "ab", + }, + { + in: "a\x1b[Db\r", // left + line: "ba", + }, + { + in: "a\177b\r", // backspace + line: "b", + }, + { + in: "\x1b[A\r", // up + }, + { + in: "\x1b[B\r", // down + }, + { + in: "line\x1b[A\x1b[B\r", // up then down + line: "line", + }, + { + in: "line1\rline2\x1b[A\r", // recall previous line. + line: "line1", + throwAwayLines: 1, + }, + { + // recall two previous lines and append. + in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r", + line: "line1xxx", + throwAwayLines: 2, + }, + { + // Ctrl-A to move to beginning of line followed by ^K to kill + // line. + in: "a b \001\013\r", + line: "", + }, + { + // Ctrl-A to move to beginning of line, Ctrl-E to move to end, + // finally ^K to kill nothing. + in: "a b \001\005\013\r", + line: "a b ", + }, + { + in: "\027\r", + line: "", + }, + { + in: "a\027\r", + line: "", + }, + { + in: "a \027\r", + line: "", + }, + { + in: "a b\027\r", + line: "a ", + }, + { + in: "a b \027\r", + line: "a ", + }, + { + in: "one two thr\x1b[D\027\r", + line: "one two r", + }, + { + in: "\013\r", + line: "", + }, + { + in: "a\013\r", + line: "a", + }, + { + in: "ab\x1b[D\013\r", + line: "a", + }, + { + in: "Ξεσκεπάζω\r", + line: "Ξεσκεπάζω", + }, + { + in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace. + line: "", + throwAwayLines: 1, + }, + { + in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter. + line: "£", + throwAwayLines: 1, + }, + { + // Ctrl-D at the end of the line should be ignored. + in: "a\004\r", + line: "a", + }, + { + // a, b, left, Ctrl-D should erase the b. + in: "ab\x1b[D\004\r", + line: "a", + }, + { + // a, b, c, d, left, left, ^U should erase to the beginning of + // the line. + in: "abcd\x1b[D\x1b[D\025\r", + line: "cd", + }, + { + // Bracketed paste mode: control sequences should be returned + // verbatim in paste mode. + in: "abc\x1b[200~de\177f\x1b[201~\177\r", + line: "abcde\177", + }, + { + // Enter in bracketed paste mode should still work. + in: "abc\x1b[200~d\refg\x1b[201~h\r", + line: "efgh", + throwAwayLines: 1, + }, + { + // Lines consisting entirely of pasted data should be indicated as such. + in: "\x1b[200~a\r", + line: "a", + err: ErrPasteIndicator, + }, +} + +func TestKeyPresses(t *testing.T) { + for i, test := range keyPressTests { + for j := 1; j < len(test.in); j++ { + c := &MockTerminal{ + toSend: []byte(test.in), + bytesPerRead: j, + } + ss := NewTerminal(c, "> ") + for k := 0; k < test.throwAwayLines; k++ { + _, err := ss.ReadLine() + if err != nil { + t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err) + } + } + line, err := ss.ReadLine() + if line != test.line { + t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line) + break + } + if err != test.err { + t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err) + break + } + } + } +} + +func TestPasswordNotSaved(t *testing.T) { + c := &MockTerminal{ + toSend: []byte("password\r\x1b[A\r"), + bytesPerRead: 1, + } + ss := NewTerminal(c, "> ") + pw, _ := ss.ReadPassword("> ") + if pw != "password" { + t.Fatalf("failed to read password, got %s", pw) + } + line, _ := ss.ReadLine() + if len(line) > 0 { + t.Fatalf("password was saved in history") + } +} + +var setSizeTests = []struct { + width, height int +}{ + {40, 13}, + {80, 24}, + {132, 43}, +} + +func TestTerminalSetSize(t *testing.T) { + for _, setSize := range setSizeTests { + c := &MockTerminal{ + toSend: []byte("password\r\x1b[A\r"), + bytesPerRead: 1, + } + ss := NewTerminal(c, "> ") + ss.SetSize(setSize.width, setSize.height) + pw, _ := ss.ReadPassword("Password: ") + if pw != "password" { + t.Fatalf("failed to read password, got %s", pw) + } + if string(c.received) != "Password: \r\n" { + t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received) + } + } +} + +func TestReadPasswordLineEnd(t *testing.T) { + var tests = []struct { + input string + want string + }{ + {"\n", ""}, + {"\r\n", ""}, + {"test\r\n", "test"}, + {"testtesttesttes\n", "testtesttesttes"}, + {"testtesttesttes\r\n", "testtesttesttes"}, + {"testtesttesttesttest\n", "testtesttesttesttest"}, + {"testtesttesttesttest\r\n", "testtesttesttesttest"}, + } + for _, test := range tests { + buf := new(bytes.Buffer) + if _, err := buf.WriteString(test.input); err != nil { + t.Fatal(err) + } + + have, err := readPasswordLine(buf) + if err != nil { + t.Errorf("readPasswordLine(%q) failed: %v", test.input, err) + continue + } + if string(have) != test.want { + t.Errorf("readPasswordLine(%q) returns %q, but %q is expected", test.input, string(have), test.want) + continue + } + + if _, err = buf.WriteString(test.input); err != nil { + t.Fatal(err) + } + have, err = readPasswordLine(buf) + if err != nil { + t.Errorf("readPasswordLine(%q) failed: %v", test.input, err) + continue + } + if string(have) != test.want { + t.Errorf("readPasswordLine(%q) returns %q, but %q is expected", test.input, string(have), test.want) + continue + } + } +} + +func TestMakeRawState(t *testing.T) { + fd := int(os.Stdout.Fd()) + if !IsTerminal(fd) { + t.Skip("stdout is not a terminal; skipping test") + } + + st, err := GetState(fd) + if err != nil { + t.Fatalf("failed to get terminal state from GetState: %s", err) + } + + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("MakeRaw not allowed on iOS; skipping test") + } + + defer Restore(fd, st) + raw, err := MakeRaw(fd) + if err != nil { + t.Fatalf("failed to get terminal state from MakeRaw: %s", err) + } + + if *st != *raw { + t.Errorf("states do not match; was %v, expected %v", raw, st) + } +} + +func TestOutputNewlines(t *testing.T) { + // \n should be changed to \r\n in terminal output. + buf := new(bytes.Buffer) + term := NewTerminal(buf, ">") + + term.Write([]byte("1\n2\n")) + output := string(buf.Bytes()) + const expected = "1\r\n2\r\n" + + if output != expected { + t.Errorf("incorrect output: was %q, expected %q", output, expected) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/testdata_test.go b/vendor/golang.org/x/crypto/ssh/testdata_test.go new file mode 100644 index 000000000..2da8c79dc --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/testdata_test.go @@ -0,0 +1,63 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// IMPLEMENTATION NOTE: To avoid a package loop, this file is in three places: +// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three +// instances. + +package ssh + +import ( + "crypto/rand" + "fmt" + + "golang.org/x/crypto/ssh/testdata" +) + +var ( + testPrivateKeys map[string]interface{} + testSigners map[string]Signer + testPublicKeys map[string]PublicKey +) + +func init() { + var err error + + n := len(testdata.PEMBytes) + testPrivateKeys = make(map[string]interface{}, n) + testSigners = make(map[string]Signer, n) + testPublicKeys = make(map[string]PublicKey, n) + for t, k := range testdata.PEMBytes { + testPrivateKeys[t], err = ParseRawPrivateKey(k) + if err != nil { + panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err)) + } + testSigners[t], err = NewSignerFromKey(testPrivateKeys[t]) + if err != nil { + panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err)) + } + testPublicKeys[t] = testSigners[t].PublicKey() + } + + // Create a cert and sign it for use in tests. + testCert := &Certificate{ + Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil + ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage + ValidAfter: 0, // unix epoch + ValidBefore: CertTimeInfinity, // The end of currently representable time. + Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil + Key: testPublicKeys["ecdsa"], + SignatureKey: testPublicKeys["rsa"], + Permissions: Permissions{ + CriticalOptions: map[string]string{}, + Extensions: map[string]string{}, + }, + } + testCert.SignCert(rand.Reader, testSigners["rsa"]) + testPrivateKeys["cert"] = testPrivateKeys["ecdsa"] + testSigners["cert"], err = NewCertSigner(testCert, testSigners["ecdsa"]) + if err != nil { + panic(fmt.Sprintf("Unable to create certificate signer: %v", err)) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go new file mode 100644 index 000000000..f6fae1db4 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/transport.go @@ -0,0 +1,353 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bufio" + "bytes" + "errors" + "io" + "log" +) + +// debugTransport if set, will print packet types as they go over the +// wire. No message decoding is done, to minimize the impact on timing. +const debugTransport = false + +const ( + gcmCipherID = "aes128-gcm@openssh.com" + aes128cbcID = "aes128-cbc" + tripledescbcID = "3des-cbc" +) + +// packetConn represents a transport that implements packet based +// operations. +type packetConn interface { + // Encrypt and send a packet of data to the remote peer. + writePacket(packet []byte) error + + // Read a packet from the connection. The read is blocking, + // i.e. if error is nil, then the returned byte slice is + // always non-empty. + readPacket() ([]byte, error) + + // Close closes the write-side of the connection. + Close() error +} + +// transport is the keyingTransport that implements the SSH packet +// protocol. +type transport struct { + reader connectionState + writer connectionState + + bufReader *bufio.Reader + bufWriter *bufio.Writer + rand io.Reader + isClient bool + io.Closer +} + +// packetCipher represents a combination of SSH encryption/MAC +// protocol. A single instance should be used for one direction only. +type packetCipher interface { + // writePacket encrypts the packet and writes it to w. The + // contents of the packet are generally scrambled. + writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error + + // readPacket reads and decrypts a packet of data. The + // returned packet may be overwritten by future calls of + // readPacket. + readPacket(seqnum uint32, r io.Reader) ([]byte, error) +} + +// connectionState represents one side (read or write) of the +// connection. This is necessary because each direction has its own +// keys, and can even have its own algorithms +type connectionState struct { + packetCipher + seqNum uint32 + dir direction + pendingKeyChange chan packetCipher +} + +// prepareKeyChange sets up key material for a keychange. The key changes in +// both directions are triggered by reading and writing a msgNewKey packet +// respectively. +func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { + ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult) + if err != nil { + return err + } + t.reader.pendingKeyChange <- ciph + + ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult) + if err != nil { + return err + } + t.writer.pendingKeyChange <- ciph + + return nil +} + +func (t *transport) printPacket(p []byte, write bool) { + if len(p) == 0 { + return + } + who := "server" + if t.isClient { + who = "client" + } + what := "read" + if write { + what = "write" + } + + log.Println(what, who, p[0]) +} + +// Read and decrypt next packet. +func (t *transport) readPacket() (p []byte, err error) { + for { + p, err = t.reader.readPacket(t.bufReader) + if err != nil { + break + } + if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { + break + } + } + if debugTransport { + t.printPacket(p, false) + } + + return p, err +} + +func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { + packet, err := s.packetCipher.readPacket(s.seqNum, r) + s.seqNum++ + if err == nil && len(packet) == 0 { + err = errors.New("ssh: zero length packet") + } + + if len(packet) > 0 { + switch packet[0] { + case msgNewKeys: + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher + default: + return nil, errors.New("ssh: got bogus newkeys message") + } + + case msgDisconnect: + // Transform a disconnect message into an + // error. Since this is lowest level at which + // we interpret message types, doing it here + // ensures that we don't have to handle it + // elsewhere. + var msg disconnectMsg + if err := Unmarshal(packet, &msg); err != nil { + return nil, err + } + return nil, &msg + } + } + + // The packet may point to an internal buffer, so copy the + // packet out here. + fresh := make([]byte, len(packet)) + copy(fresh, packet) + + return fresh, err +} + +func (t *transport) writePacket(packet []byte) error { + if debugTransport { + t.printPacket(packet, true) + } + return t.writer.writePacket(t.bufWriter, t.rand, packet) +} + +func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { + changeKeys := len(packet) > 0 && packet[0] == msgNewKeys + + err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) + if err != nil { + return err + } + if err = w.Flush(); err != nil { + return err + } + s.seqNum++ + if changeKeys { + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher + default: + panic("ssh: no key material for msgNewKeys") + } + } + return err +} + +func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { + t := &transport{ + bufReader: bufio.NewReader(rwc), + bufWriter: bufio.NewWriter(rwc), + rand: rand, + reader: connectionState{ + packetCipher: &streamPacketCipher{cipher: noneCipher{}}, + pendingKeyChange: make(chan packetCipher, 1), + }, + writer: connectionState{ + packetCipher: &streamPacketCipher{cipher: noneCipher{}}, + pendingKeyChange: make(chan packetCipher, 1), + }, + Closer: rwc, + } + t.isClient = isClient + + if isClient { + t.reader.dir = serverKeys + t.writer.dir = clientKeys + } else { + t.reader.dir = clientKeys + t.writer.dir = serverKeys + } + + return t +} + +type direction struct { + ivTag []byte + keyTag []byte + macKeyTag []byte +} + +var ( + serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} + clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} +) + +// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as +// described in RFC 4253, section 6.4. direction should either be serverKeys +// (to setup server->client keys) or clientKeys (for client->server keys). +func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { + cipherMode := cipherModes[algs.Cipher] + macMode := macModes[algs.MAC] + + iv := make([]byte, cipherMode.ivSize) + key := make([]byte, cipherMode.keySize) + macKey := make([]byte, macMode.keySize) + + generateKeyMaterial(iv, d.ivTag, kex) + generateKeyMaterial(key, d.keyTag, kex) + generateKeyMaterial(macKey, d.macKeyTag, kex) + + return cipherModes[algs.Cipher].create(key, iv, macKey, algs) +} + +// generateKeyMaterial fills out with key material generated from tag, K, H +// and sessionId, as specified in RFC 4253, section 7.2. +func generateKeyMaterial(out, tag []byte, r *kexResult) { + var digestsSoFar []byte + + h := r.Hash.New() + for len(out) > 0 { + h.Reset() + h.Write(r.K) + h.Write(r.H) + + if len(digestsSoFar) == 0 { + h.Write(tag) + h.Write(r.SessionID) + } else { + h.Write(digestsSoFar) + } + + digest := h.Sum(nil) + n := copy(out, digest) + out = out[n:] + if len(out) > 0 { + digestsSoFar = append(digestsSoFar, digest...) + } + } +} + +const packageVersion = "SSH-2.0-Go" + +// Sends and receives a version line. The versionLine string should +// be US ASCII, start with "SSH-2.0-", and should not include a +// newline. exchangeVersions returns the other side's version line. +func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { + // Contrary to the RFC, we do not ignore lines that don't + // start with "SSH-2.0-" to make the library usable with + // nonconforming servers. + for _, c := range versionLine { + // The spec disallows non US-ASCII chars, and + // specifically forbids null chars. + if c < 32 { + return nil, errors.New("ssh: junk character in version line") + } + } + if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { + return + } + + them, err = readVersion(rw) + return them, err +} + +// maxVersionStringBytes is the maximum number of bytes that we'll +// accept as a version string. RFC 4253 section 4.2 limits this at 255 +// chars +const maxVersionStringBytes = 255 + +// Read version string as specified by RFC 4253, section 4.2. +func readVersion(r io.Reader) ([]byte, error) { + versionString := make([]byte, 0, 64) + var ok bool + var buf [1]byte + + for length := 0; length < maxVersionStringBytes; length++ { + _, err := io.ReadFull(r, buf[:]) + if err != nil { + return nil, err + } + // The RFC says that the version should be terminated with \r\n + // but several SSH servers actually only send a \n. + if buf[0] == '\n' { + if !bytes.HasPrefix(versionString, []byte("SSH-")) { + // RFC 4253 says we need to ignore all version string lines + // except the one containing the SSH version (provided that + // all the lines do not exceed 255 bytes in total). + versionString = versionString[:0] + continue + } + ok = true + break + } + + // non ASCII chars are disallowed, but we are lenient, + // since Go doesn't use null-terminated strings. + + // The RFC allows a comment after a space, however, + // all of it (version and comments) goes into the + // session hash. + versionString = append(versionString, buf[0]) + } + + if !ok { + return nil, errors.New("ssh: overflow reading version string") + } + + // There might be a '\r' on the end which we should remove. + if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { + versionString = versionString[:len(versionString)-1] + } + return versionString, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/transport_test.go b/vendor/golang.org/x/crypto/ssh/transport_test.go new file mode 100644 index 000000000..8445e1e56 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/transport_test.go @@ -0,0 +1,113 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "bytes" + "crypto/rand" + "encoding/binary" + "strings" + "testing" +) + +func TestReadVersion(t *testing.T) { + longVersion := strings.Repeat("SSH-2.0-bla", 50)[:253] + multiLineVersion := strings.Repeat("ignored\r\n", 20) + "SSH-2.0-bla\r\n" + cases := map[string]string{ + "SSH-2.0-bla\r\n": "SSH-2.0-bla", + "SSH-2.0-bla\n": "SSH-2.0-bla", + multiLineVersion: "SSH-2.0-bla", + longVersion + "\r\n": longVersion, + } + + for in, want := range cases { + result, err := readVersion(bytes.NewBufferString(in)) + if err != nil { + t.Errorf("readVersion(%q): %s", in, err) + } + got := string(result) + if got != want { + t.Errorf("got %q, want %q", got, want) + } + } +} + +func TestReadVersionError(t *testing.T) { + longVersion := strings.Repeat("SSH-2.0-bla", 50)[:253] + multiLineVersion := strings.Repeat("ignored\r\n", 50) + "SSH-2.0-bla\r\n" + cases := []string{ + longVersion + "too-long\r\n", + multiLineVersion, + } + for _, in := range cases { + if _, err := readVersion(bytes.NewBufferString(in)); err == nil { + t.Errorf("readVersion(%q) should have failed", in) + } + } +} + +func TestExchangeVersionsBasic(t *testing.T) { + v := "SSH-2.0-bla" + buf := bytes.NewBufferString(v + "\r\n") + them, err := exchangeVersions(buf, []byte("xyz")) + if err != nil { + t.Errorf("exchangeVersions: %v", err) + } + + if want := "SSH-2.0-bla"; string(them) != want { + t.Errorf("got %q want %q for our version", them, want) + } +} + +func TestExchangeVersions(t *testing.T) { + cases := []string{ + "not\x000allowed", + "not allowed\x01\r\n", + } + for _, c := range cases { + buf := bytes.NewBufferString("SSH-2.0-bla\r\n") + if _, err := exchangeVersions(buf, []byte(c)); err == nil { + t.Errorf("exchangeVersions(%q): should have failed", c) + } + } +} + +type closerBuffer struct { + bytes.Buffer +} + +func (b *closerBuffer) Close() error { + return nil +} + +func TestTransportMaxPacketWrite(t *testing.T) { + buf := &closerBuffer{} + tr := newTransport(buf, rand.Reader, true) + huge := make([]byte, maxPacket+1) + err := tr.writePacket(huge) + if err == nil { + t.Errorf("transport accepted write for a huge packet.") + } +} + +func TestTransportMaxPacketReader(t *testing.T) { + var header [5]byte + huge := make([]byte, maxPacket+128) + binary.BigEndian.PutUint32(header[0:], uint32(len(huge))) + // padding. + header[4] = 0 + + buf := &closerBuffer{} + buf.Write(header[:]) + buf.Write(huge) + + tr := newTransport(buf, rand.Reader, true) + _, err := tr.readPacket() + if err == nil { + t.Errorf("transport succeeded reading huge packet.") + } else if !strings.Contains(err.Error(), "large") { + t.Errorf("got %q, should mention %q", err.Error(), "large") + } +} diff --git a/vendor/golang.org/x/net/.gitattributes b/vendor/golang.org/x/net/.gitattributes new file mode 100644 index 000000000..d2f212e5d --- /dev/null +++ b/vendor/golang.org/x/net/.gitattributes @@ -0,0 +1,10 @@ +# Treat all files in this repo as binary, with no git magic updating +# line endings. Windows users contributing to Go will need to use a +# modern version of git and editors capable of LF line endings. +# +# We'll prevent accidental CRLF line endings from entering the repo +# via the git-review gofmt checks. +# +# See golang.org/issue/9281 + +* -text diff --git a/vendor/golang.org/x/net/.gitignore b/vendor/golang.org/x/net/.gitignore new file mode 100644 index 000000000..8339fd61d --- /dev/null +++ b/vendor/golang.org/x/net/.gitignore @@ -0,0 +1,2 @@ +# Add no patterns to .hgignore except for files generated by the build. +last-change diff --git a/vendor/golang.org/x/net/CONTRIBUTING.md b/vendor/golang.org/x/net/CONTRIBUTING.md new file mode 100644 index 000000000..d0485e887 --- /dev/null +++ b/vendor/golang.org/x/net/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/net/README.md b/vendor/golang.org/x/net/README.md new file mode 100644 index 000000000..00a9b6eb2 --- /dev/null +++ b/vendor/golang.org/x/net/README.md @@ -0,0 +1,16 @@ +# Go Networking + +This repository holds supplementary Go networking libraries. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/net`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/net`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit +changes to this repository, see https://golang.org/doc/contribute.html. +The main issue tracker for the net repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/net:" in the +subject line, so it is easy to find. diff --git a/vendor/golang.org/x/net/codereview.cfg b/vendor/golang.org/x/net/codereview.cfg new file mode 100644 index 000000000..3f8b14b64 --- /dev/null +++ b/vendor/golang.org/x/net/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/net/context/context_test.go b/vendor/golang.org/x/net/context/context_test.go new file mode 100644 index 000000000..62844131b --- /dev/null +++ b/vendor/golang.org/x/net/context/context_test.go @@ -0,0 +1,583 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.7 + +package context + +import ( + "fmt" + "math/rand" + "runtime" + "strings" + "sync" + "testing" + "time" +) + +// otherContext is a Context that's not one of the types defined in context.go. +// This lets us test code paths that differ based on the underlying type of the +// Context. +type otherContext struct { + Context +} + +func TestBackground(t *testing.T) { + c := Background() + if c == nil { + t.Fatalf("Background returned nil") + } + select { + case x := <-c.Done(): + t.Errorf("<-c.Done() == %v want nothing (it should block)", x) + default: + } + if got, want := fmt.Sprint(c), "context.Background"; got != want { + t.Errorf("Background().String() = %q want %q", got, want) + } +} + +func TestTODO(t *testing.T) { + c := TODO() + if c == nil { + t.Fatalf("TODO returned nil") + } + select { + case x := <-c.Done(): + t.Errorf("<-c.Done() == %v want nothing (it should block)", x) + default: + } + if got, want := fmt.Sprint(c), "context.TODO"; got != want { + t.Errorf("TODO().String() = %q want %q", got, want) + } +} + +func TestWithCancel(t *testing.T) { + c1, cancel := WithCancel(Background()) + + if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want { + t.Errorf("c1.String() = %q want %q", got, want) + } + + o := otherContext{c1} + c2, _ := WithCancel(o) + contexts := []Context{c1, o, c2} + + for i, c := range contexts { + if d := c.Done(); d == nil { + t.Errorf("c[%d].Done() == %v want non-nil", i, d) + } + if e := c.Err(); e != nil { + t.Errorf("c[%d].Err() == %v want nil", i, e) + } + + select { + case x := <-c.Done(): + t.Errorf("<-c.Done() == %v want nothing (it should block)", x) + default: + } + } + + cancel() + time.Sleep(100 * time.Millisecond) // let cancelation propagate + + for i, c := range contexts { + select { + case <-c.Done(): + default: + t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i) + } + if e := c.Err(); e != Canceled { + t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled) + } + } +} + +func TestParentFinishesChild(t *testing.T) { + // Context tree: + // parent -> cancelChild + // parent -> valueChild -> timerChild + parent, cancel := WithCancel(Background()) + cancelChild, stop := WithCancel(parent) + defer stop() + valueChild := WithValue(parent, "key", "value") + timerChild, stop := WithTimeout(valueChild, 10000*time.Hour) + defer stop() + + select { + case x := <-parent.Done(): + t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) + case x := <-cancelChild.Done(): + t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x) + case x := <-timerChild.Done(): + t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x) + case x := <-valueChild.Done(): + t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x) + default: + } + + // The parent's children should contain the two cancelable children. + pc := parent.(*cancelCtx) + cc := cancelChild.(*cancelCtx) + tc := timerChild.(*timerCtx) + pc.mu.Lock() + if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] { + t.Errorf("bad linkage: pc.children = %v, want %v and %v", + pc.children, cc, tc) + } + pc.mu.Unlock() + + if p, ok := parentCancelCtx(cc.Context); !ok || p != pc { + t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc) + } + if p, ok := parentCancelCtx(tc.Context); !ok || p != pc { + t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc) + } + + cancel() + + pc.mu.Lock() + if len(pc.children) != 0 { + t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children) + } + pc.mu.Unlock() + + // parent and children should all be finished. + check := func(ctx Context, name string) { + select { + case <-ctx.Done(): + default: + t.Errorf("<-%s.Done() blocked, but shouldn't have", name) + } + if e := ctx.Err(); e != Canceled { + t.Errorf("%s.Err() == %v want %v", name, e, Canceled) + } + } + check(parent, "parent") + check(cancelChild, "cancelChild") + check(valueChild, "valueChild") + check(timerChild, "timerChild") + + // WithCancel should return a canceled context on a canceled parent. + precanceledChild := WithValue(parent, "key", "value") + select { + case <-precanceledChild.Done(): + default: + t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have") + } + if e := precanceledChild.Err(); e != Canceled { + t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled) + } +} + +func TestChildFinishesFirst(t *testing.T) { + cancelable, stop := WithCancel(Background()) + defer stop() + for _, parent := range []Context{Background(), cancelable} { + child, cancel := WithCancel(parent) + + select { + case x := <-parent.Done(): + t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) + case x := <-child.Done(): + t.Errorf("<-child.Done() == %v want nothing (it should block)", x) + default: + } + + cc := child.(*cancelCtx) + pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background() + if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) { + t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok) + } + + if pcok { + pc.mu.Lock() + if len(pc.children) != 1 || !pc.children[cc] { + t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc) + } + pc.mu.Unlock() + } + + cancel() + + if pcok { + pc.mu.Lock() + if len(pc.children) != 0 { + t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children) + } + pc.mu.Unlock() + } + + // child should be finished. + select { + case <-child.Done(): + default: + t.Errorf("<-child.Done() blocked, but shouldn't have") + } + if e := child.Err(); e != Canceled { + t.Errorf("child.Err() == %v want %v", e, Canceled) + } + + // parent should not be finished. + select { + case x := <-parent.Done(): + t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) + default: + } + if e := parent.Err(); e != nil { + t.Errorf("parent.Err() == %v want nil", e) + } + } +} + +func testDeadline(c Context, wait time.Duration, t *testing.T) { + select { + case <-time.After(wait): + t.Fatalf("context should have timed out") + case <-c.Done(): + } + if e := c.Err(); e != DeadlineExceeded { + t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded) + } +} + +func TestDeadline(t *testing.T) { + t.Parallel() + const timeUnit = 500 * time.Millisecond + c, _ := WithDeadline(Background(), time.Now().Add(1*timeUnit)) + if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { + t.Errorf("c.String() = %q want prefix %q", got, prefix) + } + testDeadline(c, 2*timeUnit, t) + + c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit)) + o := otherContext{c} + testDeadline(o, 2*timeUnit, t) + + c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit)) + o = otherContext{c} + c, _ = WithDeadline(o, time.Now().Add(3*timeUnit)) + testDeadline(c, 2*timeUnit, t) +} + +func TestTimeout(t *testing.T) { + t.Parallel() + const timeUnit = 500 * time.Millisecond + c, _ := WithTimeout(Background(), 1*timeUnit) + if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { + t.Errorf("c.String() = %q want prefix %q", got, prefix) + } + testDeadline(c, 2*timeUnit, t) + + c, _ = WithTimeout(Background(), 1*timeUnit) + o := otherContext{c} + testDeadline(o, 2*timeUnit, t) + + c, _ = WithTimeout(Background(), 1*timeUnit) + o = otherContext{c} + c, _ = WithTimeout(o, 3*timeUnit) + testDeadline(c, 2*timeUnit, t) +} + +func TestCanceledTimeout(t *testing.T) { + t.Parallel() + const timeUnit = 500 * time.Millisecond + c, _ := WithTimeout(Background(), 2*timeUnit) + o := otherContext{c} + c, cancel := WithTimeout(o, 4*timeUnit) + cancel() + time.Sleep(1 * timeUnit) // let cancelation propagate + select { + case <-c.Done(): + default: + t.Errorf("<-c.Done() blocked, but shouldn't have") + } + if e := c.Err(); e != Canceled { + t.Errorf("c.Err() == %v want %v", e, Canceled) + } +} + +type key1 int +type key2 int + +var k1 = key1(1) +var k2 = key2(1) // same int as k1, different type +var k3 = key2(3) // same type as k2, different int + +func TestValues(t *testing.T) { + check := func(c Context, nm, v1, v2, v3 string) { + if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 { + t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0) + } + if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 { + t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0) + } + if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 { + t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0) + } + } + + c0 := Background() + check(c0, "c0", "", "", "") + + c1 := WithValue(Background(), k1, "c1k1") + check(c1, "c1", "c1k1", "", "") + + if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want { + t.Errorf("c.String() = %q want %q", got, want) + } + + c2 := WithValue(c1, k2, "c2k2") + check(c2, "c2", "c1k1", "c2k2", "") + + c3 := WithValue(c2, k3, "c3k3") + check(c3, "c2", "c1k1", "c2k2", "c3k3") + + c4 := WithValue(c3, k1, nil) + check(c4, "c4", "", "c2k2", "c3k3") + + o0 := otherContext{Background()} + check(o0, "o0", "", "", "") + + o1 := otherContext{WithValue(Background(), k1, "c1k1")} + check(o1, "o1", "c1k1", "", "") + + o2 := WithValue(o1, k2, "o2k2") + check(o2, "o2", "c1k1", "o2k2", "") + + o3 := otherContext{c4} + check(o3, "o3", "", "c2k2", "c3k3") + + o4 := WithValue(o3, k3, nil) + check(o4, "o4", "", "c2k2", "") +} + +func TestAllocs(t *testing.T) { + bg := Background() + for _, test := range []struct { + desc string + f func() + limit float64 + gccgoLimit float64 + }{ + { + desc: "Background()", + f: func() { Background() }, + limit: 0, + gccgoLimit: 0, + }, + { + desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1), + f: func() { + c := WithValue(bg, k1, nil) + c.Value(k1) + }, + limit: 3, + gccgoLimit: 3, + }, + { + desc: "WithTimeout(bg, 15*time.Millisecond)", + f: func() { + c, _ := WithTimeout(bg, 15*time.Millisecond) + <-c.Done() + }, + limit: 8, + gccgoLimit: 16, + }, + { + desc: "WithCancel(bg)", + f: func() { + c, cancel := WithCancel(bg) + cancel() + <-c.Done() + }, + limit: 5, + gccgoLimit: 8, + }, + { + desc: "WithTimeout(bg, 100*time.Millisecond)", + f: func() { + c, cancel := WithTimeout(bg, 100*time.Millisecond) + cancel() + <-c.Done() + }, + limit: 8, + gccgoLimit: 25, + }, + } { + limit := test.limit + if runtime.Compiler == "gccgo" { + // gccgo does not yet do escape analysis. + // TODO(iant): Remove this when gccgo does do escape analysis. + limit = test.gccgoLimit + } + if n := testing.AllocsPerRun(100, test.f); n > limit { + t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit)) + } + } +} + +func TestSimultaneousCancels(t *testing.T) { + root, cancel := WithCancel(Background()) + m := map[Context]CancelFunc{root: cancel} + q := []Context{root} + // Create a tree of contexts. + for len(q) != 0 && len(m) < 100 { + parent := q[0] + q = q[1:] + for i := 0; i < 4; i++ { + ctx, cancel := WithCancel(parent) + m[ctx] = cancel + q = append(q, ctx) + } + } + // Start all the cancels in a random order. + var wg sync.WaitGroup + wg.Add(len(m)) + for _, cancel := range m { + go func(cancel CancelFunc) { + cancel() + wg.Done() + }(cancel) + } + // Wait on all the contexts in a random order. + for ctx := range m { + select { + case <-ctx.Done(): + case <-time.After(1 * time.Second): + buf := make([]byte, 10<<10) + n := runtime.Stack(buf, true) + t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n]) + } + } + // Wait for all the cancel functions to return. + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + select { + case <-done: + case <-time.After(1 * time.Second): + buf := make([]byte, 10<<10) + n := runtime.Stack(buf, true) + t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n]) + } +} + +func TestInterlockedCancels(t *testing.T) { + parent, cancelParent := WithCancel(Background()) + child, cancelChild := WithCancel(parent) + go func() { + parent.Done() + cancelChild() + }() + cancelParent() + select { + case <-child.Done(): + case <-time.After(1 * time.Second): + buf := make([]byte, 10<<10) + n := runtime.Stack(buf, true) + t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n]) + } +} + +func TestLayersCancel(t *testing.T) { + testLayers(t, time.Now().UnixNano(), false) +} + +func TestLayersTimeout(t *testing.T) { + testLayers(t, time.Now().UnixNano(), true) +} + +func testLayers(t *testing.T, seed int64, testTimeout bool) { + rand.Seed(seed) + errorf := func(format string, a ...interface{}) { + t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...) + } + const ( + timeout = 200 * time.Millisecond + minLayers = 30 + ) + type value int + var ( + vals []*value + cancels []CancelFunc + numTimers int + ctx = Background() + ) + for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ { + switch rand.Intn(3) { + case 0: + v := new(value) + ctx = WithValue(ctx, v, v) + vals = append(vals, v) + case 1: + var cancel CancelFunc + ctx, cancel = WithCancel(ctx) + cancels = append(cancels, cancel) + case 2: + var cancel CancelFunc + ctx, cancel = WithTimeout(ctx, timeout) + cancels = append(cancels, cancel) + numTimers++ + } + } + checkValues := func(when string) { + for _, key := range vals { + if val := ctx.Value(key).(*value); key != val { + errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key) + } + } + } + select { + case <-ctx.Done(): + errorf("ctx should not be canceled yet") + default: + } + if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) { + t.Errorf("ctx.String() = %q want prefix %q", s, prefix) + } + t.Log(ctx) + checkValues("before cancel") + if testTimeout { + select { + case <-ctx.Done(): + case <-time.After(timeout + 100*time.Millisecond): + errorf("ctx should have timed out") + } + checkValues("after timeout") + } else { + cancel := cancels[rand.Intn(len(cancels))] + cancel() + select { + case <-ctx.Done(): + default: + errorf("ctx should be canceled") + } + checkValues("after cancel") + } +} + +func TestCancelRemoves(t *testing.T) { + checkChildren := func(when string, ctx Context, want int) { + if got := len(ctx.(*cancelCtx).children); got != want { + t.Errorf("%s: context has %d children, want %d", when, got, want) + } + } + + ctx, _ := WithCancel(Background()) + checkChildren("after creation", ctx, 0) + _, cancel := WithCancel(ctx) + checkChildren("with WithCancel child ", ctx, 1) + cancel() + checkChildren("after cancelling WithCancel child", ctx, 0) + + ctx, _ = WithCancel(Background()) + checkChildren("after creation", ctx, 0) + _, cancel = WithTimeout(ctx, 60*time.Minute) + checkChildren("with WithTimeout child ", ctx, 1) + cancel() + checkChildren("after cancelling WithTimeout child", ctx, 0) +} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go new file mode 100644 index 000000000..72411b1b6 --- /dev/null +++ b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go @@ -0,0 +1,29 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,go1.7 + +package ctxhttp + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" + + "context" +) + +func TestGo17Context(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, "ok") + })) + defer ts.Close() + ctx := context.Background() + resp, err := Get(ctx, http.DefaultClient, ts.URL) + if resp == nil || err != nil { + t.Fatalf("error received from client: %v %v", err, resp) + } + resp.Body.Close() +} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go new file mode 100644 index 000000000..9159cf022 --- /dev/null +++ b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go @@ -0,0 +1,79 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,!go1.7 + +package ctxhttp + +import ( + "net" + "net/http" + "net/http/httptest" + "sync" + "testing" + "time" + + "golang.org/x/net/context" +) + +// golang.org/issue/14065 +func TestClosesResponseBodyOnCancel(t *testing.T) { + defer func() { testHookContextDoneBeforeHeaders = nop }() + defer func() { testHookDoReturned = nop }() + defer func() { testHookDidBodyClose = nop }() + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) + defer ts.Close() + + ctx, cancel := context.WithCancel(context.Background()) + + // closed when Do enters select case <-ctx.Done() + enteredDonePath := make(chan struct{}) + + testHookContextDoneBeforeHeaders = func() { + close(enteredDonePath) + } + + testHookDoReturned = func() { + // We now have the result (the Flush'd headers) at least, + // so we can cancel the request. + cancel() + + // But block the client.Do goroutine from sending + // until Do enters into the <-ctx.Done() path, since + // otherwise if both channels are readable, select + // picks a random one. + <-enteredDonePath + } + + sawBodyClose := make(chan struct{}) + testHookDidBodyClose = func() { close(sawBodyClose) } + + tr := &http.Transport{} + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + req, _ := http.NewRequest("GET", ts.URL, nil) + _, doErr := Do(ctx, c, req) + + select { + case <-sawBodyClose: + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for body to close") + } + + if doErr != ctx.Err() { + t.Errorf("Do error = %v; want %v", doErr, ctx.Err()) + } +} + +type noteCloseConn struct { + net.Conn + onceClose sync.Once + closefn func() +} + +func (c *noteCloseConn) Close() error { + c.onceClose.Do(c.closefn) + return c.Conn.Close() +} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go new file mode 100644 index 000000000..1e4155180 --- /dev/null +++ b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go @@ -0,0 +1,105 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9 + +package ctxhttp + +import ( + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + "time" + + "golang.org/x/net/context" +) + +const ( + requestDuration = 100 * time.Millisecond + requestBody = "ok" +) + +func okHandler(w http.ResponseWriter, r *http.Request) { + time.Sleep(requestDuration) + io.WriteString(w, requestBody) +} + +func TestNoTimeout(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(okHandler)) + defer ts.Close() + + ctx := context.Background() + res, err := Get(ctx, nil, ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if string(slurp) != requestBody { + t.Errorf("body = %q; want %q", slurp, requestBody) + } +} + +func TestCancelBeforeHeaders(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + blockServer := make(chan struct{}) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + cancel() + <-blockServer + io.WriteString(w, requestBody) + })) + defer ts.Close() + defer close(blockServer) + + res, err := Get(ctx, nil, ts.URL) + if err == nil { + res.Body.Close() + t.Fatal("Get returned unexpected nil error") + } + if err != context.Canceled { + t.Errorf("err = %v; want %v", err, context.Canceled) + } +} + +func TestCancelAfterHangingRequest(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.(http.Flusher).Flush() + <-w.(http.CloseNotifier).CloseNotify() + })) + defer ts.Close() + + ctx, cancel := context.WithCancel(context.Background()) + resp, err := Get(ctx, nil, ts.URL) + if err != nil { + t.Fatalf("unexpected error in Get: %v", err) + } + + // Cancel befer reading the body. + // Reading Request.Body should fail, since the request was + // canceled before anything was written. + cancel() + + done := make(chan struct{}) + + go func() { + b, err := ioutil.ReadAll(resp.Body) + if len(b) != 0 || err == nil { + t.Errorf(`Read got (%q, %v); want ("", error)`, b, err) + } + close(done) + }() + + select { + case <-time.After(1 * time.Second): + t.Errorf("Test timed out") + case <-done: + } +} diff --git a/vendor/golang.org/x/net/context/withtimeout_test.go b/vendor/golang.org/x/net/context/withtimeout_test.go new file mode 100644 index 000000000..e6f56691d --- /dev/null +++ b/vendor/golang.org/x/net/context/withtimeout_test.go @@ -0,0 +1,31 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package context_test + +import ( + "fmt" + "time" + + "golang.org/x/net/context" +) + +// This example passes a context with a timeout to tell a blocking function that +// it should abandon its work after the timeout elapses. +func ExampleWithTimeout() { + // Pass a context with a timeout to tell a blocking function that it + // should abandon its work after the timeout elapses. + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + + select { + case <-time.After(1 * time.Second): + fmt.Println("overslept") + case <-ctx.Done(): + fmt.Println(ctx.Err()) // prints "context deadline exceeded" + } + + // Output: + // context deadline exceeded +} diff --git a/vendor/golang.org/x/net/html/atom/atom_test.go b/vendor/golang.org/x/net/html/atom/atom_test.go new file mode 100644 index 000000000..6e33704dd --- /dev/null +++ b/vendor/golang.org/x/net/html/atom/atom_test.go @@ -0,0 +1,109 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package atom + +import ( + "sort" + "testing" +) + +func TestKnown(t *testing.T) { + for _, s := range testAtomList { + if atom := Lookup([]byte(s)); atom.String() != s { + t.Errorf("Lookup(%q) = %#x (%q)", s, uint32(atom), atom.String()) + } + } +} + +func TestHits(t *testing.T) { + for _, a := range table { + if a == 0 { + continue + } + got := Lookup([]byte(a.String())) + if got != a { + t.Errorf("Lookup(%q) = %#x, want %#x", a.String(), uint32(got), uint32(a)) + } + } +} + +func TestMisses(t *testing.T) { + testCases := []string{ + "", + "\x00", + "\xff", + "A", + "DIV", + "Div", + "dIV", + "aa", + "a\x00", + "ab", + "abb", + "abbr0", + "abbr ", + " abbr", + " a", + "acceptcharset", + "acceptCharset", + "accept_charset", + "h0", + "h1h2", + "h7", + "onClick", + "λ", + // The following string has the same hash (0xa1d7fab7) as "onmouseover". + "\x00\x00\x00\x00\x00\x50\x18\xae\x38\xd0\xb7", + } + for _, tc := range testCases { + got := Lookup([]byte(tc)) + if got != 0 { + t.Errorf("Lookup(%q): got %d, want 0", tc, got) + } + } +} + +func TestForeignObject(t *testing.T) { + const ( + afo = Foreignobject + afO = ForeignObject + sfo = "foreignobject" + sfO = "foreignObject" + ) + if got := Lookup([]byte(sfo)); got != afo { + t.Errorf("Lookup(%q): got %#v, want %#v", sfo, got, afo) + } + if got := Lookup([]byte(sfO)); got != afO { + t.Errorf("Lookup(%q): got %#v, want %#v", sfO, got, afO) + } + if got := afo.String(); got != sfo { + t.Errorf("Atom(%#v).String(): got %q, want %q", afo, got, sfo) + } + if got := afO.String(); got != sfO { + t.Errorf("Atom(%#v).String(): got %q, want %q", afO, got, sfO) + } +} + +func BenchmarkLookup(b *testing.B) { + sortedTable := make([]string, 0, len(table)) + for _, a := range table { + if a != 0 { + sortedTable = append(sortedTable, a.String()) + } + } + sort.Strings(sortedTable) + + x := make([][]byte, 1000) + for i := range x { + x[i] = []byte(sortedTable[i%len(sortedTable)]) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, s := range x { + Lookup(s) + } + } +} diff --git a/vendor/golang.org/x/net/html/atom/table_test.go b/vendor/golang.org/x/net/html/atom/table_test.go new file mode 100644 index 000000000..8a30762ec --- /dev/null +++ b/vendor/golang.org/x/net/html/atom/table_test.go @@ -0,0 +1,376 @@ +// Code generated by go generate gen.go; DO NOT EDIT. + +//go:generate go run gen.go -test + +package atom + +var testAtomList = []string{ + "a", + "abbr", + "accept", + "accept-charset", + "accesskey", + "acronym", + "action", + "address", + "align", + "allowfullscreen", + "allowpaymentrequest", + "allowusermedia", + "alt", + "annotation", + "annotation-xml", + "applet", + "area", + "article", + "as", + "aside", + "async", + "audio", + "autocomplete", + "autofocus", + "autoplay", + "b", + "base", + "basefont", + "bdi", + "bdo", + "bgsound", + "big", + "blink", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "center", + "challenge", + "charset", + "checked", + "cite", + "class", + "code", + "col", + "colgroup", + "color", + "cols", + "colspan", + "command", + "content", + "contenteditable", + "contextmenu", + "controls", + "coords", + "crossorigin", + "data", + "datalist", + "datetime", + "dd", + "default", + "defer", + "del", + "desc", + "details", + "dfn", + "dialog", + "dir", + "dirname", + "disabled", + "div", + "dl", + "download", + "draggable", + "dropzone", + "dt", + "em", + "embed", + "enctype", + "face", + "fieldset", + "figcaption", + "figure", + "font", + "footer", + "for", + "foreignObject", + "foreignobject", + "form", + "formaction", + "formenctype", + "formmethod", + "formnovalidate", + "formtarget", + "frame", + "frameset", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "headers", + "height", + "hgroup", + "hidden", + "high", + "hr", + "href", + "hreflang", + "html", + "http-equiv", + "i", + "icon", + "id", + "iframe", + "image", + "img", + "input", + "inputmode", + "ins", + "integrity", + "is", + "isindex", + "ismap", + "itemid", + "itemprop", + "itemref", + "itemscope", + "itemtype", + "kbd", + "keygen", + "keytype", + "kind", + "label", + "lang", + "legend", + "li", + "link", + "list", + "listing", + "loop", + "low", + "main", + "malignmark", + "manifest", + "map", + "mark", + "marquee", + "math", + "max", + "maxlength", + "media", + "mediagroup", + "menu", + "menuitem", + "meta", + "meter", + "method", + "mglyph", + "mi", + "min", + "minlength", + "mn", + "mo", + "ms", + "mtext", + "multiple", + "muted", + "name", + "nav", + "nobr", + "noembed", + "noframes", + "nomodule", + "nonce", + "noscript", + "novalidate", + "object", + "ol", + "onabort", + "onafterprint", + "onautocomplete", + "onautocompleteerror", + "onauxclick", + "onbeforeprint", + "onbeforeunload", + "onblur", + "oncancel", + "oncanplay", + "oncanplaythrough", + "onchange", + "onclick", + "onclose", + "oncontextmenu", + "oncopy", + "oncuechange", + "oncut", + "ondblclick", + "ondrag", + "ondragend", + "ondragenter", + "ondragexit", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onended", + "onerror", + "onfocus", + "onhashchange", + "oninput", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeyup", + "onlanguagechange", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadend", + "onloadstart", + "onmessage", + "onmessageerror", + "onmousedown", + "onmouseenter", + "onmouseleave", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onoffline", + "ononline", + "onpagehide", + "onpageshow", + "onpaste", + "onpause", + "onplay", + "onplaying", + "onpopstate", + "onprogress", + "onratechange", + "onrejectionhandled", + "onreset", + "onresize", + "onscroll", + "onsecuritypolicyviolation", + "onseeked", + "onseeking", + "onselect", + "onshow", + "onsort", + "onstalled", + "onstorage", + "onsubmit", + "onsuspend", + "ontimeupdate", + "ontoggle", + "onunhandledrejection", + "onunload", + "onvolumechange", + "onwaiting", + "onwheel", + "open", + "optgroup", + "optimum", + "option", + "output", + "p", + "param", + "pattern", + "picture", + "ping", + "placeholder", + "plaintext", + "playsinline", + "poster", + "pre", + "preload", + "progress", + "prompt", + "public", + "q", + "radiogroup", + "rb", + "readonly", + "referrerpolicy", + "rel", + "required", + "reversed", + "rows", + "rowspan", + "rp", + "rt", + "rtc", + "ruby", + "s", + "samp", + "sandbox", + "scope", + "scoped", + "script", + "seamless", + "section", + "select", + "selected", + "shape", + "size", + "sizes", + "slot", + "small", + "sortable", + "sorted", + "source", + "spacer", + "span", + "spellcheck", + "src", + "srcdoc", + "srclang", + "srcset", + "start", + "step", + "strike", + "strong", + "style", + "sub", + "summary", + "sup", + "svg", + "system", + "tabindex", + "table", + "target", + "tbody", + "td", + "template", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "translate", + "tt", + "type", + "typemustmatch", + "u", + "ul", + "updateviacache", + "usemap", + "value", + "var", + "video", + "wbr", + "width", + "workertype", + "wrap", + "xmp", +} diff --git a/vendor/golang.org/x/net/html/charset/charset_test.go b/vendor/golang.org/x/net/html/charset/charset_test.go new file mode 100644 index 000000000..e4e7d86bf --- /dev/null +++ b/vendor/golang.org/x/net/html/charset/charset_test.go @@ -0,0 +1,237 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package charset + +import ( + "bytes" + "encoding/xml" + "io/ioutil" + "runtime" + "strings" + "testing" + + "golang.org/x/text/transform" +) + +func transformString(t transform.Transformer, s string) (string, error) { + r := transform.NewReader(strings.NewReader(s), t) + b, err := ioutil.ReadAll(r) + return string(b), err +} + +type testCase struct { + utf8, other, otherEncoding string +} + +// testCases for encoding and decoding. +var testCases = []testCase{ + {"Résumé", "Résumé", "utf8"}, + {"Résumé", "R\xe9sum\xe9", "latin1"}, + {"これは漢字です。", "S0\x8c0o0\"oW[g0Y0\x020", "UTF-16LE"}, + {"これは漢字です。", "0S0\x8c0oo\"[W0g0Y0\x02", "UTF-16BE"}, + {"Hello, world", "Hello, world", "ASCII"}, + {"Gdańsk", "Gda\xf1sk", "ISO-8859-2"}, + {"Ââ Čč Đđ Ŋŋ Õõ Šš Žž Åå Ää", "\xc2\xe2 \xc8\xe8 \xa9\xb9 \xaf\xbf \xd5\xf5 \xaa\xba \xac\xbc \xc5\xe5 \xc4\xe4", "ISO-8859-10"}, + {"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "ISO-8859-11"}, + {"latviešu", "latvie\xf0u", "ISO-8859-13"}, + {"Seònaid", "Se\xf2naid", "ISO-8859-14"}, + {"€1 is cheap", "\xa41 is cheap", "ISO-8859-15"}, + {"românește", "rom\xe2ne\xbate", "ISO-8859-16"}, + {"nutraĵo", "nutra\xbco", "ISO-8859-3"}, + {"Kalâdlit", "Kal\xe2dlit", "ISO-8859-4"}, + {"русский", "\xe0\xe3\xe1\xe1\xda\xd8\xd9", "ISO-8859-5"}, + {"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "ISO-8859-7"}, + {"Kağan", "Ka\xf0an", "ISO-8859-9"}, + {"Résumé", "R\x8esum\x8e", "macintosh"}, + {"Gdańsk", "Gda\xf1sk", "windows-1250"}, + {"русский", "\xf0\xf3\xf1\xf1\xea\xe8\xe9", "windows-1251"}, + {"Résumé", "R\xe9sum\xe9", "windows-1252"}, + {"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "windows-1253"}, + {"Kağan", "Ka\xf0an", "windows-1254"}, + {"עִבְרִית", "\xf2\xc4\xe1\xc0\xf8\xc4\xe9\xfa", "windows-1255"}, + {"العربية", "\xc7\xe1\xda\xd1\xc8\xed\xc9", "windows-1256"}, + {"latviešu", "latvie\xf0u", "windows-1257"}, + {"Việt", "Vi\xea\xf2t", "windows-1258"}, + {"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "windows-874"}, + {"русский", "\xd2\xd5\xd3\xd3\xcb\xc9\xca", "KOI8-R"}, + {"українська", "\xd5\xcb\xd2\xc1\xa7\xce\xd3\xd8\xcb\xc1", "KOI8-U"}, + {"Hello 常用國字標準字體表", "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed", "big5"}, + {"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gbk"}, + {"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gb18030"}, + {"עִבְרִית", "\x81\x30\xfb\x30\x81\x30\xf6\x34\x81\x30\xf9\x33\x81\x30\xf6\x30\x81\x30\xfb\x36\x81\x30\xf6\x34\x81\x30\xfa\x31\x81\x30\xfb\x38", "gb18030"}, + {"㧯", "\x82\x31\x89\x38", "gb18030"}, + {"これは漢字です。", "\x82\xb1\x82\xea\x82\xcd\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7\x81B", "SJIS"}, + {"Hello, 世界!", "Hello, \x90\xa2\x8aE!", "SJIS"}, + {"イウエオカ", "\xb2\xb3\xb4\xb5\xb6", "SJIS"}, + {"これは漢字です。", "\xa4\xb3\xa4\xec\xa4\u03f4\xc1\xbb\xfa\xa4\u01e4\xb9\xa1\xa3", "EUC-JP"}, + {"Hello, 世界!", "Hello, \x1b$B@$3&\x1b(B!", "ISO-2022-JP"}, + {"다음과 같은 조건을 따라야 합니다: 저작자표시", "\xb4\xd9\xc0\xbd\xb0\xfa \xb0\xb0\xc0\xba \xc1\xb6\xb0\xc7\xc0\xbb \xb5\xfb\xb6\xf3\xbe\xdf \xc7մϴ\xd9: \xc0\xfa\xc0\xdb\xc0\xdaǥ\xbd\xc3", "EUC-KR"}, +} + +func TestDecode(t *testing.T) { + testCases := append(testCases, []testCase{ + // Replace multi-byte maximum subpart of ill-formed subsequence with + // single replacement character (WhatWG requirement). + {"Rés\ufffdumé", "Rés\xe1\x80umé", "utf8"}, + }...) + for _, tc := range testCases { + e, _ := Lookup(tc.otherEncoding) + if e == nil { + t.Errorf("%s: not found", tc.otherEncoding) + continue + } + s, err := transformString(e.NewDecoder(), tc.other) + if err != nil { + t.Errorf("%s: decode %q: %v", tc.otherEncoding, tc.other, err) + continue + } + if s != tc.utf8 { + t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.utf8) + } + } +} + +func TestEncode(t *testing.T) { + testCases := append(testCases, []testCase{ + // Use Go-style replacement. + {"Rés\xe1\x80umé", "Rés\ufffd\ufffdumé", "utf8"}, + // U+0144 LATIN SMALL LETTER N WITH ACUTE not supported by encoding. + {"Gdańsk", "Gdańsk", "ISO-8859-11"}, + {"\ufffd", "�", "ISO-8859-11"}, + {"a\xe1\x80b", "a��b", "ISO-8859-11"}, + }...) + for _, tc := range testCases { + e, _ := Lookup(tc.otherEncoding) + if e == nil { + t.Errorf("%s: not found", tc.otherEncoding) + continue + } + s, err := transformString(e.NewEncoder(), tc.utf8) + if err != nil { + t.Errorf("%s: encode %q: %s", tc.otherEncoding, tc.utf8, err) + continue + } + if s != tc.other { + t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.other) + } + } +} + +var sniffTestCases = []struct { + filename, declared, want string +}{ + {"HTTP-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, + {"UTF-16LE-BOM.html", "", "utf-16le"}, + {"UTF-16BE-BOM.html", "", "utf-16be"}, + {"meta-content-attribute.html", "text/html", "iso-8859-15"}, + {"meta-charset-attribute.html", "text/html", "iso-8859-15"}, + {"No-encoding-declaration.html", "text/html", "utf-8"}, + {"HTTP-vs-UTF-8-BOM.html", "text/html; charset=iso-8859-15", "utf-8"}, + {"HTTP-vs-meta-content.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, + {"HTTP-vs-meta-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, + {"UTF-8-BOM-vs-meta-content.html", "text/html", "utf-8"}, + {"UTF-8-BOM-vs-meta-charset.html", "text/html", "utf-8"}, +} + +func TestSniff(t *testing.T) { + switch runtime.GOOS { + case "nacl": // platforms that don't permit direct file system access + t.Skipf("not supported on %q", runtime.GOOS) + } + + for _, tc := range sniffTestCases { + content, err := ioutil.ReadFile("testdata/" + tc.filename) + if err != nil { + t.Errorf("%s: error reading file: %v", tc.filename, err) + continue + } + + _, name, _ := DetermineEncoding(content, tc.declared) + if name != tc.want { + t.Errorf("%s: got %q, want %q", tc.filename, name, tc.want) + continue + } + } +} + +func TestReader(t *testing.T) { + switch runtime.GOOS { + case "nacl": // platforms that don't permit direct file system access + t.Skipf("not supported on %q", runtime.GOOS) + } + + for _, tc := range sniffTestCases { + content, err := ioutil.ReadFile("testdata/" + tc.filename) + if err != nil { + t.Errorf("%s: error reading file: %v", tc.filename, err) + continue + } + + r, err := NewReader(bytes.NewReader(content), tc.declared) + if err != nil { + t.Errorf("%s: error creating reader: %v", tc.filename, err) + continue + } + + got, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("%s: error reading from charset.NewReader: %v", tc.filename, err) + continue + } + + e, _ := Lookup(tc.want) + want, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(content), e.NewDecoder())) + if err != nil { + t.Errorf("%s: error decoding with hard-coded charset name: %v", tc.filename, err) + continue + } + + if !bytes.Equal(got, want) { + t.Errorf("%s: got %q, want %q", tc.filename, got, want) + continue + } + } +} + +var metaTestCases = []struct { + meta, want string +}{ + {"", ""}, + {"text/html", ""}, + {"text/html; charset utf-8", ""}, + {"text/html; charset=latin-2", "latin-2"}, + {"text/html; charset; charset = utf-8", "utf-8"}, + {`charset="big5"`, "big5"}, + {"charset='shift_jis'", "shift_jis"}, +} + +func TestFromMeta(t *testing.T) { + for _, tc := range metaTestCases { + got := fromMetaElement(tc.meta) + if got != tc.want { + t.Errorf("%q: got %q, want %q", tc.meta, got, tc.want) + } + } +} + +func TestXML(t *testing.T) { + const s = "r\xe9sum\xe9" + + d := xml.NewDecoder(strings.NewReader(s)) + d.CharsetReader = NewReaderLabel + + var a struct { + Word string + } + err := d.Decode(&a) + if err != nil { + t.Fatalf("Decode: %v", err) + } + + want := "résumé" + if a.Word != want { + t.Errorf("got %q, want %q", a.Word, want) + } +} diff --git a/vendor/golang.org/x/net/html/entity_test.go b/vendor/golang.org/x/net/html/entity_test.go new file mode 100644 index 000000000..b53f866fa --- /dev/null +++ b/vendor/golang.org/x/net/html/entity_test.go @@ -0,0 +1,29 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "testing" + "unicode/utf8" +) + +func TestEntityLength(t *testing.T) { + // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). + // The +1 comes from the leading "&". This property implies that the length of + // unescaped text is <= the length of escaped text. + for k, v := range entity { + if 1+len(k) < utf8.RuneLen(v) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) + } + if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { + t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) + } + } + for k, v := range entity2 { + if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { + t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) + } + } +} diff --git a/vendor/golang.org/x/net/html/escape_test.go b/vendor/golang.org/x/net/html/escape_test.go new file mode 100644 index 000000000..b405d4b4a --- /dev/null +++ b/vendor/golang.org/x/net/html/escape_test.go @@ -0,0 +1,97 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import "testing" + +type unescapeTest struct { + // A short description of the test case. + desc string + // The HTML text. + html string + // The unescaped text. + unescaped string +} + +var unescapeTests = []unescapeTest{ + // Handle no entities. + { + "copy", + "A\ttext\nstring", + "A\ttext\nstring", + }, + // Handle simple named entities. + { + "simple", + "& > <", + "& > <", + }, + // Handle hitting the end of the string. + { + "stringEnd", + "& &", + "& &", + }, + // Handle entities with two codepoints. + { + "multiCodepoint", + "text ⋛︀ blah", + "text \u22db\ufe00 blah", + }, + // Handle decimal numeric entities. + { + "decimalEntity", + "Delta = Δ ", + "Delta = Δ ", + }, + // Handle hexadecimal numeric entities. + { + "hexadecimalEntity", + "Lambda = λ = λ ", + "Lambda = λ = λ ", + }, + // Handle numeric early termination. + { + "numericEnds", + "&# &#x €43 © = ©f = ©", + "&# &#x €43 © = ©f = ©", + }, + // Handle numeric ISO-8859-1 entity replacements. + { + "numericReplacements", + "Footnote‡", + "Footnote‡", + }, +} + +func TestUnescape(t *testing.T) { + for _, tt := range unescapeTests { + unescaped := UnescapeString(tt.html) + if unescaped != tt.unescaped { + t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) + } + } +} + +func TestUnescapeEscape(t *testing.T) { + ss := []string{ + ``, + `abc def`, + `a & b`, + `a&b`, + `a & b`, + `"`, + `"`, + `"<&>"`, + `"<&>"`, + `3&5==1 && 0<1, "0<1", a+acute=á`, + `The special characters are: <, >, &, ' and "`, + } + for _, s := range ss { + if got := UnescapeString(EscapeString(s)); got != s { + t.Errorf("got %q want %q", got, s) + } + } +} diff --git a/vendor/golang.org/x/net/html/example_test.go b/vendor/golang.org/x/net/html/example_test.go new file mode 100644 index 000000000..0b06ed773 --- /dev/null +++ b/vendor/golang.org/x/net/html/example_test.go @@ -0,0 +1,40 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This example demonstrates parsing HTML data and walking the resulting tree. +package html_test + +import ( + "fmt" + "log" + "strings" + + "golang.org/x/net/html" +) + +func ExampleParse() { + s := `

Links:

` + doc, err := html.Parse(strings.NewReader(s)) + if err != nil { + log.Fatal(err) + } + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + for _, a := range n.Attr { + if a.Key == "href" { + fmt.Println(a.Val) + break + } + } + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + // Output: + // foo + // /bar/baz +} diff --git a/vendor/golang.org/x/net/html/node_test.go b/vendor/golang.org/x/net/html/node_test.go new file mode 100644 index 000000000..471102f3a --- /dev/null +++ b/vendor/golang.org/x/net/html/node_test.go @@ -0,0 +1,146 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "fmt" +) + +// checkTreeConsistency checks that a node and its descendants are all +// consistent in their parent/child/sibling relationships. +func checkTreeConsistency(n *Node) error { + return checkTreeConsistency1(n, 0) +} + +func checkTreeConsistency1(n *Node, depth int) error { + if depth == 1e4 { + return fmt.Errorf("html: tree looks like it contains a cycle") + } + if err := checkNodeConsistency(n); err != nil { + return err + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + if err := checkTreeConsistency1(c, depth+1); err != nil { + return err + } + } + return nil +} + +// checkNodeConsistency checks that a node's parent/child/sibling relationships +// are consistent. +func checkNodeConsistency(n *Node) error { + if n == nil { + return nil + } + + nParent := 0 + for p := n.Parent; p != nil; p = p.Parent { + nParent++ + if nParent == 1e4 { + return fmt.Errorf("html: parent list looks like an infinite loop") + } + } + + nForward := 0 + for c := n.FirstChild; c != nil; c = c.NextSibling { + nForward++ + if nForward == 1e6 { + return fmt.Errorf("html: forward list of children looks like an infinite loop") + } + if c.Parent != n { + return fmt.Errorf("html: inconsistent child/parent relationship") + } + } + + nBackward := 0 + for c := n.LastChild; c != nil; c = c.PrevSibling { + nBackward++ + if nBackward == 1e6 { + return fmt.Errorf("html: backward list of children looks like an infinite loop") + } + if c.Parent != n { + return fmt.Errorf("html: inconsistent child/parent relationship") + } + } + + if n.Parent != nil { + if n.Parent == n { + return fmt.Errorf("html: inconsistent parent relationship") + } + if n.Parent == n.FirstChild { + return fmt.Errorf("html: inconsistent parent/first relationship") + } + if n.Parent == n.LastChild { + return fmt.Errorf("html: inconsistent parent/last relationship") + } + if n.Parent == n.PrevSibling { + return fmt.Errorf("html: inconsistent parent/prev relationship") + } + if n.Parent == n.NextSibling { + return fmt.Errorf("html: inconsistent parent/next relationship") + } + + parentHasNAsAChild := false + for c := n.Parent.FirstChild; c != nil; c = c.NextSibling { + if c == n { + parentHasNAsAChild = true + break + } + } + if !parentHasNAsAChild { + return fmt.Errorf("html: inconsistent parent/child relationship") + } + } + + if n.PrevSibling != nil && n.PrevSibling.NextSibling != n { + return fmt.Errorf("html: inconsistent prev/next relationship") + } + if n.NextSibling != nil && n.NextSibling.PrevSibling != n { + return fmt.Errorf("html: inconsistent next/prev relationship") + } + + if (n.FirstChild == nil) != (n.LastChild == nil) { + return fmt.Errorf("html: inconsistent first/last relationship") + } + if n.FirstChild != nil && n.FirstChild == n.LastChild { + // We have a sole child. + if n.FirstChild.PrevSibling != nil || n.FirstChild.NextSibling != nil { + return fmt.Errorf("html: inconsistent sole child's sibling relationship") + } + } + + seen := map[*Node]bool{} + + var last *Node + for c := n.FirstChild; c != nil; c = c.NextSibling { + if seen[c] { + return fmt.Errorf("html: inconsistent repeated child") + } + seen[c] = true + last = c + } + if last != n.LastChild { + return fmt.Errorf("html: inconsistent last relationship") + } + + var first *Node + for c := n.LastChild; c != nil; c = c.PrevSibling { + if !seen[c] { + return fmt.Errorf("html: inconsistent missing child") + } + delete(seen, c) + first = c + } + if first != n.FirstChild { + return fmt.Errorf("html: inconsistent first relationship") + } + + if len(seen) != 0 { + return fmt.Errorf("html: inconsistent forwards/backwards child list") + } + + return nil +} diff --git a/vendor/golang.org/x/net/html/parse_test.go b/vendor/golang.org/x/net/html/parse_test.go new file mode 100644 index 000000000..89d964264 --- /dev/null +++ b/vendor/golang.org/x/net/html/parse_test.go @@ -0,0 +1,400 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "sort" + "strings" + "testing" + + "golang.org/x/net/html/atom" +) + +// readParseTest reads a single test case from r. +func readParseTest(r *bufio.Reader) (text, want, context string, err error) { + line, err := r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + var b []byte + + // Read the HTML. + if string(line) != "#data\n" { + return "", "", "", fmt.Errorf(`got %q want "#data\n"`, line) + } + for { + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + if line[0] == '#' { + break + } + b = append(b, line...) + } + text = strings.TrimSuffix(string(b), "\n") + b = b[:0] + + // Skip the error list. + if string(line) != "#errors\n" { + return "", "", "", fmt.Errorf(`got %q want "#errors\n"`, line) + } + for { + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + if line[0] == '#' { + break + } + } + + if string(line) == "#document-fragment\n" { + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + context = strings.TrimSpace(string(line)) + line, err = r.ReadSlice('\n') + if err != nil { + return "", "", "", err + } + } + + // Read the dump of what the parse tree should be. + if string(line) != "#document\n" { + return "", "", "", fmt.Errorf(`got %q want "#document\n"`, line) + } + inQuote := false + for { + line, err = r.ReadSlice('\n') + if err != nil && err != io.EOF { + return "", "", "", err + } + trimmed := bytes.Trim(line, "| \n") + if len(trimmed) > 0 { + if line[0] == '|' && trimmed[0] == '"' { + inQuote = true + } + if trimmed[len(trimmed)-1] == '"' && !(line[0] == '|' && len(trimmed) == 1) { + inQuote = false + } + } + if len(line) == 0 || len(line) == 1 && line[0] == '\n' && !inQuote { + break + } + b = append(b, line...) + } + return text, string(b), context, nil +} + +func dumpIndent(w io.Writer, level int) { + io.WriteString(w, "| ") + for i := 0; i < level; i++ { + io.WriteString(w, " ") + } +} + +type sortedAttributes []Attribute + +func (a sortedAttributes) Len() int { + return len(a) +} + +func (a sortedAttributes) Less(i, j int) bool { + if a[i].Namespace != a[j].Namespace { + return a[i].Namespace < a[j].Namespace + } + return a[i].Key < a[j].Key +} + +func (a sortedAttributes) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func dumpLevel(w io.Writer, n *Node, level int) error { + dumpIndent(w, level) + level++ + switch n.Type { + case ErrorNode: + return errors.New("unexpected ErrorNode") + case DocumentNode: + return errors.New("unexpected DocumentNode") + case ElementNode: + if n.Namespace != "" { + fmt.Fprintf(w, "<%s %s>", n.Namespace, n.Data) + } else { + fmt.Fprintf(w, "<%s>", n.Data) + } + attr := sortedAttributes(n.Attr) + sort.Sort(attr) + for _, a := range attr { + io.WriteString(w, "\n") + dumpIndent(w, level) + if a.Namespace != "" { + fmt.Fprintf(w, `%s %s="%s"`, a.Namespace, a.Key, a.Val) + } else { + fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val) + } + } + if n.Namespace == "" && n.DataAtom == atom.Template { + io.WriteString(w, "\n") + dumpIndent(w, level) + level++ + io.WriteString(w, "content") + } + case TextNode: + fmt.Fprintf(w, `"%s"`, n.Data) + case CommentNode: + fmt.Fprintf(w, "", n.Data) + case DoctypeNode: + fmt.Fprintf(w, "") + case scopeMarkerNode: + return errors.New("unexpected scopeMarkerNode") + default: + return errors.New("unknown node type") + } + io.WriteString(w, "\n") + for c := n.FirstChild; c != nil; c = c.NextSibling { + if err := dumpLevel(w, c, level); err != nil { + return err + } + } + return nil +} + +func dump(n *Node) (string, error) { + if n == nil || n.FirstChild == nil { + return "", nil + } + var b bytes.Buffer + for c := n.FirstChild; c != nil; c = c.NextSibling { + if err := dumpLevel(&b, c, 0); err != nil { + return "", err + } + } + return b.String(), nil +} + +const testDataDir = "testdata/webkit/" + +func TestParser(t *testing.T) { + testFiles, err := filepath.Glob(testDataDir + "*.dat") + if err != nil { + t.Fatal(err) + } + for _, tf := range testFiles { + f, err := os.Open(tf) + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := bufio.NewReader(f) + + for i := 0; ; i++ { + text, want, context, err := readParseTest(r) + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } + + err = testParseCase(text, want, context) + + if err != nil { + t.Errorf("%s test #%d %q, %s", tf, i, text, err) + } + } + } +} + +// testParseCase tests one test case from the test files. If the test does not +// pass, it returns an error that explains the failure. +// text is the HTML to be parsed, want is a dump of the correct parse tree, +// and context is the name of the context node, if any. +func testParseCase(text, want, context string) (err error) { + defer func() { + if x := recover(); x != nil { + switch e := x.(type) { + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + } + }() + + var doc *Node + if context == "" { + doc, err = Parse(strings.NewReader(text)) + if err != nil { + return err + } + } else { + contextNode := &Node{ + Type: ElementNode, + DataAtom: atom.Lookup([]byte(context)), + Data: context, + } + nodes, err := ParseFragment(strings.NewReader(text), contextNode) + if err != nil { + return err + } + doc = &Node{ + Type: DocumentNode, + } + for _, n := range nodes { + doc.AppendChild(n) + } + } + + if err := checkTreeConsistency(doc); err != nil { + return err + } + + got, err := dump(doc) + if err != nil { + return err + } + // Compare the parsed tree to the #document section. + if got != want { + return fmt.Errorf("got vs want:\n----\n%s----\n%s----", got, want) + } + + if renderTestBlacklist[text] || context != "" { + return nil + } + + // Check that rendering and re-parsing results in an identical tree. + pr, pw := io.Pipe() + go func() { + pw.CloseWithError(Render(pw, doc)) + }() + doc1, err := Parse(pr) + if err != nil { + return err + } + got1, err := dump(doc1) + if err != nil { + return err + } + if got != got1 { + return fmt.Errorf("got vs got1:\n----\n%s----\n%s----", got, got1) + } + + return nil +} + +// Some test input result in parse trees are not 'well-formed' despite +// following the HTML5 recovery algorithms. Rendering and re-parsing such a +// tree will not result in an exact clone of that tree. We blacklist such +// inputs from the render test. +var renderTestBlacklist = map[string]bool{ + // The second will be reparented to the first 's parent. This + // results in an whose parent is an , which is not 'well-formed'. + `
XCY`: true, + // The same thing with a

: + `

`: true, + // More cases of being reparented: + `aba
brx
aoe`: true, + `

`: true, + `
`: true, + // A similar reparenting situation involving : + `123`: true, + // A element is reparented, putting it before a table. + // A <plaintext> element can't have anything after it in HTML. + `<table><plaintext><td>`: true, + `<!doctype html><table><plaintext></plaintext>`: true, + `<!doctype html><table><tbody><plaintext></plaintext>`: true, + `<!doctype html><table><tbody><tr><plaintext></plaintext>`: true, + // A form inside a table inside a form doesn't work either. + `<!doctype html><form><table></form><form></table></form>`: true, + // A script that ends at EOF may escape its own closing tag when rendered. + `<!doctype html><script><!--<script `: true, + `<!doctype html><script><!--<script <`: true, + `<!doctype html><script><!--<script <a`: true, + `<!doctype html><script><!--<script </`: true, + `<!doctype html><script><!--<script </s`: true, + `<!doctype html><script><!--<script </script`: true, + `<!doctype html><script><!--<script </scripta`: true, + `<!doctype html><script><!--<script -`: true, + `<!doctype html><script><!--<script -a`: true, + `<!doctype html><script><!--<script -<`: true, + `<!doctype html><script><!--<script --`: true, + `<!doctype html><script><!--<script --a`: true, + `<!doctype html><script><!--<script --<`: true, + `<script><!--<script `: true, + `<script><!--<script <a`: true, + `<script><!--<script </script`: true, + `<script><!--<script </scripta`: true, + `<script><!--<script -`: true, + `<script><!--<script -a`: true, + `<script><!--<script --`: true, + `<script><!--<script --a`: true, + `<script><!--<script <`: true, + `<script><!--<script </`: true, + `<script><!--<script </s`: true, + // Reconstructing the active formatting elements results in a <plaintext> + // element that contains an <a> element. + `<!doctype html><p><a><plaintext>b`: true, +} + +func TestNodeConsistency(t *testing.T) { + // inconsistentNode is a Node whose DataAtom and Data do not agree. + inconsistentNode := &Node{ + Type: ElementNode, + DataAtom: atom.Frameset, + Data: "table", + } + _, err := ParseFragment(strings.NewReader("<p>hello</p>"), inconsistentNode) + if err == nil { + t.Errorf("got nil error, want non-nil") + } +} + +func TestParseFragmentWithNilContext(t *testing.T) { + // This shouldn't panic. + ParseFragment(strings.NewReader("<p>hello</p>"), nil) +} + +func BenchmarkParser(b *testing.B) { + buf, err := ioutil.ReadFile("testdata/go1.html") + if err != nil { + b.Fatalf("could not read testdata/go1.html: %v", err) + } + b.SetBytes(int64(len(buf))) + runtime.GC() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + Parse(bytes.NewBuffer(buf)) + } +} diff --git a/vendor/golang.org/x/net/html/render_test.go b/vendor/golang.org/x/net/html/render_test.go new file mode 100644 index 000000000..11da54b31 --- /dev/null +++ b/vendor/golang.org/x/net/html/render_test.go @@ -0,0 +1,156 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "bytes" + "testing" +) + +func TestRenderer(t *testing.T) { + nodes := [...]*Node{ + 0: { + Type: ElementNode, + Data: "html", + }, + 1: { + Type: ElementNode, + Data: "head", + }, + 2: { + Type: ElementNode, + Data: "body", + }, + 3: { + Type: TextNode, + Data: "0<1", + }, + 4: { + Type: ElementNode, + Data: "p", + Attr: []Attribute{ + { + Key: "id", + Val: "A", + }, + { + Key: "foo", + Val: `abc"def`, + }, + }, + }, + 5: { + Type: TextNode, + Data: "2", + }, + 6: { + Type: ElementNode, + Data: "b", + Attr: []Attribute{ + { + Key: "empty", + Val: "", + }, + }, + }, + 7: { + Type: TextNode, + Data: "3", + }, + 8: { + Type: ElementNode, + Data: "i", + Attr: []Attribute{ + { + Key: "backslash", + Val: `\`, + }, + }, + }, + 9: { + Type: TextNode, + Data: "&4", + }, + 10: { + Type: TextNode, + Data: "5", + }, + 11: { + Type: ElementNode, + Data: "blockquote", + }, + 12: { + Type: ElementNode, + Data: "br", + }, + 13: { + Type: TextNode, + Data: "6", + }, + } + + // Build a tree out of those nodes, based on a textual representation. + // Only the ".\t"s are significant. The trailing HTML-like text is + // just commentary. The "0:" prefixes are for easy cross-reference with + // the nodes array. + treeAsText := [...]string{ + 0: `<html>`, + 1: `. <head>`, + 2: `. <body>`, + 3: `. . "0&lt;1"`, + 4: `. . <p id="A" foo="abc&#34;def">`, + 5: `. . . "2"`, + 6: `. . . <b empty="">`, + 7: `. . . . "3"`, + 8: `. . . <i backslash="\">`, + 9: `. . . . "&amp;4"`, + 10: `. . "5"`, + 11: `. . <blockquote>`, + 12: `. . <br>`, + 13: `. . "6"`, + } + if len(nodes) != len(treeAsText) { + t.Fatal("len(nodes) != len(treeAsText)") + } + var stack [8]*Node + for i, line := range treeAsText { + level := 0 + for line[0] == '.' { + // Strip a leading ".\t". + line = line[2:] + level++ + } + n := nodes[i] + if level == 0 { + if stack[0] != nil { + t.Fatal("multiple root nodes") + } + stack[0] = n + } else { + stack[level-1].AppendChild(n) + stack[level] = n + for i := level + 1; i < len(stack); i++ { + stack[i] = nil + } + } + // At each stage of tree construction, we check all nodes for consistency. + for j, m := range nodes { + if err := checkNodeConsistency(m); err != nil { + t.Fatalf("i=%d, j=%d: %v", i, j, err) + } + } + } + + want := `<html><head></head><body>0&lt;1<p id="A" foo="abc&#34;def">` + + `2<b empty="">3</b><i backslash="\">&amp;4</i></p>` + + `5<blockquote></blockquote><br/>6</body></html>` + b := new(bytes.Buffer) + if err := Render(b, nodes[0]); err != nil { + t.Fatal(err) + } + if got := b.String(); got != want { + t.Errorf("got vs want:\n%s\n%s\n", got, want) + } +} diff --git a/vendor/golang.org/x/net/html/token_test.go b/vendor/golang.org/x/net/html/token_test.go new file mode 100644 index 000000000..f2473ba63 --- /dev/null +++ b/vendor/golang.org/x/net/html/token_test.go @@ -0,0 +1,748 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "bytes" + "io" + "io/ioutil" + "reflect" + "runtime" + "strings" + "testing" +) + +type tokenTest struct { + // A short description of the test case. + desc string + // The HTML to parse. + html string + // The string representations of the expected tokens, joined by '$'. + golden string +} + +var tokenTests = []tokenTest{ + { + "empty", + "", + "", + }, + // A single text node. The tokenizer should not break text nodes on whitespace, + // nor should it normalize whitespace within a text node. + { + "text", + "foo bar", + "foo bar", + }, + // An entity. + { + "entity", + "one &lt; two", + "one &lt; two", + }, + // A start, self-closing and end tag. The tokenizer does not care if the start + // and end tokens don't match; that is the job of the parser. + { + "tags", + "<a>b<c/>d</e>", + "<a>$b$<c/>$d$</e>", + }, + // Angle brackets that aren't a tag. + { + "not a tag #0", + "<", + "&lt;", + }, + { + "not a tag #1", + "</", + "&lt;/", + }, + { + "not a tag #2", + "</>", + "<!---->", + }, + { + "not a tag #3", + "a</>b", + "a$<!---->$b", + }, + { + "not a tag #4", + "</ >", + "<!-- -->", + }, + { + "not a tag #5", + "</.", + "<!--.-->", + }, + { + "not a tag #6", + "</.>", + "<!--.-->", + }, + { + "not a tag #7", + "a < b", + "a &lt; b", + }, + { + "not a tag #8", + "<.>", + "&lt;.&gt;", + }, + { + "not a tag #9", + "a<<<b>>>c", + "a&lt;&lt;$<b>$&gt;&gt;c", + }, + { + "not a tag #10", + "if x<0 and y < 0 then x*y>0", + "if x&lt;0 and y &lt; 0 then x*y&gt;0", + }, + { + "not a tag #11", + "<<p>", + "&lt;$<p>", + }, + // EOF in a tag name. + { + "tag name eof #0", + "<a", + "", + }, + { + "tag name eof #1", + "<a ", + "", + }, + { + "tag name eof #2", + "a<b", + "a", + }, + { + "tag name eof #3", + "<a><b", + "<a>", + }, + { + "tag name eof #4", + `<a x`, + ``, + }, + // Some malformed tags that are missing a '>'. + { + "malformed tag #0", + `<p</p>`, + `<p< p="">`, + }, + { + "malformed tag #1", + `<p </p>`, + `<p <="" p="">`, + }, + { + "malformed tag #2", + `<p id`, + ``, + }, + { + "malformed tag #3", + `<p id=`, + ``, + }, + { + "malformed tag #4", + `<p id=>`, + `<p id="">`, + }, + { + "malformed tag #5", + `<p id=0`, + ``, + }, + { + "malformed tag #6", + `<p id=0</p>`, + `<p id="0&lt;/p">`, + }, + { + "malformed tag #7", + `<p id="0</p>`, + ``, + }, + { + "malformed tag #8", + `<p id="0"</p>`, + `<p id="0" <="" p="">`, + }, + { + "malformed tag #9", + `<p></p id`, + `<p>`, + }, + // Raw text and RCDATA. + { + "basic raw text", + "<script><a></b></script>", + "<script>$&lt;a&gt;&lt;/b&gt;$</script>", + }, + { + "unfinished script end tag", + "<SCRIPT>a</SCR", + "<script>$a&lt;/SCR", + }, + { + "broken script end tag", + "<SCRIPT>a</SCR ipt>", + "<script>$a&lt;/SCR ipt&gt;", + }, + { + "EOF in script end tag", + "<SCRIPT>a</SCRipt", + "<script>$a&lt;/SCRipt", + }, + { + "scriptx end tag", + "<SCRIPT>a</SCRiptx", + "<script>$a&lt;/SCRiptx", + }, + { + "' ' completes script end tag", + "<SCRIPT>a</SCRipt ", + "<script>$a", + }, + { + "'>' completes script end tag", + "<SCRIPT>a</SCRipt>", + "<script>$a$</script>", + }, + { + "self-closing script end tag", + "<SCRIPT>a</SCRipt/>", + "<script>$a$</script>", + }, + { + "nested script tag", + "<SCRIPT>a</SCRipt<script>", + "<script>$a&lt;/SCRipt&lt;script&gt;", + }, + { + "script end tag after unfinished", + "<SCRIPT>a</SCRipt</script>", + "<script>$a&lt;/SCRipt$</script>", + }, + { + "script/style mismatched tags", + "<script>a</style>", + "<script>$a&lt;/style&gt;", + }, + { + "style element with entity", + "<style>&apos;", + "<style>$&amp;apos;", + }, + { + "textarea with tag", + "<textarea><div></textarea>", + "<textarea>$&lt;div&gt;$</textarea>", + }, + { + "title with tag and entity", + "<title><b>K&amp;R C</b></title>", + "<title>$&lt;b&gt;K&amp;R C&lt;/b&gt;$</title>", + }, + // DOCTYPE tests. + { + "Proper DOCTYPE", + "<!DOCTYPE html>", + "<!DOCTYPE html>", + }, + { + "DOCTYPE with no space", + "<!doctypehtml>", + "<!DOCTYPE html>", + }, + { + "DOCTYPE with two spaces", + "<!doctype html>", + "<!DOCTYPE html>", + }, + { + "looks like DOCTYPE but isn't", + "<!DOCUMENT html>", + "<!--DOCUMENT html-->", + }, + { + "DOCTYPE at EOF", + "<!DOCtype", + "<!DOCTYPE >", + }, + // XML processing instructions. + { + "XML processing instruction", + "<?xml?>", + "<!--?xml?-->", + }, + // Comments. + { + "comment0", + "abc<b><!-- skipme --></b>def", + "abc$<b>$<!-- skipme -->$</b>$def", + }, + { + "comment1", + "a<!-->z", + "a$<!---->$z", + }, + { + "comment2", + "a<!--->z", + "a$<!---->$z", + }, + { + "comment3", + "a<!--x>-->z", + "a$<!--x>-->$z", + }, + { + "comment4", + "a<!--x->-->z", + "a$<!--x->-->$z", + }, + { + "comment5", + "a<!>z", + "a$<!---->$z", + }, + { + "comment6", + "a<!->z", + "a$<!----->$z", + }, + { + "comment7", + "a<!---<>z", + "a$<!---<>z-->", + }, + { + "comment8", + "a<!--z", + "a$<!--z-->", + }, + { + "comment9", + "a<!--z-", + "a$<!--z-->", + }, + { + "comment10", + "a<!--z--", + "a$<!--z-->", + }, + { + "comment11", + "a<!--z---", + "a$<!--z--->", + }, + { + "comment12", + "a<!--z----", + "a$<!--z---->", + }, + { + "comment13", + "a<!--x--!>z", + "a$<!--x-->$z", + }, + // An attribute with a backslash. + { + "backslash", + `<p id="a\"b">`, + `<p id="a\" b"="">`, + }, + // Entities, tag name and attribute key lower-casing, and whitespace + // normalization within a tag. + { + "tricky", + "<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>", + `<p id="a&#34;B" foo="bar">$<em>$te&lt;&amp;;xt$</em>$</p>`, + }, + // A nonexistent entity. Tokenizing and converting back to a string should + // escape the "&" to become "&amp;". + { + "noSuchEntity", + `<a b="c&noSuchEntity;d">&lt;&alsoDoesntExist;&`, + `<a b="c&amp;noSuchEntity;d">$&lt;&amp;alsoDoesntExist;&amp;`, + }, + { + "entity without semicolon", + `&notit;&notin;<a b="q=z&amp=5&notice=hello&not;=world">`, + `¬it;∉$<a b="q=z&amp;amp=5&amp;notice=hello¬=world">`, + }, + { + "entity with digits", + "&frac12;", + "½", + }, + // Attribute tests: + // http://dev.w3.org/html5/pf-summary/Overview.html#attributes + { + "Empty attribute", + `<input disabled FOO>`, + `<input disabled="" foo="">`, + }, + { + "Empty attribute, whitespace", + `<input disabled FOO >`, + `<input disabled="" foo="">`, + }, + { + "Unquoted attribute value", + `<input value=yes FOO=BAR>`, + `<input value="yes" foo="BAR">`, + }, + { + "Unquoted attribute value, spaces", + `<input value = yes FOO = BAR>`, + `<input value="yes" foo="BAR">`, + }, + { + "Unquoted attribute value, trailing space", + `<input value=yes FOO=BAR >`, + `<input value="yes" foo="BAR">`, + }, + { + "Single-quoted attribute value", + `<input value='yes' FOO='BAR'>`, + `<input value="yes" foo="BAR">`, + }, + { + "Single-quoted attribute value, trailing space", + `<input value='yes' FOO='BAR' >`, + `<input value="yes" foo="BAR">`, + }, + { + "Double-quoted attribute value", + `<input value="I'm an attribute" FOO="BAR">`, + `<input value="I&#39;m an attribute" foo="BAR">`, + }, + { + "Attribute name characters", + `<meta http-equiv="content-type">`, + `<meta http-equiv="content-type">`, + }, + { + "Mixed attributes", + `a<P V="0 1" w='2' X=3 y>z`, + `a$<p v="0 1" w="2" x="3" y="">$z`, + }, + { + "Attributes with a solitary single quote", + `<p id=can't><p id=won't>`, + `<p id="can&#39;t">$<p id="won&#39;t">`, + }, +} + +func TestTokenizer(t *testing.T) { +loop: + for _, tt := range tokenTests { + z := NewTokenizer(strings.NewReader(tt.html)) + if tt.golden != "" { + for i, s := range strings.Split(tt.golden, "$") { + if z.Next() == ErrorToken { + t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Err()) + continue loop + } + actual := z.Token().String() + if s != actual { + t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual) + continue loop + } + } + } + z.Next() + if z.Err() != io.EOF { + t.Errorf("%s: want EOF got %q", tt.desc, z.Err()) + } + } +} + +func TestMaxBuffer(t *testing.T) { + // Exceeding the maximum buffer size generates ErrBufferExceeded. + z := NewTokenizer(strings.NewReader("<" + strings.Repeat("t", 10))) + z.SetMaxBuf(5) + tt := z.Next() + if got, want := tt, ErrorToken; got != want { + t.Fatalf("token type: got: %v want: %v", got, want) + } + if got, want := z.Err(), ErrBufferExceeded; got != want { + t.Errorf("error type: got: %v want: %v", got, want) + } + if got, want := string(z.Raw()), "<tttt"; got != want { + t.Fatalf("buffered before overflow: got: %q want: %q", got, want) + } +} + +func TestMaxBufferReconstruction(t *testing.T) { + // Exceeding the maximum buffer size at any point while tokenizing permits + // reconstructing the original input. +tests: + for _, test := range tokenTests { + for maxBuf := 1; ; maxBuf++ { + r := strings.NewReader(test.html) + z := NewTokenizer(r) + z.SetMaxBuf(maxBuf) + var tokenized bytes.Buffer + for { + tt := z.Next() + tokenized.Write(z.Raw()) + if tt == ErrorToken { + if err := z.Err(); err != io.EOF && err != ErrBufferExceeded { + t.Errorf("%s: unexpected error: %v", test.desc, err) + } + break + } + } + // Anything tokenized along with untokenized input or data left in the reader. + assembled, err := ioutil.ReadAll(io.MultiReader(&tokenized, bytes.NewReader(z.Buffered()), r)) + if err != nil { + t.Errorf("%s: ReadAll: %v", test.desc, err) + continue tests + } + if got, want := string(assembled), test.html; got != want { + t.Errorf("%s: reassembled html:\n got: %q\nwant: %q", test.desc, got, want) + continue tests + } + // EOF indicates that we completed tokenization and hence found the max + // maxBuf that generates ErrBufferExceeded, so continue to the next test. + if z.Err() == io.EOF { + break + } + } // buffer sizes + } // tests +} + +func TestPassthrough(t *testing.T) { + // Accumulating the raw output for each parse event should reconstruct the + // original input. + for _, test := range tokenTests { + z := NewTokenizer(strings.NewReader(test.html)) + var parsed bytes.Buffer + for { + tt := z.Next() + parsed.Write(z.Raw()) + if tt == ErrorToken { + break + } + } + if got, want := parsed.String(), test.html; got != want { + t.Errorf("%s: parsed output:\n got: %q\nwant: %q", test.desc, got, want) + } + } +} + +func TestBufAPI(t *testing.T) { + s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9" + z := NewTokenizer(bytes.NewBufferString(s)) + var result bytes.Buffer + depth := 0 +loop: + for { + tt := z.Next() + switch tt { + case ErrorToken: + if z.Err() != io.EOF { + t.Error(z.Err()) + } + break loop + case TextToken: + if depth > 0 { + result.Write(z.Text()) + } + case StartTagToken, EndTagToken: + tn, _ := z.TagName() + if len(tn) == 1 && tn[0] == 'a' { + if tt == StartTagToken { + depth++ + } else { + depth-- + } + } + } + } + u := "14567" + v := string(result.Bytes()) + if u != v { + t.Errorf("TestBufAPI: want %q got %q", u, v) + } +} + +func TestConvertNewlines(t *testing.T) { + testCases := map[string]string{ + "Mac\rDOS\r\nUnix\n": "Mac\nDOS\nUnix\n", + "Unix\nMac\rDOS\r\n": "Unix\nMac\nDOS\n", + "DOS\r\nDOS\r\nDOS\r\n": "DOS\nDOS\nDOS\n", + "": "", + "\n": "\n", + "\n\r": "\n\n", + "\r": "\n", + "\r\n": "\n", + "\r\n\n": "\n\n", + "\r\n\r": "\n\n", + "\r\n\r\n": "\n\n", + "\r\r": "\n\n", + "\r\r\n": "\n\n", + "\r\r\n\n": "\n\n\n", + "\r\r\r\n": "\n\n\n", + "\r \n": "\n \n", + "xyz": "xyz", + } + for in, want := range testCases { + if got := string(convertNewlines([]byte(in))); got != want { + t.Errorf("input %q: got %q, want %q", in, got, want) + } + } +} + +func TestReaderEdgeCases(t *testing.T) { + const s = "<p>An io.Reader can return (0, nil) or (n, io.EOF).</p>" + testCases := []io.Reader{ + &zeroOneByteReader{s: s}, + &eofStringsReader{s: s}, + &stuckReader{}, + } + for i, tc := range testCases { + got := []TokenType{} + z := NewTokenizer(tc) + for { + tt := z.Next() + if tt == ErrorToken { + break + } + got = append(got, tt) + } + if err := z.Err(); err != nil && err != io.EOF { + if err != io.ErrNoProgress { + t.Errorf("i=%d: %v", i, err) + } + continue + } + want := []TokenType{ + StartTagToken, + TextToken, + EndTagToken, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("i=%d: got %v, want %v", i, got, want) + continue + } + } +} + +// zeroOneByteReader is like a strings.Reader that alternates between +// returning 0 bytes and 1 byte at a time. +type zeroOneByteReader struct { + s string + n int +} + +func (r *zeroOneByteReader) Read(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + if len(r.s) == 0 { + return 0, io.EOF + } + r.n++ + if r.n%2 != 0 { + return 0, nil + } + p[0], r.s = r.s[0], r.s[1:] + return 1, nil +} + +// eofStringsReader is like a strings.Reader but can return an (n, err) where +// n > 0 && err != nil. +type eofStringsReader struct { + s string +} + +func (r *eofStringsReader) Read(p []byte) (int, error) { + n := copy(p, r.s) + r.s = r.s[n:] + if r.s != "" { + return n, nil + } + return n, io.EOF +} + +// stuckReader is an io.Reader that always returns no data and no error. +type stuckReader struct{} + +func (*stuckReader) Read(p []byte) (int, error) { + return 0, nil +} + +const ( + rawLevel = iota + lowLevel + highLevel +) + +func benchmarkTokenizer(b *testing.B, level int) { + buf, err := ioutil.ReadFile("testdata/go1.html") + if err != nil { + b.Fatalf("could not read testdata/go1.html: %v", err) + } + b.SetBytes(int64(len(buf))) + runtime.GC() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + z := NewTokenizer(bytes.NewBuffer(buf)) + for { + tt := z.Next() + if tt == ErrorToken { + if err := z.Err(); err != nil && err != io.EOF { + b.Fatalf("tokenizer error: %v", err) + } + break + } + switch level { + case rawLevel: + // Calling z.Raw just returns the raw bytes of the token. It does + // not unescape &lt; to <, or lower-case tag names and attribute keys. + z.Raw() + case lowLevel: + // Caling z.Text, z.TagName and z.TagAttr returns []byte values + // whose contents may change on the next call to z.Next. + switch tt { + case TextToken, CommentToken, DoctypeToken: + z.Text() + case StartTagToken, SelfClosingTagToken: + _, more := z.TagName() + for more { + _, _, more = z.TagAttr() + } + case EndTagToken: + z.TagName() + } + case highLevel: + // Calling z.Token converts []byte values to strings whose validity + // extend beyond the next call to z.Next. + z.Token() + } + } + } +} + +func BenchmarkRawLevelTokenizer(b *testing.B) { benchmarkTokenizer(b, rawLevel) } +func BenchmarkLowLevelTokenizer(b *testing.B) { benchmarkTokenizer(b, lowLevel) } +func BenchmarkHighLevelTokenizer(b *testing.B) { benchmarkTokenizer(b, highLevel) } diff --git a/vendor/golang.org/x/net/http/httpguts/httplex_test.go b/vendor/golang.org/x/net/http/httpguts/httplex_test.go new file mode 100644 index 000000000..a2c57f392 --- /dev/null +++ b/vendor/golang.org/x/net/http/httpguts/httplex_test.go @@ -0,0 +1,119 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package httpguts + +import ( + "testing" +) + +func isChar(c rune) bool { return c <= 127 } + +func isCtl(c rune) bool { return c <= 31 || c == 127 } + +func isSeparator(c rune) bool { + switch c { + case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t': + return true + } + return false +} + +func TestIsToken(t *testing.T) { + for i := 0; i <= 130; i++ { + r := rune(i) + expected := isChar(r) && !isCtl(r) && !isSeparator(r) + if IsTokenRune(r) != expected { + t.Errorf("isToken(0x%x) = %v", r, !expected) + } + } +} + +func TestHeaderValuesContainsToken(t *testing.T) { + tests := []struct { + vals []string + token string + want bool + }{ + { + vals: []string{"foo"}, + token: "foo", + want: true, + }, + { + vals: []string{"bar", "foo"}, + token: "foo", + want: true, + }, + { + vals: []string{"foo"}, + token: "FOO", + want: true, + }, + { + vals: []string{"foo"}, + token: "bar", + want: false, + }, + { + vals: []string{" foo "}, + token: "FOO", + want: true, + }, + { + vals: []string{"foo,bar"}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar,foo,bar"}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar , foo"}, + token: "FOO", + want: true, + }, + { + vals: []string{"foo ,bar "}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar, foo ,bar"}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar , foo"}, + token: "FOO", + want: true, + }, + } + for _, tt := range tests { + got := HeaderValuesContainsToken(tt.vals, tt.token) + if got != tt.want { + t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want) + } + } +} + +func TestPunycodeHostPort(t *testing.T) { + tests := []struct { + in, want string + }{ + {"www.google.com", "www.google.com"}, + {"гофер.рф", "xn--c1ae0ajs.xn--p1ai"}, + {"bücher.de", "xn--bcher-kva.de"}, + {"bücher.de:8080", "xn--bcher-kva.de:8080"}, + {"[1::6]:8080", "[1::6]:8080"}, + } + for _, tt := range tests { + got, err := PunycodeHostPort(tt.in) + if tt.want != got || err != nil { + t.Errorf("PunycodeHostPort(%q) = %q, %v, want %q, nil", tt.in, got, err, tt.want) + } + } +} diff --git a/vendor/golang.org/x/net/http2/.gitignore b/vendor/golang.org/x/net/http2/.gitignore new file mode 100644 index 000000000..190f12234 --- /dev/null +++ b/vendor/golang.org/x/net/http2/.gitignore @@ -0,0 +1,2 @@ +*~ +h2i/h2i diff --git a/vendor/golang.org/x/net/http2/Dockerfile b/vendor/golang.org/x/net/http2/Dockerfile new file mode 100644 index 000000000..53fc52579 --- /dev/null +++ b/vendor/golang.org/x/net/http2/Dockerfile @@ -0,0 +1,51 @@ +# +# This Dockerfile builds a recent curl with HTTP/2 client support, using +# a recent nghttp2 build. +# +# See the Makefile for how to tag it. If Docker and that image is found, the +# Go tests use this curl binary for integration tests. +# + +FROM ubuntu:trusty + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y git-core build-essential wget + +RUN apt-get install -y --no-install-recommends \ + autotools-dev libtool pkg-config zlib1g-dev \ + libcunit1-dev libssl-dev libxml2-dev libevent-dev \ + automake autoconf + +# The list of packages nghttp2 recommends for h2load: +RUN apt-get install -y --no-install-recommends make binutils \ + autoconf automake autotools-dev \ + libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev \ + libev-dev libevent-dev libjansson-dev libjemalloc-dev \ + cython python3.4-dev python-setuptools + +# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached: +ENV NGHTTP2_VER 895da9a +RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git + +WORKDIR /root/nghttp2 +RUN git reset --hard $NGHTTP2_VER +RUN autoreconf -i +RUN automake +RUN autoconf +RUN ./configure +RUN make +RUN make install + +WORKDIR /root +RUN wget http://curl.haxx.se/download/curl-7.45.0.tar.gz +RUN tar -zxvf curl-7.45.0.tar.gz +WORKDIR /root/curl-7.45.0 +RUN ./configure --with-ssl --with-nghttp2=/usr/local +RUN make +RUN make install +RUN ldconfig + +CMD ["-h"] +ENTRYPOINT ["/usr/local/bin/curl"] + diff --git a/vendor/golang.org/x/net/http2/Makefile b/vendor/golang.org/x/net/http2/Makefile new file mode 100644 index 000000000..55fd826f7 --- /dev/null +++ b/vendor/golang.org/x/net/http2/Makefile @@ -0,0 +1,3 @@ +curlimage: + docker build -t gohttp2/curl . + diff --git a/vendor/golang.org/x/net/http2/README b/vendor/golang.org/x/net/http2/README new file mode 100644 index 000000000..360d5aa37 --- /dev/null +++ b/vendor/golang.org/x/net/http2/README @@ -0,0 +1,20 @@ +This is a work-in-progress HTTP/2 implementation for Go. + +It will eventually live in the Go standard library and won't require +any changes to your code to use. It will just be automatic. + +Status: + +* The server support is pretty good. A few things are missing + but are being worked on. +* The client work has just started but shares a lot of code + is coming along much quicker. + +Docs are at https://godoc.org/golang.org/x/net/http2 + +Demo test server at https://http2.golang.org/ + +Help & bug reports welcome! + +Contributing: https://golang.org/doc/contribute.html +Bugs: https://golang.org/issue/new?title=x/net/http2:+ diff --git a/vendor/golang.org/x/net/http2/ciphers_test.go b/vendor/golang.org/x/net/http2/ciphers_test.go new file mode 100644 index 000000000..764bbc8c8 --- /dev/null +++ b/vendor/golang.org/x/net/http2/ciphers_test.go @@ -0,0 +1,309 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import "testing" + +func TestIsBadCipherBad(t *testing.T) { + for _, c := range badCiphers { + if !isBadCipher(c) { + t.Errorf("Wrong result for isBadCipher(%d), want true", c) + } + } +} + +// verify we don't give false positives on ciphers not on blacklist +func TestIsBadCipherGood(t *testing.T) { + goodCiphers := map[uint16]string{ + cipher_TLS_DHE_RSA_WITH_AES_256_CCM: "cipher_TLS_DHE_RSA_WITH_AES_256_CCM", + cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM: "cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM", + cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: "cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", + } + for c, name := range goodCiphers { + if isBadCipher(c) { + t.Errorf("Wrong result for isBadCipher(%d) %s, want false", c, name) + } + } +} + +// copied from https://http2.github.io/http2-spec/#BadCipherSuites, +var badCiphers = []uint16{ + cipher_TLS_NULL_WITH_NULL_NULL, + cipher_TLS_RSA_WITH_NULL_MD5, + cipher_TLS_RSA_WITH_NULL_SHA, + cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5, + cipher_TLS_RSA_WITH_RC4_128_MD5, + cipher_TLS_RSA_WITH_RC4_128_SHA, + cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, + cipher_TLS_RSA_WITH_IDEA_CBC_SHA, + cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, + cipher_TLS_RSA_WITH_DES_CBC_SHA, + cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, + cipher_TLS_DH_DSS_WITH_DES_CBC_SHA, + cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, + cipher_TLS_DH_RSA_WITH_DES_CBC_SHA, + cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, + cipher_TLS_DH_anon_WITH_RC4_128_MD5, + cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, + cipher_TLS_DH_anon_WITH_DES_CBC_SHA, + cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_KRB5_WITH_DES_CBC_SHA, + cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_KRB5_WITH_RC4_128_SHA, + cipher_TLS_KRB5_WITH_IDEA_CBC_SHA, + cipher_TLS_KRB5_WITH_DES_CBC_MD5, + cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5, + cipher_TLS_KRB5_WITH_RC4_128_MD5, + cipher_TLS_KRB5_WITH_IDEA_CBC_MD5, + cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, + cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA, + cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA, + cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5, + cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5, + cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5, + cipher_TLS_PSK_WITH_NULL_SHA, + cipher_TLS_DHE_PSK_WITH_NULL_SHA, + cipher_TLS_RSA_PSK_WITH_NULL_SHA, + cipher_TLS_RSA_WITH_AES_128_CBC_SHA, + cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA, + cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA, + cipher_TLS_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA, + cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA, + cipher_TLS_RSA_WITH_NULL_SHA256, + cipher_TLS_RSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_RSA_WITH_AES_256_CBC_SHA256, + cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256, + cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, + cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA, + cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256, + cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256, + cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, + cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256, + cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256, + cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, + cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA, + cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA, + cipher_TLS_PSK_WITH_RC4_128_SHA, + cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_PSK_WITH_AES_128_CBC_SHA, + cipher_TLS_PSK_WITH_AES_256_CBC_SHA, + cipher_TLS_DHE_PSK_WITH_RC4_128_SHA, + cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + cipher_TLS_RSA_PSK_WITH_RC4_128_SHA, + cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + cipher_TLS_RSA_WITH_SEED_CBC_SHA, + cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA, + cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA, + cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA, + cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA, + cipher_TLS_DH_anon_WITH_SEED_CBC_SHA, + cipher_TLS_RSA_WITH_AES_128_GCM_SHA256, + cipher_TLS_RSA_WITH_AES_256_GCM_SHA384, + cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256, + cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384, + cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256, + cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384, + cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256, + cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384, + cipher_TLS_PSK_WITH_AES_128_GCM_SHA256, + cipher_TLS_PSK_WITH_AES_256_GCM_SHA384, + cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, + cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, + cipher_TLS_PSK_WITH_AES_128_CBC_SHA256, + cipher_TLS_PSK_WITH_AES_256_CBC_SHA384, + cipher_TLS_PSK_WITH_NULL_SHA256, + cipher_TLS_PSK_WITH_NULL_SHA384, + cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + cipher_TLS_DHE_PSK_WITH_NULL_SHA256, + cipher_TLS_DHE_PSK_WITH_NULL_SHA384, + cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + cipher_TLS_RSA_PSK_WITH_NULL_SHA256, + cipher_TLS_RSA_PSK_WITH_NULL_SHA384, + cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, + cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256, + cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256, + cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256, + cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, + cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256, + cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV, + cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA, + cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA, + cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + cipher_TLS_ECDH_RSA_WITH_NULL_SHA, + cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA, + cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_ECDHE_RSA_WITH_NULL_SHA, + cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA, + cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_ECDH_anon_WITH_NULL_SHA, + cipher_TLS_ECDH_anon_WITH_RC4_128_SHA, + cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA, + cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA, + cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA, + cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA, + cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA, + cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + cipher_TLS_ECDHE_PSK_WITH_NULL_SHA, + cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256, + cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384, + cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, + cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, + cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, + cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, + cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, + cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, + cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + cipher_TLS_RSA_WITH_AES_128_CCM, + cipher_TLS_RSA_WITH_AES_256_CCM, + cipher_TLS_RSA_WITH_AES_128_CCM_8, + cipher_TLS_RSA_WITH_AES_256_CCM_8, + cipher_TLS_PSK_WITH_AES_128_CCM, + cipher_TLS_PSK_WITH_AES_256_CCM, + cipher_TLS_PSK_WITH_AES_128_CCM_8, + cipher_TLS_PSK_WITH_AES_256_CCM_8, +} diff --git a/vendor/golang.org/x/net/http2/databuffer_test.go b/vendor/golang.org/x/net/http2/databuffer_test.go new file mode 100644 index 000000000..028e12e52 --- /dev/null +++ b/vendor/golang.org/x/net/http2/databuffer_test.go @@ -0,0 +1,157 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7 + +package http2 + +import ( + "bytes" + "fmt" + "reflect" + "testing" +) + +func fmtDataChunk(chunk []byte) string { + out := "" + var last byte + var count int + for _, c := range chunk { + if c != last { + if count > 0 { + out += fmt.Sprintf(" x %d ", count) + count = 0 + } + out += string([]byte{c}) + last = c + } + count++ + } + if count > 0 { + out += fmt.Sprintf(" x %d", count) + } + return out +} + +func fmtDataChunks(chunks [][]byte) string { + var out string + for _, chunk := range chunks { + out += fmt.Sprintf("{%q}", fmtDataChunk(chunk)) + } + return out +} + +func testDataBuffer(t *testing.T, wantBytes []byte, setup func(t *testing.T) *dataBuffer) { + // Run setup, then read the remaining bytes from the dataBuffer and check + // that they match wantBytes. We use different read sizes to check corner + // cases in Read. + for _, readSize := range []int{1, 2, 1 * 1024, 32 * 1024} { + t.Run(fmt.Sprintf("ReadSize=%d", readSize), func(t *testing.T) { + b := setup(t) + buf := make([]byte, readSize) + var gotRead bytes.Buffer + for { + n, err := b.Read(buf) + gotRead.Write(buf[:n]) + if err == errReadEmpty { + break + } + if err != nil { + t.Fatalf("error after %v bytes: %v", gotRead.Len(), err) + } + } + if got, want := gotRead.Bytes(), wantBytes; !bytes.Equal(got, want) { + t.Errorf("FinalRead=%q, want %q", fmtDataChunk(got), fmtDataChunk(want)) + } + }) + } +} + +func TestDataBufferAllocation(t *testing.T) { + writes := [][]byte{ + bytes.Repeat([]byte("a"), 1*1024-1), + []byte("a"), + bytes.Repeat([]byte("b"), 4*1024-1), + []byte("b"), + bytes.Repeat([]byte("c"), 8*1024-1), + []byte("c"), + bytes.Repeat([]byte("d"), 16*1024-1), + []byte("d"), + bytes.Repeat([]byte("e"), 32*1024), + } + var wantRead bytes.Buffer + for _, p := range writes { + wantRead.Write(p) + } + + testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer { + b := &dataBuffer{} + for _, p := range writes { + if n, err := b.Write(p); n != len(p) || err != nil { + t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p)) + } + } + want := [][]byte{ + bytes.Repeat([]byte("a"), 1*1024), + bytes.Repeat([]byte("b"), 4*1024), + bytes.Repeat([]byte("c"), 8*1024), + bytes.Repeat([]byte("d"), 16*1024), + bytes.Repeat([]byte("e"), 16*1024), + bytes.Repeat([]byte("e"), 16*1024), + } + if !reflect.DeepEqual(b.chunks, want) { + t.Errorf("dataBuffer.chunks\ngot: %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want)) + } + return b + }) +} + +func TestDataBufferAllocationWithExpected(t *testing.T) { + writes := [][]byte{ + bytes.Repeat([]byte("a"), 1*1024), // allocates 16KB + bytes.Repeat([]byte("b"), 14*1024), + bytes.Repeat([]byte("c"), 15*1024), // allocates 16KB more + bytes.Repeat([]byte("d"), 2*1024), + bytes.Repeat([]byte("e"), 1*1024), // overflows 32KB expectation, allocates just 1KB + } + var wantRead bytes.Buffer + for _, p := range writes { + wantRead.Write(p) + } + + testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer { + b := &dataBuffer{expected: 32 * 1024} + for _, p := range writes { + if n, err := b.Write(p); n != len(p) || err != nil { + t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p)) + } + } + want := [][]byte{ + append(bytes.Repeat([]byte("a"), 1*1024), append(bytes.Repeat([]byte("b"), 14*1024), bytes.Repeat([]byte("c"), 1*1024)...)...), + append(bytes.Repeat([]byte("c"), 14*1024), bytes.Repeat([]byte("d"), 2*1024)...), + bytes.Repeat([]byte("e"), 1*1024), + } + if !reflect.DeepEqual(b.chunks, want) { + t.Errorf("dataBuffer.chunks\ngot: %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want)) + } + return b + }) +} + +func TestDataBufferWriteAfterPartialRead(t *testing.T) { + testDataBuffer(t, []byte("cdxyz"), func(t *testing.T) *dataBuffer { + b := &dataBuffer{} + if n, err := b.Write([]byte("abcd")); n != 4 || err != nil { + t.Fatalf("Write(\"abcd\")=%v,%v want 4,nil", n, err) + } + p := make([]byte, 2) + if n, err := b.Read(p); n != 2 || err != nil || !bytes.Equal(p, []byte("ab")) { + t.Fatalf("Read()=%q,%v,%v want \"ab\",2,nil", p, n, err) + } + if n, err := b.Write([]byte("xyz")); n != 3 || err != nil { + t.Fatalf("Write(\"xyz\")=%v,%v want 3,nil", n, err) + } + return b + }) +} diff --git a/vendor/golang.org/x/net/http2/errors_test.go b/vendor/golang.org/x/net/http2/errors_test.go new file mode 100644 index 000000000..da5c58c31 --- /dev/null +++ b/vendor/golang.org/x/net/http2/errors_test.go @@ -0,0 +1,24 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import "testing" + +func TestErrCodeString(t *testing.T) { + tests := []struct { + err ErrCode + want string + }{ + {ErrCodeProtocol, "PROTOCOL_ERROR"}, + {0xd, "HTTP_1_1_REQUIRED"}, + {0xf, "unknown error code 0xf"}, + } + for i, tt := range tests { + got := tt.err.String() + if got != tt.want { + t.Errorf("%d. Error = %q; want %q", i, got, tt.want) + } + } +} diff --git a/vendor/golang.org/x/net/http2/flow_test.go b/vendor/golang.org/x/net/http2/flow_test.go new file mode 100644 index 000000000..859adf5d1 --- /dev/null +++ b/vendor/golang.org/x/net/http2/flow_test.go @@ -0,0 +1,53 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import "testing" + +func TestFlow(t *testing.T) { + var st flow + var conn flow + st.add(3) + conn.add(2) + + if got, want := st.available(), int32(3); got != want { + t.Errorf("available = %d; want %d", got, want) + } + st.setConnFlow(&conn) + if got, want := st.available(), int32(2); got != want { + t.Errorf("after parent setup, available = %d; want %d", got, want) + } + + st.take(2) + if got, want := conn.available(), int32(0); got != want { + t.Errorf("after taking 2, conn = %d; want %d", got, want) + } + if got, want := st.available(), int32(0); got != want { + t.Errorf("after taking 2, stream = %d; want %d", got, want) + } +} + +func TestFlowAdd(t *testing.T) { + var f flow + if !f.add(1) { + t.Fatal("failed to add 1") + } + if !f.add(-1) { + t.Fatal("failed to add -1") + } + if got, want := f.available(), int32(0); got != want { + t.Fatalf("size = %d; want %d", got, want) + } + if !f.add(1<<31 - 1) { + t.Fatal("failed to add 2^31-1") + } + if got, want := f.available(), int32(1<<31-1); got != want { + t.Fatalf("size = %d; want %d", got, want) + } + if f.add(1) { + t.Fatal("adding 1 to max shouldn't be allowed") + } + +} diff --git a/vendor/golang.org/x/net/http2/frame_test.go b/vendor/golang.org/x/net/http2/frame_test.go new file mode 100644 index 000000000..37266bc58 --- /dev/null +++ b/vendor/golang.org/x/net/http2/frame_test.go @@ -0,0 +1,1191 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bytes" + "fmt" + "io" + "reflect" + "strings" + "testing" + "unsafe" + + "golang.org/x/net/http2/hpack" +) + +func testFramer() (*Framer, *bytes.Buffer) { + buf := new(bytes.Buffer) + return NewFramer(buf, buf), buf +} + +func TestFrameSizes(t *testing.T) { + // Catch people rearranging the FrameHeader fields. + if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want { + t.Errorf("FrameHeader size = %d; want %d", got, want) + } +} + +func TestFrameTypeString(t *testing.T) { + tests := []struct { + ft FrameType + want string + }{ + {FrameData, "DATA"}, + {FramePing, "PING"}, + {FrameGoAway, "GOAWAY"}, + {0xf, "UNKNOWN_FRAME_TYPE_15"}, + } + + for i, tt := range tests { + got := tt.ft.String() + if got != tt.want { + t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want) + } + } +} + +func TestWriteRST(t *testing.T) { + fr, buf := testFramer() + var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4 + var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4 + fr.WriteRSTStream(streamID, ErrCode(errCode)) + const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + want := &RSTStreamFrame{ + FrameHeader: FrameHeader{ + valid: true, + Type: 0x3, + Flags: 0x0, + Length: 0x4, + StreamID: 0x1020304, + }, + ErrCode: 0x7060504, + } + if !reflect.DeepEqual(f, want) { + t.Errorf("parsed back %#v; want %#v", f, want) + } +} + +func TestWriteData(t *testing.T) { + fr, buf := testFramer() + var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4 + data := []byte("ABC") + fr.WriteData(streamID, true, data) + const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + df, ok := f.(*DataFrame) + if !ok { + t.Fatalf("got %T; want *DataFrame", f) + } + if !bytes.Equal(df.Data(), data) { + t.Errorf("got %q; want %q", df.Data(), data) + } + if f.Header().Flags&1 == 0 { + t.Errorf("didn't see END_STREAM flag") + } +} + +func TestWriteDataPadded(t *testing.T) { + tests := [...]struct { + streamID uint32 + endStream bool + data []byte + pad []byte + wantHeader FrameHeader + }{ + // Unpadded: + 0: { + streamID: 1, + endStream: true, + data: []byte("foo"), + pad: nil, + wantHeader: FrameHeader{ + Type: FrameData, + Flags: FlagDataEndStream, + Length: 3, + StreamID: 1, + }, + }, + + // Padded bit set, but no padding: + 1: { + streamID: 1, + endStream: true, + data: []byte("foo"), + pad: []byte{}, + wantHeader: FrameHeader{ + Type: FrameData, + Flags: FlagDataEndStream | FlagDataPadded, + Length: 4, + StreamID: 1, + }, + }, + + // Padded bit set, with padding: + 2: { + streamID: 1, + endStream: false, + data: []byte("foo"), + pad: []byte{0, 0, 0}, + wantHeader: FrameHeader{ + Type: FrameData, + Flags: FlagDataPadded, + Length: 7, + StreamID: 1, + }, + }, + } + for i, tt := range tests { + fr, _ := testFramer() + fr.WriteDataPadded(tt.streamID, tt.endStream, tt.data, tt.pad) + f, err := fr.ReadFrame() + if err != nil { + t.Errorf("%d. ReadFrame: %v", i, err) + continue + } + got := f.Header() + tt.wantHeader.valid = true + if got != tt.wantHeader { + t.Errorf("%d. read %+v; want %+v", i, got, tt.wantHeader) + continue + } + df := f.(*DataFrame) + if !bytes.Equal(df.Data(), tt.data) { + t.Errorf("%d. got %q; want %q", i, df.Data(), tt.data) + } + } +} + +func TestWriteHeaders(t *testing.T) { + tests := []struct { + name string + p HeadersFrameParam + wantEnc string + wantFrame *HeadersFrame + }{ + { + "basic", + HeadersFrameParam{ + StreamID: 42, + BlockFragment: []byte("abc"), + Priority: PriorityParam{}, + }, + "\x00\x00\x03\x01\x00\x00\x00\x00*abc", + &HeadersFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: 42, + Type: FrameHeaders, + Length: uint32(len("abc")), + }, + Priority: PriorityParam{}, + headerFragBuf: []byte("abc"), + }, + }, + { + "basic + end flags", + HeadersFrameParam{ + StreamID: 42, + BlockFragment: []byte("abc"), + EndStream: true, + EndHeaders: true, + Priority: PriorityParam{}, + }, + "\x00\x00\x03\x01\x05\x00\x00\x00*abc", + &HeadersFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: 42, + Type: FrameHeaders, + Flags: FlagHeadersEndStream | FlagHeadersEndHeaders, + Length: uint32(len("abc")), + }, + Priority: PriorityParam{}, + headerFragBuf: []byte("abc"), + }, + }, + { + "with padding", + HeadersFrameParam{ + StreamID: 42, + BlockFragment: []byte("abc"), + EndStream: true, + EndHeaders: true, + PadLength: 5, + Priority: PriorityParam{}, + }, + "\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00", + &HeadersFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: 42, + Type: FrameHeaders, + Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded, + Length: uint32(1 + len("abc") + 5), // pad length + contents + padding + }, + Priority: PriorityParam{}, + headerFragBuf: []byte("abc"), + }, + }, + { + "with priority", + HeadersFrameParam{ + StreamID: 42, + BlockFragment: []byte("abc"), + EndStream: true, + EndHeaders: true, + PadLength: 2, + Priority: PriorityParam{ + StreamDep: 15, + Exclusive: true, + Weight: 127, + }, + }, + "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00", + &HeadersFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: 42, + Type: FrameHeaders, + Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority, + Length: uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding + }, + Priority: PriorityParam{ + StreamDep: 15, + Exclusive: true, + Weight: 127, + }, + headerFragBuf: []byte("abc"), + }, + }, + { + "with priority stream dep zero", // golang.org/issue/15444 + HeadersFrameParam{ + StreamID: 42, + BlockFragment: []byte("abc"), + EndStream: true, + EndHeaders: true, + PadLength: 2, + Priority: PriorityParam{ + StreamDep: 0, + Exclusive: true, + Weight: 127, + }, + }, + "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x00\u007fabc\x00\x00", + &HeadersFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: 42, + Type: FrameHeaders, + Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority, + Length: uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding + }, + Priority: PriorityParam{ + StreamDep: 0, + Exclusive: true, + Weight: 127, + }, + headerFragBuf: []byte("abc"), + }, + }, + } + for _, tt := range tests { + fr, buf := testFramer() + if err := fr.WriteHeaders(tt.p); err != nil { + t.Errorf("test %q: %v", tt.name, err) + continue + } + if buf.String() != tt.wantEnc { + t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) + continue + } + if !reflect.DeepEqual(f, tt.wantFrame) { + t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) + } + } +} + +func TestWriteInvalidStreamDep(t *testing.T) { + fr, _ := testFramer() + err := fr.WriteHeaders(HeadersFrameParam{ + StreamID: 42, + Priority: PriorityParam{ + StreamDep: 1 << 31, + }, + }) + if err != errDepStreamID { + t.Errorf("header error = %v; want %q", err, errDepStreamID) + } + + err = fr.WritePriority(2, PriorityParam{StreamDep: 1 << 31}) + if err != errDepStreamID { + t.Errorf("priority error = %v; want %q", err, errDepStreamID) + } +} + +func TestWriteContinuation(t *testing.T) { + const streamID = 42 + tests := []struct { + name string + end bool + frag []byte + + wantFrame *ContinuationFrame + }{ + { + "not end", + false, + []byte("abc"), + &ContinuationFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: streamID, + Type: FrameContinuation, + Length: uint32(len("abc")), + }, + headerFragBuf: []byte("abc"), + }, + }, + { + "end", + true, + []byte("def"), + &ContinuationFrame{ + FrameHeader: FrameHeader{ + valid: true, + StreamID: streamID, + Type: FrameContinuation, + Flags: FlagContinuationEndHeaders, + Length: uint32(len("def")), + }, + headerFragBuf: []byte("def"), + }, + }, + } + for _, tt := range tests { + fr, _ := testFramer() + if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil { + t.Errorf("test %q: %v", tt.name, err) + continue + } + fr.AllowIllegalReads = true + f, err := fr.ReadFrame() + if err != nil { + t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) + continue + } + if !reflect.DeepEqual(f, tt.wantFrame) { + t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) + } + } +} + +func TestWritePriority(t *testing.T) { + const streamID = 42 + tests := []struct { + name string + priority PriorityParam + wantFrame *PriorityFrame + }{ + { + "not exclusive", + PriorityParam{ + StreamDep: 2, + Exclusive: false, + Weight: 127, + }, + &PriorityFrame{ + FrameHeader{ + valid: true, + StreamID: streamID, + Type: FramePriority, + Length: 5, + }, + PriorityParam{ + StreamDep: 2, + Exclusive: false, + Weight: 127, + }, + }, + }, + + { + "exclusive", + PriorityParam{ + StreamDep: 3, + Exclusive: true, + Weight: 77, + }, + &PriorityFrame{ + FrameHeader{ + valid: true, + StreamID: streamID, + Type: FramePriority, + Length: 5, + }, + PriorityParam{ + StreamDep: 3, + Exclusive: true, + Weight: 77, + }, + }, + }, + } + for _, tt := range tests { + fr, _ := testFramer() + if err := fr.WritePriority(streamID, tt.priority); err != nil { + t.Errorf("test %q: %v", tt.name, err) + continue + } + f, err := fr.ReadFrame() + if err != nil { + t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) + continue + } + if !reflect.DeepEqual(f, tt.wantFrame) { + t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) + } + } +} + +func TestWriteSettings(t *testing.T) { + fr, buf := testFramer() + settings := []Setting{{1, 2}, {3, 4}} + fr.WriteSettings(settings...) + const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + sf, ok := f.(*SettingsFrame) + if !ok { + t.Fatalf("Got a %T; want a SettingsFrame", f) + } + var got []Setting + sf.ForeachSetting(func(s Setting) error { + got = append(got, s) + valBack, ok := sf.Value(s.ID) + if !ok || valBack != s.Val { + t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val) + } + return nil + }) + if !reflect.DeepEqual(settings, got) { + t.Errorf("Read settings %+v != written settings %+v", got, settings) + } +} + +func TestWriteSettingsAck(t *testing.T) { + fr, buf := testFramer() + fr.WriteSettingsAck() + const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } +} + +func TestWriteWindowUpdate(t *testing.T) { + fr, buf := testFramer() + const streamID = 1<<24 + 2<<16 + 3<<8 + 4 + const incr = 7<<24 + 6<<16 + 5<<8 + 4 + if err := fr.WriteWindowUpdate(streamID, incr); err != nil { + t.Fatal(err) + } + const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + want := &WindowUpdateFrame{ + FrameHeader: FrameHeader{ + valid: true, + Type: 0x8, + Flags: 0x0, + Length: 0x4, + StreamID: 0x1020304, + }, + Increment: 0x7060504, + } + if !reflect.DeepEqual(f, want) { + t.Errorf("parsed back %#v; want %#v", f, want) + } +} + +func TestWritePing(t *testing.T) { testWritePing(t, false) } +func TestWritePingAck(t *testing.T) { testWritePing(t, true) } + +func testWritePing(t *testing.T, ack bool) { + fr, buf := testFramer() + if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil { + t.Fatal(err) + } + var wantFlags Flags + if ack { + wantFlags = FlagPingAck + } + var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + want := &PingFrame{ + FrameHeader: FrameHeader{ + valid: true, + Type: 0x6, + Flags: wantFlags, + Length: 0x8, + StreamID: 0, + }, + Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + } + if !reflect.DeepEqual(f, want) { + t.Errorf("parsed back %#v; want %#v", f, want) + } +} + +func TestReadFrameHeader(t *testing.T) { + tests := []struct { + in string + want FrameHeader + }{ + {in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}}, + {in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{ + Length: 66051, Type: 4, Flags: 5, StreamID: 101124105, + }}, + // Ignore high bit: + {in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{ + Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}}, + {in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{ + Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}}, + } + for i, tt := range tests { + got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in)) + if err != nil { + t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err) + continue + } + tt.want.valid = true + if got != tt.want { + t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want) + } + } +} + +func TestReadWriteFrameHeader(t *testing.T) { + tests := []struct { + len uint32 + typ FrameType + flags Flags + streamID uint32 + }{ + {len: 0, typ: 255, flags: 1, streamID: 0}, + {len: 0, typ: 255, flags: 1, streamID: 1}, + {len: 0, typ: 255, flags: 1, streamID: 255}, + {len: 0, typ: 255, flags: 1, streamID: 256}, + {len: 0, typ: 255, flags: 1, streamID: 65535}, + {len: 0, typ: 255, flags: 1, streamID: 65536}, + + {len: 0, typ: 1, flags: 255, streamID: 1}, + {len: 255, typ: 1, flags: 255, streamID: 1}, + {len: 256, typ: 1, flags: 255, streamID: 1}, + {len: 65535, typ: 1, flags: 255, streamID: 1}, + {len: 65536, typ: 1, flags: 255, streamID: 1}, + {len: 16777215, typ: 1, flags: 255, streamID: 1}, + } + for _, tt := range tests { + fr, buf := testFramer() + fr.startWrite(tt.typ, tt.flags, tt.streamID) + fr.writeBytes(make([]byte, tt.len)) + fr.endWrite() + fh, err := ReadFrameHeader(buf) + if err != nil { + t.Errorf("ReadFrameHeader(%+v) = %v", tt, err) + continue + } + if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID { + t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh) + } + } + +} + +func TestWriteTooLargeFrame(t *testing.T) { + fr, _ := testFramer() + fr.startWrite(0, 1, 1) + fr.writeBytes(make([]byte, 1<<24)) + err := fr.endWrite() + if err != ErrFrameTooLarge { + t.Errorf("endWrite = %v; want errFrameTooLarge", err) + } +} + +func TestWriteGoAway(t *testing.T) { + const debug = "foo" + fr, buf := testFramer() + if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil { + t.Fatal(err) + } + const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + want := &GoAwayFrame{ + FrameHeader: FrameHeader{ + valid: true, + Type: 0x7, + Flags: 0, + Length: uint32(4 + 4 + len(debug)), + StreamID: 0, + }, + LastStreamID: 0x01020304, + ErrCode: 0x05060708, + debugData: []byte(debug), + } + if !reflect.DeepEqual(f, want) { + t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want) + } + if got := string(f.(*GoAwayFrame).DebugData()); got != debug { + t.Errorf("debug data = %q; want %q", got, debug) + } +} + +func TestWritePushPromise(t *testing.T) { + pp := PushPromiseParam{ + StreamID: 42, + PromiseID: 42, + BlockFragment: []byte("abc"), + } + fr, buf := testFramer() + if err := fr.WritePushPromise(pp); err != nil { + t.Fatal(err) + } + const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc" + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + _, ok := f.(*PushPromiseFrame) + if !ok { + t.Fatalf("got %T; want *PushPromiseFrame", f) + } + want := &PushPromiseFrame{ + FrameHeader: FrameHeader{ + valid: true, + Type: 0x5, + Flags: 0x0, + Length: 0x7, + StreamID: 42, + }, + PromiseID: 42, + headerFragBuf: []byte("abc"), + } + if !reflect.DeepEqual(f, want) { + t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want) + } +} + +// test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled. +func TestReadFrameOrder(t *testing.T) { + head := func(f *Framer, id uint32, end bool) { + f.WriteHeaders(HeadersFrameParam{ + StreamID: id, + BlockFragment: []byte("foo"), // unused, but non-empty + EndHeaders: end, + }) + } + cont := func(f *Framer, id uint32, end bool) { + f.WriteContinuation(id, end, []byte("foo")) + } + + tests := [...]struct { + name string + w func(*Framer) + atLeast int + wantErr string + }{ + 0: { + w: func(f *Framer) { + head(f, 1, true) + }, + }, + 1: { + w: func(f *Framer) { + head(f, 1, true) + head(f, 2, true) + }, + }, + 2: { + wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1", + w: func(f *Framer) { + head(f, 1, false) + head(f, 2, true) + }, + }, + 3: { + wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1", + w: func(f *Framer) { + head(f, 1, false) + }, + }, + 4: { + w: func(f *Framer) { + head(f, 1, false) + cont(f, 1, true) + head(f, 2, true) + }, + }, + 5: { + wantErr: "got CONTINUATION for stream 2; expected stream 1", + w: func(f *Framer) { + head(f, 1, false) + cont(f, 2, true) + head(f, 2, true) + }, + }, + 6: { + wantErr: "unexpected CONTINUATION for stream 1", + w: func(f *Framer) { + cont(f, 1, true) + }, + }, + 7: { + wantErr: "unexpected CONTINUATION for stream 1", + w: func(f *Framer) { + cont(f, 1, false) + }, + }, + 8: { + wantErr: "HEADERS frame with stream ID 0", + w: func(f *Framer) { + head(f, 0, true) + }, + }, + 9: { + wantErr: "CONTINUATION frame with stream ID 0", + w: func(f *Framer) { + cont(f, 0, true) + }, + }, + 10: { + wantErr: "unexpected CONTINUATION for stream 1", + atLeast: 5, + w: func(f *Framer) { + head(f, 1, false) + cont(f, 1, false) + cont(f, 1, false) + cont(f, 1, false) + cont(f, 1, true) + cont(f, 1, false) + }, + }, + } + for i, tt := range tests { + buf := new(bytes.Buffer) + f := NewFramer(buf, buf) + f.AllowIllegalWrites = true + tt.w(f) + f.WriteData(1, true, nil) // to test transition away from last step + + var err error + n := 0 + var log bytes.Buffer + for { + var got Frame + got, err = f.ReadFrame() + fmt.Fprintf(&log, " read %v, %v\n", got, err) + if err != nil { + break + } + n++ + } + if err == io.EOF { + err = nil + } + ok := tt.wantErr == "" + if ok && err != nil { + t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes()) + continue + } + if !ok && err != ConnectionError(ErrCodeProtocol) { + t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes()) + continue + } + if !((f.errDetail == nil && tt.wantErr == "") || (fmt.Sprint(f.errDetail) == tt.wantErr)) { + t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errDetail, tt.wantErr, log.Bytes()) + } + if n < tt.atLeast { + t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes()) + } + } +} + +func TestMetaFrameHeader(t *testing.T) { + write := func(f *Framer, frags ...[]byte) { + for i, frag := range frags { + end := (i == len(frags)-1) + if i == 0 { + f.WriteHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: frag, + EndHeaders: end, + }) + } else { + f.WriteContinuation(1, end, frag) + } + } + } + + want := func(flags Flags, length uint32, pairs ...string) *MetaHeadersFrame { + mh := &MetaHeadersFrame{ + HeadersFrame: &HeadersFrame{ + FrameHeader: FrameHeader{ + Type: FrameHeaders, + Flags: flags, + Length: length, + StreamID: 1, + }, + }, + Fields: []hpack.HeaderField(nil), + } + for len(pairs) > 0 { + mh.Fields = append(mh.Fields, hpack.HeaderField{ + Name: pairs[0], + Value: pairs[1], + }) + pairs = pairs[2:] + } + return mh + } + truncated := func(mh *MetaHeadersFrame) *MetaHeadersFrame { + mh.Truncated = true + return mh + } + + const noFlags Flags = 0 + + oneKBString := strings.Repeat("a", 1<<10) + + tests := [...]struct { + name string + w func(*Framer) + want interface{} // *MetaHeaderFrame or error + wantErrReason string + maxHeaderListSize uint32 + }{ + 0: { + name: "single_headers", + w: func(f *Framer) { + var he hpackEncoder + all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/") + write(f, all) + }, + want: want(FlagHeadersEndHeaders, 2, ":method", "GET", ":path", "/"), + }, + 1: { + name: "with_continuation", + w: func(f *Framer) { + var he hpackEncoder + all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar") + write(f, all[:1], all[1:]) + }, + want: want(noFlags, 1, ":method", "GET", ":path", "/", "foo", "bar"), + }, + 2: { + name: "with_two_continuation", + w: func(f *Framer) { + var he hpackEncoder + all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar") + write(f, all[:2], all[2:4], all[4:]) + }, + want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", "bar"), + }, + 3: { + name: "big_string_okay", + w: func(f *Framer) { + var he hpackEncoder + all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString) + write(f, all[:2], all[2:]) + }, + want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", oneKBString), + }, + 4: { + name: "big_string_error", + w: func(f *Framer) { + var he hpackEncoder + all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString) + write(f, all[:2], all[2:]) + }, + maxHeaderListSize: (1 << 10) / 2, + want: ConnectionError(ErrCodeCompression), + }, + 5: { + name: "max_header_list_truncated", + w: func(f *Framer) { + var he hpackEncoder + var pairs = []string{":method", "GET", ":path", "/"} + for i := 0; i < 100; i++ { + pairs = append(pairs, "foo", "bar") + } + all := he.encodeHeaderRaw(t, pairs...) + write(f, all[:2], all[2:]) + }, + maxHeaderListSize: (1 << 10) / 2, + want: truncated(want(noFlags, 2, + ":method", "GET", + ":path", "/", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", + "foo", "bar", // 11 + )), + }, + 6: { + name: "pseudo_order", + w: func(f *Framer) { + write(f, encodeHeaderRaw(t, + ":method", "GET", + "foo", "bar", + ":path", "/", // bogus + )) + }, + want: streamError(1, ErrCodeProtocol), + wantErrReason: "pseudo header field after regular", + }, + 7: { + name: "pseudo_unknown", + w: func(f *Framer) { + write(f, encodeHeaderRaw(t, + ":unknown", "foo", // bogus + "foo", "bar", + )) + }, + want: streamError(1, ErrCodeProtocol), + wantErrReason: "invalid pseudo-header \":unknown\"", + }, + 8: { + name: "pseudo_mix_request_response", + w: func(f *Framer) { + write(f, encodeHeaderRaw(t, + ":method", "GET", + ":status", "100", + )) + }, + want: streamError(1, ErrCodeProtocol), + wantErrReason: "mix of request and response pseudo headers", + }, + 9: { + name: "pseudo_dup", + w: func(f *Framer) { + write(f, encodeHeaderRaw(t, + ":method", "GET", + ":method", "POST", + )) + }, + want: streamError(1, ErrCodeProtocol), + wantErrReason: "duplicate pseudo-header \":method\"", + }, + 10: { + name: "trailer_okay_no_pseudo", + w: func(f *Framer) { write(f, encodeHeaderRaw(t, "foo", "bar")) }, + want: want(FlagHeadersEndHeaders, 8, "foo", "bar"), + }, + 11: { + name: "invalid_field_name", + w: func(f *Framer) { write(f, encodeHeaderRaw(t, "CapitalBad", "x")) }, + want: streamError(1, ErrCodeProtocol), + wantErrReason: "invalid header field name \"CapitalBad\"", + }, + 12: { + name: "invalid_field_value", + w: func(f *Framer) { write(f, encodeHeaderRaw(t, "key", "bad_null\x00")) }, + want: streamError(1, ErrCodeProtocol), + wantErrReason: "invalid header field value \"bad_null\\x00\"", + }, + } + for i, tt := range tests { + buf := new(bytes.Buffer) + f := NewFramer(buf, buf) + f.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil) + f.MaxHeaderListSize = tt.maxHeaderListSize + tt.w(f) + + name := tt.name + if name == "" { + name = fmt.Sprintf("test index %d", i) + } + + var got interface{} + var err error + got, err = f.ReadFrame() + if err != nil { + got = err + + // Ignore the StreamError.Cause field, if it matches the wantErrReason. + // The test table above predates the Cause field. + if se, ok := err.(StreamError); ok && se.Cause != nil && se.Cause.Error() == tt.wantErrReason { + se.Cause = nil + got = se + } + } + if !reflect.DeepEqual(got, tt.want) { + if mhg, ok := got.(*MetaHeadersFrame); ok { + if mhw, ok := tt.want.(*MetaHeadersFrame); ok { + hg := mhg.HeadersFrame + hw := mhw.HeadersFrame + if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) { + t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", name, *hg, *hw) + } + } + } + str := func(v interface{}) string { + if _, ok := v.(error); ok { + return fmt.Sprintf("error %v", v) + } else { + return fmt.Sprintf("value %#v", v) + } + } + t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want)) + } + if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) { + t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason) + } + } +} + +func TestSetReuseFrames(t *testing.T) { + fr, buf := testFramer() + fr.SetReuseFrames() + + // Check that DataFrames are reused. Note that + // SetReuseFrames only currently implements reuse of DataFrames. + firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t) + + for i := 0; i < 10; i++ { + df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) + if df != firstDf { + t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) + } + } + + for i := 0; i < 10; i++ { + df := readAndVerifyDataFrame("", 0, fr, buf, t) + if df != firstDf { + t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) + } + } + + for i := 0; i < 10; i++ { + df := readAndVerifyDataFrame("HHH", 3, fr, buf, t) + if df != firstDf { + t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) + } + } +} + +func TestSetReuseFramesMoreThanOnce(t *testing.T) { + fr, buf := testFramer() + fr.SetReuseFrames() + + firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t) + fr.SetReuseFrames() + + for i := 0; i < 10; i++ { + df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) + // SetReuseFrames should be idempotent + fr.SetReuseFrames() + if df != firstDf { + t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) + } + } +} + +func TestNoSetReuseFrames(t *testing.T) { + fr, buf := testFramer() + const numNewDataFrames = 10 + dfSoFar := make([]interface{}, numNewDataFrames) + + // Check that DataFrames are not reused if SetReuseFrames wasn't called. + // SetReuseFrames only currently implements reuse of DataFrames. + for i := 0; i < numNewDataFrames; i++ { + df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) + for _, item := range dfSoFar { + if df == item { + t.Errorf("Expected Framer to return new DataFrames since SetNoReuseFrames not set.") + } + } + dfSoFar[i] = df + } +} + +func readAndVerifyDataFrame(data string, length byte, fr *Framer, buf *bytes.Buffer, t *testing.T) *DataFrame { + var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4 + fr.WriteData(streamID, true, []byte(data)) + wantEnc := "\x00\x00" + string(length) + "\x00\x01\x01\x02\x03\x04" + data + if buf.String() != wantEnc { + t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) + } + f, err := fr.ReadFrame() + if err != nil { + t.Fatal(err) + } + df, ok := f.(*DataFrame) + if !ok { + t.Fatalf("got %T; want *DataFrame", f) + } + if !bytes.Equal(df.Data(), []byte(data)) { + t.Errorf("got %q; want %q", df.Data(), []byte(data)) + } + if f.Header().Flags&1 == 0 { + t.Errorf("didn't see END_STREAM flag") + } + return df +} + +func encodeHeaderRaw(t *testing.T, pairs ...string) []byte { + var he hpackEncoder + return he.encodeHeaderRaw(t, pairs...) +} diff --git a/vendor/golang.org/x/net/http2/go18_test.go b/vendor/golang.org/x/net/http2/go18_test.go new file mode 100644 index 000000000..30e3b038b --- /dev/null +++ b/vendor/golang.org/x/net/http2/go18_test.go @@ -0,0 +1,79 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.8 + +package http2 + +import ( + "crypto/tls" + "net/http" + "testing" + "time" +) + +// Tests that http2.Server.IdleTimeout is initialized from +// http.Server.{Idle,Read}Timeout. http.Server.IdleTimeout was +// added in Go 1.8. +func TestConfigureServerIdleTimeout_Go18(t *testing.T) { + const timeout = 5 * time.Second + const notThisOne = 1 * time.Second + + // With a zero http2.Server, verify that it copies IdleTimeout: + { + s1 := &http.Server{ + IdleTimeout: timeout, + ReadTimeout: notThisOne, + } + s2 := &Server{} + if err := ConfigureServer(s1, s2); err != nil { + t.Fatal(err) + } + if s2.IdleTimeout != timeout { + t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout) + } + } + + // And that it falls back to ReadTimeout: + { + s1 := &http.Server{ + ReadTimeout: timeout, + } + s2 := &Server{} + if err := ConfigureServer(s1, s2); err != nil { + t.Fatal(err) + } + if s2.IdleTimeout != timeout { + t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout) + } + } + + // Verify that s1's IdleTimeout doesn't overwrite an existing setting: + { + s1 := &http.Server{ + IdleTimeout: notThisOne, + } + s2 := &Server{ + IdleTimeout: timeout, + } + if err := ConfigureServer(s1, s2); err != nil { + t.Fatal(err) + } + if s2.IdleTimeout != timeout { + t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout) + } + } +} + +func TestCertClone(t *testing.T) { + c := &tls.Config{ + GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { + panic("shouldn't be called") + }, + } + c2 := cloneTLSConfig(c) + if c2.GetClientCertificate == nil { + t.Error("GetClientCertificate is nil") + } +} diff --git a/vendor/golang.org/x/net/http2/go19_test.go b/vendor/golang.org/x/net/http2/go19_test.go new file mode 100644 index 000000000..22b000667 --- /dev/null +++ b/vendor/golang.org/x/net/http2/go19_test.go @@ -0,0 +1,59 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.9 + +package http2 + +import ( + "context" + "net/http" + "reflect" + "testing" + "time" +) + +func TestServerGracefulShutdown(t *testing.T) { + var st *serverTester + handlerDone := make(chan struct{}) + st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + defer close(handlerDone) + go st.ts.Config.Shutdown(context.Background()) + + ga := st.wantGoAway() + if ga.ErrCode != ErrCodeNo { + t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode) + } + if ga.LastStreamID != 1 { + t.Errorf("GOAWAY LastStreamID = %v; want 1", ga.LastStreamID) + } + + w.Header().Set("x-foo", "bar") + }) + defer st.Close() + + st.greet() + st.bodylessReq1() + + select { + case <-handlerDone: + case <-time.After(5 * time.Second): + t.Fatalf("server did not shutdown?") + } + hf := st.wantHeaders() + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"x-foo", "bar"}, + {"content-length", "0"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + + n, err := st.cc.Read([]byte{0}) + if n != 0 || err == nil { + t.Errorf("Read = %v, %v; want 0, non-nil", n, err) + } +} diff --git a/vendor/golang.org/x/net/http2/gotrack_test.go b/vendor/golang.org/x/net/http2/gotrack_test.go new file mode 100644 index 000000000..06db61231 --- /dev/null +++ b/vendor/golang.org/x/net/http2/gotrack_test.go @@ -0,0 +1,33 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "fmt" + "strings" + "testing" +) + +func TestGoroutineLock(t *testing.T) { + oldDebug := DebugGoroutines + DebugGoroutines = true + defer func() { DebugGoroutines = oldDebug }() + + g := newGoroutineLock() + g.check() + + sawPanic := make(chan interface{}) + go func() { + defer func() { sawPanic <- recover() }() + g.check() // should panic + }() + e := <-sawPanic + if e == nil { + t.Fatal("did not see panic from check in other goroutine") + } + if !strings.Contains(fmt.Sprint(e), "wrong goroutine") { + t.Errorf("expected on see panic about running on the wrong goroutine; got %v", e) + } +} diff --git a/vendor/golang.org/x/net/http2/hpack/encode_test.go b/vendor/golang.org/x/net/http2/hpack/encode_test.go new file mode 100644 index 000000000..05f12db9c --- /dev/null +++ b/vendor/golang.org/x/net/http2/hpack/encode_test.go @@ -0,0 +1,386 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package hpack + +import ( + "bytes" + "encoding/hex" + "fmt" + "math/rand" + "reflect" + "strings" + "testing" +) + +func TestEncoderTableSizeUpdate(t *testing.T) { + tests := []struct { + size1, size2 uint32 + wantHex string + }{ + // Should emit 2 table size updates (2048 and 4096) + {2048, 4096, "3fe10f 3fe11f 82"}, + + // Should emit 1 table size update (2048) + {16384, 2048, "3fe10f 82"}, + } + for _, tt := range tests { + var buf bytes.Buffer + e := NewEncoder(&buf) + e.SetMaxDynamicTableSize(tt.size1) + e.SetMaxDynamicTableSize(tt.size2) + if err := e.WriteField(pair(":method", "GET")); err != nil { + t.Fatal(err) + } + want := removeSpace(tt.wantHex) + if got := hex.EncodeToString(buf.Bytes()); got != want { + t.Errorf("e.SetDynamicTableSize %v, %v = %q; want %q", tt.size1, tt.size2, got, want) + } + } +} + +func TestEncoderWriteField(t *testing.T) { + var buf bytes.Buffer + e := NewEncoder(&buf) + var got []HeaderField + d := NewDecoder(4<<10, func(f HeaderField) { + got = append(got, f) + }) + + tests := []struct { + hdrs []HeaderField + }{ + {[]HeaderField{ + pair(":method", "GET"), + pair(":scheme", "http"), + pair(":path", "/"), + pair(":authority", "www.example.com"), + }}, + {[]HeaderField{ + pair(":method", "GET"), + pair(":scheme", "http"), + pair(":path", "/"), + pair(":authority", "www.example.com"), + pair("cache-control", "no-cache"), + }}, + {[]HeaderField{ + pair(":method", "GET"), + pair(":scheme", "https"), + pair(":path", "/index.html"), + pair(":authority", "www.example.com"), + pair("custom-key", "custom-value"), + }}, + } + for i, tt := range tests { + buf.Reset() + got = got[:0] + for _, hf := range tt.hdrs { + if err := e.WriteField(hf); err != nil { + t.Fatal(err) + } + } + _, err := d.Write(buf.Bytes()) + if err != nil { + t.Errorf("%d. Decoder Write = %v", i, err) + } + if !reflect.DeepEqual(got, tt.hdrs) { + t.Errorf("%d. Decoded %+v; want %+v", i, got, tt.hdrs) + } + } +} + +func TestEncoderSearchTable(t *testing.T) { + e := NewEncoder(nil) + + e.dynTab.add(pair("foo", "bar")) + e.dynTab.add(pair("blake", "miz")) + e.dynTab.add(pair(":method", "GET")) + + tests := []struct { + hf HeaderField + wantI uint64 + wantMatch bool + }{ + // Name and Value match + {pair("foo", "bar"), uint64(staticTable.len()) + 3, true}, + {pair("blake", "miz"), uint64(staticTable.len()) + 2, true}, + {pair(":method", "GET"), 2, true}, + + // Only name match because Sensitive == true. This is allowed to match + // any ":method" entry. The current implementation uses the last entry + // added in newStaticTable. + {HeaderField{":method", "GET", true}, 3, false}, + + // Only Name matches + {pair("foo", "..."), uint64(staticTable.len()) + 3, false}, + {pair("blake", "..."), uint64(staticTable.len()) + 2, false}, + // As before, this is allowed to match any ":method" entry. + {pair(":method", "..."), 3, false}, + + // None match + {pair("foo-", "bar"), 0, false}, + } + for _, tt := range tests { + if gotI, gotMatch := e.searchTable(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch { + t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch) + } + } +} + +func TestAppendVarInt(t *testing.T) { + tests := []struct { + n byte + i uint64 + want []byte + }{ + // Fits in a byte: + {1, 0, []byte{0}}, + {2, 2, []byte{2}}, + {3, 6, []byte{6}}, + {4, 14, []byte{14}}, + {5, 30, []byte{30}}, + {6, 62, []byte{62}}, + {7, 126, []byte{126}}, + {8, 254, []byte{254}}, + + // Multiple bytes: + {5, 1337, []byte{31, 154, 10}}, + } + for _, tt := range tests { + got := appendVarInt(nil, tt.n, tt.i) + if !bytes.Equal(got, tt.want) { + t.Errorf("appendVarInt(nil, %v, %v) = %v; want %v", tt.n, tt.i, got, tt.want) + } + } +} + +func TestAppendHpackString(t *testing.T) { + tests := []struct { + s, wantHex string + }{ + // Huffman encoded + {"www.example.com", "8c f1e3 c2e5 f23a 6ba0 ab90 f4ff"}, + + // Not Huffman encoded + {"a", "01 61"}, + + // zero length + {"", "00"}, + } + for _, tt := range tests { + want := removeSpace(tt.wantHex) + buf := appendHpackString(nil, tt.s) + if got := hex.EncodeToString(buf); want != got { + t.Errorf("appendHpackString(nil, %q) = %q; want %q", tt.s, got, want) + } + } +} + +func TestAppendIndexed(t *testing.T) { + tests := []struct { + i uint64 + wantHex string + }{ + // 1 byte + {1, "81"}, + {126, "fe"}, + + // 2 bytes + {127, "ff00"}, + {128, "ff01"}, + } + for _, tt := range tests { + want := removeSpace(tt.wantHex) + buf := appendIndexed(nil, tt.i) + if got := hex.EncodeToString(buf); want != got { + t.Errorf("appendIndex(nil, %v) = %q; want %q", tt.i, got, want) + } + } +} + +func TestAppendNewName(t *testing.T) { + tests := []struct { + f HeaderField + indexing bool + wantHex string + }{ + // Incremental indexing + {HeaderField{"custom-key", "custom-value", false}, true, "40 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, + + // Without indexing + {HeaderField{"custom-key", "custom-value", false}, false, "00 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, + + // Never indexed + {HeaderField{"custom-key", "custom-value", true}, true, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, + {HeaderField{"custom-key", "custom-value", true}, false, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, + } + for _, tt := range tests { + want := removeSpace(tt.wantHex) + buf := appendNewName(nil, tt.f, tt.indexing) + if got := hex.EncodeToString(buf); want != got { + t.Errorf("appendNewName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want) + } + } +} + +func TestAppendIndexedName(t *testing.T) { + tests := []struct { + f HeaderField + i uint64 + indexing bool + wantHex string + }{ + // Incremental indexing + {HeaderField{":status", "302", false}, 8, true, "48 82 6402"}, + + // Without indexing + {HeaderField{":status", "302", false}, 8, false, "08 82 6402"}, + + // Never indexed + {HeaderField{":status", "302", true}, 8, true, "18 82 6402"}, + {HeaderField{":status", "302", true}, 8, false, "18 82 6402"}, + } + for _, tt := range tests { + want := removeSpace(tt.wantHex) + buf := appendIndexedName(nil, tt.f, tt.i, tt.indexing) + if got := hex.EncodeToString(buf); want != got { + t.Errorf("appendIndexedName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want) + } + } +} + +func TestAppendTableSize(t *testing.T) { + tests := []struct { + i uint32 + wantHex string + }{ + // Fits into 1 byte + {30, "3e"}, + + // Extra byte + {31, "3f00"}, + {32, "3f01"}, + } + for _, tt := range tests { + want := removeSpace(tt.wantHex) + buf := appendTableSize(nil, tt.i) + if got := hex.EncodeToString(buf); want != got { + t.Errorf("appendTableSize(nil, %v) = %q; want %q", tt.i, got, want) + } + } +} + +func TestEncoderSetMaxDynamicTableSize(t *testing.T) { + var buf bytes.Buffer + e := NewEncoder(&buf) + tests := []struct { + v uint32 + wantUpdate bool + wantMinSize uint32 + wantMaxSize uint32 + }{ + // Set new table size to 2048 + {2048, true, 2048, 2048}, + + // Set new table size to 16384, but still limited to + // 4096 + {16384, true, 2048, 4096}, + } + for _, tt := range tests { + e.SetMaxDynamicTableSize(tt.v) + if got := e.tableSizeUpdate; tt.wantUpdate != got { + t.Errorf("e.tableSizeUpdate = %v; want %v", got, tt.wantUpdate) + } + if got := e.minSize; tt.wantMinSize != got { + t.Errorf("e.minSize = %v; want %v", got, tt.wantMinSize) + } + if got := e.dynTab.maxSize; tt.wantMaxSize != got { + t.Errorf("e.maxSize = %v; want %v", got, tt.wantMaxSize) + } + } +} + +func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) { + e := NewEncoder(nil) + // 4095 < initialHeaderTableSize means maxSize is truncated to + // 4095. + e.SetMaxDynamicTableSizeLimit(4095) + if got, want := e.dynTab.maxSize, uint32(4095); got != want { + t.Errorf("e.dynTab.maxSize = %v; want %v", got, want) + } + if got, want := e.maxSizeLimit, uint32(4095); got != want { + t.Errorf("e.maxSizeLimit = %v; want %v", got, want) + } + if got, want := e.tableSizeUpdate, true; got != want { + t.Errorf("e.tableSizeUpdate = %v; want %v", got, want) + } + // maxSize will be truncated to maxSizeLimit + e.SetMaxDynamicTableSize(16384) + if got, want := e.dynTab.maxSize, uint32(4095); got != want { + t.Errorf("e.dynTab.maxSize = %v; want %v", got, want) + } + // 8192 > current maxSizeLimit, so maxSize does not change. + e.SetMaxDynamicTableSizeLimit(8192) + if got, want := e.dynTab.maxSize, uint32(4095); got != want { + t.Errorf("e.dynTab.maxSize = %v; want %v", got, want) + } + if got, want := e.maxSizeLimit, uint32(8192); got != want { + t.Errorf("e.maxSizeLimit = %v; want %v", got, want) + } +} + +func removeSpace(s string) string { + return strings.Replace(s, " ", "", -1) +} + +func BenchmarkEncoderSearchTable(b *testing.B) { + e := NewEncoder(nil) + + // A sample of possible header fields. + // This is not based on any actual data from HTTP/2 traces. + var possible []HeaderField + for _, f := range staticTable.ents { + if f.Value == "" { + possible = append(possible, f) + continue + } + // Generate 5 random values, except for cookie and set-cookie, + // which we know can have many values in practice. + num := 5 + if f.Name == "cookie" || f.Name == "set-cookie" { + num = 25 + } + for i := 0; i < num; i++ { + f.Value = fmt.Sprintf("%s-%d", f.Name, i) + possible = append(possible, f) + } + } + for k := 0; k < 10; k++ { + f := HeaderField{ + Name: fmt.Sprintf("x-header-%d", k), + Sensitive: rand.Int()%2 == 0, + } + for i := 0; i < 5; i++ { + f.Value = fmt.Sprintf("%s-%d", f.Name, i) + possible = append(possible, f) + } + } + + // Add a random sample to the dynamic table. This very loosely simulates + // a history of 100 requests with 20 header fields per request. + for r := 0; r < 100*20; r++ { + f := possible[rand.Int31n(int32(len(possible)))] + // Skip if this is in the staticTable verbatim. + if _, has := staticTable.search(f); !has { + e.dynTab.add(f) + } + } + + b.ResetTimer() + for n := 0; n < b.N; n++ { + for _, f := range possible { + e.searchTable(f) + } + } +} diff --git a/vendor/golang.org/x/net/http2/hpack/hpack_test.go b/vendor/golang.org/x/net/http2/hpack/hpack_test.go new file mode 100644 index 000000000..974c35f08 --- /dev/null +++ b/vendor/golang.org/x/net/http2/hpack/hpack_test.go @@ -0,0 +1,741 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package hpack + +import ( + "bytes" + "encoding/hex" + "fmt" + "math/rand" + "reflect" + "strings" + "testing" + "time" +) + +func (d *Decoder) mustAt(idx int) HeaderField { + if hf, ok := d.at(uint64(idx)); !ok { + panic(fmt.Sprintf("bogus index %d", idx)) + } else { + return hf + } +} + +func TestDynamicTableAt(t *testing.T) { + d := NewDecoder(4096, nil) + at := d.mustAt + if got, want := at(2), (pair(":method", "GET")); got != want { + t.Errorf("at(2) = %v; want %v", got, want) + } + d.dynTab.add(pair("foo", "bar")) + d.dynTab.add(pair("blake", "miz")) + if got, want := at(staticTable.len()+1), (pair("blake", "miz")); got != want { + t.Errorf("at(dyn 1) = %v; want %v", got, want) + } + if got, want := at(staticTable.len()+2), (pair("foo", "bar")); got != want { + t.Errorf("at(dyn 2) = %v; want %v", got, want) + } + if got, want := at(3), (pair(":method", "POST")); got != want { + t.Errorf("at(3) = %v; want %v", got, want) + } +} + +func TestDynamicTableSizeEvict(t *testing.T) { + d := NewDecoder(4096, nil) + if want := uint32(0); d.dynTab.size != want { + t.Fatalf("size = %d; want %d", d.dynTab.size, want) + } + add := d.dynTab.add + add(pair("blake", "eats pizza")) + if want := uint32(15 + 32); d.dynTab.size != want { + t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want) + } + add(pair("foo", "bar")) + if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want { + t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want) + } + d.dynTab.setMaxSize(15 + 32 + 1 /* slop */) + if want := uint32(6 + 32); d.dynTab.size != want { + t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want) + } + if got, want := d.mustAt(staticTable.len()+1), (pair("foo", "bar")); got != want { + t.Errorf("at(dyn 1) = %v; want %v", got, want) + } + add(pair("long", strings.Repeat("x", 500))) + if want := uint32(0); d.dynTab.size != want { + t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want) + } +} + +func TestDecoderDecode(t *testing.T) { + tests := []struct { + name string + in []byte + want []HeaderField + wantDynTab []HeaderField // newest entry first + }{ + // C.2.1 Literal Header Field with Indexing + // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1 + {"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"), + []HeaderField{pair("custom-key", "custom-header")}, + []HeaderField{pair("custom-key", "custom-header")}, + }, + + // C.2.2 Literal Header Field without Indexing + // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2 + {"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"), + []HeaderField{pair(":path", "/sample/path")}, + []HeaderField{}}, + + // C.2.3 Literal Header Field never Indexed + // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3 + {"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"), + []HeaderField{{"password", "secret", true}}, + []HeaderField{}}, + + // C.2.4 Indexed Header Field + // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4 + {"C.2.4", []byte("\x82"), + []HeaderField{pair(":method", "GET")}, + []HeaderField{}}, + } + for _, tt := range tests { + d := NewDecoder(4096, nil) + hf, err := d.DecodeFull(tt.in) + if err != nil { + t.Errorf("%s: %v", tt.name, err) + continue + } + if !reflect.DeepEqual(hf, tt.want) { + t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want) + } + gotDynTab := d.dynTab.reverseCopy() + if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) { + t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab) + } + } +} + +func (dt *dynamicTable) reverseCopy() (hf []HeaderField) { + hf = make([]HeaderField, len(dt.table.ents)) + for i := range hf { + hf[i] = dt.table.ents[len(dt.table.ents)-1-i] + } + return +} + +type encAndWant struct { + enc []byte + want []HeaderField + wantDynTab []HeaderField + wantDynSize uint32 +} + +// C.3 Request Examples without Huffman Coding +// http://http2.github.io/http2-spec/compression.html#rfc.section.C.3 +func TestDecodeC3_NoHuffman(t *testing.T) { + testDecodeSeries(t, 4096, []encAndWant{ + {dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"), + []HeaderField{ + pair(":method", "GET"), + pair(":scheme", "http"), + pair(":path", "/"), + pair(":authority", "www.example.com"), + }, + []HeaderField{ + pair(":authority", "www.example.com"), + }, + 57, + }, + {dehex("8286 84be 5808 6e6f 2d63 6163 6865"), + []HeaderField{ + pair(":method", "GET"), + pair(":scheme", "http"), + pair(":path", "/"), + pair(":authority", "www.example.com"), + pair("cache-control", "no-cache"), + }, + []HeaderField{ + pair("cache-control", "no-cache"), + pair(":authority", "www.example.com"), + }, + 110, + }, + {dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"), + []HeaderField{ + pair(":method", "GET"), + pair(":scheme", "https"), + pair(":path", "/index.html"), + pair(":authority", "www.example.com"), + pair("custom-key", "custom-value"), + }, + []HeaderField{ + pair("custom-key", "custom-value"), + pair("cache-control", "no-cache"), + pair(":authority", "www.example.com"), + }, + 164, + }, + }) +} + +// C.4 Request Examples with Huffman Coding +// http://http2.github.io/http2-spec/compression.html#rfc.section.C.4 +func TestDecodeC4_Huffman(t *testing.T) { + testDecodeSeries(t, 4096, []encAndWant{ + {dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"), + []HeaderField{ + pair(":method", "GET"), + pair(":scheme", "http"), + pair(":path", "/"), + pair(":authority", "www.example.com"), + }, + []HeaderField{ + pair(":authority", "www.example.com"), + }, + 57, + }, + {dehex("8286 84be 5886 a8eb 1064 9cbf"), + []HeaderField{ + pair(":method", "GET"), + pair(":scheme", "http"), + pair(":path", "/"), + pair(":authority", "www.example.com"), + pair("cache-control", "no-cache"), + }, + []HeaderField{ + pair("cache-control", "no-cache"), + pair(":authority", "www.example.com"), + }, + 110, + }, + {dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"), + []HeaderField{ + pair(":method", "GET"), + pair(":scheme", "https"), + pair(":path", "/index.html"), + pair(":authority", "www.example.com"), + pair("custom-key", "custom-value"), + }, + []HeaderField{ + pair("custom-key", "custom-value"), + pair("cache-control", "no-cache"), + pair(":authority", "www.example.com"), + }, + 164, + }, + }) +} + +// http://http2.github.io/http2-spec/compression.html#rfc.section.C.5 +// "This section shows several consecutive header lists, corresponding +// to HTTP responses, on the same connection. The HTTP/2 setting +// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 +// octets, causing some evictions to occur." +func TestDecodeC5_ResponsesNoHuff(t *testing.T) { + testDecodeSeries(t, 256, []encAndWant{ + {dehex(` +4803 3330 3258 0770 7269 7661 7465 611d +4d6f 6e2c 2032 3120 4f63 7420 3230 3133 +2032 303a 3133 3a32 3120 474d 546e 1768 +7474 7073 3a2f 2f77 7777 2e65 7861 6d70 +6c65 2e63 6f6d +`), + []HeaderField{ + pair(":status", "302"), + pair("cache-control", "private"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("location", "https://www.example.com"), + }, + []HeaderField{ + pair("location", "https://www.example.com"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("cache-control", "private"), + pair(":status", "302"), + }, + 222, + }, + {dehex("4803 3330 37c1 c0bf"), + []HeaderField{ + pair(":status", "307"), + pair("cache-control", "private"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("location", "https://www.example.com"), + }, + []HeaderField{ + pair(":status", "307"), + pair("location", "https://www.example.com"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("cache-control", "private"), + }, + 222, + }, + {dehex(` +88c1 611d 4d6f 6e2c 2032 3120 4f63 7420 +3230 3133 2032 303a 3133 3a32 3220 474d +54c0 5a04 677a 6970 7738 666f 6f3d 4153 +444a 4b48 514b 425a 584f 5157 454f 5049 +5541 5851 5745 4f49 553b 206d 6178 2d61 +6765 3d33 3630 303b 2076 6572 7369 6f6e +3d31 +`), + []HeaderField{ + pair(":status", "200"), + pair("cache-control", "private"), + pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), + pair("location", "https://www.example.com"), + pair("content-encoding", "gzip"), + pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), + }, + []HeaderField{ + pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), + pair("content-encoding", "gzip"), + pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), + }, + 215, + }, + }) +} + +// http://http2.github.io/http2-spec/compression.html#rfc.section.C.6 +// "This section shows the same examples as the previous section, but +// using Huffman encoding for the literal values. The HTTP/2 setting +// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 +// octets, causing some evictions to occur. The eviction mechanism +// uses the length of the decoded literal values, so the same +// evictions occurs as in the previous section." +func TestDecodeC6_ResponsesHuffman(t *testing.T) { + testDecodeSeries(t, 256, []encAndWant{ + {dehex(` +4882 6402 5885 aec3 771a 4b61 96d0 7abe +9410 54d4 44a8 2005 9504 0b81 66e0 82a6 +2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8 +e9ae 82ae 43d3 +`), + []HeaderField{ + pair(":status", "302"), + pair("cache-control", "private"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("location", "https://www.example.com"), + }, + []HeaderField{ + pair("location", "https://www.example.com"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("cache-control", "private"), + pair(":status", "302"), + }, + 222, + }, + {dehex("4883 640e ffc1 c0bf"), + []HeaderField{ + pair(":status", "307"), + pair("cache-control", "private"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("location", "https://www.example.com"), + }, + []HeaderField{ + pair(":status", "307"), + pair("location", "https://www.example.com"), + pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), + pair("cache-control", "private"), + }, + 222, + }, + {dehex(` +88c1 6196 d07a be94 1054 d444 a820 0595 +040b 8166 e084 a62d 1bff c05a 839b d9ab +77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b +3960 d5af 2708 7f36 72c1 ab27 0fb5 291f +9587 3160 65c0 03ed 4ee5 b106 3d50 07 +`), + []HeaderField{ + pair(":status", "200"), + pair("cache-control", "private"), + pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), + pair("location", "https://www.example.com"), + pair("content-encoding", "gzip"), + pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), + }, + []HeaderField{ + pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), + pair("content-encoding", "gzip"), + pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), + }, + 215, + }, + }) +} + +func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) { + d := NewDecoder(size, nil) + for i, step := range steps { + hf, err := d.DecodeFull(step.enc) + if err != nil { + t.Fatalf("Error at step index %d: %v", i, err) + } + if !reflect.DeepEqual(hf, step.want) { + t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want) + } + gotDynTab := d.dynTab.reverseCopy() + if !reflect.DeepEqual(gotDynTab, step.wantDynTab) { + t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab) + } + if d.dynTab.size != step.wantDynSize { + t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize) + } + } +} + +func TestHuffmanDecodeExcessPadding(t *testing.T) { + tests := [][]byte{ + {0xff}, // Padding Exceeds 7 bits + {0x1f, 0xff}, // {"a", 1 byte excess padding} + {0x1f, 0xff, 0xff}, // {"a", 2 byte excess padding} + {0x1f, 0xff, 0xff, 0xff}, // {"a", 3 byte excess padding} + {0xff, 0x9f, 0xff, 0xff, 0xff}, // {"a", 29 bit excess padding} + {'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol. + } + for i, in := range tests { + var buf bytes.Buffer + if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman { + t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err) + } + } +} + +func TestHuffmanDecodeEOS(t *testing.T) { + in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"} + var buf bytes.Buffer + if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman { + t.Errorf("error = %v; want ErrInvalidHuffman", err) + } +} + +func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) { + in := []byte{0x00, 0x01} // {"0", "0", "0"} + var buf bytes.Buffer + if err := huffmanDecode(&buf, 2, in); err != ErrStringLength { + t.Errorf("error = %v; want ErrStringLength", err) + } +} + +func TestHuffmanDecodeCorruptPadding(t *testing.T) { + in := []byte{0x00} + var buf bytes.Buffer + if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman { + t.Errorf("error = %v; want ErrInvalidHuffman", err) + } +} + +func TestHuffmanDecode(t *testing.T) { + tests := []struct { + inHex, want string + }{ + {"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"}, + {"a8eb 1064 9cbf", "no-cache"}, + {"25a8 49e9 5ba9 7d7f", "custom-key"}, + {"25a8 49e9 5bb8 e8b4 bf", "custom-value"}, + {"6402", "302"}, + {"aec3 771a 4b", "private"}, + {"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"}, + {"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"}, + {"9bd9 ab", "gzip"}, + {"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07", + "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}, + } + for i, tt := range tests { + var buf bytes.Buffer + in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1)) + if err != nil { + t.Errorf("%d. hex input error: %v", i, err) + continue + } + if _, err := HuffmanDecode(&buf, in); err != nil { + t.Errorf("%d. decode error: %v", i, err) + continue + } + if got := buf.String(); tt.want != got { + t.Errorf("%d. decode = %q; want %q", i, got, tt.want) + } + } +} + +func TestAppendHuffmanString(t *testing.T) { + tests := []struct { + in, want string + }{ + {"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"}, + {"no-cache", "a8eb 1064 9cbf"}, + {"custom-key", "25a8 49e9 5ba9 7d7f"}, + {"custom-value", "25a8 49e9 5bb8 e8b4 bf"}, + {"302", "6402"}, + {"private", "aec3 771a 4b"}, + {"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"}, + {"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"}, + {"gzip", "9bd9 ab"}, + {"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", + "94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"}, + } + for i, tt := range tests { + buf := []byte{} + want := strings.Replace(tt.want, " ", "", -1) + buf = AppendHuffmanString(buf, tt.in) + if got := hex.EncodeToString(buf); want != got { + t.Errorf("%d. encode = %q; want %q", i, got, want) + } + } +} + +func TestHuffmanMaxStrLen(t *testing.T) { + const msg = "Some string" + huff := AppendHuffmanString(nil, msg) + + testGood := func(max int) { + var out bytes.Buffer + if err := huffmanDecode(&out, max, huff); err != nil { + t.Errorf("For maxLen=%d, unexpected error: %v", max, err) + } + if out.String() != msg { + t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg) + } + } + testGood(0) + testGood(len(msg)) + testGood(len(msg) + 1) + + var out bytes.Buffer + if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength { + t.Errorf("err = %v; want ErrStringLength", err) + } +} + +func TestHuffmanRoundtripStress(t *testing.T) { + const Len = 50 // of uncompressed string + input := make([]byte, Len) + var output bytes.Buffer + var huff []byte + + n := 5000 + if testing.Short() { + n = 100 + } + seed := time.Now().UnixNano() + t.Logf("Seed = %v", seed) + src := rand.New(rand.NewSource(seed)) + var encSize int64 + for i := 0; i < n; i++ { + for l := range input { + input[l] = byte(src.Intn(256)) + } + huff = AppendHuffmanString(huff[:0], string(input)) + encSize += int64(len(huff)) + output.Reset() + if err := huffmanDecode(&output, 0, huff); err != nil { + t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err) + continue + } + if !bytes.Equal(output.Bytes(), input) { + t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes()) + } + } + t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize) +} + +func TestHuffmanDecodeFuzz(t *testing.T) { + const Len = 50 // of compressed + var buf, zbuf bytes.Buffer + + n := 5000 + if testing.Short() { + n = 100 + } + seed := time.Now().UnixNano() + t.Logf("Seed = %v", seed) + src := rand.New(rand.NewSource(seed)) + numFail := 0 + for i := 0; i < n; i++ { + zbuf.Reset() + if i == 0 { + // Start with at least one invalid one. + zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8") + } else { + for l := 0; l < Len; l++ { + zbuf.WriteByte(byte(src.Intn(256))) + } + } + + buf.Reset() + if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil { + if err == ErrInvalidHuffman { + numFail++ + continue + } + t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err) + continue + } + } + t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n) + if numFail < 1 { + t.Error("expected at least one invalid huffman encoding (test starts with one)") + } +} + +func TestReadVarInt(t *testing.T) { + type res struct { + i uint64 + consumed int + err error + } + tests := []struct { + n byte + p []byte + want res + }{ + // Fits in a byte: + {1, []byte{0}, res{0, 1, nil}}, + {2, []byte{2}, res{2, 1, nil}}, + {3, []byte{6}, res{6, 1, nil}}, + {4, []byte{14}, res{14, 1, nil}}, + {5, []byte{30}, res{30, 1, nil}}, + {6, []byte{62}, res{62, 1, nil}}, + {7, []byte{126}, res{126, 1, nil}}, + {8, []byte{254}, res{254, 1, nil}}, + + // Doesn't fit in a byte: + {1, []byte{1}, res{0, 0, errNeedMore}}, + {2, []byte{3}, res{0, 0, errNeedMore}}, + {3, []byte{7}, res{0, 0, errNeedMore}}, + {4, []byte{15}, res{0, 0, errNeedMore}}, + {5, []byte{31}, res{0, 0, errNeedMore}}, + {6, []byte{63}, res{0, 0, errNeedMore}}, + {7, []byte{127}, res{0, 0, errNeedMore}}, + {8, []byte{255}, res{0, 0, errNeedMore}}, + + // Ignoring top bits: + {5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111 + {5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100 + {5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101 + + // Extra byte: + {5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte + + // Short a byte: + {5, []byte{191, 154}, res{0, 0, errNeedMore}}, + + // integer overflow: + {1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}}, + } + for _, tt := range tests { + i, remain, err := readVarInt(tt.n, tt.p) + consumed := len(tt.p) - len(remain) + got := res{i, consumed, err} + if got != tt.want { + t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want) + } + } +} + +// Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56 +func TestHuffmanFuzzCrash(t *testing.T) { + got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8")) + if got != "" { + t.Errorf("Got %q; want empty string", got) + } + if err != ErrInvalidHuffman { + t.Errorf("Err = %v; want ErrInvalidHuffman", err) + } +} + +func pair(name, value string) HeaderField { + return HeaderField{Name: name, Value: value} +} + +func dehex(s string) []byte { + s = strings.Replace(s, " ", "", -1) + s = strings.Replace(s, "\n", "", -1) + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +func TestEmitEnabled(t *testing.T) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) + enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) + + numCallback := 0 + var dec *Decoder + dec = NewDecoder(8<<20, func(HeaderField) { + numCallback++ + dec.SetEmitEnabled(false) + }) + if !dec.EmitEnabled() { + t.Errorf("initial emit enabled = false; want true") + } + if _, err := dec.Write(buf.Bytes()); err != nil { + t.Error(err) + } + if numCallback != 1 { + t.Errorf("num callbacks = %d; want 1", numCallback) + } + if dec.EmitEnabled() { + t.Errorf("emit enabled = true; want false") + } +} + +func TestSaveBufLimit(t *testing.T) { + const maxStr = 1 << 10 + var got []HeaderField + dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) { + got = append(got, hf) + }) + dec.SetMaxStringLength(maxStr) + var frag []byte + frag = append(frag[:0], encodeTypeByte(false, false)) + frag = appendVarInt(frag, 7, 3) + frag = append(frag, "foo"...) + frag = appendVarInt(frag, 7, 3) + frag = append(frag, "bar"...) + + if _, err := dec.Write(frag); err != nil { + t.Fatal(err) + } + + want := []HeaderField{{Name: "foo", Value: "bar"}} + if !reflect.DeepEqual(got, want) { + t.Errorf("After small writes, got %v; want %v", got, want) + } + + frag = append(frag[:0], encodeTypeByte(false, false)) + frag = appendVarInt(frag, 7, maxStr*3) + frag = append(frag, make([]byte, maxStr*3)...) + + _, err := dec.Write(frag) + if err != ErrStringLength { + t.Fatalf("Write error = %v; want ErrStringLength", err) + } +} + +func TestDynamicSizeUpdate(t *testing.T) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + enc.SetMaxDynamicTableSize(255) + enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) + + d := NewDecoder(4096, nil) + _, err := d.DecodeFull(buf.Bytes()) + if err != nil { + t.Fatalf("unexpected error: got = %v", err) + } + + // must fail since the dynamic table update must be at the beginning + _, err = d.DecodeFull(buf.Bytes()) + if err == nil { + t.Fatalf("dynamic table size update not at the beginning of a header block") + } +} diff --git a/vendor/golang.org/x/net/http2/hpack/tables_test.go b/vendor/golang.org/x/net/http2/hpack/tables_test.go new file mode 100644 index 000000000..d963f3635 --- /dev/null +++ b/vendor/golang.org/x/net/http2/hpack/tables_test.go @@ -0,0 +1,214 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package hpack + +import ( + "bufio" + "regexp" + "strconv" + "strings" + "testing" +) + +func TestHeaderFieldTable(t *testing.T) { + table := &headerFieldTable{} + table.init() + table.addEntry(pair("key1", "value1-1")) + table.addEntry(pair("key2", "value2-1")) + table.addEntry(pair("key1", "value1-2")) + table.addEntry(pair("key3", "value3-1")) + table.addEntry(pair("key4", "value4-1")) + table.addEntry(pair("key2", "value2-2")) + + // Tests will be run twice: once before evicting anything, and + // again after evicting the three oldest entries. + tests := []struct { + f HeaderField + beforeWantStaticI uint64 + beforeWantMatch bool + afterWantStaticI uint64 + afterWantMatch bool + }{ + {HeaderField{"key1", "value1-1", false}, 1, true, 0, false}, + {HeaderField{"key1", "value1-2", false}, 3, true, 0, false}, + {HeaderField{"key1", "value1-3", false}, 3, false, 0, false}, + {HeaderField{"key2", "value2-1", false}, 2, true, 3, false}, + {HeaderField{"key2", "value2-2", false}, 6, true, 3, true}, + {HeaderField{"key2", "value2-3", false}, 6, false, 3, false}, + {HeaderField{"key4", "value4-1", false}, 5, true, 2, true}, + // Name match only, because sensitive. + {HeaderField{"key4", "value4-1", true}, 5, false, 2, false}, + // Key not found. + {HeaderField{"key5", "value5-x", false}, 0, false, 0, false}, + } + + staticToDynamic := func(i uint64) uint64 { + if i == 0 { + return 0 + } + return uint64(table.len()) - i + 1 // dynamic is the reversed table + } + + searchStatic := func(f HeaderField) (uint64, bool) { + old := staticTable + staticTable = table + defer func() { staticTable = old }() + return staticTable.search(f) + } + + searchDynamic := func(f HeaderField) (uint64, bool) { + return table.search(f) + } + + for _, test := range tests { + gotI, gotMatch := searchStatic(test.f) + if wantI, wantMatch := test.beforeWantStaticI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch { + t.Errorf("before evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) + } + gotI, gotMatch = searchDynamic(test.f) + wantDynamicI := staticToDynamic(test.beforeWantStaticI) + if wantI, wantMatch := wantDynamicI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch { + t.Errorf("before evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) + } + } + + table.evictOldest(3) + + for _, test := range tests { + gotI, gotMatch := searchStatic(test.f) + if wantI, wantMatch := test.afterWantStaticI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch { + t.Errorf("after evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) + } + gotI, gotMatch = searchDynamic(test.f) + wantDynamicI := staticToDynamic(test.afterWantStaticI) + if wantI, wantMatch := wantDynamicI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch { + t.Errorf("after evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) + } + } +} + +func TestHeaderFieldTable_LookupMapEviction(t *testing.T) { + table := &headerFieldTable{} + table.init() + table.addEntry(pair("key1", "value1-1")) + table.addEntry(pair("key2", "value2-1")) + table.addEntry(pair("key1", "value1-2")) + table.addEntry(pair("key3", "value3-1")) + table.addEntry(pair("key4", "value4-1")) + table.addEntry(pair("key2", "value2-2")) + + // evict all pairs + table.evictOldest(table.len()) + + if l := table.len(); l > 0 { + t.Errorf("table.len() = %d, want 0", l) + } + + if l := len(table.byName); l > 0 { + t.Errorf("len(table.byName) = %d, want 0", l) + } + + if l := len(table.byNameValue); l > 0 { + t.Errorf("len(table.byNameValue) = %d, want 0", l) + } +} + +func TestStaticTable(t *testing.T) { + fromSpec := ` + +-------+-----------------------------+---------------+ + | 1 | :authority | | + | 2 | :method | GET | + | 3 | :method | POST | + | 4 | :path | / | + | 5 | :path | /index.html | + | 6 | :scheme | http | + | 7 | :scheme | https | + | 8 | :status | 200 | + | 9 | :status | 204 | + | 10 | :status | 206 | + | 11 | :status | 304 | + | 12 | :status | 400 | + | 13 | :status | 404 | + | 14 | :status | 500 | + | 15 | accept-charset | | + | 16 | accept-encoding | gzip, deflate | + | 17 | accept-language | | + | 18 | accept-ranges | | + | 19 | accept | | + | 20 | access-control-allow-origin | | + | 21 | age | | + | 22 | allow | | + | 23 | authorization | | + | 24 | cache-control | | + | 25 | content-disposition | | + | 26 | content-encoding | | + | 27 | content-language | | + | 28 | content-length | | + | 29 | content-location | | + | 30 | content-range | | + | 31 | content-type | | + | 32 | cookie | | + | 33 | date | | + | 34 | etag | | + | 35 | expect | | + | 36 | expires | | + | 37 | from | | + | 38 | host | | + | 39 | if-match | | + | 40 | if-modified-since | | + | 41 | if-none-match | | + | 42 | if-range | | + | 43 | if-unmodified-since | | + | 44 | last-modified | | + | 45 | link | | + | 46 | location | | + | 47 | max-forwards | | + | 48 | proxy-authenticate | | + | 49 | proxy-authorization | | + | 50 | range | | + | 51 | referer | | + | 52 | refresh | | + | 53 | retry-after | | + | 54 | server | | + | 55 | set-cookie | | + | 56 | strict-transport-security | | + | 57 | transfer-encoding | | + | 58 | user-agent | | + | 59 | vary | | + | 60 | via | | + | 61 | www-authenticate | | + +-------+-----------------------------+---------------+ +` + bs := bufio.NewScanner(strings.NewReader(fromSpec)) + re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`) + for bs.Scan() { + l := bs.Text() + if !strings.Contains(l, "|") { + continue + } + m := re.FindStringSubmatch(l) + if m == nil { + continue + } + i, err := strconv.Atoi(m[1]) + if err != nil { + t.Errorf("Bogus integer on line %q", l) + continue + } + if i < 1 || i > staticTable.len() { + t.Errorf("Bogus index %d on line %q", i, l) + continue + } + if got, want := staticTable.ents[i-1].Name, m[2]; got != want { + t.Errorf("header index %d name = %q; want %q", i, got, want) + } + if got, want := staticTable.ents[i-1].Value, m[3]; got != want { + t.Errorf("header index %d value = %q; want %q", i, got, want) + } + } + if err := bs.Err(); err != nil { + t.Error(err) + } +} diff --git a/vendor/golang.org/x/net/http2/http2_test.go b/vendor/golang.org/x/net/http2/http2_test.go new file mode 100644 index 000000000..524877647 --- /dev/null +++ b/vendor/golang.org/x/net/http2/http2_test.go @@ -0,0 +1,199 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bytes" + "errors" + "flag" + "fmt" + "net/http" + "os/exec" + "strconv" + "strings" + "testing" + + "golang.org/x/net/http2/hpack" +) + +var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.") + +func condSkipFailingTest(t *testing.T) { + if !*knownFailing { + t.Skip("Skipping known-failing test without --known_failing") + } +} + +func init() { + inTests = true + DebugGoroutines = true + flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging") +} + +func TestSettingString(t *testing.T) { + tests := []struct { + s Setting + want string + }{ + {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"}, + {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"}, + } + for i, tt := range tests { + got := fmt.Sprint(tt.s) + if got != tt.want { + t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want) + } + } +} + +type twriter struct { + t testing.TB + st *serverTester // optional +} + +func (w twriter) Write(p []byte) (n int, err error) { + if w.st != nil { + ps := string(p) + for _, phrase := range w.st.logFilter { + if strings.Contains(ps, phrase) { + return len(p), nil // no logging + } + } + } + w.t.Logf("%s", p) + return len(p), nil +} + +// like encodeHeader, but don't add implicit pseudo headers. +func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte { + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + for len(headers) > 0 { + k, v := headers[0], headers[1] + headers = headers[2:] + if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil { + t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err) + } + } + return buf.Bytes() +} + +// Verify that curl has http2. +func requireCurl(t *testing.T) { + out, err := dockerLogs(curl(t, "--version")) + if err != nil { + t.Skipf("failed to determine curl features; skipping test") + } + if !strings.Contains(string(out), "HTTP2") { + t.Skip("curl doesn't support HTTP2; skipping test") + } +} + +func curl(t *testing.T, args ...string) (container string) { + out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).Output() + if err != nil { + t.Skipf("Failed to run curl in docker: %v, %s", err, out) + } + return strings.TrimSpace(string(out)) +} + +// Verify that h2load exists. +func requireH2load(t *testing.T) { + out, err := dockerLogs(h2load(t, "--version")) + if err != nil { + t.Skipf("failed to probe h2load; skipping test: %s", out) + } + if !strings.Contains(string(out), "h2load nghttp2/") { + t.Skipf("h2load not present; skipping test. (Output=%q)", out) + } +} + +func h2load(t *testing.T, args ...string) (container string) { + out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output() + if err != nil { + t.Skipf("Failed to run h2load in docker: %v, %s", err, out) + } + return strings.TrimSpace(string(out)) +} + +type puppetCommand struct { + fn func(w http.ResponseWriter, r *http.Request) + done chan<- bool +} + +type handlerPuppet struct { + ch chan puppetCommand +} + +func newHandlerPuppet() *handlerPuppet { + return &handlerPuppet{ + ch: make(chan puppetCommand), + } +} + +func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) { + for cmd := range p.ch { + cmd.fn(w, r) + cmd.done <- true + } +} + +func (p *handlerPuppet) done() { close(p.ch) } +func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) { + done := make(chan bool) + p.ch <- puppetCommand{fn, done} + <-done +} +func dockerLogs(container string) ([]byte, error) { + out, err := exec.Command("docker", "wait", container).CombinedOutput() + if err != nil { + return out, err + } + exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out))) + if err != nil { + return out, errors.New("unexpected exit status from docker wait") + } + out, err = exec.Command("docker", "logs", container).CombinedOutput() + exec.Command("docker", "rm", container).Run() + if err == nil && exitStatus != 0 { + err = fmt.Errorf("exit status %d: %s", exitStatus, out) + } + return out, err +} + +func kill(container string) { + exec.Command("docker", "kill", container).Run() + exec.Command("docker", "rm", container).Run() +} + +func cleanDate(res *http.Response) { + if d := res.Header["Date"]; len(d) == 1 { + d[0] = "XXX" + } +} + +func TestSorterPoolAllocs(t *testing.T) { + ss := []string{"a", "b", "c"} + h := http.Header{ + "a": nil, + "b": nil, + "c": nil, + } + sorter := new(sorter) + + if allocs := testing.AllocsPerRun(100, func() { + sorter.SortStrings(ss) + }); allocs >= 1 { + t.Logf("SortStrings allocs = %v; want <1", allocs) + } + + if allocs := testing.AllocsPerRun(5, func() { + if len(sorter.Keys(h)) != 3 { + t.Fatal("wrong result") + } + }); allocs > 0 { + t.Logf("Keys allocs = %v; want <1", allocs) + } +} diff --git a/vendor/golang.org/x/net/http2/pipe_test.go b/vendor/golang.org/x/net/http2/pipe_test.go new file mode 100644 index 000000000..1bf351ff6 --- /dev/null +++ b/vendor/golang.org/x/net/http2/pipe_test.go @@ -0,0 +1,130 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bytes" + "errors" + "io" + "io/ioutil" + "testing" +) + +func TestPipeClose(t *testing.T) { + var p pipe + p.b = new(bytes.Buffer) + a := errors.New("a") + b := errors.New("b") + p.CloseWithError(a) + p.CloseWithError(b) + _, err := p.Read(make([]byte, 1)) + if err != a { + t.Errorf("err = %v want %v", err, a) + } +} + +func TestPipeDoneChan(t *testing.T) { + var p pipe + done := p.Done() + select { + case <-done: + t.Fatal("done too soon") + default: + } + p.CloseWithError(io.EOF) + select { + case <-done: + default: + t.Fatal("should be done") + } +} + +func TestPipeDoneChan_ErrFirst(t *testing.T) { + var p pipe + p.CloseWithError(io.EOF) + done := p.Done() + select { + case <-done: + default: + t.Fatal("should be done") + } +} + +func TestPipeDoneChan_Break(t *testing.T) { + var p pipe + done := p.Done() + select { + case <-done: + t.Fatal("done too soon") + default: + } + p.BreakWithError(io.EOF) + select { + case <-done: + default: + t.Fatal("should be done") + } +} + +func TestPipeDoneChan_Break_ErrFirst(t *testing.T) { + var p pipe + p.BreakWithError(io.EOF) + done := p.Done() + select { + case <-done: + default: + t.Fatal("should be done") + } +} + +func TestPipeCloseWithError(t *testing.T) { + p := &pipe{b: new(bytes.Buffer)} + const body = "foo" + io.WriteString(p, body) + a := errors.New("test error") + p.CloseWithError(a) + all, err := ioutil.ReadAll(p) + if string(all) != body { + t.Errorf("read bytes = %q; want %q", all, body) + } + if err != a { + t.Logf("read error = %v, %v", err, a) + } + // Read and Write should fail. + if n, err := p.Write([]byte("abc")); err != errClosedPipeWrite || n != 0 { + t.Errorf("Write(abc) after close\ngot %v, %v\nwant 0, %v", n, err, errClosedPipeWrite) + } + if n, err := p.Read(make([]byte, 1)); err == nil || n != 0 { + t.Errorf("Read() after close\ngot %v, nil\nwant 0, %v", n, errClosedPipeWrite) + } +} + +func TestPipeBreakWithError(t *testing.T) { + p := &pipe{b: new(bytes.Buffer)} + io.WriteString(p, "foo") + a := errors.New("test err") + p.BreakWithError(a) + all, err := ioutil.ReadAll(p) + if string(all) != "" { + t.Errorf("read bytes = %q; want empty string", all) + } + if err != a { + t.Logf("read error = %v, %v", err, a) + } + if p.b != nil { + t.Errorf("buffer should be nil after BreakWithError") + } + // Write should succeed silently. + if n, err := p.Write([]byte("abc")); err != nil || n != 3 { + t.Errorf("Write(abc) after break\ngot %v, %v\nwant 0, nil", n, err) + } + if p.b != nil { + t.Errorf("buffer should be nil after Write") + } + // Read should fail. + if n, err := p.Read(make([]byte, 1)); err == nil || n != 0 { + t.Errorf("Read() after close\ngot %v, nil\nwant 0, not nil", n) + } +} diff --git a/vendor/golang.org/x/net/http2/server_push_test.go b/vendor/golang.org/x/net/http2/server_push_test.go new file mode 100644 index 000000000..918fd30dc --- /dev/null +++ b/vendor/golang.org/x/net/http2/server_push_test.go @@ -0,0 +1,521 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.8 + +package http2 + +import ( + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "reflect" + "strconv" + "sync" + "testing" + "time" +) + +func TestServer_Push_Success(t *testing.T) { + const ( + mainBody = "<html>index page</html>" + pushedBody = "<html>pushed page</html>" + userAgent = "testagent" + cookie = "testcookie" + ) + + var stURL string + checkPromisedReq := func(r *http.Request, wantMethod string, wantH http.Header) error { + if got, want := r.Method, wantMethod; got != want { + return fmt.Errorf("promised Req.Method=%q, want %q", got, want) + } + if got, want := r.Header, wantH; !reflect.DeepEqual(got, want) { + return fmt.Errorf("promised Req.Header=%q, want %q", got, want) + } + if got, want := "https://"+r.Host, stURL; got != want { + return fmt.Errorf("promised Req.Host=%q, want %q", got, want) + } + if r.Body == nil { + return fmt.Errorf("nil Body") + } + if buf, err := ioutil.ReadAll(r.Body); err != nil || len(buf) != 0 { + return fmt.Errorf("ReadAll(Body)=%q,%v, want '',nil", buf, err) + } + return nil + } + + errc := make(chan error, 3) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + switch r.URL.RequestURI() { + case "/": + // Push "/pushed?get" as a GET request, using an absolute URL. + opt := &http.PushOptions{ + Header: http.Header{ + "User-Agent": {userAgent}, + }, + } + if err := w.(http.Pusher).Push(stURL+"/pushed?get", opt); err != nil { + errc <- fmt.Errorf("error pushing /pushed?get: %v", err) + return + } + // Push "/pushed?head" as a HEAD request, using a path. + opt = &http.PushOptions{ + Method: "HEAD", + Header: http.Header{ + "User-Agent": {userAgent}, + "Cookie": {cookie}, + }, + } + if err := w.(http.Pusher).Push("/pushed?head", opt); err != nil { + errc <- fmt.Errorf("error pushing /pushed?head: %v", err) + return + } + w.Header().Set("Content-Type", "text/html") + w.Header().Set("Content-Length", strconv.Itoa(len(mainBody))) + w.WriteHeader(200) + io.WriteString(w, mainBody) + errc <- nil + + case "/pushed?get": + wantH := http.Header{} + wantH.Set("User-Agent", userAgent) + if err := checkPromisedReq(r, "GET", wantH); err != nil { + errc <- fmt.Errorf("/pushed?get: %v", err) + return + } + w.Header().Set("Content-Type", "text/html") + w.Header().Set("Content-Length", strconv.Itoa(len(pushedBody))) + w.WriteHeader(200) + io.WriteString(w, pushedBody) + errc <- nil + + case "/pushed?head": + wantH := http.Header{} + wantH.Set("User-Agent", userAgent) + wantH.Set("Cookie", cookie) + if err := checkPromisedReq(r, "HEAD", wantH); err != nil { + errc <- fmt.Errorf("/pushed?head: %v", err) + return + } + w.WriteHeader(204) + errc <- nil + + default: + errc <- fmt.Errorf("unknown RequestURL %q", r.URL.RequestURI()) + } + }) + stURL = st.ts.URL + + // Send one request, which should push two responses. + st.greet() + getSlash(st) + for k := 0; k < 3; k++ { + select { + case <-time.After(2 * time.Second): + t.Errorf("timeout waiting for handler %d to finish", k) + case err := <-errc: + if err != nil { + t.Fatal(err) + } + } + } + + checkPushPromise := func(f Frame, promiseID uint32, wantH [][2]string) error { + pp, ok := f.(*PushPromiseFrame) + if !ok { + return fmt.Errorf("got a %T; want *PushPromiseFrame", f) + } + if !pp.HeadersEnded() { + return fmt.Errorf("want END_HEADERS flag in PushPromiseFrame") + } + if got, want := pp.PromiseID, promiseID; got != want { + return fmt.Errorf("got PromiseID %v; want %v", got, want) + } + gotH := st.decodeHeader(pp.HeaderBlockFragment()) + if !reflect.DeepEqual(gotH, wantH) { + return fmt.Errorf("got promised headers %v; want %v", gotH, wantH) + } + return nil + } + checkHeaders := func(f Frame, wantH [][2]string) error { + hf, ok := f.(*HeadersFrame) + if !ok { + return fmt.Errorf("got a %T; want *HeadersFrame", f) + } + gotH := st.decodeHeader(hf.HeaderBlockFragment()) + if !reflect.DeepEqual(gotH, wantH) { + return fmt.Errorf("got response headers %v; want %v", gotH, wantH) + } + return nil + } + checkData := func(f Frame, wantData string) error { + df, ok := f.(*DataFrame) + if !ok { + return fmt.Errorf("got a %T; want *DataFrame", f) + } + if gotData := string(df.Data()); gotData != wantData { + return fmt.Errorf("got response data %q; want %q", gotData, wantData) + } + return nil + } + + // Stream 1 has 2 PUSH_PROMISE + HEADERS + DATA + // Stream 2 has HEADERS + DATA + // Stream 4 has HEADERS + expected := map[uint32][]func(Frame) error{ + 1: { + func(f Frame) error { + return checkPushPromise(f, 2, [][2]string{ + {":method", "GET"}, + {":scheme", "https"}, + {":authority", st.ts.Listener.Addr().String()}, + {":path", "/pushed?get"}, + {"user-agent", userAgent}, + }) + }, + func(f Frame) error { + return checkPushPromise(f, 4, [][2]string{ + {":method", "HEAD"}, + {":scheme", "https"}, + {":authority", st.ts.Listener.Addr().String()}, + {":path", "/pushed?head"}, + {"cookie", cookie}, + {"user-agent", userAgent}, + }) + }, + func(f Frame) error { + return checkHeaders(f, [][2]string{ + {":status", "200"}, + {"content-type", "text/html"}, + {"content-length", strconv.Itoa(len(mainBody))}, + }) + }, + func(f Frame) error { + return checkData(f, mainBody) + }, + }, + 2: { + func(f Frame) error { + return checkHeaders(f, [][2]string{ + {":status", "200"}, + {"content-type", "text/html"}, + {"content-length", strconv.Itoa(len(pushedBody))}, + }) + }, + func(f Frame) error { + return checkData(f, pushedBody) + }, + }, + 4: { + func(f Frame) error { + return checkHeaders(f, [][2]string{ + {":status", "204"}, + }) + }, + }, + } + + consumed := map[uint32]int{} + for k := 0; len(expected) > 0; k++ { + f, err := st.readFrame() + if err != nil { + for id, left := range expected { + t.Errorf("stream %d: missing %d frames", id, len(left)) + } + t.Fatalf("readFrame %d: %v", k, err) + } + id := f.Header().StreamID + label := fmt.Sprintf("stream %d, frame %d", id, consumed[id]) + if len(expected[id]) == 0 { + t.Fatalf("%s: unexpected frame %#+v", label, f) + } + check := expected[id][0] + expected[id] = expected[id][1:] + if len(expected[id]) == 0 { + delete(expected, id) + } + if err := check(f); err != nil { + t.Fatalf("%s: %v", label, err) + } + consumed[id]++ + } +} + +func TestServer_Push_SuccessNoRace(t *testing.T) { + // Regression test for issue #18326. Ensure the request handler can mutate + // pushed request headers without racing with the PUSH_PROMISE write. + errc := make(chan error, 2) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + switch r.URL.RequestURI() { + case "/": + opt := &http.PushOptions{ + Header: http.Header{"User-Agent": {"testagent"}}, + } + if err := w.(http.Pusher).Push("/pushed", opt); err != nil { + errc <- fmt.Errorf("error pushing: %v", err) + return + } + w.WriteHeader(200) + errc <- nil + + case "/pushed": + // Update request header, ensure there is no race. + r.Header.Set("User-Agent", "newagent") + r.Header.Set("Cookie", "cookie") + w.WriteHeader(200) + errc <- nil + + default: + errc <- fmt.Errorf("unknown RequestURL %q", r.URL.RequestURI()) + } + }) + + // Send one request, which should push one response. + st.greet() + getSlash(st) + for k := 0; k < 2; k++ { + select { + case <-time.After(2 * time.Second): + t.Errorf("timeout waiting for handler %d to finish", k) + case err := <-errc: + if err != nil { + t.Fatal(err) + } + } + } +} + +func TestServer_Push_RejectRecursivePush(t *testing.T) { + // Expect two requests, but might get three if there's a bug and the second push succeeds. + errc := make(chan error, 3) + handler := func(w http.ResponseWriter, r *http.Request) error { + baseURL := "https://" + r.Host + switch r.URL.Path { + case "/": + if err := w.(http.Pusher).Push(baseURL+"/push1", nil); err != nil { + return fmt.Errorf("first Push()=%v, want nil", err) + } + return nil + + case "/push1": + if got, want := w.(http.Pusher).Push(baseURL+"/push2", nil), ErrRecursivePush; got != want { + return fmt.Errorf("Push()=%v, want %v", got, want) + } + return nil + + default: + return fmt.Errorf("unexpected path: %q", r.URL.Path) + } + } + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + errc <- handler(w, r) + }) + defer st.Close() + st.greet() + getSlash(st) + if err := <-errc; err != nil { + t.Errorf("First request failed: %v", err) + } + if err := <-errc; err != nil { + t.Errorf("Second request failed: %v", err) + } +} + +func testServer_Push_RejectSingleRequest(t *testing.T, doPush func(http.Pusher, *http.Request) error, settings ...Setting) { + // Expect one request, but might get two if there's a bug and the push succeeds. + errc := make(chan error, 2) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + errc <- doPush(w.(http.Pusher), r) + }) + defer st.Close() + st.greet() + if err := st.fr.WriteSettings(settings...); err != nil { + st.t.Fatalf("WriteSettings: %v", err) + } + st.wantSettingsAck() + getSlash(st) + if err := <-errc; err != nil { + t.Error(err) + } + // Should not get a PUSH_PROMISE frame. + hf := st.wantHeaders() + if !hf.StreamEnded() { + t.Error("stream should end after headers") + } +} + +func TestServer_Push_RejectIfDisabled(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + if got, want := p.Push("https://"+r.Host+"/pushed", nil), http.ErrNotSupported; got != want { + return fmt.Errorf("Push()=%v, want %v", got, want) + } + return nil + }, + Setting{SettingEnablePush, 0}) +} + +func TestServer_Push_RejectWhenNoConcurrentStreams(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + if got, want := p.Push("https://"+r.Host+"/pushed", nil), ErrPushLimitReached; got != want { + return fmt.Errorf("Push()=%v, want %v", got, want) + } + return nil + }, + Setting{SettingMaxConcurrentStreams, 0}) +} + +func TestServer_Push_RejectWrongScheme(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + if err := p.Push("http://"+r.Host+"/pushed", nil); err == nil { + return errors.New("Push() should have failed (push target URL is http)") + } + return nil + }) +} + +func TestServer_Push_RejectMissingHost(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + if err := p.Push("https:pushed", nil); err == nil { + return errors.New("Push() should have failed (push target URL missing host)") + } + return nil + }) +} + +func TestServer_Push_RejectRelativePath(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + if err := p.Push("../test", nil); err == nil { + return errors.New("Push() should have failed (push target is a relative path)") + } + return nil + }) +} + +func TestServer_Push_RejectForbiddenMethod(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + if err := p.Push("https://"+r.Host+"/pushed", &http.PushOptions{Method: "POST"}); err == nil { + return errors.New("Push() should have failed (cannot promise a POST)") + } + return nil + }) +} + +func TestServer_Push_RejectForbiddenHeader(t *testing.T) { + testServer_Push_RejectSingleRequest(t, + func(p http.Pusher, r *http.Request) error { + header := http.Header{ + "Content-Length": {"10"}, + "Content-Encoding": {"gzip"}, + "Trailer": {"Foo"}, + "Te": {"trailers"}, + "Host": {"test.com"}, + ":authority": {"test.com"}, + } + if err := p.Push("https://"+r.Host+"/pushed", &http.PushOptions{Header: header}); err == nil { + return errors.New("Push() should have failed (forbidden headers)") + } + return nil + }) +} + +func TestServer_Push_StateTransitions(t *testing.T) { + const body = "foo" + + gotPromise := make(chan bool) + finishedPush := make(chan bool) + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + switch r.URL.RequestURI() { + case "/": + if err := w.(http.Pusher).Push("/pushed", nil); err != nil { + t.Errorf("Push error: %v", err) + } + // Don't finish this request until the push finishes so we don't + // nondeterministically interleave output frames with the push. + <-finishedPush + case "/pushed": + <-gotPromise + } + w.Header().Set("Content-Type", "text/html") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(200) + io.WriteString(w, body) + }) + defer st.Close() + + st.greet() + if st.stream(2) != nil { + t.Fatal("stream 2 should be empty") + } + if got, want := st.streamState(2), stateIdle; got != want { + t.Fatalf("streamState(2)=%v, want %v", got, want) + } + getSlash(st) + // After the PUSH_PROMISE is sent, the stream should be stateHalfClosedRemote. + st.wantPushPromise() + if got, want := st.streamState(2), stateHalfClosedRemote; got != want { + t.Fatalf("streamState(2)=%v, want %v", got, want) + } + // We stall the HTTP handler for "/pushed" until the above check. If we don't + // stall the handler, then the handler might write HEADERS and DATA and finish + // the stream before we check st.streamState(2) -- should that happen, we'll + // see stateClosed and fail the above check. + close(gotPromise) + st.wantHeaders() + if df := st.wantData(); !df.StreamEnded() { + t.Fatal("expected END_STREAM flag on DATA") + } + if got, want := st.streamState(2), stateClosed; got != want { + t.Fatalf("streamState(2)=%v, want %v", got, want) + } + close(finishedPush) +} + +func TestServer_Push_RejectAfterGoAway(t *testing.T) { + var readyOnce sync.Once + ready := make(chan struct{}) + errc := make(chan error, 2) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + select { + case <-ready: + case <-time.After(5 * time.Second): + errc <- fmt.Errorf("timeout waiting for GOAWAY to be processed") + } + if got, want := w.(http.Pusher).Push("https://"+r.Host+"/pushed", nil), http.ErrNotSupported; got != want { + errc <- fmt.Errorf("Push()=%v, want %v", got, want) + } + errc <- nil + }) + defer st.Close() + st.greet() + getSlash(st) + + // Send GOAWAY and wait for it to be processed. + st.fr.WriteGoAway(1, ErrCodeNo, nil) + go func() { + for { + select { + case <-ready: + return + default: + } + st.sc.serveMsgCh <- func(loopNum int) { + if !st.sc.pushEnabled { + readyOnce.Do(func() { close(ready) }) + } + } + } + }() + if err := <-errc; err != nil { + t.Error(err) + } +} diff --git a/vendor/golang.org/x/net/http2/server_test.go b/vendor/golang.org/x/net/http2/server_test.go new file mode 100644 index 000000000..ffa40c0df --- /dev/null +++ b/vendor/golang.org/x/net/http2/server_test.go @@ -0,0 +1,3785 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bytes" + "crypto/tls" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "net" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "reflect" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "golang.org/x/net/http2/hpack" +) + +var stderrVerbose = flag.Bool("stderr_verbose", false, "Mirror verbosity to stderr, unbuffered") + +func stderrv() io.Writer { + if *stderrVerbose { + return os.Stderr + } + + return ioutil.Discard +} + +type serverTester struct { + cc net.Conn // client conn + t testing.TB + ts *httptest.Server + fr *Framer + serverLogBuf bytes.Buffer // logger for httptest.Server + logFilter []string // substrings to filter out + scMu sync.Mutex // guards sc + sc *serverConn + hpackDec *hpack.Decoder + decodedHeaders [][2]string + + // If http2debug!=2, then we capture Frame debug logs that will be written + // to t.Log after a test fails. The read and write logs use separate locks + // and buffers so we don't accidentally introduce synchronization between + // the read and write goroutines, which may hide data races. + frameReadLogMu sync.Mutex + frameReadLogBuf bytes.Buffer + frameWriteLogMu sync.Mutex + frameWriteLogBuf bytes.Buffer + + // writing headers: + headerBuf bytes.Buffer + hpackEnc *hpack.Encoder +} + +func init() { + testHookOnPanicMu = new(sync.Mutex) + goAwayTimeout = 25 * time.Millisecond +} + +func resetHooks() { + testHookOnPanicMu.Lock() + testHookOnPanic = nil + testHookOnPanicMu.Unlock() +} + +type serverTesterOpt string + +var optOnlyServer = serverTesterOpt("only_server") +var optQuiet = serverTesterOpt("quiet_logging") +var optFramerReuseFrames = serverTesterOpt("frame_reuse_frames") + +func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester { + resetHooks() + + ts := httptest.NewUnstartedServer(handler) + + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, + NextProtos: []string{NextProtoTLS}, + } + + var onlyServer, quiet, framerReuseFrames bool + h2server := new(Server) + for _, opt := range opts { + switch v := opt.(type) { + case func(*tls.Config): + v(tlsConfig) + case func(*httptest.Server): + v(ts) + case func(*Server): + v(h2server) + case serverTesterOpt: + switch v { + case optOnlyServer: + onlyServer = true + case optQuiet: + quiet = true + case optFramerReuseFrames: + framerReuseFrames = true + } + case func(net.Conn, http.ConnState): + ts.Config.ConnState = v + default: + t.Fatalf("unknown newServerTester option type %T", v) + } + } + + ConfigureServer(ts.Config, h2server) + + st := &serverTester{ + t: t, + ts: ts, + } + st.hpackEnc = hpack.NewEncoder(&st.headerBuf) + st.hpackDec = hpack.NewDecoder(initialHeaderTableSize, st.onHeaderField) + + ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config + if quiet { + ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + } else { + ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, &st.serverLogBuf), "", log.LstdFlags) + } + ts.StartTLS() + + if VerboseLogs { + t.Logf("Running test server at: %s", ts.URL) + } + testHookGetServerConn = func(v *serverConn) { + st.scMu.Lock() + defer st.scMu.Unlock() + st.sc = v + } + log.SetOutput(io.MultiWriter(stderrv(), twriter{t: t, st: st})) + if !onlyServer { + cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), tlsConfig) + if err != nil { + t.Fatal(err) + } + st.cc = cc + st.fr = NewFramer(cc, cc) + if framerReuseFrames { + st.fr.SetReuseFrames() + } + if !logFrameReads && !logFrameWrites { + st.fr.debugReadLoggerf = func(m string, v ...interface{}) { + m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n" + st.frameReadLogMu.Lock() + fmt.Fprintf(&st.frameReadLogBuf, m, v...) + st.frameReadLogMu.Unlock() + } + st.fr.debugWriteLoggerf = func(m string, v ...interface{}) { + m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n" + st.frameWriteLogMu.Lock() + fmt.Fprintf(&st.frameWriteLogBuf, m, v...) + st.frameWriteLogMu.Unlock() + } + st.fr.logReads = true + st.fr.logWrites = true + } + } + return st +} + +func (st *serverTester) closeConn() { + st.scMu.Lock() + defer st.scMu.Unlock() + st.sc.conn.Close() +} + +func (st *serverTester) addLogFilter(phrase string) { + st.logFilter = append(st.logFilter, phrase) +} + +func (st *serverTester) stream(id uint32) *stream { + ch := make(chan *stream, 1) + st.sc.serveMsgCh <- func(int) { + ch <- st.sc.streams[id] + } + return <-ch +} + +func (st *serverTester) streamState(id uint32) streamState { + ch := make(chan streamState, 1) + st.sc.serveMsgCh <- func(int) { + state, _ := st.sc.state(id) + ch <- state + } + return <-ch +} + +// loopNum reports how many times this conn's select loop has gone around. +func (st *serverTester) loopNum() int { + lastc := make(chan int, 1) + st.sc.serveMsgCh <- func(loopNum int) { + lastc <- loopNum + } + return <-lastc +} + +// awaitIdle heuristically awaits for the server conn's select loop to be idle. +// The heuristic is that the server connection's serve loop must schedule +// 50 times in a row without any channel sends or receives occurring. +func (st *serverTester) awaitIdle() { + remain := 50 + last := st.loopNum() + for remain > 0 { + n := st.loopNum() + if n == last+1 { + remain-- + } else { + remain = 50 + } + last = n + } +} + +func (st *serverTester) Close() { + if st.t.Failed() { + st.frameReadLogMu.Lock() + if st.frameReadLogBuf.Len() > 0 { + st.t.Logf("Framer read log:\n%s", st.frameReadLogBuf.String()) + } + st.frameReadLogMu.Unlock() + + st.frameWriteLogMu.Lock() + if st.frameWriteLogBuf.Len() > 0 { + st.t.Logf("Framer write log:\n%s", st.frameWriteLogBuf.String()) + } + st.frameWriteLogMu.Unlock() + + // If we failed already (and are likely in a Fatal, + // unwindowing), force close the connection, so the + // httptest.Server doesn't wait forever for the conn + // to close. + if st.cc != nil { + st.cc.Close() + } + } + st.ts.Close() + if st.cc != nil { + st.cc.Close() + } + log.SetOutput(os.Stderr) +} + +// greet initiates the client's HTTP/2 connection into a state where +// frames may be sent. +func (st *serverTester) greet() { + st.greetAndCheckSettings(func(Setting) error { return nil }) +} + +func (st *serverTester) greetAndCheckSettings(checkSetting func(s Setting) error) { + st.writePreface() + st.writeInitialSettings() + st.wantSettings().ForeachSetting(checkSetting) + st.writeSettingsAck() + + // The initial WINDOW_UPDATE and SETTINGS ACK can come in any order. + var gotSettingsAck bool + var gotWindowUpdate bool + + for i := 0; i < 2; i++ { + f, err := st.readFrame() + if err != nil { + st.t.Fatal(err) + } + switch f := f.(type) { + case *SettingsFrame: + if !f.Header().Flags.Has(FlagSettingsAck) { + st.t.Fatal("Settings Frame didn't have ACK set") + } + gotSettingsAck = true + + case *WindowUpdateFrame: + if f.FrameHeader.StreamID != 0 { + st.t.Fatalf("WindowUpdate StreamID = %d; want 0", f.FrameHeader.StreamID) + } + incr := uint32((&Server{}).initialConnRecvWindowSize() - initialWindowSize) + if f.Increment != incr { + st.t.Fatalf("WindowUpdate increment = %d; want %d", f.Increment, incr) + } + gotWindowUpdate = true + + default: + st.t.Fatalf("Wanting a settings ACK or window update, received a %T", f) + } + } + + if !gotSettingsAck { + st.t.Fatalf("Didn't get a settings ACK") + } + if !gotWindowUpdate { + st.t.Fatalf("Didn't get a window update") + } +} + +func (st *serverTester) writePreface() { + n, err := st.cc.Write(clientPreface) + if err != nil { + st.t.Fatalf("Error writing client preface: %v", err) + } + if n != len(clientPreface) { + st.t.Fatalf("Writing client preface, wrote %d bytes; want %d", n, len(clientPreface)) + } +} + +func (st *serverTester) writeInitialSettings() { + if err := st.fr.WriteSettings(); err != nil { + st.t.Fatalf("Error writing initial SETTINGS frame from client to server: %v", err) + } +} + +func (st *serverTester) writeSettingsAck() { + if err := st.fr.WriteSettingsAck(); err != nil { + st.t.Fatalf("Error writing ACK of server's SETTINGS: %v", err) + } +} + +func (st *serverTester) writeHeaders(p HeadersFrameParam) { + if err := st.fr.WriteHeaders(p); err != nil { + st.t.Fatalf("Error writing HEADERS: %v", err) + } +} + +func (st *serverTester) writePriority(id uint32, p PriorityParam) { + if err := st.fr.WritePriority(id, p); err != nil { + st.t.Fatalf("Error writing PRIORITY: %v", err) + } +} + +func (st *serverTester) encodeHeaderField(k, v string) { + err := st.hpackEnc.WriteField(hpack.HeaderField{Name: k, Value: v}) + if err != nil { + st.t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err) + } +} + +// encodeHeaderRaw is the magic-free version of encodeHeader. +// It takes 0 or more (k, v) pairs and encodes them. +func (st *serverTester) encodeHeaderRaw(headers ...string) []byte { + if len(headers)%2 == 1 { + panic("odd number of kv args") + } + st.headerBuf.Reset() + for len(headers) > 0 { + k, v := headers[0], headers[1] + st.encodeHeaderField(k, v) + headers = headers[2:] + } + return st.headerBuf.Bytes() +} + +// encodeHeader encodes headers and returns their HPACK bytes. headers +// must contain an even number of key/value pairs. There may be +// multiple pairs for keys (e.g. "cookie"). The :method, :path, and +// :scheme headers default to GET, / and https. The :authority header +// defaults to st.ts.Listener.Addr(). +func (st *serverTester) encodeHeader(headers ...string) []byte { + if len(headers)%2 == 1 { + panic("odd number of kv args") + } + + st.headerBuf.Reset() + defaultAuthority := st.ts.Listener.Addr().String() + + if len(headers) == 0 { + // Fast path, mostly for benchmarks, so test code doesn't pollute + // profiles when we're looking to improve server allocations. + st.encodeHeaderField(":method", "GET") + st.encodeHeaderField(":scheme", "https") + st.encodeHeaderField(":authority", defaultAuthority) + st.encodeHeaderField(":path", "/") + return st.headerBuf.Bytes() + } + + if len(headers) == 2 && headers[0] == ":method" { + // Another fast path for benchmarks. + st.encodeHeaderField(":method", headers[1]) + st.encodeHeaderField(":scheme", "https") + st.encodeHeaderField(":authority", defaultAuthority) + st.encodeHeaderField(":path", "/") + return st.headerBuf.Bytes() + } + + pseudoCount := map[string]int{} + keys := []string{":method", ":scheme", ":authority", ":path"} + vals := map[string][]string{ + ":method": {"GET"}, + ":scheme": {"https"}, + ":authority": {defaultAuthority}, + ":path": {"/"}, + } + for len(headers) > 0 { + k, v := headers[0], headers[1] + headers = headers[2:] + if _, ok := vals[k]; !ok { + keys = append(keys, k) + } + if strings.HasPrefix(k, ":") { + pseudoCount[k]++ + if pseudoCount[k] == 1 { + vals[k] = []string{v} + } else { + // Allows testing of invalid headers w/ dup pseudo fields. + vals[k] = append(vals[k], v) + } + } else { + vals[k] = append(vals[k], v) + } + } + for _, k := range keys { + for _, v := range vals[k] { + st.encodeHeaderField(k, v) + } + } + return st.headerBuf.Bytes() +} + +// bodylessReq1 writes a HEADERS frames with StreamID 1 and EndStream and EndHeaders set. +func (st *serverTester) bodylessReq1(headers ...string) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(headers...), + EndStream: true, + EndHeaders: true, + }) +} + +func (st *serverTester) writeData(streamID uint32, endStream bool, data []byte) { + if err := st.fr.WriteData(streamID, endStream, data); err != nil { + st.t.Fatalf("Error writing DATA: %v", err) + } +} + +func (st *serverTester) writeDataPadded(streamID uint32, endStream bool, data, pad []byte) { + if err := st.fr.WriteDataPadded(streamID, endStream, data, pad); err != nil { + st.t.Fatalf("Error writing DATA: %v", err) + } +} + +func readFrameTimeout(fr *Framer, wait time.Duration) (Frame, error) { + ch := make(chan interface{}, 1) + go func() { + fr, err := fr.ReadFrame() + if err != nil { + ch <- err + } else { + ch <- fr + } + }() + t := time.NewTimer(wait) + select { + case v := <-ch: + t.Stop() + if fr, ok := v.(Frame); ok { + return fr, nil + } + return nil, v.(error) + case <-t.C: + return nil, errors.New("timeout waiting for frame") + } +} + +func (st *serverTester) readFrame() (Frame, error) { + return readFrameTimeout(st.fr, 2*time.Second) +} + +func (st *serverTester) wantHeaders() *HeadersFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a HEADERS frame: %v", err) + } + hf, ok := f.(*HeadersFrame) + if !ok { + st.t.Fatalf("got a %T; want *HeadersFrame", f) + } + return hf +} + +func (st *serverTester) wantContinuation() *ContinuationFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a CONTINUATION frame: %v", err) + } + cf, ok := f.(*ContinuationFrame) + if !ok { + st.t.Fatalf("got a %T; want *ContinuationFrame", f) + } + return cf +} + +func (st *serverTester) wantData() *DataFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a DATA frame: %v", err) + } + df, ok := f.(*DataFrame) + if !ok { + st.t.Fatalf("got a %T; want *DataFrame", f) + } + return df +} + +func (st *serverTester) wantSettings() *SettingsFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a SETTINGS frame: %v", err) + } + sf, ok := f.(*SettingsFrame) + if !ok { + st.t.Fatalf("got a %T; want *SettingsFrame", f) + } + return sf +} + +func (st *serverTester) wantPing() *PingFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a PING frame: %v", err) + } + pf, ok := f.(*PingFrame) + if !ok { + st.t.Fatalf("got a %T; want *PingFrame", f) + } + return pf +} + +func (st *serverTester) wantGoAway() *GoAwayFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a GOAWAY frame: %v", err) + } + gf, ok := f.(*GoAwayFrame) + if !ok { + st.t.Fatalf("got a %T; want *GoAwayFrame", f) + } + return gf +} + +func (st *serverTester) wantRSTStream(streamID uint32, errCode ErrCode) { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting an RSTStream frame: %v", err) + } + rs, ok := f.(*RSTStreamFrame) + if !ok { + st.t.Fatalf("got a %T; want *RSTStreamFrame", f) + } + if rs.FrameHeader.StreamID != streamID { + st.t.Fatalf("RSTStream StreamID = %d; want %d", rs.FrameHeader.StreamID, streamID) + } + if rs.ErrCode != errCode { + st.t.Fatalf("RSTStream ErrCode = %d (%s); want %d (%s)", rs.ErrCode, rs.ErrCode, errCode, errCode) + } +} + +func (st *serverTester) wantWindowUpdate(streamID, incr uint32) { + f, err := st.readFrame() + if err != nil { + st.t.Fatalf("Error while expecting a WINDOW_UPDATE frame: %v", err) + } + wu, ok := f.(*WindowUpdateFrame) + if !ok { + st.t.Fatalf("got a %T; want *WindowUpdateFrame", f) + } + if wu.FrameHeader.StreamID != streamID { + st.t.Fatalf("WindowUpdate StreamID = %d; want %d", wu.FrameHeader.StreamID, streamID) + } + if wu.Increment != incr { + st.t.Fatalf("WindowUpdate increment = %d; want %d", wu.Increment, incr) + } +} + +func (st *serverTester) wantSettingsAck() { + f, err := st.readFrame() + if err != nil { + st.t.Fatal(err) + } + sf, ok := f.(*SettingsFrame) + if !ok { + st.t.Fatalf("Wanting a settings ACK, received a %T", f) + } + if !sf.Header().Flags.Has(FlagSettingsAck) { + st.t.Fatal("Settings Frame didn't have ACK set") + } +} + +func (st *serverTester) wantPushPromise() *PushPromiseFrame { + f, err := st.readFrame() + if err != nil { + st.t.Fatal(err) + } + ppf, ok := f.(*PushPromiseFrame) + if !ok { + st.t.Fatalf("Wanted PushPromise, received %T", ppf) + } + return ppf +} + +func TestServer(t *testing.T) { + gotReq := make(chan bool, 1) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Foo", "Bar") + gotReq <- true + }) + defer st.Close() + + covers("3.5", ` + The server connection preface consists of a potentially empty + SETTINGS frame ([SETTINGS]) that MUST be the first frame the + server sends in the HTTP/2 connection. + `) + + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(), + EndStream: true, // no DATA frames + EndHeaders: true, + }) + + select { + case <-gotReq: + case <-time.After(2 * time.Second): + t.Error("timeout waiting for request") + } +} + +func TestServer_Request_Get(t *testing.T) { + testServerRequest(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader("foo-bar", "some-value"), + EndStream: true, // no DATA frames + EndHeaders: true, + }) + }, func(r *http.Request) { + if r.Method != "GET" { + t.Errorf("Method = %q; want GET", r.Method) + } + if r.URL.Path != "/" { + t.Errorf("URL.Path = %q; want /", r.URL.Path) + } + if r.ContentLength != 0 { + t.Errorf("ContentLength = %v; want 0", r.ContentLength) + } + if r.Close { + t.Error("Close = true; want false") + } + if !strings.Contains(r.RemoteAddr, ":") { + t.Errorf("RemoteAddr = %q; want something with a colon", r.RemoteAddr) + } + if r.Proto != "HTTP/2.0" || r.ProtoMajor != 2 || r.ProtoMinor != 0 { + t.Errorf("Proto = %q Major=%v,Minor=%v; want HTTP/2.0", r.Proto, r.ProtoMajor, r.ProtoMinor) + } + wantHeader := http.Header{ + "Foo-Bar": []string{"some-value"}, + } + if !reflect.DeepEqual(r.Header, wantHeader) { + t.Errorf("Header = %#v; want %#v", r.Header, wantHeader) + } + if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 { + t.Errorf("Read = %d, %v; want 0, EOF", n, err) + } + }) +} + +func TestServer_Request_Get_PathSlashes(t *testing.T) { + testServerRequest(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":path", "/%2f/"), + EndStream: true, // no DATA frames + EndHeaders: true, + }) + }, func(r *http.Request) { + if r.RequestURI != "/%2f/" { + t.Errorf("RequestURI = %q; want /%%2f/", r.RequestURI) + } + if r.URL.Path != "///" { + t.Errorf("URL.Path = %q; want ///", r.URL.Path) + } + }) +} + +// TODO: add a test with EndStream=true on the HEADERS but setting a +// Content-Length anyway. Should we just omit it and force it to +// zero? + +func TestServer_Request_Post_NoContentLength_EndStream(t *testing.T) { + testServerRequest(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: true, + EndHeaders: true, + }) + }, func(r *http.Request) { + if r.Method != "POST" { + t.Errorf("Method = %q; want POST", r.Method) + } + if r.ContentLength != 0 { + t.Errorf("ContentLength = %v; want 0", r.ContentLength) + } + if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 { + t.Errorf("Read = %d, %v; want 0, EOF", n, err) + } + }) +} + +func TestServer_Request_Post_Body_ImmediateEOF(t *testing.T) { + testBodyContents(t, -1, "", func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, true, nil) // just kidding. empty body. + }) +} + +func TestServer_Request_Post_Body_OneData(t *testing.T) { + const content = "Some content" + testBodyContents(t, -1, content, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, true, []byte(content)) + }) +} + +func TestServer_Request_Post_Body_TwoData(t *testing.T) { + const content = "Some content" + testBodyContents(t, -1, content, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, false, []byte(content[:5])) + st.writeData(1, true, []byte(content[5:])) + }) +} + +func TestServer_Request_Post_Body_ContentLength_Correct(t *testing.T) { + const content = "Some content" + testBodyContents(t, int64(len(content)), content, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader( + ":method", "POST", + "content-length", strconv.Itoa(len(content)), + ), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, true, []byte(content)) + }) +} + +func TestServer_Request_Post_Body_ContentLength_TooLarge(t *testing.T) { + testBodyContentsFail(t, 3, "request declared a Content-Length of 3 but only wrote 2 bytes", + func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader( + ":method", "POST", + "content-length", "3", + ), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, true, []byte("12")) + }) +} + +func TestServer_Request_Post_Body_ContentLength_TooSmall(t *testing.T) { + testBodyContentsFail(t, 4, "sender tried to send more than declared Content-Length of 4 bytes", + func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader( + ":method", "POST", + "content-length", "4", + ), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, true, []byte("12345")) + }) +} + +func testBodyContents(t *testing.T, wantContentLength int64, wantBody string, write func(st *serverTester)) { + testServerRequest(t, write, func(r *http.Request) { + if r.Method != "POST" { + t.Errorf("Method = %q; want POST", r.Method) + } + if r.ContentLength != wantContentLength { + t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength) + } + all, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + if string(all) != wantBody { + t.Errorf("Read = %q; want %q", all, wantBody) + } + if err := r.Body.Close(); err != nil { + t.Fatalf("Close: %v", err) + } + }) +} + +func testBodyContentsFail(t *testing.T, wantContentLength int64, wantReadError string, write func(st *serverTester)) { + testServerRequest(t, write, func(r *http.Request) { + if r.Method != "POST" { + t.Errorf("Method = %q; want POST", r.Method) + } + if r.ContentLength != wantContentLength { + t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength) + } + all, err := ioutil.ReadAll(r.Body) + if err == nil { + t.Fatalf("expected an error (%q) reading from the body. Successfully read %q instead.", + wantReadError, all) + } + if !strings.Contains(err.Error(), wantReadError) { + t.Fatalf("Body.Read = %v; want substring %q", err, wantReadError) + } + if err := r.Body.Close(); err != nil { + t.Fatalf("Close: %v", err) + } + }) +} + +// Using a Host header, instead of :authority +func TestServer_Request_Get_Host(t *testing.T) { + const host = "example.com" + testServerRequest(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":authority", "", "host", host), + EndStream: true, + EndHeaders: true, + }) + }, func(r *http.Request) { + if r.Host != host { + t.Errorf("Host = %q; want %q", r.Host, host) + } + }) +} + +// Using an :authority pseudo-header, instead of Host +func TestServer_Request_Get_Authority(t *testing.T) { + const host = "example.com" + testServerRequest(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":authority", host), + EndStream: true, + EndHeaders: true, + }) + }, func(r *http.Request) { + if r.Host != host { + t.Errorf("Host = %q; want %q", r.Host, host) + } + }) +} + +func TestServer_Request_WithContinuation(t *testing.T) { + wantHeader := http.Header{ + "Foo-One": []string{"value-one"}, + "Foo-Two": []string{"value-two"}, + "Foo-Three": []string{"value-three"}, + } + testServerRequest(t, func(st *serverTester) { + fullHeaders := st.encodeHeader( + "foo-one", "value-one", + "foo-two", "value-two", + "foo-three", "value-three", + ) + remain := fullHeaders + chunks := 0 + for len(remain) > 0 { + const maxChunkSize = 5 + chunk := remain + if len(chunk) > maxChunkSize { + chunk = chunk[:maxChunkSize] + } + remain = remain[len(chunk):] + + if chunks == 0 { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: chunk, + EndStream: true, // no DATA frames + EndHeaders: false, // we'll have continuation frames + }) + } else { + err := st.fr.WriteContinuation(1, len(remain) == 0, chunk) + if err != nil { + t.Fatal(err) + } + } + chunks++ + } + if chunks < 2 { + t.Fatal("too few chunks") + } + }, func(r *http.Request) { + if !reflect.DeepEqual(r.Header, wantHeader) { + t.Errorf("Header = %#v; want %#v", r.Header, wantHeader) + } + }) +} + +// Concatenated cookie headers. ("8.1.2.5 Compressing the Cookie Header Field") +func TestServer_Request_CookieConcat(t *testing.T) { + const host = "example.com" + testServerRequest(t, func(st *serverTester) { + st.bodylessReq1( + ":authority", host, + "cookie", "a=b", + "cookie", "c=d", + "cookie", "e=f", + ) + }, func(r *http.Request) { + const want = "a=b; c=d; e=f" + if got := r.Header.Get("Cookie"); got != want { + t.Errorf("Cookie = %q; want %q", got, want) + } + }) +} + +func TestServer_Request_Reject_CapitalHeader(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("UPPER", "v") }) +} + +func TestServer_Request_Reject_HeaderFieldNameColon(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("has:colon", "v") }) +} + +func TestServer_Request_Reject_HeaderFieldNameNULL(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("has\x00null", "v") }) +} + +func TestServer_Request_Reject_HeaderFieldNameEmpty(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("", "v") }) +} + +func TestServer_Request_Reject_HeaderFieldValueNewline(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\nnewline") }) +} + +func TestServer_Request_Reject_HeaderFieldValueCR(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\rcarriage") }) +} + +func TestServer_Request_Reject_HeaderFieldValueDEL(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("foo", "has\x7fdel") }) +} + +func TestServer_Request_Reject_Pseudo_Missing_method(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":method", "") }) +} + +func TestServer_Request_Reject_Pseudo_ExactlyOne(t *testing.T) { + // 8.1.2.3 Request Pseudo-Header Fields + // "All HTTP/2 requests MUST include exactly one valid value" ... + testRejectRequest(t, func(st *serverTester) { + st.addLogFilter("duplicate pseudo-header") + st.bodylessReq1(":method", "GET", ":method", "POST") + }) +} + +func TestServer_Request_Reject_Pseudo_AfterRegular(t *testing.T) { + // 8.1.2.3 Request Pseudo-Header Fields + // "All pseudo-header fields MUST appear in the header block + // before regular header fields. Any request or response that + // contains a pseudo-header field that appears in a header + // block after a regular header field MUST be treated as + // malformed (Section 8.1.2.6)." + testRejectRequest(t, func(st *serverTester) { + st.addLogFilter("pseudo-header after regular header") + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":method", Value: "GET"}) + enc.WriteField(hpack.HeaderField{Name: "regular", Value: "foobar"}) + enc.WriteField(hpack.HeaderField{Name: ":path", Value: "/"}) + enc.WriteField(hpack.HeaderField{Name: ":scheme", Value: "https"}) + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: buf.Bytes(), + EndStream: true, + EndHeaders: true, + }) + }) +} + +func TestServer_Request_Reject_Pseudo_Missing_path(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":path", "") }) +} + +func TestServer_Request_Reject_Pseudo_Missing_scheme(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "") }) +} + +func TestServer_Request_Reject_Pseudo_scheme_invalid(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "bogus") }) +} + +func TestServer_Request_Reject_Pseudo_Unknown(t *testing.T) { + testRejectRequest(t, func(st *serverTester) { + st.addLogFilter(`invalid pseudo-header ":unknown_thing"`) + st.bodylessReq1(":unknown_thing", "") + }) +} + +func testRejectRequest(t *testing.T, send func(*serverTester)) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + t.Error("server request made it to handler; should've been rejected") + }) + defer st.Close() + + st.greet() + send(st) + st.wantRSTStream(1, ErrCodeProtocol) +} + +func testRejectRequestWithProtocolError(t *testing.T, send func(*serverTester)) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + t.Error("server request made it to handler; should've been rejected") + }, optQuiet) + defer st.Close() + + st.greet() + send(st) + gf := st.wantGoAway() + if gf.ErrCode != ErrCodeProtocol { + t.Errorf("err code = %v; want %v", gf.ErrCode, ErrCodeProtocol) + } +} + +// Section 5.1, on idle connections: "Receiving any frame other than +// HEADERS or PRIORITY on a stream in this state MUST be treated as a +// connection error (Section 5.4.1) of type PROTOCOL_ERROR." +func TestRejectFrameOnIdle_WindowUpdate(t *testing.T) { + testRejectRequestWithProtocolError(t, func(st *serverTester) { + st.fr.WriteWindowUpdate(123, 456) + }) +} +func TestRejectFrameOnIdle_Data(t *testing.T) { + testRejectRequestWithProtocolError(t, func(st *serverTester) { + st.fr.WriteData(123, true, nil) + }) +} +func TestRejectFrameOnIdle_RSTStream(t *testing.T) { + testRejectRequestWithProtocolError(t, func(st *serverTester) { + st.fr.WriteRSTStream(123, ErrCodeCancel) + }) +} + +func TestServer_Request_Connect(t *testing.T) { + testServerRequest(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeaderRaw( + ":method", "CONNECT", + ":authority", "example.com:123", + ), + EndStream: true, + EndHeaders: true, + }) + }, func(r *http.Request) { + if g, w := r.Method, "CONNECT"; g != w { + t.Errorf("Method = %q; want %q", g, w) + } + if g, w := r.RequestURI, "example.com:123"; g != w { + t.Errorf("RequestURI = %q; want %q", g, w) + } + if g, w := r.URL.Host, "example.com:123"; g != w { + t.Errorf("URL.Host = %q; want %q", g, w) + } + }) +} + +func TestServer_Request_Connect_InvalidPath(t *testing.T) { + testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeaderRaw( + ":method", "CONNECT", + ":authority", "example.com:123", + ":path", "/bogus", + ), + EndStream: true, + EndHeaders: true, + }) + }) +} + +func TestServer_Request_Connect_InvalidScheme(t *testing.T) { + testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeaderRaw( + ":method", "CONNECT", + ":authority", "example.com:123", + ":scheme", "https", + ), + EndStream: true, + EndHeaders: true, + }) + }) +} + +func TestServer_Ping(t *testing.T) { + st := newServerTester(t, nil) + defer st.Close() + st.greet() + + // Server should ignore this one, since it has ACK set. + ackPingData := [8]byte{1, 2, 4, 8, 16, 32, 64, 128} + if err := st.fr.WritePing(true, ackPingData); err != nil { + t.Fatal(err) + } + + // But the server should reply to this one, since ACK is false. + pingData := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} + if err := st.fr.WritePing(false, pingData); err != nil { + t.Fatal(err) + } + + pf := st.wantPing() + if !pf.Flags.Has(FlagPingAck) { + t.Error("response ping doesn't have ACK set") + } + if pf.Data != pingData { + t.Errorf("response ping has data %q; want %q", pf.Data, pingData) + } +} + +func TestServer_RejectsLargeFrames(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("see golang.org/issue/13434") + } + + st := newServerTester(t, nil) + defer st.Close() + st.greet() + + // Write too large of a frame (too large by one byte) + // We ignore the return value because it's expected that the server + // will only read the first 9 bytes (the headre) and then disconnect. + st.fr.WriteRawFrame(0xff, 0, 0, make([]byte, defaultMaxReadFrameSize+1)) + + gf := st.wantGoAway() + if gf.ErrCode != ErrCodeFrameSize { + t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFrameSize) + } + if st.serverLogBuf.Len() != 0 { + // Previously we spun here for a bit until the GOAWAY disconnect + // timer fired, logging while we fired. + t.Errorf("unexpected server output: %.500s\n", st.serverLogBuf.Bytes()) + } +} + +func TestServer_Handler_Sends_WindowUpdate(t *testing.T) { + puppet := newHandlerPuppet() + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + puppet.act(w, r) + }) + defer st.Close() + defer puppet.done() + + st.greet() + + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // data coming + EndHeaders: true, + }) + st.writeData(1, false, []byte("abcdef")) + puppet.do(readBodyHandler(t, "abc")) + st.wantWindowUpdate(0, 3) + st.wantWindowUpdate(1, 3) + + puppet.do(readBodyHandler(t, "def")) + st.wantWindowUpdate(0, 3) + st.wantWindowUpdate(1, 3) + + st.writeData(1, true, []byte("ghijkl")) // END_STREAM here + puppet.do(readBodyHandler(t, "ghi")) + puppet.do(readBodyHandler(t, "jkl")) + st.wantWindowUpdate(0, 3) + st.wantWindowUpdate(0, 3) // no more stream-level, since END_STREAM +} + +// the version of the TestServer_Handler_Sends_WindowUpdate with padding. +// See golang.org/issue/16556 +func TestServer_Handler_Sends_WindowUpdate_Padding(t *testing.T) { + puppet := newHandlerPuppet() + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + puppet.act(w, r) + }) + defer st.Close() + defer puppet.done() + + st.greet() + + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, + EndHeaders: true, + }) + st.writeDataPadded(1, false, []byte("abcdef"), []byte{0, 0, 0, 0}) + + // Expect to immediately get our 5 bytes of padding back for + // both the connection and stream (4 bytes of padding + 1 byte of length) + st.wantWindowUpdate(0, 5) + st.wantWindowUpdate(1, 5) + + puppet.do(readBodyHandler(t, "abc")) + st.wantWindowUpdate(0, 3) + st.wantWindowUpdate(1, 3) + + puppet.do(readBodyHandler(t, "def")) + st.wantWindowUpdate(0, 3) + st.wantWindowUpdate(1, 3) +} + +func TestServer_Send_GoAway_After_Bogus_WindowUpdate(t *testing.T) { + st := newServerTester(t, nil) + defer st.Close() + st.greet() + if err := st.fr.WriteWindowUpdate(0, 1<<31-1); err != nil { + t.Fatal(err) + } + gf := st.wantGoAway() + if gf.ErrCode != ErrCodeFlowControl { + t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFlowControl) + } + if gf.LastStreamID != 0 { + t.Errorf("GOAWAY last stream ID = %v; want %v", gf.LastStreamID, 0) + } +} + +func TestServer_Send_RstStream_After_Bogus_WindowUpdate(t *testing.T) { + inHandler := make(chan bool) + blockHandler := make(chan bool) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + inHandler <- true + <-blockHandler + }) + defer st.Close() + defer close(blockHandler) + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // keep it open + EndHeaders: true, + }) + <-inHandler + // Send a bogus window update: + if err := st.fr.WriteWindowUpdate(1, 1<<31-1); err != nil { + t.Fatal(err) + } + st.wantRSTStream(1, ErrCodeFlowControl) +} + +// testServerPostUnblock sends a hanging POST with unsent data to handler, +// then runs fn once in the handler, and verifies that the error returned from +// handler is acceptable. It fails if takes over 5 seconds for handler to exit. +func testServerPostUnblock(t *testing.T, + handler func(http.ResponseWriter, *http.Request) error, + fn func(*serverTester), + checkErr func(error), + otherHeaders ...string) { + inHandler := make(chan bool) + errc := make(chan error, 1) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + inHandler <- true + errc <- handler(w, r) + }) + defer st.Close() + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(append([]string{":method", "POST"}, otherHeaders...)...), + EndStream: false, // keep it open + EndHeaders: true, + }) + <-inHandler + fn(st) + select { + case err := <-errc: + if checkErr != nil { + checkErr(err) + } + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for Handler to return") + } +} + +func TestServer_RSTStream_Unblocks_Read(t *testing.T) { + testServerPostUnblock(t, + func(w http.ResponseWriter, r *http.Request) (err error) { + _, err = r.Body.Read(make([]byte, 1)) + return + }, + func(st *serverTester) { + if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { + t.Fatal(err) + } + }, + func(err error) { + want := StreamError{StreamID: 0x1, Code: 0x8} + if !reflect.DeepEqual(err, want) { + t.Errorf("Read error = %v; want %v", err, want) + } + }, + ) +} + +func TestServer_RSTStream_Unblocks_Header_Write(t *testing.T) { + // Run this test a bunch, because it doesn't always + // deadlock. But with a bunch, it did. + n := 50 + if testing.Short() { + n = 5 + } + for i := 0; i < n; i++ { + testServer_RSTStream_Unblocks_Header_Write(t) + } +} + +func testServer_RSTStream_Unblocks_Header_Write(t *testing.T) { + inHandler := make(chan bool, 1) + unblockHandler := make(chan bool, 1) + headerWritten := make(chan bool, 1) + wroteRST := make(chan bool, 1) + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + inHandler <- true + <-wroteRST + w.Header().Set("foo", "bar") + w.WriteHeader(200) + w.(http.Flusher).Flush() + headerWritten <- true + <-unblockHandler + }) + defer st.Close() + + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // keep it open + EndHeaders: true, + }) + <-inHandler + if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { + t.Fatal(err) + } + wroteRST <- true + st.awaitIdle() + select { + case <-headerWritten: + case <-time.After(2 * time.Second): + t.Error("timeout waiting for header write") + } + unblockHandler <- true +} + +func TestServer_DeadConn_Unblocks_Read(t *testing.T) { + testServerPostUnblock(t, + func(w http.ResponseWriter, r *http.Request) (err error) { + _, err = r.Body.Read(make([]byte, 1)) + return + }, + func(st *serverTester) { st.cc.Close() }, + func(err error) { + if err == nil { + t.Error("unexpected nil error from Request.Body.Read") + } + }, + ) +} + +var blockUntilClosed = func(w http.ResponseWriter, r *http.Request) error { + <-w.(http.CloseNotifier).CloseNotify() + return nil +} + +func TestServer_CloseNotify_After_RSTStream(t *testing.T) { + testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { + if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { + t.Fatal(err) + } + }, nil) +} + +func TestServer_CloseNotify_After_ConnClose(t *testing.T) { + testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { st.cc.Close() }, nil) +} + +// that CloseNotify unblocks after a stream error due to the client's +// problem that's unrelated to them explicitly canceling it (which is +// TestServer_CloseNotify_After_RSTStream above) +func TestServer_CloseNotify_After_StreamError(t *testing.T) { + testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { + // data longer than declared Content-Length => stream error + st.writeData(1, true, []byte("1234")) + }, nil, "content-length", "3") +} + +func TestServer_StateTransitions(t *testing.T) { + var st *serverTester + inHandler := make(chan bool) + writeData := make(chan bool) + leaveHandler := make(chan bool) + st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + inHandler <- true + if st.stream(1) == nil { + t.Errorf("nil stream 1 in handler") + } + if got, want := st.streamState(1), stateOpen; got != want { + t.Errorf("in handler, state is %v; want %v", got, want) + } + writeData <- true + if n, err := r.Body.Read(make([]byte, 1)); n != 0 || err != io.EOF { + t.Errorf("body read = %d, %v; want 0, EOF", n, err) + } + if got, want := st.streamState(1), stateHalfClosedRemote; got != want { + t.Errorf("in handler, state is %v; want %v", got, want) + } + + <-leaveHandler + }) + st.greet() + if st.stream(1) != nil { + t.Fatal("stream 1 should be empty") + } + if got := st.streamState(1); got != stateIdle { + t.Fatalf("stream 1 should be idle; got %v", got) + } + + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, // keep it open + EndHeaders: true, + }) + <-inHandler + <-writeData + st.writeData(1, true, nil) + + leaveHandler <- true + hf := st.wantHeaders() + if !hf.StreamEnded() { + t.Fatal("expected END_STREAM flag") + } + + if got, want := st.streamState(1), stateClosed; got != want { + t.Errorf("at end, state is %v; want %v", got, want) + } + if st.stream(1) != nil { + t.Fatal("at end, stream 1 should be gone") + } +} + +// test HEADERS w/o EndHeaders + another HEADERS (should get rejected) +func TestServer_Rejects_HeadersNoEnd_Then_Headers(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: false, + }) + st.writeHeaders(HeadersFrameParam{ // Not a continuation. + StreamID: 3, // different stream. + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: true, + }) + }) +} + +// test HEADERS w/o EndHeaders + PING (should get rejected) +func TestServer_Rejects_HeadersNoEnd_Then_Ping(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: false, + }) + if err := st.fr.WritePing(false, [8]byte{}); err != nil { + t.Fatal(err) + } + }) +} + +// test HEADERS w/ EndHeaders + a continuation HEADERS (should get rejected) +func TestServer_Rejects_HeadersEnd_Then_Continuation(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: true, + }) + st.wantHeaders() + if err := st.fr.WriteContinuation(1, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil { + t.Fatal(err) + } + }) +} + +// test HEADERS w/o EndHeaders + a continuation HEADERS on wrong stream ID +func TestServer_Rejects_HeadersNoEnd_Then_ContinuationWrongStream(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: false, + }) + if err := st.fr.WriteContinuation(3, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil { + t.Fatal(err) + } + }) +} + +// No HEADERS on stream 0. +func TestServer_Rejects_Headers0(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.fr.AllowIllegalWrites = true + st.writeHeaders(HeadersFrameParam{ + StreamID: 0, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: true, + }) + }) +} + +// No CONTINUATION on stream 0. +func TestServer_Rejects_Continuation0(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.fr.AllowIllegalWrites = true + if err := st.fr.WriteContinuation(0, true, st.encodeHeader()); err != nil { + t.Fatal(err) + } + }) +} + +// No PRIORITY on stream 0. +func TestServer_Rejects_Priority0(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + st.fr.AllowIllegalWrites = true + st.writePriority(0, PriorityParam{StreamDep: 1}) + }) +} + +// No HEADERS frame with a self-dependence. +func TestServer_Rejects_HeadersSelfDependence(t *testing.T) { + testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) { + st.fr.AllowIllegalWrites = true + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: true, + Priority: PriorityParam{StreamDep: 1}, + }) + }) +} + +// No PRIORTY frame with a self-dependence. +func TestServer_Rejects_PrioritySelfDependence(t *testing.T) { + testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) { + st.fr.AllowIllegalWrites = true + st.writePriority(1, PriorityParam{StreamDep: 1}) + }) +} + +func TestServer_Rejects_PushPromise(t *testing.T) { + testServerRejectsConn(t, func(st *serverTester) { + pp := PushPromiseParam{ + StreamID: 1, + PromiseID: 3, + } + if err := st.fr.WritePushPromise(pp); err != nil { + t.Fatal(err) + } + }) +} + +// testServerRejectsConn tests that the server hangs up with a GOAWAY +// frame and a server close after the client does something +// deserving a CONNECTION_ERROR. +func testServerRejectsConn(t *testing.T, writeReq func(*serverTester)) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}) + st.addLogFilter("connection error: PROTOCOL_ERROR") + defer st.Close() + st.greet() + writeReq(st) + + st.wantGoAway() + errc := make(chan error, 1) + go func() { + fr, err := st.fr.ReadFrame() + if err == nil { + err = fmt.Errorf("got frame of type %T", fr) + } + errc <- err + }() + select { + case err := <-errc: + if err != io.EOF { + t.Errorf("ReadFrame = %v; want io.EOF", err) + } + case <-time.After(2 * time.Second): + t.Error("timeout waiting for disconnect") + } +} + +// testServerRejectsStream tests that the server sends a RST_STREAM with the provided +// error code after a client sends a bogus request. +func testServerRejectsStream(t *testing.T, code ErrCode, writeReq func(*serverTester)) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}) + defer st.Close() + st.greet() + writeReq(st) + st.wantRSTStream(1, code) +} + +// testServerRequest sets up an idle HTTP/2 connection and lets you +// write a single request with writeReq, and then verify that the +// *http.Request is built correctly in checkReq. +func testServerRequest(t *testing.T, writeReq func(*serverTester), checkReq func(*http.Request)) { + gotReq := make(chan bool, 1) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + if r.Body == nil { + t.Fatal("nil Body") + } + checkReq(r) + gotReq <- true + }) + defer st.Close() + + st.greet() + writeReq(st) + + select { + case <-gotReq: + case <-time.After(2 * time.Second): + t.Error("timeout waiting for request") + } +} + +func getSlash(st *serverTester) { st.bodylessReq1() } + +func TestServer_Response_NoData(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + // Nothing. + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if !hf.StreamEnded() { + t.Fatal("want END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + }) +} + +func TestServer_Response_NoData_Header_FooBar(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Set("Foo-Bar", "some-value") + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if !hf.StreamEnded() { + t.Fatal("want END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"foo-bar", "some-value"}, + {"content-length", "0"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + }) +} + +func TestServer_Response_Data_Sniff_DoesntOverride(t *testing.T) { + const msg = "<html>this is HTML." + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Set("Content-Type", "foo/bar") + io.WriteString(w, msg) + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("don't want END_STREAM, expecting data") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"content-type", "foo/bar"}, + {"content-length", strconv.Itoa(len(msg))}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + df := st.wantData() + if !df.StreamEnded() { + t.Error("expected DATA to have END_STREAM flag") + } + if got := string(df.Data()); got != msg { + t.Errorf("got DATA %q; want %q", got, msg) + } + }) +} + +func TestServer_Response_Nosniff_WithoutContentType(t *testing.T) { + const msg = "<html>this is HTML." + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Set("X-Content-Type-Options", "nosniff") + w.WriteHeader(200) + io.WriteString(w, msg) + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("don't want END_STREAM, expecting data") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"x-content-type-options", "nosniff"}, + {"content-type", "application/octet-stream"}, + {"content-length", strconv.Itoa(len(msg))}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + df := st.wantData() + if !df.StreamEnded() { + t.Error("expected DATA to have END_STREAM flag") + } + if got := string(df.Data()); got != msg { + t.Errorf("got DATA %q; want %q", got, msg) + } + }) +} + +func TestServer_Response_TransferEncoding_chunked(t *testing.T) { + const msg = "hi" + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Set("Transfer-Encoding", "chunked") // should be stripped + io.WriteString(w, msg) + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"content-type", "text/plain; charset=utf-8"}, + {"content-length", strconv.Itoa(len(msg))}, + {"x-content-type-options", "nosniff"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + }) +} + +// Header accessed only after the initial write. +func TestServer_Response_Data_IgnoreHeaderAfterWrite_After(t *testing.T) { + const msg = "<html>this is HTML." + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + io.WriteString(w, msg) + w.Header().Set("foo", "should be ignored") + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"content-type", "text/html; charset=utf-8"}, + {"content-length", strconv.Itoa(len(msg))}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + }) +} + +// Header accessed before the initial write and later mutated. +func TestServer_Response_Data_IgnoreHeaderAfterWrite_Overwrite(t *testing.T) { + const msg = "<html>this is HTML." + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Set("foo", "proper value") + io.WriteString(w, msg) + w.Header().Set("foo", "should be ignored") + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"foo", "proper value"}, + {"content-type", "text/html; charset=utf-8"}, + {"content-length", strconv.Itoa(len(msg))}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + }) +} + +func TestServer_Response_Data_SniffLenType(t *testing.T) { + const msg = "<html>this is HTML." + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + io.WriteString(w, msg) + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("don't want END_STREAM, expecting data") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"content-type", "text/html; charset=utf-8"}, + {"content-length", strconv.Itoa(len(msg))}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + df := st.wantData() + if !df.StreamEnded() { + t.Error("expected DATA to have END_STREAM flag") + } + if got := string(df.Data()); got != msg { + t.Errorf("got DATA %q; want %q", got, msg) + } + }) +} + +func TestServer_Response_Header_Flush_MidWrite(t *testing.T) { + const msg = "<html>this is HTML" + const msg2 = ", and this is the next chunk" + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + io.WriteString(w, msg) + w.(http.Flusher).Flush() + io.WriteString(w, msg2) + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"content-type", "text/html; charset=utf-8"}, // sniffed + // and no content-length + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + { + df := st.wantData() + if df.StreamEnded() { + t.Error("unexpected END_STREAM flag") + } + if got := string(df.Data()); got != msg { + t.Errorf("got DATA %q; want %q", got, msg) + } + } + { + df := st.wantData() + if !df.StreamEnded() { + t.Error("wanted END_STREAM flag on last data chunk") + } + if got := string(df.Data()); got != msg2 { + t.Errorf("got DATA %q; want %q", got, msg2) + } + } + }) +} + +func TestServer_Response_LargeWrite(t *testing.T) { + const size = 1 << 20 + const maxFrameSize = 16 << 10 + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + n, err := w.Write(bytes.Repeat([]byte("a"), size)) + if err != nil { + return fmt.Errorf("Write error: %v", err) + } + if n != size { + return fmt.Errorf("wrong size %d from Write", n) + } + return nil + }, func(st *serverTester) { + if err := st.fr.WriteSettings( + Setting{SettingInitialWindowSize, 0}, + Setting{SettingMaxFrameSize, maxFrameSize}, + ); err != nil { + t.Fatal(err) + } + st.wantSettingsAck() + + getSlash(st) // make the single request + + // Give the handler quota to write: + if err := st.fr.WriteWindowUpdate(1, size); err != nil { + t.Fatal(err) + } + // Give the handler quota to write to connection-level + // window as well + if err := st.fr.WriteWindowUpdate(0, size); err != nil { + t.Fatal(err) + } + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"content-type", "text/plain; charset=utf-8"}, // sniffed + {"x-content-type-options", "nosniff"}, + // and no content-length + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + var bytes, frames int + for { + df := st.wantData() + bytes += len(df.Data()) + frames++ + for _, b := range df.Data() { + if b != 'a' { + t.Fatal("non-'a' byte seen in DATA") + } + } + if df.StreamEnded() { + break + } + } + if bytes != size { + t.Errorf("Got %d bytes; want %d", bytes, size) + } + if want := int(size / maxFrameSize); frames < want || frames > want*2 { + t.Errorf("Got %d frames; want %d", frames, size) + } + }) +} + +// Test that the handler can't write more than the client allows +func TestServer_Response_LargeWrite_FlowControlled(t *testing.T) { + // Make these reads. Before each read, the client adds exactly enough + // flow-control to satisfy the read. Numbers chosen arbitrarily. + reads := []int{123, 1, 13, 127} + size := 0 + for _, n := range reads { + size += n + } + + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.(http.Flusher).Flush() + n, err := w.Write(bytes.Repeat([]byte("a"), size)) + if err != nil { + return fmt.Errorf("Write error: %v", err) + } + if n != size { + return fmt.Errorf("wrong size %d from Write", n) + } + return nil + }, func(st *serverTester) { + // Set the window size to something explicit for this test. + // It's also how much initial data we expect. + if err := st.fr.WriteSettings(Setting{SettingInitialWindowSize, uint32(reads[0])}); err != nil { + t.Fatal(err) + } + st.wantSettingsAck() + + getSlash(st) // make the single request + + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + + df := st.wantData() + if got := len(df.Data()); got != reads[0] { + t.Fatalf("Initial window size = %d but got DATA with %d bytes", reads[0], got) + } + + for _, quota := range reads[1:] { + if err := st.fr.WriteWindowUpdate(1, uint32(quota)); err != nil { + t.Fatal(err) + } + df := st.wantData() + if int(quota) != len(df.Data()) { + t.Fatalf("read %d bytes after giving %d quota", len(df.Data()), quota) + } + } + }) +} + +// Test that the handler blocked in a Write is unblocked if the server sends a RST_STREAM. +func TestServer_Response_RST_Unblocks_LargeWrite(t *testing.T) { + const size = 1 << 20 + const maxFrameSize = 16 << 10 + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.(http.Flusher).Flush() + errc := make(chan error, 1) + go func() { + _, err := w.Write(bytes.Repeat([]byte("a"), size)) + errc <- err + }() + select { + case err := <-errc: + if err == nil { + return errors.New("unexpected nil error from Write in handler") + } + return nil + case <-time.After(2 * time.Second): + return errors.New("timeout waiting for Write in handler") + } + }, func(st *serverTester) { + if err := st.fr.WriteSettings( + Setting{SettingInitialWindowSize, 0}, + Setting{SettingMaxFrameSize, maxFrameSize}, + ); err != nil { + t.Fatal(err) + } + st.wantSettingsAck() + + getSlash(st) // make the single request + + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + + if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { + t.Fatal(err) + } + }) +} + +func TestServer_Response_Empty_Data_Not_FlowControlled(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.(http.Flusher).Flush() + // Nothing; send empty DATA + return nil + }, func(st *serverTester) { + // Handler gets no data quota: + if err := st.fr.WriteSettings(Setting{SettingInitialWindowSize, 0}); err != nil { + t.Fatal(err) + } + st.wantSettingsAck() + + getSlash(st) // make the single request + + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + + df := st.wantData() + if got := len(df.Data()); got != 0 { + t.Fatalf("unexpected %d DATA bytes; want 0", got) + } + if !df.StreamEnded() { + t.Fatal("DATA didn't have END_STREAM") + } + }) +} + +func TestServer_Response_Automatic100Continue(t *testing.T) { + const msg = "foo" + const reply = "bar" + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + if v := r.Header.Get("Expect"); v != "" { + t.Errorf("Expect header = %q; want empty", v) + } + buf := make([]byte, len(msg)) + // This read should trigger the 100-continue being sent. + if n, err := io.ReadFull(r.Body, buf); err != nil || n != len(msg) || string(buf) != msg { + return fmt.Errorf("ReadFull = %q, %v; want %q, nil", buf[:n], err, msg) + } + _, err := io.WriteString(w, reply) + return err + }, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "POST", "expect", "100-continue"), + EndStream: false, + EndHeaders: true, + }) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "100"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Fatalf("Got headers %v; want %v", goth, wanth) + } + + // Okay, they sent status 100, so we can send our + // gigantic and/or sensitive "foo" payload now. + st.writeData(1, true, []byte(msg)) + + st.wantWindowUpdate(0, uint32(len(msg))) + + hf = st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("expected data to follow") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + goth = st.decodeHeader(hf.HeaderBlockFragment()) + wanth = [][2]string{ + {":status", "200"}, + {"content-type", "text/plain; charset=utf-8"}, + {"content-length", strconv.Itoa(len(reply))}, + {"x-content-type-options", "nosniff"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } + + df := st.wantData() + if string(df.Data()) != reply { + t.Errorf("Client read %q; want %q", df.Data(), reply) + } + if !df.StreamEnded() { + t.Errorf("expect data stream end") + } + }) +} + +func TestServer_HandlerWriteErrorOnDisconnect(t *testing.T) { + errc := make(chan error, 1) + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + p := []byte("some data.\n") + for { + _, err := w.Write(p) + if err != nil { + errc <- err + return nil + } + } + }, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: false, + EndHeaders: true, + }) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("unexpected END_STREAM flag") + } + if !hf.HeadersEnded() { + t.Fatal("want END_HEADERS flag") + } + // Close the connection and wait for the handler to (hopefully) notice. + st.cc.Close() + select { + case <-errc: + case <-time.After(5 * time.Second): + t.Error("timeout") + } + }) +} + +func TestServer_Rejects_Too_Many_Streams(t *testing.T) { + const testPath = "/some/path" + + inHandler := make(chan uint32) + leaveHandler := make(chan bool) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + id := w.(*responseWriter).rws.stream.id + inHandler <- id + if id == 1+(defaultMaxStreams+1)*2 && r.URL.Path != testPath { + t.Errorf("decoded final path as %q; want %q", r.URL.Path, testPath) + } + <-leaveHandler + }) + defer st.Close() + st.greet() + nextStreamID := uint32(1) + streamID := func() uint32 { + defer func() { nextStreamID += 2 }() + return nextStreamID + } + sendReq := func(id uint32, headers ...string) { + st.writeHeaders(HeadersFrameParam{ + StreamID: id, + BlockFragment: st.encodeHeader(headers...), + EndStream: true, + EndHeaders: true, + }) + } + for i := 0; i < defaultMaxStreams; i++ { + sendReq(streamID()) + <-inHandler + } + defer func() { + for i := 0; i < defaultMaxStreams; i++ { + leaveHandler <- true + } + }() + + // And this one should cross the limit: + // (It's also sent as a CONTINUATION, to verify we still track the decoder context, + // even if we're rejecting it) + rejectID := streamID() + headerBlock := st.encodeHeader(":path", testPath) + frag1, frag2 := headerBlock[:3], headerBlock[3:] + st.writeHeaders(HeadersFrameParam{ + StreamID: rejectID, + BlockFragment: frag1, + EndStream: true, + EndHeaders: false, // CONTINUATION coming + }) + if err := st.fr.WriteContinuation(rejectID, true, frag2); err != nil { + t.Fatal(err) + } + st.wantRSTStream(rejectID, ErrCodeProtocol) + + // But let a handler finish: + leaveHandler <- true + st.wantHeaders() + + // And now another stream should be able to start: + goodID := streamID() + sendReq(goodID, ":path", testPath) + select { + case got := <-inHandler: + if got != goodID { + t.Errorf("Got stream %d; want %d", got, goodID) + } + case <-time.After(3 * time.Second): + t.Error("timeout waiting for handler") + } +} + +// So many response headers that the server needs to use CONTINUATION frames: +func TestServer_Response_ManyHeaders_With_Continuation(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + h := w.Header() + for i := 0; i < 5000; i++ { + h.Set(fmt.Sprintf("x-header-%d", i), fmt.Sprintf("x-value-%d", i)) + } + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.HeadersEnded() { + t.Fatal("got unwanted END_HEADERS flag") + } + n := 0 + for { + n++ + cf := st.wantContinuation() + if cf.HeadersEnded() { + break + } + } + if n < 5 { + t.Errorf("Only got %d CONTINUATION frames; expected 5+ (currently 6)", n) + } + }) +} + +// This previously crashed (reported by Mathieu Lonjaret as observed +// while using Camlistore) because we got a DATA frame from the client +// after the handler exited and our logic at the time was wrong, +// keeping a stream in the map in stateClosed, which tickled an +// invariant check later when we tried to remove that stream (via +// defer sc.closeAllStreamsOnConnClose) when the serverConn serve loop +// ended. +func TestServer_NoCrash_HandlerClose_Then_ClientClose(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + // nothing + return nil + }, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: false, // DATA is coming + EndHeaders: true, + }) + hf := st.wantHeaders() + if !hf.HeadersEnded() || !hf.StreamEnded() { + t.Fatalf("want END_HEADERS+END_STREAM, got %v", hf) + } + + // Sent when the a Handler closes while a client has + // indicated it's still sending DATA: + st.wantRSTStream(1, ErrCodeNo) + + // Now the handler has ended, so it's ended its + // stream, but the client hasn't closed its side + // (stateClosedLocal). So send more data and verify + // it doesn't crash with an internal invariant panic, like + // it did before. + st.writeData(1, true, []byte("foo")) + + // Get our flow control bytes back, since the handler didn't get them. + st.wantWindowUpdate(0, uint32(len("foo"))) + + // Sent after a peer sends data anyway (admittedly the + // previous RST_STREAM might've still been in-flight), + // but they'll get the more friendly 'cancel' code + // first. + st.wantRSTStream(1, ErrCodeStreamClosed) + + // Set up a bunch of machinery to record the panic we saw + // previously. + var ( + panMu sync.Mutex + panicVal interface{} + ) + + testHookOnPanicMu.Lock() + testHookOnPanic = func(sc *serverConn, pv interface{}) bool { + panMu.Lock() + panicVal = pv + panMu.Unlock() + return true + } + testHookOnPanicMu.Unlock() + + // Now force the serve loop to end, via closing the connection. + st.cc.Close() + select { + case <-st.sc.doneServing: + // Loop has exited. + panMu.Lock() + got := panicVal + panMu.Unlock() + if got != nil { + t.Errorf("Got panic: %v", got) + } + case <-time.After(5 * time.Second): + t.Error("timeout") + } + }) +} + +func TestServer_Rejects_TLS10(t *testing.T) { testRejectTLS(t, tls.VersionTLS10) } +func TestServer_Rejects_TLS11(t *testing.T) { testRejectTLS(t, tls.VersionTLS11) } + +func testRejectTLS(t *testing.T, max uint16) { + st := newServerTester(t, nil, func(c *tls.Config) { + c.MaxVersion = max + }) + defer st.Close() + gf := st.wantGoAway() + if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want { + t.Errorf("Got error code %v; want %v", got, want) + } +} + +func TestServer_Rejects_TLSBadCipher(t *testing.T) { + st := newServerTester(t, nil, func(c *tls.Config) { + // Only list bad ones: + c.CipherSuites = []uint16{ + tls.TLS_RSA_WITH_RC4_128_SHA, + tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + tls.TLS_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, + tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + cipher_TLS_RSA_WITH_AES_128_CBC_SHA256, + } + }) + defer st.Close() + gf := st.wantGoAway() + if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want { + t.Errorf("Got error code %v; want %v", got, want) + } +} + +func TestServer_Advertises_Common_Cipher(t *testing.T) { + const requiredSuite = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + st := newServerTester(t, nil, func(c *tls.Config) { + // Have the client only support the one required by the spec. + c.CipherSuites = []uint16{requiredSuite} + }, func(ts *httptest.Server) { + var srv *http.Server = ts.Config + // Have the server configured with no specific cipher suites. + // This tests that Go's defaults include the required one. + srv.TLSConfig = nil + }) + defer st.Close() + st.greet() +} + +func (st *serverTester) onHeaderField(f hpack.HeaderField) { + if f.Name == "date" { + return + } + st.decodedHeaders = append(st.decodedHeaders, [2]string{f.Name, f.Value}) +} + +func (st *serverTester) decodeHeader(headerBlock []byte) (pairs [][2]string) { + st.decodedHeaders = nil + if _, err := st.hpackDec.Write(headerBlock); err != nil { + st.t.Fatalf("hpack decoding error: %v", err) + } + if err := st.hpackDec.Close(); err != nil { + st.t.Fatalf("hpack decoding error: %v", err) + } + return st.decodedHeaders +} + +// testServerResponse sets up an idle HTTP/2 connection. The client function should +// write a single request that must be handled by the handler. This waits up to 5s +// for client to return, then up to an additional 2s for the handler to return. +func testServerResponse(t testing.TB, + handler func(http.ResponseWriter, *http.Request) error, + client func(*serverTester), +) { + errc := make(chan error, 1) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + if r.Body == nil { + t.Fatal("nil Body") + } + errc <- handler(w, r) + }) + defer st.Close() + + donec := make(chan bool) + go func() { + defer close(donec) + st.greet() + client(st) + }() + + select { + case <-donec: + case <-time.After(5 * time.Second): + t.Fatal("timeout in client") + } + + select { + case err := <-errc: + if err != nil { + t.Fatalf("Error in handler: %v", err) + } + case <-time.After(2 * time.Second): + t.Fatal("timeout in handler") + } +} + +// readBodyHandler returns an http Handler func that reads len(want) +// bytes from r.Body and fails t if the contents read were not +// the value of want. +func readBodyHandler(t *testing.T, want string) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + buf := make([]byte, len(want)) + _, err := io.ReadFull(r.Body, buf) + if err != nil { + t.Error(err) + return + } + if string(buf) != want { + t.Errorf("read %q; want %q", buf, want) + } + } +} + +// TestServerWithCurl currently fails, hence the LenientCipherSuites test. See: +// https://github.com/tatsuhiro-t/nghttp2/issues/140 & +// http://sourceforge.net/p/curl/bugs/1472/ +func TestServerWithCurl(t *testing.T) { testServerWithCurl(t, false) } +func TestServerWithCurl_LenientCipherSuites(t *testing.T) { testServerWithCurl(t, true) } + +func testServerWithCurl(t *testing.T, permitProhibitedCipherSuites bool) { + if runtime.GOOS != "linux" { + t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway") + } + if testing.Short() { + t.Skip("skipping curl test in short mode") + } + requireCurl(t) + var gotConn int32 + testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) } + + const msg = "Hello from curl!\n" + ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Foo", "Bar") + w.Header().Set("Client-Proto", r.Proto) + io.WriteString(w, msg) + })) + ConfigureServer(ts.Config, &Server{ + PermitProhibitedCipherSuites: permitProhibitedCipherSuites, + }) + ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config + ts.StartTLS() + defer ts.Close() + + t.Logf("Running test server for curl to hit at: %s", ts.URL) + container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL) + defer kill(container) + resc := make(chan interface{}, 1) + go func() { + res, err := dockerLogs(container) + if err != nil { + resc <- err + } else { + resc <- res + } + }() + select { + case res := <-resc: + if err, ok := res.(error); ok { + t.Fatal(err) + } + body := string(res.([]byte)) + // Search for both "key: value" and "key:value", since curl changed their format + // Our Dockerfile contains the latest version (no space), but just in case people + // didn't rebuild, check both. + if !strings.Contains(body, "foo: Bar") && !strings.Contains(body, "foo:Bar") { + t.Errorf("didn't see foo: Bar header") + t.Logf("Got: %s", body) + } + if !strings.Contains(body, "client-proto: HTTP/2") && !strings.Contains(body, "client-proto:HTTP/2") { + t.Errorf("didn't see client-proto: HTTP/2 header") + t.Logf("Got: %s", res) + } + if !strings.Contains(string(res.([]byte)), msg) { + t.Errorf("didn't see %q content", msg) + t.Logf("Got: %s", res) + } + case <-time.After(3 * time.Second): + t.Errorf("timeout waiting for curl") + } + + if atomic.LoadInt32(&gotConn) == 0 { + t.Error("never saw an http2 connection") + } +} + +var doh2load = flag.Bool("h2load", false, "Run h2load test") + +func TestServerWithH2Load(t *testing.T) { + if !*doh2load { + t.Skip("Skipping without --h2load flag.") + } + if runtime.GOOS != "linux" { + t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway") + } + requireH2load(t) + + msg := strings.Repeat("Hello, h2load!\n", 5000) + ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, msg) + w.(http.Flusher).Flush() + io.WriteString(w, msg) + })) + ts.StartTLS() + defer ts.Close() + + cmd := exec.Command("docker", "run", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl", + "-n100000", "-c100", "-m100", ts.URL) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + t.Fatal(err) + } +} + +// Issue 12843 +func TestServerDoS_MaxHeaderListSize(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}) + defer st.Close() + + // shake hands + frameSize := defaultMaxReadFrameSize + var advHeaderListSize *uint32 + st.greetAndCheckSettings(func(s Setting) error { + switch s.ID { + case SettingMaxFrameSize: + if s.Val < minMaxFrameSize { + frameSize = minMaxFrameSize + } else if s.Val > maxFrameSize { + frameSize = maxFrameSize + } else { + frameSize = int(s.Val) + } + case SettingMaxHeaderListSize: + advHeaderListSize = &s.Val + } + return nil + }) + + if advHeaderListSize == nil { + t.Errorf("server didn't advertise a max header list size") + } else if *advHeaderListSize == 0 { + t.Errorf("server advertised a max header list size of 0") + } + + st.encodeHeaderField(":method", "GET") + st.encodeHeaderField(":path", "/") + st.encodeHeaderField(":scheme", "https") + cookie := strings.Repeat("*", 4058) + st.encodeHeaderField("cookie", cookie) + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.headerBuf.Bytes(), + EndStream: true, + EndHeaders: false, + }) + + // Capture the short encoding of a duplicate ~4K cookie, now + // that we've already sent it once. + st.headerBuf.Reset() + st.encodeHeaderField("cookie", cookie) + + // Now send 1MB of it. + const size = 1 << 20 + b := bytes.Repeat(st.headerBuf.Bytes(), size/st.headerBuf.Len()) + for len(b) > 0 { + chunk := b + if len(chunk) > frameSize { + chunk = chunk[:frameSize] + } + b = b[len(chunk):] + st.fr.WriteContinuation(1, len(b) == 0, chunk) + } + + h := st.wantHeaders() + if !h.HeadersEnded() { + t.Fatalf("Got HEADERS without END_HEADERS set: %v", h) + } + headers := st.decodeHeader(h.HeaderBlockFragment()) + want := [][2]string{ + {":status", "431"}, + {"content-type", "text/html; charset=utf-8"}, + {"content-length", "63"}, + } + if !reflect.DeepEqual(headers, want) { + t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) + } +} + +func TestCompressionErrorOnWrite(t *testing.T) { + const maxStrLen = 8 << 10 + var serverConfig *http.Server + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + // No response body. + }, func(ts *httptest.Server) { + serverConfig = ts.Config + serverConfig.MaxHeaderBytes = maxStrLen + }) + st.addLogFilter("connection error: COMPRESSION_ERROR") + defer st.Close() + st.greet() + + maxAllowed := st.sc.framer.maxHeaderStringLen() + + // Crank this up, now that we have a conn connected with the + // hpack.Decoder's max string length set has been initialized + // from the earlier low ~8K value. We want this higher so don't + // hit the max header list size. We only want to test hitting + // the max string size. + serverConfig.MaxHeaderBytes = 1 << 20 + + // First a request with a header that's exactly the max allowed size + // for the hpack compression. It's still too long for the header list + // size, so we'll get the 431 error, but that keeps the compression + // context still valid. + hbf := st.encodeHeader("foo", strings.Repeat("a", maxAllowed)) + + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: hbf, + EndStream: true, + EndHeaders: true, + }) + h := st.wantHeaders() + if !h.HeadersEnded() { + t.Fatalf("Got HEADERS without END_HEADERS set: %v", h) + } + headers := st.decodeHeader(h.HeaderBlockFragment()) + want := [][2]string{ + {":status", "431"}, + {"content-type", "text/html; charset=utf-8"}, + {"content-length", "63"}, + } + if !reflect.DeepEqual(headers, want) { + t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) + } + df := st.wantData() + if !strings.Contains(string(df.Data()), "HTTP Error 431") { + t.Errorf("Unexpected data body: %q", df.Data()) + } + if !df.StreamEnded() { + t.Fatalf("expect data stream end") + } + + // And now send one that's just one byte too big. + hbf = st.encodeHeader("bar", strings.Repeat("b", maxAllowed+1)) + st.writeHeaders(HeadersFrameParam{ + StreamID: 3, + BlockFragment: hbf, + EndStream: true, + EndHeaders: true, + }) + ga := st.wantGoAway() + if ga.ErrCode != ErrCodeCompression { + t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode) + } +} + +func TestCompressionErrorOnClose(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + // No response body. + }) + st.addLogFilter("connection error: COMPRESSION_ERROR") + defer st.Close() + st.greet() + + hbf := st.encodeHeader("foo", "bar") + hbf = hbf[:len(hbf)-1] // truncate one byte from the end, so hpack.Decoder.Close fails. + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: hbf, + EndStream: true, + EndHeaders: true, + }) + ga := st.wantGoAway() + if ga.ErrCode != ErrCodeCompression { + t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode) + } +} + +// test that a server handler can read trailers from a client +func TestServerReadsTrailers(t *testing.T) { + const testBody = "some test body" + writeReq := func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader("trailer", "Foo, Bar", "trailer", "Baz"), + EndStream: false, + EndHeaders: true, + }) + st.writeData(1, false, []byte(testBody)) + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeaderRaw( + "foo", "foov", + "bar", "barv", + "baz", "bazv", + "surprise", "wasn't declared; shouldn't show up", + ), + EndStream: true, + EndHeaders: true, + }) + } + checkReq := func(r *http.Request) { + wantTrailer := http.Header{ + "Foo": nil, + "Bar": nil, + "Baz": nil, + } + if !reflect.DeepEqual(r.Trailer, wantTrailer) { + t.Errorf("initial Trailer = %v; want %v", r.Trailer, wantTrailer) + } + slurp, err := ioutil.ReadAll(r.Body) + if string(slurp) != testBody { + t.Errorf("read body %q; want %q", slurp, testBody) + } + if err != nil { + t.Fatalf("Body slurp: %v", err) + } + wantTrailerAfter := http.Header{ + "Foo": {"foov"}, + "Bar": {"barv"}, + "Baz": {"bazv"}, + } + if !reflect.DeepEqual(r.Trailer, wantTrailerAfter) { + t.Errorf("final Trailer = %v; want %v", r.Trailer, wantTrailerAfter) + } + } + testServerRequest(t, writeReq, checkReq) +} + +// test that a server handler can send trailers +func TestServerWritesTrailers_WithFlush(t *testing.T) { testServerWritesTrailers(t, true) } +func TestServerWritesTrailers_WithoutFlush(t *testing.T) { testServerWritesTrailers(t, false) } + +func testServerWritesTrailers(t *testing.T, withFlush bool) { + // See https://httpwg.github.io/specs/rfc7540.html#rfc.section.8.1.3 + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B") + w.Header().Add("Trailer", "Server-Trailer-C") + w.Header().Add("Trailer", "Transfer-Encoding, Content-Length, Trailer") // filtered + + // Regular headers: + w.Header().Set("Foo", "Bar") + w.Header().Set("Content-Length", "5") // len("Hello") + + io.WriteString(w, "Hello") + if withFlush { + w.(http.Flusher).Flush() + } + w.Header().Set("Server-Trailer-A", "valuea") + w.Header().Set("Server-Trailer-C", "valuec") // skipping B + // After a flush, random keys like Server-Surprise shouldn't show up: + w.Header().Set("Server-Surpise", "surprise! this isn't predeclared!") + // But we do permit promoting keys to trailers after a + // flush if they start with the magic + // otherwise-invalid "Trailer:" prefix: + w.Header().Set("Trailer:Post-Header-Trailer", "hi1") + w.Header().Set("Trailer:post-header-trailer2", "hi2") + w.Header().Set("Trailer:Range", "invalid") + w.Header().Set("Trailer:Foo\x01Bogus", "invalid") + w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 7230 4.1.2") + w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 7230 4.1.2") + w.Header().Set("Trailer", "should not be included; Forbidden by RFC 7230 4.1.2") + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if hf.StreamEnded() { + t.Fatal("response HEADERS had END_STREAM") + } + if !hf.HeadersEnded() { + t.Fatal("response HEADERS didn't have END_HEADERS") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"foo", "Bar"}, + {"trailer", "Server-Trailer-A, Server-Trailer-B"}, + {"trailer", "Server-Trailer-C"}, + {"trailer", "Transfer-Encoding, Content-Length, Trailer"}, + {"content-type", "text/plain; charset=utf-8"}, + {"content-length", "5"}, + {"x-content-type-options", "nosniff"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth) + } + df := st.wantData() + if string(df.Data()) != "Hello" { + t.Fatalf("Client read %q; want Hello", df.Data()) + } + if df.StreamEnded() { + t.Fatalf("data frame had STREAM_ENDED") + } + tf := st.wantHeaders() // for the trailers + if !tf.StreamEnded() { + t.Fatalf("trailers HEADERS lacked END_STREAM") + } + if !tf.HeadersEnded() { + t.Fatalf("trailers HEADERS lacked END_HEADERS") + } + wanth = [][2]string{ + {"post-header-trailer", "hi1"}, + {"post-header-trailer2", "hi2"}, + {"server-trailer-a", "valuea"}, + {"server-trailer-c", "valuec"}, + } + goth = st.decodeHeader(tf.HeaderBlockFragment()) + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth) + } + }) +} + +// validate transmitted header field names & values +// golang.org/issue/14048 +func TestServerDoesntWriteInvalidHeaders(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + w.Header().Add("OK1", "x") + w.Header().Add("Bad:Colon", "x") // colon (non-token byte) in key + w.Header().Add("Bad1\x00", "x") // null in key + w.Header().Add("Bad2", "x\x00y") // null in value + return nil + }, func(st *serverTester) { + getSlash(st) + hf := st.wantHeaders() + if !hf.StreamEnded() { + t.Error("response HEADERS lacked END_STREAM") + } + if !hf.HeadersEnded() { + t.Fatal("response HEADERS didn't have END_HEADERS") + } + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "200"}, + {"ok1", "x"}, + {"content-length", "0"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth) + } + }) +} + +func BenchmarkServerGets(b *testing.B) { + defer disableGoroutineTracking()() + b.ReportAllocs() + + const msg = "Hello, world" + st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, msg) + }) + defer st.Close() + st.greet() + + // Give the server quota to reply. (plus it has the 64KB) + if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil { + b.Fatal(err) + } + + for i := 0; i < b.N; i++ { + id := 1 + uint32(i)*2 + st.writeHeaders(HeadersFrameParam{ + StreamID: id, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: true, + }) + st.wantHeaders() + df := st.wantData() + if !df.StreamEnded() { + b.Fatalf("DATA didn't have END_STREAM; got %v", df) + } + } +} + +func BenchmarkServerPosts(b *testing.B) { + defer disableGoroutineTracking()() + b.ReportAllocs() + + const msg = "Hello, world" + st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { + // Consume the (empty) body from th peer before replying, otherwise + // the server will sometimes (depending on scheduling) send the peer a + // a RST_STREAM with the CANCEL error code. + if n, err := io.Copy(ioutil.Discard, r.Body); n != 0 || err != nil { + b.Errorf("Copy error; got %v, %v; want 0, nil", n, err) + } + io.WriteString(w, msg) + }) + defer st.Close() + st.greet() + + // Give the server quota to reply. (plus it has the 64KB) + if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil { + b.Fatal(err) + } + + for i := 0; i < b.N; i++ { + id := 1 + uint32(i)*2 + st.writeHeaders(HeadersFrameParam{ + StreamID: id, + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, + EndHeaders: true, + }) + st.writeData(id, true, nil) + st.wantHeaders() + df := st.wantData() + if !df.StreamEnded() { + b.Fatalf("DATA didn't have END_STREAM; got %v", df) + } + } +} + +// Send a stream of messages from server to client in separate data frames. +// Brings up performance issues seen in long streams. +// Created to show problem in go issue #18502 +func BenchmarkServerToClientStreamDefaultOptions(b *testing.B) { + benchmarkServerToClientStream(b) +} + +// Justification for Change-Id: Iad93420ef6c3918f54249d867098f1dadfa324d8 +// Expect to see memory/alloc reduction by opting in to Frame reuse with the Framer. +func BenchmarkServerToClientStreamReuseFrames(b *testing.B) { + benchmarkServerToClientStream(b, optFramerReuseFrames) +} + +func benchmarkServerToClientStream(b *testing.B, newServerOpts ...interface{}) { + defer disableGoroutineTracking()() + b.ReportAllocs() + const msgLen = 1 + // default window size + const windowSize = 1<<16 - 1 + + // next message to send from the server and for the client to expect + nextMsg := func(i int) []byte { + msg := make([]byte, msgLen) + msg[0] = byte(i) + if len(msg) != msgLen { + panic("invalid test setup msg length") + } + return msg + } + + st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { + // Consume the (empty) body from th peer before replying, otherwise + // the server will sometimes (depending on scheduling) send the peer a + // a RST_STREAM with the CANCEL error code. + if n, err := io.Copy(ioutil.Discard, r.Body); n != 0 || err != nil { + b.Errorf("Copy error; got %v, %v; want 0, nil", n, err) + } + for i := 0; i < b.N; i += 1 { + w.Write(nextMsg(i)) + w.(http.Flusher).Flush() + } + }, newServerOpts...) + defer st.Close() + st.greet() + + const id = uint32(1) + + st.writeHeaders(HeadersFrameParam{ + StreamID: id, + BlockFragment: st.encodeHeader(":method", "POST"), + EndStream: false, + EndHeaders: true, + }) + + st.writeData(id, true, nil) + st.wantHeaders() + + var pendingWindowUpdate = uint32(0) + + for i := 0; i < b.N; i += 1 { + expected := nextMsg(i) + df := st.wantData() + if bytes.Compare(expected, df.data) != 0 { + b.Fatalf("Bad message received; want %v; got %v", expected, df.data) + } + // try to send infrequent but large window updates so they don't overwhelm the test + pendingWindowUpdate += uint32(len(df.data)) + if pendingWindowUpdate >= windowSize/2 { + if err := st.fr.WriteWindowUpdate(0, pendingWindowUpdate); err != nil { + b.Fatal(err) + } + if err := st.fr.WriteWindowUpdate(id, pendingWindowUpdate); err != nil { + b.Fatal(err) + } + pendingWindowUpdate = 0 + } + } + df := st.wantData() + if !df.StreamEnded() { + b.Fatalf("DATA didn't have END_STREAM; got %v", df) + } +} + +// go-fuzz bug, originally reported at https://github.com/bradfitz/http2/issues/53 +// Verify we don't hang. +func TestIssue53(t *testing.T) { + const data = "PRI * HTTP/2.0\r\n\r\nSM" + + "\r\n\r\n\x00\x00\x00\x01\ainfinfin\ad" + s := &http.Server{ + ErrorLog: log.New(io.MultiWriter(stderrv(), twriter{t: t}), "", log.LstdFlags), + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.Write([]byte("hello")) + }), + } + s2 := &Server{ + MaxReadFrameSize: 1 << 16, + PermitProhibitedCipherSuites: true, + } + c := &issue53Conn{[]byte(data), false, false} + s2.ServeConn(c, &ServeConnOpts{BaseConfig: s}) + if !c.closed { + t.Fatal("connection is not closed") + } +} + +type issue53Conn struct { + data []byte + closed bool + written bool +} + +func (c *issue53Conn) Read(b []byte) (n int, err error) { + if len(c.data) == 0 { + return 0, io.EOF + } + n = copy(b, c.data) + c.data = c.data[n:] + return +} + +func (c *issue53Conn) Write(b []byte) (n int, err error) { + c.written = true + return len(b), nil +} + +func (c *issue53Conn) Close() error { + c.closed = true + return nil +} + +func (c *issue53Conn) LocalAddr() net.Addr { + return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 49706} +} +func (c *issue53Conn) RemoteAddr() net.Addr { + return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 49706} +} +func (c *issue53Conn) SetDeadline(t time.Time) error { return nil } +func (c *issue53Conn) SetReadDeadline(t time.Time) error { return nil } +func (c *issue53Conn) SetWriteDeadline(t time.Time) error { return nil } + +// golang.org/issue/12895 +func TestConfigureServer(t *testing.T) { + tests := []struct { + name string + tlsConfig *tls.Config + wantErr string + }{ + { + name: "empty server", + }, + { + name: "just the required cipher suite", + tlsConfig: &tls.Config{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + }, + }, + { + name: "just the alternative required cipher suite", + tlsConfig: &tls.Config{ + CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + }, + }, + { + name: "missing required cipher suite", + tlsConfig: &tls.Config{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, + }, + wantErr: "is missing an HTTP/2-required AES_128_GCM_SHA256 cipher.", + }, + { + name: "required after bad", + tlsConfig: &tls.Config{ + CipherSuites: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + }, + wantErr: "contains an HTTP/2-approved cipher suite (0xc02f), but it comes after", + }, + { + name: "bad after required", + tlsConfig: &tls.Config{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_RC4_128_SHA}, + }, + }, + } + for _, tt := range tests { + srv := &http.Server{TLSConfig: tt.tlsConfig} + err := ConfigureServer(srv, nil) + if (err != nil) != (tt.wantErr != "") { + if tt.wantErr != "" { + t.Errorf("%s: success, but want error", tt.name) + } else { + t.Errorf("%s: unexpected error: %v", tt.name, err) + } + } + if err != nil && tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr) { + t.Errorf("%s: err = %v; want substring %q", tt.name, err, tt.wantErr) + } + if err == nil && !srv.TLSConfig.PreferServerCipherSuites { + t.Errorf("%s: PreferServerCipherSuite is false; want true", tt.name) + } + } +} + +func TestServerRejectHeadWithBody(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + // No response body. + }) + defer st.Close() + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "HEAD"), + EndStream: false, // what we're testing, a bogus HEAD request with body + EndHeaders: true, + }) + st.wantRSTStream(1, ErrCodeProtocol) +} + +func TestServerNoAutoContentLengthOnHead(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + // No response body. (or smaller than one frame) + }) + defer st.Close() + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader(":method", "HEAD"), + EndStream: true, + EndHeaders: true, + }) + h := st.wantHeaders() + headers := st.decodeHeader(h.HeaderBlockFragment()) + want := [][2]string{ + {":status", "200"}, + } + if !reflect.DeepEqual(headers, want) { + t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) + } +} + +// golang.org/issue/13495 +func TestServerNoDuplicateContentType(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + w.Header()["Content-Type"] = []string{""} + fmt.Fprintf(w, "<html><head></head><body>hi</body></html>") + }) + defer st.Close() + st.greet() + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: st.encodeHeader(), + EndStream: true, + EndHeaders: true, + }) + h := st.wantHeaders() + headers := st.decodeHeader(h.HeaderBlockFragment()) + want := [][2]string{ + {":status", "200"}, + {"content-type", ""}, + {"content-length", "41"}, + {"x-content-type-options", "nosniff"}, + } + if !reflect.DeepEqual(headers, want) { + t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) + } +} + +func disableGoroutineTracking() (restore func()) { + old := DebugGoroutines + DebugGoroutines = false + return func() { DebugGoroutines = old } +} + +func BenchmarkServer_GetRequest(b *testing.B) { + defer disableGoroutineTracking()() + b.ReportAllocs() + const msg = "Hello, world." + st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { + n, err := io.Copy(ioutil.Discard, r.Body) + if err != nil || n > 0 { + b.Errorf("Read %d bytes, error %v; want 0 bytes.", n, err) + } + io.WriteString(w, msg) + }) + defer st.Close() + + st.greet() + // Give the server quota to reply. (plus it has the 64KB) + if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil { + b.Fatal(err) + } + hbf := st.encodeHeader(":method", "GET") + for i := 0; i < b.N; i++ { + streamID := uint32(1 + 2*i) + st.writeHeaders(HeadersFrameParam{ + StreamID: streamID, + BlockFragment: hbf, + EndStream: true, + EndHeaders: true, + }) + st.wantHeaders() + st.wantData() + } +} + +func BenchmarkServer_PostRequest(b *testing.B) { + defer disableGoroutineTracking()() + b.ReportAllocs() + const msg = "Hello, world." + st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { + n, err := io.Copy(ioutil.Discard, r.Body) + if err != nil || n > 0 { + b.Errorf("Read %d bytes, error %v; want 0 bytes.", n, err) + } + io.WriteString(w, msg) + }) + defer st.Close() + st.greet() + // Give the server quota to reply. (plus it has the 64KB) + if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil { + b.Fatal(err) + } + hbf := st.encodeHeader(":method", "POST") + for i := 0; i < b.N; i++ { + streamID := uint32(1 + 2*i) + st.writeHeaders(HeadersFrameParam{ + StreamID: streamID, + BlockFragment: hbf, + EndStream: false, + EndHeaders: true, + }) + st.writeData(streamID, true, nil) + st.wantHeaders() + st.wantData() + } +} + +type connStateConn struct { + net.Conn + cs tls.ConnectionState +} + +func (c connStateConn) ConnectionState() tls.ConnectionState { return c.cs } + +// golang.org/issue/12737 -- handle any net.Conn, not just +// *tls.Conn. +func TestServerHandleCustomConn(t *testing.T) { + var s Server + c1, c2 := net.Pipe() + clientDone := make(chan struct{}) + handlerDone := make(chan struct{}) + var req *http.Request + go func() { + defer close(clientDone) + defer c2.Close() + fr := NewFramer(c2, c2) + io.WriteString(c2, ClientPreface) + fr.WriteSettings() + fr.WriteSettingsAck() + f, err := fr.ReadFrame() + if err != nil { + t.Error(err) + return + } + if sf, ok := f.(*SettingsFrame); !ok || sf.IsAck() { + t.Errorf("Got %v; want non-ACK SettingsFrame", summarizeFrame(f)) + return + } + f, err = fr.ReadFrame() + if err != nil { + t.Error(err) + return + } + if sf, ok := f.(*SettingsFrame); !ok || !sf.IsAck() { + t.Errorf("Got %v; want ACK SettingsFrame", summarizeFrame(f)) + return + } + var henc hpackEncoder + fr.WriteHeaders(HeadersFrameParam{ + StreamID: 1, + BlockFragment: henc.encodeHeaderRaw(t, ":method", "GET", ":path", "/", ":scheme", "https", ":authority", "foo.com"), + EndStream: true, + EndHeaders: true, + }) + go io.Copy(ioutil.Discard, c2) + <-handlerDone + }() + const testString = "my custom ConnectionState" + fakeConnState := tls.ConnectionState{ + ServerName: testString, + Version: tls.VersionTLS12, + CipherSuite: cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + } + go s.ServeConn(connStateConn{c1, fakeConnState}, &ServeConnOpts{ + BaseConfig: &http.Server{ + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer close(handlerDone) + req = r + }), + }}) + select { + case <-clientDone: + case <-time.After(5 * time.Second): + t.Fatal("timeout waiting for handler") + } + if req.TLS == nil { + t.Fatalf("Request.TLS is nil. Got: %#v", req) + } + if req.TLS.ServerName != testString { + t.Fatalf("Request.TLS = %+v; want ServerName of %q", req.TLS, testString) + } +} + +// golang.org/issue/14214 +func TestServer_Rejects_ConnHeaders(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + t.Error("should not get to Handler") + }) + defer st.Close() + st.greet() + st.bodylessReq1("connection", "foo") + hf := st.wantHeaders() + goth := st.decodeHeader(hf.HeaderBlockFragment()) + wanth := [][2]string{ + {":status", "400"}, + {"content-type", "text/plain; charset=utf-8"}, + {"x-content-type-options", "nosniff"}, + {"content-length", "51"}, + } + if !reflect.DeepEqual(goth, wanth) { + t.Errorf("Got headers %v; want %v", goth, wanth) + } +} + +type hpackEncoder struct { + enc *hpack.Encoder + buf bytes.Buffer +} + +func (he *hpackEncoder) encodeHeaderRaw(t *testing.T, headers ...string) []byte { + if len(headers)%2 == 1 { + panic("odd number of kv args") + } + he.buf.Reset() + if he.enc == nil { + he.enc = hpack.NewEncoder(&he.buf) + } + for len(headers) > 0 { + k, v := headers[0], headers[1] + err := he.enc.WriteField(hpack.HeaderField{Name: k, Value: v}) + if err != nil { + t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err) + } + headers = headers[2:] + } + return he.buf.Bytes() +} + +func TestCheckValidHTTP2Request(t *testing.T) { + tests := []struct { + h http.Header + want error + }{ + { + h: http.Header{"Te": {"trailers"}}, + want: nil, + }, + { + h: http.Header{"Te": {"trailers", "bogus"}}, + want: errors.New(`request header "TE" may only be "trailers" in HTTP/2`), + }, + { + h: http.Header{"Foo": {""}}, + want: nil, + }, + { + h: http.Header{"Connection": {""}}, + want: errors.New(`request header "Connection" is not valid in HTTP/2`), + }, + { + h: http.Header{"Proxy-Connection": {""}}, + want: errors.New(`request header "Proxy-Connection" is not valid in HTTP/2`), + }, + { + h: http.Header{"Keep-Alive": {""}}, + want: errors.New(`request header "Keep-Alive" is not valid in HTTP/2`), + }, + { + h: http.Header{"Upgrade": {""}}, + want: errors.New(`request header "Upgrade" is not valid in HTTP/2`), + }, + } + for i, tt := range tests { + got := checkValidHTTP2RequestHeaders(tt.h) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%d. checkValidHTTP2Request = %v; want %v", i, got, tt.want) + } + } +} + +// golang.org/issue/14030 +func TestExpect100ContinueAfterHandlerWrites(t *testing.T) { + const msg = "Hello" + const msg2 = "World" + + doRead := make(chan bool, 1) + defer close(doRead) // fallback cleanup + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, msg) + w.(http.Flusher).Flush() + + // Do a read, which might force a 100-continue status to be sent. + <-doRead + r.Body.Read(make([]byte, 10)) + + io.WriteString(w, msg2) + + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + req, _ := http.NewRequest("POST", st.ts.URL, io.LimitReader(neverEnding('A'), 2<<20)) + req.Header.Set("Expect", "100-continue") + + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + buf := make([]byte, len(msg)) + if _, err := io.ReadFull(res.Body, buf); err != nil { + t.Fatal(err) + } + if string(buf) != msg { + t.Fatalf("msg = %q; want %q", buf, msg) + } + + doRead <- true + + if _, err := io.ReadFull(res.Body, buf); err != nil { + t.Fatal(err) + } + if string(buf) != msg2 { + t.Fatalf("second msg = %q; want %q", buf, msg2) + } +} + +type funcReader func([]byte) (n int, err error) + +func (f funcReader) Read(p []byte) (n int, err error) { return f(p) } + +// golang.org/issue/16481 -- return flow control when streams close with unread data. +// (The Server version of the bug. See also TestUnreadFlowControlReturned_Transport) +func TestUnreadFlowControlReturned_Server(t *testing.T) { + unblock := make(chan bool, 1) + defer close(unblock) + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + // Don't read the 16KB request body. Wait until the client's + // done sending it and then return. This should cause the Server + // to then return those 16KB of flow control to the client. + <-unblock + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + // This previously hung on the 4th iteration. + for i := 0; i < 6; i++ { + body := io.MultiReader( + io.LimitReader(neverEnding('A'), 16<<10), + funcReader(func([]byte) (n int, err error) { + unblock <- true + return 0, io.EOF + }), + ) + req, _ := http.NewRequest("POST", st.ts.URL, body) + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + } + +} + +func TestServerIdleTimeout(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + }, func(h2s *Server) { + h2s.IdleTimeout = 500 * time.Millisecond + }) + defer st.Close() + + st.greet() + ga := st.wantGoAway() + if ga.ErrCode != ErrCodeNo { + t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode) + } +} + +func TestServerIdleTimeout_AfterRequest(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + const timeout = 250 * time.Millisecond + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + time.Sleep(timeout * 2) + }, func(h2s *Server) { + h2s.IdleTimeout = timeout + }) + defer st.Close() + + st.greet() + + // Send a request which takes twice the timeout. Verifies the + // idle timeout doesn't fire while we're in a request: + st.bodylessReq1() + st.wantHeaders() + + // But the idle timeout should be rearmed after the request + // is done: + ga := st.wantGoAway() + if ga.ErrCode != ErrCodeNo { + t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode) + } +} + +// grpc-go closes the Request.Body currently with a Read. +// Verify that it doesn't race. +// See https://github.com/grpc/grpc-go/pull/938 +func TestRequestBodyReadCloseRace(t *testing.T) { + for i := 0; i < 100; i++ { + body := &requestBody{ + pipe: &pipe{ + b: new(bytes.Buffer), + }, + } + body.pipe.CloseWithError(io.EOF) + + done := make(chan bool, 1) + buf := make([]byte, 10) + go func() { + time.Sleep(1 * time.Millisecond) + body.Close() + done <- true + }() + body.Read(buf) + <-done + } +} + +func TestIssue20704Race(t *testing.T) { + if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" { + t.Skip("skipping in short mode") + } + const ( + itemSize = 1 << 10 + itemCount = 100 + ) + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + for i := 0; i < itemCount; i++ { + _, err := w.Write(make([]byte, itemSize)) + if err != nil { + return + } + } + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + cl := &http.Client{Transport: tr} + + for i := 0; i < 1000; i++ { + resp, err := cl.Get(st.ts.URL) + if err != nil { + t.Fatal(err) + } + // Force a RST stream to the server by closing without + // reading the body: + resp.Body.Close() + } +} + +func TestServer_Rejects_TooSmall(t *testing.T) { + testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { + return nil + }, func(st *serverTester) { + st.writeHeaders(HeadersFrameParam{ + StreamID: 1, // clients send odd numbers + BlockFragment: st.encodeHeader( + ":method", "POST", + "content-length", "4", + ), + EndStream: false, // to say DATA frames are coming + EndHeaders: true, + }) + st.writeData(1, true, []byte("12345")) + + st.wantRSTStream(1, ErrCodeProtocol) + }) +} diff --git a/vendor/golang.org/x/net/http2/transport_test.go b/vendor/golang.org/x/net/http2/transport_test.go new file mode 100644 index 000000000..ed58ce870 --- /dev/null +++ b/vendor/golang.org/x/net/http2/transport_test.go @@ -0,0 +1,3848 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bufio" + "bytes" + "crypto/tls" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "math/rand" + "net" + "net/http" + "net/http/httptest" + "net/url" + "os" + "reflect" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "golang.org/x/net/http2/hpack" +) + +var ( + extNet = flag.Bool("extnet", false, "do external network tests") + transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport") + insecure = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove? +) + +var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true} + +type testContext struct{} + +func (testContext) Done() <-chan struct{} { return make(chan struct{}) } +func (testContext) Err() error { panic("should not be called") } +func (testContext) Deadline() (deadline time.Time, ok bool) { return time.Time{}, false } +func (testContext) Value(key interface{}) interface{} { return nil } + +func TestTransportExternal(t *testing.T) { + if !*extNet { + t.Skip("skipping external network test") + } + req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil) + rt := &Transport{TLSClientConfig: tlsConfigInsecure} + res, err := rt.RoundTrip(req) + if err != nil { + t.Fatalf("%v", err) + } + res.Write(os.Stdout) +} + +type fakeTLSConn struct { + net.Conn +} + +func (c *fakeTLSConn) ConnectionState() tls.ConnectionState { + return tls.ConnectionState{ + Version: tls.VersionTLS12, + CipherSuite: cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + } +} + +func startH2cServer(t *testing.T) net.Listener { + h2Server := &Server{} + l := newLocalListener(t) + go func() { + conn, err := l.Accept() + if err != nil { + t.Error(err) + return + } + h2Server.ServeConn(&fakeTLSConn{conn}, &ServeConnOpts{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil) + })}) + }() + return l +} + +func TestTransportH2c(t *testing.T) { + l := startH2cServer(t) + defer l.Close() + req, err := http.NewRequest("GET", "http://"+l.Addr().String()+"/foobar", nil) + if err != nil { + t.Fatal(err) + } + tr := &Transport{ + AllowHTTP: true, + DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { + return net.Dial(network, addr) + }, + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + if res.ProtoMajor != 2 { + t.Fatal("proto not h2c") + } + body, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if got, want := string(body), "Hello, /foobar, http: true"; got != want { + t.Fatalf("response got %v, want %v", got, want) + } +} + +func TestTransport(t *testing.T) { + const body = "sup" + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, body) + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + t.Fatal(err) + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + t.Logf("Got res: %+v", res) + if g, w := res.StatusCode, 200; g != w { + t.Errorf("StatusCode = %v; want %v", g, w) + } + if g, w := res.Status, "200 OK"; g != w { + t.Errorf("Status = %q; want %q", g, w) + } + wantHeader := http.Header{ + "Content-Length": []string{"3"}, + "X-Content-Type-Options": []string{"nosniff"}, + "Content-Type": []string{"text/plain; charset=utf-8"}, + "Date": []string{"XXX"}, // see cleanDate + } + cleanDate(res) + if !reflect.DeepEqual(res.Header, wantHeader) { + t.Errorf("res Header = %v; want %v", res.Header, wantHeader) + } + if res.Request != req { + t.Errorf("Response.Request = %p; want %p", res.Request, req) + } + if res.TLS == nil { + t.Error("Response.TLS = nil; want non-nil") + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Errorf("Body read: %v", err) + } else if string(slurp) != body { + t.Errorf("Body = %q; want %q", slurp, body) + } +} + +func onSameConn(t *testing.T, modReq func(*http.Request)) bool { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, r.RemoteAddr) + }, optOnlyServer, func(c net.Conn, st http.ConnState) { + t.Logf("conn %v is now state %v", c.RemoteAddr(), st) + }) + defer st.Close() + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + get := func() string { + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + t.Fatal(err) + } + modReq(req) + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatalf("Body read: %v", err) + } + addr := strings.TrimSpace(string(slurp)) + if addr == "" { + t.Fatalf("didn't get an addr in response") + } + return addr + } + first := get() + second := get() + return first == second +} + +func TestTransportReusesConns(t *testing.T) { + if !onSameConn(t, func(*http.Request) {}) { + t.Errorf("first and second responses were on different connections") + } +} + +func TestTransportReusesConn_RequestClose(t *testing.T) { + if onSameConn(t, func(r *http.Request) { r.Close = true }) { + t.Errorf("first and second responses were not on different connections") + } +} + +func TestTransportReusesConn_ConnClose(t *testing.T) { + if onSameConn(t, func(r *http.Request) { r.Header.Set("Connection", "close") }) { + t.Errorf("first and second responses were not on different connections") + } +} + +// Tests that the Transport only keeps one pending dial open per destination address. +// https://golang.org/issue/13397 +func TestTransportGroupsPendingDials(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, r.RemoteAddr) + }, optOnlyServer) + defer st.Close() + tr := &Transport{ + TLSClientConfig: tlsConfigInsecure, + } + defer tr.CloseIdleConnections() + var ( + mu sync.Mutex + dials = map[string]int{} + ) + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + t.Error(err) + return + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Error(err) + return + } + defer res.Body.Close() + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Errorf("Body read: %v", err) + } + addr := strings.TrimSpace(string(slurp)) + if addr == "" { + t.Errorf("didn't get an addr in response") + } + mu.Lock() + dials[addr]++ + mu.Unlock() + }() + } + wg.Wait() + if len(dials) != 1 { + t.Errorf("saw %d dials; want 1: %v", len(dials), dials) + } + tr.CloseIdleConnections() + if err := retry(50, 10*time.Millisecond, func() error { + cp, ok := tr.connPool().(*clientConnPool) + if !ok { + return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool()) + } + cp.mu.Lock() + defer cp.mu.Unlock() + if len(cp.dialing) != 0 { + return fmt.Errorf("dialing map = %v; want empty", cp.dialing) + } + if len(cp.conns) != 0 { + return fmt.Errorf("conns = %v; want empty", cp.conns) + } + if len(cp.keys) != 0 { + return fmt.Errorf("keys = %v; want empty", cp.keys) + } + return nil + }); err != nil { + t.Errorf("State of pool after CloseIdleConnections: %v", err) + } +} + +func retry(tries int, delay time.Duration, fn func() error) error { + var err error + for i := 0; i < tries; i++ { + err = fn() + if err == nil { + return nil + } + time.Sleep(delay) + } + return err +} + +func TestTransportAbortClosesPipes(t *testing.T) { + shutdown := make(chan struct{}) + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + w.(http.Flusher).Flush() + <-shutdown + }, + optOnlyServer, + ) + defer st.Close() + defer close(shutdown) // we must shutdown before st.Close() to avoid hanging + + done := make(chan struct{}) + requestMade := make(chan struct{}) + go func() { + defer close(done) + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + t.Fatal(err) + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + close(requestMade) + _, err = ioutil.ReadAll(res.Body) + if err == nil { + t.Error("expected error from res.Body.Read") + } + }() + + <-requestMade + // Now force the serve loop to end, via closing the connection. + st.closeConn() + // deadlock? that's a bug. + select { + case <-done: + case <-time.After(3 * time.Second): + t.Fatal("timeout") + } +} + +// TODO: merge this with TestTransportBody to make TestTransportRequest? This +// could be a table-driven test with extra goodies. +func TestTransportPath(t *testing.T) { + gotc := make(chan *url.URL, 1) + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + gotc <- r.URL + }, + optOnlyServer, + ) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + const ( + path = "/testpath" + query = "q=1" + ) + surl := st.ts.URL + path + "?" + query + req, err := http.NewRequest("POST", surl, nil) + if err != nil { + t.Fatal(err) + } + c := &http.Client{Transport: tr} + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + got := <-gotc + if got.Path != path { + t.Errorf("Read Path = %q; want %q", got.Path, path) + } + if got.RawQuery != query { + t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query) + } +} + +func randString(n int) string { + rnd := rand.New(rand.NewSource(int64(n))) + b := make([]byte, n) + for i := range b { + b[i] = byte(rnd.Intn(256)) + } + return string(b) +} + +type panicReader struct{} + +func (panicReader) Read([]byte) (int, error) { panic("unexpected Read") } +func (panicReader) Close() error { panic("unexpected Close") } + +func TestActualContentLength(t *testing.T) { + tests := []struct { + req *http.Request + want int64 + }{ + // Verify we don't read from Body: + 0: { + req: &http.Request{Body: panicReader{}}, + want: -1, + }, + // nil Body means 0, regardless of ContentLength: + 1: { + req: &http.Request{Body: nil, ContentLength: 5}, + want: 0, + }, + // ContentLength is used if set. + 2: { + req: &http.Request{Body: panicReader{}, ContentLength: 5}, + want: 5, + }, + // http.NoBody means 0, not -1. + 3: { + req: &http.Request{Body: go18httpNoBody()}, + want: 0, + }, + } + for i, tt := range tests { + got := actualContentLength(tt.req) + if got != tt.want { + t.Errorf("test[%d]: got %d; want %d", i, got, tt.want) + } + } +} + +func TestTransportBody(t *testing.T) { + bodyTests := []struct { + body string + noContentLen bool + }{ + {body: "some message"}, + {body: "some message", noContentLen: true}, + {body: strings.Repeat("a", 1<<20), noContentLen: true}, + {body: strings.Repeat("a", 1<<20)}, + {body: randString(16<<10 - 1)}, + {body: randString(16 << 10)}, + {body: randString(16<<10 + 1)}, + {body: randString(512<<10 - 1)}, + {body: randString(512 << 10)}, + {body: randString(512<<10 + 1)}, + {body: randString(1<<20 - 1)}, + {body: randString(1 << 20)}, + {body: randString(1<<20 + 2)}, + } + + type reqInfo struct { + req *http.Request + slurp []byte + err error + } + gotc := make(chan reqInfo, 1) + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + slurp, err := ioutil.ReadAll(r.Body) + if err != nil { + gotc <- reqInfo{err: err} + } else { + gotc <- reqInfo{req: r, slurp: slurp} + } + }, + optOnlyServer, + ) + defer st.Close() + + for i, tt := range bodyTests { + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + var body io.Reader = strings.NewReader(tt.body) + if tt.noContentLen { + body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods + } + req, err := http.NewRequest("POST", st.ts.URL, body) + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + c := &http.Client{Transport: tr} + res, err := c.Do(req) + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + defer res.Body.Close() + ri := <-gotc + if ri.err != nil { + t.Errorf("#%d: read error: %v", i, ri.err) + continue + } + if got := string(ri.slurp); got != tt.body { + t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body)) + } + wantLen := int64(len(tt.body)) + if tt.noContentLen && tt.body != "" { + wantLen = -1 + } + if ri.req.ContentLength != wantLen { + t.Errorf("#%d. handler got ContentLength = %v; want %v", i, ri.req.ContentLength, wantLen) + } + } +} + +func shortString(v string) string { + const maxLen = 100 + if len(v) <= maxLen { + return v + } + return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:]) +} + +func TestTransportDialTLS(t *testing.T) { + var mu sync.Mutex // guards following + var gotReq, didDial bool + + ts := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + mu.Lock() + gotReq = true + mu.Unlock() + }, + optOnlyServer, + ) + defer ts.Close() + tr := &Transport{ + DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { + mu.Lock() + didDial = true + mu.Unlock() + cfg.InsecureSkipVerify = true + c, err := tls.Dial(netw, addr, cfg) + if err != nil { + return nil, err + } + return c, c.Handshake() + }, + } + defer tr.CloseIdleConnections() + client := &http.Client{Transport: tr} + res, err := client.Get(ts.ts.URL) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + mu.Lock() + if !gotReq { + t.Error("didn't get request") + } + if !didDial { + t.Error("didn't use dial hook") + } +} + +func TestConfigureTransport(t *testing.T) { + t1 := &http.Transport{} + err := ConfigureTransport(t1) + if err == errTransportVersion { + t.Skip(err) + } + if err != nil { + t.Fatal(err) + } + if got := fmt.Sprintf("%#v", t1); !strings.Contains(got, `"h2"`) { + // Laziness, to avoid buildtags. + t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got) + } + wantNextProtos := []string{"h2", "http/1.1"} + if t1.TLSClientConfig == nil { + t.Errorf("nil t1.TLSClientConfig") + } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) { + t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos) + } + if err := ConfigureTransport(t1); err == nil { + t.Error("unexpected success on second call to ConfigureTransport") + } + + // And does it work? + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, r.Proto) + }, optOnlyServer) + defer st.Close() + + t1.TLSClientConfig.InsecureSkipVerify = true + c := &http.Client{Transport: t1} + res, err := c.Get(st.ts.URL) + if err != nil { + t.Fatal(err) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if got, want := string(slurp), "HTTP/2.0"; got != want { + t.Errorf("body = %q; want %q", got, want) + } +} + +type capitalizeReader struct { + r io.Reader +} + +func (cr capitalizeReader) Read(p []byte) (n int, err error) { + n, err = cr.r.Read(p) + for i, b := range p[:n] { + if b >= 'a' && b <= 'z' { + p[i] = b - ('a' - 'A') + } + } + return +} + +type flushWriter struct { + w io.Writer +} + +func (fw flushWriter) Write(p []byte) (n int, err error) { + n, err = fw.w.Write(p) + if f, ok := fw.w.(http.Flusher); ok { + f.Flush() + } + return +} + +type clientTester struct { + t *testing.T + tr *Transport + sc, cc net.Conn // server and client conn + fr *Framer // server's framer + client func() error + server func() error +} + +func newClientTester(t *testing.T) *clientTester { + var dialOnce struct { + sync.Mutex + dialed bool + } + ct := &clientTester{ + t: t, + } + ct.tr = &Transport{ + TLSClientConfig: tlsConfigInsecure, + DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { + dialOnce.Lock() + defer dialOnce.Unlock() + if dialOnce.dialed { + return nil, errors.New("only one dial allowed in test mode") + } + dialOnce.dialed = true + return ct.cc, nil + }, + } + + ln := newLocalListener(t) + cc, err := net.Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + + } + sc, err := ln.Accept() + if err != nil { + t.Fatal(err) + } + ln.Close() + ct.cc = cc + ct.sc = sc + ct.fr = NewFramer(sc, sc) + return ct +} + +func newLocalListener(t *testing.T) net.Listener { + ln, err := net.Listen("tcp4", "127.0.0.1:0") + if err == nil { + return ln + } + ln, err = net.Listen("tcp6", "[::1]:0") + if err != nil { + t.Fatal(err) + } + return ln +} + +func (ct *clientTester) greet(settings ...Setting) { + buf := make([]byte, len(ClientPreface)) + _, err := io.ReadFull(ct.sc, buf) + if err != nil { + ct.t.Fatalf("reading client preface: %v", err) + } + f, err := ct.fr.ReadFrame() + if err != nil { + ct.t.Fatalf("Reading client settings frame: %v", err) + } + if sf, ok := f.(*SettingsFrame); !ok { + ct.t.Fatalf("Wanted client settings frame; got %v", f) + _ = sf // stash it away? + } + if err := ct.fr.WriteSettings(settings...); err != nil { + ct.t.Fatal(err) + } + if err := ct.fr.WriteSettingsAck(); err != nil { + ct.t.Fatal(err) + } +} + +func (ct *clientTester) readNonSettingsFrame() (Frame, error) { + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return nil, err + } + if _, ok := f.(*SettingsFrame); ok { + continue + } + return f, nil + } +} + +func (ct *clientTester) cleanup() { + ct.tr.CloseIdleConnections() +} + +func (ct *clientTester) run() { + errc := make(chan error, 2) + ct.start("client", errc, ct.client) + ct.start("server", errc, ct.server) + defer ct.cleanup() + for i := 0; i < 2; i++ { + if err := <-errc; err != nil { + ct.t.Error(err) + return + } + } +} + +func (ct *clientTester) start(which string, errc chan<- error, fn func() error) { + go func() { + finished := false + var err error + defer func() { + if !finished { + err = fmt.Errorf("%s goroutine didn't finish.", which) + } else if err != nil { + err = fmt.Errorf("%s: %v", which, err) + } + errc <- err + }() + err = fn() + finished = true + }() +} + +func (ct *clientTester) readFrame() (Frame, error) { + return readFrameTimeout(ct.fr, 2*time.Second) +} + +func (ct *clientTester) firstHeaders() (*HeadersFrame, error) { + for { + f, err := ct.readFrame() + if err != nil { + return nil, fmt.Errorf("ReadFrame while waiting for Headers: %v", err) + } + switch f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + continue + } + hf, ok := f.(*HeadersFrame) + if !ok { + return nil, fmt.Errorf("Got %T; want HeadersFrame", f) + } + return hf, nil + } +} + +type countingReader struct { + n *int64 +} + +func (r countingReader) Read(p []byte) (n int, err error) { + for i := range p { + p[i] = byte(i) + } + atomic.AddInt64(r.n, int64(len(p))) + return len(p), err +} + +func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) } +func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) } + +func testTransportReqBodyAfterResponse(t *testing.T, status int) { + const bodySize = 10 << 20 + clientDone := make(chan struct{}) + ct := newClientTester(t) + ct.client = func() error { + defer ct.cc.(*net.TCPConn).CloseWrite() + defer close(clientDone) + + var n int64 // atomic + req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize)) + if err != nil { + return err + } + res, err := ct.tr.RoundTrip(req) + if err != nil { + return fmt.Errorf("RoundTrip: %v", err) + } + defer res.Body.Close() + if res.StatusCode != status { + return fmt.Errorf("status code = %v; want %v", res.StatusCode, status) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("Slurp: %v", err) + } + if len(slurp) > 0 { + return fmt.Errorf("unexpected body: %q", slurp) + } + if status == 200 { + if got := atomic.LoadInt64(&n); got != bodySize { + return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize) + } + } else { + if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize { + return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize) + } + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + var dataRecv int64 + var closed bool + for { + f, err := ct.fr.ReadFrame() + if err != nil { + select { + case <-clientDone: + // If the client's done, it + // will have reported any + // errors on its side. + return nil + default: + return err + } + } + //println(fmt.Sprintf("server got frame: %v", f)) + switch f := f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + case *HeadersFrame: + if !f.HeadersEnded() { + return fmt.Errorf("headers should have END_HEADERS be ended: %v", f) + } + if f.StreamEnded() { + return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f) + } + case *DataFrame: + dataLen := len(f.Data()) + if dataLen > 0 { + if dataRecv == 0 { + enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + } + if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil { + return err + } + if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil { + return err + } + } + dataRecv += int64(dataLen) + + if !closed && ((status != 200 && dataRecv > 0) || + (status == 200 && dataRecv == bodySize)) { + closed = true + if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil { + return err + } + } + default: + return fmt.Errorf("Unexpected client frame %v", f) + } + } + } + ct.run() +} + +// See golang.org/issue/13444 +func TestTransportFullDuplex(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) // redundant but for clarity + w.(http.Flusher).Flush() + io.Copy(flushWriter{w}, capitalizeReader{r.Body}) + fmt.Fprintf(w, "bye.\n") + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + + pr, pw := io.Pipe() + req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr)) + if err != nil { + t.Fatal(err) + } + req.ContentLength = -1 + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if res.StatusCode != 200 { + t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200) + } + bs := bufio.NewScanner(res.Body) + want := func(v string) { + if !bs.Scan() { + t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err()) + } + } + write := func(v string) { + _, err := io.WriteString(pw, v) + if err != nil { + t.Fatalf("pipe write: %v", err) + } + } + write("foo\n") + want("FOO") + write("bar\n") + want("BAR") + pw.Close() + want("bye.") + if err := bs.Err(); err != nil { + t.Fatal(err) + } +} + +func TestTransportConnectRequest(t *testing.T) { + gotc := make(chan *http.Request, 1) + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + gotc <- r + }, optOnlyServer) + defer st.Close() + + u, err := url.Parse(st.ts.URL) + if err != nil { + t.Fatal(err) + } + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + + tests := []struct { + req *http.Request + want string + }{ + { + req: &http.Request{ + Method: "CONNECT", + Header: http.Header{}, + URL: u, + }, + want: u.Host, + }, + { + req: &http.Request{ + Method: "CONNECT", + Header: http.Header{}, + URL: u, + Host: "example.com:123", + }, + want: "example.com:123", + }, + } + + for i, tt := range tests { + res, err := c.Do(tt.req) + if err != nil { + t.Errorf("%d. RoundTrip = %v", i, err) + continue + } + res.Body.Close() + req := <-gotc + if req.Method != "CONNECT" { + t.Errorf("method = %q; want CONNECT", req.Method) + } + if req.Host != tt.want { + t.Errorf("Host = %q; want %q", req.Host, tt.want) + } + if req.URL.Host != tt.want { + t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want) + } + } +} + +type headerType int + +const ( + noHeader headerType = iota // omitted + oneHeader + splitHeader // broken into continuation on purpose +) + +const ( + f0 = noHeader + f1 = oneHeader + f2 = splitHeader + d0 = false + d1 = true +) + +// Test all 36 combinations of response frame orders: +// (3 ways of 100-continue) * (2 ways of headers) * (2 ways of data) * (3 ways of trailers):func TestTransportResponsePattern_00f0(t *testing.T) { testTransportResponsePattern(h0, h1, false, h0) } +// Generated by http://play.golang.org/p/SScqYKJYXd +func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) } +func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) } +func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) } +func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) } +func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) } +func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) } +func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) } +func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) } +func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) } +func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) } +func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) } +func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) } +func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) } +func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) } +func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) } +func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) } +func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) } +func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) } +func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) } +func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) } +func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) } +func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) } +func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) } +func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) } +func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) } +func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) } +func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) } +func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) } +func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) } +func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) } +func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) } +func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) } +func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) } +func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) } +func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) } +func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) } + +func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) { + const reqBody = "some request body" + const resBody = "some response body" + + if resHeader == noHeader { + // TODO: test 100-continue followed by immediate + // server stream reset, without headers in the middle? + panic("invalid combination") + } + + ct := newClientTester(t) + ct.client = func() error { + req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody)) + if expect100Continue != noHeader { + req.Header.Set("Expect", "100-continue") + } + res, err := ct.tr.RoundTrip(req) + if err != nil { + return fmt.Errorf("RoundTrip: %v", err) + } + defer res.Body.Close() + if res.StatusCode != 200 { + return fmt.Errorf("status code = %v; want 200", res.StatusCode) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("Slurp: %v", err) + } + wantBody := resBody + if !withData { + wantBody = "" + } + if string(slurp) != wantBody { + return fmt.Errorf("body = %q; want %q", slurp, wantBody) + } + if trailers == noHeader { + if len(res.Trailer) > 0 { + t.Errorf("Trailer = %v; want none", res.Trailer) + } + } else { + want := http.Header{"Some-Trailer": {"some-value"}} + if !reflect.DeepEqual(res.Trailer, want) { + t.Errorf("Trailer = %v; want %v", res.Trailer, want) + } + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return err + } + endStream := false + send := func(mode headerType) { + hbf := buf.Bytes() + switch mode { + case oneHeader: + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.Header().StreamID, + EndHeaders: true, + EndStream: endStream, + BlockFragment: hbf, + }) + case splitHeader: + if len(hbf) < 2 { + panic("too small") + } + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.Header().StreamID, + EndHeaders: false, + EndStream: endStream, + BlockFragment: hbf[:1], + }) + ct.fr.WriteContinuation(f.Header().StreamID, true, hbf[1:]) + default: + panic("bogus mode") + } + } + switch f := f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + case *DataFrame: + if !f.StreamEnded() { + // No need to send flow control tokens. The test request body is tiny. + continue + } + // Response headers (1+ frames; 1 or 2 in this test, but never 0) + { + buf.Reset() + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "x-foo", Value: "blah"}) + enc.WriteField(hpack.HeaderField{Name: "x-bar", Value: "more"}) + if trailers != noHeader { + enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "some-trailer"}) + } + endStream = withData == false && trailers == noHeader + send(resHeader) + } + if withData { + endStream = trailers == noHeader + ct.fr.WriteData(f.StreamID, endStream, []byte(resBody)) + } + if trailers != noHeader { + endStream = true + buf.Reset() + enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"}) + send(trailers) + } + if endStream { + return nil + } + case *HeadersFrame: + if expect100Continue != noHeader { + buf.Reset() + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"}) + send(expect100Continue) + } + } + } + } + ct.run() +} + +func TestTransportReceiveUndeclaredTrailer(t *testing.T) { + ct := newClientTester(t) + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return fmt.Errorf("RoundTrip: %v", err) + } + defer res.Body.Close() + if res.StatusCode != 200 { + return fmt.Errorf("status code = %v; want 200", res.StatusCode) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, nil) + } + if len(slurp) > 0 { + return fmt.Errorf("body = %q; want nothing", slurp) + } + if _, ok := res.Trailer["Some-Trailer"]; !ok { + return fmt.Errorf("expected Some-Trailer") + } + return nil + } + ct.server = func() error { + ct.greet() + + var n int + var hf *HeadersFrame + for hf == nil && n < 10 { + f, err := ct.fr.ReadFrame() + if err != nil { + return err + } + hf, _ = f.(*HeadersFrame) + n++ + } + + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + + // send headers without Trailer header + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + + // send trailers + buf.Reset() + enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "I'm an undeclared Trailer!"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: true, + BlockFragment: buf.Bytes(), + }) + return nil + } + ct.run() +} + +func TestTransportInvalidTrailer_Pseudo1(t *testing.T) { + testTransportInvalidTrailer_Pseudo(t, oneHeader) +} +func TestTransportInvalidTrailer_Pseudo2(t *testing.T) { + testTransportInvalidTrailer_Pseudo(t, splitHeader) +} +func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) { + testInvalidTrailer(t, trailers, pseudoHeaderError(":colon"), func(enc *hpack.Encoder) { + enc.WriteField(hpack.HeaderField{Name: ":colon", Value: "foo"}) + enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"}) + }) +} + +func TestTransportInvalidTrailer_Capital1(t *testing.T) { + testTransportInvalidTrailer_Capital(t, oneHeader) +} +func TestTransportInvalidTrailer_Capital2(t *testing.T) { + testTransportInvalidTrailer_Capital(t, splitHeader) +} +func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) { + testInvalidTrailer(t, trailers, headerFieldNameError("Capital"), func(enc *hpack.Encoder) { + enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"}) + enc.WriteField(hpack.HeaderField{Name: "Capital", Value: "bad"}) + }) +} +func TestTransportInvalidTrailer_EmptyFieldName(t *testing.T) { + testInvalidTrailer(t, oneHeader, headerFieldNameError(""), func(enc *hpack.Encoder) { + enc.WriteField(hpack.HeaderField{Name: "", Value: "bad"}) + }) +} +func TestTransportInvalidTrailer_BinaryFieldValue(t *testing.T) { + testInvalidTrailer(t, oneHeader, headerFieldValueError("has\nnewline"), func(enc *hpack.Encoder) { + enc.WriteField(hpack.HeaderField{Name: "x", Value: "has\nnewline"}) + }) +} + +func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeTrailer func(*hpack.Encoder)) { + ct := newClientTester(t) + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return fmt.Errorf("RoundTrip: %v", err) + } + defer res.Body.Close() + if res.StatusCode != 200 { + return fmt.Errorf("status code = %v; want 200", res.StatusCode) + } + slurp, err := ioutil.ReadAll(res.Body) + se, ok := err.(StreamError) + if !ok || se.Cause != wantErr { + return fmt.Errorf("res.Body ReadAll error = %q, %#v; want StreamError with cause %T, %#v", slurp, err, wantErr, wantErr) + } + if len(slurp) > 0 { + return fmt.Errorf("body = %q; want nothing", slurp) + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return err + } + switch f := f.(type) { + case *HeadersFrame: + var endStream bool + send := func(mode headerType) { + hbf := buf.Bytes() + switch mode { + case oneHeader: + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: endStream, + BlockFragment: hbf, + }) + case splitHeader: + if len(hbf) < 2 { + panic("too small") + } + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: false, + EndStream: endStream, + BlockFragment: hbf[:1], + }) + ct.fr.WriteContinuation(f.StreamID, true, hbf[1:]) + default: + panic("bogus mode") + } + } + // Response headers (1+ frames; 1 or 2 in this test, but never 0) + { + buf.Reset() + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "declared"}) + endStream = false + send(oneHeader) + } + // Trailers: + { + endStream = true + buf.Reset() + writeTrailer(enc) + send(trailers) + } + return nil + } + } + } + ct.run() +} + +// headerListSize returns the HTTP2 header list size of h. +// http://httpwg.org/specs/rfc7540.html#SETTINGS_MAX_HEADER_LIST_SIZE +// http://httpwg.org/specs/rfc7540.html#MaxHeaderBlock +func headerListSize(h http.Header) (size uint32) { + for k, vv := range h { + for _, v := range vv { + hf := hpack.HeaderField{Name: k, Value: v} + size += hf.Size() + } + } + return size +} + +// padHeaders adds data to an http.Header until headerListSize(h) == +// limit. Due to the way header list sizes are calculated, padHeaders +// cannot add fewer than len("Pad-Headers") + 32 bytes to h, and will +// call t.Fatal if asked to do so. PadHeaders first reserves enough +// space for an empty "Pad-Headers" key, then adds as many copies of +// filler as possible. Any remaining bytes necessary to push the +// header list size up to limit are added to h["Pad-Headers"]. +func padHeaders(t *testing.T, h http.Header, limit uint64, filler string) { + if limit > 0xffffffff { + t.Fatalf("padHeaders: refusing to pad to more than 2^32-1 bytes. limit = %v", limit) + } + hf := hpack.HeaderField{Name: "Pad-Headers", Value: ""} + minPadding := uint64(hf.Size()) + size := uint64(headerListSize(h)) + + minlimit := size + minPadding + if limit < minlimit { + t.Fatalf("padHeaders: limit %v < %v", limit, minlimit) + } + + // Use a fixed-width format for name so that fieldSize + // remains constant. + nameFmt := "Pad-Headers-%06d" + hf = hpack.HeaderField{Name: fmt.Sprintf(nameFmt, 1), Value: filler} + fieldSize := uint64(hf.Size()) + + // Add as many complete filler values as possible, leaving + // room for at least one empty "Pad-Headers" key. + limit = limit - minPadding + for i := 0; size+fieldSize < limit; i++ { + name := fmt.Sprintf(nameFmt, i) + h.Add(name, filler) + size += fieldSize + } + + // Add enough bytes to reach limit. + remain := limit - size + lastValue := strings.Repeat("*", int(remain)) + h.Add("Pad-Headers", lastValue) +} + +func TestPadHeaders(t *testing.T) { + check := func(h http.Header, limit uint32, fillerLen int) { + if h == nil { + h = make(http.Header) + } + filler := strings.Repeat("f", fillerLen) + padHeaders(t, h, uint64(limit), filler) + gotSize := headerListSize(h) + if gotSize != limit { + t.Errorf("Got size = %v; want %v", gotSize, limit) + } + } + // Try all possible combinations for small fillerLen and limit. + hf := hpack.HeaderField{Name: "Pad-Headers", Value: ""} + minLimit := hf.Size() + for limit := minLimit; limit <= 128; limit++ { + for fillerLen := 0; uint32(fillerLen) <= limit; fillerLen++ { + check(nil, limit, fillerLen) + } + } + + // Try a few tests with larger limits, plus cumulative + // tests. Since these tests are cumulative, tests[i+1].limit + // must be >= tests[i].limit + minLimit. See the comment on + // padHeaders for more info on why the limit arg has this + // restriction. + tests := []struct { + fillerLen int + limit uint32 + }{ + { + fillerLen: 64, + limit: 1024, + }, + { + fillerLen: 1024, + limit: 1286, + }, + { + fillerLen: 256, + limit: 2048, + }, + { + fillerLen: 1024, + limit: 10 * 1024, + }, + { + fillerLen: 1023, + limit: 11 * 1024, + }, + } + h := make(http.Header) + for _, tc := range tests { + check(nil, tc.limit, tc.fillerLen) + check(h, tc.limit, tc.fillerLen) + } +} + +func TestTransportChecksRequestHeaderListSize(t *testing.T) { + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + // Consume body & force client to send + // trailers before writing response. + // ioutil.ReadAll returns non-nil err for + // requests that attempt to send greater than + // maxHeaderListSize bytes of trailers, since + // those requests generate a stream reset. + ioutil.ReadAll(r.Body) + r.Body.Close() + }, + func(ts *httptest.Server) { + ts.Config.MaxHeaderBytes = 16 << 10 + }, + optOnlyServer, + optQuiet, + ) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + checkRoundTrip := func(req *http.Request, wantErr error, desc string) { + res, err := tr.RoundTrip(req) + if err != wantErr { + if res != nil { + res.Body.Close() + } + t.Errorf("%v: RoundTrip err = %v; want %v", desc, err, wantErr) + return + } + if err == nil { + if res == nil { + t.Errorf("%v: response nil; want non-nil.", desc) + return + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + t.Errorf("%v: response status = %v; want %v", desc, res.StatusCode, http.StatusOK) + } + return + } + if res != nil { + t.Errorf("%v: RoundTrip err = %v but response non-nil", desc, err) + } + } + headerListSizeForRequest := func(req *http.Request) (size uint64) { + contentLen := actualContentLength(req) + trailers, err := commaSeparatedTrailers(req) + if err != nil { + t.Fatalf("headerListSizeForRequest: %v", err) + } + cc := &ClientConn{peerMaxHeaderListSize: 0xffffffffffffffff} + cc.henc = hpack.NewEncoder(&cc.hbuf) + cc.mu.Lock() + hdrs, err := cc.encodeHeaders(req, true, trailers, contentLen) + cc.mu.Unlock() + if err != nil { + t.Fatalf("headerListSizeForRequest: %v", err) + } + hpackDec := hpack.NewDecoder(initialHeaderTableSize, func(hf hpack.HeaderField) { + size += uint64(hf.Size()) + }) + if len(hdrs) > 0 { + if _, err := hpackDec.Write(hdrs); err != nil { + t.Fatalf("headerListSizeForRequest: %v", err) + } + } + return size + } + // Create a new Request for each test, rather than reusing the + // same Request, to avoid a race when modifying req.Headers. + // See https://github.com/golang/go/issues/21316 + newRequest := func() *http.Request { + // Body must be non-nil to enable writing trailers. + body := strings.NewReader("hello") + req, err := http.NewRequest("POST", st.ts.URL, body) + if err != nil { + t.Fatalf("newRequest: NewRequest: %v", err) + } + return req + } + + // Make an arbitrary request to ensure we get the server's + // settings frame and initialize peerMaxHeaderListSize. + req := newRequest() + checkRoundTrip(req, nil, "Initial request") + + // Get the ClientConn associated with the request and validate + // peerMaxHeaderListSize. + addr := authorityAddr(req.URL.Scheme, req.URL.Host) + cc, err := tr.connPool().GetClientConn(req, addr) + if err != nil { + t.Fatalf("GetClientConn: %v", err) + } + cc.mu.Lock() + peerSize := cc.peerMaxHeaderListSize + cc.mu.Unlock() + st.scMu.Lock() + wantSize := uint64(st.sc.maxHeaderListSize()) + st.scMu.Unlock() + if peerSize != wantSize { + t.Errorf("peerMaxHeaderListSize = %v; want %v", peerSize, wantSize) + } + + // Sanity check peerSize. (*serverConn) maxHeaderListSize adds + // 320 bytes of padding. + wantHeaderBytes := uint64(st.ts.Config.MaxHeaderBytes) + 320 + if peerSize != wantHeaderBytes { + t.Errorf("peerMaxHeaderListSize = %v; want %v.", peerSize, wantHeaderBytes) + } + + // Pad headers & trailers, but stay under peerSize. + req = newRequest() + req.Header = make(http.Header) + req.Trailer = make(http.Header) + filler := strings.Repeat("*", 1024) + padHeaders(t, req.Trailer, peerSize, filler) + // cc.encodeHeaders adds some default headers to the request, + // so we need to leave room for those. + defaultBytes := headerListSizeForRequest(req) + padHeaders(t, req.Header, peerSize-defaultBytes, filler) + checkRoundTrip(req, nil, "Headers & Trailers under limit") + + // Add enough header bytes to push us over peerSize. + req = newRequest() + req.Header = make(http.Header) + padHeaders(t, req.Header, peerSize, filler) + checkRoundTrip(req, errRequestHeaderListSize, "Headers over limit") + + // Push trailers over the limit. + req = newRequest() + req.Trailer = make(http.Header) + padHeaders(t, req.Trailer, peerSize+1, filler) + checkRoundTrip(req, errRequestHeaderListSize, "Trailers over limit") + + // Send headers with a single large value. + req = newRequest() + filler = strings.Repeat("*", int(peerSize)) + req.Header = make(http.Header) + req.Header.Set("Big", filler) + checkRoundTrip(req, errRequestHeaderListSize, "Single large header") + + // Send trailers with a single large value. + req = newRequest() + req.Trailer = make(http.Header) + req.Trailer.Set("Big", filler) + checkRoundTrip(req, errRequestHeaderListSize, "Single large trailer") +} + +func TestTransportChecksResponseHeaderListSize(t *testing.T) { + ct := newClientTester(t) + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != errResponseHeaderListSize { + if res != nil { + res.Body.Close() + } + size := int64(0) + for k, vv := range res.Header { + for _, v := range vv { + size += int64(len(k)) + int64(len(v)) + 32 + } + } + return fmt.Errorf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size) + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return err + } + switch f := f.(type) { + case *HeadersFrame: + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + large := strings.Repeat("a", 1<<10) + for i := 0; i < 5042; i++ { + enc.WriteField(hpack.HeaderField{Name: large, Value: large}) + } + if size, want := buf.Len(), 6329; size != want { + // Note: this number might change if + // our hpack implementation + // changes. That's fine. This is + // just a sanity check that our + // response can fit in a single + // header block fragment frame. + return fmt.Errorf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want) + } + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: true, + BlockFragment: buf.Bytes(), + }) + return nil + } + } + } + ct.run() +} + +// Test that the Transport returns a typed error from Response.Body.Read calls +// when the server sends an error. (here we use a panic, since that should generate +// a stream error, but others like cancel should be similar) +func TestTransportBodyReadErrorType(t *testing.T) { + doPanic := make(chan bool, 1) + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + w.(http.Flusher).Flush() // force headers out + <-doPanic + panic("boom") + }, + optOnlyServer, + optQuiet, + ) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + + res, err := c.Get(st.ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + doPanic <- true + buf := make([]byte, 100) + n, err := res.Body.Read(buf) + want := StreamError{StreamID: 0x1, Code: 0x2} + if !reflect.DeepEqual(want, err) { + t.Errorf("Read = %v, %#v; want error %#v", n, err, want) + } +} + +// golang.org/issue/13924 +// This used to fail after many iterations, especially with -race: +// go test -v -run=TestTransportDoubleCloseOnWriteError -count=500 -race +func TestTransportDoubleCloseOnWriteError(t *testing.T) { + var ( + mu sync.Mutex + conn net.Conn // to close if set + ) + + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + mu.Lock() + defer mu.Unlock() + if conn != nil { + conn.Close() + } + }, + optOnlyServer, + ) + defer st.Close() + + tr := &Transport{ + TLSClientConfig: tlsConfigInsecure, + DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { + tc, err := tls.Dial(network, addr, cfg) + if err != nil { + return nil, err + } + mu.Lock() + defer mu.Unlock() + conn = tc + return tc, nil + }, + } + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + c.Get(st.ts.URL) +} + +// Test that the http1 Transport.DisableKeepAlives option is respected +// and connections are closed as soon as idle. +// See golang.org/issue/14008 +func TestTransportDisableKeepAlives(t *testing.T) { + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, "hi") + }, + optOnlyServer, + ) + defer st.Close() + + connClosed := make(chan struct{}) // closed on tls.Conn.Close + tr := &Transport{ + t1: &http.Transport{ + DisableKeepAlives: true, + }, + TLSClientConfig: tlsConfigInsecure, + DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { + tc, err := tls.Dial(network, addr, cfg) + if err != nil { + return nil, err + } + return &noteCloseConn{Conn: tc, closefn: func() { close(connClosed) }}, nil + }, + } + c := &http.Client{Transport: tr} + res, err := c.Get(st.ts.URL) + if err != nil { + t.Fatal(err) + } + if _, err := ioutil.ReadAll(res.Body); err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + select { + case <-connClosed: + case <-time.After(1 * time.Second): + t.Errorf("timeout") + } + +} + +// Test concurrent requests with Transport.DisableKeepAlives. We can share connections, +// but when things are totally idle, it still needs to close. +func TestTransportDisableKeepAlives_Concurrency(t *testing.T) { + const D = 25 * time.Millisecond + st := newServerTester(t, + func(w http.ResponseWriter, r *http.Request) { + time.Sleep(D) + io.WriteString(w, "hi") + }, + optOnlyServer, + ) + defer st.Close() + + var dials int32 + var conns sync.WaitGroup + tr := &Transport{ + t1: &http.Transport{ + DisableKeepAlives: true, + }, + TLSClientConfig: tlsConfigInsecure, + DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { + tc, err := tls.Dial(network, addr, cfg) + if err != nil { + return nil, err + } + atomic.AddInt32(&dials, 1) + conns.Add(1) + return &noteCloseConn{Conn: tc, closefn: func() { conns.Done() }}, nil + }, + } + c := &http.Client{Transport: tr} + var reqs sync.WaitGroup + const N = 20 + for i := 0; i < N; i++ { + reqs.Add(1) + if i == N-1 { + // For the final request, try to make all the + // others close. This isn't verified in the + // count, other than the Log statement, since + // it's so timing dependent. This test is + // really to make sure we don't interrupt a + // valid request. + time.Sleep(D * 2) + } + go func() { + defer reqs.Done() + res, err := c.Get(st.ts.URL) + if err != nil { + t.Error(err) + return + } + if _, err := ioutil.ReadAll(res.Body); err != nil { + t.Error(err) + return + } + res.Body.Close() + }() + } + reqs.Wait() + conns.Wait() + t.Logf("did %d dials, %d requests", atomic.LoadInt32(&dials), N) +} + +type noteCloseConn struct { + net.Conn + onceClose sync.Once + closefn func() +} + +func (c *noteCloseConn) Close() error { + c.onceClose.Do(c.closefn) + return c.Conn.Close() +} + +func isTimeout(err error) bool { + switch err := err.(type) { + case nil: + return false + case *url.Error: + return isTimeout(err.Err) + case net.Error: + return err.Timeout() + } + return false +} + +// Test that the http1 Transport.ResponseHeaderTimeout option and cancel is sent. +func TestTransportResponseHeaderTimeout_NoBody(t *testing.T) { + testTransportResponseHeaderTimeout(t, false) +} +func TestTransportResponseHeaderTimeout_Body(t *testing.T) { + testTransportResponseHeaderTimeout(t, true) +} + +func testTransportResponseHeaderTimeout(t *testing.T, body bool) { + ct := newClientTester(t) + ct.tr.t1 = &http.Transport{ + ResponseHeaderTimeout: 5 * time.Millisecond, + } + ct.client = func() error { + c := &http.Client{Transport: ct.tr} + var err error + var n int64 + const bodySize = 4 << 20 + if body { + _, err = c.Post("https://dummy.tld/", "text/foo", io.LimitReader(countingReader{&n}, bodySize)) + } else { + _, err = c.Get("https://dummy.tld/") + } + if !isTimeout(err) { + t.Errorf("client expected timeout error; got %#v", err) + } + if body && n != bodySize { + t.Errorf("only read %d bytes of body; want %d", n, bodySize) + } + return nil + } + ct.server = func() error { + ct.greet() + for { + f, err := ct.fr.ReadFrame() + if err != nil { + t.Logf("ReadFrame: %v", err) + return nil + } + switch f := f.(type) { + case *DataFrame: + dataLen := len(f.Data()) + if dataLen > 0 { + if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil { + return err + } + if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil { + return err + } + } + case *RSTStreamFrame: + if f.StreamID == 1 && f.ErrCode == ErrCodeCancel { + return nil + } + } + } + } + ct.run() +} + +func TestTransportDisableCompression(t *testing.T) { + const body = "sup" + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + want := http.Header{ + "User-Agent": []string{"Go-http-client/2.0"}, + } + if !reflect.DeepEqual(r.Header, want) { + t.Errorf("request headers = %v; want %v", r.Header, want) + } + }, optOnlyServer) + defer st.Close() + + tr := &Transport{ + TLSClientConfig: tlsConfigInsecure, + t1: &http.Transport{ + DisableCompression: true, + }, + } + defer tr.CloseIdleConnections() + + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + t.Fatal(err) + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() +} + +// RFC 7540 section 8.1.2.2 +func TestTransportRejectsConnHeaders(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + var got []string + for k := range r.Header { + got = append(got, k) + } + sort.Strings(got) + w.Header().Set("Got-Header", strings.Join(got, ",")) + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + tests := []struct { + key string + value []string + want string + }{ + { + key: "Upgrade", + value: []string{"anything"}, + want: "ERROR: http2: invalid Upgrade request header: [\"anything\"]", + }, + { + key: "Connection", + value: []string{"foo"}, + want: "ERROR: http2: invalid Connection request header: [\"foo\"]", + }, + { + key: "Connection", + value: []string{"close"}, + want: "Accept-Encoding,User-Agent", + }, + { + key: "Connection", + value: []string{"close", "something-else"}, + want: "ERROR: http2: invalid Connection request header: [\"close\" \"something-else\"]", + }, + { + key: "Connection", + value: []string{"keep-alive"}, + want: "Accept-Encoding,User-Agent", + }, + { + key: "Proxy-Connection", // just deleted and ignored + value: []string{"keep-alive"}, + want: "Accept-Encoding,User-Agent", + }, + { + key: "Transfer-Encoding", + value: []string{""}, + want: "Accept-Encoding,User-Agent", + }, + { + key: "Transfer-Encoding", + value: []string{"foo"}, + want: "ERROR: http2: invalid Transfer-Encoding request header: [\"foo\"]", + }, + { + key: "Transfer-Encoding", + value: []string{"chunked"}, + want: "Accept-Encoding,User-Agent", + }, + { + key: "Transfer-Encoding", + value: []string{"chunked", "other"}, + want: "ERROR: http2: invalid Transfer-Encoding request header: [\"chunked\" \"other\"]", + }, + { + key: "Content-Length", + value: []string{"123"}, + want: "Accept-Encoding,User-Agent", + }, + { + key: "Keep-Alive", + value: []string{"doop"}, + want: "Accept-Encoding,User-Agent", + }, + } + + for _, tt := range tests { + req, _ := http.NewRequest("GET", st.ts.URL, nil) + req.Header[tt.key] = tt.value + res, err := tr.RoundTrip(req) + var got string + if err != nil { + got = fmt.Sprintf("ERROR: %v", err) + } else { + got = res.Header.Get("Got-Header") + res.Body.Close() + } + if got != tt.want { + t.Errorf("For key %q, value %q, got = %q; want %q", tt.key, tt.value, got, tt.want) + } + } +} + +// golang.org/issue/14048 +func TestTransportFailsOnInvalidHeaders(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + var got []string + for k := range r.Header { + got = append(got, k) + } + sort.Strings(got) + w.Header().Set("Got-Header", strings.Join(got, ",")) + }, optOnlyServer) + defer st.Close() + + tests := [...]struct { + h http.Header + wantErr string + }{ + 0: { + h: http.Header{"with space": {"foo"}}, + wantErr: `invalid HTTP header name "with space"`, + }, + 1: { + h: http.Header{"name": {"Брэд"}}, + wantErr: "", // okay + }, + 2: { + h: http.Header{"имя": {"Brad"}}, + wantErr: `invalid HTTP header name "имя"`, + }, + 3: { + h: http.Header{"foo": {"foo\x01bar"}}, + wantErr: `invalid HTTP header value "foo\x01bar" for header "foo"`, + }, + } + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + for i, tt := range tests { + req, _ := http.NewRequest("GET", st.ts.URL, nil) + req.Header = tt.h + res, err := tr.RoundTrip(req) + var bad bool + if tt.wantErr == "" { + if err != nil { + bad = true + t.Errorf("case %d: error = %v; want no error", i, err) + } + } else { + if !strings.Contains(fmt.Sprint(err), tt.wantErr) { + bad = true + t.Errorf("case %d: error = %v; want error %q", i, err, tt.wantErr) + } + } + if err == nil { + if bad { + t.Logf("case %d: server got headers %q", i, res.Header.Get("Got-Header")) + } + res.Body.Close() + } + } +} + +// Tests that gzipReader doesn't crash on a second Read call following +// the first Read call's gzip.NewReader returning an error. +func TestGzipReader_DoubleReadCrash(t *testing.T) { + gz := &gzipReader{ + body: ioutil.NopCloser(strings.NewReader("0123456789")), + } + var buf [1]byte + n, err1 := gz.Read(buf[:]) + if n != 0 || !strings.Contains(fmt.Sprint(err1), "invalid header") { + t.Fatalf("Read = %v, %v; want 0, invalid header", n, err1) + } + n, err2 := gz.Read(buf[:]) + if n != 0 || err2 != err1 { + t.Fatalf("second Read = %v, %v; want 0, %v", n, err2, err1) + } +} + +func TestTransportNewTLSConfig(t *testing.T) { + tests := [...]struct { + conf *tls.Config + host string + want *tls.Config + }{ + // Normal case. + 0: { + conf: nil, + host: "foo.com", + want: &tls.Config{ + ServerName: "foo.com", + NextProtos: []string{NextProtoTLS}, + }, + }, + + // User-provided name (bar.com) takes precedence: + 1: { + conf: &tls.Config{ + ServerName: "bar.com", + }, + host: "foo.com", + want: &tls.Config{ + ServerName: "bar.com", + NextProtos: []string{NextProtoTLS}, + }, + }, + + // NextProto is prepended: + 2: { + conf: &tls.Config{ + NextProtos: []string{"foo", "bar"}, + }, + host: "example.com", + want: &tls.Config{ + ServerName: "example.com", + NextProtos: []string{NextProtoTLS, "foo", "bar"}, + }, + }, + + // NextProto is not duplicated: + 3: { + conf: &tls.Config{ + NextProtos: []string{"foo", "bar", NextProtoTLS}, + }, + host: "example.com", + want: &tls.Config{ + ServerName: "example.com", + NextProtos: []string{"foo", "bar", NextProtoTLS}, + }, + }, + } + for i, tt := range tests { + // Ignore the session ticket keys part, which ends up populating + // unexported fields in the Config: + if tt.conf != nil { + tt.conf.SessionTicketsDisabled = true + } + + tr := &Transport{TLSClientConfig: tt.conf} + got := tr.newTLSConfig(tt.host) + + got.SessionTicketsDisabled = false + + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%d. got %#v; want %#v", i, got, tt.want) + } + } +} + +// The Google GFE responds to HEAD requests with a HEADERS frame +// without END_STREAM, followed by a 0-length DATA frame with +// END_STREAM. Make sure we don't get confused by that. (We did.) +func TestTransportReadHeadResponse(t *testing.T) { + ct := newClientTester(t) + clientDone := make(chan struct{}) + ct.client = func() error { + defer close(clientDone) + req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return err + } + if res.ContentLength != 123 { + return fmt.Errorf("Content-Length = %d; want 123", res.ContentLength) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("ReadAll: %v", err) + } + if len(slurp) > 0 { + return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp) + } + return nil + } + ct.server = func() error { + ct.greet() + for { + f, err := ct.fr.ReadFrame() + if err != nil { + t.Logf("ReadFrame: %v", err) + return nil + } + hf, ok := f.(*HeadersFrame) + if !ok { + continue + } + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, // as the GFE does + BlockFragment: buf.Bytes(), + }) + ct.fr.WriteData(hf.StreamID, true, nil) + + <-clientDone + return nil + } + } + ct.run() +} + +func TestTransportReadHeadResponseWithBody(t *testing.T) { + // This test use not valid response format. + // Discarding logger output to not spam tests output. + log.SetOutput(ioutil.Discard) + defer log.SetOutput(os.Stderr) + + response := "redirecting to /elsewhere" + ct := newClientTester(t) + clientDone := make(chan struct{}) + ct.client = func() error { + defer close(clientDone) + req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return err + } + if res.ContentLength != int64(len(response)) { + return fmt.Errorf("Content-Length = %d; want %d", res.ContentLength, len(response)) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("ReadAll: %v", err) + } + if len(slurp) > 0 { + return fmt.Errorf("Unexpected non-empty ReadAll body: %q", slurp) + } + return nil + } + ct.server = func() error { + ct.greet() + for { + f, err := ct.fr.ReadFrame() + if err != nil { + t.Logf("ReadFrame: %v", err) + return nil + } + hf, ok := f.(*HeadersFrame) + if !ok { + continue + } + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "content-length", Value: strconv.Itoa(len(response))}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + ct.fr.WriteData(hf.StreamID, true, []byte(response)) + + <-clientDone + return nil + } + } + ct.run() +} + +type neverEnding byte + +func (b neverEnding) Read(p []byte) (int, error) { + for i := range p { + p[i] = byte(b) + } + return len(p), nil +} + +// golang.org/issue/15425: test that a handler closing the request +// body doesn't terminate the stream to the peer. (It just stops +// readability from the handler's side, and eventually the client +// runs out of flow control tokens) +func TestTransportHandlerBodyClose(t *testing.T) { + const bodySize = 10 << 20 + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + r.Body.Close() + io.Copy(w, io.LimitReader(neverEnding('A'), bodySize)) + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + g0 := runtime.NumGoroutine() + + const numReq = 10 + for i := 0; i < numReq; i++ { + req, err := http.NewRequest("POST", st.ts.URL, struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)}) + if err != nil { + t.Fatal(err) + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + n, err := io.Copy(ioutil.Discard, res.Body) + res.Body.Close() + if n != bodySize || err != nil { + t.Fatalf("req#%d: Copy = %d, %v; want %d, nil", i, n, err, bodySize) + } + } + tr.CloseIdleConnections() + + gd := runtime.NumGoroutine() - g0 + if gd > numReq/2 { + t.Errorf("appeared to leak goroutines") + } + +} + +// https://golang.org/issue/15930 +func TestTransportFlowControl(t *testing.T) { + const bufLen = 64 << 10 + var total int64 = 100 << 20 // 100MB + if testing.Short() { + total = 10 << 20 + } + + var wrote int64 // updated atomically + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + b := make([]byte, bufLen) + for wrote < total { + n, err := w.Write(b) + atomic.AddInt64(&wrote, int64(n)) + if err != nil { + t.Errorf("ResponseWriter.Write error: %v", err) + break + } + w.(http.Flusher).Flush() + } + }, optOnlyServer) + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + t.Fatal("NewRequest error:", err) + } + resp, err := tr.RoundTrip(req) + if err != nil { + t.Fatal("RoundTrip error:", err) + } + defer resp.Body.Close() + + var read int64 + b := make([]byte, bufLen) + for { + n, err := resp.Body.Read(b) + if err == io.EOF { + break + } + if err != nil { + t.Fatal("Read error:", err) + } + read += int64(n) + + const max = transportDefaultStreamFlow + if w := atomic.LoadInt64(&wrote); -max > read-w || read-w > max { + t.Fatalf("Too much data inflight: server wrote %v bytes but client only received %v", w, read) + } + + // Let the server get ahead of the client. + time.Sleep(1 * time.Millisecond) + } +} + +// golang.org/issue/14627 -- if the server sends a GOAWAY frame, make +// the Transport remember it and return it back to users (via +// RoundTrip or request body reads) if needed (e.g. if the server +// proceeds to close the TCP connection before the client gets its +// response) +func TestTransportUsesGoAwayDebugError_RoundTrip(t *testing.T) { + testTransportUsesGoAwayDebugError(t, false) +} + +func TestTransportUsesGoAwayDebugError_Body(t *testing.T) { + testTransportUsesGoAwayDebugError(t, true) +} + +func testTransportUsesGoAwayDebugError(t *testing.T, failMidBody bool) { + ct := newClientTester(t) + clientDone := make(chan struct{}) + + const goAwayErrCode = ErrCodeHTTP11Required // arbitrary + const goAwayDebugData = "some debug data" + + ct.client = func() error { + defer close(clientDone) + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if failMidBody { + if err != nil { + return fmt.Errorf("unexpected client RoundTrip error: %v", err) + } + _, err = io.Copy(ioutil.Discard, res.Body) + res.Body.Close() + } + want := GoAwayError{ + LastStreamID: 5, + ErrCode: goAwayErrCode, + DebugData: goAwayDebugData, + } + if !reflect.DeepEqual(err, want) { + t.Errorf("RoundTrip error = %T: %#v, want %T (%#v)", err, err, want, want) + } + return nil + } + ct.server = func() error { + ct.greet() + for { + f, err := ct.fr.ReadFrame() + if err != nil { + t.Logf("ReadFrame: %v", err) + return nil + } + hf, ok := f.(*HeadersFrame) + if !ok { + continue + } + if failMidBody { + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "123"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + } + // Write two GOAWAY frames, to test that the Transport takes + // the interesting parts of both. + ct.fr.WriteGoAway(5, ErrCodeNo, []byte(goAwayDebugData)) + ct.fr.WriteGoAway(5, goAwayErrCode, nil) + ct.sc.(*net.TCPConn).CloseWrite() + <-clientDone + return nil + } + } + ct.run() +} + +func testTransportReturnsUnusedFlowControl(t *testing.T, oneDataFrame bool) { + ct := newClientTester(t) + + clientClosed := make(chan struct{}) + serverWroteFirstByte := make(chan struct{}) + + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return err + } + <-serverWroteFirstByte + + if n, err := res.Body.Read(make([]byte, 1)); err != nil || n != 1 { + return fmt.Errorf("body read = %v, %v; want 1, nil", n, err) + } + res.Body.Close() // leaving 4999 bytes unread + close(clientClosed) + + return nil + } + ct.server = func() error { + ct.greet() + + var hf *HeadersFrame + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return fmt.Errorf("ReadFrame while waiting for Headers: %v", err) + } + switch f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + continue + } + var ok bool + hf, ok = f.(*HeadersFrame) + if !ok { + return fmt.Errorf("Got %T; want HeadersFrame", f) + } + break + } + + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + + // Two cases: + // - Send one DATA frame with 5000 bytes. + // - Send two DATA frames with 1 and 4999 bytes each. + // + // In both cases, the client should consume one byte of data, + // refund that byte, then refund the following 4999 bytes. + // + // In the second case, the server waits for the client connection to + // close before seconding the second DATA frame. This tests the case + // where the client receives a DATA frame after it has reset the stream. + if oneDataFrame { + ct.fr.WriteData(hf.StreamID, false /* don't end stream */, make([]byte, 5000)) + close(serverWroteFirstByte) + <-clientClosed + } else { + ct.fr.WriteData(hf.StreamID, false /* don't end stream */, make([]byte, 1)) + close(serverWroteFirstByte) + <-clientClosed + ct.fr.WriteData(hf.StreamID, false /* don't end stream */, make([]byte, 4999)) + } + + waitingFor := "RSTStreamFrame" + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return fmt.Errorf("ReadFrame while waiting for %s: %v", waitingFor, err) + } + if _, ok := f.(*SettingsFrame); ok { + continue + } + switch waitingFor { + case "RSTStreamFrame": + if rf, ok := f.(*RSTStreamFrame); !ok || rf.ErrCode != ErrCodeCancel { + return fmt.Errorf("Expected a RSTStreamFrame with code cancel; got %v", summarizeFrame(f)) + } + waitingFor = "WindowUpdateFrame" + case "WindowUpdateFrame": + if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != 4999 { + return fmt.Errorf("Expected WindowUpdateFrame for 4999 bytes; got %v", summarizeFrame(f)) + } + return nil + } + } + } + ct.run() +} + +// See golang.org/issue/16481 +func TestTransportReturnsUnusedFlowControlSingleWrite(t *testing.T) { + testTransportReturnsUnusedFlowControl(t, true) +} + +// See golang.org/issue/20469 +func TestTransportReturnsUnusedFlowControlMultipleWrites(t *testing.T) { + testTransportReturnsUnusedFlowControl(t, false) +} + +// Issue 16612: adjust flow control on open streams when transport +// receives SETTINGS with INITIAL_WINDOW_SIZE from server. +func TestTransportAdjustsFlowControl(t *testing.T) { + ct := newClientTester(t) + clientDone := make(chan struct{}) + + const bodySize = 1 << 20 + + ct.client = func() error { + defer ct.cc.(*net.TCPConn).CloseWrite() + defer close(clientDone) + + req, _ := http.NewRequest("POST", "https://dummy.tld/", struct{ io.Reader }{io.LimitReader(neverEnding('A'), bodySize)}) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return err + } + res.Body.Close() + return nil + } + ct.server = func() error { + _, err := io.ReadFull(ct.sc, make([]byte, len(ClientPreface))) + if err != nil { + return fmt.Errorf("reading client preface: %v", err) + } + + var gotBytes int64 + var sentSettings bool + for { + f, err := ct.fr.ReadFrame() + if err != nil { + select { + case <-clientDone: + return nil + default: + return fmt.Errorf("ReadFrame while waiting for Headers: %v", err) + } + } + switch f := f.(type) { + case *DataFrame: + gotBytes += int64(len(f.Data())) + // After we've got half the client's + // initial flow control window's worth + // of request body data, give it just + // enough flow control to finish. + if gotBytes >= initialWindowSize/2 && !sentSettings { + sentSettings = true + + ct.fr.WriteSettings(Setting{ID: SettingInitialWindowSize, Val: bodySize}) + ct.fr.WriteWindowUpdate(0, bodySize) + ct.fr.WriteSettingsAck() + } + + if f.StreamEnded() { + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: true, + BlockFragment: buf.Bytes(), + }) + } + } + } + } + ct.run() +} + +// See golang.org/issue/16556 +func TestTransportReturnsDataPaddingFlowControl(t *testing.T) { + ct := newClientTester(t) + + unblockClient := make(chan bool, 1) + + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err != nil { + return err + } + defer res.Body.Close() + <-unblockClient + return nil + } + ct.server = func() error { + ct.greet() + + var hf *HeadersFrame + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return fmt.Errorf("ReadFrame while waiting for Headers: %v", err) + } + switch f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + continue + } + var ok bool + hf, ok = f.(*HeadersFrame) + if !ok { + return fmt.Errorf("Got %T; want HeadersFrame", f) + } + break + } + + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "content-length", Value: "5000"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + pad := make([]byte, 5) + ct.fr.WriteDataPadded(hf.StreamID, false, make([]byte, 5000), pad) // without ending stream + + f, err := ct.readNonSettingsFrame() + if err != nil { + return fmt.Errorf("ReadFrame while waiting for first WindowUpdateFrame: %v", err) + } + wantBack := uint32(len(pad)) + 1 // one byte for the length of the padding + if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != wantBack || wuf.StreamID != 0 { + return fmt.Errorf("Expected conn WindowUpdateFrame for %d bytes; got %v", wantBack, summarizeFrame(f)) + } + + f, err = ct.readNonSettingsFrame() + if err != nil { + return fmt.Errorf("ReadFrame while waiting for second WindowUpdateFrame: %v", err) + } + if wuf, ok := f.(*WindowUpdateFrame); !ok || wuf.Increment != wantBack || wuf.StreamID == 0 { + return fmt.Errorf("Expected stream WindowUpdateFrame for %d bytes; got %v", wantBack, summarizeFrame(f)) + } + unblockClient <- true + return nil + } + ct.run() +} + +// golang.org/issue/16572 -- RoundTrip shouldn't hang when it gets a +// StreamError as a result of the response HEADERS +func TestTransportReturnsErrorOnBadResponseHeaders(t *testing.T) { + ct := newClientTester(t) + + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := ct.tr.RoundTrip(req) + if err == nil { + res.Body.Close() + return errors.New("unexpected successful GET") + } + want := StreamError{1, ErrCodeProtocol, headerFieldNameError(" content-type")} + if !reflect.DeepEqual(want, err) { + t.Errorf("RoundTrip error = %#v; want %#v", err, want) + } + return nil + } + ct.server = func() error { + ct.greet() + + hf, err := ct.firstHeaders() + if err != nil { + return err + } + + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: " content-type", Value: "bogus"}) // bogus spaces + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + + for { + fr, err := ct.readFrame() + if err != nil { + return fmt.Errorf("error waiting for RST_STREAM from client: %v", err) + } + if _, ok := fr.(*SettingsFrame); ok { + continue + } + if rst, ok := fr.(*RSTStreamFrame); !ok || rst.StreamID != 1 || rst.ErrCode != ErrCodeProtocol { + t.Errorf("Frame = %v; want RST_STREAM for stream 1 with ErrCodeProtocol", summarizeFrame(fr)) + } + break + } + + return nil + } + ct.run() +} + +// byteAndEOFReader returns is in an io.Reader which reads one byte +// (the underlying byte) and io.EOF at once in its Read call. +type byteAndEOFReader byte + +func (b byteAndEOFReader) Read(p []byte) (n int, err error) { + if len(p) == 0 { + panic("unexpected useless call") + } + p[0] = byte(b) + return 1, io.EOF +} + +// Issue 16788: the Transport had a regression where it started +// sending a spurious DATA frame with a duplicate END_STREAM bit after +// the request body writer goroutine had already read an EOF from the +// Request.Body and included the END_STREAM on a data-carrying DATA +// frame. +// +// Notably, to trigger this, the requests need to use a Request.Body +// which returns (non-0, io.EOF) and also needs to set the ContentLength +// explicitly. +func TestTransportBodyDoubleEndStream(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + // Nothing. + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + for i := 0; i < 2; i++ { + req, _ := http.NewRequest("POST", st.ts.URL, byteAndEOFReader('a')) + req.ContentLength = 1 + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatalf("failure on req %d: %v", i+1, err) + } + defer res.Body.Close() + } +} + +// golang.org/issue/16847, golang.org/issue/19103 +func TestTransportRequestPathPseudo(t *testing.T) { + type result struct { + path string + err string + } + tests := []struct { + req *http.Request + want result + }{ + 0: { + req: &http.Request{ + Method: "GET", + URL: &url.URL{ + Host: "foo.com", + Path: "/foo", + }, + }, + want: result{path: "/foo"}, + }, + // In Go 1.7, we accepted paths of "//foo". + // In Go 1.8, we rejected it (issue 16847). + // In Go 1.9, we accepted it again (issue 19103). + 1: { + req: &http.Request{ + Method: "GET", + URL: &url.URL{ + Host: "foo.com", + Path: "//foo", + }, + }, + want: result{path: "//foo"}, + }, + + // Opaque with //$Matching_Hostname/path + 2: { + req: &http.Request{ + Method: "GET", + URL: &url.URL{ + Scheme: "https", + Opaque: "//foo.com/path", + Host: "foo.com", + Path: "/ignored", + }, + }, + want: result{path: "/path"}, + }, + + // Opaque with some other Request.Host instead: + 3: { + req: &http.Request{ + Method: "GET", + Host: "bar.com", + URL: &url.URL{ + Scheme: "https", + Opaque: "//bar.com/path", + Host: "foo.com", + Path: "/ignored", + }, + }, + want: result{path: "/path"}, + }, + + // Opaque without the leading "//": + 4: { + req: &http.Request{ + Method: "GET", + URL: &url.URL{ + Opaque: "/path", + Host: "foo.com", + Path: "/ignored", + }, + }, + want: result{path: "/path"}, + }, + + // Opaque we can't handle: + 5: { + req: &http.Request{ + Method: "GET", + URL: &url.URL{ + Scheme: "https", + Opaque: "//unknown_host/path", + Host: "foo.com", + Path: "/ignored", + }, + }, + want: result{err: `invalid request :path "https://unknown_host/path" from URL.Opaque = "//unknown_host/path"`}, + }, + + // A CONNECT request: + 6: { + req: &http.Request{ + Method: "CONNECT", + URL: &url.URL{ + Host: "foo.com", + }, + }, + want: result{}, + }, + } + for i, tt := range tests { + cc := &ClientConn{peerMaxHeaderListSize: 0xffffffffffffffff} + cc.henc = hpack.NewEncoder(&cc.hbuf) + cc.mu.Lock() + hdrs, err := cc.encodeHeaders(tt.req, false, "", -1) + cc.mu.Unlock() + var got result + hpackDec := hpack.NewDecoder(initialHeaderTableSize, func(f hpack.HeaderField) { + if f.Name == ":path" { + got.path = f.Value + } + }) + if err != nil { + got.err = err.Error() + } else if len(hdrs) > 0 { + if _, err := hpackDec.Write(hdrs); err != nil { + t.Errorf("%d. bogus hpack: %v", i, err) + continue + } + } + if got != tt.want { + t.Errorf("%d. got %+v; want %+v", i, got, tt.want) + } + + } + +} + +// golang.org/issue/17071 -- don't sniff the first byte of the request body +// before we've determined that the ClientConn is usable. +func TestRoundTripDoesntConsumeRequestBodyEarly(t *testing.T) { + const body = "foo" + req, _ := http.NewRequest("POST", "http://foo.com/", ioutil.NopCloser(strings.NewReader(body))) + cc := &ClientConn{ + closed: true, + } + _, err := cc.RoundTrip(req) + if err != errClientConnUnusable { + t.Fatalf("RoundTrip = %v; want errClientConnUnusable", err) + } + slurp, err := ioutil.ReadAll(req.Body) + if err != nil { + t.Errorf("ReadAll = %v", err) + } + if string(slurp) != body { + t.Errorf("Body = %q; want %q", slurp, body) + } +} + +func TestClientConnPing(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}, optOnlyServer) + defer st.Close() + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + cc, err := tr.dialClientConn(st.ts.Listener.Addr().String(), false) + if err != nil { + t.Fatal(err) + } + if err = cc.Ping(testContext{}); err != nil { + t.Fatal(err) + } +} + +// Issue 16974: if the server sent a DATA frame after the user +// canceled the Transport's Request, the Transport previously wrote to a +// closed pipe, got an error, and ended up closing the whole TCP +// connection. +func TestTransportCancelDataResponseRace(t *testing.T) { + cancel := make(chan struct{}) + clientGotError := make(chan bool, 1) + + const msg = "Hello." + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + if strings.Contains(r.URL.Path, "/hello") { + time.Sleep(50 * time.Millisecond) + io.WriteString(w, msg) + return + } + for i := 0; i < 50; i++ { + io.WriteString(w, "Some data.") + w.(http.Flusher).Flush() + if i == 2 { + close(cancel) + <-clientGotError + } + time.Sleep(10 * time.Millisecond) + } + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + c := &http.Client{Transport: tr} + req, _ := http.NewRequest("GET", st.ts.URL, nil) + req.Cancel = cancel + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + if _, err = io.Copy(ioutil.Discard, res.Body); err == nil { + t.Fatal("unexpected success") + } + clientGotError <- true + + res, err = c.Get(st.ts.URL + "/hello") + if err != nil { + t.Fatal(err) + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if string(slurp) != msg { + t.Errorf("Got = %q; want %q", slurp, msg) + } +} + +// Issue 21316: It should be safe to reuse an http.Request after the +// request has completed. +func TestTransportNoRaceOnRequestObjectAfterRequestComplete(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + io.WriteString(w, "body") + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + req, _ := http.NewRequest("GET", st.ts.URL, nil) + resp, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + if _, err = io.Copy(ioutil.Discard, resp.Body); err != nil { + t.Fatalf("error reading response body: %v", err) + } + if err := resp.Body.Close(); err != nil { + t.Fatalf("error closing response body: %v", err) + } + + // This access of req.Header should not race with code in the transport. + req.Header = http.Header{} +} + +func TestTransportRetryAfterGOAWAY(t *testing.T) { + var dialer struct { + sync.Mutex + count int + } + ct1 := make(chan *clientTester) + ct2 := make(chan *clientTester) + + ln := newLocalListener(t) + defer ln.Close() + + tr := &Transport{ + TLSClientConfig: tlsConfigInsecure, + } + tr.DialTLS = func(network, addr string, cfg *tls.Config) (net.Conn, error) { + dialer.Lock() + defer dialer.Unlock() + dialer.count++ + if dialer.count == 3 { + return nil, errors.New("unexpected number of dials") + } + cc, err := net.Dial("tcp", ln.Addr().String()) + if err != nil { + return nil, fmt.Errorf("dial error: %v", err) + } + sc, err := ln.Accept() + if err != nil { + return nil, fmt.Errorf("accept error: %v", err) + } + ct := &clientTester{ + t: t, + tr: tr, + cc: cc, + sc: sc, + fr: NewFramer(sc, sc), + } + switch dialer.count { + case 1: + ct1 <- ct + case 2: + ct2 <- ct + } + return cc, nil + } + + errs := make(chan error, 3) + done := make(chan struct{}) + defer close(done) + + // Client. + go func() { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + res, err := tr.RoundTrip(req) + if res != nil { + res.Body.Close() + if got := res.Header.Get("Foo"); got != "bar" { + err = fmt.Errorf("foo header = %q; want bar", got) + } + } + if err != nil { + err = fmt.Errorf("RoundTrip: %v", err) + } + errs <- err + }() + + connToClose := make(chan io.Closer, 2) + + // Server for the first request. + go func() { + var ct *clientTester + select { + case ct = <-ct1: + case <-done: + return + } + + connToClose <- ct.cc + ct.greet() + hf, err := ct.firstHeaders() + if err != nil { + errs <- fmt.Errorf("server1 failed reading HEADERS: %v", err) + return + } + t.Logf("server1 got %v", hf) + if err := ct.fr.WriteGoAway(0 /*max id*/, ErrCodeNo, nil); err != nil { + errs <- fmt.Errorf("server1 failed writing GOAWAY: %v", err) + return + } + errs <- nil + }() + + // Server for the second request. + go func() { + var ct *clientTester + select { + case ct = <-ct2: + case <-done: + return + } + + connToClose <- ct.cc + ct.greet() + hf, err := ct.firstHeaders() + if err != nil { + errs <- fmt.Errorf("server2 failed reading HEADERS: %v", err) + return + } + t.Logf("server2 got %v", hf) + + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"}) + err = ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: hf.StreamID, + EndHeaders: true, + EndStream: false, + BlockFragment: buf.Bytes(), + }) + if err != nil { + errs <- fmt.Errorf("server2 failed writing response HEADERS: %v", err) + } else { + errs <- nil + } + }() + + for k := 0; k < 3; k++ { + select { + case err := <-errs: + if err != nil { + t.Error(err) + } + case <-time.After(1 * time.Second): + t.Errorf("timed out") + } + } + + for { + select { + case c := <-connToClose: + c.Close() + default: + return + } + } +} + +func TestTransportRetryAfterRefusedStream(t *testing.T) { + clientDone := make(chan struct{}) + ct := newClientTester(t) + ct.client = func() error { + defer ct.cc.(*net.TCPConn).CloseWrite() + defer close(clientDone) + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + resp, err := ct.tr.RoundTrip(req) + if err != nil { + return fmt.Errorf("RoundTrip: %v", err) + } + resp.Body.Close() + if resp.StatusCode != 204 { + return fmt.Errorf("Status = %v; want 204", resp.StatusCode) + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + nreq := 0 + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + select { + case <-clientDone: + // If the client's done, it + // will have reported any + // errors on its side. + return nil + default: + return err + } + } + switch f := f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + case *HeadersFrame: + if !f.HeadersEnded() { + return fmt.Errorf("headers should have END_HEADERS be ended: %v", f) + } + nreq++ + if nreq == 1 { + ct.fr.WriteRSTStream(f.StreamID, ErrCodeRefusedStream) + } else { + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "204"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: true, + BlockFragment: buf.Bytes(), + }) + } + default: + return fmt.Errorf("Unexpected client frame %v", f) + } + } + } + ct.run() +} + +func TestTransportRetryHasLimit(t *testing.T) { + // Skip in short mode because the total expected delay is 1s+2s+4s+8s+16s=29s. + if testing.Short() { + t.Skip("skipping long test in short mode") + } + clientDone := make(chan struct{}) + ct := newClientTester(t) + ct.client = func() error { + defer ct.cc.(*net.TCPConn).CloseWrite() + defer close(clientDone) + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + resp, err := ct.tr.RoundTrip(req) + if err == nil { + return fmt.Errorf("RoundTrip expected error, got response: %+v", resp) + } + t.Logf("expected error, got: %v", err) + return nil + } + ct.server = func() error { + ct.greet() + for { + f, err := ct.fr.ReadFrame() + if err != nil { + select { + case <-clientDone: + // If the client's done, it + // will have reported any + // errors on its side. + return nil + default: + return err + } + } + switch f := f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + case *HeadersFrame: + if !f.HeadersEnded() { + return fmt.Errorf("headers should have END_HEADERS be ended: %v", f) + } + ct.fr.WriteRSTStream(f.StreamID, ErrCodeRefusedStream) + default: + return fmt.Errorf("Unexpected client frame %v", f) + } + } + } + ct.run() +} + +func TestTransportResponseDataBeforeHeaders(t *testing.T) { + // This test use not valid response format. + // Discarding logger output to not spam tests output. + log.SetOutput(ioutil.Discard) + defer log.SetOutput(os.Stderr) + + ct := newClientTester(t) + ct.client = func() error { + defer ct.cc.(*net.TCPConn).CloseWrite() + req := httptest.NewRequest("GET", "https://dummy.tld/", nil) + // First request is normal to ensure the check is per stream and not per connection. + _, err := ct.tr.RoundTrip(req) + if err != nil { + return fmt.Errorf("RoundTrip expected no error, got: %v", err) + } + // Second request returns a DATA frame with no HEADERS. + resp, err := ct.tr.RoundTrip(req) + if err == nil { + return fmt.Errorf("RoundTrip expected error, got response: %+v", resp) + } + if err, ok := err.(StreamError); !ok || err.Code != ErrCodeProtocol { + return fmt.Errorf("expected stream PROTOCOL_ERROR, got: %v", err) + } + return nil + } + ct.server = func() error { + ct.greet() + for { + f, err := ct.fr.ReadFrame() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + switch f := f.(type) { + case *WindowUpdateFrame, *SettingsFrame: + case *HeadersFrame: + switch f.StreamID { + case 1: + // Send a valid response to first request. + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: true, + BlockFragment: buf.Bytes(), + }) + case 3: + ct.fr.WriteData(f.StreamID, true, []byte("payload")) + } + default: + return fmt.Errorf("Unexpected client frame %v", f) + } + } + } + ct.run() +} +func TestTransportRequestsStallAtServerLimit(t *testing.T) { + const maxConcurrent = 2 + + greet := make(chan struct{}) // server sends initial SETTINGS frame + gotRequest := make(chan struct{}) // server received a request + clientDone := make(chan struct{}) + + // Collect errors from goroutines. + var wg sync.WaitGroup + errs := make(chan error, 100) + defer func() { + wg.Wait() + close(errs) + for err := range errs { + t.Error(err) + } + }() + + // We will send maxConcurrent+2 requests. This checker goroutine waits for the + // following stages: + // 1. The first maxConcurrent requests are received by the server. + // 2. The client will cancel the next request + // 3. The server is unblocked so it can service the first maxConcurrent requests + // 4. The client will send the final request + wg.Add(1) + unblockClient := make(chan struct{}) + clientRequestCancelled := make(chan struct{}) + unblockServer := make(chan struct{}) + go func() { + defer wg.Done() + // Stage 1. + for k := 0; k < maxConcurrent; k++ { + <-gotRequest + } + // Stage 2. + close(unblockClient) + <-clientRequestCancelled + // Stage 3: give some time for the final RoundTrip call to be scheduled and + // verify that the final request is not sent. + time.Sleep(50 * time.Millisecond) + select { + case <-gotRequest: + errs <- errors.New("last request did not stall") + close(unblockServer) + return + default: + } + close(unblockServer) + // Stage 4. + <-gotRequest + }() + + ct := newClientTester(t) + ct.client = func() error { + var wg sync.WaitGroup + defer func() { + wg.Wait() + close(clientDone) + ct.cc.(*net.TCPConn).CloseWrite() + }() + for k := 0; k < maxConcurrent+2; k++ { + wg.Add(1) + go func(k int) { + defer wg.Done() + // Don't send the second request until after receiving SETTINGS from the server + // to avoid a race where we use the default SettingMaxConcurrentStreams, which + // is much larger than maxConcurrent. We have to send the first request before + // waiting because the first request triggers the dial and greet. + if k > 0 { + <-greet + } + // Block until maxConcurrent requests are sent before sending any more. + if k >= maxConcurrent { + <-unblockClient + } + req, _ := http.NewRequest("GET", fmt.Sprintf("https://dummy.tld/%d", k), nil) + if k == maxConcurrent { + // This request will be canceled. + cancel := make(chan struct{}) + req.Cancel = cancel + close(cancel) + _, err := ct.tr.RoundTrip(req) + close(clientRequestCancelled) + if err == nil { + errs <- fmt.Errorf("RoundTrip(%d) should have failed due to cancel", k) + return + } + } else { + resp, err := ct.tr.RoundTrip(req) + if err != nil { + errs <- fmt.Errorf("RoundTrip(%d): %v", k, err) + return + } + ioutil.ReadAll(resp.Body) + resp.Body.Close() + if resp.StatusCode != 204 { + errs <- fmt.Errorf("Status = %v; want 204", resp.StatusCode) + return + } + } + }(k) + } + return nil + } + + ct.server = func() error { + var wg sync.WaitGroup + defer wg.Wait() + + ct.greet(Setting{SettingMaxConcurrentStreams, maxConcurrent}) + + // Server write loop. + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + writeResp := make(chan uint32, maxConcurrent+1) + + wg.Add(1) + go func() { + defer wg.Done() + <-unblockServer + for id := range writeResp { + buf.Reset() + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "204"}) + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: id, + EndHeaders: true, + EndStream: true, + BlockFragment: buf.Bytes(), + }) + } + }() + + // Server read loop. + var nreq int + for { + f, err := ct.fr.ReadFrame() + if err != nil { + select { + case <-clientDone: + // If the client's done, it will have reported any errors on its side. + return nil + default: + return err + } + } + switch f := f.(type) { + case *WindowUpdateFrame: + case *SettingsFrame: + // Wait for the client SETTINGS ack until ending the greet. + close(greet) + case *HeadersFrame: + if !f.HeadersEnded() { + return fmt.Errorf("headers should have END_HEADERS be ended: %v", f) + } + gotRequest <- struct{}{} + nreq++ + writeResp <- f.StreamID + if nreq == maxConcurrent+1 { + close(writeResp) + } + default: + return fmt.Errorf("Unexpected client frame %v", f) + } + } + } + + ct.run() +} + +func TestAuthorityAddr(t *testing.T) { + tests := []struct { + scheme, authority string + want string + }{ + {"http", "foo.com", "foo.com:80"}, + {"https", "foo.com", "foo.com:443"}, + {"https", "foo.com:1234", "foo.com:1234"}, + {"https", "1.2.3.4:1234", "1.2.3.4:1234"}, + {"https", "1.2.3.4", "1.2.3.4:443"}, + {"https", "[::1]:1234", "[::1]:1234"}, + {"https", "[::1]", "[::1]:443"}, + } + for _, tt := range tests { + got := authorityAddr(tt.scheme, tt.authority) + if got != tt.want { + t.Errorf("authorityAddr(%q, %q) = %q; want %q", tt.scheme, tt.authority, got, tt.want) + } + } +} + +// Issue 20448: stop allocating for DATA frames' payload after +// Response.Body.Close is called. +func TestTransportAllocationsAfterResponseBodyClose(t *testing.T) { + megabyteZero := make([]byte, 1<<20) + + writeErr := make(chan error, 1) + + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + w.(http.Flusher).Flush() + var sum int64 + for i := 0; i < 100; i++ { + n, err := w.Write(megabyteZero) + sum += int64(n) + if err != nil { + writeErr <- err + return + } + } + t.Logf("wrote all %d bytes", sum) + writeErr <- nil + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + res, err := c.Get(st.ts.URL) + if err != nil { + t.Fatal(err) + } + var buf [1]byte + if _, err := res.Body.Read(buf[:]); err != nil { + t.Error(err) + } + if err := res.Body.Close(); err != nil { + t.Error(err) + } + + trb, ok := res.Body.(transportResponseBody) + if !ok { + t.Fatalf("res.Body = %T; want transportResponseBody", res.Body) + } + if trb.cs.bufPipe.b != nil { + t.Errorf("response body pipe is still open") + } + + gotErr := <-writeErr + if gotErr == nil { + t.Errorf("Handler unexpectedly managed to write its entire response without getting an error") + } else if gotErr != errStreamClosed { + t.Errorf("Handler Write err = %v; want errStreamClosed", gotErr) + } +} + +// Issue 18891: make sure Request.Body == NoBody means no DATA frame +// is ever sent, even if empty. +func TestTransportNoBodyMeansNoDATA(t *testing.T) { + ct := newClientTester(t) + + unblockClient := make(chan bool) + + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", go18httpNoBody()) + ct.tr.RoundTrip(req) + <-unblockClient + return nil + } + ct.server = func() error { + defer close(unblockClient) + defer ct.cc.(*net.TCPConn).Close() + ct.greet() + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return fmt.Errorf("ReadFrame while waiting for Headers: %v", err) + } + switch f := f.(type) { + default: + return fmt.Errorf("Got %T; want HeadersFrame", f) + case *WindowUpdateFrame, *SettingsFrame: + continue + case *HeadersFrame: + if !f.StreamEnded() { + return fmt.Errorf("got headers frame without END_STREAM") + } + return nil + } + } + } + ct.run() +} + +func benchSimpleRoundTrip(b *testing.B, nHeaders int) { + defer disableGoroutineTracking()() + b.ReportAllocs() + st := newServerTester(b, + func(w http.ResponseWriter, r *http.Request) { + }, + optOnlyServer, + optQuiet, + ) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + req, err := http.NewRequest("GET", st.ts.URL, nil) + if err != nil { + b.Fatal(err) + } + + for i := 0; i < nHeaders; i++ { + name := fmt.Sprint("A-", i) + req.Header.Set(name, "*") + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + res, err := tr.RoundTrip(req) + if err != nil { + if res != nil { + res.Body.Close() + } + b.Fatalf("RoundTrip err = %v; want nil", err) + } + res.Body.Close() + if res.StatusCode != http.StatusOK { + b.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK) + } + } +} + +type infiniteReader struct{} + +func (r infiniteReader) Read(b []byte) (int, error) { + return len(b), nil +} + +// Issue 20521: it is not an error to receive a response and end stream +// from the server without the body being consumed. +func TestTransportResponseAndResetWithoutConsumingBodyRace(t *testing.T) { + st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + }, optOnlyServer) + defer st.Close() + + tr := &Transport{TLSClientConfig: tlsConfigInsecure} + defer tr.CloseIdleConnections() + + // The request body needs to be big enough to trigger flow control. + req, _ := http.NewRequest("PUT", st.ts.URL, infiniteReader{}) + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + if res.StatusCode != http.StatusOK { + t.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK) + } +} + +// Verify transport doesn't crash when receiving bogus response lacking a :status header. +// Issue 22880. +func TestTransportHandlesInvalidStatuslessResponse(t *testing.T) { + ct := newClientTester(t) + ct.client = func() error { + req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) + _, err := ct.tr.RoundTrip(req) + const substr = "malformed response from server: missing status pseudo header" + if !strings.Contains(fmt.Sprint(err), substr) { + return fmt.Errorf("RoundTrip error = %v; want substring %q", err, substr) + } + return nil + } + ct.server = func() error { + ct.greet() + var buf bytes.Buffer + enc := hpack.NewEncoder(&buf) + + for { + f, err := ct.fr.ReadFrame() + if err != nil { + return err + } + switch f := f.(type) { + case *HeadersFrame: + enc.WriteField(hpack.HeaderField{Name: "content-type", Value: "text/html"}) // no :status header + ct.fr.WriteHeaders(HeadersFrameParam{ + StreamID: f.StreamID, + EndHeaders: true, + EndStream: false, // we'll send some DATA to try to crash the transport + BlockFragment: buf.Bytes(), + }) + ct.fr.WriteData(f.StreamID, true, []byte("payload")) + return nil + } + } + } + ct.run() +} + +func BenchmarkClientRequestHeaders(b *testing.B) { + b.Run(" 0 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0) }) + b.Run(" 10 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 10) }) + b.Run(" 100 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 100) }) + b.Run("1000 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 1000) }) +} diff --git a/vendor/golang.org/x/net/http2/writesched_priority_test.go b/vendor/golang.org/x/net/http2/writesched_priority_test.go new file mode 100644 index 000000000..f2b535a2c --- /dev/null +++ b/vendor/golang.org/x/net/http2/writesched_priority_test.go @@ -0,0 +1,541 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bytes" + "fmt" + "sort" + "testing" +) + +func defaultPriorityWriteScheduler() *priorityWriteScheduler { + return NewPriorityWriteScheduler(nil).(*priorityWriteScheduler) +} + +func checkPriorityWellFormed(ws *priorityWriteScheduler) error { + for id, n := range ws.nodes { + if id != n.id { + return fmt.Errorf("bad ws.nodes: ws.nodes[%d] = %d", id, n.id) + } + if n.parent == nil { + if n.next != nil || n.prev != nil { + return fmt.Errorf("bad node %d: nil parent but prev/next not nil", id) + } + continue + } + found := false + for k := n.parent.kids; k != nil; k = k.next { + if k.id == id { + found = true + break + } + } + if !found { + return fmt.Errorf("bad node %d: not found in parent %d kids list", id, n.parent.id) + } + } + return nil +} + +func fmtTree(ws *priorityWriteScheduler, fmtNode func(*priorityNode) string) string { + var ids []int + for _, n := range ws.nodes { + ids = append(ids, int(n.id)) + } + sort.Ints(ids) + + var buf bytes.Buffer + for _, id := range ids { + if buf.Len() != 0 { + buf.WriteString(" ") + } + if id == 0 { + buf.WriteString(fmtNode(&ws.root)) + } else { + buf.WriteString(fmtNode(ws.nodes[uint32(id)])) + } + } + return buf.String() +} + +func fmtNodeParentSkipRoot(n *priorityNode) string { + switch { + case n.id == 0: + return "" + case n.parent == nil: + return fmt.Sprintf("%d{parent:nil}", n.id) + default: + return fmt.Sprintf("%d{parent:%d}", n.id, n.parent.id) + } +} + +func fmtNodeWeightParentSkipRoot(n *priorityNode) string { + switch { + case n.id == 0: + return "" + case n.parent == nil: + return fmt.Sprintf("%d{weight:%d,parent:nil}", n.id, n.weight) + default: + return fmt.Sprintf("%d{weight:%d,parent:%d}", n.id, n.weight, n.parent.id) + } +} + +func TestPriorityTwoStreams(t *testing.T) { + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{}) + + want := "1{weight:15,parent:0} 2{weight:15,parent:0}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After open\ngot %q\nwant %q", got, want) + } + + // Move 1's parent to 2. + ws.AdjustStream(1, PriorityParam{ + StreamDep: 2, + Weight: 32, + Exclusive: false, + }) + want = "1{weight:32,parent:2} 2{weight:15,parent:0}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPriorityAdjustExclusiveZero(t *testing.T) { + // 1, 2, and 3 are all children of the 0 stream. + // Exclusive reprioritization to any of the streams should bring + // the rest of the streams under the reprioritized stream. + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{}) + ws.OpenStream(3, OpenStreamOptions{}) + + want := "1{weight:15,parent:0} 2{weight:15,parent:0} 3{weight:15,parent:0}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After open\ngot %q\nwant %q", got, want) + } + + ws.AdjustStream(2, PriorityParam{ + StreamDep: 0, + Weight: 20, + Exclusive: true, + }) + want = "1{weight:15,parent:2} 2{weight:20,parent:0} 3{weight:15,parent:2}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPriorityAdjustOwnParent(t *testing.T) { + // Assigning a node as its own parent should have no effect. + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{}) + ws.AdjustStream(2, PriorityParam{ + StreamDep: 2, + Weight: 20, + Exclusive: true, + }) + want := "1{weight:15,parent:0} 2{weight:15,parent:0}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPriorityClosedStreams(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{MaxClosedNodesInTree: 2}).(*priorityWriteScheduler) + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 2}) + ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) + + // Close the first three streams. We lose 1, but keep 2 and 3. + ws.CloseStream(1) + ws.CloseStream(2) + ws.CloseStream(3) + + want := "2{weight:15,parent:0} 3{weight:15,parent:2} 4{weight:15,parent:3}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After close\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } + + // Adding a stream as an exclusive child of 1 gives it default + // priorities, since 1 is gone. + ws.OpenStream(5, OpenStreamOptions{}) + ws.AdjustStream(5, PriorityParam{StreamDep: 1, Weight: 15, Exclusive: true}) + + // Adding a stream as an exclusive child of 2 should work, since 2 is not gone. + ws.OpenStream(6, OpenStreamOptions{}) + ws.AdjustStream(6, PriorityParam{StreamDep: 2, Weight: 15, Exclusive: true}) + + want = "2{weight:15,parent:0} 3{weight:15,parent:6} 4{weight:15,parent:3} 5{weight:15,parent:0} 6{weight:15,parent:2}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After add streams\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPriorityClosedStreamsDisabled(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{}).(*priorityWriteScheduler) + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 2}) + + // Close the first two streams. We keep only 3. + ws.CloseStream(1) + ws.CloseStream(2) + + want := "3{weight:15,parent:0}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After close\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPriorityIdleStreams(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{MaxIdleNodesInTree: 2}).(*priorityWriteScheduler) + ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 15}) // idle + ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 15}) // idle + ws.AdjustStream(3, PriorityParam{StreamDep: 2, Weight: 20}) // idle + ws.OpenStream(4, OpenStreamOptions{}) + ws.OpenStream(5, OpenStreamOptions{}) + ws.OpenStream(6, OpenStreamOptions{}) + ws.AdjustStream(4, PriorityParam{StreamDep: 1, Weight: 15}) + ws.AdjustStream(5, PriorityParam{StreamDep: 2, Weight: 15}) + ws.AdjustStream(6, PriorityParam{StreamDep: 3, Weight: 15}) + + want := "2{weight:15,parent:0} 3{weight:20,parent:2} 4{weight:15,parent:0} 5{weight:15,parent:2} 6{weight:15,parent:3}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After open\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPriorityIdleStreamsDisabled(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{}).(*priorityWriteScheduler) + ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 15}) // idle + ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 15}) // idle + ws.AdjustStream(3, PriorityParam{StreamDep: 2, Weight: 20}) // idle + ws.OpenStream(4, OpenStreamOptions{}) + + want := "4{weight:15,parent:0}" + if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { + t.Errorf("After open\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPrioritySection531NonExclusive(t *testing.T) { + // Example from RFC 7540 Section 5.3.1. + // A,B,C,D = 1,2,3,4 + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(4, OpenStreamOptions{}) + ws.AdjustStream(4, PriorityParam{ + StreamDep: 1, + Weight: 15, + Exclusive: false, + }) + want := "1{parent:0} 2{parent:1} 3{parent:1} 4{parent:1}" + if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPrioritySection531Exclusive(t *testing.T) { + // Example from RFC 7540 Section 5.3.1. + // A,B,C,D = 1,2,3,4 + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(4, OpenStreamOptions{}) + ws.AdjustStream(4, PriorityParam{ + StreamDep: 1, + Weight: 15, + Exclusive: true, + }) + want := "1{parent:0} 2{parent:4} 3{parent:4} 4{parent:1}" + if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func makeSection533Tree() *priorityWriteScheduler { + // Initial tree from RFC 7540 Section 5.3.3. + // A,B,C,D,E,F = 1,2,3,4,5,6 + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) + ws.OpenStream(5, OpenStreamOptions{PusherID: 3}) + ws.OpenStream(6, OpenStreamOptions{PusherID: 4}) + return ws +} + +func TestPrioritySection533NonExclusive(t *testing.T) { + // Example from RFC 7540 Section 5.3.3. + // A,B,C,D,E,F = 1,2,3,4,5,6 + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) + ws.OpenStream(5, OpenStreamOptions{PusherID: 3}) + ws.OpenStream(6, OpenStreamOptions{PusherID: 4}) + ws.AdjustStream(1, PriorityParam{ + StreamDep: 4, + Weight: 15, + Exclusive: false, + }) + want := "1{parent:4} 2{parent:1} 3{parent:1} 4{parent:0} 5{parent:3} 6{parent:4}" + if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func TestPrioritySection533Exclusive(t *testing.T) { + // Example from RFC 7540 Section 5.3.3. + // A,B,C,D,E,F = 1,2,3,4,5,6 + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) + ws.OpenStream(5, OpenStreamOptions{PusherID: 3}) + ws.OpenStream(6, OpenStreamOptions{PusherID: 4}) + ws.AdjustStream(1, PriorityParam{ + StreamDep: 4, + Weight: 15, + Exclusive: true, + }) + want := "1{parent:4} 2{parent:1} 3{parent:1} 4{parent:0} 5{parent:3} 6{parent:1}" + if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { + t.Errorf("After adjust\ngot %q\nwant %q", got, want) + } + if err := checkPriorityWellFormed(ws); err != nil { + t.Error(err) + } +} + +func checkPopAll(ws WriteScheduler, order []uint32) error { + for k, id := range order { + wr, ok := ws.Pop() + if !ok { + return fmt.Errorf("Pop[%d]: got ok=false, want %d (order=%v)", k, id, order) + } + if got := wr.StreamID(); got != id { + return fmt.Errorf("Pop[%d]: got %v, want %d (order=%v)", k, got, id, order) + } + } + wr, ok := ws.Pop() + if ok { + return fmt.Errorf("Pop[%d]: got %v, want ok=false (order=%v)", len(order), wr.StreamID(), order) + } + return nil +} + +func TestPriorityPopFrom533Tree(t *testing.T) { + ws := makeSection533Tree() + + ws.Push(makeWriteHeadersRequest(3 /*C*/)) + ws.Push(makeWriteNonStreamRequest()) + ws.Push(makeWriteHeadersRequest(5 /*E*/)) + ws.Push(makeWriteHeadersRequest(1 /*A*/)) + t.Log("tree:", fmtTree(ws, fmtNodeParentSkipRoot)) + + if err := checkPopAll(ws, []uint32{0 /*NonStream*/, 1, 3, 5}); err != nil { + t.Error(err) + } +} + +func TestPriorityPopFromLinearTree(t *testing.T) { + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + ws.OpenStream(3, OpenStreamOptions{PusherID: 2}) + ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) + + ws.Push(makeWriteHeadersRequest(3)) + ws.Push(makeWriteHeadersRequest(4)) + ws.Push(makeWriteHeadersRequest(1)) + ws.Push(makeWriteHeadersRequest(2)) + ws.Push(makeWriteNonStreamRequest()) + ws.Push(makeWriteNonStreamRequest()) + t.Log("tree:", fmtTree(ws, fmtNodeParentSkipRoot)) + + if err := checkPopAll(ws, []uint32{0, 0 /*NonStreams*/, 1, 2, 3, 4}); err != nil { + t.Error(err) + } +} + +func TestPriorityFlowControl(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ThrottleOutOfOrderWrites: false}) + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + + sc := &serverConn{maxFrameSize: 16} + st1 := &stream{id: 1, sc: sc} + st2 := &stream{id: 2, sc: sc} + + ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 16), false}, st1, nil}) + ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 16), false}, st2, nil}) + ws.AdjustStream(2, PriorityParam{StreamDep: 1}) + + // No flow-control bytes available. + if wr, ok := ws.Pop(); ok { + t.Fatalf("Pop(limited by flow control)=%v,true, want false", wr) + } + + // Add enough flow-control bytes to write st2 in two Pop calls. + // Should write data from st2 even though it's lower priority than st1. + for i := 1; i <= 2; i++ { + st2.flow.add(8) + wr, ok := ws.Pop() + if !ok { + t.Fatalf("Pop(%d)=false, want true", i) + } + if got, want := wr.DataSize(), 8; got != want { + t.Fatalf("Pop(%d)=%d bytes, want %d bytes", i, got, want) + } + } +} + +func TestPriorityThrottleOutOfOrderWrites(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ThrottleOutOfOrderWrites: true}) + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) + + sc := &serverConn{maxFrameSize: 4096} + st1 := &stream{id: 1, sc: sc} + st2 := &stream{id: 2, sc: sc} + st1.flow.add(4096) + st2.flow.add(4096) + ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 4096), false}, st2, nil}) + ws.AdjustStream(2, PriorityParam{StreamDep: 1}) + + // We have enough flow-control bytes to write st2 in a single Pop call. + // However, due to out-of-order write throttling, the first call should + // only write 1KB. + wr, ok := ws.Pop() + if !ok { + t.Fatalf("Pop(st2.first)=false, want true") + } + if got, want := wr.StreamID(), uint32(2); got != want { + t.Fatalf("Pop(st2.first)=stream %d, want stream %d", got, want) + } + if got, want := wr.DataSize(), 1024; got != want { + t.Fatalf("Pop(st2.first)=%d bytes, want %d bytes", got, want) + } + + // Now add data on st1. This should take precedence. + ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 4096), false}, st1, nil}) + wr, ok = ws.Pop() + if !ok { + t.Fatalf("Pop(st1)=false, want true") + } + if got, want := wr.StreamID(), uint32(1); got != want { + t.Fatalf("Pop(st1)=stream %d, want stream %d", got, want) + } + if got, want := wr.DataSize(), 4096; got != want { + t.Fatalf("Pop(st1)=%d bytes, want %d bytes", got, want) + } + + // Should go back to writing 1KB from st2. + wr, ok = ws.Pop() + if !ok { + t.Fatalf("Pop(st2.last)=false, want true") + } + if got, want := wr.StreamID(), uint32(2); got != want { + t.Fatalf("Pop(st2.last)=stream %d, want stream %d", got, want) + } + if got, want := wr.DataSize(), 1024; got != want { + t.Fatalf("Pop(st2.last)=%d bytes, want %d bytes", got, want) + } +} + +func TestPriorityWeights(t *testing.T) { + ws := defaultPriorityWriteScheduler() + ws.OpenStream(1, OpenStreamOptions{}) + ws.OpenStream(2, OpenStreamOptions{}) + + sc := &serverConn{maxFrameSize: 8} + st1 := &stream{id: 1, sc: sc} + st2 := &stream{id: 2, sc: sc} + st1.flow.add(40) + st2.flow.add(40) + + ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 40), false}, st1, nil}) + ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 40), false}, st2, nil}) + ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 34}) + ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 9}) + + // st1 gets 3.5x the bandwidth of st2 (3.5 = (34+1)/(9+1)). + // The maximum frame size is 8 bytes. The write sequence should be: + // st1, total bytes so far is (st1=8, st=0) + // st2, total bytes so far is (st1=8, st=8) + // st1, total bytes so far is (st1=16, st=8) + // st1, total bytes so far is (st1=24, st=8) // 3x bandwidth + // st1, total bytes so far is (st1=32, st=8) // 4x bandwidth + // st2, total bytes so far is (st1=32, st=16) // 2x bandwidth + // st1, total bytes so far is (st1=40, st=16) + // st2, total bytes so far is (st1=40, st=24) + // st2, total bytes so far is (st1=40, st=32) + // st2, total bytes so far is (st1=40, st=40) + if err := checkPopAll(ws, []uint32{1, 2, 1, 1, 1, 2, 1, 2, 2, 2}); err != nil { + t.Error(err) + } +} + +func TestPriorityRstStreamOnNonOpenStreams(t *testing.T) { + ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ + MaxClosedNodesInTree: 0, + MaxIdleNodesInTree: 0, + }) + ws.OpenStream(1, OpenStreamOptions{}) + ws.CloseStream(1) + ws.Push(FrameWriteRequest{write: streamError(1, ErrCodeProtocol)}) + ws.Push(FrameWriteRequest{write: streamError(2, ErrCodeProtocol)}) + + if err := checkPopAll(ws, []uint32{1, 2}); err != nil { + t.Error(err) + } +} diff --git a/vendor/golang.org/x/net/http2/writesched_random_test.go b/vendor/golang.org/x/net/http2/writesched_random_test.go new file mode 100644 index 000000000..3bf4aa36a --- /dev/null +++ b/vendor/golang.org/x/net/http2/writesched_random_test.go @@ -0,0 +1,44 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import "testing" + +func TestRandomScheduler(t *testing.T) { + ws := NewRandomWriteScheduler() + ws.Push(makeWriteHeadersRequest(3)) + ws.Push(makeWriteHeadersRequest(4)) + ws.Push(makeWriteHeadersRequest(1)) + ws.Push(makeWriteHeadersRequest(2)) + ws.Push(makeWriteNonStreamRequest()) + ws.Push(makeWriteNonStreamRequest()) + + // Pop all frames. Should get the non-stream requests first, + // followed by the stream requests in any order. + var order []FrameWriteRequest + for { + wr, ok := ws.Pop() + if !ok { + break + } + order = append(order, wr) + } + t.Logf("got frames: %v", order) + if len(order) != 6 { + t.Fatalf("got %d frames, expected 6", len(order)) + } + if order[0].StreamID() != 0 || order[1].StreamID() != 0 { + t.Fatal("expected non-stream frames first", order[0], order[1]) + } + got := make(map[uint32]bool) + for _, wr := range order[2:] { + got[wr.StreamID()] = true + } + for id := uint32(1); id <= 4; id++ { + if !got[id] { + t.Errorf("frame not found for stream %d", id) + } + } +} diff --git a/vendor/golang.org/x/net/http2/writesched_test.go b/vendor/golang.org/x/net/http2/writesched_test.go new file mode 100644 index 000000000..0807056bc --- /dev/null +++ b/vendor/golang.org/x/net/http2/writesched_test.go @@ -0,0 +1,125 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "fmt" + "math" + "reflect" + "testing" +) + +func makeWriteNonStreamRequest() FrameWriteRequest { + return FrameWriteRequest{writeSettingsAck{}, nil, nil} +} + +func makeWriteHeadersRequest(streamID uint32) FrameWriteRequest { + st := &stream{id: streamID} + return FrameWriteRequest{&writeResHeaders{streamID: streamID, httpResCode: 200}, st, nil} +} + +func checkConsume(wr FrameWriteRequest, nbytes int32, want []FrameWriteRequest) error { + consumed, rest, n := wr.Consume(nbytes) + var wantConsumed, wantRest FrameWriteRequest + switch len(want) { + case 0: + case 1: + wantConsumed = want[0] + case 2: + wantConsumed = want[0] + wantRest = want[1] + } + if !reflect.DeepEqual(consumed, wantConsumed) || !reflect.DeepEqual(rest, wantRest) || n != len(want) { + return fmt.Errorf("got %v, %v, %v\nwant %v, %v, %v", consumed, rest, n, wantConsumed, wantRest, len(want)) + } + return nil +} + +func TestFrameWriteRequestNonData(t *testing.T) { + wr := makeWriteNonStreamRequest() + if got, want := wr.DataSize(), 0; got != want { + t.Errorf("DataSize: got %v, want %v", got, want) + } + + // Non-DATA frames are always consumed whole. + if err := checkConsume(wr, 0, []FrameWriteRequest{wr}); err != nil { + t.Errorf("Consume:\n%v", err) + } +} + +func TestFrameWriteRequestData(t *testing.T) { + st := &stream{ + id: 1, + sc: &serverConn{maxFrameSize: 16}, + } + const size = 32 + wr := FrameWriteRequest{&writeData{st.id, make([]byte, size), true}, st, make(chan error)} + if got, want := wr.DataSize(), size; got != want { + t.Errorf("DataSize: got %v, want %v", got, want) + } + + // No flow-control bytes available: cannot consume anything. + if err := checkConsume(wr, math.MaxInt32, []FrameWriteRequest{}); err != nil { + t.Errorf("Consume(limited by flow control):\n%v", err) + } + + // Add enough flow-control bytes to consume the entire frame, + // but we're now restricted by st.sc.maxFrameSize. + st.flow.add(size) + want := []FrameWriteRequest{ + { + write: &writeData{st.id, make([]byte, st.sc.maxFrameSize), false}, + stream: st, + done: nil, + }, + { + write: &writeData{st.id, make([]byte, size-st.sc.maxFrameSize), true}, + stream: st, + done: wr.done, + }, + } + if err := checkConsume(wr, math.MaxInt32, want); err != nil { + t.Errorf("Consume(limited by maxFrameSize):\n%v", err) + } + rest := want[1] + + // Consume 8 bytes from the remaining frame. + want = []FrameWriteRequest{ + { + write: &writeData{st.id, make([]byte, 8), false}, + stream: st, + done: nil, + }, + { + write: &writeData{st.id, make([]byte, size-st.sc.maxFrameSize-8), true}, + stream: st, + done: wr.done, + }, + } + if err := checkConsume(rest, 8, want); err != nil { + t.Errorf("Consume(8):\n%v", err) + } + rest = want[1] + + // Consume all remaining bytes. + want = []FrameWriteRequest{ + { + write: &writeData{st.id, make([]byte, size-st.sc.maxFrameSize-8), true}, + stream: st, + done: wr.done, + }, + } + if err := checkConsume(rest, math.MaxInt32, want); err != nil { + t.Errorf("Consume(remainder):\n%v", err) + } +} + +func TestFrameWriteRequest_StreamID(t *testing.T) { + const streamID = 123 + wr := FrameWriteRequest{write: streamError(streamID, ErrCodeNo)} + if got := wr.StreamID(); got != streamID { + t.Errorf("FrameWriteRequest(StreamError) = %v; want %v", got, streamID) + } +} diff --git a/vendor/golang.org/x/net/http2/z_spec_test.go b/vendor/golang.org/x/net/http2/z_spec_test.go new file mode 100644 index 000000000..610b2cdbc --- /dev/null +++ b/vendor/golang.org/x/net/http2/z_spec_test.go @@ -0,0 +1,356 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package http2 + +import ( + "bytes" + "encoding/xml" + "flag" + "fmt" + "io" + "os" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "sync" + "testing" +) + +var coverSpec = flag.Bool("coverspec", false, "Run spec coverage tests") + +// The global map of sentence coverage for the http2 spec. +var defaultSpecCoverage specCoverage + +var loadSpecOnce sync.Once + +func loadSpec() { + if f, err := os.Open("testdata/draft-ietf-httpbis-http2.xml"); err != nil { + panic(err) + } else { + defaultSpecCoverage = readSpecCov(f) + f.Close() + } +} + +// covers marks all sentences for section sec in defaultSpecCoverage. Sentences not +// "covered" will be included in report outputted by TestSpecCoverage. +func covers(sec, sentences string) { + loadSpecOnce.Do(loadSpec) + defaultSpecCoverage.cover(sec, sentences) +} + +type specPart struct { + section string + sentence string +} + +func (ss specPart) Less(oo specPart) bool { + atoi := func(s string) int { + n, err := strconv.Atoi(s) + if err != nil { + panic(err) + } + return n + } + a := strings.Split(ss.section, ".") + b := strings.Split(oo.section, ".") + for len(a) > 0 { + if len(b) == 0 { + return false + } + x, y := atoi(a[0]), atoi(b[0]) + if x == y { + a, b = a[1:], b[1:] + continue + } + return x < y + } + if len(b) > 0 { + return true + } + return false +} + +type bySpecSection []specPart + +func (a bySpecSection) Len() int { return len(a) } +func (a bySpecSection) Less(i, j int) bool { return a[i].Less(a[j]) } +func (a bySpecSection) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +type specCoverage struct { + coverage map[specPart]bool + d *xml.Decoder +} + +func joinSection(sec []int) string { + s := fmt.Sprintf("%d", sec[0]) + for _, n := range sec[1:] { + s = fmt.Sprintf("%s.%d", s, n) + } + return s +} + +func (sc specCoverage) readSection(sec []int) { + var ( + buf = new(bytes.Buffer) + sub = 0 + ) + for { + tk, err := sc.d.Token() + if err != nil { + if err == io.EOF { + return + } + panic(err) + } + switch v := tk.(type) { + case xml.StartElement: + if skipElement(v) { + if err := sc.d.Skip(); err != nil { + panic(err) + } + if v.Name.Local == "section" { + sub++ + } + break + } + switch v.Name.Local { + case "section": + sub++ + sc.readSection(append(sec, sub)) + case "xref": + buf.Write(sc.readXRef(v)) + } + case xml.CharData: + if len(sec) == 0 { + break + } + buf.Write(v) + case xml.EndElement: + if v.Name.Local == "section" { + sc.addSentences(joinSection(sec), buf.String()) + return + } + } + } +} + +func (sc specCoverage) readXRef(se xml.StartElement) []byte { + var b []byte + for { + tk, err := sc.d.Token() + if err != nil { + panic(err) + } + switch v := tk.(type) { + case xml.CharData: + if b != nil { + panic("unexpected CharData") + } + b = []byte(string(v)) + case xml.EndElement: + if v.Name.Local != "xref" { + panic("expected </xref>") + } + if b != nil { + return b + } + sig := attrSig(se) + switch sig { + case "target": + return []byte(fmt.Sprintf("[%s]", attrValue(se, "target"))) + case "fmt-of,rel,target", "fmt-,,rel,target": + return []byte(fmt.Sprintf("[%s, %s]", attrValue(se, "target"), attrValue(se, "rel"))) + case "fmt-of,sec,target", "fmt-,,sec,target": + return []byte(fmt.Sprintf("[section %s of %s]", attrValue(se, "sec"), attrValue(se, "target"))) + case "fmt-of,rel,sec,target": + return []byte(fmt.Sprintf("[section %s of %s, %s]", attrValue(se, "sec"), attrValue(se, "target"), attrValue(se, "rel"))) + default: + panic(fmt.Sprintf("unknown attribute signature %q in %#v", sig, fmt.Sprintf("%#v", se))) + } + default: + panic(fmt.Sprintf("unexpected tag %q", v)) + } + } +} + +var skipAnchor = map[string]bool{ + "intro": true, + "Overview": true, +} + +var skipTitle = map[string]bool{ + "Acknowledgements": true, + "Change Log": true, + "Document Organization": true, + "Conventions and Terminology": true, +} + +func skipElement(s xml.StartElement) bool { + switch s.Name.Local { + case "artwork": + return true + case "section": + for _, attr := range s.Attr { + switch attr.Name.Local { + case "anchor": + if skipAnchor[attr.Value] || strings.HasPrefix(attr.Value, "changes.since.") { + return true + } + case "title": + if skipTitle[attr.Value] { + return true + } + } + } + } + return false +} + +func readSpecCov(r io.Reader) specCoverage { + sc := specCoverage{ + coverage: map[specPart]bool{}, + d: xml.NewDecoder(r)} + sc.readSection(nil) + return sc +} + +func (sc specCoverage) addSentences(sec string, sentence string) { + for _, s := range parseSentences(sentence) { + sc.coverage[specPart{sec, s}] = false + } +} + +func (sc specCoverage) cover(sec string, sentence string) { + for _, s := range parseSentences(sentence) { + p := specPart{sec, s} + if _, ok := sc.coverage[p]; !ok { + panic(fmt.Sprintf("Not found in spec: %q, %q", sec, s)) + } + sc.coverage[specPart{sec, s}] = true + } + +} + +var whitespaceRx = regexp.MustCompile(`\s+`) + +func parseSentences(sens string) []string { + sens = strings.TrimSpace(sens) + if sens == "" { + return nil + } + ss := strings.Split(whitespaceRx.ReplaceAllString(sens, " "), ". ") + for i, s := range ss { + s = strings.TrimSpace(s) + if !strings.HasSuffix(s, ".") { + s += "." + } + ss[i] = s + } + return ss +} + +func TestSpecParseSentences(t *testing.T) { + tests := []struct { + ss string + want []string + }{ + {"Sentence 1. Sentence 2.", + []string{ + "Sentence 1.", + "Sentence 2.", + }}, + {"Sentence 1. \nSentence 2.\tSentence 3.", + []string{ + "Sentence 1.", + "Sentence 2.", + "Sentence 3.", + }}, + } + + for i, tt := range tests { + got := parseSentences(tt.ss) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%d: got = %q, want %q", i, got, tt.want) + } + } +} + +func TestSpecCoverage(t *testing.T) { + if !*coverSpec { + t.Skip() + } + + loadSpecOnce.Do(loadSpec) + + var ( + list []specPart + cv = defaultSpecCoverage.coverage + total = len(cv) + complete = 0 + ) + + for sp, touched := range defaultSpecCoverage.coverage { + if touched { + complete++ + } else { + list = append(list, sp) + } + } + sort.Stable(bySpecSection(list)) + + if testing.Short() && len(list) > 5 { + list = list[:5] + } + + for _, p := range list { + t.Errorf("\tSECTION %s: %s", p.section, p.sentence) + } + + t.Logf("%d/%d (%d%%) sentences covered", complete, total, (complete/total)*100) +} + +func attrSig(se xml.StartElement) string { + var names []string + for _, attr := range se.Attr { + if attr.Name.Local == "fmt" { + names = append(names, "fmt-"+attr.Value) + } else { + names = append(names, attr.Name.Local) + } + } + sort.Strings(names) + return strings.Join(names, ",") +} + +func attrValue(se xml.StartElement, attr string) string { + for _, a := range se.Attr { + if a.Name.Local == attr { + return a.Value + } + } + panic("unknown attribute " + attr) +} + +func TestSpecPartLess(t *testing.T) { + tests := []struct { + sec1, sec2 string + want bool + }{ + {"6.2.1", "6.2", false}, + {"6.2", "6.2.1", true}, + {"6.10", "6.10.1", true}, + {"6.10", "6.1.1", false}, // 10, not 1 + {"6.1", "6.1", false}, // equal, so not less + } + for _, tt := range tests { + got := (specPart{tt.sec1, "foo"}).Less(specPart{tt.sec2, "foo"}) + if got != tt.want { + t.Errorf("Less(%q, %q) = %v; want %v", tt.sec1, tt.sec2, got, tt.want) + } + } +} diff --git a/vendor/golang.org/x/net/idna/example_test.go b/vendor/golang.org/x/net/idna/example_test.go new file mode 100644 index 000000000..948f6eb20 --- /dev/null +++ b/vendor/golang.org/x/net/idna/example_test.go @@ -0,0 +1,70 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package idna_test + +import ( + "fmt" + + "golang.org/x/net/idna" +) + +func ExampleProfile() { + // Raw Punycode has no restrictions and does no mappings. + fmt.Println(idna.ToASCII("")) + fmt.Println(idna.ToASCII("*.faß.com")) + fmt.Println(idna.Punycode.ToASCII("*.faß.com")) + + // Rewrite IDN for lookup. This (currently) uses transitional mappings to + // find a balance between IDNA2003 and IDNA2008 compatibility. + fmt.Println(idna.Lookup.ToASCII("")) + fmt.Println(idna.Lookup.ToASCII("www.faß.com")) + + // Convert an IDN to ASCII for registration purposes. This changes the + // encoding, but reports an error if the input was illformed. + fmt.Println(idna.Registration.ToASCII("")) + fmt.Println(idna.Registration.ToASCII("www.faß.com")) + + // Output: + // <nil> + // *.xn--fa-hia.com <nil> + // *.xn--fa-hia.com <nil> + // <nil> + // www.fass.com <nil> + // idna: invalid label "" + // www.xn--fa-hia.com <nil> +} + +func ExampleNew() { + var p *idna.Profile + + // Raw Punycode has no restrictions and does no mappings. + p = idna.New() + fmt.Println(p.ToASCII("*.faß.com")) + + // Do mappings. Note that star is not allowed in a DNS lookup. + p = idna.New( + idna.MapForLookup(), + idna.Transitional(true)) // Map ß -> ss + fmt.Println(p.ToASCII("*.faß.com")) + + // Lookup for registration. Also does not allow '*'. + p = idna.New(idna.ValidateForRegistration()) + fmt.Println(p.ToUnicode("*.faß.com")) + + // Set up a profile maps for lookup, but allows wild cards. + p = idna.New( + idna.MapForLookup(), + idna.Transitional(true), // Map ß -> ss + idna.StrictDomainName(false)) // Set more permissive ASCII rules. + fmt.Println(p.ToASCII("*.faß.com")) + + // Output: + // *.xn--fa-hia.com <nil> + // *.fass.com idna: disallowed rune U+002A + // *.faß.com idna: disallowed rune U+002A + // *.fass.com <nil> +} diff --git a/vendor/golang.org/x/net/idna/idna_test.go b/vendor/golang.org/x/net/idna/idna_test.go new file mode 100644 index 000000000..0b067cac9 --- /dev/null +++ b/vendor/golang.org/x/net/idna/idna_test.go @@ -0,0 +1,108 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package idna + +import ( + "testing" +) + +var idnaTestCases = [...]struct { + ascii, unicode string +}{ + // Labels. + {"books", "books"}, + {"xn--bcher-kva", "bücher"}, + + // Domains. + {"foo--xn--bar.org", "foo--xn--bar.org"}, + {"golang.org", "golang.org"}, + {"example.xn--p1ai", "example.рф"}, + {"xn--czrw28b.tw", "商業.tw"}, + {"www.xn--mller-kva.de", "www.müller.de"}, +} + +func TestIDNA(t *testing.T) { + for _, tc := range idnaTestCases { + if a, err := ToASCII(tc.unicode); err != nil { + t.Errorf("ToASCII(%q): %v", tc.unicode, err) + } else if a != tc.ascii { + t.Errorf("ToASCII(%q): got %q, want %q", tc.unicode, a, tc.ascii) + } + + if u, err := ToUnicode(tc.ascii); err != nil { + t.Errorf("ToUnicode(%q): %v", tc.ascii, err) + } else if u != tc.unicode { + t.Errorf("ToUnicode(%q): got %q, want %q", tc.ascii, u, tc.unicode) + } + } +} + +func TestIDNASeparators(t *testing.T) { + type subCase struct { + unicode string + wantASCII string + wantErr bool + } + + testCases := []struct { + name string + profile *Profile + subCases []subCase + }{ + { + name: "Punycode", profile: Punycode, + subCases: []subCase{ + {"example\u3002jp", "xn--examplejp-ck3h", false}, + {"東京\uFF0Ejp", "xn--jp-l92cn98g071o", false}, + {"大阪\uFF61jp", "xn--jp-ku9cz72u463f", false}, + }, + }, + { + name: "Lookup", profile: Lookup, + subCases: []subCase{ + {"example\u3002jp", "example.jp", false}, + {"東京\uFF0Ejp", "xn--1lqs71d.jp", false}, + {"大阪\uFF61jp", "xn--pssu33l.jp", false}, + }, + }, + { + name: "Display", profile: Display, + subCases: []subCase{ + {"example\u3002jp", "example.jp", false}, + {"東京\uFF0Ejp", "xn--1lqs71d.jp", false}, + {"大阪\uFF61jp", "xn--pssu33l.jp", false}, + }, + }, + { + name: "Registration", profile: Registration, + subCases: []subCase{ + {"example\u3002jp", "", true}, + {"東京\uFF0Ejp", "", true}, + {"大阪\uFF61jp", "", true}, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + for _, c := range tc.subCases { + gotA, err := tc.profile.ToASCII(c.unicode) + if c.wantErr { + if err == nil { + t.Errorf("ToASCII(%q): got no error, but an error expected", c.unicode) + } + } else { + if err != nil { + t.Errorf("ToASCII(%q): got err=%v, but no error expected", c.unicode, err) + } else if gotA != c.wantASCII { + t.Errorf("ToASCII(%q): got %q, want %q", c.unicode, gotA, c.wantASCII) + } + } + } + }) + } +} + +// TODO(nigeltao): test errors, once we've specified when ToASCII and ToUnicode +// return errors. diff --git a/vendor/golang.org/x/net/idna/punycode_test.go b/vendor/golang.org/x/net/idna/punycode_test.go new file mode 100644 index 000000000..bfec81dec --- /dev/null +++ b/vendor/golang.org/x/net/idna/punycode_test.go @@ -0,0 +1,198 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package idna + +import ( + "strings" + "testing" +) + +var punycodeTestCases = [...]struct { + s, encoded string +}{ + {"", ""}, + {"-", "--"}, + {"-a", "-a-"}, + {"-a-", "-a--"}, + {"a", "a-"}, + {"a-", "a--"}, + {"a-b", "a-b-"}, + {"books", "books-"}, + {"bücher", "bcher-kva"}, + {"Hello世界", "Hello-ck1hg65u"}, + {"ü", "tda"}, + {"üý", "tdac"}, + + // The test cases below come from RFC 3492 section 7.1 with Errata 3026. + { + // (A) Arabic (Egyptian). + "\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" + + "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F", + "egbpdaj6bu4bxfgehfvwxn", + }, + { + // (B) Chinese (simplified). + "\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587", + "ihqwcrb4cv8a8dqg056pqjye", + }, + { + // (C) Chinese (traditional). + "\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587", + "ihqwctvzc91f659drss3x8bo0yb", + }, + { + // (D) Czech. + "\u0050\u0072\u006F\u010D\u0070\u0072\u006F\u0073\u0074" + + "\u011B\u006E\u0065\u006D\u006C\u0075\u0076\u00ED\u010D" + + "\u0065\u0073\u006B\u0079", + "Proprostnemluvesky-uyb24dma41a", + }, + { + // (E) Hebrew. + "\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8" + + "\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2" + + "\u05D1\u05E8\u05D9\u05EA", + "4dbcagdahymbxekheh6e0a7fei0b", + }, + { + // (F) Hindi (Devanagari). + "\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D" + + "\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939" + + "\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947" + + "\u0939\u0948\u0902", + "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd", + }, + { + // (G) Japanese (kanji and hiragana). + "\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092" + + "\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B", + "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa", + }, + { + // (H) Korean (Hangul syllables). + "\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774" + + "\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74" + + "\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C", + "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5j" + + "psd879ccm6fea98c", + }, + { + // (I) Russian (Cyrillic). + "\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E" + + "\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440" + + "\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A" + + "\u0438", + "b1abfaaepdrnnbgefbadotcwatmq2g4l", + }, + { + // (J) Spanish. + "\u0050\u006F\u0072\u0071\u0075\u00E9\u006E\u006F\u0070" + + "\u0075\u0065\u0064\u0065\u006E\u0073\u0069\u006D\u0070" + + "\u006C\u0065\u006D\u0065\u006E\u0074\u0065\u0068\u0061" + + "\u0062\u006C\u0061\u0072\u0065\u006E\u0045\u0073\u0070" + + "\u0061\u00F1\u006F\u006C", + "PorqunopuedensimplementehablarenEspaol-fmd56a", + }, + { + // (K) Vietnamese. + "\u0054\u1EA1\u0069\u0073\u0061\u006F\u0068\u1ECD\u006B" + + "\u0068\u00F4\u006E\u0067\u0074\u0068\u1EC3\u0063\u0068" + + "\u1EC9\u006E\u00F3\u0069\u0074\u0069\u1EBF\u006E\u0067" + + "\u0056\u0069\u1EC7\u0074", + "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g", + }, + { + // (L) 3<nen>B<gumi><kinpachi><sensei>. + "\u0033\u5E74\u0042\u7D44\u91D1\u516B\u5148\u751F", + "3B-ww4c5e180e575a65lsy2b", + }, + { + // (M) <amuro><namie>-with-SUPER-MONKEYS. + "\u5B89\u5BA4\u5948\u7F8E\u6075\u002D\u0077\u0069\u0074" + + "\u0068\u002D\u0053\u0055\u0050\u0045\u0052\u002D\u004D" + + "\u004F\u004E\u004B\u0045\u0059\u0053", + "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n", + }, + { + // (N) Hello-Another-Way-<sorezore><no><basho>. + "\u0048\u0065\u006C\u006C\u006F\u002D\u0041\u006E\u006F" + + "\u0074\u0068\u0065\u0072\u002D\u0057\u0061\u0079\u002D" + + "\u305D\u308C\u305E\u308C\u306E\u5834\u6240", + "Hello-Another-Way--fc4qua05auwb3674vfr0b", + }, + { + // (O) <hitotsu><yane><no><shita>2. + "\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B\u0032", + "2-u9tlzr9756bt3uc0v", + }, + { + // (P) Maji<de>Koi<suru>5<byou><mae> + "\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" + + "\u308B\u0035\u79D2\u524D", + "MajiKoi5-783gue6qz075azm5e", + }, + { + // (Q) <pafii>de<runba> + "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", + "de-jg4avhby1noc0d", + }, + { + // (R) <sono><supiido><de> + "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067", + "d9juau41awczczp", + }, + { + // (S) -> $1.00 <- + "\u002D\u003E\u0020\u0024\u0031\u002E\u0030\u0030\u0020" + + "\u003C\u002D", + "-> $1.00 <--", + }, +} + +func TestPunycode(t *testing.T) { + for _, tc := range punycodeTestCases { + if got, err := decode(tc.encoded); err != nil { + t.Errorf("decode(%q): %v", tc.encoded, err) + } else if got != tc.s { + t.Errorf("decode(%q): got %q, want %q", tc.encoded, got, tc.s) + } + + if got, err := encode("", tc.s); err != nil { + t.Errorf(`encode("", %q): %v`, tc.s, err) + } else if got != tc.encoded { + t.Errorf(`encode("", %q): got %q, want %q`, tc.s, got, tc.encoded) + } + } +} + +var punycodeErrorTestCases = [...]string{ + "decode -", // A sole '-' is invalid. + "decode foo\x00bar", // '\x00' is not in [0-9A-Za-z]. + "decode foo#bar", // '#' is not in [0-9A-Za-z]. + "decode foo\u00A3bar", // '\u00A3' is not in [0-9A-Za-z]. + "decode 9", // "9a" decodes to codepoint \u00A3; "9" is truncated. + "decode 99999a", // "99999a" decodes to codepoint \U0048A3C1, which is > \U0010FFFF. + "decode 9999999999a", // "9999999999a" overflows the int32 calculation. + + "encode " + strings.Repeat("x", 65536) + "\uff00", // int32 overflow. +} + +func TestPunycodeErrors(t *testing.T) { + for _, tc := range punycodeErrorTestCases { + var err error + switch { + case strings.HasPrefix(tc, "decode "): + _, err = decode(tc[7:]) + case strings.HasPrefix(tc, "encode "): + _, err = encode("", tc[7:]) + } + if err == nil { + if len(tc) > 256 { + tc = tc[:100] + "..." + tc[len(tc)-100:] + } + t.Errorf("no error for %s", tc) + } + } +} diff --git a/vendor/golang.org/x/oauth2/.travis.yml b/vendor/golang.org/x/oauth2/.travis.yml new file mode 100644 index 000000000..fa139db22 --- /dev/null +++ b/vendor/golang.org/x/oauth2/.travis.yml @@ -0,0 +1,13 @@ +language: go + +go: + - tip + +install: + - export GOPATH="$HOME/gopath" + - mkdir -p "$GOPATH/src/golang.org/x" + - mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/golang.org/x/oauth2" + - go get -v -t -d golang.org/x/oauth2/... + +script: + - go test -v golang.org/x/oauth2/... diff --git a/vendor/golang.org/x/oauth2/CONTRIBUTING.md b/vendor/golang.org/x/oauth2/CONTRIBUTING.md new file mode 100644 index 000000000..dfbed62cf --- /dev/null +++ b/vendor/golang.org/x/oauth2/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://github.com/golang/oauth2/issues), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/oauth2/README.md b/vendor/golang.org/x/oauth2/README.md new file mode 100644 index 000000000..eb8dcee17 --- /dev/null +++ b/vendor/golang.org/x/oauth2/README.md @@ -0,0 +1,77 @@ +# OAuth2 for Go + +[![Build Status](https://travis-ci.org/golang/oauth2.svg?branch=master)](https://travis-ci.org/golang/oauth2) +[![GoDoc](https://godoc.org/golang.org/x/oauth2?status.svg)](https://godoc.org/golang.org/x/oauth2) + +oauth2 package contains a client implementation for OAuth 2.0 spec. + +## Installation + +~~~~ +go get golang.org/x/oauth2 +~~~~ + +Or you can manually git clone the repository to +`$(go env GOPATH)/src/golang.org/x/oauth2`. + +See godoc for further documentation and examples. + +* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2) +* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google) + + +## App Engine + +In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor +of the [`context.Context`](https://golang.org/x/net/context#Context) type from +the `golang.org/x/net/context` package + +This means it's no longer possible to use the "Classic App Engine" +`appengine.Context` type with the `oauth2` package. (You're using +Classic App Engine if you import the package `"appengine"`.) + +To work around this, you may use the new `"google.golang.org/appengine"` +package. This package has almost the same API as the `"appengine"` package, +but it can be fetched with `go get` and used on "Managed VMs" and well as +Classic App Engine. + +See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app) +for information on updating your app. + +If you don't want to update your entire app to use the new App Engine packages, +you may use both sets of packages in parallel, using only the new packages +with the `oauth2` package. + +```go +import ( + "golang.org/x/net/context" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + newappengine "google.golang.org/appengine" + newurlfetch "google.golang.org/appengine/urlfetch" + + "appengine" +) + +func handler(w http.ResponseWriter, r *http.Request) { + var c appengine.Context = appengine.NewContext(r) + c.Infof("Logging a message with the old package") + + var ctx context.Context = newappengine.NewContext(r) + client := &http.Client{ + Transport: &oauth2.Transport{ + Source: google.AppEngineTokenSource(ctx, "scope"), + Base: &newurlfetch.Transport{Context: ctx}, + }, + } + client.Get("...") +} +``` + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the oauth2 repository is located at +https://github.com/golang/oauth2/issues. diff --git a/vendor/golang.org/x/oauth2/example_test.go b/vendor/golang.org/x/oauth2/example_test.go new file mode 100644 index 000000000..fc2f793b2 --- /dev/null +++ b/vendor/golang.org/x/oauth2/example_test.go @@ -0,0 +1,89 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package oauth2_test + +import ( + "context" + "fmt" + "log" + "net/http" + "time" + + "golang.org/x/oauth2" +) + +func ExampleConfig() { + ctx := context.Background() + conf := &oauth2.Config{ + ClientID: "YOUR_CLIENT_ID", + ClientSecret: "YOUR_CLIENT_SECRET", + Scopes: []string{"SCOPE1", "SCOPE2"}, + Endpoint: oauth2.Endpoint{ + AuthURL: "https://provider.com/o/oauth2/auth", + TokenURL: "https://provider.com/o/oauth2/token", + }, + } + + // Redirect user to consent page to ask for permission + // for the scopes specified above. + url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline) + fmt.Printf("Visit the URL for the auth dialog: %v", url) + + // Use the authorization code that is pushed to the redirect + // URL. Exchange will do the handshake to retrieve the + // initial access token. The HTTP Client returned by + // conf.Client will refresh the token as necessary. + var code string + if _, err := fmt.Scan(&code); err != nil { + log.Fatal(err) + } + tok, err := conf.Exchange(ctx, code) + if err != nil { + log.Fatal(err) + } + + client := conf.Client(ctx, tok) + client.Get("...") +} + +func ExampleConfig_customHTTP() { + ctx := context.Background() + + conf := &oauth2.Config{ + ClientID: "YOUR_CLIENT_ID", + ClientSecret: "YOUR_CLIENT_SECRET", + Scopes: []string{"SCOPE1", "SCOPE2"}, + Endpoint: oauth2.Endpoint{ + TokenURL: "https://provider.com/o/oauth2/token", + AuthURL: "https://provider.com/o/oauth2/auth", + }, + } + + // Redirect user to consent page to ask for permission + // for the scopes specified above. + url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline) + fmt.Printf("Visit the URL for the auth dialog: %v", url) + + // Use the authorization code that is pushed to the redirect + // URL. Exchange will do the handshake to retrieve the + // initial access token. The HTTP Client returned by + // conf.Client will refresh the token as necessary. + var code string + if _, err := fmt.Scan(&code); err != nil { + log.Fatal(err) + } + + // Use the custom HTTP client when requesting a token. + httpClient := &http.Client{Timeout: 2 * time.Second} + ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) + + tok, err := conf.Exchange(ctx, code) + if err != nil { + log.Fatal(err) + } + + client := conf.Client(ctx, tok) + _ = client +} diff --git a/vendor/golang.org/x/oauth2/google/example_test.go b/vendor/golang.org/x/oauth2/google/example_test.go new file mode 100644 index 000000000..643f50716 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/example_test.go @@ -0,0 +1,162 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package google_test + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + + "golang.org/x/net/context" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + "golang.org/x/oauth2/jwt" + "google.golang.org/appengine" + "google.golang.org/appengine/urlfetch" +) + +func ExampleDefaultClient() { + client, err := google.DefaultClient(oauth2.NoContext, + "https://www.googleapis.com/auth/devstorage.full_control") + if err != nil { + log.Fatal(err) + } + client.Get("...") +} + +func Example_webServer() { + // Your credentials should be obtained from the Google + // Developer Console (https://console.developers.google.com). + conf := &oauth2.Config{ + ClientID: "YOUR_CLIENT_ID", + ClientSecret: "YOUR_CLIENT_SECRET", + RedirectURL: "YOUR_REDIRECT_URL", + Scopes: []string{ + "https://www.googleapis.com/auth/bigquery", + "https://www.googleapis.com/auth/blogger", + }, + Endpoint: google.Endpoint, + } + // Redirect user to Google's consent page to ask for permission + // for the scopes specified above. + url := conf.AuthCodeURL("state") + fmt.Printf("Visit the URL for the auth dialog: %v", url) + + // Handle the exchange code to initiate a transport. + tok, err := conf.Exchange(oauth2.NoContext, "authorization-code") + if err != nil { + log.Fatal(err) + } + client := conf.Client(oauth2.NoContext, tok) + client.Get("...") +} + +func ExampleJWTConfigFromJSON() { + // Your credentials should be obtained from the Google + // Developer Console (https://console.developers.google.com). + // Navigate to your project, then see the "Credentials" page + // under "APIs & Auth". + // To create a service account client, click "Create new Client ID", + // select "Service Account", and click "Create Client ID". A JSON + // key file will then be downloaded to your computer. + data, err := ioutil.ReadFile("/path/to/your-project-key.json") + if err != nil { + log.Fatal(err) + } + conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/bigquery") + if err != nil { + log.Fatal(err) + } + // Initiate an http.Client. The following GET request will be + // authorized and authenticated on the behalf of + // your service account. + client := conf.Client(oauth2.NoContext) + client.Get("...") +} + +func ExampleSDKConfig() { + // The credentials will be obtained from the first account that + // has been authorized with `gcloud auth login`. + conf, err := google.NewSDKConfig("") + if err != nil { + log.Fatal(err) + } + // Initiate an http.Client. The following GET request will be + // authorized and authenticated on the behalf of the SDK user. + client := conf.Client(oauth2.NoContext) + client.Get("...") +} + +func Example_serviceAccount() { + // Your credentials should be obtained from the Google + // Developer Console (https://console.developers.google.com). + conf := &jwt.Config{ + Email: "xxx@developer.gserviceaccount.com", + // The contents of your RSA private key or your PEM file + // that contains a private key. + // If you have a p12 file instead, you + // can use `openssl` to export the private key into a pem file. + // + // $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes + // + // The field only supports PEM containers with no passphrase. + // The openssl command will convert p12 keys to passphrase-less PEM containers. + PrivateKey: []byte("-----BEGIN RSA PRIVATE KEY-----..."), + Scopes: []string{ + "https://www.googleapis.com/auth/bigquery", + "https://www.googleapis.com/auth/blogger", + }, + TokenURL: google.JWTTokenURL, + // If you would like to impersonate a user, you can + // create a transport with a subject. The following GET + // request will be made on the behalf of user@example.com. + // Optional. + Subject: "user@example.com", + } + // Initiate an http.Client, the following GET request will be + // authorized and authenticated on the behalf of user@example.com. + client := conf.Client(oauth2.NoContext) + client.Get("...") +} + +func ExampleAppEngineTokenSource() { + var req *http.Request // from the ServeHTTP handler + ctx := appengine.NewContext(req) + client := &http.Client{ + Transport: &oauth2.Transport{ + Source: google.AppEngineTokenSource(ctx, "https://www.googleapis.com/auth/bigquery"), + Base: &urlfetch.Transport{ + Context: ctx, + }, + }, + } + client.Get("...") +} + +func ExampleComputeTokenSource() { + client := &http.Client{ + Transport: &oauth2.Transport{ + // Fetch from Google Compute Engine's metadata server to retrieve + // an access token for the provided account. + // If no account is specified, "default" is used. + Source: google.ComputeTokenSource(""), + }, + } + client.Get("...") +} + +func ExampleCredentialsFromJSON() { + ctx := context.Background() + data, err := ioutil.ReadFile("/path/to/key-file.json") + if err != nil { + log.Fatal(err) + } + creds, err := google.CredentialsFromJSON(ctx, data, "https://www.googleapis.com/auth/bigquery") + if err != nil { + log.Fatal(err) + } + _ = creds // TODO: Use creds. +} diff --git a/vendor/golang.org/x/oauth2/google/google_test.go b/vendor/golang.org/x/oauth2/google/google_test.go new file mode 100644 index 000000000..287c699e7 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/google_test.go @@ -0,0 +1,116 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package google + +import ( + "strings" + "testing" +) + +var webJSONKey = []byte(` +{ + "web": { + "auth_uri": "https://google.com/o/oauth2/auth", + "client_secret": "3Oknc4jS_wA2r9i", + "token_uri": "https://google.com/o/oauth2/token", + "client_email": "222-nprqovg5k43uum874cs9osjt2koe97g8@developer.gserviceaccount.com", + "redirect_uris": ["https://www.example.com/oauth2callback"], + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/222-nprqovg5k43uum874cs9osjt2koe97g8@developer.gserviceaccount.com", + "client_id": "222-nprqovg5k43uum874cs9osjt2koe97g8.apps.googleusercontent.com", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "javascript_origins": ["https://www.example.com"] + } +}`) + +var installedJSONKey = []byte(`{ + "installed": { + "client_id": "222-installed.apps.googleusercontent.com", + "redirect_uris": ["https://www.example.com/oauth2callback"] + } +}`) + +var jwtJSONKey = []byte(`{ + "private_key_id": "268f54e43a1af97cfc71731688434f45aca15c8b", + "private_key": "super secret key", + "client_email": "gopher@developer.gserviceaccount.com", + "client_id": "gopher.apps.googleusercontent.com", + "token_uri": "https://accounts.google.com/o/gophers/token", + "type": "service_account" +}`) + +var jwtJSONKeyNoTokenURL = []byte(`{ + "private_key_id": "268f54e43a1af97cfc71731688434f45aca15c8b", + "private_key": "super secret key", + "client_email": "gopher@developer.gserviceaccount.com", + "client_id": "gopher.apps.googleusercontent.com", + "type": "service_account" +}`) + +func TestConfigFromJSON(t *testing.T) { + conf, err := ConfigFromJSON(webJSONKey, "scope1", "scope2") + if err != nil { + t.Error(err) + } + if got, want := conf.ClientID, "222-nprqovg5k43uum874cs9osjt2koe97g8.apps.googleusercontent.com"; got != want { + t.Errorf("ClientID = %q; want %q", got, want) + } + if got, want := conf.ClientSecret, "3Oknc4jS_wA2r9i"; got != want { + t.Errorf("ClientSecret = %q; want %q", got, want) + } + if got, want := conf.RedirectURL, "https://www.example.com/oauth2callback"; got != want { + t.Errorf("RedictURL = %q; want %q", got, want) + } + if got, want := strings.Join(conf.Scopes, ","), "scope1,scope2"; got != want { + t.Errorf("Scopes = %q; want %q", got, want) + } + if got, want := conf.Endpoint.AuthURL, "https://google.com/o/oauth2/auth"; got != want { + t.Errorf("AuthURL = %q; want %q", got, want) + } + if got, want := conf.Endpoint.TokenURL, "https://google.com/o/oauth2/token"; got != want { + t.Errorf("TokenURL = %q; want %q", got, want) + } +} + +func TestConfigFromJSON_Installed(t *testing.T) { + conf, err := ConfigFromJSON(installedJSONKey) + if err != nil { + t.Error(err) + } + if got, want := conf.ClientID, "222-installed.apps.googleusercontent.com"; got != want { + t.Errorf("ClientID = %q; want %q", got, want) + } +} + +func TestJWTConfigFromJSON(t *testing.T) { + conf, err := JWTConfigFromJSON(jwtJSONKey, "scope1", "scope2") + if err != nil { + t.Fatal(err) + } + if got, want := conf.Email, "gopher@developer.gserviceaccount.com"; got != want { + t.Errorf("Email = %q, want %q", got, want) + } + if got, want := string(conf.PrivateKey), "super secret key"; got != want { + t.Errorf("PrivateKey = %q, want %q", got, want) + } + if got, want := conf.PrivateKeyID, "268f54e43a1af97cfc71731688434f45aca15c8b"; got != want { + t.Errorf("PrivateKeyID = %q, want %q", got, want) + } + if got, want := strings.Join(conf.Scopes, ","), "scope1,scope2"; got != want { + t.Errorf("Scopes = %q; want %q", got, want) + } + if got, want := conf.TokenURL, "https://accounts.google.com/o/gophers/token"; got != want { + t.Errorf("TokenURL = %q; want %q", got, want) + } +} + +func TestJWTConfigFromJSONNoTokenURL(t *testing.T) { + conf, err := JWTConfigFromJSON(jwtJSONKeyNoTokenURL, "scope1", "scope2") + if err != nil { + t.Fatal(err) + } + if got, want := conf.TokenURL, "https://accounts.google.com/o/oauth2/token"; got != want { + t.Errorf("TokenURL = %q; want %q", got, want) + } +} diff --git a/vendor/golang.org/x/oauth2/google/jwt_test.go b/vendor/golang.org/x/oauth2/google/jwt_test.go new file mode 100644 index 000000000..f844436fc --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/jwt_test.go @@ -0,0 +1,91 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package google + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "strings" + "testing" + "time" + + "golang.org/x/oauth2/jws" +) + +func TestJWTAccessTokenSourceFromJSON(t *testing.T) { + // Generate a key we can use in the test data. + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + + // Encode the key and substitute into our example JSON. + enc := pem.EncodeToMemory(&pem.Block{ + Type: "PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(privateKey), + }) + enc, err = json.Marshal(string(enc)) + if err != nil { + t.Fatalf("json.Marshal: %v", err) + } + jsonKey := bytes.Replace(jwtJSONKey, []byte(`"super secret key"`), enc, 1) + + ts, err := JWTAccessTokenSourceFromJSON(jsonKey, "audience") + if err != nil { + t.Fatalf("JWTAccessTokenSourceFromJSON: %v\nJSON: %s", err, string(jsonKey)) + } + + tok, err := ts.Token() + if err != nil { + t.Fatalf("Token: %v", err) + } + + if got, want := tok.TokenType, "Bearer"; got != want { + t.Errorf("TokenType = %q, want %q", got, want) + } + if got := tok.Expiry; tok.Expiry.Before(time.Now()) { + t.Errorf("Expiry = %v, should not be expired", got) + } + + err = jws.Verify(tok.AccessToken, &privateKey.PublicKey) + if err != nil { + t.Errorf("jws.Verify on AccessToken: %v", err) + } + + claim, err := jws.Decode(tok.AccessToken) + if err != nil { + t.Fatalf("jws.Decode on AccessToken: %v", err) + } + + if got, want := claim.Iss, "gopher@developer.gserviceaccount.com"; got != want { + t.Errorf("Iss = %q, want %q", got, want) + } + if got, want := claim.Sub, "gopher@developer.gserviceaccount.com"; got != want { + t.Errorf("Sub = %q, want %q", got, want) + } + if got, want := claim.Aud, "audience"; got != want { + t.Errorf("Aud = %q, want %q", got, want) + } + + // Finally, check the header private key. + parts := strings.Split(tok.AccessToken, ".") + hdrJSON, err := base64.RawURLEncoding.DecodeString(parts[0]) + if err != nil { + t.Fatalf("base64 DecodeString: %v\nString: %q", err, parts[0]) + } + var hdr jws.Header + if err := json.Unmarshal([]byte(hdrJSON), &hdr); err != nil { + t.Fatalf("json.Unmarshal: %v (%q)", err, hdrJSON) + } + + if got, want := hdr.KeyID, "268f54e43a1af97cfc71731688434f45aca15c8b"; got != want { + t.Errorf("Header KeyID = %q, want %q", got, want) + } +} diff --git a/vendor/golang.org/x/oauth2/google/sdk_test.go b/vendor/golang.org/x/oauth2/google/sdk_test.go new file mode 100644 index 000000000..52b8ecada --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/sdk_test.go @@ -0,0 +1,107 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package google + +import ( + "reflect" + "strings" + "testing" +) + +func TestSDKConfig(t *testing.T) { + sdkConfigPath = func() (string, error) { + return "testdata/gcloud", nil + } + + tests := []struct { + account string + accessToken string + err bool + }{ + {"", "bar_access_token", false}, + {"foo@example.com", "foo_access_token", false}, + {"bar@example.com", "bar_access_token", false}, + {"baz@serviceaccount.example.com", "", true}, + } + for _, tt := range tests { + c, err := NewSDKConfig(tt.account) + if got, want := err != nil, tt.err; got != want { + if !tt.err { + t.Errorf("got %v, want nil", err) + } else { + t.Errorf("got nil, want error") + } + continue + } + if err != nil { + continue + } + tok := c.initialToken + if tok == nil { + t.Errorf("got nil, want %q", tt.accessToken) + continue + } + if tok.AccessToken != tt.accessToken { + t.Errorf("got %q, want %q", tok.AccessToken, tt.accessToken) + } + } +} + +func TestParseINI(t *testing.T) { + tests := []struct { + ini string + want map[string]map[string]string + }{ + { + `root = toor +[foo] +bar = hop +ini = nin +`, + map[string]map[string]string{ + "": {"root": "toor"}, + "foo": {"bar": "hop", "ini": "nin"}, + }, + }, + { + "\t extra \t = whitespace \t\r\n \t [everywhere] \t \r\n here \t = \t there \t \r\n", + map[string]map[string]string{ + "": {"extra": "whitespace"}, + "everywhere": {"here": "there"}, + }, + }, + { + `[empty] +[section] +empty= +`, + map[string]map[string]string{ + "": {}, + "empty": {}, + "section": {"empty": ""}, + }, + }, + { + `ignore +[invalid +=stuff +;comment=true +`, + map[string]map[string]string{ + "": {}, + }, + }, + } + for _, tt := range tests { + result, err := parseINI(strings.NewReader(tt.ini)) + if err != nil { + t.Errorf("parseINI(%q) error %v, want: no error", tt.ini, err) + continue + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("parseINI(%q) = %#v, want: %#v", tt.ini, result, tt.want) + } + } +} diff --git a/vendor/golang.org/x/oauth2/internal/token_test.go b/vendor/golang.org/x/oauth2/internal/token_test.go new file mode 100644 index 000000000..7b52e511f --- /dev/null +++ b/vendor/golang.org/x/oauth2/internal/token_test.go @@ -0,0 +1,112 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +import ( + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "golang.org/x/net/context" +) + +func TestRegisterBrokenAuthHeaderProvider(t *testing.T) { + RegisterBrokenAuthHeaderProvider("https://aaa.com/") + tokenURL := "https://aaa.com/token" + if providerAuthHeaderWorks(tokenURL) { + t.Errorf("got %q as unbroken; want broken", tokenURL) + } +} + +func TestRetrieveTokenBustedNoSecret(t *testing.T) { + const clientID = "client-id" + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if got, want := r.FormValue("client_id"), clientID; got != want { + t.Errorf("client_id = %q; want %q", got, want) + } + if got, want := r.FormValue("client_secret"), ""; got != want { + t.Errorf("client_secret = %q; want empty", got) + } + w.Header().Set("Content-Type", "application/json") + io.WriteString(w, `{"access_token": "ACCESS_TOKEN", "token_type": "bearer"}`) + })) + defer ts.Close() + + RegisterBrokenAuthHeaderProvider(ts.URL) + _, err := RetrieveToken(context.Background(), clientID, "", ts.URL, url.Values{}) + if err != nil { + t.Errorf("RetrieveToken = %v; want no error", err) + } +} + +func Test_providerAuthHeaderWorks(t *testing.T) { + for _, p := range brokenAuthHeaderProviders { + if providerAuthHeaderWorks(p) { + t.Errorf("got %q as unbroken; want broken", p) + } + p := fmt.Sprintf("%ssomesuffix", p) + if providerAuthHeaderWorks(p) { + t.Errorf("got %q as unbroken; want broken", p) + } + } + p := "https://api.not-in-the-list-example.com/" + if !providerAuthHeaderWorks(p) { + t.Errorf("got %q as unbroken; want broken", p) + } +} + +func TestProviderAuthHeaderWorksDomain(t *testing.T) { + tests := []struct { + tokenURL string + wantWorks bool + }{ + {"https://dev-12345.okta.com/token-url", false}, + {"https://dev-12345.oktapreview.com/token-url", false}, + {"https://dev-12345.okta.org/token-url", true}, + {"https://foo.bar.force.com/token-url", false}, + {"https://foo.force.com/token-url", false}, + {"https://force.com/token-url", true}, + } + + for _, test := range tests { + got := providerAuthHeaderWorks(test.tokenURL) + if got != test.wantWorks { + t.Errorf("providerAuthHeaderWorks(%q) = %v; want %v", test.tokenURL, got, test.wantWorks) + } + } +} + +func TestRetrieveTokenWithContexts(t *testing.T) { + const clientID = "client-id" + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + io.WriteString(w, `{"access_token": "ACCESS_TOKEN", "token_type": "bearer"}`) + })) + defer ts.Close() + + _, err := RetrieveToken(context.Background(), clientID, "", ts.URL, url.Values{}) + if err != nil { + t.Errorf("RetrieveToken (with background context) = %v; want no error", err) + } + + retrieved := make(chan struct{}) + cancellingts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + <-retrieved + })) + defer cancellingts.Close() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + _, err = RetrieveToken(ctx, clientID, "", cancellingts.URL, url.Values{}) + close(retrieved) + if err == nil { + t.Errorf("RetrieveToken (with cancelled context) = nil; want error") + } +} diff --git a/vendor/golang.org/x/oauth2/jws/jws_test.go b/vendor/golang.org/x/oauth2/jws/jws_test.go new file mode 100644 index 000000000..39a136a29 --- /dev/null +++ b/vendor/golang.org/x/oauth2/jws/jws_test.go @@ -0,0 +1,46 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package jws + +import ( + "crypto/rand" + "crypto/rsa" + "testing" +) + +func TestSignAndVerify(t *testing.T) { + header := &Header{ + Algorithm: "RS256", + Typ: "JWT", + } + payload := &ClaimSet{ + Iss: "http://google.com/", + Aud: "", + Exp: 3610, + Iat: 10, + } + + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + + token, err := Encode(header, payload, privateKey) + if err != nil { + t.Fatal(err) + } + + err = Verify(token, &privateKey.PublicKey) + if err != nil { + t.Fatal(err) + } +} + +func TestVerifyFailsOnMalformedClaim(t *testing.T) { + err := Verify("abc.def", nil) + if err == nil { + t.Error("got no errors; want improperly formed JWT not to be verified") + } +} diff --git a/vendor/golang.org/x/oauth2/jwt/example_test.go b/vendor/golang.org/x/oauth2/jwt/example_test.go new file mode 100644 index 000000000..58503d80d --- /dev/null +++ b/vendor/golang.org/x/oauth2/jwt/example_test.go @@ -0,0 +1,33 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package jwt_test + +import ( + "context" + + "golang.org/x/oauth2/jwt" +) + +func ExampleJWTConfig() { + ctx := context.Background() + conf := &jwt.Config{ + Email: "xxx@developer.com", + // The contents of your RSA private key or your PEM file + // that contains a private key. + // If you have a p12 file instead, you + // can use `openssl` to export the private key into a pem file. + // + // $ openssl pkcs12 -in key.p12 -out key.pem -nodes + // + // It only supports PEM containers with no passphrase. + PrivateKey: []byte("-----BEGIN RSA PRIVATE KEY-----..."), + Subject: "user@example.com", + TokenURL: "https://provider.com/o/oauth2/token", + } + // Initiate an http.Client, the following GET request will be + // authorized and authenticated on the behalf of user@example.com. + client := conf.Client(ctx) + client.Get("...") +} diff --git a/vendor/golang.org/x/oauth2/jwt/jwt_test.go b/vendor/golang.org/x/oauth2/jwt/jwt_test.go new file mode 100644 index 000000000..1fbb9aa7d --- /dev/null +++ b/vendor/golang.org/x/oauth2/jwt/jwt_test.go @@ -0,0 +1,221 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package jwt + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/jws" +) + +var dummyPrivateKey = []byte(`-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAx4fm7dngEmOULNmAs1IGZ9Apfzh+BkaQ1dzkmbUgpcoghucE +DZRnAGd2aPyB6skGMXUytWQvNYav0WTR00wFtX1ohWTfv68HGXJ8QXCpyoSKSSFY +fuP9X36wBSkSX9J5DVgiuzD5VBdzUISSmapjKm+DcbRALjz6OUIPEWi1Tjl6p5RK +1w41qdbmt7E5/kGhKLDuT7+M83g4VWhgIvaAXtnhklDAggilPPa8ZJ1IFe31lNlr +k4DRk38nc6sEutdf3RL7QoH7FBusI7uXV03DC6dwN1kP4GE7bjJhcRb/7jYt7CQ9 +/E9Exz3c0yAp0yrTg0Fwh+qxfH9dKwN52S7SBwIDAQABAoIBAQCaCs26K07WY5Jt +3a2Cw3y2gPrIgTCqX6hJs7O5ByEhXZ8nBwsWANBUe4vrGaajQHdLj5OKfsIDrOvn +2NI1MqflqeAbu/kR32q3tq8/Rl+PPiwUsW3E6Pcf1orGMSNCXxeducF2iySySzh3 +nSIhCG5uwJDWI7a4+9KiieFgK1pt/Iv30q1SQS8IEntTfXYwANQrfKUVMmVF9aIK +6/WZE2yd5+q3wVVIJ6jsmTzoDCX6QQkkJICIYwCkglmVy5AeTckOVwcXL0jqw5Kf +5/soZJQwLEyBoQq7Kbpa26QHq+CJONetPP8Ssy8MJJXBT+u/bSseMb3Zsr5cr43e +DJOhwsThAoGBAPY6rPKl2NT/K7XfRCGm1sbWjUQyDShscwuWJ5+kD0yudnT/ZEJ1 +M3+KS/iOOAoHDdEDi9crRvMl0UfNa8MAcDKHflzxg2jg/QI+fTBjPP5GOX0lkZ9g +z6VePoVoQw2gpPFVNPPTxKfk27tEzbaffvOLGBEih0Kb7HTINkW8rIlzAoGBAM9y +1yr+jvfS1cGFtNU+Gotoihw2eMKtIqR03Yn3n0PK1nVCDKqwdUqCypz4+ml6cxRK +J8+Pfdh7D+ZJd4LEG6Y4QRDLuv5OA700tUoSHxMSNn3q9As4+T3MUyYxWKvTeu3U +f2NWP9ePU0lV8ttk7YlpVRaPQmc1qwooBA/z/8AdAoGAW9x0HWqmRICWTBnpjyxx +QGlW9rQ9mHEtUotIaRSJ6K/F3cxSGUEkX1a3FRnp6kPLcckC6NlqdNgNBd6rb2rA +cPl/uSkZP42Als+9YMoFPU/xrrDPbUhu72EDrj3Bllnyb168jKLa4VBOccUvggxr +Dm08I1hgYgdN5huzs7y6GeUCgYEAj+AZJSOJ6o1aXS6rfV3mMRve9bQ9yt8jcKXw +5HhOCEmMtaSKfnOF1Ziih34Sxsb7O2428DiX0mV/YHtBnPsAJidL0SdLWIapBzeg +KHArByIRkwE6IvJvwpGMdaex1PIGhx5i/3VZL9qiq/ElT05PhIb+UXgoWMabCp84 +OgxDK20CgYAeaFo8BdQ7FmVX2+EEejF+8xSge6WVLtkaon8bqcn6P0O8lLypoOhd +mJAYH8WU+UAy9pecUnDZj14LAGNVmYcse8HFX71MoshnvCTFEPVo4rZxIAGwMpeJ +5jgQ3slYLpqrGlcbLgUXBUgzEO684Wk/UV9DFPlHALVqCfXQ9dpJPg== +-----END RSA PRIVATE KEY-----`) + +func TestJWTFetch_JSONResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{ + "access_token": "90d64460d14870c08c81352a05dedd3465940a7c", + "scope": "user", + "token_type": "bearer", + "expires_in": 3600 + }`)) + })) + defer ts.Close() + + conf := &Config{ + Email: "aaa@xxx.com", + PrivateKey: dummyPrivateKey, + TokenURL: ts.URL, + } + tok, err := conf.TokenSource(context.Background()).Token() + if err != nil { + t.Fatal(err) + } + if !tok.Valid() { + t.Errorf("got invalid token: %v", tok) + } + if got, want := tok.AccessToken, "90d64460d14870c08c81352a05dedd3465940a7c"; got != want { + t.Errorf("access token = %q; want %q", got, want) + } + if got, want := tok.TokenType, "bearer"; got != want { + t.Errorf("token type = %q; want %q", got, want) + } + if got := tok.Expiry.IsZero(); got { + t.Errorf("token expiry = %v, want none", got) + } + scope := tok.Extra("scope") + if got, want := scope, "user"; got != want { + t.Errorf("scope = %q; want %q", got, want) + } +} + +func TestJWTFetch_BadResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"scope": "user", "token_type": "bearer"}`)) + })) + defer ts.Close() + + conf := &Config{ + Email: "aaa@xxx.com", + PrivateKey: dummyPrivateKey, + TokenURL: ts.URL, + } + tok, err := conf.TokenSource(context.Background()).Token() + if err != nil { + t.Fatal(err) + } + if tok == nil { + t.Fatalf("got nil token; want token") + } + if tok.Valid() { + t.Errorf("got invalid token: %v", tok) + } + if got, want := tok.AccessToken, ""; got != want { + t.Errorf("access token = %q; want %q", got, want) + } + if got, want := tok.TokenType, "bearer"; got != want { + t.Errorf("token type = %q; want %q", got, want) + } + scope := tok.Extra("scope") + if got, want := scope, "user"; got != want { + t.Errorf("token scope = %q; want %q", got, want) + } +} + +func TestJWTFetch_BadResponseType(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"access_token":123, "scope": "user", "token_type": "bearer"}`)) + })) + defer ts.Close() + conf := &Config{ + Email: "aaa@xxx.com", + PrivateKey: dummyPrivateKey, + TokenURL: ts.URL, + } + tok, err := conf.TokenSource(context.Background()).Token() + if err == nil { + t.Error("got a token; expected error") + if got, want := tok.AccessToken, ""; got != want { + t.Errorf("access token = %q; want %q", got, want) + } + } +} + +func TestJWTFetch_Assertion(t *testing.T) { + var assertion string + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + assertion = r.Form.Get("assertion") + + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{ + "access_token": "90d64460d14870c08c81352a05dedd3465940a7c", + "scope": "user", + "token_type": "bearer", + "expires_in": 3600 + }`)) + })) + defer ts.Close() + + conf := &Config{ + Email: "aaa@xxx.com", + PrivateKey: dummyPrivateKey, + PrivateKeyID: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + TokenURL: ts.URL, + } + + _, err := conf.TokenSource(context.Background()).Token() + if err != nil { + t.Fatalf("Failed to fetch token: %v", err) + } + + parts := strings.Split(assertion, ".") + if len(parts) != 3 { + t.Fatalf("assertion = %q; want 3 parts", assertion) + } + gotjson, err := base64.RawURLEncoding.DecodeString(parts[0]) + if err != nil { + t.Fatalf("invalid token header; err = %v", err) + } + + got := jws.Header{} + if err := json.Unmarshal(gotjson, &got); err != nil { + t.Errorf("failed to unmarshal json token header = %q; err = %v", gotjson, err) + } + + want := jws.Header{ + Algorithm: "RS256", + Typ: "JWT", + KeyID: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + } + if got != want { + t.Errorf("access token header = %q; want %q", got, want) + } +} + +func TestTokenRetrieveError(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-type", "application/json") + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`{"error": "invalid_grant"}`)) + })) + defer ts.Close() + + conf := &Config{ + Email: "aaa@xxx.com", + PrivateKey: dummyPrivateKey, + TokenURL: ts.URL, + } + + _, err := conf.TokenSource(context.Background()).Token() + if err == nil { + t.Fatalf("got no error, expected one") + } + _, ok := err.(*oauth2.RetrieveError) + if !ok { + t.Fatalf("got %T error, expected *RetrieveError", err) + } + // Test error string for backwards compatibility + expected := fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", "400 Bad Request", `{"error": "invalid_grant"}`) + if errStr := err.Error(); errStr != expected { + t.Fatalf("got %#v, expected %#v", errStr, expected) + } +} diff --git a/vendor/golang.org/x/oauth2/oauth2_test.go b/vendor/golang.org/x/oauth2/oauth2_test.go new file mode 100644 index 000000000..847160f91 --- /dev/null +++ b/vendor/golang.org/x/oauth2/oauth2_test.go @@ -0,0 +1,505 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package oauth2 + +import ( + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "golang.org/x/net/context" +) + +type mockTransport struct { + rt func(req *http.Request) (resp *http.Response, err error) +} + +func (t *mockTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { + return t.rt(req) +} + +func newConf(url string) *Config { + return &Config{ + ClientID: "CLIENT_ID", + ClientSecret: "CLIENT_SECRET", + RedirectURL: "REDIRECT_URL", + Scopes: []string{"scope1", "scope2"}, + Endpoint: Endpoint{ + AuthURL: url + "/auth", + TokenURL: url + "/token", + }, + } +} + +func TestAuthCodeURL(t *testing.T) { + conf := newConf("server") + url := conf.AuthCodeURL("foo", AccessTypeOffline, ApprovalForce) + const want = "server/auth?access_type=offline&approval_prompt=force&client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=foo" + if got := url; got != want { + t.Errorf("got auth code URL = %q; want %q", got, want) + } +} + +func TestAuthCodeURL_CustomParam(t *testing.T) { + conf := newConf("server") + param := SetAuthURLParam("foo", "bar") + url := conf.AuthCodeURL("baz", param) + const want = "server/auth?client_id=CLIENT_ID&foo=bar&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=baz" + if got := url; got != want { + t.Errorf("got auth code = %q; want %q", got, want) + } +} + +func TestAuthCodeURL_Optional(t *testing.T) { + conf := &Config{ + ClientID: "CLIENT_ID", + Endpoint: Endpoint{ + AuthURL: "/auth-url", + TokenURL: "/token-url", + }, + } + url := conf.AuthCodeURL("") + const want = "/auth-url?client_id=CLIENT_ID&response_type=code" + if got := url; got != want { + t.Fatalf("got auth code = %q; want %q", got, want) + } +} + +func TestURLUnsafeClientConfig(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Authorization"), "Basic Q0xJRU5UX0lEJTNGJTNGOkNMSUVOVF9TRUNSRVQlM0YlM0Y="; got != want { + t.Errorf("Authorization header = %q; want %q", got, want) + } + + w.Header().Set("Content-Type", "application/x-www-form-urlencoded") + w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) + })) + defer ts.Close() + conf := newConf(ts.URL) + conf.ClientID = "CLIENT_ID??" + conf.ClientSecret = "CLIENT_SECRET??" + _, err := conf.Exchange(context.Background(), "exchange-code") + if err != nil { + t.Error(err) + } +} + +func TestExchangeRequest(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() != "/token" { + t.Errorf("Unexpected exchange request URL, %v is found.", r.URL) + } + headerAuth := r.Header.Get("Authorization") + if headerAuth != "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" { + t.Errorf("Unexpected authorization header, %v is found.", headerAuth) + } + headerContentType := r.Header.Get("Content-Type") + if headerContentType != "application/x-www-form-urlencoded" { + t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) + } + body, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("Failed reading request body: %s.", err) + } + if string(body) != "code=exchange-code&grant_type=authorization_code&redirect_uri=REDIRECT_URL" { + t.Errorf("Unexpected exchange payload, %v is found.", string(body)) + } + w.Header().Set("Content-Type", "application/x-www-form-urlencoded") + w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) + })) + defer ts.Close() + conf := newConf(ts.URL) + tok, err := conf.Exchange(context.Background(), "exchange-code") + if err != nil { + t.Error(err) + } + if !tok.Valid() { + t.Fatalf("Token invalid. Got: %#v", tok) + } + if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" { + t.Errorf("Unexpected access token, %#v.", tok.AccessToken) + } + if tok.TokenType != "bearer" { + t.Errorf("Unexpected token type, %#v.", tok.TokenType) + } + scope := tok.Extra("scope") + if scope != "user" { + t.Errorf("Unexpected value for scope: %v", scope) + } +} + +func TestExchangeRequest_JSONResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() != "/token" { + t.Errorf("Unexpected exchange request URL, %v is found.", r.URL) + } + headerAuth := r.Header.Get("Authorization") + if headerAuth != "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" { + t.Errorf("Unexpected authorization header, %v is found.", headerAuth) + } + headerContentType := r.Header.Get("Content-Type") + if headerContentType != "application/x-www-form-urlencoded" { + t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) + } + body, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("Failed reading request body: %s.", err) + } + if string(body) != "code=exchange-code&grant_type=authorization_code&redirect_uri=REDIRECT_URL" { + t.Errorf("Unexpected exchange payload, %v is found.", string(body)) + } + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"access_token": "90d64460d14870c08c81352a05dedd3465940a7c", "scope": "user", "token_type": "bearer", "expires_in": 86400}`)) + })) + defer ts.Close() + conf := newConf(ts.URL) + tok, err := conf.Exchange(context.Background(), "exchange-code") + if err != nil { + t.Error(err) + } + if !tok.Valid() { + t.Fatalf("Token invalid. Got: %#v", tok) + } + if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" { + t.Errorf("Unexpected access token, %#v.", tok.AccessToken) + } + if tok.TokenType != "bearer" { + t.Errorf("Unexpected token type, %#v.", tok.TokenType) + } + scope := tok.Extra("scope") + if scope != "user" { + t.Errorf("Unexpected value for scope: %v", scope) + } + expiresIn := tok.Extra("expires_in") + if expiresIn != float64(86400) { + t.Errorf("Unexpected non-numeric value for expires_in: %v", expiresIn) + } +} + +func TestExtraValueRetrieval(t *testing.T) { + values := url.Values{} + kvmap := map[string]string{ + "scope": "user", "token_type": "bearer", "expires_in": "86400.92", + "server_time": "1443571905.5606415", "referer_ip": "10.0.0.1", + "etag": "\"afZYj912P4alikMz_P11982\"", "request_id": "86400", + "untrimmed": " untrimmed ", + } + for key, value := range kvmap { + values.Set(key, value) + } + + tok := Token{raw: values} + scope := tok.Extra("scope") + if got, want := scope, "user"; got != want { + t.Errorf("got scope = %q; want %q", got, want) + } + serverTime := tok.Extra("server_time") + if got, want := serverTime, 1443571905.5606415; got != want { + t.Errorf("got server_time value = %v; want %v", got, want) + } + refererIP := tok.Extra("referer_ip") + if got, want := refererIP, "10.0.0.1"; got != want { + t.Errorf("got referer_ip value = %v, want %v", got, want) + } + expiresIn := tok.Extra("expires_in") + if got, want := expiresIn, 86400.92; got != want { + t.Errorf("got expires_in value = %v, want %v", got, want) + } + requestID := tok.Extra("request_id") + if got, want := requestID, int64(86400); got != want { + t.Errorf("got request_id value = %v, want %v", got, want) + } + untrimmed := tok.Extra("untrimmed") + if got, want := untrimmed, " untrimmed "; got != want { + t.Errorf("got untrimmed = %q; want %q", got, want) + } +} + +const day = 24 * time.Hour + +func TestExchangeRequest_JSONResponse_Expiry(t *testing.T) { + seconds := int32(day.Seconds()) + for _, c := range []struct { + expires string + want bool + }{ + {fmt.Sprintf(`"expires_in": %d`, seconds), true}, + {fmt.Sprintf(`"expires_in": "%d"`, seconds), true}, // PayPal case + {fmt.Sprintf(`"expires": %d`, seconds), true}, // Facebook case + {`"expires": false`, false}, // wrong type + {`"expires": {}`, false}, // wrong type + {`"expires": "zzz"`, false}, // wrong value + } { + testExchangeRequest_JSONResponse_expiry(t, c.expires, c.want) + } +} + +func testExchangeRequest_JSONResponse_expiry(t *testing.T, exp string, want bool) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(fmt.Sprintf(`{"access_token": "90d", "scope": "user", "token_type": "bearer", %s}`, exp))) + })) + defer ts.Close() + conf := newConf(ts.URL) + t1 := time.Now().Add(day) + tok, err := conf.Exchange(context.Background(), "exchange-code") + t2 := time.Now().Add(day) + + if got := (err == nil); got != want { + if want { + t.Errorf("unexpected error: got %v", err) + } else { + t.Errorf("unexpected success") + } + } + if !want { + return + } + if !tok.Valid() { + t.Fatalf("Token invalid. Got: %#v", tok) + } + expiry := tok.Expiry + if expiry.Before(t1) || expiry.After(t2) { + t.Errorf("Unexpected value for Expiry: %v (shold be between %v and %v)", expiry, t1, t2) + } +} + +func TestExchangeRequest_BadResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"scope": "user", "token_type": "bearer"}`)) + })) + defer ts.Close() + conf := newConf(ts.URL) + _, err := conf.Exchange(context.Background(), "code") + if err == nil { + t.Error("expected error from missing access_token") + } +} + +func TestExchangeRequest_BadResponseType(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"access_token":123, "scope": "user", "token_type": "bearer"}`)) + })) + defer ts.Close() + conf := newConf(ts.URL) + _, err := conf.Exchange(context.Background(), "exchange-code") + if err == nil { + t.Error("expected error from non-string access_token") + } +} + +func TestExchangeRequest_NonBasicAuth(t *testing.T) { + tr := &mockTransport{ + rt: func(r *http.Request) (w *http.Response, err error) { + headerAuth := r.Header.Get("Authorization") + if headerAuth != "" { + t.Errorf("Unexpected authorization header, %v is found.", headerAuth) + } + return nil, errors.New("no response") + }, + } + c := &http.Client{Transport: tr} + conf := &Config{ + ClientID: "CLIENT_ID", + Endpoint: Endpoint{ + AuthURL: "https://accounts.google.com/auth", + TokenURL: "https://accounts.google.com/token", + }, + } + + ctx := context.WithValue(context.Background(), HTTPClient, c) + conf.Exchange(ctx, "code") +} + +func TestPasswordCredentialsTokenRequest(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + expected := "/token" + if r.URL.String() != expected { + t.Errorf("URL = %q; want %q", r.URL, expected) + } + headerAuth := r.Header.Get("Authorization") + expected = "Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=" + if headerAuth != expected { + t.Errorf("Authorization header = %q; want %q", headerAuth, expected) + } + headerContentType := r.Header.Get("Content-Type") + expected = "application/x-www-form-urlencoded" + if headerContentType != expected { + t.Errorf("Content-Type header = %q; want %q", headerContentType, expected) + } + body, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("Failed reading request body: %s.", err) + } + expected = "grant_type=password&password=password1&scope=scope1+scope2&username=user1" + if string(body) != expected { + t.Errorf("res.Body = %q; want %q", string(body), expected) + } + w.Header().Set("Content-Type", "application/x-www-form-urlencoded") + w.Write([]byte("access_token=90d64460d14870c08c81352a05dedd3465940a7c&scope=user&token_type=bearer")) + })) + defer ts.Close() + conf := newConf(ts.URL) + tok, err := conf.PasswordCredentialsToken(context.Background(), "user1", "password1") + if err != nil { + t.Error(err) + } + if !tok.Valid() { + t.Fatalf("Token invalid. Got: %#v", tok) + } + expected := "90d64460d14870c08c81352a05dedd3465940a7c" + if tok.AccessToken != expected { + t.Errorf("AccessToken = %q; want %q", tok.AccessToken, expected) + } + expected = "bearer" + if tok.TokenType != expected { + t.Errorf("TokenType = %q; want %q", tok.TokenType, expected) + } +} + +func TestTokenRefreshRequest(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() == "/somethingelse" { + return + } + if r.URL.String() != "/token" { + t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL) + } + headerContentType := r.Header.Get("Content-Type") + if headerContentType != "application/x-www-form-urlencoded" { + t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) + } + body, _ := ioutil.ReadAll(r.Body) + if string(body) != "grant_type=refresh_token&refresh_token=REFRESH_TOKEN" { + t.Errorf("Unexpected refresh token payload, %v is found.", string(body)) + } + })) + defer ts.Close() + conf := newConf(ts.URL) + c := conf.Client(context.Background(), &Token{RefreshToken: "REFRESH_TOKEN"}) + c.Get(ts.URL + "/somethingelse") +} + +func TestFetchWithNoRefreshToken(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() == "/somethingelse" { + return + } + if r.URL.String() != "/token" { + t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL) + } + headerContentType := r.Header.Get("Content-Type") + if headerContentType != "application/x-www-form-urlencoded" { + t.Errorf("Unexpected Content-Type header, %v is found.", headerContentType) + } + body, _ := ioutil.ReadAll(r.Body) + if string(body) != "client_id=CLIENT_ID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN" { + t.Errorf("Unexpected refresh token payload, %v is found.", string(body)) + } + })) + defer ts.Close() + conf := newConf(ts.URL) + c := conf.Client(context.Background(), nil) + _, err := c.Get(ts.URL + "/somethingelse") + if err == nil { + t.Errorf("Fetch should return an error if no refresh token is set") + } +} + +func TestTokenRetrieveError(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.String() != "/token" { + t.Errorf("Unexpected token refresh request URL, %v is found.", r.URL) + } + w.Header().Set("Content-type", "application/json") + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`{"error": "invalid_grant"}`)) + })) + defer ts.Close() + conf := newConf(ts.URL) + _, err := conf.Exchange(context.Background(), "exchange-code") + if err == nil { + t.Fatalf("got no error, expected one") + } + _, ok := err.(*RetrieveError) + if !ok { + t.Fatalf("got %T error, expected *RetrieveError", err) + } + // Test error string for backwards compatibility + expected := fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", "400 Bad Request", `{"error": "invalid_grant"}`) + if errStr := err.Error(); errStr != expected { + t.Fatalf("got %#v, expected %#v", errStr, expected) + } +} + +func TestRefreshToken_RefreshTokenReplacement(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"access_token":"ACCESS_TOKEN", "scope": "user", "token_type": "bearer", "refresh_token": "NEW_REFRESH_TOKEN"}`)) + return + })) + defer ts.Close() + conf := newConf(ts.URL) + tkr := conf.TokenSource(context.Background(), &Token{RefreshToken: "OLD_REFRESH_TOKEN"}) + tk, err := tkr.Token() + if err != nil { + t.Errorf("got err = %v; want none", err) + return + } + if want := "NEW_REFRESH_TOKEN"; tk.RefreshToken != want { + t.Errorf("RefreshToken = %q; want %q", tk.RefreshToken, want) + } +} + +func TestRefreshToken_RefreshTokenPreservation(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"access_token":"ACCESS_TOKEN", "scope": "user", "token_type": "bearer"}`)) + return + })) + defer ts.Close() + conf := newConf(ts.URL) + const oldRefreshToken = "OLD_REFRESH_TOKEN" + tkr := conf.TokenSource(context.Background(), &Token{RefreshToken: oldRefreshToken}) + tk, err := tkr.Token() + if err != nil { + t.Fatalf("got err = %v; want none", err) + } + if tk.RefreshToken != oldRefreshToken { + t.Errorf("RefreshToken = %q; want %q", tk.RefreshToken, oldRefreshToken) + } +} + +func TestConfigClientWithToken(t *testing.T) { + tok := &Token{ + AccessToken: "abc123", + } + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Authorization"), fmt.Sprintf("Bearer %s", tok.AccessToken); got != want { + t.Errorf("Authorization header = %q; want %q", got, want) + } + return + })) + defer ts.Close() + conf := newConf(ts.URL) + + c := conf.Client(context.Background(), tok) + req, err := http.NewRequest("GET", ts.URL, nil) + if err != nil { + t.Error(err) + } + _, err = c.Do(req) + if err != nil { + t.Error(err) + } +} diff --git a/vendor/golang.org/x/oauth2/token_test.go b/vendor/golang.org/x/oauth2/token_test.go new file mode 100644 index 000000000..80db83c29 --- /dev/null +++ b/vendor/golang.org/x/oauth2/token_test.go @@ -0,0 +1,72 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package oauth2 + +import ( + "testing" + "time" +) + +func TestTokenExtra(t *testing.T) { + type testCase struct { + key string + val interface{} + want interface{} + } + const key = "extra-key" + cases := []testCase{ + {key: key, val: "abc", want: "abc"}, + {key: key, val: 123, want: 123}, + {key: key, val: "", want: ""}, + {key: "other-key", val: "def", want: nil}, + } + for _, tc := range cases { + extra := make(map[string]interface{}) + extra[tc.key] = tc.val + tok := &Token{raw: extra} + if got, want := tok.Extra(key), tc.want; got != want { + t.Errorf("Extra(%q) = %q; want %q", key, got, want) + } + } +} + +func TestTokenExpiry(t *testing.T) { + now := time.Now() + cases := []struct { + name string + tok *Token + want bool + }{ + {name: "12 seconds", tok: &Token{Expiry: now.Add(12 * time.Second)}, want: false}, + {name: "10 seconds", tok: &Token{Expiry: now.Add(expiryDelta)}, want: true}, + {name: "-1 hour", tok: &Token{Expiry: now.Add(-1 * time.Hour)}, want: true}, + } + for _, tc := range cases { + if got, want := tc.tok.expired(), tc.want; got != want { + t.Errorf("expired (%q) = %v; want %v", tc.name, got, want) + } + } +} + +func TestTokenTypeMethod(t *testing.T) { + cases := []struct { + name string + tok *Token + want string + }{ + {name: "bearer-mixed_case", tok: &Token{TokenType: "beAREr"}, want: "Bearer"}, + {name: "default-bearer", tok: &Token{}, want: "Bearer"}, + {name: "basic", tok: &Token{TokenType: "basic"}, want: "Basic"}, + {name: "basic-capitalized", tok: &Token{TokenType: "Basic"}, want: "Basic"}, + {name: "mac", tok: &Token{TokenType: "mac"}, want: "MAC"}, + {name: "mac-caps", tok: &Token{TokenType: "MAC"}, want: "MAC"}, + {name: "mac-mixed_case", tok: &Token{TokenType: "mAc"}, want: "MAC"}, + } + for _, tc := range cases { + if got, want := tc.tok.Type(), tc.want; got != want { + t.Errorf("TokenType(%q) = %v; want %v", tc.name, got, want) + } + } +} diff --git a/vendor/golang.org/x/oauth2/transport_test.go b/vendor/golang.org/x/oauth2/transport_test.go new file mode 100644 index 000000000..d6e8087d6 --- /dev/null +++ b/vendor/golang.org/x/oauth2/transport_test.go @@ -0,0 +1,108 @@ +package oauth2 + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" +) + +type tokenSource struct{ token *Token } + +func (t *tokenSource) Token() (*Token, error) { + return t.token, nil +} + +func TestTransportNilTokenSource(t *testing.T) { + tr := &Transport{} + server := newMockServer(func(w http.ResponseWriter, r *http.Request) {}) + defer server.Close() + client := &http.Client{Transport: tr} + resp, err := client.Get(server.URL) + if err == nil { + t.Errorf("got no errors, want an error with nil token source") + } + if resp != nil { + t.Errorf("Response = %v; want nil", resp) + } +} + +func TestTransportTokenSource(t *testing.T) { + ts := &tokenSource{ + token: &Token{ + AccessToken: "abc", + }, + } + tr := &Transport{ + Source: ts, + } + server := newMockServer(func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Authorization"), "Bearer abc"; got != want { + t.Errorf("Authorization header = %q; want %q", got, want) + } + }) + defer server.Close() + client := &http.Client{Transport: tr} + res, err := client.Get(server.URL) + if err != nil { + t.Fatal(err) + } + res.Body.Close() +} + +// Test for case-sensitive token types, per https://github.com/golang/oauth2/issues/113 +func TestTransportTokenSourceTypes(t *testing.T) { + const val = "abc" + tests := []struct { + key string + val string + want string + }{ + {key: "bearer", val: val, want: "Bearer abc"}, + {key: "mac", val: val, want: "MAC abc"}, + {key: "basic", val: val, want: "Basic abc"}, + } + for _, tc := range tests { + ts := &tokenSource{ + token: &Token{ + AccessToken: tc.val, + TokenType: tc.key, + }, + } + tr := &Transport{ + Source: ts, + } + server := newMockServer(func(w http.ResponseWriter, r *http.Request) { + if got, want := r.Header.Get("Authorization"), tc.want; got != want { + t.Errorf("Authorization header (%q) = %q; want %q", val, got, want) + } + }) + defer server.Close() + client := &http.Client{Transport: tr} + res, err := client.Get(server.URL) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + } +} + +func TestTokenValidNoAccessToken(t *testing.T) { + token := &Token{} + if token.Valid() { + t.Errorf("got valid with no access token; want invalid") + } +} + +func TestExpiredWithExpiry(t *testing.T) { + token := &Token{ + Expiry: time.Now().Add(-5 * time.Hour), + } + if token.Valid() { + t.Errorf("got valid with expired token; want invalid") + } +} + +func newMockServer(handler func(w http.ResponseWriter, r *http.Request)) *httptest.Server { + return httptest.NewServer(http.HandlerFunc(handler)) +} diff --git a/vendor/golang.org/x/sys/.gitattributes b/vendor/golang.org/x/sys/.gitattributes new file mode 100644 index 000000000..d2f212e5d --- /dev/null +++ b/vendor/golang.org/x/sys/.gitattributes @@ -0,0 +1,10 @@ +# Treat all files in this repo as binary, with no git magic updating +# line endings. Windows users contributing to Go will need to use a +# modern version of git and editors capable of LF line endings. +# +# We'll prevent accidental CRLF line endings from entering the repo +# via the git-review gofmt checks. +# +# See golang.org/issue/9281 + +* -text diff --git a/vendor/golang.org/x/sys/.gitignore b/vendor/golang.org/x/sys/.gitignore new file mode 100644 index 000000000..8339fd61d --- /dev/null +++ b/vendor/golang.org/x/sys/.gitignore @@ -0,0 +1,2 @@ +# Add no patterns to .hgignore except for files generated by the build. +last-change diff --git a/vendor/golang.org/x/sys/CONTRIBUTING.md b/vendor/golang.org/x/sys/CONTRIBUTING.md new file mode 100644 index 000000000..d0485e887 --- /dev/null +++ b/vendor/golang.org/x/sys/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/sys/README.md b/vendor/golang.org/x/sys/README.md new file mode 100644 index 000000000..ef6c9e59c --- /dev/null +++ b/vendor/golang.org/x/sys/README.md @@ -0,0 +1,18 @@ +# sys + +This repository holds supplemental Go packages for low-level interactions with +the operating system. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/sys`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/sys`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the sys repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/sys:" in the +subject line, so it is easy to find. diff --git a/vendor/golang.org/x/sys/codereview.cfg b/vendor/golang.org/x/sys/codereview.cfg new file mode 100644 index 000000000..3f8b14b64 --- /dev/null +++ b/vendor/golang.org/x/sys/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/sys/unix/.gitignore b/vendor/golang.org/x/sys/unix/.gitignore new file mode 100644 index 000000000..e3e0fc6f8 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/.gitignore @@ -0,0 +1,2 @@ +_obj/ +unix.test diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md new file mode 100644 index 000000000..bc6f6031f --- /dev/null +++ b/vendor/golang.org/x/sys/unix/README.md @@ -0,0 +1,173 @@ +# Building `sys/unix` + +The sys/unix package provides access to the raw system call interface of the +underlying operating system. See: https://godoc.org/golang.org/x/sys/unix + +Porting Go to a new architecture/OS combination or adding syscalls, types, or +constants to an existing architecture/OS pair requires some manual effort; +however, there are tools that automate much of the process. + +## Build Systems + +There are currently two ways we generate the necessary files. We are currently +migrating the build system to use containers so the builds are reproducible. +This is being done on an OS-by-OS basis. Please update this documentation as +components of the build system change. + +### Old Build System (currently for `GOOS != "Linux" || GOARCH == "sparc64"`) + +The old build system generates the Go files based on the C header files +present on your system. This means that files +for a given GOOS/GOARCH pair must be generated on a system with that OS and +architecture. This also means that the generated code can differ from system +to system, based on differences in the header files. + +To avoid this, if you are using the old build system, only generate the Go +files on an installation with unmodified header files. It is also important to +keep track of which version of the OS the files were generated from (ex. +Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes +and have each OS upgrade correspond to a single change. + +To build the files for your current OS and architecture, make sure GOOS and +GOARCH are set correctly and run `mkall.sh`. This will generate the files for +your specific system. Running `mkall.sh -n` shows the commands that will be run. + +Requirements: bash, perl, go + +### New Build System (currently for `GOOS == "Linux" && GOARCH != "sparc64"`) + +The new build system uses a Docker container to generate the go files directly +from source checkouts of the kernel and various system libraries. This means +that on any platform that supports Docker, all the files using the new build +system can be generated at once, and generated files will not change based on +what the person running the scripts has installed on their computer. + +The OS specific files for the new build system are located in the `${GOOS}` +directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When +the kernel or system library updates, modify the Dockerfile at +`${GOOS}/Dockerfile` to checkout the new release of the source. + +To build all the files under the new build system, you must be on an amd64/Linux +system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will +then generate all of the files for all of the GOOS/GOARCH pairs in the new build +system. Running `mkall.sh -n` shows the commands that will be run. + +Requirements: bash, perl, go, docker + +## Component files + +This section describes the various files used in the code generation process. +It also contains instructions on how to modify these files to add a new +architecture/OS or to add additional syscalls, types, or constants. Note that +if you are using the new build system, the scripts cannot be called normally. +They must be called from within the docker container. + +### asm files + +The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system +call dispatch. There are three entry points: +``` + func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) + func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) + func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) +``` +The first and second are the standard ones; they differ only in how many +arguments can be passed to the kernel. The third is for low-level use by the +ForkExec wrapper. Unlike the first two, it does not call into the scheduler to +let it know that a system call is running. + +When porting Go to an new architecture/OS, this file must be implemented for +each GOOS/GOARCH pair. + +### mksysnum + +Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl` +for the old system). This script takes in a list of header files containing the +syscall number declarations and parses them to produce the corresponding list of +Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated +constants. + +Adding new syscall numbers is mostly done by running the build on a sufficiently +new installation of the target OS (or updating the source checkouts for the +new build system). However, depending on the OS, you make need to update the +parsing in mksysnum. + +### mksyscall.pl + +The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are +hand-written Go files which implement system calls (for unix, the specific OS, +or the specific OS/Architecture pair respectively) that need special handling +and list `//sys` comments giving prototypes for ones that can be generated. + +The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts +them into syscalls. This requires the name of the prototype in the comment to +match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function +prototype can be exported (capitalized) or not. + +Adding a new syscall often just requires adding a new `//sys` function prototype +with the desired arguments and a capitalized name so it is exported. However, if +you want the interface to the syscall to be different, often one will make an +unexported `//sys` prototype, an then write a custom wrapper in +`syscall_${GOOS}.go`. + +### types files + +For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or +`types_${GOOS}.go` on the old system). This file includes standard C headers and +creates Go type aliases to the corresponding C types. The file is then fed +through godef to get the Go compatible definitions. Finally, the generated code +is fed though mkpost.go to format the code correctly and remove any hidden or +private identifiers. This cleaned-up code is written to +`ztypes_${GOOS}_${GOARCH}.go`. + +The hardest part about preparing this file is figuring out which headers to +include and which symbols need to be `#define`d to get the actual data +structures that pass through to the kernel system calls. Some C libraries +preset alternate versions for binary compatibility and translate them on the +way in and out of system calls, but there is almost always a `#define` that can +get the real ones. +See `types_darwin.go` and `linux/types.go` for examples. + +To add a new type, add in the necessary include statement at the top of the +file (if it is not already there) and add in a type alias line. Note that if +your type is significantly different on different architectures, you may need +some `#if/#elif` macros in your include statements. + +### mkerrors.sh + +This script is used to generate the system's various constants. This doesn't +just include the error numbers and error strings, but also the signal numbers +an a wide variety of miscellaneous constants. The constants come from the list +of include files in the `includes_${uname}` variable. A regex then picks out +the desired `#define` statements, and generates the corresponding Go constants. +The error numbers and strings are generated from `#include <errno.h>`, and the +signal numbers and strings are generated from `#include <signal.h>`. All of +these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program, +`_errors.c`, which prints out all the constants. + +To add a constant, add the header that includes it to the appropriate variable. +Then, edit the regex (if necessary) to match the desired constant. Avoid making +the regex too broad to avoid matching unintended constants. + + +## Generated files + +### `zerror_${GOOS}_${GOARCH}.go` + +A file containing all of the system's generated error numbers, error strings, +signal numbers, and constants. Generated by `mkerrors.sh` (see above). + +### `zsyscall_${GOOS}_${GOARCH}.go` + +A file containing all the generated syscalls for a specific GOOS and GOARCH. +Generated by `mksyscall.pl` (see above). + +### `zsysnum_${GOOS}_${GOARCH}.go` + +A list of numeric constants for all the syscall number of the specific GOOS +and GOARCH. Generated by mksysnum (see above). + +### `ztypes_${GOOS}_${GOARCH}.go` + +A file containing Go types for passing into (or returning from) syscalls. +Generated by godefs and the types file (see above). diff --git a/vendor/golang.org/x/sys/unix/creds_test.go b/vendor/golang.org/x/sys/unix/creds_test.go new file mode 100644 index 000000000..1b5083196 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/creds_test.go @@ -0,0 +1,134 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package unix_test + +import ( + "bytes" + "go/build" + "net" + "os" + "testing" + + "golang.org/x/sys/unix" +) + +// TestSCMCredentials tests the sending and receiving of credentials +// (PID, UID, GID) in an ancillary message between two UNIX +// sockets. The SO_PASSCRED socket option is enabled on the sending +// socket for this to work. +func TestSCMCredentials(t *testing.T) { + socketTypeTests := []struct { + socketType int + dataLen int + }{ + { + unix.SOCK_STREAM, + 1, + }, { + unix.SOCK_DGRAM, + 0, + }, + } + + for _, tt := range socketTypeTests { + if tt.socketType == unix.SOCK_DGRAM && !atLeast1p10() { + t.Log("skipping DGRAM test on pre-1.10") + continue + } + + fds, err := unix.Socketpair(unix.AF_LOCAL, tt.socketType, 0) + if err != nil { + t.Fatalf("Socketpair: %v", err) + } + defer unix.Close(fds[0]) + defer unix.Close(fds[1]) + + err = unix.SetsockoptInt(fds[0], unix.SOL_SOCKET, unix.SO_PASSCRED, 1) + if err != nil { + t.Fatalf("SetsockoptInt: %v", err) + } + + srvFile := os.NewFile(uintptr(fds[0]), "server") + defer srvFile.Close() + srv, err := net.FileConn(srvFile) + if err != nil { + t.Errorf("FileConn: %v", err) + return + } + defer srv.Close() + + cliFile := os.NewFile(uintptr(fds[1]), "client") + defer cliFile.Close() + cli, err := net.FileConn(cliFile) + if err != nil { + t.Errorf("FileConn: %v", err) + return + } + defer cli.Close() + + var ucred unix.Ucred + ucred.Pid = int32(os.Getpid()) + ucred.Uid = uint32(os.Getuid()) + ucred.Gid = uint32(os.Getgid()) + oob := unix.UnixCredentials(&ucred) + + // On SOCK_STREAM, this is internally going to send a dummy byte + n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) + if err != nil { + t.Fatalf("WriteMsgUnix: %v", err) + } + if n != 0 { + t.Fatalf("WriteMsgUnix n = %d, want 0", n) + } + if oobn != len(oob) { + t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) + } + + oob2 := make([]byte, 10*len(oob)) + n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) + if err != nil { + t.Fatalf("ReadMsgUnix: %v", err) + } + if flags != 0 { + t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) + } + if n != tt.dataLen { + t.Fatalf("ReadMsgUnix n = %d, want %d", n, tt.dataLen) + } + if oobn2 != oobn { + // without SO_PASSCRED set on the socket, ReadMsgUnix will + // return zero oob bytes + t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) + } + oob2 = oob2[:oobn2] + if !bytes.Equal(oob, oob2) { + t.Fatal("ReadMsgUnix oob bytes don't match") + } + + scm, err := unix.ParseSocketControlMessage(oob2) + if err != nil { + t.Fatalf("ParseSocketControlMessage: %v", err) + } + newUcred, err := unix.ParseUnixCredentials(&scm[0]) + if err != nil { + t.Fatalf("ParseUnixCredentials: %v", err) + } + if *newUcred != ucred { + t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) + } + } +} + +// atLeast1p10 reports whether we are running on Go 1.10 or later. +func atLeast1p10() bool { + for _, ver := range build.Default.ReleaseTags { + if ver == "go1.10" { + return true + } + } + return false +} diff --git a/vendor/golang.org/x/sys/unix/dev_linux_test.go b/vendor/golang.org/x/sys/unix/dev_linux_test.go new file mode 100644 index 000000000..2fd3eadd0 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/dev_linux_test.go @@ -0,0 +1,53 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7 + +package unix_test + +import ( + "fmt" + "testing" + + "golang.org/x/sys/unix" +) + +func TestDevices(t *testing.T) { + testCases := []struct { + path string + major uint32 + minor uint32 + }{ + // well known major/minor numbers according to + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/devices.txt + {"/dev/null", 1, 3}, + {"/dev/zero", 1, 5}, + {"/dev/random", 1, 8}, + {"/dev/full", 1, 7}, + {"/dev/urandom", 1, 9}, + {"/dev/tty", 5, 0}, + } + for _, tc := range testCases { + t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) { + var stat unix.Stat_t + err := unix.Stat(tc.path, &stat) + if err != nil { + t.Errorf("failed to stat device: %v", err) + return + } + + dev := uint64(stat.Rdev) + if unix.Major(dev) != tc.major { + t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major) + } + if unix.Minor(dev) != tc.minor { + t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor) + } + if unix.Mkdev(tc.major, tc.minor) != dev { + t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev) + } + }) + + } +} diff --git a/vendor/golang.org/x/sys/unix/example_test.go b/vendor/golang.org/x/sys/unix/example_test.go new file mode 100644 index 000000000..10619afdd --- /dev/null +++ b/vendor/golang.org/x/sys/unix/example_test.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix_test + +import ( + "log" + "os" + + "golang.org/x/sys/unix" +) + +func ExampleExec() { + err := unix.Exec("/bin/ls", []string{"ls", "-al"}, os.Environ()) + log.Fatal(err) +} diff --git a/vendor/golang.org/x/sys/unix/export_test.go b/vendor/golang.org/x/sys/unix/export_test.go new file mode 100644 index 000000000..e8024690d --- /dev/null +++ b/vendor/golang.org/x/sys/unix/export_test.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix + +var Itoa = itoa diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh new file mode 100755 index 000000000..1715122bd --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mkall.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# This script runs or (given -n) prints suggested commands to generate files for +# the Architecture/OS specified by the GOARCH and GOOS environment variables. +# See README.md for more information about how the build system works. + +GOOSARCH="${GOOS}_${GOARCH}" + +# defaults +mksyscall="./mksyscall.pl" +mkerrors="./mkerrors.sh" +zerrors="zerrors_$GOOSARCH.go" +mksysctl="" +zsysctl="zsysctl_$GOOSARCH.go" +mksysnum= +mktypes= +run="sh" +cmd="" + +case "$1" in +-syscalls) + for i in zsyscall*go + do + # Run the command line that appears in the first line + # of the generated file to regenerate it. + sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i + rm _$i + done + exit 0 + ;; +-n) + run="cat" + cmd="echo" + shift +esac + +case "$#" in +0) + ;; +*) + echo 'usage: mkall.sh [-n]' 1>&2 + exit 2 +esac + +if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then + # Use then new build system + # Files generated through docker (use $cmd so you can Ctl-C the build or run) + $cmd docker build --tag generate:$GOOS $GOOS + $cmd docker run --interactive --tty --volume $(dirname "$(readlink -f "$0")"):/build generate:$GOOS + exit +fi + +GOOSARCH_in=syscall_$GOOSARCH.go +case "$GOOSARCH" in +_* | *_ | _) + echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 + exit 1 + ;; +darwin_386) + mkerrors="$mkerrors -m32" + mksyscall="./mksyscall.pl -l32" + mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +darwin_amd64) + mkerrors="$mkerrors -m64" + mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +darwin_arm) + mkerrors="$mkerrors" + mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +darwin_arm64) + mkerrors="$mkerrors -m64" + mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +dragonfly_amd64) + mkerrors="$mkerrors -m64" + mksyscall="./mksyscall.pl -dragonfly" + mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +freebsd_386) + mkerrors="$mkerrors -m32" + mksyscall="./mksyscall.pl -l32" + mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +freebsd_amd64) + mkerrors="$mkerrors -m64" + mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +freebsd_arm) + mkerrors="$mkerrors" + mksyscall="./mksyscall.pl -l32 -arm" + mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" + # Let the type of C char be signed for making the bare syscall + # API consistent across platforms. + mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" + ;; +linux_sparc64) + GOOSARCH_in=syscall_linux_sparc64.go + unistd_h=/usr/include/sparc64-linux-gnu/asm/unistd.h + mkerrors="$mkerrors -m64" + mksysnum="./mksysnum_linux.pl $unistd_h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +netbsd_386) + mkerrors="$mkerrors -m32" + mksyscall="./mksyscall.pl -l32 -netbsd" + mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +netbsd_amd64) + mkerrors="$mkerrors -m64" + mksyscall="./mksyscall.pl -netbsd" + mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +netbsd_arm) + mkerrors="$mkerrors" + mksyscall="./mksyscall.pl -l32 -netbsd -arm" + mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" + # Let the type of C char be signed for making the bare syscall + # API consistent across platforms. + mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" + ;; +openbsd_386) + mkerrors="$mkerrors -m32" + mksyscall="./mksyscall.pl -l32 -openbsd" + mksysctl="./mksysctl_openbsd.pl" + mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +openbsd_amd64) + mkerrors="$mkerrors -m64" + mksyscall="./mksyscall.pl -openbsd" + mksysctl="./mksysctl_openbsd.pl" + mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +openbsd_arm) + mkerrors="$mkerrors" + mksyscall="./mksyscall.pl -l32 -openbsd -arm" + mksysctl="./mksysctl_openbsd.pl" + mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" + # Let the type of C char be signed for making the bare syscall + # API consistent across platforms. + mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" + ;; +solaris_amd64) + mksyscall="./mksyscall_solaris.pl" + mkerrors="$mkerrors -m64" + mksysnum= + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +*) + echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 + exit 1 + ;; +esac + +( + if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi + case "$GOOS" in + *) + syscall_goos="syscall_$GOOS.go" + case "$GOOS" in + darwin | dragonfly | freebsd | netbsd | openbsd) + syscall_goos="syscall_bsd.go $syscall_goos" + ;; + esac + if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi + ;; + esac + if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi + if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi + if [ -n "$mktypes" ]; then + echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; + fi +) | $run diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh new file mode 100755 index 000000000..3b7d62354 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -0,0 +1,601 @@ +#!/usr/bin/env bash +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# Generate Go code listing errors and other #defined constant +# values (ENAMETOOLONG etc.), by asking the preprocessor +# about the definitions. + +unset LANG +export LC_ALL=C +export LC_CTYPE=C + +if test -z "$GOARCH" -o -z "$GOOS"; then + echo 1>&2 "GOARCH or GOOS not defined in environment" + exit 1 +fi + +# Check that we are using the new build system if we should +if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then + if [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then + echo 1>&2 "In the new build system, mkerrors should not be called directly." + echo 1>&2 "See README.md" + exit 1 + fi +fi + +CC=${CC:-cc} + +if [[ "$GOOS" = "solaris" ]]; then + # Assumes GNU versions of utilities in PATH. + export PATH=/usr/gnu/bin:$PATH +fi + +uname=$(uname) + +includes_Darwin=' +#define _DARWIN_C_SOURCE +#define KERNEL +#define _DARWIN_USE_64_BIT_INODE +#include <stdint.h> +#include <sys/attr.h> +#include <sys/types.h> +#include <sys/event.h> +#include <sys/ptrace.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/utsname.h> +#include <sys/wait.h> +#include <sys/xattr.h> +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <termios.h> +' + +includes_DragonFly=' +#include <sys/types.h> +#include <sys/event.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/route.h> +#include <netinet/in.h> +#include <termios.h> +#include <netinet/ip.h> +#include <net/ip_mroute/ip_mroute.h> +' + +includes_FreeBSD=' +#include <sys/capability.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/event.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/route.h> +#include <netinet/in.h> +#include <termios.h> +#include <netinet/ip.h> +#include <netinet/ip_mroute.h> +#include <sys/extattr.h> + +#if __FreeBSD__ >= 10 +#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10 +#undef SIOCAIFADDR +#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data +#undef SIOCSIFPHYADDR +#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data +#endif +' + +includes_Linux=' +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#ifndef __LP64__ +#define _FILE_OFFSET_BITS 64 +#endif +#define _GNU_SOURCE + +// <sys/ioctl.h> is broken on powerpc64, as it fails to include definitions of +// these structures. We just include them copied from <bits/termios.h>. +#if defined(__powerpc__) +struct sgttyb { + char sg_ispeed; + char sg_ospeed; + char sg_erase; + char sg_kill; + short sg_flags; +}; + +struct tchars { + char t_intrc; + char t_quitc; + char t_startc; + char t_stopc; + char t_eofc; + char t_brkc; +}; + +struct ltchars { + char t_suspc; + char t_dsuspc; + char t_rprntc; + char t_flushc; + char t_werasc; + char t_lnextc; +}; +#endif + +#include <bits/sockaddr.h> +#include <sys/epoll.h> +#include <sys/eventfd.h> +#include <sys/inotify.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/prctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/xattr.h> +#include <linux/if.h> +#include <linux/if_alg.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/if_tun.h> +#include <linux/if_packet.h> +#include <linux/if_addr.h> +#include <linux/falloc.h> +#include <linux/filter.h> +#include <linux/fs.h> +#include <linux/keyctl.h> +#include <linux/magic.h> +#include <linux/netlink.h> +#include <linux/perf_event.h> +#include <linux/random.h> +#include <linux/reboot.h> +#include <linux/rtnetlink.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <linux/seccomp.h> +#include <linux/sockios.h> +#include <linux/wait.h> +#include <linux/icmpv6.h> +#include <linux/serial.h> +#include <linux/can.h> +#include <linux/vm_sockets.h> +#include <linux/taskstats.h> +#include <linux/genetlink.h> +#include <linux/stat.h> +#include <linux/watchdog.h> +#include <linux/hdreg.h> +#include <net/route.h> +#include <asm/termbits.h> + +#ifndef MSG_FASTOPEN +#define MSG_FASTOPEN 0x20000000 +#endif + +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS 0xc +#endif + +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS 0xd +#endif + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#ifdef SOL_BLUETOOTH +// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h +// but it is already in bluetooth_linux.go +#undef SOL_BLUETOOTH +#endif + +// Certain constants are missing from the fs/crypto UAPI +#define FS_KEY_DESC_PREFIX "fscrypt:" +#define FS_KEY_DESC_PREFIX_SIZE 8 +#define FS_MAX_KEY_SIZE 64 +' + +includes_NetBSD=' +#include <sys/types.h> +#include <sys/param.h> +#include <sys/event.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/termios.h> +#include <sys/ttycom.h> +#include <sys/wait.h> +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_mroute.h> +#include <netinet/if_ether.h> + +// Needed since <sys/param.h> refers to it... +#define schedppq 1 +' + +includes_OpenBSD=' +#include <sys/types.h> +#include <sys/param.h> +#include <sys/event.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/termios.h> +#include <sys/ttycom.h> +#include <sys/wait.h> +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/if_var.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_mroute.h> +#include <netinet/if_ether.h> +#include <net/if_bridge.h> + +// We keep some constants not supported in OpenBSD 5.5 and beyond for +// the promise of compatibility. +#define EMUL_ENABLED 0x1 +#define EMUL_NATIVE 0x2 +#define IPV6_FAITH 0x1d +#define IPV6_OPTIONS 0x1 +#define IPV6_RTHDR_STRICT 0x1 +#define IPV6_SOCKOPT_RESERVED1 0x3 +#define SIOCGIFGENERIC 0xc020693a +#define SIOCSIFGENERIC 0x80206939 +#define WALTSIG 0x4 +' + +includes_SunOS=' +#include <limits.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <sys/mkdev.h> +#include <net/bpf.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_types.h> +#include <net/route.h> +#include <netinet/in.h> +#include <termios.h> +#include <netinet/ip.h> +#include <netinet/ip_mroute.h> +' + + +includes=' +#include <sys/types.h> +#include <sys/file.h> +#include <fcntl.h> +#include <dirent.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> +#include <errno.h> +#include <sys/signal.h> +#include <signal.h> +#include <sys/resource.h> +#include <time.h> +' +ccflags="$@" + +# Write go tool cgo -godefs input. +( + echo package unix + echo + echo '/*' + indirect="includes_$(uname)" + echo "${!indirect} $includes" + echo '*/' + echo 'import "C"' + echo 'import "syscall"' + echo + echo 'const (' + + # The gcc command line prints all the #defines + # it encounters while processing the input + echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags | + awk ' + $1 != "#define" || $2 ~ /\(/ || $3 == "" {next} + + $2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers + $2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next} + $2 ~ /^(SCM_SRCRT)$/ {next} + $2 ~ /^(MAP_FAILED)$/ {next} + $2 ~ /^ELF_.*$/ {next}# <asm/elf.h> contains ELF_ARCH, etc. + + $2 ~ /^EXTATTR_NAMESPACE_NAMES/ || + $2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next} + + $2 !~ /^ETH_/ && + $2 !~ /^EPROC_/ && + $2 !~ /^EQUIV_/ && + $2 !~ /^EXPR_/ && + $2 ~ /^E[A-Z0-9_]+$/ || + $2 ~ /^B[0-9_]+$/ || + $2 ~ /^(OLD|NEW)DEV$/ || + $2 == "BOTHER" || + $2 ~ /^CI?BAUD(EX)?$/ || + $2 == "IBSHIFT" || + $2 ~ /^V[A-Z0-9]+$/ || + $2 ~ /^CS[A-Z0-9]/ || + $2 ~ /^I(SIG|CANON|CRNL|UCLC|EXTEN|MAXBEL|STRIP|UTF8)$/ || + $2 ~ /^IGN/ || + $2 ~ /^IX(ON|ANY|OFF)$/ || + $2 ~ /^IN(LCR|PCK)$/ || + $2 !~ "X86_CR3_PCID_NOFLUSH" && + $2 ~ /(^FLU?SH)|(FLU?SH$)/ || + $2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ || + $2 == "BRKINT" || + $2 == "HUPCL" || + $2 == "PENDIN" || + $2 == "TOSTOP" || + $2 == "XCASE" || + $2 == "ALTWERASE" || + $2 == "NOKERNINFO" || + $2 ~ /^PAR/ || + $2 ~ /^SIG[^_]/ || + $2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ || + $2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ || + $2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ || + $2 ~ /^O?XTABS$/ || + $2 ~ /^TC[IO](ON|OFF)$/ || + $2 ~ /^IN_/ || + $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || + $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|T?PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ || + $2 ~ /^TP_STATUS_/ || + $2 ~ /^FALLOC_/ || + $2 == "ICMPV6_FILTER" || + $2 == "SOMAXCONN" || + $2 == "NAME_MAX" || + $2 == "IFNAMSIZ" || + $2 ~ /^CTL_(HW|KERN|MAXNAME|NET|QUERY)$/ || + $2 ~ /^KERN_(HOSTNAME|OS(RELEASE|TYPE)|VERSION)$/ || + $2 ~ /^HW_MACHINE$/ || + $2 ~ /^SYSCTL_VERS/ || + $2 ~ /^(MS|MNT|UMOUNT)_/ || + $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || + $2 ~ /^(O|F|E?FD|NAME|S|PTRACE|PT)_/ || + $2 ~ /^LINUX_REBOOT_CMD_/ || + $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || + $2 !~ "NLA_TYPE_MASK" && + $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || + $2 ~ /^SIOC/ || + $2 ~ /^TIOC/ || + $2 ~ /^TCGET/ || + $2 ~ /^TCSET/ || + $2 ~ /^TC(FLSH|SBRKP?|XONC)$/ || + $2 !~ "RTF_BITS" && + $2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ || + $2 ~ /^BIOC/ || + $2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ || + $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ || + $2 ~ /^PRIO_(PROCESS|PGRP|USER)/ || + $2 ~ /^CLONE_[A-Z_]+/ || + $2 !~ /^(BPF_TIMEVAL)$/ && + $2 ~ /^(BPF|DLT)_/ || + $2 ~ /^CLOCK_/ || + $2 ~ /^CAN_/ || + $2 ~ /^CAP_/ || + $2 ~ /^ALG_/ || + $2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE|IOC_(GET|SET)_ENCRYPTION)/ || + $2 ~ /^GRND_/ || + $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || + $2 ~ /^KEYCTL_/ || + $2 ~ /^PERF_EVENT_IOC_/ || + $2 ~ /^SECCOMP_MODE_/ || + $2 ~ /^SPLICE_/ || + $2 !~ /^AUDIT_RECORD_MAGIC/ && + $2 ~ /^[A-Z0-9_]+_MAGIC2?$/ || + $2 ~ /^(VM|VMADDR)_/ || + $2 ~ /^IOCTL_VM_SOCKETS_/ || + $2 ~ /^(TASKSTATS|TS)_/ || + $2 ~ /^CGROUPSTATS_/ || + $2 ~ /^GENL_/ || + $2 ~ /^STATX_/ || + $2 ~ /^UTIME_/ || + $2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ || + $2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ || + $2 ~ /^FSOPT_/ || + $2 ~ /^WDIOC_/ || + $2 ~ /^(HDIO|WIN|SMART)_/ || + $2 !~ "WMESGLEN" && + $2 ~ /^W[A-Z0-9]+$/ || + $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} + $2 ~ /^__WCOREFLAG$/ {next} + $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} + + {next} + ' | sort + + echo ')' +) >_const.go + +# Pull out the error names for later. +errors=$( + echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags | + awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' | + sort +) + +# Pull out the signal names for later. +signals=$( + echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | + awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | + egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | + sort +) + +# Again, writing regexps to a file. +echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags | + awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' | + sort >_error.grep +echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | + awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | + egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | + sort >_signal.grep + +echo '// mkerrors.sh' "$@" +echo '// Code generated by the command above; see README.md. DO NOT EDIT.' +echo +echo "// +build ${GOARCH},${GOOS}" +echo +go tool cgo -godefs -- "$@" _const.go >_error.out +cat _error.out | grep -vf _error.grep | grep -vf _signal.grep +echo +echo '// Errors' +echo 'const (' +cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= syscall.Errno(\1)/' +echo ')' + +echo +echo '// Signals' +echo 'const (' +cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= syscall.Signal(\1)/' +echo ')' + +# Run C program to print error and syscall strings. +( + echo -E " +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <string.h> +#include <signal.h> + +#define nelem(x) (sizeof(x)/sizeof((x)[0])) + +enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below + +struct tuple { + int num; + const char *name; +}; + +struct tuple errors[] = { +" + for i in $errors + do + echo -E ' {'$i', "'$i'" },' + done + + echo -E " +}; + +struct tuple signals[] = { +" + for i in $signals + do + echo -E ' {'$i', "'$i'" },' + done + + # Use -E because on some systems bash builtin interprets \n itself. + echo -E ' +}; + +static int +tuplecmp(const void *a, const void *b) +{ + return ((struct tuple *)a)->num - ((struct tuple *)b)->num; +} + +int +main(void) +{ + int i, e; + char buf[1024], *p; + + printf("\n\n// Error table\n"); + printf("var errorList = [...]struct {\n"); + printf("\tnum syscall.Errno\n"); + printf("\tname string\n"); + printf("\tdesc string\n"); + printf("} {\n"); + qsort(errors, nelem(errors), sizeof errors[0], tuplecmp); + for(i=0; i<nelem(errors); i++) { + e = errors[i].num; + if(i > 0 && errors[i-1].num == e) + continue; + strcpy(buf, strerror(e)); + // lowercase first letter: Bad -> bad, but STREAM -> STREAM. + if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) + buf[0] += a - A; + printf("\t{ %d, \"%s\", \"%s\" },\n", e, errors[i].name, buf); + } + printf("}\n\n"); + + printf("\n\n// Signal table\n"); + printf("var signalList = [...]struct {\n"); + printf("\tnum syscall.Signal\n"); + printf("\tname string\n"); + printf("\tdesc string\n"); + printf("} {\n"); + qsort(signals, nelem(signals), sizeof signals[0], tuplecmp); + for(i=0; i<nelem(signals); i++) { + e = signals[i].num; + if(i > 0 && signals[i-1].num == e) + continue; + strcpy(buf, strsignal(e)); + // lowercase first letter: Bad -> bad, but STREAM -> STREAM. + if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) + buf[0] += a - A; + // cut trailing : number. + p = strrchr(buf, ":"[0]); + if(p) + *p = '\0'; + printf("\t{ %d, \"%s\", \"%s\" },\n", e, signals[i].name, buf); + } + printf("}\n\n"); + + return 0; +} + +' +) >_errors.c + +$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out diff --git a/vendor/golang.org/x/sys/unix/mksyscall.pl b/vendor/golang.org/x/sys/unix/mksyscall.pl new file mode 100755 index 000000000..1f6b926f8 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksyscall.pl @@ -0,0 +1,341 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# This program reads a file containing function prototypes +# (like syscall_darwin.go) and generates system call bodies. +# The prototypes are marked by lines beginning with "//sys" +# and read like func declarations if //sys is replaced by func, but: +# * The parameter lists must give a name for each argument. +# This includes return parameters. +# * The parameter lists must give a type for each argument: +# the (x, y, z int) shorthand is not allowed. +# * If the return parameter is an error number, it must be named errno. + +# A line beginning with //sysnb is like //sys, except that the +# goroutine will not be suspended during the execution of the system +# call. This must only be used for system calls which can never +# block, as otherwise the system call could cause all goroutines to +# hang. + +use strict; + +my $cmdline = "mksyscall.pl " . join(' ', @ARGV); +my $errors = 0; +my $_32bit = ""; +my $plan9 = 0; +my $openbsd = 0; +my $netbsd = 0; +my $dragonfly = 0; +my $arm = 0; # 64-bit value should use (even, odd)-pair +my $tags = ""; # build tags + +if($ARGV[0] eq "-b32") { + $_32bit = "big-endian"; + shift; +} elsif($ARGV[0] eq "-l32") { + $_32bit = "little-endian"; + shift; +} +if($ARGV[0] eq "-plan9") { + $plan9 = 1; + shift; +} +if($ARGV[0] eq "-openbsd") { + $openbsd = 1; + shift; +} +if($ARGV[0] eq "-netbsd") { + $netbsd = 1; + shift; +} +if($ARGV[0] eq "-dragonfly") { + $dragonfly = 1; + shift; +} +if($ARGV[0] eq "-arm") { + $arm = 1; + shift; +} +if($ARGV[0] eq "-tags") { + shift; + $tags = $ARGV[0]; + shift; +} + +if($ARGV[0] =~ /^-/) { + print STDERR "usage: mksyscall.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; + exit 1; +} + +# Check that we are using the new build system if we should +if($ENV{'GOOS'} eq "linux" && $ENV{'GOARCH'} ne "sparc64") { + if($ENV{'GOLANG_SYS_BUILD'} ne "docker") { + print STDERR "In the new build system, mksyscall should not be called directly.\n"; + print STDERR "See README.md\n"; + exit 1; + } +} + + +sub parseparamlist($) { + my ($list) = @_; + $list =~ s/^\s*//; + $list =~ s/\s*$//; + if($list eq "") { + return (); + } + return split(/\s*,\s*/, $list); +} + +sub parseparam($) { + my ($p) = @_; + if($p !~ /^(\S*) (\S*)$/) { + print STDERR "$ARGV:$.: malformed parameter: $p\n"; + $errors = 1; + return ("xx", "int"); + } + return ($1, $2); +} + +my $text = ""; +while(<>) { + chomp; + s/\s+/ /g; + s/^\s+//; + s/\s+$//; + my $nonblock = /^\/\/sysnb /; + next if !/^\/\/sys / && !$nonblock; + + # Line must be of the form + # func Open(path string, mode int, perm int) (fd int, errno error) + # Split into name, in params, out params. + if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) { + print STDERR "$ARGV:$.: malformed //sys declaration\n"; + $errors = 1; + next; + } + my ($func, $in, $out, $sysname) = ($2, $3, $4, $5); + + # Split argument lists on comma. + my @in = parseparamlist($in); + my @out = parseparamlist($out); + + # Try in vain to keep people from editing this file. + # The theory is that they jump into the middle of the file + # without reading the header. + $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; + + # Go function header. + my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : ""; + $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl; + + # Check if err return available + my $errvar = ""; + foreach my $p (@out) { + my ($name, $type) = parseparam($p); + if($type eq "error") { + $errvar = $name; + last; + } + } + + # Prepare arguments to Syscall. + my @args = (); + my $n = 0; + foreach my $p (@in) { + my ($name, $type) = parseparam($p); + if($type =~ /^\*/) { + push @args, "uintptr(unsafe.Pointer($name))"; + } elsif($type eq "string" && $errvar ne "") { + $text .= "\tvar _p$n *byte\n"; + $text .= "\t_p$n, $errvar = BytePtrFromString($name)\n"; + $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; + push @args, "uintptr(unsafe.Pointer(_p$n))"; + $n++; + } elsif($type eq "string") { + print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; + $text .= "\tvar _p$n *byte\n"; + $text .= "\t_p$n, _ = BytePtrFromString($name)\n"; + push @args, "uintptr(unsafe.Pointer(_p$n))"; + $n++; + } elsif($type =~ /^\[\](.*)/) { + # Convert slice into pointer, length. + # Have to be careful not to take address of &a[0] if len == 0: + # pass dummy pointer in that case. + # Used to pass nil, but some OSes or simulators reject write(fd, nil, 0). + $text .= "\tvar _p$n unsafe.Pointer\n"; + $text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}"; + $text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}"; + $text .= "\n"; + push @args, "uintptr(_p$n)", "uintptr(len($name))"; + $n++; + } elsif($type eq "int64" && ($openbsd || $netbsd)) { + push @args, "0"; + if($_32bit eq "big-endian") { + push @args, "uintptr($name>>32)", "uintptr($name)"; + } elsif($_32bit eq "little-endian") { + push @args, "uintptr($name)", "uintptr($name>>32)"; + } else { + push @args, "uintptr($name)"; + } + } elsif($type eq "int64" && $dragonfly) { + if ($func !~ /^extp(read|write)/i) { + push @args, "0"; + } + if($_32bit eq "big-endian") { + push @args, "uintptr($name>>32)", "uintptr($name)"; + } elsif($_32bit eq "little-endian") { + push @args, "uintptr($name)", "uintptr($name>>32)"; + } else { + push @args, "uintptr($name)"; + } + } elsif($type eq "int64" && $_32bit ne "") { + if(@args % 2 && $arm) { + # arm abi specifies 64-bit argument uses + # (even, odd) pair + push @args, "0" + } + if($_32bit eq "big-endian") { + push @args, "uintptr($name>>32)", "uintptr($name)"; + } else { + push @args, "uintptr($name)", "uintptr($name>>32)"; + } + } else { + push @args, "uintptr($name)"; + } + } + + # Determine which form to use; pad args with zeros. + my $asm = "Syscall"; + if ($nonblock) { + if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { + $asm = "RawSyscallNoError"; + } else { + $asm = "RawSyscall"; + } + } else { + if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { + $asm = "SyscallNoError"; + } + } + if(@args <= 3) { + while(@args < 3) { + push @args, "0"; + } + } elsif(@args <= 6) { + $asm .= "6"; + while(@args < 6) { + push @args, "0"; + } + } elsif(@args <= 9) { + $asm .= "9"; + while(@args < 9) { + push @args, "0"; + } + } else { + print STDERR "$ARGV:$.: too many arguments to system call\n"; + } + + # System call number. + if($sysname eq "") { + $sysname = "SYS_$func"; + $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar + $sysname =~ y/a-z/A-Z/; + } + + # Actual call. + my $args = join(', ', @args); + my $call = "$asm($sysname, $args)"; + + # Assign return values. + my $body = ""; + my @ret = ("_", "_", "_"); + my $do_errno = 0; + for(my $i=0; $i<@out; $i++) { + my $p = $out[$i]; + my ($name, $type) = parseparam($p); + my $reg = ""; + if($name eq "err" && !$plan9) { + $reg = "e1"; + $ret[2] = $reg; + $do_errno = 1; + } elsif($name eq "err" && $plan9) { + $ret[0] = "r0"; + $ret[2] = "e1"; + next; + } else { + $reg = sprintf("r%d", $i); + $ret[$i] = $reg; + } + if($type eq "bool") { + $reg = "$reg != 0"; + } + if($type eq "int64" && $_32bit ne "") { + # 64-bit number in r1:r0 or r0:r1. + if($i+2 > @out) { + print STDERR "$ARGV:$.: not enough registers for int64 return\n"; + } + if($_32bit eq "big-endian") { + $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); + } else { + $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); + } + $ret[$i] = sprintf("r%d", $i); + $ret[$i+1] = sprintf("r%d", $i+1); + } + if($reg ne "e1" || $plan9) { + $body .= "\t$name = $type($reg)\n"; + } + } + if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { + $text .= "\t$call\n"; + } else { + if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { + # raw syscall without error on Linux, see golang.org/issue/22924 + $text .= "\t$ret[0], $ret[1] := $call\n"; + } else { + $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; + } + } + $text .= $body; + + if ($plan9 && $ret[2] eq "e1") { + $text .= "\tif int32(r0) == -1 {\n"; + $text .= "\t\terr = e1\n"; + $text .= "\t}\n"; + } elsif ($do_errno) { + $text .= "\tif e1 != 0 {\n"; + $text .= "\t\terr = errnoErr(e1)\n"; + $text .= "\t}\n"; + } + $text .= "\treturn\n"; + $text .= "}\n\n"; +} + +chomp $text; +chomp $text; + +if($errors) { + exit 1; +} + +print <<EOF; +// $cmdline +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $tags + +package unix + +import ( + "syscall" + "unsafe" +) + +var _ syscall.Errno + +$text +EOF +exit 0; diff --git a/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl b/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl new file mode 100755 index 000000000..3e6ed9df8 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl @@ -0,0 +1,289 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# This program reads a file containing function prototypes +# (like syscall_solaris.go) and generates system call bodies. +# The prototypes are marked by lines beginning with "//sys" +# and read like func declarations if //sys is replaced by func, but: +# * The parameter lists must give a name for each argument. +# This includes return parameters. +# * The parameter lists must give a type for each argument: +# the (x, y, z int) shorthand is not allowed. +# * If the return parameter is an error number, it must be named err. +# * If go func name needs to be different than its libc name, +# * or the function is not in libc, name could be specified +# * at the end, after "=" sign, like +# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt + +use strict; + +my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV); +my $errors = 0; +my $_32bit = ""; +my $tags = ""; # build tags + +binmode STDOUT; + +if($ARGV[0] eq "-b32") { + $_32bit = "big-endian"; + shift; +} elsif($ARGV[0] eq "-l32") { + $_32bit = "little-endian"; + shift; +} +if($ARGV[0] eq "-tags") { + shift; + $tags = $ARGV[0]; + shift; +} + +if($ARGV[0] =~ /^-/) { + print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; + exit 1; +} + +sub parseparamlist($) { + my ($list) = @_; + $list =~ s/^\s*//; + $list =~ s/\s*$//; + if($list eq "") { + return (); + } + return split(/\s*,\s*/, $list); +} + +sub parseparam($) { + my ($p) = @_; + if($p !~ /^(\S*) (\S*)$/) { + print STDERR "$ARGV:$.: malformed parameter: $p\n"; + $errors = 1; + return ("xx", "int"); + } + return ($1, $2); +} + +my $package = ""; +my $text = ""; +my $dynimports = ""; +my $linknames = ""; +my @vars = (); +while(<>) { + chomp; + s/\s+/ /g; + s/^\s+//; + s/\s+$//; + $package = $1 if !$package && /^package (\S+)$/; + my $nonblock = /^\/\/sysnb /; + next if !/^\/\/sys / && !$nonblock; + + # Line must be of the form + # func Open(path string, mode int, perm int) (fd int, err error) + # Split into name, in params, out params. + if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { + print STDERR "$ARGV:$.: malformed //sys declaration\n"; + $errors = 1; + next; + } + my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); + + # Split argument lists on comma. + my @in = parseparamlist($in); + my @out = parseparamlist($out); + + # So file name. + if($modname eq "") { + $modname = "libc"; + } + + # System call name. + if($sysname eq "") { + $sysname = "$func"; + } + + # System call pointer variable name. + my $sysvarname = "proc$sysname"; + + my $strconvfunc = "BytePtrFromString"; + my $strconvtype = "*byte"; + + $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. + + # Runtime import of function to allow cross-platform builds. + $dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n"; + # Link symbol to proc address variable. + $linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n"; + # Library proc address variable. + push @vars, $sysvarname; + + # Go function header. + $out = join(', ', @out); + if($out ne "") { + $out = " ($out)"; + } + if($text ne "") { + $text .= "\n" + } + $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; + + # Check if err return available + my $errvar = ""; + foreach my $p (@out) { + my ($name, $type) = parseparam($p); + if($type eq "error") { + $errvar = $name; + last; + } + } + + # Prepare arguments to Syscall. + my @args = (); + my $n = 0; + foreach my $p (@in) { + my ($name, $type) = parseparam($p); + if($type =~ /^\*/) { + push @args, "uintptr(unsafe.Pointer($name))"; + } elsif($type eq "string" && $errvar ne "") { + $text .= "\tvar _p$n $strconvtype\n"; + $text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; + $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; + push @args, "uintptr(unsafe.Pointer(_p$n))"; + $n++; + } elsif($type eq "string") { + print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; + $text .= "\tvar _p$n $strconvtype\n"; + $text .= "\t_p$n, _ = $strconvfunc($name)\n"; + push @args, "uintptr(unsafe.Pointer(_p$n))"; + $n++; + } elsif($type =~ /^\[\](.*)/) { + # Convert slice into pointer, length. + # Have to be careful not to take address of &a[0] if len == 0: + # pass nil in that case. + $text .= "\tvar _p$n *$1\n"; + $text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; + push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; + $n++; + } elsif($type eq "int64" && $_32bit ne "") { + if($_32bit eq "big-endian") { + push @args, "uintptr($name >> 32)", "uintptr($name)"; + } else { + push @args, "uintptr($name)", "uintptr($name >> 32)"; + } + } elsif($type eq "bool") { + $text .= "\tvar _p$n uint32\n"; + $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; + push @args, "uintptr(_p$n)"; + $n++; + } else { + push @args, "uintptr($name)"; + } + } + my $nargs = @args; + + # Determine which form to use; pad args with zeros. + my $asm = "sysvicall6"; + if ($nonblock) { + $asm = "rawSysvicall6"; + } + if(@args <= 6) { + while(@args < 6) { + push @args, "0"; + } + } else { + print STDERR "$ARGV:$.: too many arguments to system call\n"; + } + + # Actual call. + my $args = join(', ', @args); + my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)"; + + # Assign return values. + my $body = ""; + my $failexpr = ""; + my @ret = ("_", "_", "_"); + my @pout= (); + my $do_errno = 0; + for(my $i=0; $i<@out; $i++) { + my $p = $out[$i]; + my ($name, $type) = parseparam($p); + my $reg = ""; + if($name eq "err") { + $reg = "e1"; + $ret[2] = $reg; + $do_errno = 1; + } else { + $reg = sprintf("r%d", $i); + $ret[$i] = $reg; + } + if($type eq "bool") { + $reg = "$reg != 0"; + } + if($type eq "int64" && $_32bit ne "") { + # 64-bit number in r1:r0 or r0:r1. + if($i+2 > @out) { + print STDERR "$ARGV:$.: not enough registers for int64 return\n"; + } + if($_32bit eq "big-endian") { + $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); + } else { + $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); + } + $ret[$i] = sprintf("r%d", $i); + $ret[$i+1] = sprintf("r%d", $i+1); + } + if($reg ne "e1") { + $body .= "\t$name = $type($reg)\n"; + } + } + if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { + $text .= "\t$call\n"; + } else { + $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; + } + $text .= $body; + + if ($do_errno) { + $text .= "\tif e1 != 0 {\n"; + $text .= "\t\terr = e1\n"; + $text .= "\t}\n"; + } + $text .= "\treturn\n"; + $text .= "}\n"; +} + +if($errors) { + exit 1; +} + +print <<EOF; +// $cmdline +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $tags + +package $package + +import ( + "syscall" + "unsafe" +) +EOF + +print "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; + +my $vardecls = "\t" . join(",\n\t", @vars); +$vardecls .= " syscallFunc"; + +chomp($_=<<EOF); + +$dynimports +$linknames +var ( +$vardecls +) + +$text +EOF +print $_; +exit 0; diff --git a/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl b/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl new file mode 100755 index 000000000..be67afa41 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl @@ -0,0 +1,264 @@ +#!/usr/bin/env perl + +# Copyright 2011 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# +# Parse the header files for OpenBSD and generate a Go usable sysctl MIB. +# +# Build a MIB with each entry being an array containing the level, type and +# a hash that will contain additional entries if the current entry is a node. +# We then walk this MIB and create a flattened sysctl name to OID hash. +# + +use strict; + +if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { + print STDERR "GOARCH or GOOS not defined in environment\n"; + exit 1; +} + +my $debug = 0; +my %ctls = (); + +my @headers = qw ( + sys/sysctl.h + sys/socket.h + sys/tty.h + sys/malloc.h + sys/mount.h + sys/namei.h + sys/sem.h + sys/shm.h + sys/vmmeter.h + uvm/uvm_param.h + uvm/uvm_swap_encrypt.h + ddb/db_var.h + net/if.h + net/if_pfsync.h + net/pipex.h + netinet/in.h + netinet/icmp_var.h + netinet/igmp_var.h + netinet/ip_ah.h + netinet/ip_carp.h + netinet/ip_divert.h + netinet/ip_esp.h + netinet/ip_ether.h + netinet/ip_gre.h + netinet/ip_ipcomp.h + netinet/ip_ipip.h + netinet/pim_var.h + netinet/tcp_var.h + netinet/udp_var.h + netinet6/in6.h + netinet6/ip6_divert.h + netinet6/pim6_var.h + netinet/icmp6.h + netmpls/mpls.h +); + +my @ctls = qw ( + kern + vm + fs + net + #debug # Special handling required + hw + #machdep # Arch specific + user + ddb + #vfs # Special handling required + fs.posix + kern.forkstat + kern.intrcnt + kern.malloc + kern.nchstats + kern.seminfo + kern.shminfo + kern.timecounter + kern.tty + kern.watchdog + net.bpf + net.ifq + net.inet + net.inet.ah + net.inet.carp + net.inet.divert + net.inet.esp + net.inet.etherip + net.inet.gre + net.inet.icmp + net.inet.igmp + net.inet.ip + net.inet.ip.ifq + net.inet.ipcomp + net.inet.ipip + net.inet.mobileip + net.inet.pfsync + net.inet.pim + net.inet.tcp + net.inet.udp + net.inet6 + net.inet6.divert + net.inet6.ip6 + net.inet6.icmp6 + net.inet6.pim6 + net.inet6.tcp6 + net.inet6.udp6 + net.mpls + net.mpls.ifq + net.key + net.pflow + net.pfsync + net.pipex + net.rt + vm.swapencrypt + #vfsgenctl # Special handling required +); + +# Node name "fixups" +my %ctl_map = ( + "ipproto" => "net.inet", + "net.inet.ipproto" => "net.inet", + "net.inet6.ipv6proto" => "net.inet6", + "net.inet6.ipv6" => "net.inet6.ip6", + "net.inet.icmpv6" => "net.inet6.icmp6", + "net.inet6.divert6" => "net.inet6.divert", + "net.inet6.tcp6" => "net.inet.tcp", + "net.inet6.udp6" => "net.inet.udp", + "mpls" => "net.mpls", + "swpenc" => "vm.swapencrypt" +); + +# Node mappings +my %node_map = ( + "net.inet.ip.ifq" => "net.ifq", + "net.inet.pfsync" => "net.pfsync", + "net.mpls.ifq" => "net.ifq" +); + +my $ctlname; +my %mib = (); +my %sysctl = (); +my $node; + +sub debug() { + print STDERR "$_[0]\n" if $debug; +} + +# Walk the MIB and build a sysctl name to OID mapping. +sub build_sysctl() { + my ($node, $name, $oid) = @_; + my %node = %{$node}; + my @oid = @{$oid}; + + foreach my $key (sort keys %node) { + my @node = @{$node{$key}}; + my $nodename = $name.($name ne '' ? '.' : '').$key; + my @nodeoid = (@oid, $node[0]); + if ($node[1] eq 'CTLTYPE_NODE') { + if (exists $node_map{$nodename}) { + $node = \%mib; + $ctlname = $node_map{$nodename}; + foreach my $part (split /\./, $ctlname) { + $node = \%{@{$$node{$part}}[2]}; + } + } else { + $node = $node[2]; + } + &build_sysctl($node, $nodename, \@nodeoid); + } elsif ($node[1] ne '') { + $sysctl{$nodename} = \@nodeoid; + } + } +} + +foreach my $ctl (@ctls) { + $ctls{$ctl} = $ctl; +} + +# Build MIB +foreach my $header (@headers) { + &debug("Processing $header..."); + open HEADER, "/usr/include/$header" || + print STDERR "Failed to open $header\n"; + while (<HEADER>) { + if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ || + $_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ || + $_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) { + if ($1 eq 'CTL_NAMES') { + # Top level. + $node = \%mib; + } else { + # Node. + my $nodename = lc($2); + if ($header =~ /^netinet\//) { + $ctlname = "net.inet.$nodename"; + } elsif ($header =~ /^netinet6\//) { + $ctlname = "net.inet6.$nodename"; + } elsif ($header =~ /^net\//) { + $ctlname = "net.$nodename"; + } else { + $ctlname = "$nodename"; + $ctlname =~ s/^(fs|net|kern)_/$1\./; + } + if (exists $ctl_map{$ctlname}) { + $ctlname = $ctl_map{$ctlname}; + } + if (not exists $ctls{$ctlname}) { + &debug("Ignoring $ctlname..."); + next; + } + + # Walk down from the top of the MIB. + $node = \%mib; + foreach my $part (split /\./, $ctlname) { + if (not exists $$node{$part}) { + &debug("Missing node $part"); + $$node{$part} = [ 0, '', {} ]; + } + $node = \%{@{$$node{$part}}[2]}; + } + } + + # Populate current node with entries. + my $i = -1; + while (defined($_) && $_ !~ /^}/) { + $_ = <HEADER>; + $i++ if $_ =~ /{.*}/; + next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/; + $$node{$1} = [ $i, $2, {} ]; + } + } + } + close HEADER; +} + +&build_sysctl(\%mib, "", []); + +print <<EOF; +// mksysctl_openbsd.pl +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +// +build $ENV{'GOARCH'},$ENV{'GOOS'} + +package unix; + +type mibentry struct { + ctlname string + ctloid []_C_int +} + +var sysctlMib = []mibentry { +EOF + +foreach my $name (sort keys %sysctl) { + my @oid = @{$sysctl{$name}}; + print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n"; +} + +print <<EOF; +} +EOF diff --git a/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl b/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl new file mode 100755 index 000000000..5453c53b1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl @@ -0,0 +1,39 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# Generate system call table for Darwin from sys/syscall.h + +use strict; + +if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { + print STDERR "GOARCH or GOOS not defined in environment\n"; + exit 1; +} + +my $command = "mksysnum_darwin.pl " . join(' ', @ARGV); + +print <<EOF; +// $command +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $ENV{'GOARCH'},$ENV{'GOOS'} + +package unix + +const ( +EOF + +while(<>){ + if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){ + my $name = $1; + my $num = $2; + $name =~ y/a-z/A-Z/; + print " SYS_$name = $num;" + } +} + +print <<EOF; +) +EOF diff --git a/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl b/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl new file mode 100755 index 000000000..6804f4121 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl @@ -0,0 +1,50 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# Generate system call table for DragonFly from master list +# (for example, /usr/src/sys/kern/syscalls.master). + +use strict; + +if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { + print STDERR "GOARCH or GOOS not defined in environment\n"; + exit 1; +} + +my $command = "mksysnum_dragonfly.pl " . join(' ', @ARGV); + +print <<EOF; +// $command +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $ENV{'GOARCH'},$ENV{'GOOS'} + +package unix + +const ( +EOF + +while(<>){ + if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){ + my $num = $1; + my $proto = $2; + my $name = "SYS_$3"; + $name =~ y/a-z/A-Z/; + + # There are multiple entries for enosys and nosys, so comment them out. + if($name =~ /^SYS_E?NOSYS$/){ + $name = "// $name"; + } + if($name eq 'SYS_SYS_EXIT'){ + $name = 'SYS_EXIT'; + } + + print " $name = $num; // $proto\n"; + } +} + +print <<EOF; +) +EOF diff --git a/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl b/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl new file mode 100755 index 000000000..a0a22bf56 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl @@ -0,0 +1,50 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# Generate system call table for FreeBSD from master list +# (for example, /usr/src/sys/kern/syscalls.master). + +use strict; + +if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { + print STDERR "GOARCH or GOOS not defined in environment\n"; + exit 1; +} + +my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV); + +print <<EOF; +// $command +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $ENV{'GOARCH'},$ENV{'GOOS'} + +package unix + +const ( +EOF + +while(<>){ + if(/^([0-9]+)\s+\S+\s+STD\s+({ \S+\s+(\w+).*)$/){ + my $num = $1; + my $proto = $2; + my $name = "SYS_$3"; + $name =~ y/a-z/A-Z/; + + # There are multiple entries for enosys and nosys, so comment them out. + if($name =~ /^SYS_E?NOSYS$/){ + $name = "// $name"; + } + if($name eq 'SYS_SYS_EXIT'){ + $name = 'SYS_EXIT'; + } + + print " $name = $num; // $proto\n"; + } +} + +print <<EOF; +) +EOF diff --git a/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl b/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl new file mode 100755 index 000000000..85988b140 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl @@ -0,0 +1,58 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# Generate system call table for OpenBSD from master list +# (for example, /usr/src/sys/kern/syscalls.master). + +use strict; + +if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { + print STDERR "GOARCH or GOOS not defined in environment\n"; + exit 1; +} + +my $command = "mksysnum_netbsd.pl " . join(' ', @ARGV); + +print <<EOF; +// $command +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $ENV{'GOARCH'},$ENV{'GOOS'} + +package unix + +const ( +EOF + +my $line = ''; +while(<>){ + if($line =~ /^(.*)\\$/) { + # Handle continuation + $line = $1; + $_ =~ s/^\s+//; + $line .= $_; + } else { + # New line + $line = $_; + } + next if $line =~ /\\$/; + if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) { + my $num = $1; + my $proto = $6; + my $compat = $8; + my $name = "$7_$9"; + + $name = "$7_$11" if $11 ne ''; + $name =~ y/a-z/A-Z/; + + if($compat eq '' || $compat eq '13' || $compat eq '30' || $compat eq '50') { + print " $name = $num; // $proto\n"; + } + } +} + +print <<EOF; +) +EOF diff --git a/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl b/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl new file mode 100755 index 000000000..84edf60ca --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl @@ -0,0 +1,50 @@ +#!/usr/bin/env perl +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# Generate system call table for OpenBSD from master list +# (for example, /usr/src/sys/kern/syscalls.master). + +use strict; + +if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { + print STDERR "GOARCH or GOOS not defined in environment\n"; + exit 1; +} + +my $command = "mksysnum_openbsd.pl " . join(' ', @ARGV); + +print <<EOF; +// $command +// Code generated by the command above; see README.md. DO NOT EDIT. + +// +build $ENV{'GOARCH'},$ENV{'GOOS'} + +package unix + +const ( +EOF + +while(<>){ + if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){ + my $num = $1; + my $proto = $3; + my $name = $4; + $name =~ y/a-z/A-Z/; + + # There are multiple entries for enosys and nosys, so comment them out. + if($name =~ /^SYS_E?NOSYS$/){ + $name = "// $name"; + } + if($name eq 'SYS_SYS_EXIT'){ + $name = 'SYS_EXIT'; + } + + print " $name = $num; // $proto\n"; + } +} + +print <<EOF; +) +EOF diff --git a/vendor/golang.org/x/sys/unix/mmap_unix_test.go b/vendor/golang.org/x/sys/unix/mmap_unix_test.go new file mode 100644 index 000000000..3258ca328 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/mmap_unix_test.go @@ -0,0 +1,35 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix_test + +import ( + "testing" + + "golang.org/x/sys/unix" +) + +func TestMmap(t *testing.T) { + b, err := unix.Mmap(-1, 0, unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE) + if err != nil { + t.Fatalf("Mmap: %v", err) + } + if err := unix.Mprotect(b, unix.PROT_READ|unix.PROT_WRITE); err != nil { + t.Fatalf("Mprotect: %v", err) + } + + b[0] = 42 + + if err := unix.Msync(b, unix.MS_SYNC); err != nil { + t.Fatalf("Msync: %v", err) + } + if err := unix.Madvise(b, unix.MADV_DONTNEED); err != nil { + t.Fatalf("Madvise: %v", err) + } + if err := unix.Munmap(b); err != nil { + t.Fatalf("Munmap: %v", err) + } +} diff --git a/vendor/golang.org/x/sys/unix/openbsd_test.go b/vendor/golang.org/x/sys/unix/openbsd_test.go new file mode 100644 index 000000000..734d76585 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/openbsd_test.go @@ -0,0 +1,113 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build openbsd + +// This, on the face of it, bizarre testing mechanism is necessary because +// the only reliable way to gauge whether or not a pledge(2) call has succeeded +// is that the program has been killed as a result of breaking its pledge. + +package unix_test + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "testing" + + "golang.org/x/sys/unix" +) + +type testProc struct { + fn func() // should always exit instead of returning + cleanup func() error // for instance, delete coredumps from testing pledge + success bool // whether zero-exit means success or failure +} + +var ( + testProcs = map[string]testProc{} + procName = "" +) + +const ( + optName = "sys-unix-internal-procname" +) + +func init() { + flag.StringVar(&procName, optName, "", "internal use only") +} + +// testCmd generates a proper command that, when executed, runs the test +// corresponding to the given key. +func testCmd(procName string) (*exec.Cmd, error) { + exe, err := filepath.Abs(os.Args[0]) + if err != nil { + return nil, err + } + cmd := exec.Command(exe, "-"+optName+"="+procName) + cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + return cmd, nil +} + +// ExitsCorrectly is a comprehensive, one-line-of-use wrapper for testing +// a testProc with a key. +func ExitsCorrectly(procName string, t *testing.T) { + s := testProcs[procName] + c, err := testCmd(procName) + defer func() { + if s.cleanup() != nil { + t.Fatalf("Failed to run cleanup for %s", procName) + } + }() + if err != nil { + t.Fatalf("Failed to construct command for %s", procName) + } + if (c.Run() == nil) != s.success { + result := "succeed" + if !s.success { + result = "fail" + } + t.Fatalf("Process did not %s when it was supposed to", result) + } +} + +func TestMain(m *testing.M) { + flag.Parse() + if procName != "" { + testProcs[procName].fn() + } + os.Exit(m.Run()) +} + +// For example, add a test for pledge. +func init() { + testProcs["pledge"] = testProc{ + func() { + fmt.Println(unix.Pledge("", nil)) + os.Exit(0) + }, + func() error { + files, err := ioutil.ReadDir(".") + if err != nil { + return err + } + for _, file := range files { + if filepath.Ext(file.Name()) == ".core" { + if err := os.Remove(file.Name()); err != nil { + return err + } + } + } + return nil + }, + false, + } +} + +func TestPledge(t *testing.T) { + ExitsCorrectly("pledge", t) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd_test.go b/vendor/golang.org/x/sys/unix/syscall_bsd_test.go new file mode 100644 index 000000000..6c4e2aca0 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_bsd_test.go @@ -0,0 +1,93 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd openbsd + +package unix_test + +import ( + "os/exec" + "runtime" + "testing" + "time" + + "golang.org/x/sys/unix" +) + +const MNT_WAIT = 1 +const MNT_NOWAIT = 2 + +func TestGetfsstat(t *testing.T) { + const flags = MNT_NOWAIT // see golang.org/issue/16937 + n, err := unix.Getfsstat(nil, flags) + if err != nil { + t.Fatal(err) + } + + data := make([]unix.Statfs_t, n) + n2, err := unix.Getfsstat(data, flags) + if err != nil { + t.Fatal(err) + } + if n != n2 { + t.Errorf("Getfsstat(nil) = %d, but subsequent Getfsstat(slice) = %d", n, n2) + } + for i, stat := range data { + if stat == (unix.Statfs_t{}) { + t.Errorf("index %v is an empty Statfs_t struct", i) + } + } + if t.Failed() { + for i, stat := range data[:n2] { + t.Logf("data[%v] = %+v", i, stat) + } + mount, err := exec.Command("mount").CombinedOutput() + if err != nil { + t.Logf("mount: %v\n%s", err, mount) + } else { + t.Logf("mount: %s", mount) + } + } +} + +func TestSelect(t *testing.T) { + err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0}) + if err != nil { + t.Fatalf("Select: %v", err) + } + + dur := 250 * time.Millisecond + tv := unix.NsecToTimeval(int64(dur)) + start := time.Now() + err = unix.Select(0, nil, nil, nil, &tv) + took := time.Since(start) + if err != nil { + t.Fatalf("Select: %v", err) + } + + // On some BSDs the actual timeout might also be slightly less than the requested. + // Add an acceptable margin to avoid flaky tests. + if took < dur*2/3 { + t.Errorf("Select: timeout should have been at least %v, got %v", dur, took) + } +} + +func TestSysctlRaw(t *testing.T) { + if runtime.GOOS == "openbsd" { + t.Skip("kern.proc.pid does not exist on OpenBSD") + } + + _, err := unix.SysctlRaw("kern.proc.pid", unix.Getpid()) + if err != nil { + t.Fatal(err) + } +} + +func TestSysctlUint32(t *testing.T) { + maxproc, err := unix.SysctlUint32("kern.maxproc") + if err != nil { + t.Fatal(err) + } + t.Logf("kern.maxproc: %v", maxproc) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_test.go b/vendor/golang.org/x/sys/unix/syscall_darwin_test.go new file mode 100644 index 000000000..65691d5c1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_darwin_test.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix_test + +// stringsFromByteSlice converts a sequence of attributes to a []string. +// On Darwin, each entry is a NULL-terminated string. +func stringsFromByteSlice(buf []byte) []string { + var result []string + off := 0 + for i, b := range buf { + if b == 0 { + result = append(result, string(buf[off:i])) + off = i + 1 + } + } + return result +} diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_test.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_test.go new file mode 100644 index 000000000..0fec1a827 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_test.go @@ -0,0 +1,312 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build freebsd + +package unix_test + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "runtime" + "testing" + + "golang.org/x/sys/unix" +) + +func TestSysctlUint64(t *testing.T) { + _, err := unix.SysctlUint64("vm.swap_total") + if err != nil { + t.Fatal(err) + } +} + +// FIXME: Infrastructure for launching tests in subprocesses stolen from openbsd_test.go - refactor? +// testCmd generates a proper command that, when executed, runs the test +// corresponding to the given key. + +type testProc struct { + fn func() // should always exit instead of returning + arg func(t *testing.T) string // generate argument for test + cleanup func(arg string) error // for instance, delete coredumps from testing pledge + success bool // whether zero-exit means success or failure +} + +var ( + testProcs = map[string]testProc{} + procName = "" + procArg = "" +) + +const ( + optName = "sys-unix-internal-procname" + optArg = "sys-unix-internal-arg" +) + +func init() { + flag.StringVar(&procName, optName, "", "internal use only") + flag.StringVar(&procArg, optArg, "", "internal use only") + +} + +func testCmd(procName string, procArg string) (*exec.Cmd, error) { + exe, err := filepath.Abs(os.Args[0]) + if err != nil { + return nil, err + } + cmd := exec.Command(exe, "-"+optName+"="+procName, "-"+optArg+"="+procArg) + cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + return cmd, nil +} + +// ExitsCorrectly is a comprehensive, one-line-of-use wrapper for testing +// a testProc with a key. +func ExitsCorrectly(t *testing.T, procName string) { + s := testProcs[procName] + arg := "-" + if s.arg != nil { + arg = s.arg(t) + } + c, err := testCmd(procName, arg) + defer func(arg string) { + if err := s.cleanup(arg); err != nil { + t.Fatalf("Failed to run cleanup for %s %s %#v", procName, err, err) + } + }(arg) + if err != nil { + t.Fatalf("Failed to construct command for %s", procName) + } + if (c.Run() == nil) != s.success { + result := "succeed" + if !s.success { + result = "fail" + } + t.Fatalf("Process did not %s when it was supposed to", result) + } +} + +func TestMain(m *testing.M) { + flag.Parse() + if procName != "" { + t := testProcs[procName] + t.fn() + os.Stderr.WriteString("test function did not exit\n") + if t.success { + os.Exit(1) + } else { + os.Exit(0) + } + } + os.Exit(m.Run()) +} + +// end of infrastructure + +const testfile = "gocapmodetest" +const testfile2 = testfile + "2" + +func CapEnterTest() { + _, err := os.OpenFile(path.Join(procArg, testfile), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + panic(fmt.Sprintf("OpenFile: %s", err)) + } + + err = unix.CapEnter() + if err != nil { + panic(fmt.Sprintf("CapEnter: %s", err)) + } + + _, err = os.OpenFile(path.Join(procArg, testfile2), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err == nil { + panic("OpenFile works!") + } + if err.(*os.PathError).Err != unix.ECAPMODE { + panic(fmt.Sprintf("OpenFile failed wrong: %s %#v", err, err)) + } + os.Exit(0) +} + +func makeTempDir(t *testing.T) string { + d, err := ioutil.TempDir("", "go_openat_test") + if err != nil { + t.Fatalf("TempDir failed: %s", err) + } + return d +} + +func removeTempDir(arg string) error { + err := os.RemoveAll(arg) + if err != nil && err.(*os.PathError).Err == unix.ENOENT { + return nil + } + return err +} + +func init() { + testProcs["cap_enter"] = testProc{ + CapEnterTest, + makeTempDir, + removeTempDir, + true, + } +} + +func TestCapEnter(t *testing.T) { + if runtime.GOARCH != "amd64" { + t.Skipf("skipping test on %s", runtime.GOARCH) + } + ExitsCorrectly(t, "cap_enter") +} + +func OpenatTest() { + f, err := os.Open(procArg) + if err != nil { + panic(err) + } + + err = unix.CapEnter() + if err != nil { + panic(fmt.Sprintf("CapEnter: %s", err)) + } + + fxx, err := unix.Openat(int(f.Fd()), "xx", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + panic(err) + } + unix.Close(fxx) + + // The right to open BASE/xx is not ambient + _, err = os.OpenFile(procArg+"/xx", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err == nil { + panic("OpenFile succeeded") + } + if err.(*os.PathError).Err != unix.ECAPMODE { + panic(fmt.Sprintf("OpenFile failed wrong: %s %#v", err, err)) + } + + // Can't make a new directory either + err = os.Mkdir(procArg+"2", 0777) + if err == nil { + panic("MKdir succeeded") + } + if err.(*os.PathError).Err != unix.ECAPMODE { + panic(fmt.Sprintf("Mkdir failed wrong: %s %#v", err, err)) + } + + // Remove all caps except read and lookup. + r, err := unix.CapRightsInit([]uint64{unix.CAP_READ, unix.CAP_LOOKUP}) + if err != nil { + panic(fmt.Sprintf("CapRightsInit failed: %s %#v", err, err)) + } + err = unix.CapRightsLimit(f.Fd(), r) + if err != nil { + panic(fmt.Sprintf("CapRightsLimit failed: %s %#v", err, err)) + } + + // Check we can get the rights back again + r, err = unix.CapRightsGet(f.Fd()) + if err != nil { + panic(fmt.Sprintf("CapRightsGet failed: %s %#v", err, err)) + } + b, err := unix.CapRightsIsSet(r, []uint64{unix.CAP_READ, unix.CAP_LOOKUP}) + if err != nil { + panic(fmt.Sprintf("CapRightsIsSet failed: %s %#v", err, err)) + } + if !b { + panic(fmt.Sprintf("Unexpected rights")) + } + b, err = unix.CapRightsIsSet(r, []uint64{unix.CAP_READ, unix.CAP_LOOKUP, unix.CAP_WRITE}) + if err != nil { + panic(fmt.Sprintf("CapRightsIsSet failed: %s %#v", err, err)) + } + if b { + panic(fmt.Sprintf("Unexpected rights (2)")) + } + + // Can no longer create a file + _, err = unix.Openat(int(f.Fd()), "xx2", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err == nil { + panic("Openat succeeded") + } + if err != unix.ENOTCAPABLE { + panic(fmt.Sprintf("OpenFileAt failed wrong: %s %#v", err, err)) + } + + // But can read an existing one + _, err = unix.Openat(int(f.Fd()), "xx", os.O_RDONLY, 0666) + if err != nil { + panic(fmt.Sprintf("Openat failed: %s %#v", err, err)) + } + + os.Exit(0) +} + +func init() { + testProcs["openat"] = testProc{ + OpenatTest, + makeTempDir, + removeTempDir, + true, + } +} + +func TestOpenat(t *testing.T) { + if runtime.GOARCH != "amd64" { + t.Skipf("skipping test on %s", runtime.GOARCH) + } + ExitsCorrectly(t, "openat") +} + +func TestCapRightsSetAndClear(t *testing.T) { + r, err := unix.CapRightsInit([]uint64{unix.CAP_READ, unix.CAP_WRITE, unix.CAP_PDWAIT}) + if err != nil { + t.Fatalf("CapRightsInit failed: %s", err) + } + + err = unix.CapRightsSet(r, []uint64{unix.CAP_EVENT, unix.CAP_LISTEN}) + if err != nil { + t.Fatalf("CapRightsSet failed: %s", err) + } + + b, err := unix.CapRightsIsSet(r, []uint64{unix.CAP_READ, unix.CAP_WRITE, unix.CAP_PDWAIT, unix.CAP_EVENT, unix.CAP_LISTEN}) + if err != nil { + t.Fatalf("CapRightsIsSet failed: %s", err) + } + if !b { + t.Fatalf("Wrong rights set") + } + + err = unix.CapRightsClear(r, []uint64{unix.CAP_READ, unix.CAP_PDWAIT}) + if err != nil { + t.Fatalf("CapRightsClear failed: %s", err) + } + + b, err = unix.CapRightsIsSet(r, []uint64{unix.CAP_WRITE, unix.CAP_EVENT, unix.CAP_LISTEN}) + if err != nil { + t.Fatalf("CapRightsIsSet failed: %s", err) + } + if !b { + t.Fatalf("Wrong rights set") + } +} + +// stringsFromByteSlice converts a sequence of attributes to a []string. +// On FreeBSD, each entry consists of a single byte containing the length +// of the attribute name, followed by the attribute name. +// The name is _not_ NULL-terminated. +func stringsFromByteSlice(buf []byte) []string { + var result []string + i := 0 + for i < len(buf) { + next := i + 1 + int(buf[i]) + result = append(result, string(buf[i+1:next])) + i = next + } + return result +} diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_test.go b/vendor/golang.org/x/sys/unix/syscall_linux_test.go new file mode 100644 index 000000000..9c99893c3 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_test.go @@ -0,0 +1,387 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux + +package unix_test + +import ( + "os" + "runtime" + "runtime/debug" + "testing" + "time" + + "golang.org/x/sys/unix" +) + +func TestIoctlGetInt(t *testing.T) { + f, err := os.Open("/dev/random") + if err != nil { + t.Fatalf("failed to open device: %v", err) + } + defer f.Close() + + v, err := unix.IoctlGetInt(int(f.Fd()), unix.RNDGETENTCNT) + if err != nil { + t.Fatalf("failed to perform ioctl: %v", err) + } + + t.Logf("%d bits of entropy available", v) +} + +func TestPpoll(t *testing.T) { + f, cleanup := mktmpfifo(t) + defer cleanup() + + const timeout = 100 * time.Millisecond + + ok := make(chan bool, 1) + go func() { + select { + case <-time.After(10 * timeout): + t.Errorf("Ppoll: failed to timeout after %d", 10*timeout) + case <-ok: + } + }() + + fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}} + timeoutTs := unix.NsecToTimespec(int64(timeout)) + n, err := unix.Ppoll(fds, &timeoutTs, nil) + ok <- true + if err != nil { + t.Errorf("Ppoll: unexpected error: %v", err) + return + } + if n != 0 { + t.Errorf("Ppoll: wrong number of events: got %v, expected %v", n, 0) + return + } +} + +func TestTime(t *testing.T) { + var ut unix.Time_t + ut2, err := unix.Time(&ut) + if err != nil { + t.Fatalf("Time: %v", err) + } + if ut != ut2 { + t.Errorf("Time: return value %v should be equal to argument %v", ut2, ut) + } + + var now time.Time + + for i := 0; i < 10; i++ { + ut, err = unix.Time(nil) + if err != nil { + t.Fatalf("Time: %v", err) + } + + now = time.Now() + + if int64(ut) == now.Unix() { + return + } + } + + t.Errorf("Time: return value %v should be nearly equal to time.Now().Unix() %v", ut, now.Unix()) +} + +func TestUtime(t *testing.T) { + defer chtmpdir(t)() + + touch(t, "file1") + + buf := &unix.Utimbuf{ + Modtime: 12345, + } + + err := unix.Utime("file1", buf) + if err != nil { + t.Fatalf("Utime: %v", err) + } + + fi, err := os.Stat("file1") + if err != nil { + t.Fatal(err) + } + + if fi.ModTime().Unix() != 12345 { + t.Errorf("Utime: failed to change modtime: expected %v, got %v", 12345, fi.ModTime().Unix()) + } +} + +func TestUtimesNanoAt(t *testing.T) { + defer chtmpdir(t)() + + symlink := "symlink1" + os.Remove(symlink) + err := os.Symlink("nonexisting", symlink) + if err != nil { + t.Fatal(err) + } + + ts := []unix.Timespec{ + {Sec: 1111, Nsec: 2222}, + {Sec: 3333, Nsec: 4444}, + } + err = unix.UtimesNanoAt(unix.AT_FDCWD, symlink, ts, unix.AT_SYMLINK_NOFOLLOW) + if err != nil { + t.Fatalf("UtimesNanoAt: %v", err) + } + + var st unix.Stat_t + err = unix.Lstat(symlink, &st) + if err != nil { + t.Fatalf("Lstat: %v", err) + } + if st.Atim != ts[0] { + t.Errorf("UtimesNanoAt: wrong atime: %v", st.Atim) + } + if st.Mtim != ts[1] { + t.Errorf("UtimesNanoAt: wrong mtime: %v", st.Mtim) + } +} + +func TestRlimitAs(t *testing.T) { + // disable GC during to avoid flaky test + defer debug.SetGCPercent(debug.SetGCPercent(-1)) + + var rlim unix.Rlimit + err := unix.Getrlimit(unix.RLIMIT_AS, &rlim) + if err != nil { + t.Fatalf("Getrlimit: %v", err) + } + var zero unix.Rlimit + if zero == rlim { + t.Fatalf("Getrlimit: got zero value %#v", rlim) + } + set := rlim + set.Cur = uint64(unix.Getpagesize()) + err = unix.Setrlimit(unix.RLIMIT_AS, &set) + if err != nil { + t.Fatalf("Setrlimit: set failed: %#v %v", set, err) + } + + // RLIMIT_AS was set to the page size, so mmap()'ing twice the page size + // should fail. See 'man 2 getrlimit'. + _, err = unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE) + if err == nil { + t.Fatal("Mmap: unexpectedly suceeded after setting RLIMIT_AS") + } + + err = unix.Setrlimit(unix.RLIMIT_AS, &rlim) + if err != nil { + t.Fatalf("Setrlimit: restore failed: %#v %v", rlim, err) + } + + b, err := unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE) + if err != nil { + t.Fatalf("Mmap: %v", err) + } + err = unix.Munmap(b) + if err != nil { + t.Fatalf("Munmap: %v", err) + } +} + +func TestSelect(t *testing.T) { + _, err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0}) + if err != nil { + t.Fatalf("Select: %v", err) + } + + dur := 150 * time.Millisecond + tv := unix.NsecToTimeval(int64(dur)) + start := time.Now() + _, err = unix.Select(0, nil, nil, nil, &tv) + took := time.Since(start) + if err != nil { + t.Fatalf("Select: %v", err) + } + + if took < dur { + t.Errorf("Select: timeout should have been at least %v, got %v", dur, took) + } +} + +func TestPselect(t *testing.T) { + _, err := unix.Pselect(0, nil, nil, nil, &unix.Timespec{Sec: 0, Nsec: 0}, nil) + if err != nil { + t.Fatalf("Pselect: %v", err) + } + + dur := 2500 * time.Microsecond + ts := unix.NsecToTimespec(int64(dur)) + start := time.Now() + _, err = unix.Pselect(0, nil, nil, nil, &ts, nil) + took := time.Since(start) + if err != nil { + t.Fatalf("Pselect: %v", err) + } + + if took < dur { + t.Errorf("Pselect: timeout should have been at least %v, got %v", dur, took) + } +} + +func TestSchedSetaffinity(t *testing.T) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var oldMask unix.CPUSet + err := unix.SchedGetaffinity(0, &oldMask) + if err != nil { + t.Fatalf("SchedGetaffinity: %v", err) + } + + var newMask unix.CPUSet + newMask.Zero() + if newMask.Count() != 0 { + t.Errorf("CpuZero: didn't zero CPU set: %v", newMask) + } + cpu := 1 + newMask.Set(cpu) + if newMask.Count() != 1 || !newMask.IsSet(cpu) { + t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask) + } + cpu = 5 + newMask.Set(cpu) + if newMask.Count() != 2 || !newMask.IsSet(cpu) { + t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask) + } + newMask.Clear(cpu) + if newMask.Count() != 1 || newMask.IsSet(cpu) { + t.Errorf("CpuClr: didn't clear CPU %d in set: %v", cpu, newMask) + } + + if runtime.NumCPU() < 2 { + t.Skip("skipping setaffinity tests on single CPU system") + } + + err = unix.SchedSetaffinity(0, &newMask) + if err != nil { + t.Fatalf("SchedSetaffinity: %v", err) + } + + var gotMask unix.CPUSet + err = unix.SchedGetaffinity(0, &gotMask) + if err != nil { + t.Fatalf("SchedGetaffinity: %v", err) + } + + if gotMask != newMask { + t.Errorf("SchedSetaffinity: returned affinity mask does not match set affinity mask") + } + + // Restore old mask so it doesn't affect successive tests + err = unix.SchedSetaffinity(0, &oldMask) + if err != nil { + t.Fatalf("SchedSetaffinity: %v", err) + } +} + +func TestStatx(t *testing.T) { + var stx unix.Statx_t + err := unix.Statx(unix.AT_FDCWD, ".", 0, 0, &stx) + if err == unix.ENOSYS || err == unix.EPERM { + t.Skip("statx syscall is not available, skipping test") + } else if err != nil { + t.Fatalf("Statx: %v", err) + } + + defer chtmpdir(t)() + touch(t, "file1") + + var st unix.Stat_t + err = unix.Stat("file1", &st) + if err != nil { + t.Fatalf("Stat: %v", err) + } + + flags := unix.AT_STATX_SYNC_AS_STAT + err = unix.Statx(unix.AT_FDCWD, "file1", flags, unix.STATX_ALL, &stx) + if err != nil { + t.Fatalf("Statx: %v", err) + } + + if uint32(stx.Mode) != st.Mode { + t.Errorf("Statx: returned stat mode does not match Stat") + } + + atime := unix.StatxTimestamp{Sec: int64(st.Atim.Sec), Nsec: uint32(st.Atim.Nsec)} + ctime := unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)} + mtime := unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)} + + if stx.Atime != atime { + t.Errorf("Statx: returned stat atime does not match Stat") + } + if stx.Ctime != ctime { + t.Errorf("Statx: returned stat ctime does not match Stat") + } + if stx.Mtime != mtime { + t.Errorf("Statx: returned stat mtime does not match Stat") + } + + err = os.Symlink("file1", "symlink1") + if err != nil { + t.Fatal(err) + } + + err = unix.Lstat("symlink1", &st) + if err != nil { + t.Fatalf("Lstat: %v", err) + } + + err = unix.Statx(unix.AT_FDCWD, "symlink1", flags, unix.STATX_BASIC_STATS, &stx) + if err != nil { + t.Fatalf("Statx: %v", err) + } + + // follow symlink, expect a regulat file + if stx.Mode&unix.S_IFREG == 0 { + t.Errorf("Statx: didn't follow symlink") + } + + err = unix.Statx(unix.AT_FDCWD, "symlink1", flags|unix.AT_SYMLINK_NOFOLLOW, unix.STATX_ALL, &stx) + if err != nil { + t.Fatalf("Statx: %v", err) + } + + // follow symlink, expect a symlink + if stx.Mode&unix.S_IFLNK == 0 { + t.Errorf("Statx: unexpectedly followed symlink") + } + if uint32(stx.Mode) != st.Mode { + t.Errorf("Statx: returned stat mode does not match Lstat") + } + + atime = unix.StatxTimestamp{Sec: int64(st.Atim.Sec), Nsec: uint32(st.Atim.Nsec)} + ctime = unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)} + mtime = unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)} + + if stx.Atime != atime { + t.Errorf("Statx: returned stat atime does not match Lstat") + } + if stx.Ctime != ctime { + t.Errorf("Statx: returned stat ctime does not match Lstat") + } + if stx.Mtime != mtime { + t.Errorf("Statx: returned stat mtime does not match Lstat") + } +} + +// stringsFromByteSlice converts a sequence of attributes to a []string. +// On Linux, each entry is a NULL-terminated string. +func stringsFromByteSlice(buf []byte) []string { + var result []string + off := 0 + for i, b := range buf { + if b == 0 { + result = append(result, string(buf[off:i])) + off = i + 1 + } + } + return result +} diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris_test.go b/vendor/golang.org/x/sys/unix/syscall_solaris_test.go new file mode 100644 index 000000000..57dba8824 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_solaris_test.go @@ -0,0 +1,55 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris + +package unix_test + +import ( + "os/exec" + "testing" + "time" + + "golang.org/x/sys/unix" +) + +func TestSelect(t *testing.T) { + err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0}) + if err != nil { + t.Fatalf("Select: %v", err) + } + + dur := 150 * time.Millisecond + tv := unix.NsecToTimeval(int64(dur)) + start := time.Now() + err = unix.Select(0, nil, nil, nil, &tv) + took := time.Since(start) + if err != nil { + t.Fatalf("Select: %v", err) + } + + if took < dur { + t.Errorf("Select: timeout should have been at least %v, got %v", dur, took) + } +} + +func TestStatvfs(t *testing.T) { + if err := unix.Statvfs("", nil); err == nil { + t.Fatal(`Statvfs("") expected failure`) + } + + statvfs := unix.Statvfs_t{} + if err := unix.Statvfs("/", &statvfs); err != nil { + t.Errorf(`Statvfs("/") failed: %v`, err) + } + + if t.Failed() { + mount, err := exec.Command("mount").CombinedOutput() + if err != nil { + t.Logf("mount: %v\n%s", err, mount) + } else { + t.Logf("mount: %s", mount) + } + } +} diff --git a/vendor/golang.org/x/sys/unix/syscall_test.go b/vendor/golang.org/x/sys/unix/syscall_test.go new file mode 100644 index 000000000..a8eef7cf8 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_test.go @@ -0,0 +1,60 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix_test + +import ( + "fmt" + "testing" + + "golang.org/x/sys/unix" +) + +func testSetGetenv(t *testing.T, key, value string) { + err := unix.Setenv(key, value) + if err != nil { + t.Fatalf("Setenv failed to set %q: %v", value, err) + } + newvalue, found := unix.Getenv(key) + if !found { + t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value) + } + if newvalue != value { + t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value) + } +} + +func TestEnv(t *testing.T) { + testSetGetenv(t, "TESTENV", "AVALUE") + // make sure TESTENV gets set to "", not deleted + testSetGetenv(t, "TESTENV", "") +} + +func TestItoa(t *testing.T) { + // Make most negative integer: 0x8000... + i := 1 + for i<<1 != 0 { + i <<= 1 + } + if i >= 0 { + t.Fatal("bad math") + } + s := unix.Itoa(i) + f := fmt.Sprint(i) + if s != f { + t.Fatalf("itoa(%d) = %s, want %s", i, s, f) + } +} + +func TestUname(t *testing.T) { + var utsname unix.Utsname + err := unix.Uname(&utsname) + if err != nil { + t.Fatalf("Uname: %v", err) + } + + t.Logf("OS: %s/%s %s", utsname.Sysname[:], utsname.Machine[:], utsname.Release[:]) +} diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_test.go b/vendor/golang.org/x/sys/unix/syscall_unix_test.go new file mode 100644 index 000000000..218a1c5b1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_unix_test.go @@ -0,0 +1,627 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix_test + +import ( + "flag" + "fmt" + "io/ioutil" + "net" + "os" + "os/exec" + "path/filepath" + "runtime" + "syscall" + "testing" + "time" + + "golang.org/x/sys/unix" +) + +// Tests that below functions, structures and constants are consistent +// on all Unix-like systems. +func _() { + // program scheduling priority functions and constants + var ( + _ func(int, int, int) error = unix.Setpriority + _ func(int, int) (int, error) = unix.Getpriority + ) + const ( + _ int = unix.PRIO_USER + _ int = unix.PRIO_PROCESS + _ int = unix.PRIO_PGRP + ) + + // termios constants + const ( + _ int = unix.TCIFLUSH + _ int = unix.TCIOFLUSH + _ int = unix.TCOFLUSH + ) + + // fcntl file locking structure and constants + var ( + _ = unix.Flock_t{ + Type: int16(0), + Whence: int16(0), + Start: int64(0), + Len: int64(0), + Pid: int32(0), + } + ) + const ( + _ = unix.F_GETLK + _ = unix.F_SETLK + _ = unix.F_SETLKW + ) +} + +func TestErrnoSignalName(t *testing.T) { + testErrors := []struct { + num syscall.Errno + name string + }{ + {syscall.EPERM, "EPERM"}, + {syscall.EINVAL, "EINVAL"}, + {syscall.ENOENT, "ENOENT"}, + } + + for _, te := range testErrors { + t.Run(fmt.Sprintf("%d/%s", te.num, te.name), func(t *testing.T) { + e := unix.ErrnoName(te.num) + if e != te.name { + t.Errorf("ErrnoName(%d) returned %s, want %s", te.num, e, te.name) + } + }) + } + + testSignals := []struct { + num syscall.Signal + name string + }{ + {syscall.SIGHUP, "SIGHUP"}, + {syscall.SIGPIPE, "SIGPIPE"}, + {syscall.SIGSEGV, "SIGSEGV"}, + } + + for _, ts := range testSignals { + t.Run(fmt.Sprintf("%d/%s", ts.num, ts.name), func(t *testing.T) { + s := unix.SignalName(ts.num) + if s != ts.name { + t.Errorf("SignalName(%d) returned %s, want %s", ts.num, s, ts.name) + } + }) + } +} + +// TestFcntlFlock tests whether the file locking structure matches +// the calling convention of each kernel. +func TestFcntlFlock(t *testing.T) { + name := filepath.Join(os.TempDir(), "TestFcntlFlock") + fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) + if err != nil { + t.Fatalf("Open failed: %v", err) + } + defer unix.Unlink(name) + defer unix.Close(fd) + flock := unix.Flock_t{ + Type: unix.F_RDLCK, + Start: 0, Len: 0, Whence: 1, + } + if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { + t.Fatalf("FcntlFlock failed: %v", err) + } +} + +// TestPassFD tests passing a file descriptor over a Unix socket. +// +// This test involved both a parent and child process. The parent +// process is invoked as a normal test, with "go test", which then +// runs the child process by running the current test binary with args +// "-test.run=^TestPassFD$" and an environment variable used to signal +// that the test should become the child process instead. +func TestPassFD(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { + passFDChild() + return + } + + tempDir, err := ioutil.TempDir("", "TestPassFD") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDir) + + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) + if err != nil { + t.Fatalf("Socketpair: %v", err) + } + defer unix.Close(fds[0]) + defer unix.Close(fds[1]) + writeFile := os.NewFile(uintptr(fds[0]), "child-writes") + readFile := os.NewFile(uintptr(fds[1]), "parent-reads") + defer writeFile.Close() + defer readFile.Close() + + cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { + cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) + } + cmd.ExtraFiles = []*os.File{writeFile} + + out, err := cmd.CombinedOutput() + if len(out) > 0 || err != nil { + t.Fatalf("child process: %q, %v", out, err) + } + + c, err := net.FileConn(readFile) + if err != nil { + t.Fatalf("FileConn: %v", err) + } + defer c.Close() + + uc, ok := c.(*net.UnixConn) + if !ok { + t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) + } + + buf := make([]byte, 32) // expect 1 byte + oob := make([]byte, 32) // expect 24 bytes + closeUnix := time.AfterFunc(5*time.Second, func() { + t.Logf("timeout reading from unix socket") + uc.Close() + }) + _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) + if err != nil { + t.Fatalf("ReadMsgUnix: %v", err) + } + closeUnix.Stop() + + scms, err := unix.ParseSocketControlMessage(oob[:oobn]) + if err != nil { + t.Fatalf("ParseSocketControlMessage: %v", err) + } + if len(scms) != 1 { + t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) + } + scm := scms[0] + gotFds, err := unix.ParseUnixRights(&scm) + if err != nil { + t.Fatalf("unix.ParseUnixRights: %v", err) + } + if len(gotFds) != 1 { + t.Fatalf("wanted 1 fd; got %#v", gotFds) + } + + f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") + defer f.Close() + + got, err := ioutil.ReadAll(f) + want := "Hello from child process!\n" + if string(got) != want { + t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) + } +} + +// passFDChild is the child process used by TestPassFD. +func passFDChild() { + defer os.Exit(0) + + // Look for our fd. It should be fd 3, but we work around an fd leak + // bug here (http://golang.org/issue/2603) to let it be elsewhere. + var uc *net.UnixConn + for fd := uintptr(3); fd <= 10; fd++ { + f := os.NewFile(fd, "unix-conn") + var ok bool + netc, _ := net.FileConn(f) + uc, ok = netc.(*net.UnixConn) + if ok { + break + } + } + if uc == nil { + fmt.Println("failed to find unix fd") + return + } + + // Make a file f to send to our parent process on uc. + // We make it in tempDir, which our parent will clean up. + flag.Parse() + tempDir := flag.Arg(0) + f, err := ioutil.TempFile(tempDir, "") + if err != nil { + fmt.Printf("TempFile: %v", err) + return + } + + f.Write([]byte("Hello from child process!\n")) + f.Seek(0, 0) + + rights := unix.UnixRights(int(f.Fd())) + dummyByte := []byte("x") + n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) + if err != nil { + fmt.Printf("WriteMsgUnix: %v", err) + return + } + if n != 1 || oobn != len(rights) { + fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) + return + } +} + +// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, +// and ParseUnixRights are able to successfully round-trip lists of file descriptors. +func TestUnixRightsRoundtrip(t *testing.T) { + testCases := [...][][]int{ + {{42}}, + {{1, 2}}, + {{3, 4, 5}}, + {{}}, + {{1, 2}, {3, 4, 5}, {}, {7}}, + } + for _, testCase := range testCases { + b := []byte{} + var n int + for _, fds := range testCase { + // Last assignment to n wins + n = len(b) + unix.CmsgLen(4*len(fds)) + b = append(b, unix.UnixRights(fds...)...) + } + // Truncate b + b = b[:n] + + scms, err := unix.ParseSocketControlMessage(b) + if err != nil { + t.Fatalf("ParseSocketControlMessage: %v", err) + } + if len(scms) != len(testCase) { + t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) + } + for i, scm := range scms { + gotFds, err := unix.ParseUnixRights(&scm) + if err != nil { + t.Fatalf("ParseUnixRights: %v", err) + } + wantFds := testCase[i] + if len(gotFds) != len(wantFds) { + t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) + } + for j, fd := range gotFds { + if fd != wantFds[j] { + t.Fatalf("expected fd %v, got %v", wantFds[j], fd) + } + } + } + } +} + +func TestRlimit(t *testing.T) { + var rlimit, zero unix.Rlimit + err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) + if err != nil { + t.Fatalf("Getrlimit: save failed: %v", err) + } + if zero == rlimit { + t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) + } + set := rlimit + set.Cur = set.Max - 1 + err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set) + if err != nil { + t.Fatalf("Setrlimit: set failed: %#v %v", set, err) + } + var get unix.Rlimit + err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get) + if err != nil { + t.Fatalf("Getrlimit: get failed: %v", err) + } + set = rlimit + set.Cur = set.Max - 1 + if set != get { + // Seems like Darwin requires some privilege to + // increase the soft limit of rlimit sandbox, though + // Setrlimit never reports an error. + switch runtime.GOOS { + case "darwin": + default: + t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) + } + } + err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) + if err != nil { + t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) + } +} + +func TestSeekFailure(t *testing.T) { + _, err := unix.Seek(-1, 0, 0) + if err == nil { + t.Fatalf("Seek(-1, 0, 0) did not fail") + } + str := err.Error() // used to crash on Linux + t.Logf("Seek: %v", str) + if str == "" { + t.Fatalf("Seek(-1, 0, 0) return error with empty message") + } +} + +func TestDup(t *testing.T) { + file, err := ioutil.TempFile("", "TestDup") + if err != nil { + t.Fatalf("Tempfile failed: %v", err) + } + defer os.Remove(file.Name()) + defer file.Close() + f := int(file.Fd()) + + newFd, err := unix.Dup(f) + if err != nil { + t.Fatalf("Dup: %v", err) + } + + err = unix.Dup2(newFd, newFd+1) + if err != nil { + t.Fatalf("Dup2: %v", err) + } + + b1 := []byte("Test123") + b2 := make([]byte, 7) + _, err = unix.Write(newFd+1, b1) + if err != nil { + t.Fatalf("Write to dup2 fd failed: %v", err) + } + _, err = unix.Seek(f, 0, 0) + if err != nil { + t.Fatalf("Seek failed: %v", err) + } + _, err = unix.Read(f, b2) + if err != nil { + t.Fatalf("Read back failed: %v", err) + } + if string(b1) != string(b2) { + t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2)) + } +} + +func TestPoll(t *testing.T) { + f, cleanup := mktmpfifo(t) + defer cleanup() + + const timeout = 100 + + ok := make(chan bool, 1) + go func() { + select { + case <-time.After(10 * timeout * time.Millisecond): + t.Errorf("Poll: failed to timeout after %d milliseconds", 10*timeout) + case <-ok: + } + }() + + fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}} + n, err := unix.Poll(fds, timeout) + ok <- true + if err != nil { + t.Errorf("Poll: unexpected error: %v", err) + return + } + if n != 0 { + t.Errorf("Poll: wrong number of events: got %v, expected %v", n, 0) + return + } +} + +func TestGetwd(t *testing.T) { + fd, err := os.Open(".") + if err != nil { + t.Fatalf("Open .: %s", err) + } + defer fd.Close() + // These are chosen carefully not to be symlinks on a Mac + // (unlike, say, /var, /etc) + dirs := []string{"/", "/usr/bin"} + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + d1, err := ioutil.TempDir("", "d1") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + d2, err := ioutil.TempDir("", "d2") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + dirs = []string{d1, d2} + } + } + oldwd := os.Getenv("PWD") + for _, d := range dirs { + err = os.Chdir(d) + if err != nil { + t.Fatalf("Chdir: %v", err) + } + pwd, err := unix.Getwd() + if err != nil { + t.Fatalf("Getwd in %s: %s", d, err) + } + os.Setenv("PWD", oldwd) + err = fd.Chdir() + if err != nil { + // We changed the current directory and cannot go back. + // Don't let the tests continue; they'll scribble + // all over some other directory. + fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err) + os.Exit(1) + } + if pwd != d { + t.Fatalf("Getwd returned %q want %q", pwd, d) + } + } +} + +func TestFstatat(t *testing.T) { + defer chtmpdir(t)() + + touch(t, "file1") + + var st1 unix.Stat_t + err := unix.Stat("file1", &st1) + if err != nil { + t.Fatalf("Stat: %v", err) + } + + var st2 unix.Stat_t + err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0) + if err != nil { + t.Fatalf("Fstatat: %v", err) + } + + if st1 != st2 { + t.Errorf("Fstatat: returned stat does not match Stat") + } + + err = os.Symlink("file1", "symlink1") + if err != nil { + t.Fatal(err) + } + + err = unix.Lstat("symlink1", &st1) + if err != nil { + t.Fatalf("Lstat: %v", err) + } + + err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW) + if err != nil { + t.Fatalf("Fstatat: %v", err) + } + + if st1 != st2 { + t.Errorf("Fstatat: returned stat does not match Lstat") + } +} + +func TestFchmodat(t *testing.T) { + defer chtmpdir(t)() + + touch(t, "file1") + err := os.Symlink("file1", "symlink1") + if err != nil { + t.Fatal(err) + } + + mode := os.FileMode(0444) + err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), 0) + if err != nil { + t.Fatalf("Fchmodat: unexpected error: %v", err) + } + + fi, err := os.Stat("file1") + if err != nil { + t.Fatal(err) + } + + if fi.Mode() != mode { + t.Errorf("Fchmodat: failed to change file mode: expected %v, got %v", mode, fi.Mode()) + } + + mode = os.FileMode(0644) + didChmodSymlink := true + err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), unix.AT_SYMLINK_NOFOLLOW) + if err != nil { + if (runtime.GOOS == "linux" || runtime.GOOS == "solaris") && err == unix.EOPNOTSUPP { + // Linux and Illumos don't support flags != 0 + didChmodSymlink = false + } else { + t.Fatalf("Fchmodat: unexpected error: %v", err) + } + } + + if !didChmodSymlink { + // Didn't change mode of the symlink. On Linux, the permissions + // of a symbolic link are always 0777 according to symlink(7) + mode = os.FileMode(0777) + } + + var st unix.Stat_t + err = unix.Lstat("symlink1", &st) + if err != nil { + t.Fatal(err) + } + + got := os.FileMode(st.Mode & 0777) + if got != mode { + t.Errorf("Fchmodat: failed to change symlink mode: expected %v, got %v", mode, got) + } +} + +func TestMkdev(t *testing.T) { + major := uint32(42) + minor := uint32(7) + dev := unix.Mkdev(major, minor) + + if unix.Major(dev) != major { + t.Errorf("Major(%#x) == %d, want %d", dev, unix.Major(dev), major) + } + if unix.Minor(dev) != minor { + t.Errorf("Minor(%#x) == %d, want %d", dev, unix.Minor(dev), minor) + } +} + +// mktmpfifo creates a temporary FIFO and provides a cleanup function. +func mktmpfifo(t *testing.T) (*os.File, func()) { + err := unix.Mkfifo("fifo", 0666) + if err != nil { + t.Fatalf("mktmpfifo: failed to create FIFO: %v", err) + } + + f, err := os.OpenFile("fifo", os.O_RDWR, 0666) + if err != nil { + os.Remove("fifo") + t.Fatalf("mktmpfifo: failed to open FIFO: %v", err) + } + + return f, func() { + f.Close() + os.Remove("fifo") + } +} + +// utilities taken from os/os_test.go + +func touch(t *testing.T, name string) { + f, err := os.Create(name) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } +} + +// chtmpdir changes the working directory to a new temporary directory and +// provides a cleanup function. Used when PWD is read-only. +func chtmpdir(t *testing.T) func() { + oldwd, err := os.Getwd() + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + if err := os.Chdir(d); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + return func() { + if err := os.Chdir(oldwd); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + os.RemoveAll(d) + } +} diff --git a/vendor/golang.org/x/sys/unix/timestruct_test.go b/vendor/golang.org/x/sys/unix/timestruct_test.go new file mode 100644 index 000000000..4215f46d1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/timestruct_test.go @@ -0,0 +1,54 @@ +// Copyright 2017 The Go Authors. All right reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package unix_test + +import ( + "testing" + "time" + "unsafe" + + "golang.org/x/sys/unix" +) + +func TestTimeToTimespec(t *testing.T) { + timeTests := []struct { + time time.Time + valid bool + }{ + {time.Unix(0, 0), true}, + {time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), true}, + {time.Date(2262, time.December, 31, 23, 0, 0, 0, time.UTC), false}, + {time.Unix(0x7FFFFFFF, 0), true}, + {time.Unix(0x80000000, 0), false}, + {time.Unix(0x7FFFFFFF, 1000000000), false}, + {time.Unix(0x7FFFFFFF, 999999999), true}, + {time.Unix(-0x80000000, 0), true}, + {time.Unix(-0x80000001, 0), false}, + {time.Date(2038, time.January, 19, 3, 14, 7, 0, time.UTC), true}, + {time.Date(2038, time.January, 19, 3, 14, 8, 0, time.UTC), false}, + {time.Date(1901, time.December, 13, 20, 45, 52, 0, time.UTC), true}, + {time.Date(1901, time.December, 13, 20, 45, 51, 0, time.UTC), false}, + } + + // Currently all targets have either int32 or int64 for Timespec.Sec. + // If there were a new target with unsigned or floating point type for + // it, this test must be adjusted. + have64BitTime := (unsafe.Sizeof(unix.Timespec{}.Sec) == 8) + for _, tt := range timeTests { + ts, err := unix.TimeToTimespec(tt.time) + tt.valid = tt.valid || have64BitTime + if tt.valid && err != nil { + t.Errorf("TimeToTimespec(%v): %v", tt.time, err) + } + if err == nil { + tstime := time.Unix(int64(ts.Sec), int64(ts.Nsec)) + if !tstime.Equal(tt.time) { + t.Errorf("TimeToTimespec(%v) is the time %v", tt.time, tstime) + } + } + } +} diff --git a/vendor/golang.org/x/sys/unix/xattr_test.go b/vendor/golang.org/x/sys/unix/xattr_test.go new file mode 100644 index 000000000..fb846a7b1 --- /dev/null +++ b/vendor/golang.org/x/sys/unix/xattr_test.go @@ -0,0 +1,118 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin freebsd linux + +package unix_test + +import ( + "os" + "runtime" + "strings" + "testing" + + "golang.org/x/sys/unix" +) + +func TestXattr(t *testing.T) { + defer chtmpdir(t)() + + f := "xattr1" + touch(t, f) + + xattrName := "user.test" + xattrDataSet := "gopher" + err := unix.Setxattr(f, xattrName, []byte(xattrDataSet), 0) + if err == unix.ENOTSUP || err == unix.EOPNOTSUPP { + t.Skip("filesystem does not support extended attributes, skipping test") + } else if err != nil { + t.Fatalf("Setxattr: %v", err) + } + + // find size + size, err := unix.Listxattr(f, nil) + if err != nil { + t.Fatalf("Listxattr: %v", err) + } + + if size <= 0 { + t.Fatalf("Listxattr returned an empty list of attributes") + } + + buf := make([]byte, size) + read, err := unix.Listxattr(f, buf) + if err != nil { + t.Fatalf("Listxattr: %v", err) + } + + xattrs := stringsFromByteSlice(buf[:read]) + + xattrWant := xattrName + if runtime.GOOS == "freebsd" { + // On FreeBSD, the namespace is stored separately from the xattr + // name and Listxattr doesn't return the namespace prefix. + xattrWant = strings.TrimPrefix(xattrWant, "user.") + } + found := false + for _, name := range xattrs { + if name == xattrWant { + found = true + } + } + + if !found { + t.Errorf("Listxattr did not return previously set attribute '%s'", xattrName) + } + + // find size + size, err = unix.Getxattr(f, xattrName, nil) + if err != nil { + t.Fatalf("Getxattr: %v", err) + } + + if size <= 0 { + t.Fatalf("Getxattr returned an empty attribute") + } + + xattrDataGet := make([]byte, size) + _, err = unix.Getxattr(f, xattrName, xattrDataGet) + if err != nil { + t.Fatalf("Getxattr: %v", err) + } + + got := string(xattrDataGet) + if got != xattrDataSet { + t.Errorf("Getxattr: expected attribute value %s, got %s", xattrDataSet, got) + } + + err = unix.Removexattr(f, xattrName) + if err != nil { + t.Fatalf("Removexattr: %v", err) + } + + n := "nonexistent" + err = unix.Lsetxattr(n, xattrName, []byte(xattrDataSet), 0) + if err != unix.ENOENT { + t.Errorf("Lsetxattr: expected %v on non-existent file, got %v", unix.ENOENT, err) + } + + _, err = unix.Lgetxattr(n, xattrName, nil) + if err != unix.ENOENT { + t.Errorf("Lgetxattr: %v", err) + } + + s := "symlink1" + err = os.Symlink(n, s) + if err != nil { + t.Fatal(err) + } + + // Linux doesn't support xattrs on symlink according to xattr(7), so + // just test that we get the proper errors. + + err = unix.Lsetxattr(s, xattrName, []byte(xattrDataSet), 0) + if err != nil && (runtime.GOOS != "linux" || err != unix.EPERM) { + t.Fatalf("Lsetxattr: %v", err) + } +} diff --git a/vendor/golang.org/x/sys/windows/syscall_test.go b/vendor/golang.org/x/sys/windows/syscall_test.go new file mode 100644 index 000000000..d7009e44a --- /dev/null +++ b/vendor/golang.org/x/sys/windows/syscall_test.go @@ -0,0 +1,53 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package windows_test + +import ( + "syscall" + "testing" + + "golang.org/x/sys/windows" +) + +func testSetGetenv(t *testing.T, key, value string) { + err := windows.Setenv(key, value) + if err != nil { + t.Fatalf("Setenv failed to set %q: %v", value, err) + } + newvalue, found := windows.Getenv(key) + if !found { + t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value) + } + if newvalue != value { + t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value) + } +} + +func TestEnv(t *testing.T) { + testSetGetenv(t, "TESTENV", "AVALUE") + // make sure TESTENV gets set to "", not deleted + testSetGetenv(t, "TESTENV", "") +} + +func TestGetProcAddressByOrdinal(t *testing.T) { + // Attempt calling shlwapi.dll:IsOS, resolving it by ordinal, as + // suggested in + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb773795.aspx + h, err := windows.LoadLibrary("shlwapi.dll") + if err != nil { + t.Fatalf("Failed to load shlwapi.dll: %s", err) + } + procIsOS, err := windows.GetProcAddressByOrdinal(h, 437) + if err != nil { + t.Fatalf("Could not find shlwapi.dll:IsOS by ordinal: %s", err) + } + const OS_NT = 1 + r, _, _ := syscall.Syscall(procIsOS, 1, OS_NT, 0, 0) + if r == 0 { + t.Error("shlwapi.dll:IsOS(OS_NT) returned 0, expected non-zero value") + } +} diff --git a/vendor/golang.org/x/sys/windows/syscall_windows_test.go b/vendor/golang.org/x/sys/windows/syscall_windows_test.go new file mode 100644 index 000000000..9c7133cc4 --- /dev/null +++ b/vendor/golang.org/x/sys/windows/syscall_windows_test.go @@ -0,0 +1,107 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "syscall" + "testing" + "unsafe" + + "golang.org/x/sys/windows" +) + +func TestWin32finddata(t *testing.T) { + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatalf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + path := filepath.Join(dir, "long_name.and_extension") + f, err := os.Create(path) + if err != nil { + t.Fatalf("failed to create %v: %v", path, err) + } + f.Close() + + type X struct { + fd windows.Win32finddata + got byte + pad [10]byte // to protect ourselves + + } + var want byte = 2 // it is unlikely to have this character in the filename + x := X{got: want} + + pathp, _ := windows.UTF16PtrFromString(path) + h, err := windows.FindFirstFile(pathp, &(x.fd)) + if err != nil { + t.Fatalf("FindFirstFile failed: %v", err) + } + err = windows.FindClose(h) + if err != nil { + t.Fatalf("FindClose failed: %v", err) + } + + if x.got != want { + t.Fatalf("memory corruption: want=%d got=%d", want, x.got) + } +} + +func TestFormatMessage(t *testing.T) { + dll := windows.MustLoadDLL("pdh.dll") + + pdhOpenQuery := func(datasrc *uint16, userdata uint32, query *windows.Handle) (errno uintptr) { + r0, _, _ := syscall.Syscall(dll.MustFindProc("PdhOpenQueryW").Addr(), 3, uintptr(unsafe.Pointer(datasrc)), uintptr(userdata), uintptr(unsafe.Pointer(query))) + return r0 + } + + pdhCloseQuery := func(query windows.Handle) (errno uintptr) { + r0, _, _ := syscall.Syscall(dll.MustFindProc("PdhCloseQuery").Addr(), 1, uintptr(query), 0, 0) + return r0 + } + + var q windows.Handle + name, err := windows.UTF16PtrFromString("no_such_source") + if err != nil { + t.Fatal(err) + } + errno := pdhOpenQuery(name, 0, &q) + if errno == 0 { + pdhCloseQuery(q) + t.Fatal("PdhOpenQuery succeeded, but expected to fail.") + } + + const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS + buf := make([]uint16, 300) + _, err = windows.FormatMessage(flags, uintptr(dll.Handle), uint32(errno), 0, buf, nil) + if err != nil { + t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, errno, err) + } +} + +func abort(funcname string, err error) { + panic(funcname + " failed: " + err.Error()) +} + +func ExampleLoadLibrary() { + h, err := windows.LoadLibrary("kernel32.dll") + if err != nil { + abort("LoadLibrary", err) + } + defer windows.FreeLibrary(h) + proc, err := windows.GetProcAddress(h, "GetVersion") + if err != nil { + abort("GetProcAddress", err) + } + r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0) + major := byte(r) + minor := uint8(r >> 8) + build := uint16(r >> 16) + print("windows version ", major, ".", minor, " (Build ", build, ")\n") +} diff --git a/vendor/golang.org/x/text/.gitattributes b/vendor/golang.org/x/text/.gitattributes new file mode 100644 index 000000000..d2f212e5d --- /dev/null +++ b/vendor/golang.org/x/text/.gitattributes @@ -0,0 +1,10 @@ +# Treat all files in this repo as binary, with no git magic updating +# line endings. Windows users contributing to Go will need to use a +# modern version of git and editors capable of LF line endings. +# +# We'll prevent accidental CRLF line endings from entering the repo +# via the git-review gofmt checks. +# +# See golang.org/issue/9281 + +* -text diff --git a/vendor/golang.org/x/text/.gitignore b/vendor/golang.org/x/text/.gitignore new file mode 100644 index 000000000..b2de568ba --- /dev/null +++ b/vendor/golang.org/x/text/.gitignore @@ -0,0 +1,6 @@ +# Add no patterns to .gitignore except for files generated by the build. +last-change +/DATA +# This file is rather large and the tests really only need to be run +# after generation. +/unicode/norm/data_test.go \ No newline at end of file diff --git a/vendor/golang.org/x/text/CONTRIBUTING.md b/vendor/golang.org/x/text/CONTRIBUTING.md new file mode 100644 index 000000000..88dff59bc --- /dev/null +++ b/vendor/golang.org/x/text/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +**We do not accept GitHub pull requests** +(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. + diff --git a/vendor/golang.org/x/text/README.md b/vendor/golang.org/x/text/README.md new file mode 100644 index 000000000..b3f365eed --- /dev/null +++ b/vendor/golang.org/x/text/README.md @@ -0,0 +1,93 @@ +# Go Text + +This repository holds supplementary Go libraries for text processing, many involving Unicode. + +## Semantic Versioning +This repo uses Semantic versioning (http://semver.org/), so +1. MAJOR version when you make incompatible API changes, +1. MINOR version when you add functionality in a backwards-compatible manner, + and +1. PATCH version when you make backwards-compatible bug fixes. + +Until version 1.0.0 of x/text is reached, the minor version is considered a +major version. So going from 0.1.0 to 0.2.0 is considered to be a major version +bump. + +A major new CLDR version is mapped to a minor version increase in x/text. +Any other new CLDR version is mapped to a patch version increase in x/text. + +It is important that the Unicode version used in `x/text` matches the one used +by your Go compiler. The `x/text` repository supports multiple versions of +Unicode and will match the version of Unicode to that of the Go compiler. At the +moment this is supported for Go compilers from version 1.7. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/text`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/text`. + +## Contribute +To submit changes to this repository, see http://golang.org/doc/contribute.html. + +To generate the tables in this repository (except for the encoding tables), +run go generate from this directory. By default tables are generated for the +Unicode version in core and the CLDR version defined in +golang.org/x/text/unicode/cldr. + +Running go generate will as a side effect create a DATA subdirectory in this +directory, which holds all files that are used as a source for generating the +tables. This directory will also serve as a cache. + +## Testing +Run + + go test ./... + +from this directory to run all tests. Add the "-tags icu" flag to also run +ICU conformance tests (if available). This requires that you have the correct +ICU version installed on your system. + +TODO: +- updating unversioned source files. + +## Generating Tables + +To generate the tables in this repository (except for the encoding +tables), run `go generate` from this directory. By default tables are +generated for the Unicode version in core and the CLDR version defined in +golang.org/x/text/unicode/cldr. + +Running go generate will as a side effect create a DATA subdirectory in this +directory which holds all files that are used as a source for generating the +tables. This directory will also serve as a cache. + +## Versions +To update a Unicode version run + + UNICODE_VERSION=x.x.x go generate + +where `x.x.x` must correspond to a directory in http://www.unicode.org/Public/. +If this version is newer than the version in core it will also update the +relevant packages there. The idna package in x/net will always be updated. + +To update a CLDR version run + + CLDR_VERSION=version go generate + +where `version` must correspond to a directory in +http://www.unicode.org/Public/cldr/. + +Note that the code gets adapted over time to changes in the data and that +backwards compatibility is not maintained. +So updating to a different version may not work. + +The files in DATA/{iana|icu|w3|whatwg} are currently not versioned. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the image repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/image:" in the +subject line, so it is easy to find. diff --git a/vendor/golang.org/x/text/codereview.cfg b/vendor/golang.org/x/text/codereview.cfg new file mode 100644 index 000000000..3f8b14b64 --- /dev/null +++ b/vendor/golang.org/x/text/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/text/collate/build/builder_test.go b/vendor/golang.org/x/text/collate/build/builder_test.go new file mode 100644 index 000000000..ff0aba3ae --- /dev/null +++ b/vendor/golang.org/x/text/collate/build/builder_test.go @@ -0,0 +1,290 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package build + +import "testing" + +// cjk returns an implicit collation element for a CJK rune. +func cjk(r rune) []rawCE { + // A CJK character C is represented in the DUCET as + // [.AAAA.0020.0002.C][.BBBB.0000.0000.C] + // Where AAAA is the most significant 15 bits plus a base value. + // Any base value will work for the test, so we pick the common value of FB40. + const base = 0xFB40 + return []rawCE{ + {w: []int{base + int(r>>15), defaultSecondary, defaultTertiary, int(r)}}, + {w: []int{int(r&0x7FFF) | 0x8000, 0, 0, int(r)}}, + } +} + +func pCE(p int) []rawCE { + return mkCE([]int{p, defaultSecondary, defaultTertiary, 0}, 0) +} + +func pqCE(p, q int) []rawCE { + return mkCE([]int{p, defaultSecondary, defaultTertiary, q}, 0) +} + +func ptCE(p, t int) []rawCE { + return mkCE([]int{p, defaultSecondary, t, 0}, 0) +} + +func ptcCE(p, t int, ccc uint8) []rawCE { + return mkCE([]int{p, defaultSecondary, t, 0}, ccc) +} + +func sCE(s int) []rawCE { + return mkCE([]int{0, s, defaultTertiary, 0}, 0) +} + +func stCE(s, t int) []rawCE { + return mkCE([]int{0, s, t, 0}, 0) +} + +func scCE(s int, ccc uint8) []rawCE { + return mkCE([]int{0, s, defaultTertiary, 0}, ccc) +} + +func mkCE(w []int, ccc uint8) []rawCE { + return []rawCE{rawCE{w, ccc}} +} + +// ducetElem is used to define test data that is used to generate a table. +type ducetElem struct { + str string + ces []rawCE +} + +func newBuilder(t *testing.T, ducet []ducetElem) *Builder { + b := NewBuilder() + for _, e := range ducet { + ces := [][]int{} + for _, ce := range e.ces { + ces = append(ces, ce.w) + } + if err := b.Add([]rune(e.str), ces, nil); err != nil { + t.Errorf(err.Error()) + } + } + b.t = &table{} + b.root.sort() + return b +} + +type convertTest struct { + in, out []rawCE + err bool +} + +var convLargeTests = []convertTest{ + {pCE(0xFB39), pCE(0xFB39), false}, + {cjk(0x2F9B2), pqCE(0x3F9B2, 0x2F9B2), false}, + {pCE(0xFB40), pCE(0), true}, + {append(pCE(0xFB40), pCE(0)[0]), pCE(0), true}, + {pCE(0xFFFE), pCE(illegalOffset), false}, + {pCE(0xFFFF), pCE(illegalOffset + 1), false}, +} + +func TestConvertLarge(t *testing.T) { + for i, tt := range convLargeTests { + e := new(entry) + for _, ce := range tt.in { + e.elems = append(e.elems, makeRawCE(ce.w, ce.ccc)) + } + elems, err := convertLargeWeights(e.elems) + if tt.err { + if err == nil { + t.Errorf("%d: expected error; none found", i) + } + continue + } else if err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + } + if !equalCEArrays(elems, tt.out) { + t.Errorf("%d: conversion was %x; want %x", i, elems, tt.out) + } + } +} + +// Collation element table for simplify tests. +var simplifyTest = []ducetElem{ + {"\u0300", sCE(30)}, // grave + {"\u030C", sCE(40)}, // caron + {"A", ptCE(100, 8)}, + {"D", ptCE(104, 8)}, + {"E", ptCE(105, 8)}, + {"I", ptCE(110, 8)}, + {"z", ptCE(130, 8)}, + {"\u05F2", append(ptCE(200, 4), ptCE(200, 4)[0])}, + {"\u05B7", sCE(80)}, + {"\u00C0", append(ptCE(100, 8), sCE(30)...)}, // A with grave, can be removed + {"\u00C8", append(ptCE(105, 8), sCE(30)...)}, // E with grave + {"\uFB1F", append(ptCE(200, 4), ptCE(200, 4)[0], sCE(80)[0])}, // eliminated by NFD + {"\u00C8\u0302", ptCE(106, 8)}, // block previous from simplifying + {"\u01C5", append(ptCE(104, 9), ptCE(130, 4)[0], stCE(40, maxTertiary)[0])}, // eliminated by NFKD + // no removal: tertiary value of third element is not maxTertiary + {"\u2162", append(ptCE(110, 9), ptCE(110, 4)[0], ptCE(110, 8)[0])}, +} + +var genColTests = []ducetElem{ + {"\uFA70", pqCE(0x1FA70, 0xFA70)}, + {"A\u0300", append(ptCE(100, 8), sCE(30)...)}, + {"A\u0300\uFA70", append(ptCE(100, 8), sCE(30)[0], pqCE(0x1FA70, 0xFA70)[0])}, + {"A\u0300A\u0300", append(ptCE(100, 8), sCE(30)[0], ptCE(100, 8)[0], sCE(30)[0])}, +} + +func TestGenColElems(t *testing.T) { + b := newBuilder(t, simplifyTest[:5]) + + for i, tt := range genColTests { + res := b.root.genColElems(tt.str) + if !equalCEArrays(tt.ces, res) { + t.Errorf("%d: result %X; want %X", i, res, tt.ces) + } + } +} + +type strArray []string + +func (sa strArray) contains(s string) bool { + for _, e := range sa { + if e == s { + return true + } + } + return false +} + +var simplifyRemoved = strArray{"\u00C0", "\uFB1F"} +var simplifyMarked = strArray{"\u01C5"} + +func TestSimplify(t *testing.T) { + b := newBuilder(t, simplifyTest) + o := &b.root + simplify(o) + + for i, tt := range simplifyTest { + if simplifyRemoved.contains(tt.str) { + continue + } + e := o.find(tt.str) + if e.str != tt.str || !equalCEArrays(e.elems, tt.ces) { + t.Errorf("%d: found element %s -> %X; want %s -> %X", i, e.str, e.elems, tt.str, tt.ces) + break + } + } + var i, k int + for e := o.front(); e != nil; e, _ = e.nextIndexed() { + gold := simplifyMarked.contains(e.str) + if gold { + k++ + } + if gold != e.decompose { + t.Errorf("%d: %s has decompose %v; want %v", i, e.str, e.decompose, gold) + } + i++ + } + if k != len(simplifyMarked) { + t.Errorf(" an entry that should be marked as decompose was deleted") + } +} + +var expandTest = []ducetElem{ + {"\u0300", append(scCE(29, 230), scCE(30, 230)...)}, + {"\u00C0", append(ptCE(100, 8), scCE(30, 230)...)}, + {"\u00C8", append(ptCE(105, 8), scCE(30, 230)...)}, + {"\u00C9", append(ptCE(105, 8), scCE(30, 230)...)}, // identical expansion + {"\u05F2", append(ptCE(200, 4), ptCE(200, 4)[0], ptCE(200, 4)[0])}, + {"\u01FF", append(ptCE(200, 4), ptcCE(201, 4, 0)[0], scCE(30, 230)[0])}, +} + +func TestExpand(t *testing.T) { + const ( + totalExpansions = 5 + totalElements = 2 + 2 + 2 + 3 + 3 + totalExpansions + ) + b := newBuilder(t, expandTest) + o := &b.root + b.processExpansions(o) + + e := o.front() + for _, tt := range expandTest { + exp := b.t.ExpandElem[e.expansionIndex:] + if int(exp[0]) != len(tt.ces) { + t.Errorf("%U: len(expansion)==%d; want %d", []rune(tt.str)[0], exp[0], len(tt.ces)) + } + exp = exp[1:] + for j, w := range tt.ces { + if ce, _ := makeCE(w); exp[j] != ce { + t.Errorf("%U: element %d is %X; want %X", []rune(tt.str)[0], j, exp[j], ce) + } + } + e, _ = e.nextIndexed() + } + // Verify uniquing. + if len(b.t.ExpandElem) != totalElements { + t.Errorf("len(expandElem)==%d; want %d", len(b.t.ExpandElem), totalElements) + } +} + +var contractTest = []ducetElem{ + {"abc", pCE(102)}, + {"abd", pCE(103)}, + {"a", pCE(100)}, + {"ab", pCE(101)}, + {"ac", pCE(104)}, + {"bcd", pCE(202)}, + {"b", pCE(200)}, + {"bc", pCE(201)}, + {"bd", pCE(203)}, + // shares suffixes with a* + {"Ab", pCE(301)}, + {"A", pCE(300)}, + {"Ac", pCE(304)}, + {"Abc", pCE(302)}, + {"Abd", pCE(303)}, + // starter to be ignored + {"z", pCE(1000)}, +} + +func TestContract(t *testing.T) { + const ( + totalElements = 5 + 5 + 4 + ) + b := newBuilder(t, contractTest) + o := &b.root + b.processContractions(o) + + indexMap := make(map[int]bool) + handleMap := make(map[rune]*entry) + for e := o.front(); e != nil; e, _ = e.nextIndexed() { + if e.contractionHandle.n > 0 { + handleMap[e.runes[0]] = e + indexMap[e.contractionHandle.index] = true + } + } + // Verify uniquing. + if len(indexMap) != 2 { + t.Errorf("number of tries is %d; want %d", len(indexMap), 2) + } + for _, tt := range contractTest { + e, ok := handleMap[[]rune(tt.str)[0]] + if !ok { + continue + } + str := tt.str[1:] + offset, n := lookup(&b.t.ContractTries, e.contractionHandle, []byte(str)) + if len(str) != n { + t.Errorf("%s: bytes consumed==%d; want %d", tt.str, n, len(str)) + } + ce := b.t.ContractElem[offset+e.contractionIndex] + if want, _ := makeCE(tt.ces[0]); want != ce { + t.Errorf("%s: element %X; want %X", tt.str, ce, want) + } + } + if len(b.t.ContractElem) != totalElements { + t.Errorf("len(expandElem)==%d; want %d", len(b.t.ContractElem), totalElements) + } +} diff --git a/vendor/golang.org/x/text/collate/build/colelem_test.go b/vendor/golang.org/x/text/collate/build/colelem_test.go new file mode 100644 index 000000000..d0c8d07d8 --- /dev/null +++ b/vendor/golang.org/x/text/collate/build/colelem_test.go @@ -0,0 +1,215 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package build + +import ( + "testing" + + "golang.org/x/text/internal/colltab" +) + +type ceTest struct { + f func(in []int) (uint32, error) + arg []int + val uint32 +} + +func normalCE(in []int) (ce uint32, err error) { + return makeCE(rawCE{w: in[:3], ccc: uint8(in[3])}) +} + +func expandCE(in []int) (ce uint32, err error) { + return makeExpandIndex(in[0]) +} + +func contractCE(in []int) (ce uint32, err error) { + return makeContractIndex(ctHandle{in[0], in[1]}, in[2]) +} + +func decompCE(in []int) (ce uint32, err error) { + return makeDecompose(in[0], in[1]) +} + +var ceTests = []ceTest{ + {normalCE, []int{0, 0, 0, 0}, 0xA0000000}, + {normalCE, []int{0, 0x28, 3, 0}, 0xA0002803}, + {normalCE, []int{0, 0x28, 3, 0xFF}, 0xAFF02803}, + {normalCE, []int{100, defaultSecondary, 3, 0}, 0x0000C883}, + // non-ignorable primary with non-default secondary + {normalCE, []int{100, 0x28, defaultTertiary, 0}, 0x4000C828}, + {normalCE, []int{100, defaultSecondary + 8, 3, 0}, 0x0000C983}, + {normalCE, []int{100, 0, 3, 0}, 0xFFFF}, // non-ignorable primary with non-supported secondary + {normalCE, []int{100, 1, 3, 0}, 0xFFFF}, + {normalCE, []int{1 << maxPrimaryBits, defaultSecondary, 0, 0}, 0xFFFF}, + {normalCE, []int{0, 1 << maxSecondaryBits, 0, 0}, 0xFFFF}, + {normalCE, []int{100, defaultSecondary, 1 << maxTertiaryBits, 0}, 0xFFFF}, + {normalCE, []int{0x123, defaultSecondary, 8, 0xFF}, 0x88FF0123}, + {normalCE, []int{0x123, defaultSecondary + 1, 8, 0xFF}, 0xFFFF}, + + {contractCE, []int{0, 0, 0}, 0xC0000000}, + {contractCE, []int{1, 1, 1}, 0xC0010011}, + {contractCE, []int{1, (1 << maxNBits) - 1, 1}, 0xC001001F}, + {contractCE, []int{(1 << maxTrieIndexBits) - 1, 1, 1}, 0xC001FFF1}, + {contractCE, []int{1, 1, (1 << maxContractOffsetBits) - 1}, 0xDFFF0011}, + {contractCE, []int{1, (1 << maxNBits), 1}, 0xFFFF}, + {contractCE, []int{(1 << maxTrieIndexBits), 1, 1}, 0xFFFF}, + {contractCE, []int{1, (1 << maxContractOffsetBits), 1}, 0xFFFF}, + + {expandCE, []int{0}, 0xE0000000}, + {expandCE, []int{5}, 0xE0000005}, + {expandCE, []int{(1 << maxExpandIndexBits) - 1}, 0xE000FFFF}, + {expandCE, []int{1 << maxExpandIndexBits}, 0xFFFF}, + + {decompCE, []int{0, 0}, 0xF0000000}, + {decompCE, []int{1, 1}, 0xF0000101}, + {decompCE, []int{0x1F, 0x1F}, 0xF0001F1F}, + {decompCE, []int{256, 0x1F}, 0xFFFF}, + {decompCE, []int{0x1F, 256}, 0xFFFF}, +} + +func TestColElem(t *testing.T) { + for i, tt := range ceTests { + in := make([]int, len(tt.arg)) + copy(in, tt.arg) + ce, err := tt.f(in) + if tt.val == 0xFFFF { + if err == nil { + t.Errorf("%d: expected error for args %x", i, tt.arg) + } + continue + } + if err != nil { + t.Errorf("%d: unexpected error: %v", i, err.Error()) + } + if ce != tt.val { + t.Errorf("%d: colElem=%X; want %X", i, ce, tt.val) + } + } +} + +func mkRawCES(in [][]int) []rawCE { + out := []rawCE{} + for _, w := range in { + out = append(out, rawCE{w: w}) + } + return out +} + +type weightsTest struct { + a, b [][]int + level colltab.Level + result int +} + +var nextWeightTests = []weightsTest{ + { + a: [][]int{{100, 20, 5, 0}}, + b: [][]int{{101, defaultSecondary, defaultTertiary, 0}}, + level: colltab.Primary, + }, + { + a: [][]int{{100, 20, 5, 0}}, + b: [][]int{{100, 21, defaultTertiary, 0}}, + level: colltab.Secondary, + }, + { + a: [][]int{{100, 20, 5, 0}}, + b: [][]int{{100, 20, 6, 0}}, + level: colltab.Tertiary, + }, + { + a: [][]int{{100, 20, 5, 0}}, + b: [][]int{{100, 20, 5, 0}}, + level: colltab.Identity, + }, +} + +var extra = [][]int{{200, 32, 8, 0}, {0, 32, 8, 0}, {0, 0, 8, 0}, {0, 0, 0, 0}} + +func TestNextWeight(t *testing.T) { + for i, tt := range nextWeightTests { + test := func(l colltab.Level, tt weightsTest, a, gold [][]int) { + res := nextWeight(tt.level, mkRawCES(a)) + if !equalCEArrays(mkRawCES(gold), res) { + t.Errorf("%d:%d: expected weights %d; found %d", i, l, gold, res) + } + } + test(-1, tt, tt.a, tt.b) + for l := colltab.Primary; l <= colltab.Tertiary; l++ { + if tt.level <= l { + test(l, tt, append(tt.a, extra[l]), tt.b) + } else { + test(l, tt, append(tt.a, extra[l]), append(tt.b, extra[l])) + } + } + } +} + +var compareTests = []weightsTest{ + { + [][]int{{100, 20, 5, 0}}, + [][]int{{100, 20, 5, 0}}, + colltab.Identity, + 0, + }, + { + [][]int{{100, 20, 5, 0}, extra[0]}, + [][]int{{100, 20, 5, 1}}, + colltab.Primary, + 1, + }, + { + [][]int{{100, 20, 5, 0}}, + [][]int{{101, 20, 5, 0}}, + colltab.Primary, + -1, + }, + { + [][]int{{101, 20, 5, 0}}, + [][]int{{100, 20, 5, 0}}, + colltab.Primary, + 1, + }, + { + [][]int{{100, 0, 0, 0}, {0, 20, 5, 0}}, + [][]int{{0, 20, 5, 0}, {100, 0, 0, 0}}, + colltab.Identity, + 0, + }, + { + [][]int{{100, 20, 5, 0}}, + [][]int{{100, 21, 5, 0}}, + colltab.Secondary, + -1, + }, + { + [][]int{{100, 20, 5, 0}}, + [][]int{{100, 20, 2, 0}}, + colltab.Tertiary, + 1, + }, + { + [][]int{{100, 20, 5, 1}}, + [][]int{{100, 20, 5, 2}}, + colltab.Quaternary, + -1, + }, +} + +func TestCompareWeights(t *testing.T) { + for i, tt := range compareTests { + test := func(tt weightsTest, a, b [][]int) { + res, level := compareWeights(mkRawCES(a), mkRawCES(b)) + if res != tt.result { + t.Errorf("%d: expected comparison result %d; found %d", i, tt.result, res) + } + if level != tt.level { + t.Errorf("%d: expected level %d; found %d", i, tt.level, level) + } + } + test(tt, tt.a, tt.b) + test(tt, append(tt.a, extra[0]), append(tt.b, extra[0])) + } +} diff --git a/vendor/golang.org/x/text/collate/build/contract_test.go b/vendor/golang.org/x/text/collate/build/contract_test.go new file mode 100644 index 000000000..2e0eaecd5 --- /dev/null +++ b/vendor/golang.org/x/text/collate/build/contract_test.go @@ -0,0 +1,266 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package build + +import ( + "bytes" + "sort" + "testing" + + "golang.org/x/text/internal/colltab" +) + +var largetosmall = []stridx{ + {"a", 5}, + {"ab", 4}, + {"abc", 3}, + {"abcd", 2}, + {"abcde", 1}, + {"abcdef", 0}, +} + +var offsetSortTests = [][]stridx{ + { + {"bcde", 1}, + {"bc", 5}, + {"ab", 4}, + {"bcd", 3}, + {"abcd", 0}, + {"abc", 2}, + }, + largetosmall, +} + +func TestOffsetSort(t *testing.T) { + for i, st := range offsetSortTests { + sort.Sort(offsetSort(st)) + for j, si := range st { + if j != si.index { + t.Errorf("%d: failed: %v", i, st) + } + } + } + for i, tt := range genStateTests { + // ensure input is well-formed + sort.Sort(offsetSort(tt.in)) + for j, si := range tt.in { + if si.index != j+1 { + t.Errorf("%dth sort failed: %v", i, tt.in) + } + } + } +} + +var genidxtest1 = []stridx{ + {"bcde", 3}, + {"bc", 6}, + {"ab", 2}, + {"bcd", 5}, + {"abcd", 0}, + {"abc", 1}, + {"bcdf", 4}, +} + +var genidxSortTests = [][]stridx{ + genidxtest1, + largetosmall, +} + +func TestGenIdxSort(t *testing.T) { + for i, st := range genidxSortTests { + sort.Sort(genidxSort(st)) + for j, si := range st { + if j != si.index { + t.Errorf("%dth sort failed %v", i, st) + break + } + } + } +} + +var entrySortTests = []colltab.ContractTrieSet{ + { + {10, 0, 1, 3}, + {99, 0, 1, 0}, + {20, 50, 0, 2}, + {30, 0, 1, 1}, + }, +} + +func TestEntrySort(t *testing.T) { + for i, et := range entrySortTests { + sort.Sort(entrySort(et)) + for j, fe := range et { + if j != int(fe.I) { + t.Errorf("%dth sort failed %v", i, et) + break + } + } + } +} + +type GenStateTest struct { + in []stridx + firstBlockLen int + out colltab.ContractTrieSet +} + +var genStateTests = []GenStateTest{ + {[]stridx{ + {"abc", 1}, + }, + 1, + colltab.ContractTrieSet{ + {'a', 0, 1, noIndex}, + {'b', 0, 1, noIndex}, + {'c', 'c', final, 1}, + }, + }, + {[]stridx{ + {"abc", 1}, + {"abd", 2}, + {"abe", 3}, + }, + 1, + colltab.ContractTrieSet{ + {'a', 0, 1, noIndex}, + {'b', 0, 1, noIndex}, + {'c', 'e', final, 1}, + }, + }, + {[]stridx{ + {"abc", 1}, + {"ab", 2}, + {"a", 3}, + }, + 1, + colltab.ContractTrieSet{ + {'a', 0, 1, 3}, + {'b', 0, 1, 2}, + {'c', 'c', final, 1}, + }, + }, + {[]stridx{ + {"abc", 1}, + {"abd", 2}, + {"ab", 3}, + {"ac", 4}, + {"a", 5}, + {"b", 6}, + }, + 2, + colltab.ContractTrieSet{ + {'b', 'b', final, 6}, + {'a', 0, 2, 5}, + {'c', 'c', final, 4}, + {'b', 0, 1, 3}, + {'c', 'd', final, 1}, + }, + }, + {[]stridx{ + {"bcde", 2}, + {"bc", 7}, + {"ab", 6}, + {"bcd", 5}, + {"abcd", 1}, + {"abc", 4}, + {"bcdf", 3}, + }, + 2, + colltab.ContractTrieSet{ + {'b', 3, 1, noIndex}, + {'a', 0, 1, noIndex}, + {'b', 0, 1, 6}, + {'c', 0, 1, 4}, + {'d', 'd', final, 1}, + {'c', 0, 1, 7}, + {'d', 0, 1, 5}, + {'e', 'f', final, 2}, + }, + }, +} + +func TestGenStates(t *testing.T) { + for i, tt := range genStateTests { + si := []stridx{} + for _, e := range tt.in { + si = append(si, e) + } + // ensure input is well-formed + sort.Sort(genidxSort(si)) + ct := colltab.ContractTrieSet{} + n, _ := genStates(&ct, si) + if nn := tt.firstBlockLen; nn != n { + t.Errorf("%d: block len %v; want %v", i, n, nn) + } + if lv, lw := len(ct), len(tt.out); lv != lw { + t.Errorf("%d: len %v; want %v", i, lv, lw) + continue + } + for j, fe := range tt.out { + const msg = "%d:%d: value %s=%v; want %v" + if fe.L != ct[j].L { + t.Errorf(msg, i, j, "l", ct[j].L, fe.L) + } + if fe.H != ct[j].H { + t.Errorf(msg, i, j, "h", ct[j].H, fe.H) + } + if fe.N != ct[j].N { + t.Errorf(msg, i, j, "n", ct[j].N, fe.N) + } + if fe.I != ct[j].I { + t.Errorf(msg, i, j, "i", ct[j].I, fe.I) + } + } + } +} + +func TestLookupContraction(t *testing.T) { + for i, tt := range genStateTests { + input := []string{} + for _, e := range tt.in { + input = append(input, e.str) + } + cts := colltab.ContractTrieSet{} + h, _ := appendTrie(&cts, input) + for j, si := range tt.in { + str := si.str + for _, s := range []string{str, str + "X"} { + msg := "%d:%d: %s(%s) %v; want %v" + idx, sn := lookup(&cts, h, []byte(s)) + if idx != si.index { + t.Errorf(msg, i, j, "index", s, idx, si.index) + } + if sn != len(str) { + t.Errorf(msg, i, j, "sn", s, sn, len(str)) + } + } + } + } +} + +func TestPrintContractionTrieSet(t *testing.T) { + testdata := colltab.ContractTrieSet(genStateTests[4].out) + buf := &bytes.Buffer{} + print(&testdata, buf, "test") + if contractTrieOutput != buf.String() { + t.Errorf("output differs; found\n%s", buf.String()) + println(string(buf.Bytes())) + } +} + +const contractTrieOutput = `// testCTEntries: 8 entries, 32 bytes +var testCTEntries = [8]struct{L,H,N,I uint8}{ + {0x62, 0x3, 1, 255}, + {0x61, 0x0, 1, 255}, + {0x62, 0x0, 1, 6}, + {0x63, 0x0, 1, 4}, + {0x64, 0x64, 0, 1}, + {0x63, 0x0, 1, 7}, + {0x64, 0x0, 1, 5}, + {0x65, 0x66, 0, 2}, +} +var testContractTrieSet = colltab.ContractTrieSet( testCTEntries[:] ) +` diff --git a/vendor/golang.org/x/text/collate/build/order_test.go b/vendor/golang.org/x/text/collate/build/order_test.go new file mode 100644 index 000000000..0e174bfbd --- /dev/null +++ b/vendor/golang.org/x/text/collate/build/order_test.go @@ -0,0 +1,229 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package build + +import ( + "strconv" + "testing" + + "golang.org/x/text/internal/colltab" +) + +type entryTest struct { + f func(in []int) (uint32, error) + arg []int + val uint32 +} + +// makeList returns a list of entries of length n+2, with n normal +// entries plus a leading and trailing anchor. +func makeList(n int) []*entry { + es := make([]*entry, n+2) + weights := []rawCE{{w: []int{100, 20, 5, 0}}} + for i := range es { + runes := []rune{rune(i)} + es[i] = &entry{ + runes: runes, + elems: weights, + } + weights = nextWeight(colltab.Primary, weights) + } + for i := 1; i < len(es); i++ { + es[i-1].next = es[i] + es[i].prev = es[i-1] + _, es[i-1].level = compareWeights(es[i-1].elems, es[i].elems) + } + es[0].exclude = true + es[0].logical = firstAnchor + es[len(es)-1].exclude = true + es[len(es)-1].logical = lastAnchor + return es +} + +func TestNextIndexed(t *testing.T) { + const n = 5 + es := makeList(n) + for i := int64(0); i < 1<<n; i++ { + mask := strconv.FormatInt(i+(1<<n), 2) + for i, c := range mask { + es[i].exclude = c == '1' + } + e := es[0] + for i, c := range mask { + if c == '0' { + e, _ = e.nextIndexed() + if e != es[i] { + t.Errorf("%d: expected entry %d; found %d", i, es[i].elems, e.elems) + } + } + } + if e, _ = e.nextIndexed(); e != nil { + t.Errorf("%d: expected nil entry; found %d", i, e.elems) + } + } +} + +func TestRemove(t *testing.T) { + const n = 5 + for i := int64(0); i < 1<<n; i++ { + es := makeList(n) + mask := strconv.FormatInt(i+(1<<n), 2) + for i, c := range mask { + if c == '0' { + es[i].remove() + } + } + e := es[0] + for i, c := range mask { + if c == '1' { + if e != es[i] { + t.Errorf("%d: expected entry %d; found %d", i, es[i].elems, e.elems) + } + e, _ = e.nextIndexed() + } + } + if e != nil { + t.Errorf("%d: expected nil entry; found %d", i, e.elems) + } + } +} + +// nextPerm generates the next permutation of the array. The starting +// permutation is assumed to be a list of integers sorted in increasing order. +// It returns false if there are no more permuations left. +func nextPerm(a []int) bool { + i := len(a) - 2 + for ; i >= 0; i-- { + if a[i] < a[i+1] { + break + } + } + if i < 0 { + return false + } + for j := len(a) - 1; j >= i; j-- { + if a[j] > a[i] { + a[i], a[j] = a[j], a[i] + break + } + } + for j := i + 1; j < (len(a)+i+1)/2; j++ { + a[j], a[len(a)+i-j] = a[len(a)+i-j], a[j] + } + return true +} + +func TestInsertAfter(t *testing.T) { + const n = 5 + orig := makeList(n) + perm := make([]int, n) + for i := range perm { + perm[i] = i + 1 + } + for ok := true; ok; ok = nextPerm(perm) { + es := makeList(n) + last := es[0] + for _, i := range perm { + last.insertAfter(es[i]) + last = es[i] + } + for _, e := range es { + e.elems = es[0].elems + } + e := es[0] + for _, i := range perm { + e, _ = e.nextIndexed() + if e.runes[0] != orig[i].runes[0] { + t.Errorf("%d:%d: expected entry %X; found %X", perm, i, orig[i].runes, e.runes) + break + } + } + } +} + +func TestInsertBefore(t *testing.T) { + const n = 5 + orig := makeList(n) + perm := make([]int, n) + for i := range perm { + perm[i] = i + 1 + } + for ok := true; ok; ok = nextPerm(perm) { + es := makeList(n) + last := es[len(es)-1] + for _, i := range perm { + last.insertBefore(es[i]) + last = es[i] + } + for _, e := range es { + e.elems = es[0].elems + } + e := es[0] + for i := n - 1; i >= 0; i-- { + e, _ = e.nextIndexed() + if e.runes[0] != rune(perm[i]) { + t.Errorf("%d:%d: expected entry %X; found %X", perm, i, orig[i].runes, e.runes) + break + } + } + } +} + +type entryLessTest struct { + a, b *entry + res bool +} + +var ( + w1 = []rawCE{{w: []int{100, 20, 5, 5}}} + w2 = []rawCE{{w: []int{101, 20, 5, 5}}} +) + +var entryLessTests = []entryLessTest{ + {&entry{str: "a", elems: w1}, + &entry{str: "a", elems: w1}, + false, + }, + {&entry{str: "a", elems: w1}, + &entry{str: "a", elems: w2}, + true, + }, + {&entry{str: "a", elems: w1}, + &entry{str: "b", elems: w1}, + true, + }, + {&entry{str: "a", elems: w2}, + &entry{str: "a", elems: w1}, + false, + }, + {&entry{str: "c", elems: w1}, + &entry{str: "b", elems: w1}, + false, + }, + {&entry{str: "a", elems: w1, logical: firstAnchor}, + &entry{str: "a", elems: w1}, + true, + }, + {&entry{str: "a", elems: w1}, + &entry{str: "b", elems: w1, logical: firstAnchor}, + false, + }, + {&entry{str: "b", elems: w1}, + &entry{str: "a", elems: w1, logical: lastAnchor}, + true, + }, + {&entry{str: "a", elems: w1, logical: lastAnchor}, + &entry{str: "c", elems: w1}, + false, + }, +} + +func TestEntryLess(t *testing.T) { + for i, tt := range entryLessTests { + if res := entryLess(tt.a, tt.b); res != tt.res { + t.Errorf("%d: was %v; want %v", i, res, tt.res) + } + } +} diff --git a/vendor/golang.org/x/text/collate/build/trie_test.go b/vendor/golang.org/x/text/collate/build/trie_test.go new file mode 100644 index 000000000..4d4f6e4d1 --- /dev/null +++ b/vendor/golang.org/x/text/collate/build/trie_test.go @@ -0,0 +1,107 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package build + +import ( + "bytes" + "fmt" + "testing" +) + +// We take the smallest, largest and an arbitrary value for each +// of the UTF-8 sequence lengths. +var testRunes = []rune{ + 0x01, 0x0C, 0x7F, // 1-byte sequences + 0x80, 0x100, 0x7FF, // 2-byte sequences + 0x800, 0x999, 0xFFFF, // 3-byte sequences + 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences + 0x200, 0x201, 0x202, 0x210, 0x215, // five entries in one sparse block +} + +func makeTestTrie(t *testing.T) trie { + n := newNode() + for i, r := range testRunes { + n.insert(r, uint32(i)) + } + idx := newTrieBuilder() + idx.addTrie(n) + tr, err := idx.generate() + if err != nil { + t.Errorf(err.Error()) + } + return *tr +} + +func TestGenerateTrie(t *testing.T) { + testdata := makeTestTrie(t) + buf := &bytes.Buffer{} + testdata.printArrays(buf, "test") + fmt.Fprintf(buf, "var testTrie = ") + testdata.printStruct(buf, &trieHandle{19, 0}, "test") + if output != buf.String() { + t.Error("output differs") + } +} + +var output = `// testValues: 832 entries, 3328 bytes +// Block 2 is the null block. +var testValues = [832]uint32 { + // Block 0x0, offset 0x0 + 0x000c:0x00000001, + // Block 0x1, offset 0x40 + 0x007f:0x00000002, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00c0:0x00000003, + // Block 0x4, offset 0x100 + 0x0100:0x00000004, + // Block 0x5, offset 0x140 + 0x0140:0x0000000c, 0x0141:0x0000000d, 0x0142:0x0000000e, + 0x0150:0x0000000f, + 0x0155:0x00000010, + // Block 0x6, offset 0x180 + 0x01bf:0x00000005, + // Block 0x7, offset 0x1c0 + 0x01c0:0x00000006, + // Block 0x8, offset 0x200 + 0x0219:0x00000007, + // Block 0x9, offset 0x240 + 0x027f:0x00000008, + // Block 0xa, offset 0x280 + 0x0280:0x00000009, + // Block 0xb, offset 0x2c0 + 0x02c1:0x0000000a, + // Block 0xc, offset 0x300 + 0x033f:0x0000000b, +} + +// testLookup: 640 entries, 1280 bytes +// Block 0 is the null block. +var testLookup = [640]uint16 { + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0e0:0x05, 0x0e6:0x06, + // Block 0x4, offset 0x100 + 0x13f:0x07, + // Block 0x5, offset 0x140 + 0x140:0x08, 0x144:0x09, + // Block 0x6, offset 0x180 + 0x190:0x03, + // Block 0x7, offset 0x1c0 + 0x1ff:0x0a, + // Block 0x8, offset 0x200 + 0x20f:0x05, + // Block 0x9, offset 0x240 + 0x242:0x01, 0x244:0x02, + 0x248:0x03, + 0x25f:0x04, + 0x260:0x01, + 0x26f:0x02, + 0x270:0x04, 0x274:0x06, +} + +var testTrie = trie{ testLookup[1216:], testValues[0:], testLookup[:], testValues[:]}` diff --git a/vendor/golang.org/x/text/collate/collate_test.go b/vendor/golang.org/x/text/collate/collate_test.go new file mode 100644 index 000000000..0e78b96fa --- /dev/null +++ b/vendor/golang.org/x/text/collate/collate_test.go @@ -0,0 +1,482 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package collate + +import ( + "bytes" + "testing" + + "golang.org/x/text/internal/colltab" + "golang.org/x/text/language" +) + +type weightsTest struct { + opt opts + in, out ColElems +} + +type opts struct { + lev int + alt alternateHandling + top int + + backwards bool + caseLevel bool +} + +// ignore returns an initialized boolean array based on the given Level. +// A negative value means using the default setting of quaternary. +func ignore(level colltab.Level) (ignore [colltab.NumLevels]bool) { + if level < 0 { + level = colltab.Quaternary + } + for i := range ignore { + ignore[i] = level < colltab.Level(i) + } + return ignore +} + +func makeCE(w []int) colltab.Elem { + ce, err := colltab.MakeElem(w[0], w[1], w[2], uint8(w[3])) + if err != nil { + panic(err) + } + return ce +} + +func (o opts) collator() *Collator { + c := &Collator{ + options: options{ + ignore: ignore(colltab.Level(o.lev - 1)), + alternate: o.alt, + backwards: o.backwards, + caseLevel: o.caseLevel, + variableTop: uint32(o.top), + }, + } + return c +} + +const ( + maxQ = 0x1FFFFF +) + +func wpq(p, q int) Weights { + return W(p, defaults.Secondary, defaults.Tertiary, q) +} + +func wsq(s, q int) Weights { + return W(0, s, defaults.Tertiary, q) +} + +func wq(q int) Weights { + return W(0, 0, 0, q) +} + +var zero = W(0, 0, 0, 0) + +var processTests = []weightsTest{ + // Shifted + { // simple sequence of non-variables + opt: opts{alt: altShifted, top: 100}, + in: ColElems{W(200), W(300), W(400)}, + out: ColElems{wpq(200, maxQ), wpq(300, maxQ), wpq(400, maxQ)}, + }, + { // first is a variable + opt: opts{alt: altShifted, top: 250}, + in: ColElems{W(200), W(300), W(400)}, + out: ColElems{wq(200), wpq(300, maxQ), wpq(400, maxQ)}, + }, + { // all but first are variable + opt: opts{alt: altShifted, top: 999}, + in: ColElems{W(1000), W(200), W(300), W(400)}, + out: ColElems{wpq(1000, maxQ), wq(200), wq(300), wq(400)}, + }, + { // first is a modifier + opt: opts{alt: altShifted, top: 999}, + in: ColElems{W(0, 10), W(1000)}, + out: ColElems{wsq(10, maxQ), wpq(1000, maxQ)}, + }, + { // primary ignorables + opt: opts{alt: altShifted, top: 250}, + in: ColElems{W(200), W(0, 10), W(300), W(0, 15), W(400)}, + out: ColElems{wq(200), zero, wpq(300, maxQ), wsq(15, maxQ), wpq(400, maxQ)}, + }, + { // secondary ignorables + opt: opts{alt: altShifted, top: 250}, + in: ColElems{W(200), W(0, 0, 10), W(300), W(0, 0, 15), W(400)}, + out: ColElems{wq(200), zero, wpq(300, maxQ), W(0, 0, 15, maxQ), wpq(400, maxQ)}, + }, + { // tertiary ignorables, no change + opt: opts{alt: altShifted, top: 250}, + in: ColElems{W(200), zero, W(300), zero, W(400)}, + out: ColElems{wq(200), zero, wpq(300, maxQ), zero, wpq(400, maxQ)}, + }, + + // ShiftTrimmed (same as Shifted) + { // simple sequence of non-variables + opt: opts{alt: altShiftTrimmed, top: 100}, + in: ColElems{W(200), W(300), W(400)}, + out: ColElems{wpq(200, maxQ), wpq(300, maxQ), wpq(400, maxQ)}, + }, + { // first is a variable + opt: opts{alt: altShiftTrimmed, top: 250}, + in: ColElems{W(200), W(300), W(400)}, + out: ColElems{wq(200), wpq(300, maxQ), wpq(400, maxQ)}, + }, + { // all but first are variable + opt: opts{alt: altShiftTrimmed, top: 999}, + in: ColElems{W(1000), W(200), W(300), W(400)}, + out: ColElems{wpq(1000, maxQ), wq(200), wq(300), wq(400)}, + }, + { // first is a modifier + opt: opts{alt: altShiftTrimmed, top: 999}, + in: ColElems{W(0, 10), W(1000)}, + out: ColElems{wsq(10, maxQ), wpq(1000, maxQ)}, + }, + { // primary ignorables + opt: opts{alt: altShiftTrimmed, top: 250}, + in: ColElems{W(200), W(0, 10), W(300), W(0, 15), W(400)}, + out: ColElems{wq(200), zero, wpq(300, maxQ), wsq(15, maxQ), wpq(400, maxQ)}, + }, + { // secondary ignorables + opt: opts{alt: altShiftTrimmed, top: 250}, + in: ColElems{W(200), W(0, 0, 10), W(300), W(0, 0, 15), W(400)}, + out: ColElems{wq(200), zero, wpq(300, maxQ), W(0, 0, 15, maxQ), wpq(400, maxQ)}, + }, + { // tertiary ignorables, no change + opt: opts{alt: altShiftTrimmed, top: 250}, + in: ColElems{W(200), zero, W(300), zero, W(400)}, + out: ColElems{wq(200), zero, wpq(300, maxQ), zero, wpq(400, maxQ)}, + }, + + // Blanked + { // simple sequence of non-variables + opt: opts{alt: altBlanked, top: 100}, + in: ColElems{W(200), W(300), W(400)}, + out: ColElems{W(200), W(300), W(400)}, + }, + { // first is a variable + opt: opts{alt: altBlanked, top: 250}, + in: ColElems{W(200), W(300), W(400)}, + out: ColElems{zero, W(300), W(400)}, + }, + { // all but first are variable + opt: opts{alt: altBlanked, top: 999}, + in: ColElems{W(1000), W(200), W(300), W(400)}, + out: ColElems{W(1000), zero, zero, zero}, + }, + { // first is a modifier + opt: opts{alt: altBlanked, top: 999}, + in: ColElems{W(0, 10), W(1000)}, + out: ColElems{W(0, 10), W(1000)}, + }, + { // primary ignorables + opt: opts{alt: altBlanked, top: 250}, + in: ColElems{W(200), W(0, 10), W(300), W(0, 15), W(400)}, + out: ColElems{zero, zero, W(300), W(0, 15), W(400)}, + }, + { // secondary ignorables + opt: opts{alt: altBlanked, top: 250}, + in: ColElems{W(200), W(0, 0, 10), W(300), W(0, 0, 15), W(400)}, + out: ColElems{zero, zero, W(300), W(0, 0, 15), W(400)}, + }, + { // tertiary ignorables, no change + opt: opts{alt: altBlanked, top: 250}, + in: ColElems{W(200), zero, W(300), zero, W(400)}, + out: ColElems{zero, zero, W(300), zero, W(400)}, + }, + + // Non-ignorable: input is always equal to output. + { // all but first are variable + opt: opts{alt: altNonIgnorable, top: 999}, + in: ColElems{W(1000), W(200), W(300), W(400)}, + out: ColElems{W(1000), W(200), W(300), W(400)}, + }, + { // primary ignorables + opt: opts{alt: altNonIgnorable, top: 250}, + in: ColElems{W(200), W(0, 10), W(300), W(0, 15), W(400)}, + out: ColElems{W(200), W(0, 10), W(300), W(0, 15), W(400)}, + }, + { // secondary ignorables + opt: opts{alt: altNonIgnorable, top: 250}, + in: ColElems{W(200), W(0, 0, 10), W(300), W(0, 0, 15), W(400)}, + out: ColElems{W(200), W(0, 0, 10), W(300), W(0, 0, 15), W(400)}, + }, + { // tertiary ignorables, no change + opt: opts{alt: altNonIgnorable, top: 250}, + in: ColElems{W(200), zero, W(300), zero, W(400)}, + out: ColElems{W(200), zero, W(300), zero, W(400)}, + }, +} + +func TestProcessWeights(t *testing.T) { + for i, tt := range processTests { + in := convertFromWeights(tt.in) + out := convertFromWeights(tt.out) + processWeights(tt.opt.alt, uint32(tt.opt.top), in) + for j, w := range in { + if w != out[j] { + t.Errorf("%d: Weights %d was %v; want %v", i, j, w, out[j]) + } + } + } +} + +type keyFromElemTest struct { + opt opts + in ColElems + out []byte +} + +var defS = byte(defaults.Secondary) +var defT = byte(defaults.Tertiary) + +const sep = 0 // separator byte + +var keyFromElemTests = []keyFromElemTest{ + { // simple primary and secondary weights. + opts{alt: altShifted}, + ColElems{W(0x200), W(0x7FFF), W(0, 0x30), W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary + sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary + }, + }, + { // same as first, but with zero element that need to be removed + opts{alt: altShifted}, + ColElems{W(0x200), zero, W(0x7FFF), W(0, 0x30), zero, W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary + sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary + }, + }, + { // same as first, with large primary values + opts{alt: altShifted}, + ColElems{W(0x200), W(0x8000), W(0, 0x30), W(0x12345)}, + []byte{0x2, 0, 0x80, 0x80, 0x00, 0x81, 0x23, 0x45, // primary + sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary + }, + }, + { // same as first, but with the secondary level backwards + opts{alt: altShifted, backwards: true}, + ColElems{W(0x200), W(0x7FFF), W(0, 0x30), W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary + sep, sep, 0, defS, 0, 0x30, 0, defS, 0, defS, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + sep, 0xFF, 0xFF, 0xFF, 0xFF, // quaternary + }, + }, + { // same as first, ignoring quaternary level + opts{alt: altShifted, lev: 3}, + ColElems{W(0x200), zero, W(0x7FFF), W(0, 0x30), zero, W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary + sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + }, + }, + { // same as first, ignoring tertiary level + opts{alt: altShifted, lev: 2}, + ColElems{W(0x200), zero, W(0x7FFF), W(0, 0x30), zero, W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary + sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary + }, + }, + { // same as first, ignoring secondary level + opts{alt: altShifted, lev: 1}, + ColElems{W(0x200), zero, W(0x7FFF), W(0, 0x30), zero, W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00}, + }, + { // simple primary and secondary weights. + opts{alt: altShiftTrimmed, top: 0x250}, + ColElems{W(0x300), W(0x200), W(0x7FFF), W(0, 0x30), W(0x800)}, + []byte{0x3, 0, 0x7F, 0xFF, 0x8, 0x00, // primary + sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + sep, 0xFF, 0x2, 0, // quaternary + }, + }, + { // as first, primary with case level enabled + opts{alt: altShifted, lev: 1, caseLevel: true}, + ColElems{W(0x200), W(0x7FFF), W(0, 0x30), W(0x100)}, + []byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary + sep, sep, // secondary + sep, sep, defT, defT, defT, defT, // tertiary + }, + }, +} + +func TestKeyFromElems(t *testing.T) { + buf := Buffer{} + for i, tt := range keyFromElemTests { + buf.Reset() + in := convertFromWeights(tt.in) + processWeights(tt.opt.alt, uint32(tt.opt.top), in) + tt.opt.collator().keyFromElems(&buf, in) + res := buf.key + if len(res) != len(tt.out) { + t.Errorf("%d: len(ws) was %d; want %d (%X should be %X)", i, len(res), len(tt.out), res, tt.out) + } + n := len(res) + if len(tt.out) < n { + n = len(tt.out) + } + for j, c := range res[:n] { + if c != tt.out[j] { + t.Errorf("%d: byte %d was %X; want %X", i, j, c, tt.out[j]) + } + } + } +} + +func TestGetColElems(t *testing.T) { + for i, tt := range appendNextTests { + c, err := makeTable(tt.in) + if err != nil { + // error is reported in TestAppendNext + continue + } + // Create one large test per table + str := make([]byte, 0, 4000) + out := ColElems{} + for len(str) < 3000 { + for _, chk := range tt.chk { + str = append(str, chk.in[:chk.n]...) + out = append(out, chk.out...) + } + } + for j, chk := range append(tt.chk, check{string(str), len(str), out}) { + out := convertFromWeights(chk.out) + ce := c.getColElems([]byte(chk.in)[:chk.n]) + if len(ce) != len(out) { + t.Errorf("%d:%d: len(ws) was %d; want %d", i, j, len(ce), len(out)) + continue + } + cnt := 0 + for k, w := range ce { + w, _ = colltab.MakeElem(w.Primary(), w.Secondary(), int(w.Tertiary()), 0) + if w != out[k] { + t.Errorf("%d:%d: Weights %d was %X; want %X", i, j, k, w, out[k]) + cnt++ + } + if cnt > 10 { + break + } + } + } + } +} + +type keyTest struct { + in string + out []byte +} + +var keyTests = []keyTest{ + {"abc", + []byte{0, 100, 0, 200, 1, 44, 0, 0, 0, 32, 0, 32, 0, 32, 0, 0, 2, 2, 2, 0, 255, 255, 255}, + }, + {"a\u0301", + []byte{0, 102, 0, 0, 0, 32, 0, 0, 2, 0, 255}, + }, + {"aaaaa", + []byte{0, 100, 0, 100, 0, 100, 0, 100, 0, 100, 0, 0, + 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 0, + 2, 2, 2, 2, 2, 0, + 255, 255, 255, 255, 255, + }, + }, + // Issue 16391: incomplete rune at end of UTF-8 sequence. + {"\xc2", []byte{133, 255, 253, 0, 0, 0, 32, 0, 0, 2, 0, 255}}, + {"\xc2a", []byte{133, 255, 253, 0, 100, 0, 0, 0, 32, 0, 32, 0, 0, 2, 2, 0, 255, 255}}, +} + +func TestKey(t *testing.T) { + c, _ := makeTable(appendNextTests[4].in) + c.alternate = altShifted + c.ignore = ignore(colltab.Quaternary) + buf := Buffer{} + keys1 := [][]byte{} + keys2 := [][]byte{} + for _, tt := range keyTests { + keys1 = append(keys1, c.Key(&buf, []byte(tt.in))) + keys2 = append(keys2, c.KeyFromString(&buf, tt.in)) + } + // Separate generation from testing to ensure buffers are not overwritten. + for i, tt := range keyTests { + if !bytes.Equal(keys1[i], tt.out) { + t.Errorf("%d: Key(%q) = %d; want %d", i, tt.in, keys1[i], tt.out) + } + if !bytes.Equal(keys2[i], tt.out) { + t.Errorf("%d: KeyFromString(%q) = %d; want %d", i, tt.in, keys2[i], tt.out) + } + } +} + +type compareTest struct { + a, b string + res int // comparison result +} + +var compareTests = []compareTest{ + {"a\u0301", "a", 1}, + {"a\u0301b", "ab", 1}, + {"a", "a\u0301", -1}, + {"ab", "a\u0301b", -1}, + {"bc", "a\u0301c", 1}, + {"ab", "aB", -1}, + {"a\u0301", "a\u0301", 0}, + {"a", "a", 0}, + // Only clip prefixes of whole runes. + {"\u302E", "\u302F", 1}, + // Don't clip prefixes when last rune of prefix may be part of contraction. + {"a\u035E", "a\u0301\u035F", -1}, + {"a\u0301\u035Fb", "a\u0301\u035F", -1}, +} + +func TestCompare(t *testing.T) { + c, _ := makeTable(appendNextTests[4].in) + for i, tt := range compareTests { + if res := c.Compare([]byte(tt.a), []byte(tt.b)); res != tt.res { + t.Errorf("%d: Compare(%q, %q) == %d; want %d", i, tt.a, tt.b, res, tt.res) + } + if res := c.CompareString(tt.a, tt.b); res != tt.res { + t.Errorf("%d: CompareString(%q, %q) == %d; want %d", i, tt.a, tt.b, res, tt.res) + } + } +} + +func TestNumeric(t *testing.T) { + c := New(language.English, Loose, Numeric) + + for i, tt := range []struct { + a, b string + want int + }{ + {"1", "2", -1}, + {"2", "12", -1}, + {"2", "12", -1}, // Fullwidth is sorted as usual. + {"₂", "₁₂", 1}, // Subscript is not sorted as numbers. + {"②", "①②", 1}, // Circled is not sorted as numbers. + { // Imperial Aramaic, is not sorted as number. + "\U00010859", + "\U00010858\U00010859", + 1, + }, + {"12", "2", 1}, + {"A-1", "A-2", -1}, + {"A-2", "A-12", -1}, + {"A-12", "A-2", 1}, + {"A-0001", "A-1", 0}, + } { + if got := c.CompareString(tt.a, tt.b); got != tt.want { + t.Errorf("%d: CompareString(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want) + } + } +} diff --git a/vendor/golang.org/x/text/collate/export_test.go b/vendor/golang.org/x/text/collate/export_test.go new file mode 100644 index 000000000..69bfeaf1a --- /dev/null +++ b/vendor/golang.org/x/text/collate/export_test.go @@ -0,0 +1,51 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package collate + +// Export for testing. +// TODO: no longer necessary. Remove at some point. + +import ( + "fmt" + + "golang.org/x/text/internal/colltab" +) + +const ( + defaultSecondary = 0x20 + defaultTertiary = 0x2 +) + +type Weights struct { + Primary, Secondary, Tertiary, Quaternary int +} + +func W(ce ...int) Weights { + w := Weights{ce[0], defaultSecondary, defaultTertiary, 0} + if len(ce) > 1 { + w.Secondary = ce[1] + } + if len(ce) > 2 { + w.Tertiary = ce[2] + } + if len(ce) > 3 { + w.Quaternary = ce[3] + } + return w +} +func (w Weights) String() string { + return fmt.Sprintf("[%X.%X.%X.%X]", w.Primary, w.Secondary, w.Tertiary, w.Quaternary) +} + +func convertFromWeights(ws []Weights) []colltab.Elem { + out := make([]colltab.Elem, len(ws)) + for i, w := range ws { + out[i], _ = colltab.MakeElem(w.Primary, w.Secondary, w.Tertiary, 0) + if out[i] == colltab.Ignore && w.Quaternary > 0 { + out[i] = colltab.MakeQuaternary(w.Quaternary) + } + } + return out +} diff --git a/vendor/golang.org/x/text/collate/option_test.go b/vendor/golang.org/x/text/collate/option_test.go new file mode 100644 index 000000000..0f6ba9bc8 --- /dev/null +++ b/vendor/golang.org/x/text/collate/option_test.go @@ -0,0 +1,209 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package collate + +import ( + "reflect" + "strings" + "testing" + + "golang.org/x/text/internal/colltab" + "golang.org/x/text/language" +) + +var ( + defaultIgnore = ignore(colltab.Tertiary) + defaultTable = getTable(locales[0]) +) + +func TestOptions(t *testing.T) { + for i, tt := range []struct { + in []Option + out options + }{ + 0: { + out: options{ + ignore: defaultIgnore, + }, + }, + 1: { + in: []Option{IgnoreDiacritics}, + out: options{ + ignore: [colltab.NumLevels]bool{false, true, false, true, true}, + }, + }, + 2: { + in: []Option{IgnoreCase, IgnoreDiacritics}, + out: options{ + ignore: ignore(colltab.Primary), + }, + }, + 3: { + in: []Option{ignoreDiacritics, IgnoreWidth}, + out: options{ + ignore: ignore(colltab.Primary), + caseLevel: true, + }, + }, + 4: { + in: []Option{IgnoreWidth, ignoreDiacritics}, + out: options{ + ignore: ignore(colltab.Primary), + caseLevel: true, + }, + }, + 5: { + in: []Option{IgnoreCase, IgnoreWidth}, + out: options{ + ignore: ignore(colltab.Secondary), + }, + }, + 6: { + in: []Option{IgnoreCase, IgnoreWidth, Loose}, + out: options{ + ignore: ignore(colltab.Primary), + }, + }, + 7: { + in: []Option{Force, IgnoreCase, IgnoreWidth, Loose}, + out: options{ + ignore: [colltab.NumLevels]bool{false, true, true, true, false}, + }, + }, + 8: { + in: []Option{IgnoreDiacritics, IgnoreCase}, + out: options{ + ignore: ignore(colltab.Primary), + }, + }, + 9: { + in: []Option{Numeric}, + out: options{ + ignore: defaultIgnore, + numeric: true, + }, + }, + 10: { + in: []Option{OptionsFromTag(language.MustParse("und-u-ks-level1"))}, + out: options{ + ignore: ignore(colltab.Primary), + }, + }, + 11: { + in: []Option{OptionsFromTag(language.MustParse("und-u-ks-level4"))}, + out: options{ + ignore: ignore(colltab.Quaternary), + }, + }, + 12: { + in: []Option{OptionsFromTag(language.MustParse("und-u-ks-identic"))}, + out: options{}, + }, + 13: { + in: []Option{ + OptionsFromTag(language.MustParse("und-u-kn-true-kb-true-kc-true")), + }, + out: options{ + ignore: defaultIgnore, + caseLevel: true, + backwards: true, + numeric: true, + }, + }, + 14: { + in: []Option{ + OptionsFromTag(language.MustParse("und-u-kn-true-kb-true-kc-true")), + OptionsFromTag(language.MustParse("und-u-kn-false-kb-false-kc-false")), + }, + out: options{ + ignore: defaultIgnore, + }, + }, + 15: { + in: []Option{ + OptionsFromTag(language.MustParse("und-u-kn-true-kb-true-kc-true")), + OptionsFromTag(language.MustParse("und-u-kn-foo-kb-foo-kc-foo")), + }, + out: options{ + ignore: defaultIgnore, + caseLevel: true, + backwards: true, + numeric: true, + }, + }, + 16: { // Normal options take precedence over tag options. + in: []Option{ + Numeric, IgnoreCase, + OptionsFromTag(language.MustParse("und-u-kn-false-kc-true")), + }, + out: options{ + ignore: ignore(colltab.Secondary), + caseLevel: false, + numeric: true, + }, + }, + 17: { + in: []Option{ + OptionsFromTag(language.MustParse("und-u-ka-shifted")), + }, + out: options{ + ignore: defaultIgnore, + alternate: altShifted, + }, + }, + 18: { + in: []Option{ + OptionsFromTag(language.MustParse("und-u-ka-blanked")), + }, + out: options{ + ignore: defaultIgnore, + alternate: altBlanked, + }, + }, + 19: { + in: []Option{ + OptionsFromTag(language.MustParse("und-u-ka-posix")), + }, + out: options{ + ignore: defaultIgnore, + alternate: altShiftTrimmed, + }, + }, + } { + c := newCollator(defaultTable) + c.t = nil + c.variableTop = 0 + c.f = 0 + + c.setOptions(tt.in) + if !reflect.DeepEqual(c.options, tt.out) { + t.Errorf("%d: got %v; want %v", i, c.options, tt.out) + } + } +} + +func TestAlternateSortTypes(t *testing.T) { + testCases := []struct { + lang string + in []string + want []string + }{{ + lang: "zh,cmn,zh-Hant-u-co-pinyin,zh-HK-u-co-pinyin,zh-pinyin", + in: []string{"爸爸", "妈妈", "儿子", "女儿"}, + want: []string{"爸爸", "儿子", "妈妈", "女儿"}, + }, { + lang: "zh-Hant,zh-u-co-stroke,zh-Hant-u-co-stroke", + in: []string{"爸爸", "妈妈", "儿子", "女儿"}, + want: []string{"儿子", "女儿", "妈妈", "爸爸"}, + }} + for _, tc := range testCases { + for _, tag := range strings.Split(tc.lang, ",") { + got := append([]string{}, tc.in...) + New(language.MustParse(tag)).SortStrings(got) + if !reflect.DeepEqual(got, tc.want) { + t.Errorf("New(%s).SortStrings(%v) = %v; want %v", tag, tc.in, got, tc.want) + } + } + } +} diff --git a/vendor/golang.org/x/text/collate/reg_test.go b/vendor/golang.org/x/text/collate/reg_test.go new file mode 100644 index 000000000..1ac5fedc8 --- /dev/null +++ b/vendor/golang.org/x/text/collate/reg_test.go @@ -0,0 +1,230 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package collate + +import ( + "archive/zip" + "bufio" + "bytes" + "flag" + "io" + "io/ioutil" + "log" + "path" + "regexp" + "strconv" + "strings" + "testing" + "unicode/utf8" + + "golang.org/x/text/collate/build" + "golang.org/x/text/internal/gen" + "golang.org/x/text/language" +) + +var long = flag.Bool("long", false, + "run time-consuming tests, such as tests that fetch data online") + +// This regression test runs tests for the test files in CollationTest.zip +// (taken from http://www.unicode.org/Public/UCA/<gen.UnicodeVersion()>/). +// +// The test files have the following form: +// # header +// 0009 0021; # ('\u0009') <CHARACTER TABULATION> [| | | 0201 025E] +// 0009 003F; # ('\u0009') <CHARACTER TABULATION> [| | | 0201 0263] +// 000A 0021; # ('\u000A') <LINE FEED (LF)> [| | | 0202 025E] +// 000A 003F; # ('\u000A') <LINE FEED (LF)> [| | | 0202 0263] +// +// The part before the semicolon is the hex representation of a sequence +// of runes. After the hash mark is a comment. The strings +// represented by rune sequence are in the file in sorted order, as +// defined by the DUCET. + +type Test struct { + name string + str [][]byte + comment []string +} + +var versionRe = regexp.MustCompile(`# UCA Version: (.*)\n?$`) +var testRe = regexp.MustCompile(`^([\dA-F ]+);.*# (.*)\n?$`) + +func TestCollation(t *testing.T) { + if !gen.IsLocal() && !*long { + t.Skip("skipping test to prevent downloading; to run use -long or use -local to specify a local source") + } + t.Skip("must first update to new file format to support test") + for _, test := range loadTestData() { + doTest(t, test) + } +} + +func Error(e error) { + if e != nil { + log.Fatal(e) + } +} + +// parseUCA parses a Default Unicode Collation Element Table of the format +// specified in http://www.unicode.org/reports/tr10/#File_Format. +// It returns the variable top. +func parseUCA(builder *build.Builder) { + r := gen.OpenUnicodeFile("UCA", "", "allkeys.txt") + defer r.Close() + input := bufio.NewReader(r) + colelem := regexp.MustCompile(`\[([.*])([0-9A-F.]+)\]`) + for i := 1; true; i++ { + l, prefix, err := input.ReadLine() + if err == io.EOF { + break + } + Error(err) + line := string(l) + if prefix { + log.Fatalf("%d: buffer overflow", i) + } + if len(line) == 0 || line[0] == '#' { + continue + } + if line[0] == '@' { + if strings.HasPrefix(line[1:], "version ") { + if v := strings.Split(line[1:], " ")[1]; v != gen.UnicodeVersion() { + log.Fatalf("incompatible version %s; want %s", v, gen.UnicodeVersion()) + } + } + } else { + // parse entries + part := strings.Split(line, " ; ") + if len(part) != 2 { + log.Fatalf("%d: production rule without ';': %v", i, line) + } + lhs := []rune{} + for _, v := range strings.Split(part[0], " ") { + if v != "" { + lhs = append(lhs, rune(convHex(i, v))) + } + } + vars := []int{} + rhs := [][]int{} + for i, m := range colelem.FindAllStringSubmatch(part[1], -1) { + if m[1] == "*" { + vars = append(vars, i) + } + elem := []int{} + for _, h := range strings.Split(m[2], ".") { + elem = append(elem, convHex(i, h)) + } + rhs = append(rhs, elem) + } + builder.Add(lhs, rhs, vars) + } + } +} + +func convHex(line int, s string) int { + r, e := strconv.ParseInt(s, 16, 32) + if e != nil { + log.Fatalf("%d: %v", line, e) + } + return int(r) +} + +func loadTestData() []Test { + f := gen.OpenUnicodeFile("UCA", "", "CollationTest.zip") + buffer, err := ioutil.ReadAll(f) + f.Close() + Error(err) + archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer))) + Error(err) + tests := []Test{} + for _, f := range archive.File { + // Skip the short versions, which are simply duplicates of the long versions. + if strings.Contains(f.Name, "SHORT") || f.FileInfo().IsDir() { + continue + } + ff, err := f.Open() + Error(err) + defer ff.Close() + scanner := bufio.NewScanner(ff) + test := Test{name: path.Base(f.Name)} + for scanner.Scan() { + line := scanner.Text() + if len(line) <= 1 || line[0] == '#' { + if m := versionRe.FindStringSubmatch(line); m != nil { + if m[1] != gen.UnicodeVersion() { + log.Printf("warning:%s: version is %s; want %s", f.Name, m[1], gen.UnicodeVersion()) + } + } + continue + } + m := testRe.FindStringSubmatch(line) + if m == nil || len(m) < 3 { + log.Fatalf(`Failed to parse: "%s" result: %#v`, line, m) + } + str := []byte{} + // In the regression test data (unpaired) surrogates are assigned a weight + // corresponding to their code point value. However, utf8.DecodeRune, + // which is used to compute the implicit weight, assigns FFFD to surrogates. + // We therefore skip tests with surrogates. This skips about 35 entries + // per test. + valid := true + for _, split := range strings.Split(m[1], " ") { + r, err := strconv.ParseUint(split, 16, 64) + Error(err) + valid = valid && utf8.ValidRune(rune(r)) + str = append(str, string(rune(r))...) + } + if valid { + test.str = append(test.str, str) + test.comment = append(test.comment, m[2]) + } + } + if scanner.Err() != nil { + log.Fatal(scanner.Err()) + } + tests = append(tests, test) + } + return tests +} + +var errorCount int + +func runes(b []byte) []rune { + return []rune(string(b)) +} + +var shifted = language.MustParse("und-u-ka-shifted-ks-level4") + +func doTest(t *testing.T, tc Test) { + bld := build.NewBuilder() + parseUCA(bld) + w, err := bld.Build() + Error(err) + var tag language.Tag + if !strings.Contains(tc.name, "NON_IGNOR") { + tag = shifted + } + c := NewFromTable(w, OptionsFromTag(tag)) + b := &Buffer{} + prev := tc.str[0] + for i := 1; i < len(tc.str); i++ { + b.Reset() + s := tc.str[i] + ka := c.Key(b, prev) + kb := c.Key(b, s) + if r := bytes.Compare(ka, kb); r == 1 { + t.Errorf("%s:%d: Key(%.4X) < Key(%.4X) (%X < %X) == %d; want -1 or 0", tc.name, i, []rune(string(prev)), []rune(string(s)), ka, kb, r) + prev = s + continue + } + if r := c.Compare(prev, s); r == 1 { + t.Errorf("%s:%d: Compare(%.4X, %.4X) == %d; want -1 or 0", tc.name, i, runes(prev), runes(s), r) + } + if r := c.Compare(s, prev); r == -1 { + t.Errorf("%s:%d: Compare(%.4X, %.4X) == %d; want 1 or 0", tc.name, i, runes(s), runes(prev), r) + } + prev = s + } +} diff --git a/vendor/golang.org/x/text/collate/sort_test.go b/vendor/golang.org/x/text/collate/sort_test.go new file mode 100644 index 000000000..d9e7f31cc --- /dev/null +++ b/vendor/golang.org/x/text/collate/sort_test.go @@ -0,0 +1,55 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package collate_test + +import ( + "fmt" + "testing" + + "golang.org/x/text/collate" + "golang.org/x/text/language" +) + +func ExampleCollator_Strings() { + c := collate.New(language.Und) + strings := []string{ + "ad", + "ab", + "äb", + "ac", + } + c.SortStrings(strings) + fmt.Println(strings) + // Output: [ab äb ac ad] +} + +type sorter []string + +func (s sorter) Len() int { + return len(s) +} + +func (s sorter) Swap(i, j int) { + s[j], s[i] = s[i], s[j] +} + +func (s sorter) Bytes(i int) []byte { + return []byte(s[i]) +} + +func TestSort(t *testing.T) { + c := collate.New(language.English) + strings := []string{ + "bcd", + "abc", + "ddd", + } + c.Sort(sorter(strings)) + res := fmt.Sprint(strings) + want := "[abc bcd ddd]" + if res != want { + t.Errorf("found %s; want %s", res, want) + } +} diff --git a/vendor/golang.org/x/text/collate/table_test.go b/vendor/golang.org/x/text/collate/table_test.go new file mode 100644 index 000000000..3a6b12fd6 --- /dev/null +++ b/vendor/golang.org/x/text/collate/table_test.go @@ -0,0 +1,291 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package collate + +import ( + "testing" + + "golang.org/x/text/collate/build" + "golang.org/x/text/internal/colltab" + "golang.org/x/text/unicode/norm" +) + +type ColElems []Weights + +type input struct { + str string + ces [][]int +} + +type check struct { + in string + n int + out ColElems +} + +type tableTest struct { + in []input + chk []check +} + +func w(ce ...int) Weights { + return W(ce...) +} + +var defaults = w(0) + +func pt(p, t int) []int { + return []int{p, defaults.Secondary, t} +} + +func makeTable(in []input) (*Collator, error) { + b := build.NewBuilder() + for _, r := range in { + if e := b.Add([]rune(r.str), r.ces, nil); e != nil { + panic(e) + } + } + t, err := b.Build() + if err != nil { + return nil, err + } + return NewFromTable(t), nil +} + +// modSeq holds a seqeunce of modifiers in increasing order of CCC long enough +// to cause a segment overflow if not handled correctly. The last rune in this +// list has a CCC of 214. +var modSeq = []rune{ + 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BB, + 0x05BC, 0x05BD, 0x05BF, 0x05C1, 0x05C2, 0xFB1E, 0x064B, 0x064C, 0x064D, 0x064E, + 0x064F, 0x0650, 0x0651, 0x0652, 0x0670, 0x0711, 0x0C55, 0x0C56, 0x0E38, 0x0E48, + 0x0EB8, 0x0EC8, 0x0F71, 0x0F72, 0x0F74, 0x0321, 0x1DCE, +} + +var mods []input +var modW = func() ColElems { + ws := ColElems{} + for _, r := range modSeq { + rune := norm.NFC.PropertiesString(string(r)) + ws = append(ws, w(0, int(rune.CCC()))) + mods = append(mods, input{string(r), [][]int{{0, int(rune.CCC())}}}) + } + return ws +}() + +var appendNextTests = []tableTest{ + { // test getWeights + []input{ + {"a", [][]int{{100}}}, + {"b", [][]int{{105}}}, + {"c", [][]int{{110}}}, + {"ß", [][]int{{120}}}, + }, + []check{ + {"a", 1, ColElems{w(100)}}, + {"b", 1, ColElems{w(105)}}, + {"c", 1, ColElems{w(110)}}, + {"d", 1, ColElems{w(0x50064)}}, + {"ab", 1, ColElems{w(100)}}, + {"bc", 1, ColElems{w(105)}}, + {"dd", 1, ColElems{w(0x50064)}}, + {"ß", 2, ColElems{w(120)}}, + }, + }, + { // test expansion + []input{ + {"u", [][]int{{100}}}, + {"U", [][]int{{100}, {0, 25}}}, + {"w", [][]int{{100}, {100}}}, + {"W", [][]int{{100}, {0, 25}, {100}, {0, 25}}}, + }, + []check{ + {"u", 1, ColElems{w(100)}}, + {"U", 1, ColElems{w(100), w(0, 25)}}, + {"w", 1, ColElems{w(100), w(100)}}, + {"W", 1, ColElems{w(100), w(0, 25), w(100), w(0, 25)}}, + }, + }, + { // test decompose + []input{ + {"D", [][]int{pt(104, 8)}}, + {"z", [][]int{pt(130, 8)}}, + {"\u030C", [][]int{{0, 40}}}, // Caron + {"\u01C5", [][]int{pt(104, 9), pt(130, 4), {0, 40, 0x1F}}}, // Dž = D+z+caron + }, + []check{ + {"\u01C5", 2, ColElems{w(pt(104, 9)...), w(pt(130, 4)...), w(0, 40, 0x1F)}}, + }, + }, + { // test basic contraction + []input{ + {"a", [][]int{{100}}}, + {"ab", [][]int{{101}}}, + {"aab", [][]int{{101}, {101}}}, + {"abc", [][]int{{102}}}, + {"b", [][]int{{200}}}, + {"c", [][]int{{300}}}, + {"d", [][]int{{400}}}, + }, + []check{ + {"a", 1, ColElems{w(100)}}, + {"aa", 1, ColElems{w(100)}}, + {"aac", 1, ColElems{w(100)}}, + {"d", 1, ColElems{w(400)}}, + {"ab", 2, ColElems{w(101)}}, + {"abb", 2, ColElems{w(101)}}, + {"aab", 3, ColElems{w(101), w(101)}}, + {"aaba", 3, ColElems{w(101), w(101)}}, + {"abc", 3, ColElems{w(102)}}, + {"abcd", 3, ColElems{w(102)}}, + }, + }, + { // test discontinuous contraction + append(mods, []input{ + // modifiers; secondary weight equals ccc + {"\u0316", [][]int{{0, 220}}}, + {"\u0317", [][]int{{0, 220}, {0, 220}}}, + {"\u302D", [][]int{{0, 222}}}, + {"\u302E", [][]int{{0, 225}}}, // used as starter + {"\u302F", [][]int{{0, 224}}}, // used as starter + {"\u18A9", [][]int{{0, 228}}}, + {"\u0300", [][]int{{0, 230}}}, + {"\u0301", [][]int{{0, 230}}}, + {"\u0315", [][]int{{0, 232}}}, + {"\u031A", [][]int{{0, 232}}}, + {"\u035C", [][]int{{0, 233}}}, + {"\u035F", [][]int{{0, 233}}}, + {"\u035D", [][]int{{0, 234}}}, + {"\u035E", [][]int{{0, 234}}}, + {"\u0345", [][]int{{0, 240}}}, + + // starters + {"a", [][]int{{100}}}, + {"b", [][]int{{200}}}, + {"c", [][]int{{300}}}, + {"\u03B1", [][]int{{900}}}, + {"\x01", [][]int{{0, 0, 0, 0}}}, + + // contractions + {"a\u0300", [][]int{{101}}}, + {"a\u0301", [][]int{{102}}}, + {"a\u035E", [][]int{{110}}}, + {"a\u035Eb\u035E", [][]int{{115}}}, + {"ac\u035Eaca\u035E", [][]int{{116}}}, + {"a\u035Db\u035D", [][]int{{117}}}, + {"a\u0301\u035Db", [][]int{{120}}}, + {"a\u0301\u035F", [][]int{{121}}}, + {"a\u0301\u035Fb", [][]int{{119}}}, + {"\u03B1\u0345", [][]int{{901}, {902}}}, + {"\u302E\u302F", [][]int{{0, 131}, {0, 131}}}, + {"\u302F\u18A9", [][]int{{0, 130}}}, + }...), + []check{ + {"a\x01\u0300", 1, ColElems{w(100)}}, + {"ab", 1, ColElems{w(100)}}, // closing segment + {"a\u0316\u0300b", 5, ColElems{w(101), w(0, 220)}}, // closing segment + {"a\u0316\u0300", 5, ColElems{w(101), w(0, 220)}}, // no closing segment + {"a\u0316\u0300\u035Cb", 5, ColElems{w(101), w(0, 220)}}, // completes before segment end + {"a\u0316\u0300\u035C", 5, ColElems{w(101), w(0, 220)}}, // completes before segment end + + {"a\u0316\u0301b", 5, ColElems{w(102), w(0, 220)}}, // closing segment + {"a\u0316\u0301", 5, ColElems{w(102), w(0, 220)}}, // no closing segment + {"a\u0316\u0301\u035Cb", 5, ColElems{w(102), w(0, 220)}}, // completes before segment end + {"a\u0316\u0301\u035C", 5, ColElems{w(102), w(0, 220)}}, // completes before segment end + + // match blocked by modifier with same ccc + {"a\u0301\u0315\u031A\u035Fb", 3, ColElems{w(102)}}, + + // multiple gaps + {"a\u0301\u035Db", 6, ColElems{w(120)}}, + {"a\u0301\u035F", 5, ColElems{w(121)}}, + {"a\u0301\u035Fb", 6, ColElems{w(119)}}, + {"a\u0316\u0301\u035F", 7, ColElems{w(121), w(0, 220)}}, + {"a\u0301\u0315\u035Fb", 7, ColElems{w(121), w(0, 232)}}, + {"a\u0316\u0301\u0315\u035Db", 5, ColElems{w(102), w(0, 220)}}, + {"a\u0316\u0301\u0315\u035F", 9, ColElems{w(121), w(0, 220), w(0, 232)}}, + {"a\u0316\u0301\u0315\u035Fb", 9, ColElems{w(121), w(0, 220), w(0, 232)}}, + {"a\u0316\u0301\u0315\u035F\u035D", 9, ColElems{w(121), w(0, 220), w(0, 232)}}, + {"a\u0316\u0301\u0315\u035F\u035Db", 9, ColElems{w(121), w(0, 220), w(0, 232)}}, + + // handling of segment overflow + { // just fits within segment + "a" + string(modSeq[:30]) + "\u0301", + 3 + len(string(modSeq[:30])), + append(ColElems{w(102)}, modW[:30]...), + }, + {"a" + string(modSeq[:31]) + "\u0301", 1, ColElems{w(100)}}, // overflow + {"a" + string(modSeq) + "\u0301", 1, ColElems{w(100)}}, + { // just fits within segment with two interstitial runes + "a" + string(modSeq[:28]) + "\u0301\u0315\u035F", + 7 + len(string(modSeq[:28])), + append(append(ColElems{w(121)}, modW[:28]...), w(0, 232)), + }, + { // second half does not fit within segment + "a" + string(modSeq[:29]) + "\u0301\u0315\u035F", + 3 + len(string(modSeq[:29])), + append(ColElems{w(102)}, modW[:29]...), + }, + + // discontinuity can only occur in last normalization segment + {"a\u035Eb\u035E", 6, ColElems{w(115)}}, + {"a\u0316\u035Eb\u035E", 5, ColElems{w(110), w(0, 220)}}, + {"a\u035Db\u035D", 6, ColElems{w(117)}}, + {"a\u0316\u035Db\u035D", 1, ColElems{w(100)}}, + {"a\u035Eb\u0316\u035E", 8, ColElems{w(115), w(0, 220)}}, + {"a\u035Db\u0316\u035D", 8, ColElems{w(117), w(0, 220)}}, + {"ac\u035Eaca\u035E", 9, ColElems{w(116)}}, + {"a\u0316c\u035Eaca\u035E", 1, ColElems{w(100)}}, + {"ac\u035Eac\u0316a\u035E", 1, ColElems{w(100)}}, + + // expanding contraction + {"\u03B1\u0345", 4, ColElems{w(901), w(902)}}, + + // Theoretical possibilities + // contraction within a gap + {"a\u302F\u18A9\u0301", 9, ColElems{w(102), w(0, 130)}}, + // expansion within a gap + {"a\u0317\u0301", 5, ColElems{w(102), w(0, 220), w(0, 220)}}, + // repeating CCC blocks last modifier + {"a\u302E\u302F\u0301", 1, ColElems{w(100)}}, + // The trailing combining characters (with lower CCC) should block the first one. + // TODO: make the following pass. + // {"a\u035E\u0316\u0316", 1, ColElems{w(100)}}, + {"a\u035F\u035Eb", 5, ColElems{w(110), w(0, 233)}}, + // Last combiner should match after normalization. + // TODO: make the following pass. + // {"a\u035D\u0301", 3, ColElems{w(102), w(0, 234)}}, + // The first combiner is blocking the second one as they have the same CCC. + {"a\u035D\u035Eb", 1, ColElems{w(100)}}, + }, + }, +} + +func TestAppendNext(t *testing.T) { + for i, tt := range appendNextTests { + c, err := makeTable(tt.in) + if err != nil { + t.Errorf("%d: error creating table: %v", i, err) + continue + } + for j, chk := range tt.chk { + ws, n := c.t.AppendNext(nil, []byte(chk.in)) + if n != chk.n { + t.Errorf("%d:%d: bytes consumed was %d; want %d", i, j, n, chk.n) + } + out := convertFromWeights(chk.out) + if len(ws) != len(out) { + t.Errorf("%d:%d: len(ws) was %d; want %d (%X vs %X)\n%X", i, j, len(ws), len(out), ws, out, chk.in) + continue + } + for k, w := range ws { + w, _ = colltab.MakeElem(w.Primary(), w.Secondary(), int(w.Tertiary()), 0) + if w != out[k] { + t.Errorf("%d:%d: Weights %d was %X; want %X", i, j, k, w, out[k]) + } + } + } + } +} diff --git a/vendor/golang.org/x/text/doc.go b/vendor/golang.org/x/text/doc.go new file mode 100644 index 000000000..a48e2843f --- /dev/null +++ b/vendor/golang.org/x/text/doc.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run gen.go + +// text is a repository of text-related packages related to internationalization +// (i18n) and localization (l10n), such as character encodings, text +// transformations, and locale-specific text handling. +package text + +// TODO: more documentation on general concepts, such as Transformers, use +// of normalization, etc. diff --git a/vendor/golang.org/x/text/encoding/charmap/charmap_test.go b/vendor/golang.org/x/text/encoding/charmap/charmap_test.go new file mode 100644 index 000000000..03dd76ebd --- /dev/null +++ b/vendor/golang.org/x/text/encoding/charmap/charmap_test.go @@ -0,0 +1,258 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package charmap + +import ( + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/internal" + "golang.org/x/text/encoding/internal/enctest" + "golang.org/x/text/transform" +) + +func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Decode", e.NewDecoder(), nil +} + +func encASCIISuperset(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement +} + +func encEBCDIC(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Encode", e.NewEncoder(), internal.RepertoireError(0x3f) +} + +func TestNonRepertoire(t *testing.T) { + testCases := []struct { + init func(e encoding.Encoding) (string, transform.Transformer, error) + e encoding.Encoding + src, want string + }{ + {dec, Windows1252, "\x81", "\ufffd"}, + + {encEBCDIC, CodePage037, "갂", ""}, + + {encEBCDIC, CodePage1047, "갂", ""}, + {encEBCDIC, CodePage1047, "a¤갂", "\x81\x9F"}, + + {encEBCDIC, CodePage1140, "갂", ""}, + {encEBCDIC, CodePage1140, "a€갂", "\x81\x9F"}, + + {encASCIISuperset, Windows1252, "갂", ""}, + {encASCIISuperset, Windows1252, "a갂", "a"}, + {encASCIISuperset, Windows1252, "\u00E9갂", "\xE9"}, + } + for _, tc := range testCases { + dir, tr, wantErr := tc.init(tc.e) + + dst, _, err := transform.String(tr, tc.src) + if err != wantErr { + t.Errorf("%s %v(%q): got %v; want %v", dir, tc.e, tc.src, err, wantErr) + } + if got := string(dst); got != tc.want { + t.Errorf("%s %v(%q):\ngot %q\nwant %q", dir, tc.e, tc.src, got, tc.want) + } + } +} + +func TestBasics(t *testing.T) { + testCases := []struct { + e encoding.Encoding + encoded string + utf8 string + }{{ + e: CodePage037, + encoded: "\xc8\x51\xba\x93\xcf", + utf8: "Hé[lõ", + }, { + e: CodePage437, + encoded: "H\x82ll\x93 \x9d\xa7\xf4\x9c\xbe", + utf8: "Héllô ¥º⌠£╛", + }, { + e: CodePage866, + encoded: "H\xf3\xd3o \x98\xfd\x9f\xdd\xa1", + utf8: "Hє╙o Ш¤Я▌б", + }, { + e: CodePage1047, + encoded: "\xc8\x54\x93\x93\x9f", + utf8: "Hèll¤", + }, { + e: CodePage1140, + encoded: "\xc8\x9f\x93\x93\xcf", + utf8: "H€llõ", + }, { + e: ISO8859_2, + encoded: "Hel\xe5\xf5", + utf8: "Helĺő", + }, { + e: ISO8859_3, + encoded: "He\xbd\xd4", + utf8: "He½Ô", + }, { + e: ISO8859_4, + encoded: "Hel\xb6\xf8", + utf8: "Helļø", + }, { + e: ISO8859_5, + encoded: "H\xd7\xc6o", + utf8: "HзЦo", + }, { + e: ISO8859_6, + encoded: "Hel\xc2\xc9", + utf8: "Helآة", + }, { + e: ISO8859_7, + encoded: "H\xeel\xebo", + utf8: "Hξlλo", + }, { + e: ISO8859_8, + encoded: "Hel\xf5\xed", + utf8: "Helץם", + }, { + e: ISO8859_9, + encoded: "\xdeayet", + utf8: "Şayet", + }, { + e: ISO8859_10, + encoded: "H\xea\xbfo", + utf8: "Hęŋo", + }, { + e: ISO8859_13, + encoded: "H\xe6l\xf9o", + utf8: "Hęlło", + }, { + e: ISO8859_14, + encoded: "He\xfe\xd0o", + utf8: "HeŷŴo", + }, { + e: ISO8859_15, + encoded: "H\xa4ll\xd8", + utf8: "H€llØ", + }, { + e: ISO8859_16, + encoded: "H\xe6ll\xbd", + utf8: "Hællœ", + }, { + e: KOI8R, + encoded: "He\x93\xad\x9c", + utf8: "He⌠╜°", + }, { + e: KOI8U, + encoded: "He\x93\xad\x9c", + utf8: "He⌠ґ°", + }, { + e: Macintosh, + encoded: "He\xdf\xd7", + utf8: "Hefl◊", + }, { + e: MacintoshCyrillic, + encoded: "He\xbe\x94", + utf8: "HeЊФ", + }, { + e: Windows874, + encoded: "He\xb7\xf0", + utf8: "Heท๐", + }, { + e: Windows1250, + encoded: "He\xe5\xe5o", + utf8: "Heĺĺo", + }, { + e: Windows1251, + encoded: "H\xball\xfe", + utf8: "Hєllю", + }, { + e: Windows1252, + encoded: "H\xe9ll\xf4 \xa5\xbA\xae\xa3\xd0", + utf8: "Héllô ¥º®£Ð", + }, { + e: Windows1253, + encoded: "H\xe5ll\xd6", + utf8: "HεllΦ", + }, { + e: Windows1254, + encoded: "\xd0ello", + utf8: "Ğello", + }, { + e: Windows1255, + encoded: "He\xd4o", + utf8: "Heװo", + }, { + e: Windows1256, + encoded: "H\xdbllo", + utf8: "Hغllo", + }, { + e: Windows1257, + encoded: "He\xeflo", + utf8: "Heļlo", + }, { + e: Windows1258, + encoded: "Hell\xf5", + utf8: "Hellơ", + }, { + e: XUserDefined, + encoded: "\x00\x40\x7f\x80\xab\xff", + utf8: "\u0000\u0040\u007f\uf780\uf7ab\uf7ff", + }} + + for _, tc := range testCases { + enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, "", "") + } +} + +var windows1255TestCases = []struct { + b byte + ok bool + r rune +}{ + {'\x00', true, '\u0000'}, + {'\x1a', true, '\u001a'}, + {'\x61', true, '\u0061'}, + {'\x7f', true, '\u007f'}, + {'\x80', true, '\u20ac'}, + {'\x95', true, '\u2022'}, + {'\xa0', true, '\u00a0'}, + {'\xc0', true, '\u05b0'}, + {'\xfc', true, '\ufffd'}, + {'\xfd', true, '\u200e'}, + {'\xfe', true, '\u200f'}, + {'\xff', true, '\ufffd'}, + {encoding.ASCIISub, false, '\u0400'}, + {encoding.ASCIISub, false, '\u2603'}, + {encoding.ASCIISub, false, '\U0001f4a9'}, +} + +func TestDecodeByte(t *testing.T) { + for _, tc := range windows1255TestCases { + if !tc.ok { + continue + } + + got := Windows1255.DecodeByte(tc.b) + want := tc.r + if got != want { + t.Errorf("DecodeByte(%#02x): got %#08x, want %#08x", tc.b, got, want) + } + } +} + +func TestEncodeRune(t *testing.T) { + for _, tc := range windows1255TestCases { + // There can be multiple tc.b values that map to tc.r = '\ufffd'. + if tc.r == '\ufffd' { + continue + } + + gotB, gotOK := Windows1255.EncodeRune(tc.r) + wantB, wantOK := tc.b, tc.ok + if gotB != wantB || gotOK != wantOK { + t.Errorf("EncodeRune(%#08x): got (%#02x, %t), want (%#02x, %t)", tc.r, gotB, gotOK, wantB, wantOK) + } + } +} + +func TestFiles(t *testing.T) { enctest.TestFile(t, Windows1252) } + +func BenchmarkEncoding(b *testing.B) { enctest.Benchmark(b, Windows1252) } diff --git a/vendor/golang.org/x/text/encoding/encoding_test.go b/vendor/golang.org/x/text/encoding/encoding_test.go new file mode 100644 index 000000000..173814762 --- /dev/null +++ b/vendor/golang.org/x/text/encoding/encoding_test.go @@ -0,0 +1,290 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package encoding_test + +import ( + "io/ioutil" + "strings" + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" + "golang.org/x/text/transform" +) + +func TestEncodeInvalidUTF8(t *testing.T) { + inputs := []string{ + "hello.", + "wo\ufffdld.", + "ABC\xff\x80\x80", // Invalid UTF-8. + "\x80\x80\x80\x80\x80", + "\x80\x80D\x80\x80", // Valid rune at "D". + "E\xed\xa0\x80\xed\xbf\xbfF", // Two invalid UTF-8 runes (surrogates). + "G", + "H\xe2\x82", // U+20AC in UTF-8 is "\xe2\x82\xac", which we split over two + "\xacI\xe2\x82", // input lines. It maps to 0x80 in the Windows-1252 encoding. + } + // Each invalid source byte becomes '\x1a'. + want := strings.Replace("hello.wo?ld.ABC??????????D??E??????FGH\x80I??", "?", "\x1a", -1) + + transformer := encoding.ReplaceUnsupported(charmap.Windows1252.NewEncoder()) + gotBuf := make([]byte, 0, 1024) + src := make([]byte, 0, 1024) + for i, input := range inputs { + dst := make([]byte, 1024) + src = append(src, input...) + atEOF := i == len(inputs)-1 + nDst, nSrc, err := transformer.Transform(dst, src, atEOF) + gotBuf = append(gotBuf, dst[:nDst]...) + src = src[nSrc:] + if err != nil && err != transform.ErrShortSrc { + t.Fatalf("i=%d: %v", i, err) + } + if atEOF && err != nil { + t.Fatalf("i=%d: atEOF: %v", i, err) + } + } + if got := string(gotBuf); got != want { + t.Fatalf("\ngot %+q\nwant %+q", got, want) + } +} + +func TestReplacement(t *testing.T) { + for _, direction := range []string{"Decode", "Encode"} { + enc, want := (transform.Transformer)(nil), "" + if direction == "Decode" { + enc = encoding.Replacement.NewDecoder() + want = "\ufffd" + } else { + enc = encoding.Replacement.NewEncoder() + want = "AB\x00CD\ufffdYZ" + } + sr := strings.NewReader("AB\x00CD\x80YZ") + g, err := ioutil.ReadAll(transform.NewReader(sr, enc)) + if err != nil { + t.Errorf("%s: ReadAll: %v", direction, err) + continue + } + if got := string(g); got != want { + t.Errorf("%s:\ngot %q\nwant %q", direction, got, want) + continue + } + } +} + +func TestUTF8Validator(t *testing.T) { + testCases := []struct { + desc string + dstSize int + src string + atEOF bool + want string + wantErr error + }{ + { + "empty input", + 100, + "", + false, + "", + nil, + }, + { + "valid 1-byte 1-rune input", + 100, + "a", + false, + "a", + nil, + }, + { + "valid 3-byte 1-rune input", + 100, + "\u1234", + false, + "\u1234", + nil, + }, + { + "valid 5-byte 3-rune input", + 100, + "a\u0100\u0101", + false, + "a\u0100\u0101", + nil, + }, + { + "perfectly sized dst (non-ASCII)", + 5, + "a\u0100\u0101", + false, + "a\u0100\u0101", + nil, + }, + { + "short dst (non-ASCII)", + 4, + "a\u0100\u0101", + false, + "a\u0100", + transform.ErrShortDst, + }, + { + "perfectly sized dst (ASCII)", + 5, + "abcde", + false, + "abcde", + nil, + }, + { + "short dst (ASCII)", + 4, + "abcde", + false, + "abcd", + transform.ErrShortDst, + }, + { + "partial input (!EOF)", + 100, + "a\u0100\xf1", + false, + "a\u0100", + transform.ErrShortSrc, + }, + { + "invalid input (EOF)", + 100, + "a\u0100\xf1", + true, + "a\u0100", + encoding.ErrInvalidUTF8, + }, + { + "invalid input (!EOF)", + 100, + "a\u0100\x80", + false, + "a\u0100", + encoding.ErrInvalidUTF8, + }, + { + "invalid input (above U+10FFFF)", + 100, + "a\u0100\xf7\xbf\xbf\xbf", + false, + "a\u0100", + encoding.ErrInvalidUTF8, + }, + { + "invalid input (surrogate half)", + 100, + "a\u0100\xed\xa0\x80", + false, + "a\u0100", + encoding.ErrInvalidUTF8, + }, + } + for _, tc := range testCases { + dst := make([]byte, tc.dstSize) + nDst, nSrc, err := encoding.UTF8Validator.Transform(dst, []byte(tc.src), tc.atEOF) + if nDst < 0 || len(dst) < nDst { + t.Errorf("%s: nDst=%d out of range", tc.desc, nDst) + continue + } + got := string(dst[:nDst]) + if got != tc.want || nSrc != len(tc.want) || err != tc.wantErr { + t.Errorf("%s:\ngot %+q, %d, %v\nwant %+q, %d, %v", + tc.desc, got, nSrc, err, tc.want, len(tc.want), tc.wantErr) + continue + } + } +} + +func TestErrorHandler(t *testing.T) { + testCases := []struct { + desc string + handler func(*encoding.Encoder) *encoding.Encoder + sizeDst int + src, want string + nSrc int + err error + }{ + { + desc: "one rune replacement", + handler: encoding.ReplaceUnsupported, + sizeDst: 100, + src: "\uAC00", + want: "\x1a", + nSrc: 3, + }, + { + desc: "mid-stream rune replacement", + handler: encoding.ReplaceUnsupported, + sizeDst: 100, + src: "a\uAC00bcd\u00e9", + want: "a\x1abcd\xe9", + nSrc: 9, + }, + { + desc: "at end rune replacement", + handler: encoding.ReplaceUnsupported, + sizeDst: 10, + src: "\u00e9\uAC00", + want: "\xe9\x1a", + nSrc: 5, + }, + { + desc: "short buffer replacement", + handler: encoding.ReplaceUnsupported, + sizeDst: 1, + src: "\u00e9\uAC00", + want: "\xe9", + nSrc: 2, + err: transform.ErrShortDst, + }, + { + desc: "one rune html escape", + handler: encoding.HTMLEscapeUnsupported, + sizeDst: 100, + src: "\uAC00", + want: "&#44032;", + nSrc: 3, + }, + { + desc: "mid-stream html escape", + handler: encoding.HTMLEscapeUnsupported, + sizeDst: 100, + src: "\u00e9\uAC00dcba", + want: "\xe9&#44032;dcba", + nSrc: 9, + }, + { + desc: "short buffer html escape", + handler: encoding.HTMLEscapeUnsupported, + sizeDst: 9, + src: "ab\uAC01", + want: "ab", + nSrc: 2, + err: transform.ErrShortDst, + }, + } + for i, tc := range testCases { + tr := tc.handler(charmap.Windows1250.NewEncoder()) + b := make([]byte, tc.sizeDst) + nDst, nSrc, err := tr.Transform(b, []byte(tc.src), true) + if err != tc.err { + t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err) + } + if got := string(b[:nDst]); got != tc.want { + t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want) + } + if nSrc != tc.nSrc { + t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc) + } + + } +} diff --git a/vendor/golang.org/x/text/encoding/example_test.go b/vendor/golang.org/x/text/encoding/example_test.go new file mode 100644 index 000000000..4f923530f --- /dev/null +++ b/vendor/golang.org/x/text/encoding/example_test.go @@ -0,0 +1,42 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package encoding_test + +import ( + "fmt" + "io" + "os" + "strings" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" + "golang.org/x/text/encoding/unicode" + "golang.org/x/text/transform" +) + +func ExampleDecodeWindows1252() { + sr := strings.NewReader("Gar\xe7on !") + tr := charmap.Windows1252.NewDecoder().Reader(sr) + io.Copy(os.Stdout, tr) + // Output: Garçon ! +} + +func ExampleUTF8Validator() { + for i := 0; i < 2; i++ { + var transformer transform.Transformer + transformer = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM).NewEncoder() + if i == 1 { + transformer = transform.Chain(encoding.UTF8Validator, transformer) + } + dst := make([]byte, 256) + src := []byte("abc\xffxyz") // src is invalid UTF-8. + nDst, nSrc, err := transformer.Transform(dst, src, true) + fmt.Printf("i=%d: produced %q, consumed %q, error %v\n", + i, dst[:nDst], src[:nSrc], err) + } + // Output: + // i=0: produced "\x00a\x00b\x00c\xff\xfd\x00x\x00y\x00z", consumed "abc\xffxyz", error <nil> + // i=1: produced "\x00a\x00b\x00c", consumed "abc", error encoding: invalid UTF-8 +} diff --git a/vendor/golang.org/x/text/encoding/htmlindex/htmlindex_test.go b/vendor/golang.org/x/text/encoding/htmlindex/htmlindex_test.go new file mode 100644 index 000000000..3fdab0f49 --- /dev/null +++ b/vendor/golang.org/x/text/encoding/htmlindex/htmlindex_test.go @@ -0,0 +1,144 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package htmlindex + +import ( + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" + "golang.org/x/text/encoding/internal/identifier" + "golang.org/x/text/encoding/unicode" + "golang.org/x/text/language" +) + +func TestGet(t *testing.T) { + for i, tc := range []struct { + name string + canonical string + err error + }{ + {"utf-8", "utf-8", nil}, + {" utf-8 ", "utf-8", nil}, + {" l5 ", "windows-1254", nil}, + {"latin5 ", "windows-1254", nil}, + {"latin 5", "", errInvalidName}, + {"latin-5", "", errInvalidName}, + } { + enc, err := Get(tc.name) + if err != tc.err { + t.Errorf("%d: error was %v; want %v", i, err, tc.err) + } + if err != nil { + continue + } + if got, err := Name(enc); got != tc.canonical { + t.Errorf("%d: Name(Get(%q)) = %q; want %q (%v)", i, tc.name, got, tc.canonical, err) + } + } +} + +func TestTables(t *testing.T) { + for name, index := range nameMap { + got, err := Get(name) + if err != nil { + t.Errorf("%s:err: expected non-nil error", name) + } + if want := encodings[index]; got != want { + t.Errorf("%s:encoding: got %v; want %v", name, got, want) + } + mib, _ := got.(identifier.Interface).ID() + if mibMap[mib] != index { + t.Errorf("%s:mibMab: got %d; want %d", name, mibMap[mib], index) + } + } +} + +func TestName(t *testing.T) { + for i, tc := range []struct { + desc string + enc encoding.Encoding + name string + err error + }{{ + "defined encoding", + charmap.ISO8859_2, + "iso-8859-2", + nil, + }, { + "defined Unicode encoding", + unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM), + "utf-16be", + nil, + }, { + "undefined Unicode encoding in HTML standard", + unicode.UTF16(unicode.BigEndian, unicode.UseBOM), + "", + errUnsupported, + }, { + "undefined other encoding in HTML standard", + charmap.CodePage437, + "", + errUnsupported, + }, { + "unknown encoding", + encoding.Nop, + "", + errUnknown, + }} { + name, err := Name(tc.enc) + if name != tc.name || err != tc.err { + t.Errorf("%d:%s: got %q, %v; want %q, %v", i, tc.desc, name, err, tc.name, tc.err) + } + } +} + +func TestLanguageDefault(t *testing.T) { + for _, tc := range []struct{ tag, want string }{ + {"und", "windows-1252"}, // The default value. + {"ar", "windows-1256"}, + {"ba", "windows-1251"}, + {"be", "windows-1251"}, + {"bg", "windows-1251"}, + {"cs", "windows-1250"}, + {"el", "iso-8859-7"}, + {"et", "windows-1257"}, + {"fa", "windows-1256"}, + {"he", "windows-1255"}, + {"hr", "windows-1250"}, + {"hu", "iso-8859-2"}, + {"ja", "shift_jis"}, + {"kk", "windows-1251"}, + {"ko", "euc-kr"}, + {"ku", "windows-1254"}, + {"ky", "windows-1251"}, + {"lt", "windows-1257"}, + {"lv", "windows-1257"}, + {"mk", "windows-1251"}, + {"pl", "iso-8859-2"}, + {"ru", "windows-1251"}, + {"sah", "windows-1251"}, + {"sk", "windows-1250"}, + {"sl", "iso-8859-2"}, + {"sr", "windows-1251"}, + {"tg", "windows-1251"}, + {"th", "windows-874"}, + {"tr", "windows-1254"}, + {"tt", "windows-1251"}, + {"uk", "windows-1251"}, + {"vi", "windows-1258"}, + {"zh-hans", "gb18030"}, + {"zh-hant", "big5"}, + // Variants and close approximates of the above. + {"ar_EG", "windows-1256"}, + {"bs", "windows-1250"}, // Bosnian Latin maps to Croatian. + // Use default fallback in case of miss. + {"nl", "windows-1252"}, + } { + if got := LanguageDefault(language.MustParse(tc.tag)); got != tc.want { + t.Errorf("LanguageDefault(%s) = %s; want %s", tc.tag, got, tc.want) + } + } +} diff --git a/vendor/golang.org/x/text/encoding/japanese/all_test.go b/vendor/golang.org/x/text/encoding/japanese/all_test.go new file mode 100644 index 000000000..9cffe10dc --- /dev/null +++ b/vendor/golang.org/x/text/encoding/japanese/all_test.go @@ -0,0 +1,248 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package japanese + +import ( + "fmt" + "strings" + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/internal" + "golang.org/x/text/encoding/internal/enctest" + "golang.org/x/text/transform" +) + +func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Decode", e.NewDecoder(), nil +} +func enc(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement +} + +func TestNonRepertoire(t *testing.T) { + // Pick n to cause the destination buffer in transform.String to overflow. + const n = 100 + long := strings.Repeat(".", n) + testCases := []struct { + init func(e encoding.Encoding) (string, transform.Transformer, error) + e encoding.Encoding + src, want string + }{ + {enc, EUCJP, "갂", ""}, + {enc, EUCJP, "a갂", "a"}, + {enc, EUCJP, "丌갂", "\x8f\xb0\xa4"}, + + {enc, ISO2022JP, "갂", ""}, + {enc, ISO2022JP, "a갂", "a"}, + {enc, ISO2022JP, "朗갂", "\x1b$BzF\x1b(B"}, // switch back to ASCII mode at end + + {enc, ShiftJIS, "갂", ""}, + {enc, ShiftJIS, "a갂", "a"}, + {enc, ShiftJIS, "\u2190갂", "\x81\xa9"}, + + // Continue correctly after errors + {dec, EUCJP, "\x8e\xa0", "\ufffd\ufffd"}, + {dec, EUCJP, "\x8e\xe0", "\ufffd"}, + {dec, EUCJP, "\x8e\xff", "\ufffd\ufffd"}, + {dec, EUCJP, "\x8ea", "\ufffda"}, + {dec, EUCJP, "\x8f\xa0", "\ufffd\ufffd"}, + {dec, EUCJP, "\x8f\xa1\xa0", "\ufffd\ufffd"}, + {dec, EUCJP, "\x8f\xa1a", "\ufffda"}, + {dec, EUCJP, "\x8f\xa1a", "\ufffda"}, + {dec, EUCJP, "\x8f\xa1a", "\ufffda"}, + {dec, EUCJP, "\x8f\xa2\xa2", "\ufffd"}, + {dec, EUCJP, "\xfe", "\ufffd"}, + {dec, EUCJP, "\xfe\xfc", "\ufffd"}, + {dec, EUCJP, "\xfe\xff", "\ufffd\ufffd"}, + // Correct handling of end of source + {dec, EUCJP, strings.Repeat("\x8e", n), strings.Repeat("\ufffd", n)}, + {dec, EUCJP, strings.Repeat("\x8f", n), strings.Repeat("\ufffd", n)}, + {dec, EUCJP, strings.Repeat("\x8f\xa0", n), strings.Repeat("\ufffd", 2*n)}, + {dec, EUCJP, "a" + strings.Repeat("\x8f\xa1", n), "a" + strings.Repeat("\ufffd", n)}, + {dec, EUCJP, "a" + strings.Repeat("\x8f\xa1\xff", n), "a" + strings.Repeat("\ufffd", 2*n)}, + + // Continue correctly after errors + {dec, ShiftJIS, "\x80", "\u0080"}, // It's what the spec says. + {dec, ShiftJIS, "\x81", "\ufffd"}, + {dec, ShiftJIS, "\x81\x7f", "\ufffd\u007f"}, + {dec, ShiftJIS, "\xe0", "\ufffd"}, + {dec, ShiftJIS, "\xe0\x39", "\ufffd\u0039"}, + {dec, ShiftJIS, "\xe0\x9f", "燹"}, + {dec, ShiftJIS, "\xe0\xfd", "\ufffd"}, + {dec, ShiftJIS, "\xef\xfc", "\ufffd"}, + {dec, ShiftJIS, "\xfc\xfc", "\ufffd"}, + {dec, ShiftJIS, "\xfc\xfd", "\ufffd"}, + {dec, ShiftJIS, "\xfdaa", "\ufffdaa"}, + + {dec, ShiftJIS, strings.Repeat("\x81\x81", n), strings.Repeat("=", n)}, + {dec, ShiftJIS, strings.Repeat("\xe0\xfd", n), strings.Repeat("\ufffd", n)}, + {dec, ShiftJIS, "a" + strings.Repeat("\xe0\xfd", n), "a" + strings.Repeat("\ufffd", n)}, + + {dec, ISO2022JP, "\x1b$", "\ufffd$"}, + {dec, ISO2022JP, "\x1b(", "\ufffd("}, + {dec, ISO2022JP, "\x1b@", "\ufffd@"}, + {dec, ISO2022JP, "\x1bZ", "\ufffdZ"}, + // incomplete escapes + {dec, ISO2022JP, "\x1b$", "\ufffd$"}, + {dec, ISO2022JP, "\x1b$J.", "\ufffd$J."}, // illegal + {dec, ISO2022JP, "\x1b$B.", "\ufffd"}, // JIS208 + {dec, ISO2022JP, "\x1b$(", "\ufffd$("}, // JIS212 + {dec, ISO2022JP, "\x1b$(..", "\ufffd$(.."}, // JIS212 + {dec, ISO2022JP, "\x1b$(" + long, "\ufffd$(" + long}, // JIS212 + {dec, ISO2022JP, "\x1b$(D.", "\ufffd"}, // JIS212 + {dec, ISO2022JP, "\x1b$(D..", "\ufffd"}, // JIS212 + {dec, ISO2022JP, "\x1b$(D...", "\ufffd\ufffd"}, // JIS212 + {dec, ISO2022JP, "\x1b(B.", "."}, // ascii + {dec, ISO2022JP, "\x1b(B..", ".."}, // ascii + {dec, ISO2022JP, "\x1b(J.", "."}, // roman + {dec, ISO2022JP, "\x1b(J..", ".."}, // roman + {dec, ISO2022JP, "\x1b(I\x20", "\ufffd"}, // katakana + {dec, ISO2022JP, "\x1b(I\x20\x20", "\ufffd\ufffd"}, // katakana + // recover to same state + {dec, ISO2022JP, "\x1b(B\x1b.", "\ufffd."}, + {dec, ISO2022JP, "\x1b(I\x1b.", "\ufffdョ"}, + {dec, ISO2022JP, "\x1b(I\x1b$.", "\ufffd、ョ"}, + {dec, ISO2022JP, "\x1b(I\x1b(.", "\ufffdィョ"}, + {dec, ISO2022JP, "\x1b$B\x7e\x7e", "\ufffd"}, + {dec, ISO2022JP, "\x1b$@\x0a.", "\x0a."}, + {dec, ISO2022JP, "\x1b$B\x0a.", "\x0a."}, + {dec, ISO2022JP, "\x1b$(D\x0a.", "\x0a."}, + {dec, ISO2022JP, "\x1b$(D\x7e\x7e", "\ufffd"}, + {dec, ISO2022JP, "\x80", "\ufffd"}, + + // TODO: according to https://encoding.spec.whatwg.org/#iso-2022-jp, + // these should all be correct. + // {dec, ISO2022JP, "\x1b(B\x0E", "\ufffd"}, + // {dec, ISO2022JP, "\x1b(B\x0F", "\ufffd"}, + {dec, ISO2022JP, "\x1b(B\x5C", "\u005C"}, + {dec, ISO2022JP, "\x1b(B\x7E", "\u007E"}, + // {dec, ISO2022JP, "\x1b(J\x0E", "\ufffd"}, + // {dec, ISO2022JP, "\x1b(J\x0F", "\ufffd"}, + // {dec, ISO2022JP, "\x1b(J\x5C", "\u00A5"}, + // {dec, ISO2022JP, "\x1b(J\x7E", "\u203E"}, + } + for _, tc := range testCases { + dir, tr, wantErr := tc.init(tc.e) + t.Run(fmt.Sprintf("%s/%v/%q", dir, tc.e, tc.src), func(t *testing.T) { + dst := make([]byte, 100000) + src := []byte(tc.src) + for i := 0; i <= len(tc.src); i++ { + nDst, nSrc, err := tr.Transform(dst, src[:i], false) + if err != nil && err != transform.ErrShortSrc && err != wantErr { + t.Fatalf("error on first call to Transform: %v", err) + } + n, _, err := tr.Transform(dst[nDst:], src[nSrc:], true) + nDst += n + if err != wantErr { + t.Fatalf("(%q|%q): got %v; want %v", tc.src[:i], tc.src[i:], err, wantErr) + } + if got := string(dst[:nDst]); got != tc.want { + t.Errorf("(%q|%q):\ngot %q\nwant %q", tc.src[:i], tc.src[i:], got, tc.want) + } + } + }) + } +} + +func TestCorrect(t *testing.T) { + testCases := []struct { + init func(e encoding.Encoding) (string, transform.Transformer, error) + e encoding.Encoding + src, want string + }{ + {dec, ShiftJIS, "\x9f\xfc", "滌"}, + {dec, ShiftJIS, "\xfb\xfc", "髙"}, + {dec, ShiftJIS, "\xfa\xb1", "﨑"}, + {enc, ShiftJIS, "滌", "\x9f\xfc"}, + {enc, ShiftJIS, "﨑", "\xed\x95"}, + } + for _, tc := range testCases { + dir, tr, _ := tc.init(tc.e) + + dst, _, err := transform.String(tr, tc.src) + if err != nil { + t.Errorf("%s %v(%q): got %v; want %v", dir, tc.e, tc.src, err, nil) + } + if got := string(dst); got != tc.want { + t.Errorf("%s %v(%q):\ngot %q\nwant %q", dir, tc.e, tc.src, got, tc.want) + } + } +} + +func TestBasics(t *testing.T) { + // The encoded forms can be verified by the iconv program: + // $ echo 月日は百代 | iconv -f UTF-8 -t SHIFT-JIS | xxd + testCases := []struct { + e encoding.Encoding + encPrefix string + encSuffix string + encoded string + utf8 string + }{{ + // "A。カ゚ 0208: etc 0212: etc" is a nonsense string that contains ASCII, half-width + // kana, JIS X 0208 (including two near the kink in the Shift JIS second byte + // encoding) and JIS X 0212 encodable codepoints. + // + // "月日は百代の過客にして、行かふ年も又旅人也。" is from the 17th century poem + // "Oku no Hosomichi" and contains both hiragana and kanji. + e: EUCJP, + encoded: "A\x8e\xa1\x8e\xb6\x8e\xdf " + + "0208: \xa1\xa1\xa1\xa2\xa1\xdf\xa1\xe0\xa1\xfd\xa1\xfe\xa2\xa1\xa2\xa2\xf4\xa6 " + + "0212: \x8f\xa2\xaf\x8f\xed\xe3", + utf8: "A。カ゚ " + + "0208: \u3000\u3001\u00d7\u00f7\u25ce\u25c7\u25c6\u25a1\u7199 " + + "0212: \u02d8\u9fa5", + }, { + e: EUCJP, + encoded: "\xb7\xee\xc6\xfc\xa4\xcf\xc9\xb4\xc2\xe5\xa4\xce\xb2\xe1\xb5\xd2" + + "\xa4\xcb\xa4\xb7\xa4\xc6\xa1\xa2\xb9\xd4\xa4\xab\xa4\xd5\xc7\xaf" + + "\xa4\xe2\xcb\xf4\xce\xb9\xbf\xcd\xcc\xe9\xa1\xa3", + utf8: "月日は百代の過客にして、行かふ年も又旅人也。", + }, { + e: ISO2022JP, + encSuffix: "\x1b\x28\x42", + encoded: "\x1b\x28\x49\x21\x36\x5f\x1b\x28\x42 " + + "0208: \x1b\x24\x42\x21\x21\x21\x22\x21\x5f\x21\x60\x21\x7d\x21\x7e\x22\x21\x22\x22\x74\x26", + utf8: "。カ゚ " + + "0208: \u3000\u3001\u00d7\u00f7\u25ce\u25c7\u25c6\u25a1\u7199", + }, { + e: ISO2022JP, + encPrefix: "\x1b\x24\x42", + encSuffix: "\x1b\x28\x42", + encoded: "\x37\x6e\x46\x7c\x24\x4f\x49\x34\x42\x65\x24\x4e\x32\x61\x35\x52" + + "\x24\x4b\x24\x37\x24\x46\x21\x22\x39\x54\x24\x2b\x24\x55\x47\x2f" + + "\x24\x62\x4b\x74\x4e\x39\x3f\x4d\x4c\x69\x21\x23", + utf8: "月日は百代の過客にして、行かふ年も又旅人也。", + }, { + e: ShiftJIS, + encoded: "A\xa1\xb6\xdf " + + "0208: \x81\x40\x81\x41\x81\x7e\x81\x80\x81\x9d\x81\x9e\x81\x9f\x81\xa0\xea\xa4", + utf8: "A。カ゚ " + + "0208: \u3000\u3001\u00d7\u00f7\u25ce\u25c7\u25c6\u25a1\u7199", + }, { + e: ShiftJIS, + encoded: "\x8c\x8e\x93\xfa\x82\xcd\x95\x53\x91\xe3\x82\xcc\x89\xdf\x8b\x71" + + "\x82\xc9\x82\xb5\x82\xc4\x81\x41\x8d\x73\x82\xa9\x82\xd3\x94\x4e" + + "\x82\xe0\x96\x94\x97\xb7\x90\x6c\x96\xe7\x81\x42", + utf8: "月日は百代の過客にして、行かふ年も又旅人也。", + }} + + for _, tc := range testCases { + enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, tc.encPrefix, tc.encSuffix) + } +} + +func TestFiles(t *testing.T) { + enctest.TestFile(t, EUCJP) + enctest.TestFile(t, ISO2022JP) + enctest.TestFile(t, ShiftJIS) +} + +func BenchmarkEncoding(b *testing.B) { + enctest.Benchmark(b, EUCJP) + enctest.Benchmark(b, ISO2022JP) + enctest.Benchmark(b, ShiftJIS) +} diff --git a/vendor/golang.org/x/text/encoding/korean/all_test.go b/vendor/golang.org/x/text/encoding/korean/all_test.go new file mode 100644 index 000000000..8225ce62a --- /dev/null +++ b/vendor/golang.org/x/text/encoding/korean/all_test.go @@ -0,0 +1,94 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package korean + +import ( + "strings" + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/internal" + "golang.org/x/text/encoding/internal/enctest" + "golang.org/x/text/transform" +) + +func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Decode", e.NewDecoder(), nil +} +func enc(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement +} + +func TestNonRepertoire(t *testing.T) { + // Pick n large enough to cause an overflow in the destination buffer of + // transform.String. + const n = 10000 + testCases := []struct { + init func(e encoding.Encoding) (string, transform.Transformer, error) + e encoding.Encoding + src, want string + }{ + {dec, EUCKR, "\xfe\xfe", "\ufffd"}, + // {dec, EUCKR, "א", "\ufffd"}, // TODO: why is this different? + + {enc, EUCKR, "א", ""}, + {enc, EUCKR, "aא", "a"}, + {enc, EUCKR, "\uac00א", "\xb0\xa1"}, + // TODO: should we also handle Jamo? + + {dec, EUCKR, "\x80", "\ufffd"}, + {dec, EUCKR, "\xff", "\ufffd"}, + {dec, EUCKR, "\x81", "\ufffd"}, + {dec, EUCKR, "\xb0\x40", "\ufffd@"}, + {dec, EUCKR, "\xb0\xff", "\ufffd"}, + {dec, EUCKR, "\xd0\x20", "\ufffd "}, + {dec, EUCKR, "\xd0\xff", "\ufffd"}, + + {dec, EUCKR, strings.Repeat("\x81", n), strings.Repeat("걖", n/2)}, + } + for _, tc := range testCases { + dir, tr, wantErr := tc.init(tc.e) + + dst, _, err := transform.String(tr, tc.src) + if err != wantErr { + t.Errorf("%s %v(%q): got %v; want %v", dir, tc.e, tc.src, err, wantErr) + } + if got := string(dst); got != tc.want { + t.Errorf("%s %v(%q):\ngot %q\nwant %q", dir, tc.e, tc.src, got, tc.want) + } + } +} + +func TestBasics(t *testing.T) { + // The encoded forms can be verified by the iconv program: + // $ echo 月日は百代 | iconv -f UTF-8 -t SHIFT-JIS | xxd + testCases := []struct { + e encoding.Encoding + encoded string + utf8 string + }{{ + // Korean tests. + // + // "A\uac02\uac35\uac56\ud401B\ud408\ud620\ud624C\u4f3d\u8a70D" is a + // nonsense string that contains ASCII, Hangul and CJK ideographs. + // + // "세계야, 안녕" translates as "Hello, world". + e: EUCKR, + encoded: "A\x81\x41\x81\x61\x81\x81\xc6\xfeB\xc7\xa1\xc7\xfe\xc8\xa1C\xca\xa1\xfd\xfeD", + utf8: "A\uac02\uac35\uac56\ud401B\ud408\ud620\ud624C\u4f3d\u8a70D", + }, { + e: EUCKR, + encoded: "\xbc\xbc\xb0\xe8\xbe\xdf\x2c\x20\xbe\xc8\xb3\xe7", + utf8: "세계야, 안녕", + }} + + for _, tc := range testCases { + enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, "", "") + } +} + +func TestFiles(t *testing.T) { enctest.TestFile(t, EUCKR) } + +func BenchmarkEncoding(b *testing.B) { enctest.Benchmark(b, EUCKR) } diff --git a/vendor/golang.org/x/text/encoding/simplifiedchinese/all_test.go b/vendor/golang.org/x/text/encoding/simplifiedchinese/all_test.go new file mode 100644 index 000000000..b369da21a --- /dev/null +++ b/vendor/golang.org/x/text/encoding/simplifiedchinese/all_test.go @@ -0,0 +1,143 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package simplifiedchinese + +import ( + "strings" + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/internal" + "golang.org/x/text/encoding/internal/enctest" + "golang.org/x/text/transform" +) + +func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Decode", e.NewDecoder(), nil +} +func enc(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement +} + +func TestNonRepertoire(t *testing.T) { + // Pick n large enough to overflow the destination buffer of transform.String. + const n = 10000 + testCases := []struct { + init func(e encoding.Encoding) (string, transform.Transformer, error) + e encoding.Encoding + src, want string + }{ + {dec, GBK, "a\xfe\xfeb", "a\ufffdb"}, + {dec, HZGB2312, "~{z~", "\ufffd"}, + + {enc, GBK, "갂", ""}, + {enc, GBK, "a갂", "a"}, + {enc, GBK, "\u4e02갂", "\x81@"}, + + {enc, HZGB2312, "갂", ""}, + {enc, HZGB2312, "a갂", "a"}, + {enc, HZGB2312, "\u6cf5갂", "~{1C~}"}, + + {dec, GB18030, "\x80", "€"}, + {dec, GB18030, "\x81", "\ufffd"}, + {dec, GB18030, "\x81\x20", "\ufffd "}, + {dec, GB18030, "\xfe\xfe", "\ufffd"}, + {dec, GB18030, "\xfe\xff", "\ufffd\ufffd"}, + {dec, GB18030, "\xfe\x30", "\ufffd0"}, + {dec, GB18030, "\xfe\x30\x30 ", "\ufffd00 "}, + {dec, GB18030, "\xfe\x30\xff ", "\ufffd0\ufffd "}, + {dec, GB18030, "\xfe\x30\x81\x21", "\ufffd0\ufffd!"}, + + {dec, GB18030, strings.Repeat("\xfe\x30", n), strings.Repeat("\ufffd0", n)}, + + {dec, HZGB2312, "~/", "\ufffd"}, + {dec, HZGB2312, "~{a\x80", "\ufffd"}, + {dec, HZGB2312, "~{a\x80", "\ufffd"}, + {dec, HZGB2312, "~{" + strings.Repeat("z~", n), strings.Repeat("\ufffd", n)}, + {dec, HZGB2312, "~{" + strings.Repeat("\xfe\x30", n), strings.Repeat("\ufffd", n*2)}, + } + for _, tc := range testCases { + dir, tr, wantErr := tc.init(tc.e) + + dst, _, err := transform.String(tr, tc.src) + if err != wantErr { + t.Errorf("%s %v(%q): got %v; want %v", dir, tc.e, tc.src, err, wantErr) + } + if got := string(dst); got != tc.want { + t.Errorf("%s %v(%q):\ngot %q\nwant %q", dir, tc.e, tc.src, got, tc.want) + } + } +} + +func TestBasics(t *testing.T) { + // The encoded forms can be verified by the iconv program: + // $ echo 月日は百代 | iconv -f UTF-8 -t SHIFT-JIS | xxd + testCases := []struct { + e encoding.Encoding + encPrefix string + encoded string + utf8 string + }{{ + // "\u0081\u00de\u00df\u00e0\u00e1\u00e2\u00e3\uffff\U00010000" is a + // nonsense string that contains GB18030 encodable codepoints of which + // only U+00E0 and U+00E1 are GBK encodable. + // + // "A\u3000\u554a\u4e02\u4e90\u72dc\u7349\u02ca\u2588Z€" is a nonsense + // string that contains ASCII and GBK encodable codepoints from Levels + // 1-5 as well as the Euro sign. + // + // "A\u43f0\u4c32\U00027267\u3000\U0002910d\u79d4Z€" is a nonsense string + // that contains ASCII and Big5 encodable codepoints from the Basic + // Multilingual Plane and the Supplementary Ideographic Plane as well as + // the Euro sign. + // + // "花间一壶酒,独酌无相亲。" (simplified) and + // "花間一壺酒,獨酌無相親。" (traditional) + // are from the 8th century poem "Yuè Xià Dú Zhuó". + e: GB18030, + encoded: "\x81\x30\x81\x31\x81\x30\x89\x37\x81\x30\x89\x38\xa8\xa4\xa8\xa2" + + "\x81\x30\x89\x39\x81\x30\x8a\x30\x84\x31\xa4\x39\x90\x30\x81\x30", + utf8: "\u0081\u00de\u00df\u00e0\u00e1\u00e2\u00e3\uffff\U00010000", + }, { + e: GB18030, + encoded: "\xbb\xa8\xbc\xe4\xd2\xbb\xba\xf8\xbe\xc6\xa3\xac\xb6\xc0\xd7\xc3" + + "\xce\xde\xcf\xe0\xc7\xd7\xa1\xa3", + utf8: "花间一壶酒,独酌无相亲。", + }, { + e: GBK, + encoded: "A\xa1\xa1\xb0\xa1\x81\x40\x81\x80\xaa\x40\xaa\x80\xa8\x40\xa8\x80Z\x80", + utf8: "A\u3000\u554a\u4e02\u4e90\u72dc\u7349\u02ca\u2588Z€", + }, { + e: GBK, + encoded: "\xbb\xa8\xbc\xe4\xd2\xbb\xba\xf8\xbe\xc6\xa3\xac\xb6\xc0\xd7\xc3" + + "\xce\xde\xcf\xe0\xc7\xd7\xa1\xa3", + utf8: "花间一壶酒,独酌无相亲。", + }, { + e: HZGB2312, + encoded: "A~{\x21\x21~~\x30\x21~}Z~~", + utf8: "A\u3000~\u554aZ~", + }, { + e: HZGB2312, + encPrefix: "~{", + encoded: ";(<dR;:x>F#,6@WCN^O`GW!#", + utf8: "花间一壶酒,独酌无相亲。", + }} + + for _, tc := range testCases { + enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, tc.encPrefix, "") + } +} + +func TestFiles(t *testing.T) { + enctest.TestFile(t, GB18030) + enctest.TestFile(t, GBK) + enctest.TestFile(t, HZGB2312) +} + +func BenchmarkEncoding(b *testing.B) { + enctest.Benchmark(b, GB18030) + enctest.Benchmark(b, GBK) + enctest.Benchmark(b, HZGB2312) +} diff --git a/vendor/golang.org/x/text/encoding/traditionalchinese/all_test.go b/vendor/golang.org/x/text/encoding/traditionalchinese/all_test.go new file mode 100644 index 000000000..3825c7672 --- /dev/null +++ b/vendor/golang.org/x/text/encoding/traditionalchinese/all_test.go @@ -0,0 +1,114 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package traditionalchinese + +import ( + "fmt" + "io/ioutil" + "strings" + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/internal" + "golang.org/x/text/encoding/internal/enctest" + "golang.org/x/text/transform" +) + +func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Decode", e.NewDecoder(), nil +} +func enc(e encoding.Encoding) (dir string, t transform.Transformer, err error) { + return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement +} + +func TestNonRepertoire(t *testing.T) { + testCases := []struct { + init func(e encoding.Encoding) (string, transform.Transformer, error) + e encoding.Encoding + src, want string + }{ + {dec, Big5, "\x80", "\ufffd"}, + {dec, Big5, "\x81", "\ufffd"}, + {dec, Big5, "\x81\x30", "\ufffd\x30"}, + {dec, Big5, "\x81\x40", "\ufffd"}, + {dec, Big5, "\x81\xa0", "\ufffd"}, + {dec, Big5, "\xff", "\ufffd"}, + + {enc, Big5, "갂", ""}, + {enc, Big5, "a갂", "a"}, + {enc, Big5, "\u43f0갂", "\x87@"}, + } + for _, tc := range testCases { + dir, tr, wantErr := tc.init(tc.e) + t.Run(fmt.Sprintf("%s/%v/%q", dir, tc.e, tc.src), func(t *testing.T) { + dst := make([]byte, 100) + src := []byte(tc.src) + for i := 0; i <= len(tc.src); i++ { + nDst, nSrc, err := tr.Transform(dst, src[:i], false) + if err != nil && err != transform.ErrShortSrc && err != wantErr { + t.Fatalf("error on first call to Transform: %v", err) + } + n, _, err := tr.Transform(dst[nDst:], src[nSrc:], true) + nDst += n + if err != wantErr { + t.Fatalf("(%q|%q): got %v; want %v", tc.src[:i], tc.src[i:], err, wantErr) + } + if got := string(dst[:nDst]); got != tc.want { + t.Errorf("(%q|%q):\ngot %q\nwant %q", tc.src[:i], tc.src[i:], got, tc.want) + } + } + }) + } +} + +func TestBasics(t *testing.T) { + // The encoded forms can be verified by the iconv program: + // $ echo 月日は百代 | iconv -f UTF-8 -t SHIFT-JIS | xxd + testCases := []struct { + e encoding.Encoding + encPrefix string + encSuffix string + encoded string + utf8 string + }{{ + e: Big5, + encoded: "A\x87\x40\x87\x41\x87\x45\xa1\x40\xfe\xfd\xfe\xfeZ\xa3\xe1", + utf8: "A\u43f0\u4c32\U00027267\u3000\U0002910d\u79d4Z€", + }, { + e: Big5, + encoded: "\xaa\xe1\xb6\xa1\xa4\x40\xb3\xfd\xb0\x73\xa1\x41\xbf\x57\xb0\x75" + + "\xb5\x4c\xac\xdb\xbf\xcb\xa1\x43", + utf8: "花間一壺酒,獨酌無相親。", + }} + + for _, tc := range testCases { + enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, "", "") + } +} + +func TestFiles(t *testing.T) { enctest.TestFile(t, Big5) } + +func BenchmarkEncoding(b *testing.B) { enctest.Benchmark(b, Big5) } + +// TestBig5CircumflexAndMacron tests the special cases listed in +// http://encoding.spec.whatwg.org/#big5 +// Note that these special cases aren't preserved by round-tripping through +// decoding and encoding (since +// http://encoding.spec.whatwg.org/index-big5.txt does not have an entry for +// U+0304 or U+030C), so we can't test this in TestBasics. +func TestBig5CircumflexAndMacron(t *testing.T) { + src := "\x88\x5f\x88\x60\x88\x61\x88\x62\x88\x63\x88\x64\x88\x65\x88\x66 " + + "\x88\xa2\x88\xa3\x88\xa4\x88\xa5\x88\xa6" + want := "ÓǑÒ\u00ca\u0304Ế\u00ca\u030cỀÊ " + + "ü\u00ea\u0304ế\u00ea\u030cề" + dst, err := ioutil.ReadAll(transform.NewReader( + strings.NewReader(src), Big5.NewDecoder())) + if err != nil { + t.Fatal(err) + } + if got := string(dst); got != want { + t.Fatalf("\ngot %q\nwant %q", got, want) + } +} diff --git a/vendor/golang.org/x/text/encoding/unicode/unicode_test.go b/vendor/golang.org/x/text/encoding/unicode/unicode_test.go new file mode 100644 index 000000000..51b4712d8 --- /dev/null +++ b/vendor/golang.org/x/text/encoding/unicode/unicode_test.go @@ -0,0 +1,499 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unicode + +import ( + "testing" + + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" + "golang.org/x/text/encoding/internal/enctest" + "golang.org/x/text/transform" +) + +func TestBasics(t *testing.T) { + testCases := []struct { + e encoding.Encoding + encPrefix string + encSuffix string + encoded string + utf8 string + }{{ + e: utf16BEIB, + encoded: "\x00\x57\x00\xe4\xd8\x35\xdd\x65", + utf8: "\x57\u00e4\U0001d565", + }, { + e: utf16BEEB, + encPrefix: "\xfe\xff", + encoded: "\x00\x57\x00\xe4\xd8\x35\xdd\x65", + utf8: "\x57\u00e4\U0001d565", + }, { + e: utf16LEIB, + encoded: "\x57\x00\xe4\x00\x35\xd8\x65\xdd", + utf8: "\x57\u00e4\U0001d565", + }, { + e: utf16LEEB, + encPrefix: "\xff\xfe", + encoded: "\x57\x00\xe4\x00\x35\xd8\x65\xdd", + utf8: "\x57\u00e4\U0001d565", + }} + + for _, tc := range testCases { + enctest.TestEncoding(t, tc.e, tc.encoded, tc.utf8, tc.encPrefix, tc.encSuffix) + } +} + +func TestFiles(t *testing.T) { + enctest.TestFile(t, UTF8) + enctest.TestFile(t, utf16LEIB) +} + +func BenchmarkEncoding(b *testing.B) { + enctest.Benchmark(b, UTF8) + enctest.Benchmark(b, utf16LEIB) +} + +var ( + utf16LEIB = UTF16(LittleEndian, IgnoreBOM) // UTF-16LE (atypical interpretation) + utf16LEUB = UTF16(LittleEndian, UseBOM) // UTF-16, LE + utf16LEEB = UTF16(LittleEndian, ExpectBOM) // UTF-16, LE, Expect + utf16BEIB = UTF16(BigEndian, IgnoreBOM) // UTF-16BE (atypical interpretation) + utf16BEUB = UTF16(BigEndian, UseBOM) // UTF-16 default + utf16BEEB = UTF16(BigEndian, ExpectBOM) // UTF-16 Expect +) + +func TestUTF16(t *testing.T) { + testCases := []struct { + desc string + src string + notEOF bool // the inverse of atEOF + sizeDst int + want string + nSrc int + err error + t transform.Transformer + }{{ + desc: "utf-16 IgnoreBOM dec: empty string", + t: utf16BEIB.NewDecoder(), + }, { + desc: "utf-16 UseBOM dec: empty string", + t: utf16BEUB.NewDecoder(), + }, { + desc: "utf-16 ExpectBOM dec: empty string", + err: ErrMissingBOM, + t: utf16BEEB.NewDecoder(), + }, { + desc: "utf-16 dec: BOM determines encoding BE (RFC 2781:3.3)", + src: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61", + sizeDst: 100, + want: "\U00012345=Ra", + nSrc: 12, + t: utf16BEUB.NewDecoder(), + }, { + desc: "utf-16 dec: BOM determines encoding LE (RFC 2781:3.3)", + src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00", + sizeDst: 100, + want: "\U00012345=Ra", + nSrc: 12, + t: utf16LEUB.NewDecoder(), + }, { + desc: "utf-16 dec: BOM determines encoding LE, change default (RFC 2781:3.3)", + src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00", + sizeDst: 100, + want: "\U00012345=Ra", + nSrc: 12, + t: utf16BEUB.NewDecoder(), + }, { + desc: "utf-16 dec: Fail on missing BOM when required", + src: "\x08\xD8\x45\xDF\x3D\x00\xFF\xFE\xFE\xFF\x00\x52\x00\x61", + sizeDst: 100, + want: "", + nSrc: 0, + err: ErrMissingBOM, + t: utf16BEEB.NewDecoder(), + }, { + desc: "utf-16 dec: SHOULD interpret text as big-endian when BOM not present (RFC 2781:4.3)", + src: "\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61", + sizeDst: 100, + want: "\U00012345=Ra", + nSrc: 10, + t: utf16BEUB.NewDecoder(), + }, { + // This is an error according to RFC 2781. But errors in RFC 2781 are + // open to interpretations, so I guess this is fine. + desc: "utf-16le dec: incorrect BOM is an error (RFC 2781:4.1)", + src: "\xFE\xFF\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00", + sizeDst: 100, + want: "\uFFFE\U00012345=Ra", + nSrc: 12, + t: utf16LEIB.NewDecoder(), + }, { + desc: "utf-16 enc: SHOULD write BOM (RFC 2781:3.3)", + src: "\U00012345=Ra", + sizeDst: 100, + want: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00", + nSrc: 7, + t: utf16LEUB.NewEncoder(), + }, { + desc: "utf-16 enc: SHOULD write BOM (RFC 2781:3.3)", + src: "\U00012345=Ra", + sizeDst: 100, + want: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61", + nSrc: 7, + t: utf16BEUB.NewEncoder(), + }, { + desc: "utf-16le enc: MUST NOT write BOM (RFC 2781:3.3)", + src: "\U00012345=Ra", + sizeDst: 100, + want: "\x08\xD8\x45\xDF\x3D\x00\x52\x00\x61\x00", + nSrc: 7, + t: utf16LEIB.NewEncoder(), + }, { + desc: "utf-16be dec: incorrect UTF-16: odd bytes", + src: "\x00", + sizeDst: 100, + want: "\uFFFD", + nSrc: 1, + t: utf16BEIB.NewDecoder(), + }, { + desc: "utf-16be dec: unpaired surrogate, odd bytes", + src: "\xD8\x45\x00", + sizeDst: 100, + want: "\uFFFD\uFFFD", + nSrc: 3, + t: utf16BEIB.NewDecoder(), + }, { + desc: "utf-16be dec: unpaired low surrogate + valid text", + src: "\xD8\x45\x00a", + sizeDst: 100, + want: "\uFFFDa", + nSrc: 4, + t: utf16BEIB.NewDecoder(), + }, { + desc: "utf-16be dec: unpaired low surrogate + valid text + single byte", + src: "\xD8\x45\x00ab", + sizeDst: 100, + want: "\uFFFDa\uFFFD", + nSrc: 5, + t: utf16BEIB.NewDecoder(), + }, { + desc: "utf-16le dec: unpaired high surrogate", + src: "\x00\x00\x00\xDC\x12\xD8", + sizeDst: 100, + want: "\x00\uFFFD\uFFFD", + nSrc: 6, + t: utf16LEIB.NewDecoder(), + }, { + desc: "utf-16be dec: two unpaired low surrogates", + src: "\xD8\x45\xD8\x12", + sizeDst: 100, + want: "\uFFFD\uFFFD", + nSrc: 4, + t: utf16BEIB.NewDecoder(), + }, { + desc: "utf-16be dec: short dst", + src: "\x00a", + sizeDst: 0, + want: "", + nSrc: 0, + t: utf16BEIB.NewDecoder(), + err: transform.ErrShortDst, + }, { + desc: "utf-16be dec: short dst surrogate", + src: "\xD8\xF5\xDC\x12", + sizeDst: 3, + want: "", + nSrc: 0, + t: utf16BEIB.NewDecoder(), + err: transform.ErrShortDst, + }, { + desc: "utf-16be dec: short dst trailing byte", + src: "\x00", + sizeDst: 2, + want: "", + nSrc: 0, + t: utf16BEIB.NewDecoder(), + err: transform.ErrShortDst, + }, { + desc: "utf-16be dec: short src", + src: "\x00", + notEOF: true, + sizeDst: 3, + want: "", + nSrc: 0, + t: utf16BEIB.NewDecoder(), + err: transform.ErrShortSrc, + }, { + desc: "utf-16 enc", + src: "\U00012345=Ra", + sizeDst: 100, + want: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61", + nSrc: 7, + t: utf16BEUB.NewEncoder(), + }, { + desc: "utf-16 enc: short dst normal", + src: "\U00012345=Ra", + sizeDst: 9, + want: "\xD8\x08\xDF\x45\x00\x3D\x00\x52", + nSrc: 6, + t: utf16BEIB.NewEncoder(), + err: transform.ErrShortDst, + }, { + desc: "utf-16 enc: short dst surrogate", + src: "\U00012345=Ra", + sizeDst: 3, + want: "", + nSrc: 0, + t: utf16BEIB.NewEncoder(), + err: transform.ErrShortDst, + }, { + desc: "utf-16 enc: short src", + src: "\U00012345=Ra\xC2", + notEOF: true, + sizeDst: 100, + want: "\xD8\x08\xDF\x45\x00\x3D\x00\x52\x00\x61", + nSrc: 7, + t: utf16BEIB.NewEncoder(), + err: transform.ErrShortSrc, + }, { + desc: "utf-16be dec: don't change byte order mid-stream", + src: "\xFE\xFF\xD8\x08\xDF\x45\x00\x3D\xFF\xFE\x00\x52\x00\x61", + sizeDst: 100, + want: "\U00012345=\ufffeRa", + nSrc: 14, + t: utf16BEUB.NewDecoder(), + }, { + desc: "utf-16le dec: don't change byte order mid-stream", + src: "\xFF\xFE\x08\xD8\x45\xDF\x3D\x00\xFF\xFE\xFE\xFF\x52\x00\x61\x00", + sizeDst: 100, + want: "\U00012345=\ufeff\ufffeRa", + nSrc: 16, + t: utf16LEUB.NewDecoder(), + }} + for i, tc := range testCases { + b := make([]byte, tc.sizeDst) + nDst, nSrc, err := tc.t.Transform(b, []byte(tc.src), !tc.notEOF) + if err != tc.err { + t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err) + } + if got := string(b[:nDst]); got != tc.want { + t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want) + } + if nSrc != tc.nSrc { + t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc) + } + } +} + +func TestUTF8Decoder(t *testing.T) { + testCases := []struct { + desc string + src string + notEOF bool // the inverse of atEOF + sizeDst int + want string + nSrc int + err error + }{{ + desc: "empty string, empty dest buffer", + }, { + desc: "empty string", + sizeDst: 8, + }, { + desc: "empty string, streaming", + notEOF: true, + sizeDst: 8, + }, { + desc: "ascii", + src: "abcde", + sizeDst: 8, + want: "abcde", + nSrc: 5, + }, { + desc: "ascii and error", + src: "ab\x80de", + sizeDst: 7, + want: "ab\ufffdde", + nSrc: 5, + }, { + desc: "valid two-byte sequence", + src: "a\u0300bc", + sizeDst: 7, + want: "a\u0300bc", + nSrc: 5, + }, { + desc: "valid three-byte sequence", + src: "a\u0300中", + sizeDst: 7, + want: "a\u0300中", + nSrc: 6, + }, { + desc: "valid four-byte sequence", + src: "a中\U00016F50", + sizeDst: 8, + want: "a中\U00016F50", + nSrc: 8, + }, { + desc: "short source buffer", + src: "abc\xf0\x90", + notEOF: true, + sizeDst: 10, + want: "abc", + nSrc: 3, + err: transform.ErrShortSrc, + }, { + // We don't check for the maximal subpart of an ill-formed subsequence + // at the end of an open segment. + desc: "complete invalid that looks like short at end", + src: "abc\xf0\x80", + notEOF: true, + sizeDst: 10, + want: "abc", // instead of "abc\ufffd\ufffd", + nSrc: 3, + err: transform.ErrShortSrc, + }, { + desc: "incomplete sequence at end", + src: "a\x80bc\xf0\x90", + sizeDst: 9, + want: "a\ufffdbc\ufffd", + nSrc: 6, + }, { + desc: "invalid second byte", + src: "abc\xf0dddd", + sizeDst: 10, + want: "abc\ufffddddd", + nSrc: 8, + }, { + desc: "invalid second byte at end", + src: "abc\xf0d", + sizeDst: 10, + want: "abc\ufffdd", + nSrc: 5, + }, { + desc: "invalid third byte", + src: "a\u0300bc\xf0\x90dddd", + sizeDst: 12, + want: "a\u0300bc\ufffddddd", + nSrc: 11, + }, { + desc: "invalid third byte at end", + src: "a\u0300bc\xf0\x90d", + sizeDst: 12, + want: "a\u0300bc\ufffdd", + nSrc: 8, + }, { + desc: "invalid fourth byte, tight buffer", + src: "a\u0300bc\xf0\x90\x80d", + sizeDst: 9, + want: "a\u0300bc\ufffdd", + nSrc: 9, + }, { + desc: "invalid fourth byte at end", + src: "a\u0300bc\xf0\x90\x80", + sizeDst: 8, + want: "a\u0300bc\ufffd", + nSrc: 8, + }, { + desc: "invalid fourth byte and short four byte sequence", + src: "a\u0300bc\xf0\x90\x80\xf0\x90\x80", + notEOF: true, + sizeDst: 20, + want: "a\u0300bc\ufffd", + nSrc: 8, + err: transform.ErrShortSrc, + }, { + desc: "valid four-byte sequence overflowing short buffer", + src: "a\u0300bc\xf0\x90\x80\x80", + notEOF: true, + sizeDst: 8, + want: "a\u0300bc", + nSrc: 5, + err: transform.ErrShortDst, + }, { + desc: "invalid fourth byte at end short, but short dst", + src: "a\u0300bc\xf0\x90\x80\xf0\x90\x80", + notEOF: true, + sizeDst: 8, + // More bytes would fit in the buffer, but this seems to require a more + // complicated and slower algorithm. + want: "a\u0300bc", // instead of "a\u0300bc" + nSrc: 5, + err: transform.ErrShortDst, + }, { + desc: "short dst for error", + src: "abc\x80", + notEOF: true, + sizeDst: 5, + want: "abc", + nSrc: 3, + err: transform.ErrShortDst, + }, { + desc: "adjusting short dst buffer", + src: "abc\x80ef", + notEOF: true, + sizeDst: 6, + want: "abc\ufffd", + nSrc: 4, + err: transform.ErrShortDst, + }} + tr := UTF8.NewDecoder() + for i, tc := range testCases { + b := make([]byte, tc.sizeDst) + nDst, nSrc, err := tr.Transform(b, []byte(tc.src), !tc.notEOF) + if err != tc.err { + t.Errorf("%d:%s: error was %v; want %v", i, tc.desc, err, tc.err) + } + if got := string(b[:nDst]); got != tc.want { + t.Errorf("%d:%s: result was %q: want %q", i, tc.desc, got, tc.want) + } + if nSrc != tc.nSrc { + t.Errorf("%d:%s: nSrc was %d; want %d", i, tc.desc, nSrc, tc.nSrc) + } + } +} + +func TestBOMOverride(t *testing.T) { + dec := BOMOverride(charmap.CodePage437.NewDecoder()) + dst := make([]byte, 100) + for i, tc := range []struct { + src string + atEOF bool + dst string + nSrc int + err error + }{ + 0: {"H\x82ll\x93", true, "Héllô", 5, nil}, + 1: {"\uFEFFHéllö", true, "Héllö", 10, nil}, + 2: {"\xFE\xFF\x00H\x00e\x00l\x00l\x00o", true, "Hello", 12, nil}, + 3: {"\xFF\xFEH\x00e\x00l\x00l\x00o\x00", true, "Hello", 12, nil}, + 4: {"\uFEFF", true, "", 3, nil}, + 5: {"\xFE\xFF", true, "", 2, nil}, + 6: {"\xFF\xFE", true, "", 2, nil}, + 7: {"\xEF\xBB", true, "\u2229\u2557", 2, nil}, + 8: {"\xEF", true, "\u2229", 1, nil}, + 9: {"", true, "", 0, nil}, + 10: {"\xFE", true, "\u25a0", 1, nil}, + 11: {"\xFF", true, "\u00a0", 1, nil}, + 12: {"\xEF\xBB", false, "", 0, transform.ErrShortSrc}, + 13: {"\xEF", false, "", 0, transform.ErrShortSrc}, + 14: {"", false, "", 0, transform.ErrShortSrc}, + 15: {"\xFE", false, "", 0, transform.ErrShortSrc}, + 16: {"\xFF", false, "", 0, transform.ErrShortSrc}, + 17: {"\xFF\xFE", false, "", 0, transform.ErrShortSrc}, + } { + dec.Reset() + nDst, nSrc, err := dec.Transform(dst, []byte(tc.src), tc.atEOF) + got := string(dst[:nDst]) + if nSrc != tc.nSrc { + t.Errorf("%d: nSrc: got %d; want %d", i, nSrc, tc.nSrc) + } + if got != tc.dst { + t.Errorf("%d: got %+q; want %+q", i, got, tc.dst) + } + if err != tc.err { + t.Errorf("%d: error: got %v; want %v", i, err, tc.err) + } + } +} diff --git a/vendor/golang.org/x/text/gen.go b/vendor/golang.org/x/text/gen.go new file mode 100644 index 000000000..757fefb74 --- /dev/null +++ b/vendor/golang.org/x/text/gen.go @@ -0,0 +1,319 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// gen runs go generate on Unicode- and CLDR-related package in the text +// repositories, taking into account dependencies and versions. +package main + +import ( + "bytes" + "flag" + "fmt" + "go/build" + "go/format" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "regexp" + "runtime" + "strings" + "sync" + "unicode" + + "golang.org/x/text/collate" + "golang.org/x/text/internal/gen" + "golang.org/x/text/language" +) + +var ( + verbose = flag.Bool("v", false, "verbose output") + force = flag.Bool("force", false, "ignore failing dependencies") + doCore = flag.Bool("core", false, "force an update to core") + excludeList = flag.String("exclude", "", + "comma-separated list of packages to exclude") + + // The user can specify a selection of packages to build on the command line. + args []string +) + +func exclude(pkg string) bool { + if len(args) > 0 { + return !contains(args, pkg) + } + return contains(strings.Split(*excludeList, ","), pkg) +} + +// TODO: +// - Better version handling. +// - Generate tables for the core unicode package? +// - Add generation for encodings. This requires some retooling here and there. +// - Running repo-wide "long" tests. + +var vprintf = fmt.Printf + +func main() { + gen.Init() + args = flag.Args() + if !*verbose { + // Set vprintf to a no-op. + vprintf = func(string, ...interface{}) (int, error) { return 0, nil } + } + + // TODO: create temporary cache directory to load files and create and set + // a "cache" option if the user did not specify the UNICODE_DIR environment + // variable. This will prevent duplicate downloads and also will enable long + // tests, which really need to be run after each generated package. + + updateCore := *doCore + if gen.UnicodeVersion() != unicode.Version { + fmt.Printf("Requested Unicode version %s; core unicode version is %s.\n", + gen.UnicodeVersion(), + unicode.Version) + c := collate.New(language.Und, collate.Numeric) + if c.CompareString(gen.UnicodeVersion(), unicode.Version) < 0 && !*force { + os.Exit(2) + } + updateCore = true + goroot := os.Getenv("GOROOT") + appendToFile( + filepath.Join(goroot, "api", "except.txt"), + fmt.Sprintf("pkg unicode, const Version = %q\n", unicode.Version), + ) + const lines = `pkg unicode, const Version = %q +// TODO: add a new line of the following form for each new script and property. +pkg unicode, var <new script or property> *RangeTable +` + appendToFile( + filepath.Join(goroot, "api", "next.txt"), + fmt.Sprintf(lines, gen.UnicodeVersion()), + ) + } + + var unicode = &dependency{} + if updateCore { + fmt.Printf("Updating core to version %s...\n", gen.UnicodeVersion()) + unicode = generate("unicode") + + // Test some users of the unicode packages, especially the ones that + // keep a mirrored table. These may need to be corrected by hand. + generate("regexp", unicode) + generate("strconv", unicode) // mimics Unicode table + generate("strings", unicode) + generate("testing", unicode) // mimics Unicode table + } + + var ( + cldr = generate("./unicode/cldr", unicode) + language = generate("./language", cldr) + internal = generate("./internal", unicode, language) + norm = generate("./unicode/norm", unicode) + rangetable = generate("./unicode/rangetable", unicode) + cases = generate("./cases", unicode, norm, language, rangetable) + width = generate("./width", unicode) + bidi = generate("./unicode/bidi", unicode, norm, rangetable) + mib = generate("./encoding/internal/identifier", unicode) + number = generate("./internal/number", unicode, cldr, language, internal) + _ = generate("./encoding/htmlindex", unicode, language, mib) + _ = generate("./encoding/ianaindex", unicode, language, mib) + _ = generate("./secure/precis", unicode, norm, rangetable, cases, width, bidi) + _ = generate("./internal/cldrtree", language) + _ = generate("./currency", unicode, cldr, language, internal, number) + _ = generate("./feature/plural", unicode, cldr, language, internal, number) + _ = generate("./internal/export/idna", unicode, bidi, norm) + _ = generate("./language/display", unicode, cldr, language, internal, number) + _ = generate("./collate", unicode, norm, cldr, language, rangetable) + _ = generate("./search", unicode, norm, cldr, language, rangetable) + ) + all.Wait() + + // Copy exported packages to the destination golang.org repo. + copyExported("golang.org/x/net/idna") + + if updateCore { + copyVendored() + } + + if hasErrors { + fmt.Println("FAIL") + os.Exit(1) + } + vprintf("SUCCESS\n") +} + +func appendToFile(file, text string) { + fmt.Println("Augmenting", file) + w, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + fmt.Println("Failed to open file:", err) + os.Exit(1) + } + defer w.Close() + if _, err := w.WriteString(text); err != nil { + fmt.Println("Failed to write to file:", err) + os.Exit(1) + } +} + +var ( + all sync.WaitGroup + hasErrors bool +) + +type dependency struct { + sync.WaitGroup + hasErrors bool +} + +func generate(pkg string, deps ...*dependency) *dependency { + var wg dependency + if exclude(pkg) { + return &wg + } + wg.Add(1) + all.Add(1) + go func() { + defer wg.Done() + defer all.Done() + // Wait for dependencies to finish. + for _, d := range deps { + d.Wait() + if d.hasErrors && !*force { + fmt.Printf("--- ABORT: %s\n", pkg) + wg.hasErrors = true + return + } + } + vprintf("=== GENERATE %s\n", pkg) + args := []string{"generate"} + if *verbose { + args = append(args, "-v") + } + args = append(args, pkg) + cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) + w := &bytes.Buffer{} + cmd.Stderr = w + cmd.Stdout = w + if err := cmd.Run(); err != nil { + fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(w), err) + hasErrors = true + wg.hasErrors = true + return + } + + vprintf("=== TEST %s\n", pkg) + args[0] = "test" + cmd = exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) + wt := &bytes.Buffer{} + cmd.Stderr = wt + cmd.Stdout = wt + if err := cmd.Run(); err != nil { + fmt.Printf("--- FAIL: %s:\n\t%v\n\tError: %v\n", pkg, indent(wt), err) + hasErrors = true + wg.hasErrors = true + return + } + vprintf("--- SUCCESS: %s\n\t%v\n", pkg, indent(w)) + fmt.Print(wt.String()) + }() + return &wg +} + +// copyExported copies a package in x/text/internal/export to the +// destination repository. +func copyExported(p string) { + copyPackage( + filepath.Join("internal", "export", path.Base(p)), + filepath.Join("..", filepath.FromSlash(p[len("golang.org/x"):])), + "golang.org/x/text/internal/export/"+path.Base(p), + p) +} + +// copyVendored copies packages used by Go core into the vendored directory. +func copyVendored() { + root := filepath.Join(build.Default.GOROOT, filepath.FromSlash("src/vendor/golang_org/x")) + + err := filepath.Walk(root, func(dir string, info os.FileInfo, err error) error { + if err != nil || !info.IsDir() || root == dir { + return err + } + src := dir[len(root)+1:] + const slash = string(filepath.Separator) + if c := strings.Split(src, slash); c[0] == "text" { + // Copy a text repo package from its normal location. + src = strings.Join(c[1:], slash) + } else { + // Copy the vendored package if it exists in the export directory. + src = filepath.Join("internal", "export", filepath.Base(src)) + } + copyPackage(src, dir, "golang.org", "golang_org") + return nil + }) + if err != nil { + fmt.Printf("Seeding directory %s has failed %v:", root, err) + os.Exit(1) + } +} + +// goGenRE is used to remove go:generate lines. +var goGenRE = regexp.MustCompile("//go:generate[^\n]*\n") + +// copyPackage copies relevant files from a directory in x/text to the +// destination package directory. The destination package is assumed to have +// the same name. For each copied file go:generate lines are removed and +// and package comments are rewritten to the new path. +func copyPackage(dirSrc, dirDst, search, replace string) { + err := filepath.Walk(dirSrc, func(file string, info os.FileInfo, err error) error { + base := filepath.Base(file) + if err != nil || info.IsDir() || + !strings.HasSuffix(base, ".go") || + strings.HasSuffix(base, "_test.go") || + // Don't process subdirectories. + filepath.Dir(file) != dirSrc { + return nil + } + b, err := ioutil.ReadFile(file) + if err != nil || bytes.Contains(b, []byte("\n// +build ignore")) { + return err + } + // Fix paths. + b = bytes.Replace(b, []byte(search), []byte(replace), -1) + // Remove go:generate lines. + b = goGenRE.ReplaceAllLiteral(b, nil) + comment := "// Code generated by running \"go generate\" in golang.org/x/text. DO NOT EDIT.\n\n" + if *doCore { + comment = "// Code generated by running \"go run gen.go -core\" in golang.org/x/text. DO NOT EDIT.\n\n" + } + if !bytes.HasPrefix(b, []byte(comment)) { + b = append([]byte(comment), b...) + } + if b, err = format.Source(b); err != nil { + fmt.Println("Failed to format file:", err) + os.Exit(1) + } + file = filepath.Join(dirDst, base) + vprintf("=== COPY %s\n", file) + return ioutil.WriteFile(file, b, 0666) + }) + if err != nil { + fmt.Println("Copying exported files failed:", err) + os.Exit(1) + } +} + +func contains(a []string, s string) bool { + for _, e := range a { + if s == e { + return true + } + } + return false +} + +func indent(b *bytes.Buffer) string { + return strings.Replace(strings.TrimSpace(b.String()), "\n", "\n\t", -1) +} diff --git a/vendor/golang.org/x/text/internal/colltab/collate_test.go b/vendor/golang.org/x/text/internal/colltab/collate_test.go new file mode 100644 index 000000000..580c85c22 --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/collate_test.go @@ -0,0 +1,121 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab_test + +// This file contains tests which need to import package collate, which causes +// an import cycle when done within package colltab itself. + +import ( + "bytes" + "testing" + "unicode" + + "golang.org/x/text/collate" + "golang.org/x/text/language" + "golang.org/x/text/unicode/rangetable" +) + +// assigned is used to only test runes that are inside the scope of the Unicode +// version used to generation the collation table. +var assigned = rangetable.Assigned(collate.UnicodeVersion) + +func TestNonDigits(t *testing.T) { + c := collate.New(language.English, collate.Loose, collate.Numeric) + + // Verify that all non-digit numbers sort outside of the number range. + for r, hi := rune(unicode.N.R16[0].Lo), rune(unicode.N.R32[0].Hi); r <= hi; r++ { + if unicode.In(r, unicode.Nd) || !unicode.In(r, assigned) { + continue + } + if a := string(r); c.CompareString(a, "0") != -1 && c.CompareString(a, "999999") != 1 { + t.Errorf("%+q non-digit number is collated as digit", a) + } + } +} + +func TestNumericCompare(t *testing.T) { + c := collate.New(language.English, collate.Loose, collate.Numeric) + + // Iterate over all digits. + for _, r16 := range unicode.Nd.R16 { + testDigitCompare(t, c, rune(r16.Lo), rune(r16.Hi)) + } + for _, r32 := range unicode.Nd.R32 { + testDigitCompare(t, c, rune(r32.Lo), rune(r32.Hi)) + } +} + +func testDigitCompare(t *testing.T, c *collate.Collator, zero, nine rune) { + if !unicode.In(zero, assigned) { + return + } + n := int(nine - zero + 1) + if n%10 != 0 { + t.Fatalf("len([%+q, %+q]) = %d; want a multiple of 10", zero, nine, n) + } + for _, tt := range []struct { + prefix string + b [11]string + }{ + { + prefix: "", + b: [11]string{ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + }, + }, + { + prefix: "1", + b: [11]string{ + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", + }, + }, + { + prefix: "0", + b: [11]string{ + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", + }, + }, + { + prefix: "00", + b: [11]string{ + "000", "001", "002", "003", "004", "005", "006", "007", "008", "009", "010", + }, + }, + { + prefix: "9", + b: [11]string{ + "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", + }, + }, + } { + for k := 0; k <= n; k++ { + i := k % 10 + a := tt.prefix + string(zero+rune(i)) + for j, b := range tt.b { + want := 0 + switch { + case i < j: + want = -1 + case i > j: + want = 1 + } + got := c.CompareString(a, b) + if got != want { + t.Errorf("Compare(%+q, %+q) = %d; want %d", a, b, got, want) + return + } + } + } + } +} + +func BenchmarkNumericWeighter(b *testing.B) { + c := collate.New(language.English, collate.Numeric) + input := bytes.Repeat([]byte("Testing, testing 123..."), 100) + b.SetBytes(int64(2 * len(input))) + for i := 0; i < b.N; i++ { + c.Compare(input, input) + } +} diff --git a/vendor/golang.org/x/text/internal/colltab/collelem_test.go b/vendor/golang.org/x/text/internal/colltab/collelem_test.go new file mode 100644 index 000000000..f131ecc32 --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/collelem_test.go @@ -0,0 +1,183 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab + +import ( + "fmt" + "testing" + "unicode" +) + +func (e Elem) String() string { + q := "" + if v := e.Quaternary(); v == MaxQuaternary { + q = "max" + } else { + q = fmt.Sprint(v) + } + return fmt.Sprintf("[%d, %d, %d, %s]", + e.Primary(), + e.Secondary(), + e.Tertiary(), + q) +} + +type ceTest struct { + f func(inout []int) (Elem, ceType) + arg []int +} + +func makeCE(weights []int) Elem { + ce, _ := MakeElem(weights[0], weights[1], weights[2], uint8(weights[3])) + return ce +} + +var defaultValues = []int{0, defaultSecondary, defaultTertiary, 0} + +func e(w ...int) Elem { + return makeCE(append(w, defaultValues[len(w):]...)) +} + +func makeContractIndex(index, n, offset int) Elem { + const ( + contractID = 0xC0000000 + maxNBits = 4 + maxTrieIndexBits = 12 + maxContractOffsetBits = 13 + ) + ce := Elem(contractID) + ce += Elem(offset << (maxNBits + maxTrieIndexBits)) + ce += Elem(index << maxNBits) + ce += Elem(n) + return ce +} + +func makeExpandIndex(index int) Elem { + const expandID = 0xE0000000 + return expandID + Elem(index) +} + +func makeDecompose(t1, t2 int) Elem { + const decompID = 0xF0000000 + return Elem(t2<<8+t1) + decompID +} + +func normalCE(inout []int) (ce Elem, t ceType) { + ce = makeCE(inout) + inout[0] = ce.Primary() + inout[1] = ce.Secondary() + inout[2] = int(ce.Tertiary()) + inout[3] = int(ce.CCC()) + return ce, ceNormal +} + +func expandCE(inout []int) (ce Elem, t ceType) { + ce = makeExpandIndex(inout[0]) + inout[0] = splitExpandIndex(ce) + return ce, ceExpansionIndex +} + +func contractCE(inout []int) (ce Elem, t ceType) { + ce = makeContractIndex(inout[0], inout[1], inout[2]) + i, n, o := splitContractIndex(ce) + inout[0], inout[1], inout[2] = i, n, o + return ce, ceContractionIndex +} + +func decompCE(inout []int) (ce Elem, t ceType) { + ce = makeDecompose(inout[0], inout[1]) + t1, t2 := splitDecompose(ce) + inout[0], inout[1] = int(t1), int(t2) + return ce, ceDecompose +} + +var ceTests = []ceTest{ + {normalCE, []int{0, 0, 0, 0}}, + {normalCE, []int{0, 30, 3, 0}}, + {normalCE, []int{0, 30, 3, 0xFF}}, + {normalCE, []int{100, defaultSecondary, defaultTertiary, 0}}, + {normalCE, []int{100, defaultSecondary, defaultTertiary, 0xFF}}, + {normalCE, []int{100, defaultSecondary, 3, 0}}, + {normalCE, []int{0x123, defaultSecondary, 8, 0xFF}}, + + {contractCE, []int{0, 0, 0}}, + {contractCE, []int{1, 1, 1}}, + {contractCE, []int{1, (1 << maxNBits) - 1, 1}}, + {contractCE, []int{(1 << maxTrieIndexBits) - 1, 1, 1}}, + {contractCE, []int{1, 1, (1 << maxContractOffsetBits) - 1}}, + + {expandCE, []int{0}}, + {expandCE, []int{5}}, + {expandCE, []int{(1 << maxExpandIndexBits) - 1}}, + + {decompCE, []int{0, 0}}, + {decompCE, []int{1, 1}}, + {decompCE, []int{0x1F, 0x1F}}, +} + +func TestColElem(t *testing.T) { + for i, tt := range ceTests { + inout := make([]int, len(tt.arg)) + copy(inout, tt.arg) + ce, typ := tt.f(inout) + if ce.ctype() != typ { + t.Errorf("%d: type is %d; want %d (ColElem: %X)", i, ce.ctype(), typ, ce) + } + for j, a := range tt.arg { + if inout[j] != a { + t.Errorf("%d: argument %d is %X; want %X (ColElem: %X)", i, j, inout[j], a, ce) + } + } + } +} + +type implicitTest struct { + r rune + p int +} + +var implicitTests = []implicitTest{ + {0x33FF, 0x533FF}, + {0x3400, 0x23400}, + {0x4DC0, 0x54DC0}, + {0x4DFF, 0x54DFF}, + {0x4E00, 0x14E00}, + {0x9FCB, 0x19FCB}, + {0xA000, 0x5A000}, + {0xF8FF, 0x5F8FF}, + {0xF900, 0x1F900}, + {0xFA23, 0x1FA23}, + {0xFAD9, 0x1FAD9}, + {0xFB00, 0x5FB00}, + {0x20000, 0x40000}, + {0x2B81C, 0x4B81C}, + {unicode.MaxRune, 0x15FFFF}, // maximum primary value +} + +func TestImplicit(t *testing.T) { + for _, tt := range implicitTests { + if p := implicitPrimary(tt.r); p != tt.p { + t.Errorf("%U: was %X; want %X", tt.r, p, tt.p) + } + } +} + +func TestUpdateTertiary(t *testing.T) { + tests := []struct { + in, out Elem + t uint8 + }{ + {0x4000FE20, 0x0000FE8A, 0x0A}, + {0x4000FE21, 0x0000FEAA, 0x0A}, + {0x0000FE8B, 0x0000FE83, 0x03}, + {0x82FF0188, 0x9BFF0188, 0x1B}, + {0xAFF0CC02, 0xAFF0CC1B, 0x1B}, + } + for i, tt := range tests { + if out := tt.in.updateTertiary(tt.t); out != tt.out { + t.Errorf("%d: was %X; want %X", i, out, tt.out) + } + } +} diff --git a/vendor/golang.org/x/text/internal/colltab/colltab_test.go b/vendor/golang.org/x/text/internal/colltab/colltab_test.go new file mode 100644 index 000000000..c403ac346 --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/colltab_test.go @@ -0,0 +1,64 @@ +package colltab + +import ( + "testing" + + "golang.org/x/text/language" +) + +func TestMatchLang(t *testing.T) { + tags := []language.Tag{ + 0: language.Und, + 1: language.MustParse("bs"), + 2: language.German, + 3: language.English, + 4: language.AmericanEnglish, + 5: language.MustParse("en-US-u-va-posix"), + 6: language.Portuguese, + 7: language.Serbian, + 8: language.MustParse("sr-Latn"), + 9: language.Chinese, + 10: language.MustParse("zh-u-co-stroke"), + 11: language.MustParse("zh-Hant-u-co-pinyin"), + 12: language.TraditionalChinese, + } + for i, tc := range []struct { + x int + t language.Tag + }{ + {0, language.Und}, + {0, language.Persian}, // Default to first element when no match. + {3, language.English}, + {4, language.AmericanEnglish}, + {5, language.MustParse("en-US-u-va-posix")}, // Ext. variant match. + {4, language.MustParse("en-US-u-va-noposix")}, // Ext. variant mismatch. + {3, language.MustParse("en-UK-u-va-noposix")}, // Ext. variant mismatch. + {7, language.Serbian}, + {0, language.Croatian}, // Don't match to close language! + {0, language.MustParse("gsw")}, // Don't match to close language! + {1, language.MustParse("bs-Cyrl")}, // Odd, but correct. + {1, language.MustParse("bs-Latn")}, // Estimated script drops. + {8, language.MustParse("sr-Latn")}, + {9, language.Chinese}, + {9, language.SimplifiedChinese}, + {12, language.TraditionalChinese}, + {11, language.MustParse("zh-Hant-u-co-pinyin")}, + // TODO: should this be 12? Either inherited value (10) or default is + // fine in this case, though. Other locales are not affected. + {10, language.MustParse("zh-Hant-u-co-stroke")}, + // There is no "phonebk" sorting order for zh-Hant, so use default. + {12, language.MustParse("zh-Hant-u-co-phonebk")}, + {10, language.MustParse("zh-u-co-stroke")}, + {12, language.MustParse("und-TW")}, // Infer script and language. + {12, language.MustParse("und-HK")}, // Infer script and language. + {6, language.MustParse("und-BR")}, // Infer script and language. + {6, language.MustParse("und-PT")}, // Infer script and language. + {2, language.MustParse("und-Latn-DE")}, // Infer language. + {0, language.MustParse("und-Jpan-BR")}, // Infers "ja", so no match. + {0, language.MustParse("zu")}, // No match past index. + } { + if x := MatchLang(tc.t, tags); x != tc.x { + t.Errorf("%d: MatchLang(%q, tags) = %d; want %d", i, tc.t, x, tc.x) + } + } +} diff --git a/vendor/golang.org/x/text/internal/colltab/contract_test.go b/vendor/golang.org/x/text/internal/colltab/contract_test.go new file mode 100644 index 000000000..ce2871dd4 --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/contract_test.go @@ -0,0 +1,131 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab + +import ( + "testing" +) + +type lookupStrings struct { + str string + offset int + n int // bytes consumed from input +} + +type LookupTest struct { + lookup []lookupStrings + n int + tries ContractTrieSet +} + +var lookupTests = []LookupTest{{ + []lookupStrings{ + {"abc", 1, 3}, + {"a", 0, 0}, + {"b", 0, 0}, + {"c", 0, 0}, + {"d", 0, 0}, + }, + 1, + ContractTrieSet{ + {'a', 0, 1, 0xFF}, + {'b', 0, 1, 0xFF}, + {'c', 'c', 0, 1}, + }, +}, { + []lookupStrings{ + {"abc", 1, 3}, + {"abd", 2, 3}, + {"abe", 3, 3}, + {"a", 0, 0}, + {"ab", 0, 0}, + {"d", 0, 0}, + {"f", 0, 0}, + }, + 1, + ContractTrieSet{ + {'a', 0, 1, 0xFF}, + {'b', 0, 1, 0xFF}, + {'c', 'e', 0, 1}, + }, +}, { + []lookupStrings{ + {"abc", 1, 3}, + {"ab", 2, 2}, + {"a", 3, 1}, + {"abcd", 1, 3}, + {"abe", 2, 2}, + }, + 1, + ContractTrieSet{ + {'a', 0, 1, 3}, + {'b', 0, 1, 2}, + {'c', 'c', 0, 1}, + }, +}, { + []lookupStrings{ + {"abc", 1, 3}, + {"abd", 2, 3}, + {"ab", 3, 2}, + {"ac", 4, 2}, + {"a", 5, 1}, + {"b", 6, 1}, + {"ba", 6, 1}, + }, + 2, + ContractTrieSet{ + {'b', 'b', 0, 6}, + {'a', 0, 2, 5}, + {'c', 'c', 0, 4}, + {'b', 0, 1, 3}, + {'c', 'd', 0, 1}, + }, +}, { + []lookupStrings{ + {"bcde", 2, 4}, + {"bc", 7, 2}, + {"ab", 6, 2}, + {"bcd", 5, 3}, + {"abcd", 1, 4}, + {"abc", 4, 3}, + {"bcdf", 3, 4}, + }, + 2, + ContractTrieSet{ + {'b', 3, 1, 0xFF}, + {'a', 0, 1, 0xFF}, + {'b', 0, 1, 6}, + {'c', 0, 1, 4}, + {'d', 'd', 0, 1}, + {'c', 0, 1, 7}, + {'d', 0, 1, 5}, + {'e', 'f', 0, 2}, + }, +}} + +func lookup(c *ContractTrieSet, nnode int, s []uint8) (i, n int) { + scan := c.scanner(0, nnode, s) + scan.scan(0) + return scan.result() +} + +func TestLookupContraction(t *testing.T) { + for i, tt := range lookupTests { + cts := ContractTrieSet(tt.tries) + for j, lu := range tt.lookup { + str := lu.str + for _, s := range []string{str, str + "X"} { + const msg = `%d:%d: %s of "%s" %v; want %v` + offset, n := lookup(&cts, tt.n, []byte(s)) + if offset != lu.offset { + t.Errorf(msg, i, j, "offset", s, offset, lu.offset) + } + if n != lu.n { + t.Errorf(msg, i, j, "bytes consumed", s, n, len(str)) + } + } + } + } +} diff --git a/vendor/golang.org/x/text/internal/colltab/iter_test.go b/vendor/golang.org/x/text/internal/colltab/iter_test.go new file mode 100644 index 000000000..5783534c7 --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/iter_test.go @@ -0,0 +1,63 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab + +import ( + "testing" +) + +func TestDoNorm(t *testing.T) { + const div = -1 // The insertion point of the next block. + tests := []struct { + in, out []int + }{{ + in: []int{4, div, 3}, + out: []int{3, 4}, + }, { + in: []int{4, div, 3, 3, 3}, + out: []int{3, 3, 3, 4}, + }, { + in: []int{0, 4, div, 3}, + out: []int{0, 3, 4}, + }, { + in: []int{0, 0, 4, 5, div, 3, 3}, + out: []int{0, 0, 3, 3, 4, 5}, + }, { + in: []int{0, 0, 1, 4, 5, div, 3, 3}, + out: []int{0, 0, 1, 3, 3, 4, 5}, + }, { + in: []int{0, 0, 1, 4, 5, div, 4, 4}, + out: []int{0, 0, 1, 4, 4, 4, 5}, + }, + } + for j, tt := range tests { + i := Iter{} + var w, p int + for k, cc := range tt.in { + + if cc == div { + w = 100 + p = k + continue + } + i.Elems = append(i.Elems, makeCE([]int{w, defaultSecondary, 2, cc})) + } + i.doNorm(p, i.Elems[p].CCC()) + if len(i.Elems) != len(tt.out) { + t.Errorf("%d: length was %d; want %d", j, len(i.Elems), len(tt.out)) + } + prevCCC := uint8(0) + for k, ce := range i.Elems { + if int(ce.CCC()) != tt.out[k] { + t.Errorf("%d:%d: unexpected CCC. Was %d; want %d", j, k, ce.CCC(), tt.out[k]) + } + if k > 0 && ce.CCC() == prevCCC && i.Elems[k-1].Primary() > ce.Primary() { + t.Errorf("%d:%d: normalization crossed across CCC boundary.", j, k) + } + } + } + + // Combining rune overflow is tested in search/pattern_test.go. +} diff --git a/vendor/golang.org/x/text/internal/colltab/numeric_test.go b/vendor/golang.org/x/text/internal/colltab/numeric_test.go new file mode 100644 index 000000000..e9406ae3f --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/numeric_test.go @@ -0,0 +1,159 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab + +import ( + "reflect" + "strings" + "testing" + + "golang.org/x/text/internal/testtext" +) + +const ( + digSec = defaultSecondary + digTert = defaultTertiary +) + +var tPlus3 = e(0, 50, digTert+3) + +// numWeighter is a testWeighter used for testing numericWeighter. +var numWeighter = testWeighter{ + "0": p(100), + "0": []Elem{e(100, digSec, digTert+1)}, // U+FF10 FULLWIDTH DIGIT ZERO + "₀": []Elem{e(100, digSec, digTert+5)}, // U+2080 SUBSCRIPT ZERO + + "1": p(101), + // Allow non-primary collation elements to be inserted. + "١": append(p(101), tPlus3), // U+0661 ARABIC-INDIC DIGIT ONE + // Allow varying tertiary weight if the number is Nd. + "1": []Elem{e(101, digSec, digTert+1)}, // U+FF11 FULLWIDTH DIGIT ONE + "2": p(102), + // Allow non-primary collation elements to be inserted. + "٢": append(p(102), tPlus3), // U+0662 ARABIC-INDIC DIGIT TWO + // Varying tertiary weights should be ignored. + "2": []Elem{e(102, digSec, digTert+3)}, // U+FF12 FULLWIDTH DIGIT TWO + "3": p(103), + "4": p(104), + "5": p(105), + "6": p(106), + "7": p(107), + // Weights must be strictly monotonically increasing, but do not need to be + // consecutive. + "8": p(118), + "9": p(119), + // Allow non-primary collation elements to be inserted. + "٩": append(p(119), tPlus3), // U+0669 ARABIC-INDIC DIGIT NINE + // Varying tertiary weights should be ignored. + "9": []Elem{e(119, digSec, digTert+1)}, // U+FF19 FULLWIDTH DIGIT NINE + "₉": []Elem{e(119, digSec, digTert+5)}, // U+2089 SUBSCRIPT NINE + + "a": p(5), + "b": p(6), + "c": p(8, 2), + + "klm": p(99), + + "nop": p(121), + + "x": p(200), + "y": p(201), +} + +func p(w ...int) (elems []Elem) { + for _, x := range w { + e, _ := MakeElem(x, digSec, digTert, 0) + elems = append(elems, e) + } + return elems +} + +func TestNumericAppendNext(t *testing.T) { + for _, tt := range []struct { + in string + w []Elem + }{ + {"a", p(5)}, + {"klm", p(99)}, + {"aa", p(5, 5)}, + {"1", p(120, 1, 101)}, + {"0", p(120, 0)}, + {"01", p(120, 1, 101)}, + {"0001", p(120, 1, 101)}, + {"10", p(120, 2, 101, 100)}, + {"99", p(120, 2, 119, 119)}, + {"9999", p(120, 4, 119, 119, 119, 119)}, + {"1a", p(120, 1, 101, 5)}, + {"0b", p(120, 0, 6)}, + {"01c", p(120, 1, 101, 8, 2)}, + {"10x", p(120, 2, 101, 100, 200)}, + {"99y", p(120, 2, 119, 119, 201)}, + {"9999nop", p(120, 4, 119, 119, 119, 119, 121)}, + + // Allow follow-up collation elements if they have a zero non-primary. + {"١٢٩", []Elem{e(120), e(3), e(101), tPlus3, e(102), tPlus3, e(119), tPlus3}}, + { + "129", + []Elem{ + e(120), e(3), + e(101, digSec, digTert+1), + e(102, digSec, digTert+3), + e(119, digSec, digTert+1), + }, + }, + + // Ensure AppendNext* adds to the given buffer. + {"a10", p(5, 120, 2, 101, 100)}, + } { + nw := NewNumericWeighter(numWeighter) + + b := []byte(tt.in) + got := []Elem(nil) + for n, sz := 0, 0; n < len(b); { + got, sz = nw.AppendNext(got, b[n:]) + n += sz + } + if !reflect.DeepEqual(got, tt.w) { + t.Errorf("AppendNext(%q) =\n%v; want\n%v", tt.in, got, tt.w) + } + + got = nil + for n, sz := 0, 0; n < len(tt.in); { + got, sz = nw.AppendNextString(got, tt.in[n:]) + n += sz + } + if !reflect.DeepEqual(got, tt.w) { + t.Errorf("AppendNextString(%q) =\n%v; want\n%v", tt.in, got, tt.w) + } + } +} + +func TestNumericOverflow(t *testing.T) { + manyDigits := strings.Repeat("9", maxDigits+1) + "a" + + nw := NewNumericWeighter(numWeighter) + + got, n := nw.AppendNextString(nil, manyDigits) + + if n != maxDigits { + t.Errorf("n: got %d; want %d", n, maxDigits) + } + + if got[1].Primary() != maxDigits { + t.Errorf("primary(e[1]): got %d; want %d", n, maxDigits) + } +} + +func TestNumericWeighterAlloc(t *testing.T) { + buf := make([]Elem, 100) + w := NewNumericWeighter(numWeighter) + s := "1234567890a" + + nNormal := testtext.AllocsPerRun(3, func() { numWeighter.AppendNextString(buf, s) }) + nNumeric := testtext.AllocsPerRun(3, func() { w.AppendNextString(buf, s) }) + if n := nNumeric - nNormal; n > 0 { + t.Errorf("got %f; want 0", n) + } +} diff --git a/vendor/golang.org/x/text/internal/colltab/trie_test.go b/vendor/golang.org/x/text/internal/colltab/trie_test.go new file mode 100644 index 000000000..b056a811e --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/trie_test.go @@ -0,0 +1,106 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab + +import ( + "testing" +) + +// We take the smallest, largest and an arbitrary value for each +// of the UTF-8 sequence lengths. +var testRunes = []rune{ + 0x01, 0x0C, 0x7F, // 1-byte sequences + 0x80, 0x100, 0x7FF, // 2-byte sequences + 0x800, 0x999, 0xFFFF, // 3-byte sequences + 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences + 0x200, 0x201, 0x202, 0x210, 0x215, // five entries in one sparse block +} + +// Test cases for illegal runes. +type trietest struct { + size int + bytes []byte +} + +var tests = []trietest{ + // illegal runes + {1, []byte{0x80}}, + {1, []byte{0xFF}}, + {1, []byte{t2, tx - 1}}, + {1, []byte{t2, t2}}, + {2, []byte{t3, tx, tx - 1}}, + {2, []byte{t3, tx, t2}}, + {1, []byte{t3, tx - 1, tx}}, + {3, []byte{t4, tx, tx, tx - 1}}, + {3, []byte{t4, tx, tx, t2}}, + {1, []byte{t4, t2, tx, tx - 1}}, + {2, []byte{t4, tx, t2, tx - 1}}, + + // short runes + {0, []byte{t2}}, + {0, []byte{t3, tx}}, + {0, []byte{t4, tx, tx}}, + + // we only support UTF-8 up to utf8.UTFMax bytes (4 bytes) + {1, []byte{t5, tx, tx, tx, tx}}, + {1, []byte{t6, tx, tx, tx, tx, tx}}, +} + +func TestLookupTrie(t *testing.T) { + for i, r := range testRunes { + b := []byte(string(r)) + v, sz := testTrie.lookup(b) + if int(v) != i { + t.Errorf("lookup(%U): found value %#x, expected %#x", r, v, i) + } + if sz != len(b) { + t.Errorf("lookup(%U): found size %d, expected %d", r, sz, len(b)) + } + } + for i, tt := range tests { + v, sz := testTrie.lookup(tt.bytes) + if int(v) != 0 { + t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v) + } + if sz != tt.size { + t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size) + } + } +} + +// test data is taken from exp/collate/locale/build/trie_test.go +var testValues = [832]uint32{ + 0x000c: 0x00000001, + 0x007f: 0x00000002, + 0x00c0: 0x00000003, + 0x0100: 0x00000004, + 0x0140: 0x0000000c, 0x0141: 0x0000000d, 0x0142: 0x0000000e, + 0x0150: 0x0000000f, + 0x0155: 0x00000010, + 0x01bf: 0x00000005, + 0x01c0: 0x00000006, + 0x0219: 0x00000007, + 0x027f: 0x00000008, + 0x0280: 0x00000009, + 0x02c1: 0x0000000a, + 0x033f: 0x0000000b, +} + +var testLookup = [640]uint16{ + 0x0e0: 0x05, 0x0e6: 0x06, + 0x13f: 0x07, + 0x140: 0x08, 0x144: 0x09, + 0x190: 0x03, + 0x1ff: 0x0a, + 0x20f: 0x05, + 0x242: 0x01, 0x244: 0x02, + 0x248: 0x03, + 0x25f: 0x04, + 0x260: 0x01, + 0x26f: 0x02, + 0x270: 0x04, 0x274: 0x06, +} + +var testTrie = Trie{testLookup[6*blockSize:], testValues[:], testLookup[:], testValues[:]} diff --git a/vendor/golang.org/x/text/internal/colltab/weighter_test.go b/vendor/golang.org/x/text/internal/colltab/weighter_test.go new file mode 100644 index 000000000..b5f8487b3 --- /dev/null +++ b/vendor/golang.org/x/text/internal/colltab/weighter_test.go @@ -0,0 +1,42 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package colltab + +// testWeighter is a simple Weighter that returns weights from a user-defined map. +type testWeighter map[string][]Elem + +func (t testWeighter) Start(int, []byte) int { return 0 } +func (t testWeighter) StartString(int, string) int { return 0 } +func (t testWeighter) Domain() []string { return nil } +func (t testWeighter) Top() uint32 { return 0 } + +// maxContractBytes is the maximum length of any key in the map. +const maxContractBytes = 10 + +func (t testWeighter) AppendNext(buf []Elem, s []byte) ([]Elem, int) { + n := len(s) + if n > maxContractBytes { + n = maxContractBytes + } + for i := n; i > 0; i-- { + if e, ok := t[string(s[:i])]; ok { + return append(buf, e...), i + } + } + panic("incomplete testWeighter: could not find " + string(s)) +} + +func (t testWeighter) AppendNextString(buf []Elem, s string) ([]Elem, int) { + n := len(s) + if n > maxContractBytes { + n = maxContractBytes + } + for i := n; i > 0; i-- { + if e, ok := t[s[:i]]; ok { + return append(buf, e...), i + } + } + panic("incomplete testWeighter: could not find " + s) +} diff --git a/vendor/golang.org/x/text/internal/gen.go b/vendor/golang.org/x/text/internal/gen.go new file mode 100644 index 000000000..1d678af57 --- /dev/null +++ b/vendor/golang.org/x/text/internal/gen.go @@ -0,0 +1,52 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "log" + + "golang.org/x/text/internal/gen" + "golang.org/x/text/language" + "golang.org/x/text/unicode/cldr" +) + +func main() { + r := gen.OpenCLDRCoreZip() + defer r.Close() + + d := &cldr.Decoder{} + data, err := d.DecodeZip(r) + if err != nil { + log.Fatalf("DecodeZip: %v", err) + } + + w := gen.NewCodeWriter() + defer w.WriteGoFile("tables.go", "internal") + + // Create parents table. + parents := make([]uint16, language.NumCompactTags) + for _, loc := range data.Locales() { + tag := language.MustParse(loc) + index, ok := language.CompactIndex(tag) + if !ok { + continue + } + parentIndex := 0 // und + for p := tag.Parent(); p != language.Und; p = p.Parent() { + if x, ok := language.CompactIndex(p); ok { + parentIndex = x + break + } + } + parents[index] = uint16(parentIndex) + } + + w.WriteComment(` + Parent maps a compact index of a tag to the compact index of the parent of + this tag.`) + w.WriteVar("Parent", parents) +} diff --git a/vendor/golang.org/x/text/internal/gen_test.go b/vendor/golang.org/x/text/internal/gen_test.go new file mode 100644 index 000000000..a2e1981ae --- /dev/null +++ b/vendor/golang.org/x/text/internal/gen_test.go @@ -0,0 +1,38 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +import ( + "testing" + + "golang.org/x/text/language" +) + +func TestParents(t *testing.T) { + testCases := []struct { + tag, parent string + }{ + {"af", "und"}, + {"en", "und"}, + {"en-001", "en"}, + {"en-AU", "en-001"}, + {"en-US", "en"}, + {"en-US-u-va-posix", "en-US"}, + {"ca-ES-valencia", "ca-ES"}, + } + for _, tc := range testCases { + tag, ok := language.CompactIndex(language.MustParse(tc.tag)) + if !ok { + t.Fatalf("Could not get index of flag %s", tc.tag) + } + want, ok := language.CompactIndex(language.MustParse(tc.parent)) + if !ok { + t.Fatalf("Could not get index of parent %s of tag %s", tc.parent, tc.tag) + } + if got := int(Parent[tag]); got != want { + t.Errorf("Parent[%s] = %d; want %d (%s)", tc.tag, got, want, tc.parent) + } + } +} diff --git a/vendor/golang.org/x/text/internal/internal.go b/vendor/golang.org/x/text/internal/internal.go new file mode 100644 index 000000000..eac832850 --- /dev/null +++ b/vendor/golang.org/x/text/internal/internal.go @@ -0,0 +1,51 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run gen.go + +// Package internal contains non-exported functionality that are used by +// packages in the text repository. +package internal // import "golang.org/x/text/internal" + +import ( + "sort" + + "golang.org/x/text/language" +) + +// SortTags sorts tags in place. +func SortTags(tags []language.Tag) { + sort.Sort(sorter(tags)) +} + +type sorter []language.Tag + +func (s sorter) Len() int { + return len(s) +} + +func (s sorter) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s sorter) Less(i, j int) bool { + return s[i].String() < s[j].String() +} + +// UniqueTags sorts and filters duplicate tags in place and returns a slice with +// only unique tags. +func UniqueTags(tags []language.Tag) []language.Tag { + if len(tags) <= 1 { + return tags + } + SortTags(tags) + k := 0 + for i := 1; i < len(tags); i++ { + if tags[k].String() < tags[i].String() { + k++ + tags[k] = tags[i] + } + } + return tags[:k+1] +} diff --git a/vendor/golang.org/x/text/internal/internal_test.go b/vendor/golang.org/x/text/internal/internal_test.go new file mode 100644 index 000000000..ce1b9a382 --- /dev/null +++ b/vendor/golang.org/x/text/internal/internal_test.go @@ -0,0 +1,38 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +import ( + "fmt" + "strings" + "testing" + + "golang.org/x/text/language" +) + +func TestUnique(t *testing.T) { + testCases := []struct { + in, want string + }{ + {"", "[]"}, + {"en", "[en]"}, + {"en en", "[en]"}, + {"en en en", "[en]"}, + {"en-u-cu-eur en", "[en en-u-cu-eur]"}, + {"nl en", "[en nl]"}, + {"pt-Pt pt", "[pt pt-PT]"}, + } + for _, tc := range testCases { + tags := []language.Tag{} + for _, s := range strings.Split(tc.in, " ") { + if s != "" { + tags = append(tags, language.MustParse(s)) + } + } + if got := fmt.Sprint(UniqueTags(tags)); got != tc.want { + t.Errorf("Unique(%s) = %s; want %s", tc.in, got, tc.want) + } + } +} diff --git a/vendor/golang.org/x/text/internal/match.go b/vendor/golang.org/x/text/internal/match.go new file mode 100644 index 000000000..a67fcaca1 --- /dev/null +++ b/vendor/golang.org/x/text/internal/match.go @@ -0,0 +1,67 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +// This file contains matchers that implement CLDR inheritance. +// +// See http://unicode.org/reports/tr35/#Locale_Inheritance. +// +// Some of the inheritance described in this document is already handled by +// the cldr package. + +import ( + "golang.org/x/text/language" +) + +// TODO: consider if (some of the) matching algorithm needs to be public after +// getting some feel about what is generic and what is specific. + +// NewInheritanceMatcher returns a matcher that matches based on the inheritance +// chain. +// +// The matcher uses canonicalization and the parent relationship to find a +// match. The resulting match will always be either Und or a language with the +// same language and script as the requested language. It will not match +// languages for which there is understood to be mutual or one-directional +// intelligibility. +// +// A Match will indicate an Exact match if the language matches after +// canonicalization and High if the matched tag is a parent. +func NewInheritanceMatcher(t []language.Tag) *InheritanceMatcher { + tags := &InheritanceMatcher{make(map[language.Tag]int)} + for i, tag := range t { + ct, err := language.All.Canonicalize(tag) + if err != nil { + ct = tag + } + tags.index[ct] = i + } + return tags +} + +type InheritanceMatcher struct { + index map[language.Tag]int +} + +func (m InheritanceMatcher) Match(want ...language.Tag) (language.Tag, int, language.Confidence) { + for _, t := range want { + ct, err := language.All.Canonicalize(t) + if err != nil { + ct = t + } + conf := language.Exact + for { + if index, ok := m.index[ct]; ok { + return ct, index, conf + } + if ct == language.Und { + break + } + ct = ct.Parent() + conf = language.High + } + } + return language.Und, 0, language.No +} diff --git a/vendor/golang.org/x/text/internal/match_test.go b/vendor/golang.org/x/text/internal/match_test.go new file mode 100644 index 000000000..8a3fe6572 --- /dev/null +++ b/vendor/golang.org/x/text/internal/match_test.go @@ -0,0 +1,56 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +import ( + "strings" + "testing" + + "golang.org/x/text/language" +) + +func TestInheritanceMatcher(t *testing.T) { + for i, tt := range []struct { + haveTags string + wantTags string + match string + conf language.Confidence + }{ + {"und,en,en-US", "en-US", "en-US", language.Exact}, // most specific match + {"zh-Hant,zh", "zh-TW", "zh-Hant", language.High}, // zh-TW implies Hant. + {"und,zh", "zh-TW", "und", language.High}, // zh-TW does not match zh. + {"zh", "zh-TW", "und", language.No}, // zh-TW does not match zh. + {"iw,en,nl", "he", "he", language.Exact}, // matches after canonicalization + {"he,en,nl", "iw", "he", language.Exact}, // matches after canonicalization + // Prefer first match over more specific match for various reasons: + // a) consistency of user interface is more important than an exact match, + // b) _if_ und is specified, it should be considered a correct and useful match, + // Note that a call to this Match will almost always be with a single tag. + {"und,en,en-US", "he,en-US", "und", language.High}, + } { + have := parseTags(tt.haveTags) + m := NewInheritanceMatcher(have) + tag, index, conf := m.Match(parseTags(tt.wantTags)...) + want := language.Raw.Make(tt.match) + if tag != want { + t.Errorf("%d:tag: got %q; want %q", i, tag, want) + } + if conf != language.No { + if got, _ := language.All.Canonicalize(have[index]); got != want { + t.Errorf("%d:index: got %q; want %q ", i, got, want) + } + } + if conf != tt.conf { + t.Errorf("%d:conf: got %v; want %v", i, conf, tt.conf) + } + } +} + +func parseTags(list string) (out []language.Tag) { + for _, s := range strings.Split(list, ",") { + out = append(out, language.Raw.Make(strings.TrimSpace(s))) + } + return out +} diff --git a/vendor/golang.org/x/text/internal/tables.go b/vendor/golang.org/x/text/internal/tables.go new file mode 100644 index 000000000..85991d3d2 --- /dev/null +++ b/vendor/golang.org/x/text/internal/tables.go @@ -0,0 +1,118 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package internal + +// Parent maps a compact index of a tag to the compact index of the parent of +// this tag. +var Parent = []uint16{ // 768 elements + // Entry 0 - 3F + 0x0000, 0x0053, 0x00e8, 0x0000, 0x0003, 0x0003, 0x0000, 0x0006, + 0x0000, 0x0008, 0x0000, 0x000a, 0x0000, 0x000c, 0x000c, 0x000c, + 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, + 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, + 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, + 0x000c, 0x0000, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x002e, + 0x0000, 0x0000, 0x0031, 0x0030, 0x0030, 0x0000, 0x0035, 0x0000, + 0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x003d, 0x0000, + // Entry 40 - 7F + 0x0000, 0x0040, 0x0000, 0x0042, 0x0042, 0x0000, 0x0045, 0x0045, + 0x0000, 0x0048, 0x0000, 0x004a, 0x0000, 0x0000, 0x004d, 0x004c, + 0x004c, 0x0000, 0x0051, 0x0051, 0x0051, 0x0051, 0x0000, 0x0056, + 0x0056, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x0000, + 0x005f, 0x005f, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066, + 0x0000, 0x0068, 0x0068, 0x0000, 0x006b, 0x0000, 0x006d, 0x006d, + 0x006d, 0x006d, 0x006d, 0x006d, 0x006d, 0x0000, 0x0075, 0x0000, + 0x0077, 0x0000, 0x0079, 0x0000, 0x0000, 0x007c, 0x0000, 0x007e, + // Entry 80 - BF + 0x0000, 0x0080, 0x0000, 0x0082, 0x0082, 0x0000, 0x0085, 0x0085, + 0x0000, 0x0088, 0x0089, 0x0089, 0x0089, 0x0088, 0x008a, 0x0089, + 0x0089, 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089, 0x008a, 0x0089, + 0x008a, 0x0089, 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088, + // Entry C0 - FF + 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, + 0x008a, 0x0089, 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088, + 0x0088, 0x0089, 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, + 0x0089, 0x0000, 0x00f1, 0x0000, 0x00f3, 0x00f4, 0x00f4, 0x00f4, + 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f4, + // Entry 100 - 13F + 0x00f3, 0x00f3, 0x00f4, 0x00f4, 0x00f3, 0x00f4, 0x00f4, 0x00f4, + 0x00f4, 0x00f3, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, + 0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0000, 0x0116, + 0x0116, 0x0000, 0x0119, 0x0119, 0x0119, 0x0119, 0x0000, 0x011e, + 0x0000, 0x0120, 0x0000, 0x0122, 0x0122, 0x0000, 0x0125, 0x0125, + 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, + 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, + 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, + // Entry 140 - 17F + 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, + 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, + 0x0125, 0x0125, 0x0125, 0x0125, 0x0000, 0x0154, 0x0000, 0x0156, + 0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x0000, 0x015e, + 0x015e, 0x015e, 0x0000, 0x0162, 0x0000, 0x0000, 0x0165, 0x0000, + 0x0167, 0x0000, 0x0169, 0x0169, 0x0169, 0x0000, 0x016d, 0x0000, + 0x016f, 0x0000, 0x0171, 0x0000, 0x0173, 0x0173, 0x0000, 0x0176, + 0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e, + // Entry 180 - 1BF + 0x0000, 0x0180, 0x0000, 0x0000, 0x0183, 0x0000, 0x0185, 0x0185, + 0x0185, 0x0185, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e, + 0x0000, 0x0190, 0x0000, 0x0000, 0x0193, 0x0000, 0x0195, 0x0000, + 0x0000, 0x0198, 0x0000, 0x0000, 0x019b, 0x0000, 0x019d, 0x0000, + 0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000, + 0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000, + 0x01af, 0x01af, 0x0000, 0x01b2, 0x0000, 0x01b4, 0x0000, 0x01b6, + 0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x0000, 0x01bd, 0x0000, + // Entry 1C0 - 1FF + 0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000, + 0x01c7, 0x0000, 0x01c9, 0x01c9, 0x01c9, 0x01c9, 0x0000, 0x01ce, + 0x0000, 0x01d0, 0x01d0, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000, + 0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x01dd, + 0x0000, 0x01e0, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6, + 0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee, + 0x0000, 0x01f0, 0x0000, 0x01f2, 0x01f2, 0x01f2, 0x0000, 0x01f6, + 0x0000, 0x01f8, 0x0000, 0x01fa, 0x0000, 0x01fc, 0x0000, 0x0000, + // Entry 200 - 23F + 0x01ff, 0x0000, 0x0201, 0x0201, 0x0000, 0x0204, 0x0000, 0x0206, + 0x0206, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x020c, + 0x020c, 0x020c, 0x020c, 0x020c, 0x0000, 0x0214, 0x0000, 0x0216, + 0x0000, 0x0218, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x021e, + 0x0000, 0x0000, 0x0221, 0x0000, 0x0223, 0x0223, 0x0000, 0x0226, + 0x0000, 0x0228, 0x0228, 0x0000, 0x0000, 0x022c, 0x022b, 0x022b, + 0x0000, 0x0000, 0x0231, 0x0000, 0x0233, 0x0000, 0x0235, 0x0000, + 0x0241, 0x0237, 0x0241, 0x0241, 0x0241, 0x0241, 0x0241, 0x0241, + // Entry 240 - 27F + 0x0241, 0x0237, 0x0241, 0x0241, 0x0000, 0x0244, 0x0244, 0x0244, + 0x0000, 0x0248, 0x0000, 0x024a, 0x0000, 0x024c, 0x024c, 0x0000, + 0x024f, 0x0000, 0x0251, 0x0251, 0x0251, 0x0251, 0x0251, 0x0251, + 0x0000, 0x0258, 0x0000, 0x025a, 0x0000, 0x025c, 0x0000, 0x025e, + 0x0000, 0x0260, 0x0000, 0x0262, 0x0000, 0x0000, 0x0265, 0x0265, + 0x0265, 0x0000, 0x0269, 0x0000, 0x026b, 0x0000, 0x026d, 0x0000, + 0x0000, 0x0270, 0x026f, 0x026f, 0x0000, 0x0274, 0x0000, 0x0276, + 0x0000, 0x0278, 0x0000, 0x0000, 0x0000, 0x0000, 0x027d, 0x0000, + // Entry 280 - 2BF + 0x0000, 0x0280, 0x0000, 0x0282, 0x0282, 0x0282, 0x0282, 0x0000, + 0x0287, 0x0287, 0x0287, 0x0000, 0x028b, 0x028b, 0x028b, 0x028b, + 0x028b, 0x0000, 0x0291, 0x0291, 0x0291, 0x0291, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0299, 0x0299, 0x0299, 0x0000, 0x029d, 0x029d, + 0x029d, 0x029d, 0x0000, 0x0000, 0x02a3, 0x02a3, 0x02a3, 0x02a3, + 0x0000, 0x02a8, 0x0000, 0x02aa, 0x02aa, 0x0000, 0x02ad, 0x0000, + 0x02af, 0x0000, 0x02b1, 0x02b1, 0x0000, 0x0000, 0x02b5, 0x0000, + 0x0000, 0x02b8, 0x0000, 0x02ba, 0x02ba, 0x0000, 0x0000, 0x02be, + // Entry 2C0 - 2FF + 0x0000, 0x02c0, 0x0000, 0x02c2, 0x0000, 0x02c4, 0x0000, 0x02c6, + 0x0000, 0x02c8, 0x02c8, 0x0000, 0x0000, 0x02cc, 0x0000, 0x02ce, + 0x02cb, 0x02cb, 0x0000, 0x0000, 0x02d3, 0x02d2, 0x02d2, 0x0000, + 0x0000, 0x02d8, 0x0000, 0x02da, 0x0000, 0x02dc, 0x0000, 0x0000, + 0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6, + 0x0000, 0x02e8, 0x0000, 0x02ea, 0x02ea, 0x0000, 0x0000, 0x02ee, + 0x02ed, 0x02ed, 0x0000, 0x02f2, 0x0000, 0x02f4, 0x02f4, 0x02f4, + 0x02f4, 0x02f4, 0x0000, 0x02fa, 0x02fb, 0x02fa, 0x0000, 0x02fe, +} // Size: 1560 bytes + +// Total table size 1560 bytes (1KiB); checksum: 4897681C diff --git a/vendor/golang.org/x/text/internal/tag/tag_test.go b/vendor/golang.org/x/text/internal/tag/tag_test.go new file mode 100644 index 000000000..da174a24c --- /dev/null +++ b/vendor/golang.org/x/text/internal/tag/tag_test.go @@ -0,0 +1,67 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tag + +import ( + "strings" + "testing" +) + +var strdata = []string{ + "aa ", + "aaa ", + "aaaa", + "aaab", + "aab ", + "ab ", + "ba ", + "xxxx", + "\xff\xff\xff\xff", +} + +var testCases = map[string]int{ + "a": 0, + "aa": 0, + "aaa": 1, + "aa ": 0, + "aaaa": 2, + "aaab": 3, + "b": 6, + "ba": 6, + " ": -1, + "aaax": -1, + "bbbb": -1, + "zzzz": -1, +} + +func TestIndex(t *testing.T) { + index := Index(strings.Join(strdata, "")) + for k, v := range testCases { + if i := index.Index([]byte(k)); i != v { + t.Errorf("%s: got %d; want %d", k, i, v) + } + } +} + +func TestFixCase(t *testing.T) { + tests := []string{ + "aaaa", "AbCD", "abcd", + "Zzzz", "AbCD", "Abcd", + "Zzzz", "AbC", "", + "XXX", "ab ", "", + "XXX", "usd", "USD", + "cmn", "AB ", "", + "gsw", "CMN", "cmn", + } + for tc := tests; len(tc) > 0; tc = tc[3:] { + b := []byte(tc[1]) + if !FixCase(tc[0], b) { + b = nil + } + if string(b) != tc[2] { + t.Errorf("FixCase(%q, %q) = %q; want %q", tc[0], tc[1], b, tc[2]) + } + } +} diff --git a/vendor/golang.org/x/text/internal/triegen/data_test.go b/vendor/golang.org/x/text/internal/triegen/data_test.go new file mode 100644 index 000000000..91de547a5 --- /dev/null +++ b/vendor/golang.org/x/text/internal/triegen/data_test.go @@ -0,0 +1,875 @@ +// This file is generated with "go test -tags generate". DO NOT EDIT! +// +build !generate + +package triegen_test + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *randTrie) lookup(s []byte) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return randValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := randIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := randIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = randIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := randIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = randIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = randIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *randTrie) lookupUnsafe(s []byte) uint8 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return randValues[c0] + } + i := randIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = randIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = randIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *randTrie) lookupString(s string) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return randValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := randIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := randIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = randIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := randIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = randIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = randIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *randTrie) lookupStringUnsafe(s string) uint8 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return randValues[c0] + } + i := randIndex[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = randIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = randIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// randTrie. Total size: 9280 bytes (9.06 KiB). Checksum: 6debd324a8debb8f. +type randTrie struct{} + +func newRandTrie(i int) *randTrie { + return &randTrie{} +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *randTrie) lookupValue(n uint32, b byte) uint8 { + switch { + default: + return uint8(randValues[n<<6+uint32(b)]) + } +} + +// randValues: 56 blocks, 3584 entries, 3584 bytes +// The third block is the zero block. +var randValues = [3584]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc9: 0x0001, + // Block 0x4, offset 0x100 + 0x100: 0x0001, + // Block 0x5, offset 0x140 + 0x155: 0x0001, + // Block 0x6, offset 0x180 + 0x196: 0x0001, + // Block 0x7, offset 0x1c0 + 0x1ef: 0x0001, + // Block 0x8, offset 0x200 + 0x206: 0x0001, + // Block 0x9, offset 0x240 + 0x258: 0x0001, + // Block 0xa, offset 0x280 + 0x288: 0x0001, + // Block 0xb, offset 0x2c0 + 0x2f2: 0x0001, + // Block 0xc, offset 0x300 + 0x304: 0x0001, + // Block 0xd, offset 0x340 + 0x34b: 0x0001, + // Block 0xe, offset 0x380 + 0x3ba: 0x0001, + // Block 0xf, offset 0x3c0 + 0x3f5: 0x0001, + // Block 0x10, offset 0x400 + 0x41d: 0x0001, + // Block 0x11, offset 0x440 + 0x442: 0x0001, + // Block 0x12, offset 0x480 + 0x4bb: 0x0001, + // Block 0x13, offset 0x4c0 + 0x4e9: 0x0001, + // Block 0x14, offset 0x500 + 0x53e: 0x0001, + // Block 0x15, offset 0x540 + 0x55f: 0x0001, + // Block 0x16, offset 0x580 + 0x5b7: 0x0001, + // Block 0x17, offset 0x5c0 + 0x5d9: 0x0001, + // Block 0x18, offset 0x600 + 0x60e: 0x0001, + // Block 0x19, offset 0x640 + 0x652: 0x0001, + // Block 0x1a, offset 0x680 + 0x68f: 0x0001, + // Block 0x1b, offset 0x6c0 + 0x6dc: 0x0001, + // Block 0x1c, offset 0x700 + 0x703: 0x0001, + // Block 0x1d, offset 0x740 + 0x741: 0x0001, + // Block 0x1e, offset 0x780 + 0x79b: 0x0001, + // Block 0x1f, offset 0x7c0 + 0x7f1: 0x0001, + // Block 0x20, offset 0x800 + 0x833: 0x0001, + // Block 0x21, offset 0x840 + 0x853: 0x0001, + // Block 0x22, offset 0x880 + 0x8a2: 0x0001, + // Block 0x23, offset 0x8c0 + 0x8f8: 0x0001, + // Block 0x24, offset 0x900 + 0x917: 0x0001, + // Block 0x25, offset 0x940 + 0x945: 0x0001, + // Block 0x26, offset 0x980 + 0x99e: 0x0001, + // Block 0x27, offset 0x9c0 + 0x9fd: 0x0001, + // Block 0x28, offset 0xa00 + 0xa0d: 0x0001, + // Block 0x29, offset 0xa40 + 0xa66: 0x0001, + // Block 0x2a, offset 0xa80 + 0xaab: 0x0001, + // Block 0x2b, offset 0xac0 + 0xaea: 0x0001, + // Block 0x2c, offset 0xb00 + 0xb2d: 0x0001, + // Block 0x2d, offset 0xb40 + 0xb54: 0x0001, + // Block 0x2e, offset 0xb80 + 0xb90: 0x0001, + // Block 0x2f, offset 0xbc0 + 0xbe5: 0x0001, + // Block 0x30, offset 0xc00 + 0xc28: 0x0001, + // Block 0x31, offset 0xc40 + 0xc7c: 0x0001, + // Block 0x32, offset 0xc80 + 0xcbf: 0x0001, + // Block 0x33, offset 0xcc0 + 0xcc7: 0x0001, + // Block 0x34, offset 0xd00 + 0xd34: 0x0001, + // Block 0x35, offset 0xd40 + 0xd61: 0x0001, + // Block 0x36, offset 0xd80 + 0xdb9: 0x0001, + // Block 0x37, offset 0xdc0 + 0xdda: 0x0001, +} + +// randIndex: 89 blocks, 5696 entries, 5696 bytes +// Block 0 is the zero block. +var randIndex = [5696]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xe1: 0x02, 0xe3: 0x03, 0xe4: 0x04, + 0xea: 0x05, 0xeb: 0x06, 0xec: 0x07, + 0xf0: 0x10, 0xf1: 0x24, 0xf2: 0x3d, 0xf3: 0x4f, 0xf4: 0x56, + // Block 0x4, offset 0x100 + 0x107: 0x01, + // Block 0x5, offset 0x140 + 0x16c: 0x02, + // Block 0x6, offset 0x180 + 0x19c: 0x03, + 0x1ae: 0x04, + // Block 0x7, offset 0x1c0 + 0x1d8: 0x05, + 0x1f7: 0x06, + // Block 0x8, offset 0x200 + 0x20c: 0x07, + // Block 0x9, offset 0x240 + 0x24a: 0x08, + // Block 0xa, offset 0x280 + 0x2b6: 0x09, + // Block 0xb, offset 0x2c0 + 0x2d5: 0x0a, + // Block 0xc, offset 0x300 + 0x31a: 0x0b, + // Block 0xd, offset 0x340 + 0x373: 0x0c, + // Block 0xe, offset 0x380 + 0x38b: 0x0d, + // Block 0xf, offset 0x3c0 + 0x3f0: 0x0e, + // Block 0x10, offset 0x400 + 0x433: 0x0f, + // Block 0x11, offset 0x440 + 0x45d: 0x10, + // Block 0x12, offset 0x480 + 0x491: 0x08, 0x494: 0x09, 0x497: 0x0a, + 0x49b: 0x0b, 0x49c: 0x0c, + 0x4a1: 0x0d, + 0x4ad: 0x0e, + 0x4ba: 0x0f, + // Block 0x13, offset 0x4c0 + 0x4c1: 0x11, + // Block 0x14, offset 0x500 + 0x531: 0x12, + // Block 0x15, offset 0x540 + 0x546: 0x13, + // Block 0x16, offset 0x580 + 0x5ab: 0x14, + // Block 0x17, offset 0x5c0 + 0x5d4: 0x11, + 0x5fe: 0x11, + // Block 0x18, offset 0x600 + 0x618: 0x0a, + // Block 0x19, offset 0x640 + 0x65b: 0x15, + // Block 0x1a, offset 0x680 + 0x6a0: 0x16, + // Block 0x1b, offset 0x6c0 + 0x6d2: 0x17, + 0x6f6: 0x18, + // Block 0x1c, offset 0x700 + 0x711: 0x19, + // Block 0x1d, offset 0x740 + 0x768: 0x1a, + // Block 0x1e, offset 0x780 + 0x783: 0x1b, + // Block 0x1f, offset 0x7c0 + 0x7f9: 0x1c, + // Block 0x20, offset 0x800 + 0x831: 0x1d, + // Block 0x21, offset 0x840 + 0x85e: 0x1e, + // Block 0x22, offset 0x880 + 0x898: 0x1f, + // Block 0x23, offset 0x8c0 + 0x8c7: 0x18, + 0x8d5: 0x14, + 0x8f7: 0x20, + 0x8fe: 0x1f, + // Block 0x24, offset 0x900 + 0x905: 0x21, + // Block 0x25, offset 0x940 + 0x966: 0x03, + // Block 0x26, offset 0x980 + 0x981: 0x07, 0x983: 0x11, + 0x989: 0x12, 0x98a: 0x13, 0x98e: 0x14, 0x98f: 0x15, + 0x992: 0x16, 0x995: 0x17, 0x996: 0x18, + 0x998: 0x19, 0x999: 0x1a, 0x99b: 0x1b, 0x99f: 0x1c, + 0x9a3: 0x1d, + 0x9ad: 0x1e, 0x9af: 0x1f, + 0x9b0: 0x20, 0x9b1: 0x21, + 0x9b8: 0x22, 0x9bd: 0x23, + // Block 0x27, offset 0x9c0 + 0x9cd: 0x22, + // Block 0x28, offset 0xa00 + 0xa0c: 0x08, + // Block 0x29, offset 0xa40 + 0xa6f: 0x1c, + // Block 0x2a, offset 0xa80 + 0xa90: 0x1a, + 0xaaf: 0x23, + // Block 0x2b, offset 0xac0 + 0xae3: 0x19, + 0xae8: 0x24, + 0xafc: 0x25, + // Block 0x2c, offset 0xb00 + 0xb13: 0x26, + // Block 0x2d, offset 0xb40 + 0xb67: 0x1c, + // Block 0x2e, offset 0xb80 + 0xb8f: 0x0b, + // Block 0x2f, offset 0xbc0 + 0xbcb: 0x27, + 0xbe7: 0x26, + // Block 0x30, offset 0xc00 + 0xc34: 0x16, + // Block 0x31, offset 0xc40 + 0xc62: 0x03, + // Block 0x32, offset 0xc80 + 0xcbb: 0x12, + // Block 0x33, offset 0xcc0 + 0xcdf: 0x09, + // Block 0x34, offset 0xd00 + 0xd34: 0x0a, + // Block 0x35, offset 0xd40 + 0xd41: 0x1e, + // Block 0x36, offset 0xd80 + 0xd83: 0x28, + // Block 0x37, offset 0xdc0 + 0xdc0: 0x15, + // Block 0x38, offset 0xe00 + 0xe1a: 0x15, + // Block 0x39, offset 0xe40 + 0xe65: 0x29, + // Block 0x3a, offset 0xe80 + 0xe86: 0x1f, + // Block 0x3b, offset 0xec0 + 0xeec: 0x18, + // Block 0x3c, offset 0xf00 + 0xf28: 0x2a, + // Block 0x3d, offset 0xf40 + 0xf53: 0x08, + // Block 0x3e, offset 0xf80 + 0xfa2: 0x2b, + 0xfaa: 0x17, + // Block 0x3f, offset 0xfc0 + 0xfc0: 0x25, 0xfc2: 0x26, + 0xfc9: 0x27, 0xfcd: 0x28, 0xfce: 0x29, + 0xfd5: 0x2a, + 0xfd8: 0x2b, 0xfd9: 0x2c, 0xfdf: 0x2d, + 0xfe1: 0x2e, 0xfe2: 0x2f, 0xfe3: 0x30, 0xfe6: 0x31, + 0xfe9: 0x32, 0xfec: 0x33, 0xfed: 0x34, 0xfef: 0x35, + 0xff1: 0x36, 0xff2: 0x37, 0xff3: 0x38, 0xff4: 0x39, + 0xffa: 0x3a, 0xffc: 0x3b, 0xffe: 0x3c, + // Block 0x40, offset 0x1000 + 0x102c: 0x2c, + // Block 0x41, offset 0x1040 + 0x1074: 0x2c, + // Block 0x42, offset 0x1080 + 0x108c: 0x08, + 0x10a0: 0x2d, + // Block 0x43, offset 0x10c0 + 0x10e8: 0x10, + // Block 0x44, offset 0x1100 + 0x110f: 0x13, + // Block 0x45, offset 0x1140 + 0x114b: 0x2e, + // Block 0x46, offset 0x1180 + 0x118b: 0x23, + 0x119d: 0x0c, + // Block 0x47, offset 0x11c0 + 0x11c3: 0x12, + 0x11f9: 0x0f, + // Block 0x48, offset 0x1200 + 0x121e: 0x1b, + // Block 0x49, offset 0x1240 + 0x1270: 0x2f, + // Block 0x4a, offset 0x1280 + 0x128a: 0x1b, + 0x12a7: 0x02, + // Block 0x4b, offset 0x12c0 + 0x12fb: 0x14, + // Block 0x4c, offset 0x1300 + 0x1333: 0x30, + // Block 0x4d, offset 0x1340 + 0x134d: 0x31, + // Block 0x4e, offset 0x1380 + 0x138e: 0x15, + // Block 0x4f, offset 0x13c0 + 0x13f4: 0x32, + // Block 0x50, offset 0x1400 + 0x141b: 0x33, + // Block 0x51, offset 0x1440 + 0x1448: 0x3e, 0x1449: 0x3f, 0x144a: 0x40, 0x144f: 0x41, + 0x1459: 0x42, 0x145c: 0x43, 0x145e: 0x44, 0x145f: 0x45, + 0x1468: 0x46, 0x1469: 0x47, 0x146c: 0x48, 0x146d: 0x49, 0x146e: 0x4a, + 0x1472: 0x4b, 0x1473: 0x4c, + 0x1479: 0x4d, 0x147b: 0x4e, + // Block 0x52, offset 0x1480 + 0x1480: 0x34, + 0x1499: 0x11, + 0x14b6: 0x2c, + // Block 0x53, offset 0x14c0 + 0x14e4: 0x0d, + // Block 0x54, offset 0x1500 + 0x1527: 0x08, + // Block 0x55, offset 0x1540 + 0x1555: 0x2b, + // Block 0x56, offset 0x1580 + 0x15b2: 0x35, + // Block 0x57, offset 0x15c0 + 0x15f2: 0x1c, 0x15f4: 0x29, + // Block 0x58, offset 0x1600 + 0x1600: 0x50, 0x1603: 0x51, + 0x1608: 0x52, 0x160a: 0x53, 0x160d: 0x54, 0x160e: 0x55, +} + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *multiTrie) lookup(s []byte) (v uint64, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return t.ascii[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := t.utf8Start[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := t.utf8Start[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = multiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := t.utf8Start[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = multiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = multiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *multiTrie) lookupUnsafe(s []byte) uint64 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return t.ascii[c0] + } + i := t.utf8Start[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = multiIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = multiIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *multiTrie) lookupString(s string) (v uint64, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return t.ascii[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := t.utf8Start[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := t.utf8Start[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = multiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := t.utf8Start[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = multiIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = multiIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return t.lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must start with a full and valid UTF-8 encoded rune. +func (t *multiTrie) lookupStringUnsafe(s string) uint64 { + c0 := s[0] + if c0 < 0x80 { // is ASCII + return t.ascii[c0] + } + i := t.utf8Start[c0] + if c0 < 0xE0 { // 2-byte UTF-8 + return t.lookupValue(uint32(i), s[1]) + } + i = multiIndex[uint32(i)<<6+uint32(s[1])] + if c0 < 0xF0 { // 3-byte UTF-8 + return t.lookupValue(uint32(i), s[2]) + } + i = multiIndex[uint32(i)<<6+uint32(s[2])] + if c0 < 0xF8 { // 4-byte UTF-8 + return t.lookupValue(uint32(i), s[3]) + } + return 0 +} + +// multiTrie. Total size: 18250 bytes (17.82 KiB). Checksum: a69a609d8696aa5e. +type multiTrie struct { + ascii []uint64 // index for ASCII bytes + utf8Start []uint8 // index for UTF-8 bytes >= 0xC0 +} + +func newMultiTrie(i int) *multiTrie { + h := multiTrieHandles[i] + return &multiTrie{multiValues[uint32(h.ascii)<<6:], multiIndex[uint32(h.multi)<<6:]} +} + +type multiTrieHandle struct { + ascii, multi uint8 +} + +// multiTrieHandles: 5 handles, 10 bytes +var multiTrieHandles = [5]multiTrieHandle{ + {0, 0}, // 8c1e77823143d35c: all + {0, 23}, // 8fb58ff8243b45b0: ASCII only + {0, 23}, // 8fb58ff8243b45b0: ASCII only 2 + {0, 24}, // 2ccc43994f11046f: BMP only + {30, 25}, // ce448591bdcb4733: No BMP +} + +// lookupValue determines the type of block n and looks up the value for b. +func (t *multiTrie) lookupValue(n uint32, b byte) uint64 { + switch { + default: + return uint64(multiValues[n<<6+uint32(b)]) + } +} + +// multiValues: 32 blocks, 2048 entries, 16384 bytes +// The third block is the zero block. +var multiValues = [2048]uint64{ + // Block 0x0, offset 0x0 + 0x03: 0x6e361699800b9fb8, 0x04: 0x52d3935a34f6f0b, 0x05: 0x2948319393e7ef10, + 0x07: 0x20f03b006704f663, 0x08: 0x6c15c0732bb2495f, 0x09: 0xe54e2c59d953551, + 0x0f: 0x33d8a825807d8037, 0x10: 0x6ecd93cb12168b92, 0x11: 0x6a81c9c0ce86e884, + 0x1f: 0xa03e77aac8be79b, 0x20: 0x28591d0e7e486efa, 0x21: 0x716fa3bc398dec8, + 0x3f: 0x4fd3bcfa72bce8b0, + // Block 0x1, offset 0x40 + 0x40: 0x3cbaef3db8ba5f12, 0x41: 0x2d262347c1f56357, + 0x7f: 0x782caa2d25a418a9, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x6bbd1f937b1ff5d2, 0xc1: 0x732e23088d2eb8a4, + // Block 0x4, offset 0x100 + 0x13f: 0x56f8c4c82f5962dc, + // Block 0x5, offset 0x140 + 0x140: 0x57dc4544729a5da2, 0x141: 0x2f62f9cd307ffa0d, + // Block 0x6, offset 0x180 + 0x1bf: 0x7bf4d0ebf302a088, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x1f0d67f249e59931, 0x1c1: 0x3011def73aa550c7, + // Block 0x8, offset 0x200 + 0x23f: 0x5de81c1dff6bf29d, + // Block 0x9, offset 0x240 + 0x240: 0x752c035737b825e8, 0x241: 0x1e793399081e3bb3, + // Block 0xa, offset 0x280 + 0x2bf: 0x6a28f01979cbf059, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x373a4b0f2cbd4c74, 0x2c1: 0x4fd2c288683b767c, + // Block 0xc, offset 0x300 + 0x33f: 0x5a10ffa9e29184fb, + // Block 0xd, offset 0x340 + 0x340: 0x700f9bdb53fff6a5, 0x341: 0xcde93df0427eb79, + // Block 0xe, offset 0x380 + 0x3bf: 0x74071288fff39c76, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x481fc2f510e5268a, 0x3c1: 0x7565c28164204849, + // Block 0x10, offset 0x400 + 0x43f: 0x5676a62fd49c6bec, + // Block 0x11, offset 0x440 + 0x440: 0x2f2d15776cbafc6b, 0x441: 0x4c55e8dc0ff11a3f, + // Block 0x12, offset 0x480 + 0x4bf: 0x69d6f0fe711fafc9, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x33181de28cfb062d, 0x4c1: 0x2ef3adc6bb2f2d02, + // Block 0x14, offset 0x500 + 0x53f: 0xe03b31814c95f8b, + // Block 0x15, offset 0x540 + 0x540: 0x3bf6dc9a1c115603, 0x541: 0x6984ec9b7f51f7fc, + // Block 0x16, offset 0x580 + 0x5bf: 0x3c02ea92fb168559, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x1badfe42e7629494, 0x5c1: 0x6dc4a554005f7645, + // Block 0x18, offset 0x600 + 0x63f: 0x3bb2ed2a72748f4b, + // Block 0x19, offset 0x640 + 0x640: 0x291354cd6767ec10, 0x641: 0x2c3a4715e3c070d6, + // Block 0x1a, offset 0x680 + 0x6bf: 0x352711cfb7236418, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x3a59d34fb8bceda, 0x6c1: 0x5e90d8ebedd64fa1, + // Block 0x1c, offset 0x700 + 0x73f: 0x7191a77b28d23110, + // Block 0x1d, offset 0x740 + 0x740: 0x4ca7f0c1623423d8, 0x741: 0x4f7156d996e2d0de, + // Block 0x1e, offset 0x780 + // Block 0x1f, offset 0x7c0 +} + +// multiIndex: 29 blocks, 1856 entries, 1856 bytes +// Block 0 is the zero block. +var multiIndex = [1856]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc7: 0x04, + 0xc8: 0x05, 0xcf: 0x06, + 0xd0: 0x07, + 0xdf: 0x08, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe7: 0x07, + 0xe8: 0x08, 0xef: 0x09, + 0xf0: 0x0e, 0xf1: 0x11, 0xf2: 0x13, 0xf3: 0x15, 0xf4: 0x17, + // Block 0x4, offset 0x100 + 0x120: 0x09, + 0x13f: 0x0a, + // Block 0x5, offset 0x140 + 0x140: 0x0b, + 0x17f: 0x0c, + // Block 0x6, offset 0x180 + 0x180: 0x0d, + // Block 0x7, offset 0x1c0 + 0x1ff: 0x0e, + // Block 0x8, offset 0x200 + 0x200: 0x0f, + // Block 0x9, offset 0x240 + 0x27f: 0x10, + // Block 0xa, offset 0x280 + 0x280: 0x11, + // Block 0xb, offset 0x2c0 + 0x2ff: 0x12, + // Block 0xc, offset 0x300 + 0x300: 0x13, + // Block 0xd, offset 0x340 + 0x37f: 0x14, + // Block 0xe, offset 0x380 + 0x380: 0x15, + // Block 0xf, offset 0x3c0 + 0x3ff: 0x16, + // Block 0x10, offset 0x400 + 0x410: 0x0a, + 0x41f: 0x0b, + 0x420: 0x0c, + 0x43f: 0x0d, + // Block 0x11, offset 0x440 + 0x440: 0x17, + // Block 0x12, offset 0x480 + 0x4bf: 0x18, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x0f, + 0x4ff: 0x10, + // Block 0x14, offset 0x500 + 0x500: 0x19, + // Block 0x15, offset 0x540 + 0x540: 0x12, + // Block 0x16, offset 0x580 + 0x5bf: 0x1a, + // Block 0x17, offset 0x5c0 + 0x5ff: 0x14, + // Block 0x18, offset 0x600 + 0x600: 0x1b, + // Block 0x19, offset 0x640 + 0x640: 0x16, + // Block 0x1a, offset 0x680 + // Block 0x1b, offset 0x6c0 + 0x6c2: 0x01, 0x6c3: 0x02, 0x6c4: 0x03, 0x6c7: 0x04, + 0x6c8: 0x05, 0x6cf: 0x06, + 0x6d0: 0x07, + 0x6df: 0x08, + 0x6e0: 0x02, 0x6e1: 0x03, 0x6e2: 0x04, 0x6e3: 0x05, 0x6e4: 0x06, 0x6e7: 0x07, + 0x6e8: 0x08, 0x6ef: 0x09, + // Block 0x1c, offset 0x700 + 0x730: 0x0e, 0x731: 0x11, 0x732: 0x13, 0x733: 0x15, 0x734: 0x17, +} diff --git a/vendor/golang.org/x/text/internal/triegen/example_compact_test.go b/vendor/golang.org/x/text/internal/triegen/example_compact_test.go new file mode 100644 index 000000000..7cf604ca4 --- /dev/null +++ b/vendor/golang.org/x/text/internal/triegen/example_compact_test.go @@ -0,0 +1,71 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package triegen_test + +import ( + "fmt" + "io" + "io/ioutil" + + "golang.org/x/text/internal/triegen" +) + +func ExampleCompacter() { + t := triegen.NewTrie("root") + for r := rune(0); r < 10000; r += 64 { + t.Insert(r, 0x9015BADA55^uint64(r)) + } + sz, _ := t.Gen(ioutil.Discard) + + fmt.Printf("Size normal: %5d\n", sz) + + var c myCompacter + sz, _ = t.Gen(ioutil.Discard, triegen.Compact(&c)) + + fmt.Printf("Size compacted: %5d\n", sz) + + // Output: + // Size normal: 81344 + // Size compacted: 3224 +} + +// A myCompacter accepts a block if only the first value is given. +type myCompacter []uint64 + +func (c *myCompacter) Size(values []uint64) (sz int, ok bool) { + for _, v := range values[1:] { + if v != 0 { + return 0, false + } + } + return 8, true // the size of a uint64 +} + +func (c *myCompacter) Store(v []uint64) uint32 { + x := uint32(len(*c)) + *c = append(*c, v[0]) + return x +} + +func (c *myCompacter) Print(w io.Writer) error { + fmt.Fprintln(w, "var firstValue = []uint64{") + for _, v := range *c { + fmt.Fprintf(w, "\t%#x,\n", v) + } + fmt.Fprintln(w, "}") + return nil +} + +func (c *myCompacter) Handler() string { + return "getFirstValue" + + // Where getFirstValue is included along with the generated code: + // func getFirstValue(n uint32, b byte) uint64 { + // if b == 0x80 { // the first continuation byte + // return firstValue[n] + // } + // return 0 + // } +} diff --git a/vendor/golang.org/x/text/internal/triegen/example_test.go b/vendor/golang.org/x/text/internal/triegen/example_test.go new file mode 100644 index 000000000..557a152e7 --- /dev/null +++ b/vendor/golang.org/x/text/internal/triegen/example_test.go @@ -0,0 +1,148 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package triegen_test + +import ( + "fmt" + "io/ioutil" + "math/rand" + "unicode" + + "golang.org/x/text/internal/triegen" +) + +const seed = 0x12345 + +var genWriter = ioutil.Discard + +func randomRunes() map[rune]uint8 { + rnd := rand.New(rand.NewSource(seed)) + m := map[rune]uint8{} + for len(m) < 100 { + // Only set our random rune if it is a valid Unicode code point. + if r := rune(rnd.Int31n(unicode.MaxRune + 1)); []rune(string(r))[0] == r { + m[r] = 1 + } + } + return m +} + +// Example_build shows how to build a simple trie. It assigns the value 1 to +// 100 random runes generated by randomRunes. +func Example_build() { + t := triegen.NewTrie("rand") + + for r, _ := range randomRunes() { + t.Insert(r, 1) + } + sz, err := t.Gen(genWriter) + + fmt.Printf("Trie size: %d bytes\n", sz) + fmt.Printf("Error: %v\n", err) + + // Output: + // Trie size: 9280 bytes + // Error: <nil> +} + +// Example_lookup demonstrates how to use the trie generated by Example_build. +func Example_lookup() { + trie := newRandTrie(0) + + // The same set of runes used by Example_build. + runes := randomRunes() + + // Verify the right value is returned for all runes. + for r := rune(0); r <= unicode.MaxRune; r++ { + // Note that the return type of lookup is uint8. + if v, _ := trie.lookupString(string(r)); v != runes[r] { + fmt.Println("FAILURE") + return + } + } + fmt.Println("SUCCESS") + + // Output: + // SUCCESS +} + +// runeValues generates some random values for a set of interesting runes. +func runeValues() map[rune]uint64 { + rnd := rand.New(rand.NewSource(seed)) + m := map[rune]uint64{} + for p := 4; p <= unicode.MaxRune; p <<= 1 { + for d := -1; d <= 1; d++ { + m[rune(p+d)] = uint64(rnd.Int63()) + } + } + return m +} + +// ExampleGen_build demonstrates the creation of multiple tries sharing common +// blocks. ExampleGen_lookup demonstrates how to use the generated tries. +func ExampleGen_build() { + var tries []*triegen.Trie + + rv := runeValues() + for _, c := range []struct { + include func(rune) bool + name string + }{ + {func(r rune) bool { return true }, "all"}, + {func(r rune) bool { return r < 0x80 }, "ASCII only"}, + {func(r rune) bool { return r < 0x80 }, "ASCII only 2"}, + {func(r rune) bool { return r <= 0xFFFF }, "BMP only"}, + {func(r rune) bool { return r > 0xFFFF }, "No BMP"}, + } { + t := triegen.NewTrie(c.name) + tries = append(tries, t) + + for r, v := range rv { + if c.include(r) { + t.Insert(r, v) + } + } + } + sz, err := triegen.Gen(genWriter, "multi", tries) + + fmt.Printf("Trie size: %d bytes\n", sz) + fmt.Printf("Error: %v\n", err) + + // Output: + // Trie size: 18250 bytes + // Error: <nil> +} + +// ExampleGen_lookup shows how to look up values in the trie generated by +// ExampleGen_build. +func ExampleGen_lookup() { + rv := runeValues() + for i, include := range []func(rune) bool{ + func(r rune) bool { return true }, // all + func(r rune) bool { return r < 0x80 }, // ASCII only + func(r rune) bool { return r < 0x80 }, // ASCII only 2 + func(r rune) bool { return r <= 0xFFFF }, // BMP only + func(r rune) bool { return r > 0xFFFF }, // No BMP + } { + t := newMultiTrie(i) + + for r := rune(0); r <= unicode.MaxRune; r++ { + x := uint64(0) + if include(r) { + x = rv[r] + } + // As we convert from a valid rune, we know it is safe to use + // lookupStringUnsafe. + if v := t.lookupStringUnsafe(string(r)); x != v { + fmt.Println("FAILURE") + return + } + } + } + fmt.Println("SUCCESS") + + // Output: + // SUCCESS +} diff --git a/vendor/golang.org/x/text/internal/triegen/gen_test.go b/vendor/golang.org/x/text/internal/triegen/gen_test.go new file mode 100644 index 000000000..831627d7a --- /dev/null +++ b/vendor/golang.org/x/text/internal/triegen/gen_test.go @@ -0,0 +1,68 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build generate + +package triegen_test + +// The code in this file generates captures and writes the tries generated in +// the examples to data_test.go. To invoke it, run: +// go test -tags=generate +// +// Making the generation code a "test" allows us to link in the necessary test +// code. + +import ( + "log" + "os" + "os/exec" +) + +func init() { + const tmpfile = "tmpout" + const dstfile = "data_test.go" + + f, err := os.Create(tmpfile) + if err != nil { + log.Fatalf("Could not create output file: %v", err) + } + defer os.Remove(tmpfile) + defer f.Close() + + // We exit before this function returns, regardless of success or failure, + // so there's no need to save (and later restore) the existing genWriter + // value. + genWriter = f + + f.Write([]byte(header)) + + Example_build() + ExampleGen_build() + + if err := exec.Command("gofmt", "-w", tmpfile).Run(); err != nil { + log.Fatal(err) + } + os.Remove(dstfile) + os.Rename(tmpfile, dstfile) + + os.Exit(0) +} + +const header = `// This file is generated with "go test -tags generate". DO NOT EDIT! +// +build !generate + +package triegen_test +` + +// Stubs for generated tries. These are needed as we exclude data_test.go if +// the generate flag is set. This will clearly make the tests fail, but that +// is okay. It allows us to bootstrap. + +type trie struct{} + +func (t *trie) lookupString(string) (uint8, int) { return 0, 1 } +func (t *trie) lookupStringUnsafe(string) uint64 { return 0 } + +func newRandTrie(i int) *trie { return &trie{} } +func newMultiTrie(i int) *trie { return &trie{} } diff --git a/vendor/golang.org/x/text/internal/ucd/example_test.go b/vendor/golang.org/x/text/internal/ucd/example_test.go new file mode 100644 index 000000000..338a50d1c --- /dev/null +++ b/vendor/golang.org/x/text/internal/ucd/example_test.go @@ -0,0 +1,81 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ucd_test + +import ( + "fmt" + "strings" + + "golang.org/x/text/internal/ucd" +) + +func Example() { + // Read rune-by-rune from UnicodeData. + var count int + p := ucd.New(strings.NewReader(unicodeData)) + for p.Next() { + count++ + if lower := p.Runes(ucd.SimpleLowercaseMapping); lower != nil { + fmt.Printf("lower(%U) -> %U\n", p.Rune(0), lower[0]) + } + } + if err := p.Err(); err != nil { + fmt.Println(err) + } + fmt.Println("Number of runes visited:", count) + + // Read raw ranges from Scripts. + p = ucd.New(strings.NewReader(scripts), ucd.KeepRanges) + for p.Next() { + start, end := p.Range(0) + fmt.Printf("%04X..%04X: %s\n", start, end, p.String(1)) + } + if err := p.Err(); err != nil { + fmt.Println(err) + } + + // Output: + // lower(U+00C0) -> U+00E0 + // lower(U+00C1) -> U+00E1 + // lower(U+00C2) -> U+00E2 + // lower(U+00C3) -> U+00E3 + // lower(U+00C4) -> U+00E4 + // Number of runes visited: 6594 + // 0000..001F: Common + // 0020..0020: Common + // 0021..0023: Common + // 0024..0024: Common +} + +// Excerpt from UnicodeData.txt +const unicodeData = ` +00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;; +00BA;MASCULINE ORDINAL INDICATOR;Lo;0;L;<super> 006F;;;;N;;;;; +00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;;;; +00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; +00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; +00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;; +00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;; +00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0; +00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; +00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2; +00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; +00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4; + +# A legacy rune range. +3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;; +4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;; +` + +// Excerpt from Scripts.txt +const scripts = ` +# Property: Script +# ================================================ + +0000..001F ; Common # Cc [32] <control-0000>..<control-001F> +0020 ; Common # Zs SPACE +0021..0023 ; Common # Po [3] EXCLAMATION MARK..NUMBER SIGN +0024 ; Common # Sc DOLLAR SIGN +` diff --git a/vendor/golang.org/x/text/internal/ucd/ucd_test.go b/vendor/golang.org/x/text/internal/ucd/ucd_test.go new file mode 100644 index 000000000..11a6542e4 --- /dev/null +++ b/vendor/golang.org/x/text/internal/ucd/ucd_test.go @@ -0,0 +1,105 @@ +package ucd + +import ( + "strings" + "testing" +) + +const file = ` +# Comments should be skipped +# rune; bool; uint; int; float; runes; # Y +0..0005; Y; 0; 2; -5.25 ; 0 1 2 3 4 5; +6..0007; Yes ; 6; 1; -4.25 ; 0006 0007; +8; T ; 8 ; 0 ;-3.25 ;;# T +9; True ;9 ; -1;-2.25 ; 0009; + +# more comments to be ignored +@Part0 + +A; N; 10 ; -2; -1.25; ;# N +B; No; 11 ; -3; -0.25; +C; False;12; -4; 0.75; +D; ;13;-5;1.75; + +@Part1 # Another part. +# We test part comments get removed by not commenting the the next line. +E..10FFFF; F; 14 ; -6; 2.75; +` + +var want = []struct { + start, end rune +}{ + {0x00, 0x05}, + {0x06, 0x07}, + {0x08, 0x08}, + {0x09, 0x09}, + {0x0A, 0x0A}, + {0x0B, 0x0B}, + {0x0C, 0x0C}, + {0x0D, 0x0D}, + {0x0E, 0x10FFFF}, +} + +func TestGetters(t *testing.T) { + parts := [][2]string{ + {"Part0", ""}, + {"Part1", "Another part."}, + } + handler := func(p *Parser) { + if len(parts) == 0 { + t.Error("Part handler invoked too many times.") + return + } + want := parts[0] + parts = parts[1:] + if got0, got1 := p.String(0), p.Comment(); got0 != want[0] || got1 != want[1] { + t.Errorf(`part: got %q, %q; want %q"`, got0, got1, want) + } + } + + p := New(strings.NewReader(file), KeepRanges, Part(handler)) + for i := 0; p.Next(); i++ { + start, end := p.Range(0) + w := want[i] + if start != w.start || end != w.end { + t.Fatalf("%d:Range(0); got %#x..%#x; want %#x..%#x", i, start, end, w.start, w.end) + } + if w.start == w.end && p.Rune(0) != w.start { + t.Errorf("%d:Range(0).start: got %U; want %U", i, p.Rune(0), w.start) + } + if got, want := p.Bool(1), w.start <= 9; got != want { + t.Errorf("%d:Bool(1): got %v; want %v", i, got, want) + } + if got := p.Rune(4); got != 0 || p.Err() == nil { + t.Errorf("%d:Rune(%q): got no error; want error", i, p.String(1)) + } + p.err = nil + if got := p.Uint(2); rune(got) != start { + t.Errorf("%d:Uint(2): got %v; want %v", i, got, start) + } + if got, want := p.Int(3), 2-i; got != want { + t.Errorf("%d:Int(3): got %v; want %v", i, got, want) + } + if got, want := p.Float(4), -5.25+float64(i); got != want { + t.Errorf("%d:Int(3): got %v; want %v", i, got, want) + } + if got := p.Runes(5); got == nil { + if p.String(5) != "" { + t.Errorf("%d:Runes(5): expected non-empty list", i) + } + } else { + if got[0] != start || got[len(got)-1] != end { + t.Errorf("%d:Runes(5): got %#x; want %#x..%#x", i, got, start, end) + } + } + if got := p.Comment(); got != "" && got != p.String(1) { + t.Errorf("%d:Comment(): got %v; want %v", i, got, p.String(1)) + } + } + if err := p.Err(); err != nil { + t.Errorf("Parser error: %v", err) + } + if len(parts) != 0 { + t.Errorf("expected %d more invocations of part handler", len(parts)) + } +} diff --git a/vendor/golang.org/x/text/language/Makefile b/vendor/golang.org/x/text/language/Makefile new file mode 100644 index 000000000..79f005784 --- /dev/null +++ b/vendor/golang.org/x/text/language/Makefile @@ -0,0 +1,16 @@ +# Copyright 2013 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +CLEANFILES+=maketables + +maketables: maketables.go + go build $^ + +tables: maketables + ./maketables > tables.go + gofmt -w -s tables.go + +# Build (but do not run) maketables during testing, +# just to make sure it still compiles. +testshort: maketables diff --git a/vendor/golang.org/x/text/language/coverage_test.go b/vendor/golang.org/x/text/language/coverage_test.go new file mode 100644 index 000000000..8e08e5ca4 --- /dev/null +++ b/vendor/golang.org/x/text/language/coverage_test.go @@ -0,0 +1,154 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language + +import ( + "fmt" + "reflect" + "testing" +) + +func TestSupported(t *testing.T) { + // To prove the results are correct for a type, we test that the number of + // results is identical to the number of results on record, that all results + // are distinct and that all results are valid. + tests := map[string]int{ + "BaseLanguages": numLanguages, + "Scripts": numScripts, + "Regions": numRegions, + "Tags": 0, + } + sup := reflect.ValueOf(Supported) + for name, num := range tests { + v := sup.MethodByName(name).Call(nil)[0] + if n := v.Len(); n != num { + t.Errorf("len(%s()) was %d; want %d", name, n, num) + } + dup := make(map[string]bool) + for i := 0; i < v.Len(); i++ { + x := v.Index(i).Interface() + // An invalid value will either cause a crash or result in a + // duplicate when passed to Sprint. + s := fmt.Sprint(x) + if dup[s] { + t.Errorf("%s: duplicate entry %q", name, s) + } + dup[s] = true + } + if len(dup) != v.Len() { + t.Errorf("%s: # unique entries was %d; want %d", name, len(dup), v.Len()) + } + } +} + +func TestNewCoverage(t *testing.T) { + bases := []Base{Base{0}, Base{3}, Base{7}} + scripts := []Script{Script{11}, Script{17}, Script{23}} + regions := []Region{Region{101}, Region{103}, Region{107}} + tags := []Tag{Make("pt"), Make("en"), Make("en-GB"), Make("en-US"), Make("pt-PT")} + fbases := func() []Base { return bases } + fscripts := func() []Script { return scripts } + fregions := func() []Region { return regions } + ftags := func() []Tag { return tags } + + tests := []struct { + desc string + list []interface{} + bases []Base + scripts []Script + regions []Region + tags []Tag + }{ + { + desc: "empty", + }, + { + desc: "bases", + list: []interface{}{bases}, + bases: bases, + }, + { + desc: "scripts", + list: []interface{}{scripts}, + scripts: scripts, + }, + { + desc: "regions", + list: []interface{}{regions}, + regions: regions, + }, + { + desc: "bases derives from tags", + list: []interface{}{tags}, + bases: []Base{Base{_en}, Base{_pt}}, + tags: tags, + }, + { + desc: "tags and bases", + list: []interface{}{tags, bases}, + bases: bases, + tags: tags, + }, + { + desc: "fully specified", + list: []interface{}{tags, bases, scripts, regions}, + bases: bases, + scripts: scripts, + regions: regions, + tags: tags, + }, + { + desc: "bases func", + list: []interface{}{fbases}, + bases: bases, + }, + { + desc: "scripts func", + list: []interface{}{fscripts}, + scripts: scripts, + }, + { + desc: "regions func", + list: []interface{}{fregions}, + regions: regions, + }, + { + desc: "tags func", + list: []interface{}{ftags}, + bases: []Base{Base{_en}, Base{_pt}}, + tags: tags, + }, + { + desc: "tags and bases", + list: []interface{}{ftags, fbases}, + bases: bases, + tags: tags, + }, + { + desc: "fully specified", + list: []interface{}{ftags, fbases, fscripts, fregions}, + bases: bases, + scripts: scripts, + regions: regions, + tags: tags, + }, + } + + for i, tt := range tests { + l := NewCoverage(tt.list...) + if a := l.BaseLanguages(); !reflect.DeepEqual(a, tt.bases) { + t.Errorf("%d:%s: BaseLanguages was %v; want %v", i, tt.desc, a, tt.bases) + } + if a := l.Scripts(); !reflect.DeepEqual(a, tt.scripts) { + t.Errorf("%d:%s: Scripts was %v; want %v", i, tt.desc, a, tt.scripts) + } + if a := l.Regions(); !reflect.DeepEqual(a, tt.regions) { + t.Errorf("%d:%s: Regions was %v; want %v", i, tt.desc, a, tt.regions) + } + if a := l.Tags(); !reflect.DeepEqual(a, tt.tags) { + t.Errorf("%d:%s: Tags was %v; want %v", i, tt.desc, a, tt.tags) + } + } +} diff --git a/vendor/golang.org/x/text/language/examples_test.go b/vendor/golang.org/x/text/language/examples_test.go new file mode 100644 index 000000000..d5e8176dc --- /dev/null +++ b/vendor/golang.org/x/text/language/examples_test.go @@ -0,0 +1,413 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language_test + +import ( + "fmt" + "net/http" + + "golang.org/x/text/language" +) + +func ExampleCanonType() { + p := func(id string) { + fmt.Printf("Default(%s) -> %s\n", id, language.Make(id)) + fmt.Printf("BCP47(%s) -> %s\n", id, language.BCP47.Make(id)) + fmt.Printf("Macro(%s) -> %s\n", id, language.Macro.Make(id)) + fmt.Printf("All(%s) -> %s\n", id, language.All.Make(id)) + } + p("en-Latn") + p("sh") + p("zh-cmn") + p("bjd") + p("iw-Latn-fonipa-u-cu-usd") + // Output: + // Default(en-Latn) -> en-Latn + // BCP47(en-Latn) -> en + // Macro(en-Latn) -> en-Latn + // All(en-Latn) -> en + // Default(sh) -> sr-Latn + // BCP47(sh) -> sh + // Macro(sh) -> sh + // All(sh) -> sr-Latn + // Default(zh-cmn) -> cmn + // BCP47(zh-cmn) -> cmn + // Macro(zh-cmn) -> zh + // All(zh-cmn) -> zh + // Default(bjd) -> drl + // BCP47(bjd) -> drl + // Macro(bjd) -> bjd + // All(bjd) -> drl + // Default(iw-Latn-fonipa-u-cu-usd) -> he-Latn-fonipa-u-cu-usd + // BCP47(iw-Latn-fonipa-u-cu-usd) -> he-Latn-fonipa-u-cu-usd + // Macro(iw-Latn-fonipa-u-cu-usd) -> iw-Latn-fonipa-u-cu-usd + // All(iw-Latn-fonipa-u-cu-usd) -> he-Latn-fonipa-u-cu-usd +} + +func ExampleTag_Base() { + fmt.Println(language.Make("und").Base()) + fmt.Println(language.Make("und-US").Base()) + fmt.Println(language.Make("und-NL").Base()) + fmt.Println(language.Make("und-419").Base()) // Latin America + fmt.Println(language.Make("und-ZZ").Base()) + // Output: + // en Low + // en High + // nl High + // es Low + // en Low +} + +func ExampleTag_Script() { + en := language.Make("en") + sr := language.Make("sr") + sr_Latn := language.Make("sr_Latn") + fmt.Println(en.Script()) + fmt.Println(sr.Script()) + // Was a script explicitly specified? + _, c := sr.Script() + fmt.Println(c == language.Exact) + _, c = sr_Latn.Script() + fmt.Println(c == language.Exact) + // Output: + // Latn High + // Cyrl Low + // false + // true +} + +func ExampleTag_Region() { + ru := language.Make("ru") + en := language.Make("en") + fmt.Println(ru.Region()) + fmt.Println(en.Region()) + // Output: + // RU Low + // US Low +} + +func ExampleRegion_TLD() { + us := language.MustParseRegion("US") + gb := language.MustParseRegion("GB") + uk := language.MustParseRegion("UK") + bu := language.MustParseRegion("BU") + + fmt.Println(us.TLD()) + fmt.Println(gb.TLD()) + fmt.Println(uk.TLD()) + fmt.Println(bu.TLD()) + + fmt.Println(us.Canonicalize().TLD()) + fmt.Println(gb.Canonicalize().TLD()) + fmt.Println(uk.Canonicalize().TLD()) + fmt.Println(bu.Canonicalize().TLD()) + // Output: + // US <nil> + // UK <nil> + // UK <nil> + // ZZ language: region is not a valid ccTLD + // US <nil> + // UK <nil> + // UK <nil> + // MM <nil> +} + +func ExampleCompose() { + nl, _ := language.ParseBase("nl") + us, _ := language.ParseRegion("US") + de := language.Make("de-1901-u-co-phonebk") + jp := language.Make("ja-JP") + fi := language.Make("fi-x-ing") + + u, _ := language.ParseExtension("u-nu-arabic") + x, _ := language.ParseExtension("x-piglatin") + + // Combine a base language and region. + fmt.Println(language.Compose(nl, us)) + // Combine a base language and extension. + fmt.Println(language.Compose(nl, x)) + // Replace the region. + fmt.Println(language.Compose(jp, us)) + // Combine several tags. + fmt.Println(language.Compose(us, nl, u)) + + // Replace the base language of a tag. + fmt.Println(language.Compose(de, nl)) + fmt.Println(language.Compose(de, nl, u)) + // Remove the base language. + fmt.Println(language.Compose(de, language.Base{})) + // Remove all variants. + fmt.Println(language.Compose(de, []language.Variant{})) + // Remove all extensions. + fmt.Println(language.Compose(de, []language.Extension{})) + fmt.Println(language.Compose(fi, []language.Extension{})) + // Remove all variants and extensions. + fmt.Println(language.Compose(de.Raw())) + + // An error is gobbled or returned if non-nil. + fmt.Println(language.Compose(language.ParseRegion("ZA"))) + fmt.Println(language.Compose(language.ParseRegion("HH"))) + + // Compose uses the same Default canonicalization as Make. + fmt.Println(language.Compose(language.Raw.Parse("en-Latn-UK"))) + + // Call compose on a different CanonType for different results. + fmt.Println(language.All.Compose(language.Raw.Parse("en-Latn-UK"))) + + // Output: + // nl-US <nil> + // nl-x-piglatin <nil> + // ja-US <nil> + // nl-US-u-nu-arabic <nil> + // nl-1901-u-co-phonebk <nil> + // nl-1901-u-nu-arabic <nil> + // und-1901-u-co-phonebk <nil> + // de-u-co-phonebk <nil> + // de-1901 <nil> + // fi <nil> + // de <nil> + // und-ZA <nil> + // und language: subtag "HH" is well-formed but unknown + // en-Latn-GB <nil> + // en-GB <nil> +} + +func ExampleParse_errors() { + for _, s := range []string{"Foo", "Bar", "Foobar"} { + _, err := language.Parse(s) + if err != nil { + if inv, ok := err.(language.ValueError); ok { + fmt.Println(inv.Subtag()) + } else { + fmt.Println(s) + } + } + } + for _, s := range []string{"en", "aa-Uuuu", "AC", "ac-u"} { + _, err := language.Parse(s) + switch e := err.(type) { + case language.ValueError: + fmt.Printf("%s: culprit %q\n", s, e.Subtag()) + case nil: + // No error. + default: + // A syntax error. + fmt.Printf("%s: ill-formed\n", s) + } + } + // Output: + // foo + // Foobar + // aa-Uuuu: culprit "Uuuu" + // AC: culprit "ac" + // ac-u: ill-formed +} + +func ExampleParent() { + p := func(tag string) { + fmt.Printf("parent(%v): %v\n", tag, language.Make(tag).Parent()) + } + p("zh-CN") + + // Australian English inherits from World English. + p("en-AU") + + // If the tag has a different maximized script from its parent, a tag with + // this maximized script is inserted. This allows different language tags + // which have the same base language and script in common to inherit from + // a common set of settings. + p("zh-HK") + + // If the maximized script of the parent is not identical, CLDR will skip + // inheriting from it, as it means there will not be many entries in common + // and inheriting from it is nonsensical. + p("zh-Hant") + + // The parent of a tag with variants and extensions is the tag with all + // variants and extensions removed. + p("de-1994-u-co-phonebk") + + // Remove default script. + p("de-Latn-LU") + + // Output: + // parent(zh-CN): zh + // parent(en-AU): en-001 + // parent(zh-HK): zh-Hant + // parent(zh-Hant): und + // parent(de-1994-u-co-phonebk): de + // parent(de-Latn-LU): de +} + +// ExampleMatcher_bestMatch gives some examples of getting the best match of +// a set of tags to any of the tags of given set. +func ExampleMatcher() { + // This is the set of tags from which we want to pick the best match. These + // can be, for example, the supported languages for some package. + tags := []language.Tag{ + language.English, + language.BritishEnglish, + language.French, + language.Afrikaans, + language.BrazilianPortuguese, + language.EuropeanPortuguese, + language.Croatian, + language.SimplifiedChinese, + language.Raw.Make("iw-IL"), + language.Raw.Make("iw"), + language.Raw.Make("he"), + } + m := language.NewMatcher(tags) + + // A simple match. + fmt.Println(m.Match(language.Make("fr"))) + + // Australian English is closer to British than American English. + fmt.Println(m.Match(language.Make("en-AU"))) + + // Default to the first tag passed to the Matcher if there is no match. + fmt.Println(m.Match(language.Make("ar"))) + + // Get the default tag. + fmt.Println(m.Match()) + + fmt.Println("----") + + // Someone specifying sr-Latn is probably fine with getting Croatian. + fmt.Println(m.Match(language.Make("sr-Latn"))) + + // We match SimplifiedChinese, but with Low confidence. + fmt.Println(m.Match(language.TraditionalChinese)) + + // Serbian in Latin script is a closer match to Croatian than Traditional + // Chinese to Simplified Chinese. + fmt.Println(m.Match(language.TraditionalChinese, language.Make("sr-Latn"))) + + fmt.Println("----") + + // In case a multiple variants of a language are available, the most spoken + // variant is typically returned. + fmt.Println(m.Match(language.Portuguese)) + + // Pick the first value passed to Match in case of a tie. + fmt.Println(m.Match(language.Dutch, language.Make("fr-BE"), language.Make("af-NA"))) + fmt.Println(m.Match(language.Dutch, language.Make("af-NA"), language.Make("fr-BE"))) + + fmt.Println("----") + + // If a Matcher is initialized with a language and it's deprecated version, + // it will distinguish between them. + fmt.Println(m.Match(language.Raw.Make("iw"))) + + // However, for non-exact matches, it will treat deprecated versions as + // equivalent and consider other factors first. + fmt.Println(m.Match(language.Raw.Make("he-IL"))) + + fmt.Println("----") + + // User settings passed to the Unicode extension are ignored for matching + // and preserved in the returned tag. + fmt.Println(m.Match(language.Make("de-u-co-phonebk"), language.Make("fr-u-cu-frf"))) + + // Even if the matching language is different. + fmt.Println(m.Match(language.Make("de-u-co-phonebk"), language.Make("br-u-cu-frf"))) + + // If there is no matching language, the options of the first preferred tag are used. + fmt.Println(m.Match(language.Make("de-u-co-phonebk"))) + + // Output: + // fr 2 Exact + // en-GB 1 High + // en 0 No + // en 0 No + // ---- + // hr 6 High + // zh-Hans 7 Low + // hr 6 High + // ---- + // pt-BR 4 High + // fr 2 High + // af 3 High + // ---- + // iw 9 Exact + // he 10 Exact + // ---- + // fr-u-cu-frf 2 Exact + // fr-u-cu-frf 2 High + // en-u-co-phonebk 0 No + + // TODO: "he" should be "he-u-rg-IL High" +} + +func ExampleMatchStrings() { + // languages supported by this service: + matcher := language.NewMatcher([]language.Tag{ + language.English, language.Dutch, language.German, + }) + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + lang, _ := r.Cookie("lang") + tag, _ := language.MatchStrings(matcher, lang.String(), r.Header.Get("Accept-Language")) + + fmt.Println("User language:", tag) + }) +} + +func ExampleComprehends() { + // Various levels of comprehensibility. + fmt.Println(language.Comprehends(language.English, language.English)) + fmt.Println(language.Comprehends(language.AmericanEnglish, language.BritishEnglish)) + + // An explicit Und results in no match. + fmt.Println(language.Comprehends(language.English, language.Und)) + + fmt.Println("----") + + // There is usually no mutual comprehensibility between different scripts. + fmt.Println(language.Comprehends(language.Make("en-Dsrt"), language.English)) + + // One exception is for Traditional versus Simplified Chinese, albeit with + // a low confidence. + fmt.Println(language.Comprehends(language.TraditionalChinese, language.SimplifiedChinese)) + + fmt.Println("----") + + // A Swiss German speaker will often understand High German. + fmt.Println(language.Comprehends(language.Make("gsw"), language.Make("de"))) + + // The converse is not generally the case. + fmt.Println(language.Comprehends(language.Make("de"), language.Make("gsw"))) + + // Output: + // Exact + // High + // No + // ---- + // No + // Low + // ---- + // High + // No +} + +func ExampleTag_values() { + us := language.MustParseRegion("US") + en := language.MustParseBase("en") + + lang, _, region := language.AmericanEnglish.Raw() + fmt.Println(lang == en, region == us) + + lang, _, region = language.BritishEnglish.Raw() + fmt.Println(lang == en, region == us) + + // Tags can be compared for exact equivalence using '=='. + en_us, _ := language.Compose(en, us) + fmt.Println(en_us == language.AmericanEnglish) + + // Output: + // true true + // true false + // true +} diff --git a/vendor/golang.org/x/text/language/httpexample_test.go b/vendor/golang.org/x/text/language/httpexample_test.go new file mode 100644 index 000000000..40d0663c8 --- /dev/null +++ b/vendor/golang.org/x/text/language/httpexample_test.go @@ -0,0 +1,48 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language_test + +import ( + "fmt" + "net/http" + "strings" + + "golang.org/x/text/language" +) + +// matcher is a language.Matcher configured for all supported languages. +var matcher = language.NewMatcher([]language.Tag{ + language.BritishEnglish, + language.Norwegian, + language.German, +}) + +// handler is a http.HandlerFunc. +func handler(w http.ResponseWriter, r *http.Request) { + t, q, err := language.ParseAcceptLanguage(r.Header.Get("Accept-Language")) + // We ignore the error: the default language will be selected for t == nil. + tag, _, _ := matcher.Match(t...) + fmt.Printf("%5v (t: %6v; q: %3v; err: %v)\n", tag, t, q, err) +} + +func ExampleParseAcceptLanguage() { + for _, al := range []string{ + "nn;q=0.3, en-us;q=0.8, en,", + "gsw, en;q=0.7, en-US;q=0.8", + "gsw, nl, da", + "invalid", + } { + // Create dummy request with Accept-Language set and pass it to handler. + r, _ := http.NewRequest("GET", "example.com", strings.NewReader("Hello")) + r.Header.Set("Accept-Language", al) + handler(nil, r) + } + + // Output: + // en-GB (t: [ en en-US nn]; q: [ 1 0.8 0.3]; err: <nil>) + // en-GB (t: [ gsw en-US en]; q: [ 1 0.8 0.7]; err: <nil>) + // de (t: [ gsw nl da]; q: [ 1 1 1]; err: <nil>) + // en-GB (t: []; q: []; err: language: tag is not well-formed) +} diff --git a/vendor/golang.org/x/text/language/language_test.go b/vendor/golang.org/x/text/language/language_test.go new file mode 100644 index 000000000..9e42d15dc --- /dev/null +++ b/vendor/golang.org/x/text/language/language_test.go @@ -0,0 +1,911 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language + +import ( + "reflect" + "testing" + + "golang.org/x/text/internal/testtext" +) + +func TestTagSize(t *testing.T) { + id := Tag{} + typ := reflect.TypeOf(id) + if typ.Size() > 24 { + t.Errorf("size of Tag was %d; want 24", typ.Size()) + } +} + +func TestIsRoot(t *testing.T) { + loc := Tag{} + if !loc.IsRoot() { + t.Errorf("unspecified should be root.") + } + for i, tt := range parseTests() { + loc, _ := Parse(tt.in) + undef := tt.lang == "und" && tt.script == "" && tt.region == "" && tt.ext == "" + if loc.IsRoot() != undef { + t.Errorf("%d: was %v; want %v", i, loc.IsRoot(), undef) + } + } +} + +func TestEquality(t *testing.T) { + for i, tt := range parseTests()[48:49] { + s := tt.in + tag := Make(s) + t1 := Make(tag.String()) + if tag != t1 { + t.Errorf("%d:%s: equality test 1 failed\n got: %#v\nwant: %#v)", i, s, t1, tag) + } + t2, _ := Compose(tag) + if tag != t2 { + t.Errorf("%d:%s: equality test 2 failed\n got: %#v\nwant: %#v", i, s, t2, tag) + } + } +} + +func TestMakeString(t *testing.T) { + tests := []struct{ in, out string }{ + {"und", "und"}, + {"und", "und-CW"}, + {"nl", "nl-NL"}, + {"de-1901", "nl-1901"}, + {"de-1901", "de-Arab-1901"}, + {"x-a-b", "de-Arab-x-a-b"}, + {"x-a-b", "x-a-b"}, + } + for i, tt := range tests { + id, _ := Parse(tt.in) + mod, _ := Parse(tt.out) + id.setTagsFrom(mod) + for j := 0; j < 2; j++ { + id.remakeString() + if str := id.String(); str != tt.out { + t.Errorf("%d:%d: found %s; want %s", i, j, id.String(), tt.out) + } + } + // The bytes to string conversion as used in remakeString + // occasionally measures as more than one alloc, breaking this test. + // To alleviate this we set the number of runs to more than 1. + if n := testtext.AllocsPerRun(8, id.remakeString); n > 1 { + t.Errorf("%d: # allocs got %.1f; want <= 1", i, n) + } + } +} + +func TestCompactIndex(t *testing.T) { + tests := []struct { + tag string + index int + ok bool + }{ + // TODO: these values will change with each CLDR update. This issue + // will be solved if we decide to fix the indexes. + {"und", 0, true}, + {"ca-ES-valencia", 1, true}, + {"ca-ES-valencia-u-va-posix", 0, false}, + {"ca-ES-valencia-u-co-phonebk", 1, true}, + {"ca-ES-valencia-u-co-phonebk-va-posix", 0, false}, + {"x-klingon", 0, false}, + {"en-US", 232, true}, + {"en-US-u-va-posix", 2, true}, + {"en", 136, true}, + {"en-u-co-phonebk", 136, true}, + {"en-001", 137, true}, + {"sh", 0, false}, // We don't normalize. + } + for _, tt := range tests { + x, ok := CompactIndex(Raw.MustParse(tt.tag)) + if x != tt.index || ok != tt.ok { + t.Errorf("%s: got %d, %v; want %d %v", tt.tag, x, ok, tt.index, tt.ok) + } + } +} + +func TestMarshal(t *testing.T) { + testCases := []string{ + // TODO: these values will change with each CLDR update. This issue + // will be solved if we decide to fix the indexes. + "und", + "ca-ES-valencia", + "ca-ES-valencia-u-va-posix", + "ca-ES-valencia-u-co-phonebk", + "ca-ES-valencia-u-co-phonebk-va-posix", + "x-klingon", + "en-US", + "en-US-u-va-posix", + "en", + "en-u-co-phonebk", + "en-001", + "sh", + } + for _, tc := range testCases { + var tag Tag + err := tag.UnmarshalText([]byte(tc)) + if err != nil { + t.Errorf("UnmarshalText(%q): unexpected error: %v", tc, err) + } + b, err := tag.MarshalText() + if err != nil { + t.Errorf("MarshalText(%q): unexpected error: %v", tc, err) + } + if got := string(b); got != tc { + t.Errorf("%s: got %q; want %q", tc, got, tc) + } + } +} + +func TestBase(t *testing.T) { + tests := []struct { + loc, lang string + conf Confidence + }{ + {"und", "en", Low}, + {"x-abc", "und", No}, + {"en", "en", Exact}, + {"und-Cyrl", "ru", High}, + // If a region is not included, the official language should be English. + {"und-US", "en", High}, + // TODO: not-explicitly listed scripts should probably be und, No + // Modify addTags to return info on how the match was derived. + // {"und-Aghb", "und", No}, + } + for i, tt := range tests { + loc, _ := Parse(tt.loc) + lang, conf := loc.Base() + if lang.String() != tt.lang { + t.Errorf("%d: language was %s; want %s", i, lang, tt.lang) + } + if conf != tt.conf { + t.Errorf("%d: confidence was %d; want %d", i, conf, tt.conf) + } + } +} + +func TestParseBase(t *testing.T) { + tests := []struct { + in string + out string + ok bool + }{ + {"en", "en", true}, + {"EN", "en", true}, + {"nld", "nl", true}, + {"dut", "dut", true}, // bibliographic + {"aaj", "und", false}, // unknown + {"qaa", "qaa", true}, + {"a", "und", false}, + {"", "und", false}, + {"aaaa", "und", false}, + } + for i, tt := range tests { + x, err := ParseBase(tt.in) + if x.String() != tt.out || err == nil != tt.ok { + t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tt.in, x, err == nil, tt.out, tt.ok) + } + if y, _, _ := Raw.Make(tt.out).Raw(); x != y { + t.Errorf("%d:%s: tag was %s; want %s", i, tt.in, x, y) + } + } +} + +func TestScript(t *testing.T) { + tests := []struct { + loc, scr string + conf Confidence + }{ + {"und", "Latn", Low}, + {"en-Latn", "Latn", Exact}, + {"en", "Latn", High}, + {"sr", "Cyrl", Low}, + {"kk", "Cyrl", High}, + {"kk-CN", "Arab", Low}, + {"cmn", "Hans", Low}, + {"ru", "Cyrl", High}, + {"ru-RU", "Cyrl", High}, + {"yue", "Hant", Low}, + {"x-abc", "Zzzz", Low}, + {"und-zyyy", "Zyyy", Exact}, + } + for i, tt := range tests { + loc, _ := Parse(tt.loc) + sc, conf := loc.Script() + if sc.String() != tt.scr { + t.Errorf("%d:%s: script was %s; want %s", i, tt.loc, sc, tt.scr) + } + if conf != tt.conf { + t.Errorf("%d:%s: confidence was %d; want %d", i, tt.loc, conf, tt.conf) + } + } +} + +func TestParseScript(t *testing.T) { + tests := []struct { + in string + out string + ok bool + }{ + {"Latn", "Latn", true}, + {"zzzz", "Zzzz", true}, + {"zyyy", "Zyyy", true}, + {"Latm", "Zzzz", false}, + {"Zzz", "Zzzz", false}, + {"", "Zzzz", false}, + {"Zzzxx", "Zzzz", false}, + } + for i, tt := range tests { + x, err := ParseScript(tt.in) + if x.String() != tt.out || err == nil != tt.ok { + t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tt.in, x, err == nil, tt.out, tt.ok) + } + if err == nil { + if _, y, _ := Raw.Make("und-" + tt.out).Raw(); x != y { + t.Errorf("%d:%s: tag was %s; want %s", i, tt.in, x, y) + } + } + } +} + +func TestRegion(t *testing.T) { + tests := []struct { + loc, reg string + conf Confidence + }{ + {"und", "US", Low}, + {"en", "US", Low}, + {"zh-Hant", "TW", Low}, + {"en-US", "US", Exact}, + {"cmn", "CN", Low}, + {"ru", "RU", Low}, + {"yue", "HK", Low}, + {"x-abc", "ZZ", Low}, + } + for i, tt := range tests { + loc, _ := Raw.Parse(tt.loc) + reg, conf := loc.Region() + if reg.String() != tt.reg { + t.Errorf("%d:%s: region was %s; want %s", i, tt.loc, reg, tt.reg) + } + if conf != tt.conf { + t.Errorf("%d:%s: confidence was %d; want %d", i, tt.loc, conf, tt.conf) + } + } +} + +func TestEncodeM49(t *testing.T) { + tests := []struct { + m49 int + code string + ok bool + }{ + {1, "001", true}, + {840, "US", true}, + {899, "ZZ", false}, + } + for i, tt := range tests { + if r, err := EncodeM49(tt.m49); r.String() != tt.code || err == nil != tt.ok { + t.Errorf("%d:%d: was %s, %v; want %s, %v", i, tt.m49, r, err == nil, tt.code, tt.ok) + } + } + for i := 1; i <= 1000; i++ { + if r, err := EncodeM49(i); err == nil && r.M49() == 0 { + t.Errorf("%d has no error, but maps to undefined region", i) + } + } +} + +func TestParseRegion(t *testing.T) { + tests := []struct { + in string + out string + ok bool + }{ + {"001", "001", true}, + {"840", "US", true}, + {"899", "ZZ", false}, + {"USA", "US", true}, + {"US", "US", true}, + {"BC", "ZZ", false}, + {"C", "ZZ", false}, + {"CCCC", "ZZ", false}, + {"01", "ZZ", false}, + } + for i, tt := range tests { + r, err := ParseRegion(tt.in) + if r.String() != tt.out || err == nil != tt.ok { + t.Errorf("%d:%s: was %s, %v; want %s, %v", i, tt.in, r, err == nil, tt.out, tt.ok) + } + if err == nil { + if _, _, y := Raw.Make("und-" + tt.out).Raw(); r != y { + t.Errorf("%d:%s: tag was %s; want %s", i, tt.in, r, y) + } + } + } +} + +func TestIsCountry(t *testing.T) { + tests := []struct { + reg string + country bool + }{ + {"US", true}, + {"001", false}, + {"958", false}, + {"419", false}, + {"203", true}, + {"020", true}, + {"900", false}, + {"999", false}, + {"QO", false}, + {"EU", false}, + {"AA", false}, + {"XK", true}, + } + for i, tt := range tests { + reg, _ := getRegionID([]byte(tt.reg)) + r := Region{reg} + if r.IsCountry() != tt.country { + t.Errorf("%d: IsCountry(%s) was %v; want %v", i, tt.reg, r.IsCountry(), tt.country) + } + } +} + +func TestIsGroup(t *testing.T) { + tests := []struct { + reg string + group bool + }{ + {"US", false}, + {"001", true}, + {"958", false}, + {"419", true}, + {"203", false}, + {"020", false}, + {"900", false}, + {"999", false}, + {"QO", true}, + {"EU", true}, + {"AA", false}, + {"XK", false}, + } + for i, tt := range tests { + reg, _ := getRegionID([]byte(tt.reg)) + r := Region{reg} + if r.IsGroup() != tt.group { + t.Errorf("%d: IsGroup(%s) was %v; want %v", i, tt.reg, r.IsGroup(), tt.group) + } + } +} + +func TestContains(t *testing.T) { + tests := []struct { + enclosing, contained string + contains bool + }{ + // A region contains itself. + {"US", "US", true}, + {"001", "001", true}, + + // Direct containment. + {"001", "002", true}, + {"039", "XK", true}, + {"150", "XK", true}, + {"EU", "AT", true}, + {"QO", "AQ", true}, + + // Indirect containemnt. + {"001", "US", true}, + {"001", "419", true}, + {"001", "013", true}, + + // No containment. + {"US", "001", false}, + {"155", "EU", false}, + } + for i, tt := range tests { + enc, _ := getRegionID([]byte(tt.enclosing)) + con, _ := getRegionID([]byte(tt.contained)) + r := Region{enc} + if got := r.Contains(Region{con}); got != tt.contains { + t.Errorf("%d: %s.Contains(%s) was %v; want %v", i, tt.enclosing, tt.contained, got, tt.contains) + } + } +} + +func TestRegionCanonicalize(t *testing.T) { + for i, tt := range []struct{ in, out string }{ + {"UK", "GB"}, + {"TP", "TL"}, + {"QU", "EU"}, + {"SU", "SU"}, + {"VD", "VN"}, + {"DD", "DE"}, + } { + r := MustParseRegion(tt.in) + want := MustParseRegion(tt.out) + if got := r.Canonicalize(); got != want { + t.Errorf("%d: got %v; want %v", i, got, want) + } + } +} + +func TestRegionTLD(t *testing.T) { + for _, tt := range []struct { + in, out string + ok bool + }{ + {"EH", "EH", true}, + {"FR", "FR", true}, + {"TL", "TL", true}, + + // In ccTLD before in ISO. + {"GG", "GG", true}, + + // Non-standard assignment of ccTLD to ISO code. + {"GB", "UK", true}, + + // Exceptionally reserved in ISO and valid ccTLD. + {"UK", "UK", true}, + {"AC", "AC", true}, + {"EU", "EU", true}, + {"SU", "SU", true}, + + // Exceptionally reserved in ISO and invalid ccTLD. + {"CP", "ZZ", false}, + {"DG", "ZZ", false}, + {"EA", "ZZ", false}, + {"FX", "ZZ", false}, + {"IC", "ZZ", false}, + {"TA", "ZZ", false}, + + // Transitionally reserved in ISO (e.g. deprecated) but valid ccTLD as + // it is still being phased out. + {"AN", "AN", true}, + {"TP", "TP", true}, + + // Transitionally reserved in ISO (e.g. deprecated) and invalid ccTLD. + // Defined in package language as it has a mapping in CLDR. + {"BU", "ZZ", false}, + {"CS", "ZZ", false}, + {"NT", "ZZ", false}, + {"YU", "ZZ", false}, + {"ZR", "ZZ", false}, + // Not defined in package: SF. + + // Indeterminately reserved in ISO. + // Defined in package language as it has a legacy mapping in CLDR. + {"DY", "ZZ", false}, + {"RH", "ZZ", false}, + {"VD", "ZZ", false}, + // Not defined in package: EW, FL, JA, LF, PI, RA, RB, RC, RI, RL, RM, + // RN, RP, WG, WL, WV, and YV. + + // Not assigned in ISO, but legacy definitions in CLDR. + {"DD", "ZZ", false}, + {"YD", "ZZ", false}, + + // Normal mappings but somewhat special status in ccTLD. + {"BL", "BL", true}, + {"MF", "MF", true}, + {"BV", "BV", true}, + {"SJ", "SJ", true}, + + // Have values when normalized, but not as is. + {"QU", "ZZ", false}, + + // ISO Private Use. + {"AA", "ZZ", false}, + {"QM", "ZZ", false}, + {"QO", "ZZ", false}, + {"XA", "ZZ", false}, + {"XK", "ZZ", false}, // Sometimes used for Kosovo, but invalid ccTLD. + } { + if tt.in == "" { + continue + } + + r := MustParseRegion(tt.in) + var want Region + if tt.out != "ZZ" { + want = MustParseRegion(tt.out) + } + tld, err := r.TLD() + if got := err == nil; got != tt.ok { + t.Errorf("error(%v): got %v; want %v", r, got, tt.ok) + } + if tld != want { + t.Errorf("TLD(%v): got %v; want %v", r, tld, want) + } + } +} + +func TestCanonicalize(t *testing.T) { + // TODO: do a full test using CLDR data in a separate regression test. + tests := []struct { + in, out string + option CanonType + }{ + {"en-Latn", "en", SuppressScript}, + {"sr-Cyrl", "sr-Cyrl", SuppressScript}, + {"sh", "sr-Latn", Legacy}, + {"sh-HR", "sr-Latn-HR", Legacy}, + {"sh-Cyrl-HR", "sr-Cyrl-HR", Legacy}, + {"tl", "fil", Legacy}, + {"no", "no", Legacy}, + {"no", "nb", Legacy | CLDR}, + {"cmn", "cmn", Legacy}, + {"cmn", "zh", Macro}, + {"cmn-u-co-stroke", "zh-u-co-stroke", Macro}, + {"yue", "yue", Macro}, + {"nb", "no", Macro}, + {"nb", "nb", Macro | CLDR}, + {"no", "no", Macro}, + {"no", "no", Macro | CLDR}, + {"iw", "he", DeprecatedBase}, + {"iw", "he", Deprecated | CLDR}, + {"mo", "ro-MD", Deprecated}, // Adopted by CLDR as of version 25. + {"alb", "sq", Legacy}, // bibliographic + {"dut", "nl", Legacy}, // bibliographic + // As of CLDR 25, mo is no longer considered a legacy mapping. + {"mo", "mo", Legacy | CLDR}, + {"und-AN", "und-AN", Deprecated}, + {"und-YD", "und-YE", DeprecatedRegion}, + {"und-YD", "und-YD", DeprecatedBase}, + {"und-Qaai", "und-Zinh", DeprecatedScript}, + {"und-Qaai", "und-Qaai", DeprecatedBase}, + {"drh", "mn", All}, // drh -> khk -> mn + } + for i, tt := range tests { + in, _ := Raw.Parse(tt.in) + in, _ = tt.option.Canonicalize(in) + if in.String() != tt.out { + t.Errorf("%d:%s: was %s; want %s", i, tt.in, in.String(), tt.out) + } + if int(in.pVariant) > int(in.pExt) || int(in.pExt) > len(in.str) { + t.Errorf("%d:%s:offsets %d <= %d <= %d must be true", i, tt.in, in.pVariant, in.pExt, len(in.str)) + } + } + // Test idempotence. + for _, base := range Supported.BaseLanguages() { + tag, _ := Raw.Compose(base) + got, _ := All.Canonicalize(tag) + want, _ := All.Canonicalize(got) + if got != want { + t.Errorf("idem(%s): got %s; want %s", tag, got, want) + } + } +} + +func TestTypeForKey(t *testing.T) { + tests := []struct{ key, in, out string }{ + {"co", "en", ""}, + {"co", "en-u-abc", ""}, + {"co", "en-u-co-phonebk", "phonebk"}, + {"co", "en-u-co-phonebk-cu-aud", "phonebk"}, + {"co", "x-foo-u-co-phonebk", ""}, + {"nu", "en-u-co-phonebk-nu-arabic", "arabic"}, + {"kc", "cmn-u-co-stroke", ""}, + } + for _, tt := range tests { + if v := Make(tt.in).TypeForKey(tt.key); v != tt.out { + t.Errorf("%q[%q]: was %q; want %q", tt.in, tt.key, v, tt.out) + } + } +} + +func TestSetTypeForKey(t *testing.T) { + tests := []struct { + key, value, in, out string + err bool + }{ + // replace existing value + {"co", "pinyin", "en-u-co-phonebk", "en-u-co-pinyin", false}, + {"co", "pinyin", "en-u-co-phonebk-cu-xau", "en-u-co-pinyin-cu-xau", false}, + {"co", "pinyin", "en-u-co-phonebk-v-xx", "en-u-co-pinyin-v-xx", false}, + {"co", "pinyin", "en-u-co-phonebk-x-x", "en-u-co-pinyin-x-x", false}, + {"nu", "arabic", "en-u-co-phonebk-nu-vaai", "en-u-co-phonebk-nu-arabic", false}, + // add to existing -u extension + {"co", "pinyin", "en-u-ca-gregory", "en-u-ca-gregory-co-pinyin", false}, + {"co", "pinyin", "en-u-ca-gregory-nu-vaai", "en-u-ca-gregory-co-pinyin-nu-vaai", false}, + {"co", "pinyin", "en-u-ca-gregory-v-va", "en-u-ca-gregory-co-pinyin-v-va", false}, + {"co", "pinyin", "en-u-ca-gregory-x-a", "en-u-ca-gregory-co-pinyin-x-a", false}, + {"ca", "gregory", "en-u-co-pinyin", "en-u-ca-gregory-co-pinyin", false}, + // remove pair + {"co", "", "en-u-co-phonebk", "en", false}, + {"co", "", "en-u-ca-gregory-co-phonebk", "en-u-ca-gregory", false}, + {"co", "", "en-u-co-phonebk-nu-arabic", "en-u-nu-arabic", false}, + {"co", "", "en", "en", false}, + // add -u extension + {"co", "pinyin", "en", "en-u-co-pinyin", false}, + {"co", "pinyin", "und", "und-u-co-pinyin", false}, + {"co", "pinyin", "en-a-aaa", "en-a-aaa-u-co-pinyin", false}, + {"co", "pinyin", "en-x-aaa", "en-u-co-pinyin-x-aaa", false}, + {"co", "pinyin", "en-v-aa", "en-u-co-pinyin-v-aa", false}, + {"co", "pinyin", "en-a-aaa-x-x", "en-a-aaa-u-co-pinyin-x-x", false}, + {"co", "pinyin", "en-a-aaa-v-va", "en-a-aaa-u-co-pinyin-v-va", false}, + // error on invalid values + {"co", "pinyinxxx", "en", "en", true}, + {"co", "piny.n", "en", "en", true}, + {"co", "pinyinxxx", "en-a-aaa", "en-a-aaa", true}, + {"co", "pinyinxxx", "en-u-aaa", "en-u-aaa", true}, + {"co", "pinyinxxx", "en-u-aaa-co-pinyin", "en-u-aaa-co-pinyin", true}, + {"co", "pinyi.", "en-u-aaa-co-pinyin", "en-u-aaa-co-pinyin", true}, + {"col", "pinyin", "en", "en", true}, + {"co", "cu", "en", "en", true}, + // error when setting on a private use tag + {"co", "phonebook", "x-foo", "x-foo", true}, + } + for i, tt := range tests { + tag := Make(tt.in) + if v, err := tag.SetTypeForKey(tt.key, tt.value); v.String() != tt.out { + t.Errorf("%d:%q[%q]=%q: was %q; want %q", i, tt.in, tt.key, tt.value, v, tt.out) + } else if (err != nil) != tt.err { + t.Errorf("%d:%q[%q]=%q: error was %v; want %v", i, tt.in, tt.key, tt.value, err != nil, tt.err) + } else if val := v.TypeForKey(tt.key); err == nil && val != tt.value { + t.Errorf("%d:%q[%q]==%q: was %v; want %v", i, tt.out, tt.key, tt.value, val, tt.value) + } + if len(tag.String()) <= 3 { + // Simulate a tag for which the string has not been set. + tag.str, tag.pExt, tag.pVariant = "", 0, 0 + if tag, err := tag.SetTypeForKey(tt.key, tt.value); err == nil { + if val := tag.TypeForKey(tt.key); err == nil && val != tt.value { + t.Errorf("%d:%q[%q]==%q: was %v; want %v", i, tt.out, tt.key, tt.value, val, tt.value) + } + } + } + } +} + +func TestFindKeyAndType(t *testing.T) { + // out is either the matched type in case of a match or the original + // string up till the insertion point. + tests := []struct { + key string + hasExt bool + in, out string + }{ + // Don't search past a private use extension. + {"co", false, "en-x-foo-u-co-pinyin", "en"}, + {"co", false, "x-foo-u-co-pinyin", ""}, + {"co", false, "en-s-fff-x-foo", "en-s-fff"}, + // Insertion points in absence of -u extension. + {"cu", false, "en", ""}, // t.str is "" + {"cu", false, "en-v-va", "en"}, + {"cu", false, "en-a-va", "en-a-va"}, + {"cu", false, "en-a-va-v-va", "en-a-va"}, + {"cu", false, "en-x-a", "en"}, + // Tags with the -u extension. + {"co", true, "en-u-co-standard", "standard"}, + {"co", true, "yue-u-co-pinyin", "pinyin"}, + {"co", true, "en-u-co-abc", "abc"}, + {"co", true, "en-u-co-abc-def", "abc-def"}, + {"co", true, "en-u-co-abc-def-x-foo", "abc-def"}, + {"co", true, "en-u-co-standard-nu-arab", "standard"}, + {"co", true, "yue-u-co-pinyin-nu-arab", "pinyin"}, + // Insertion points. + {"cu", true, "en-u-co-standard", "en-u-co-standard"}, + {"cu", true, "yue-u-co-pinyin-x-foo", "yue-u-co-pinyin"}, + {"cu", true, "en-u-co-abc", "en-u-co-abc"}, + {"cu", true, "en-u-nu-arabic", "en-u"}, + {"cu", true, "en-u-co-abc-def-nu-arabic", "en-u-co-abc-def"}, + } + for i, tt := range tests { + start, end, hasExt := Make(tt.in).findTypeForKey(tt.key) + if start != end { + res := tt.in[start:end] + if res != tt.out { + t.Errorf("%d:%s: was %q; want %q", i, tt.in, res, tt.out) + } + } else { + if hasExt != tt.hasExt { + t.Errorf("%d:%s: hasExt was %v; want %v", i, tt.in, hasExt, tt.hasExt) + continue + } + if tt.in[:start] != tt.out { + t.Errorf("%d:%s: insertion point was %q; want %q", i, tt.in, tt.in[:start], tt.out) + } + } + } +} + +func TestParent(t *testing.T) { + tests := []struct{ in, out string }{ + // Strip variants and extensions first + {"de-u-co-phonebk", "de"}, + {"de-1994", "de"}, + {"de-Latn-1994", "de"}, // remove superfluous script. + + // Ensure the canonical Tag for an entry is in the chain for base-script + // pairs. + {"zh-Hans", "zh"}, + + // Skip the script if it is the maximized version. CLDR files for the + // skipped tag are always empty. + {"zh-Hans-TW", "zh"}, + {"zh-Hans-CN", "zh"}, + + // Insert the script if the maximized script is not the same as the + // maximized script of the base language. + {"zh-TW", "zh-Hant"}, + {"zh-HK", "zh-Hant"}, + {"zh-Hant-TW", "zh-Hant"}, + {"zh-Hant-HK", "zh-Hant"}, + + // Non-default script skips to und. + // CLDR + {"az-Cyrl", "und"}, + {"bs-Cyrl", "und"}, + {"en-Dsrt", "und"}, + {"ha-Arab", "und"}, + {"mn-Mong", "und"}, + {"pa-Arab", "und"}, + {"shi-Latn", "und"}, + {"sr-Latn", "und"}, + {"uz-Arab", "und"}, + {"uz-Cyrl", "und"}, + {"vai-Latn", "und"}, + {"zh-Hant", "und"}, + // extra + {"nl-Cyrl", "und"}, + + // World english inherits from en-001. + {"en-150", "en-001"}, + {"en-AU", "en-001"}, + {"en-BE", "en-001"}, + {"en-GG", "en-001"}, + {"en-GI", "en-001"}, + {"en-HK", "en-001"}, + {"en-IE", "en-001"}, + {"en-IM", "en-001"}, + {"en-IN", "en-001"}, + {"en-JE", "en-001"}, + {"en-MT", "en-001"}, + {"en-NZ", "en-001"}, + {"en-PK", "en-001"}, + {"en-SG", "en-001"}, + + // Spanish in Latin-American countries have es-419 as parent. + {"es-AR", "es-419"}, + {"es-BO", "es-419"}, + {"es-CL", "es-419"}, + {"es-CO", "es-419"}, + {"es-CR", "es-419"}, + {"es-CU", "es-419"}, + {"es-DO", "es-419"}, + {"es-EC", "es-419"}, + {"es-GT", "es-419"}, + {"es-HN", "es-419"}, + {"es-MX", "es-419"}, + {"es-NI", "es-419"}, + {"es-PA", "es-419"}, + {"es-PE", "es-419"}, + {"es-PR", "es-419"}, + {"es-PY", "es-419"}, + {"es-SV", "es-419"}, + {"es-US", "es-419"}, + {"es-UY", "es-419"}, + {"es-VE", "es-419"}, + // exceptions (according to CLDR) + {"es-CW", "es"}, + + // Inherit from pt-PT, instead of pt for these countries. + {"pt-AO", "pt-PT"}, + {"pt-CV", "pt-PT"}, + {"pt-GW", "pt-PT"}, + {"pt-MO", "pt-PT"}, + {"pt-MZ", "pt-PT"}, + {"pt-ST", "pt-PT"}, + {"pt-TL", "pt-PT"}, + } + for _, tt := range tests { + tag := Raw.MustParse(tt.in) + if p := Raw.MustParse(tt.out); p != tag.Parent() { + t.Errorf("%s: was %v; want %v", tt.in, tag.Parent(), p) + } + } +} + +var ( + // Tags without error that don't need to be changed. + benchBasic = []string{ + "en", + "en-Latn", + "en-GB", + "za", + "zh-Hant", + "zh", + "zh-HK", + "ar-MK", + "en-CA", + "fr-CA", + "fr-CH", + "fr", + "lv", + "he-IT", + "tlh", + "ja", + "ja-Jpan", + "ja-Jpan-JP", + "de-1996", + "de-CH", + "sr", + "sr-Latn", + } + // Tags with extensions, not changes required. + benchExt = []string{ + "x-a-b-c-d", + "x-aa-bbbb-cccccccc-d", + "en-x_cc-b-bbb-a-aaa", + "en-c_cc-b-bbb-a-aaa-x-x", + "en-u-co-phonebk", + "en-Cyrl-u-co-phonebk", + "en-US-u-co-phonebk-cu-xau", + "en-nedix-u-co-phonebk", + "en-t-t0-abcd", + "en-t-nl-latn", + "en-t-t0-abcd-x-a", + } + // Change, but not memory allocation required. + benchSimpleChange = []string{ + "EN", + "i-klingon", + "en-latn", + "zh-cmn-Hans-CN", + "iw-NL", + } + // Change and memory allocation required. + benchChangeAlloc = []string{ + "en-c_cc-b-bbb-a-aaa", + "en-u-cu-xua-co-phonebk", + "en-u-cu-xua-co-phonebk-a-cd", + "en-u-def-abc-cu-xua-co-phonebk", + "en-t-en-Cyrl-NL-1994", + "en-t-en-Cyrl-NL-1994-t0-abc-def", + } + // Tags that result in errors. + benchErr = []string{ + // IllFormed + "x_A.-B-C_D", + "en-u-cu-co-phonebk", + "en-u-cu-xau-co", + "en-t-nl-abcd", + // Invalid + "xx", + "nl-Uuuu", + "nl-QB", + } + benchChange = append(benchSimpleChange, benchChangeAlloc...) + benchAll = append(append(append(benchBasic, benchExt...), benchChange...), benchErr...) +) + +func doParse(b *testing.B, tag []string) { + for i := 0; i < b.N; i++ { + // Use the modulo instead of looping over all tags so that we get a somewhat + // meaningful ns/op. + Parse(tag[i%len(tag)]) + } +} + +func BenchmarkParse(b *testing.B) { + doParse(b, benchAll) +} + +func BenchmarkParseBasic(b *testing.B) { + doParse(b, benchBasic) +} + +func BenchmarkParseError(b *testing.B) { + doParse(b, benchErr) +} + +func BenchmarkParseSimpleChange(b *testing.B) { + doParse(b, benchSimpleChange) +} + +func BenchmarkParseChangeAlloc(b *testing.B) { + doParse(b, benchChangeAlloc) +} diff --git a/vendor/golang.org/x/text/language/lookup_test.go b/vendor/golang.org/x/text/language/lookup_test.go new file mode 100644 index 000000000..9833830c4 --- /dev/null +++ b/vendor/golang.org/x/text/language/lookup_test.go @@ -0,0 +1,457 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language + +import ( + "testing" + + "golang.org/x/text/internal/tag" +) + +func b(s string) []byte { + return []byte(s) +} + +func TestLangID(t *testing.T) { + tests := []struct { + id, bcp47, iso3, norm string + err error + }{ + {id: "", bcp47: "und", iso3: "und", err: errSyntax}, + {id: " ", bcp47: "und", iso3: "und", err: errSyntax}, + {id: " ", bcp47: "und", iso3: "und", err: errSyntax}, + {id: " ", bcp47: "und", iso3: "und", err: errSyntax}, + {id: "xxx", bcp47: "und", iso3: "und", err: mkErrInvalid([]byte("xxx"))}, + {id: "und", bcp47: "und", iso3: "und"}, + {id: "aju", bcp47: "aju", iso3: "aju", norm: "jrb"}, + {id: "jrb", bcp47: "jrb", iso3: "jrb"}, + {id: "es", bcp47: "es", iso3: "spa"}, + {id: "spa", bcp47: "es", iso3: "spa"}, + {id: "ji", bcp47: "ji", iso3: "yid-", norm: "yi"}, + {id: "jw", bcp47: "jw", iso3: "jav-", norm: "jv"}, + {id: "ar", bcp47: "ar", iso3: "ara"}, + {id: "kw", bcp47: "kw", iso3: "cor"}, + {id: "arb", bcp47: "arb", iso3: "arb", norm: "ar"}, + {id: "ar", bcp47: "ar", iso3: "ara"}, + {id: "kur", bcp47: "ku", iso3: "kur"}, + {id: "nl", bcp47: "nl", iso3: "nld"}, + {id: "NL", bcp47: "nl", iso3: "nld"}, + {id: "gsw", bcp47: "gsw", iso3: "gsw"}, + {id: "gSW", bcp47: "gsw", iso3: "gsw"}, + {id: "und", bcp47: "und", iso3: "und"}, + {id: "sh", bcp47: "sh", iso3: "hbs", norm: "sr"}, + {id: "hbs", bcp47: "sh", iso3: "hbs", norm: "sr"}, + {id: "no", bcp47: "no", iso3: "nor", norm: "no"}, + {id: "nor", bcp47: "no", iso3: "nor", norm: "no"}, + {id: "cmn", bcp47: "cmn", iso3: "cmn", norm: "zh"}, + } + for i, tt := range tests { + want, err := getLangID(b(tt.id)) + if err != tt.err { + t.Errorf("%d:err(%s): found %q; want %q", i, tt.id, err, tt.err) + } + if err != nil { + continue + } + if id, _ := getLangISO2(b(tt.bcp47)); len(tt.bcp47) == 2 && want != id { + t.Errorf("%d:getISO2(%s): found %v; want %v", i, tt.bcp47, id, want) + } + if len(tt.iso3) == 3 { + if id, _ := getLangISO3(b(tt.iso3)); want != id { + t.Errorf("%d:getISO3(%s): found %q; want %q", i, tt.iso3, id, want) + } + if id, _ := getLangID(b(tt.iso3)); want != id { + t.Errorf("%d:getID3(%s): found %v; want %v", i, tt.iso3, id, want) + } + } + norm := want + if tt.norm != "" { + norm, _ = getLangID(b(tt.norm)) + } + id, _ := normLang(want) + if id != norm { + t.Errorf("%d:norm(%s): found %v; want %v", i, tt.id, id, norm) + } + if id := want.String(); tt.bcp47 != id { + t.Errorf("%d:String(): found %s; want %s", i, id, tt.bcp47) + } + if id := want.ISO3(); tt.iso3[:3] != id { + t.Errorf("%d:iso3(): found %s; want %s", i, id, tt.iso3[:3]) + } + } +} + +func TestGrandfathered(t *testing.T) { + for _, tt := range []struct{ in, out string }{ + {"art-lojban", "jbo"}, + {"i-ami", "ami"}, + {"i-bnn", "bnn"}, + {"i-hak", "hak"}, + {"i-klingon", "tlh"}, + {"i-lux", "lb"}, + {"i-navajo", "nv"}, + {"i-pwn", "pwn"}, + {"i-tao", "tao"}, + {"i-tay", "tay"}, + {"i-tsu", "tsu"}, + {"no-bok", "nb"}, + {"no-nyn", "nn"}, + {"sgn-BE-FR", "sfb"}, + {"sgn-BE-NL", "vgt"}, + {"sgn-CH-DE", "sgg"}, + {"sgn-ch-de", "sgg"}, + {"zh-guoyu", "cmn"}, + {"zh-hakka", "hak"}, + {"zh-min-nan", "nan"}, + {"zh-xiang", "hsn"}, + + // Grandfathered tags with no modern replacement will be converted as follows: + {"cel-gaulish", "xtg-x-cel-gaulish"}, + {"en-GB-oed", "en-GB-oxendict"}, + {"en-gb-oed", "en-GB-oxendict"}, + {"i-default", "en-x-i-default"}, + {"i-enochian", "und-x-i-enochian"}, + {"i-mingo", "see-x-i-mingo"}, + {"zh-min", "nan-x-zh-min"}, + + {"root", "und"}, + {"en_US_POSIX", "en-US-u-va-posix"}, + {"en_us_posix", "en-US-u-va-posix"}, + {"en-us-posix", "en-US-u-va-posix"}, + } { + got := Raw.Make(tt.in) + want := Raw.MustParse(tt.out) + if got != want { + t.Errorf("%s: got %q; want %q", tt.in, got, want) + } + } +} + +func TestRegionID(t *testing.T) { + tests := []struct { + in, out string + }{ + {"_ ", ""}, + {"_000", ""}, + {"419", "419"}, + {"AA", "AA"}, + {"ATF", "TF"}, + {"HV", "HV"}, + {"CT", "CT"}, + {"DY", "DY"}, + {"IC", "IC"}, + {"FQ", "FQ"}, + {"JT", "JT"}, + {"ZZ", "ZZ"}, + {"EU", "EU"}, + {"QO", "QO"}, + {"FX", "FX"}, + } + for i, tt := range tests { + if tt.in[0] == '_' { + id := tt.in[1:] + if _, err := getRegionID(b(id)); err == nil { + t.Errorf("%d:err(%s): found nil; want error", i, id) + } + continue + } + want, _ := getRegionID(b(tt.in)) + if s := want.String(); s != tt.out { + t.Errorf("%d:%s: found %q; want %q", i, tt.in, s, tt.out) + } + if len(tt.in) == 2 { + want, _ := getRegionISO2(b(tt.in)) + if s := want.String(); s != tt.out { + t.Errorf("%d:getISO2(%s): found %q; want %q", i, tt.in, s, tt.out) + } + } + } +} + +func TestRegionType(t *testing.T) { + for _, tt := range []struct { + r string + t byte + }{ + {"NL", bcp47Region | ccTLD}, + {"EU", bcp47Region | ccTLD}, // exceptionally reserved + {"AN", bcp47Region | ccTLD}, // transitionally reserved + + {"DD", bcp47Region}, // deleted in ISO, deprecated in BCP 47 + {"NT", bcp47Region}, // transitionally reserved, deprecated in BCP 47 + + {"XA", iso3166UserAssigned | bcp47Region}, + {"ZZ", iso3166UserAssigned | bcp47Region}, + {"AA", iso3166UserAssigned | bcp47Region}, + {"QO", iso3166UserAssigned | bcp47Region}, + {"QM", iso3166UserAssigned | bcp47Region}, + {"XK", iso3166UserAssigned | bcp47Region}, + + {"CT", 0}, // deleted in ISO, not in BCP 47, canonicalized in CLDR + } { + r := MustParseRegion(tt.r) + if tp := r.typ(); tp != tt.t { + t.Errorf("Type(%s): got %x; want %x", tt.r, tp, tt.t) + } + } +} + +func TestRegionISO3(t *testing.T) { + tests := []struct { + from, iso3, to string + }{ + {" ", "ZZZ", "ZZ"}, + {"000", "ZZZ", "ZZ"}, + {"AA", "AAA", ""}, + {"CT", "CTE", ""}, + {"DY", "DHY", ""}, + {"EU", "QUU", ""}, + {"HV", "HVO", ""}, + {"IC", "ZZZ", "ZZ"}, + {"JT", "JTN", ""}, + {"PZ", "PCZ", ""}, + {"QU", "QUU", "EU"}, + {"QO", "QOO", ""}, + {"YD", "YMD", ""}, + {"FQ", "ATF", "TF"}, + {"TF", "ATF", ""}, + {"FX", "FXX", ""}, + {"ZZ", "ZZZ", ""}, + {"419", "ZZZ", "ZZ"}, + } + for _, tt := range tests { + r, _ := getRegionID(b(tt.from)) + if s := r.ISO3(); s != tt.iso3 { + t.Errorf("iso3(%q): found %q; want %q", tt.from, s, tt.iso3) + } + if tt.iso3 == "" { + continue + } + want := tt.to + if tt.to == "" { + want = tt.from + } + r, _ = getRegionID(b(want)) + if id, _ := getRegionISO3(b(tt.iso3)); id != r { + t.Errorf("%s: found %q; want %q", tt.iso3, id, want) + } + } +} + +func TestRegionM49(t *testing.T) { + fromTests := []struct { + m49 int + id string + }{ + {0, ""}, + {-1, ""}, + {1000, ""}, + {10000, ""}, + + {001, "001"}, + {104, "MM"}, + {180, "CD"}, + {230, "ET"}, + {231, "ET"}, + {249, "FX"}, + {250, "FR"}, + {276, "DE"}, + {278, "DD"}, + {280, "DE"}, + {419, "419"}, + {626, "TL"}, + {736, "SD"}, + {840, "US"}, + {854, "BF"}, + {891, "CS"}, + {899, ""}, + {958, "AA"}, + {966, "QT"}, + {967, "EU"}, + {999, "ZZ"}, + } + for _, tt := range fromTests { + id, err := getRegionM49(tt.m49) + if want, have := err != nil, tt.id == ""; want != have { + t.Errorf("error(%d): have %v; want %v", tt.m49, have, want) + continue + } + r, _ := getRegionID(b(tt.id)) + if r != id { + t.Errorf("region(%d): have %s; want %s", tt.m49, id, r) + } + } + + toTests := []struct { + m49 int + id string + }{ + {0, "000"}, + {0, "IC"}, // Some codes don't have an ID + + {001, "001"}, + {104, "MM"}, + {104, "BU"}, + {180, "CD"}, + {180, "ZR"}, + {231, "ET"}, + {250, "FR"}, + {249, "FX"}, + {276, "DE"}, + {278, "DD"}, + {419, "419"}, + {626, "TL"}, + {626, "TP"}, + {729, "SD"}, + {826, "GB"}, + {840, "US"}, + {854, "BF"}, + {891, "YU"}, + {891, "CS"}, + {958, "AA"}, + {966, "QT"}, + {967, "EU"}, + {967, "QU"}, + {999, "ZZ"}, + // For codes that don't have an M49 code use the replacement value, + // if available. + {854, "HV"}, // maps to Burkino Faso + } + for _, tt := range toTests { + r, _ := getRegionID(b(tt.id)) + if r.M49() != tt.m49 { + t.Errorf("m49(%q): have %d; want %d", tt.id, r.M49(), tt.m49) + } + } +} + +func TestRegionDeprecation(t *testing.T) { + tests := []struct{ in, out string }{ + {"BU", "MM"}, + {"BUR", "MM"}, + {"CT", "KI"}, + {"DD", "DE"}, + {"DDR", "DE"}, + {"DY", "BJ"}, + {"FX", "FR"}, + {"HV", "BF"}, + {"JT", "UM"}, + {"MI", "UM"}, + {"NH", "VU"}, + {"NQ", "AQ"}, + {"PU", "UM"}, + {"PZ", "PA"}, + {"QU", "EU"}, + {"RH", "ZW"}, + {"TP", "TL"}, + {"UK", "GB"}, + {"VD", "VN"}, + {"WK", "UM"}, + {"YD", "YE"}, + {"NL", "NL"}, + } + for _, tt := range tests { + rIn, _ := getRegionID([]byte(tt.in)) + rOut, _ := getRegionISO2([]byte(tt.out)) + r := normRegion(rIn) + if rOut == rIn && r != 0 { + t.Errorf("%s: was %q; want %q", tt.in, r, tt.in) + } + if rOut != rIn && r != rOut { + t.Errorf("%s: was %q; want %q", tt.in, r, tt.out) + } + + } +} + +func TestGetScriptID(t *testing.T) { + idx := tag.Index("0000BbbbDdddEeeeZzzz\xff\xff\xff\xff") + tests := []struct { + in string + out scriptID + }{ + {" ", 0}, + {" ", 0}, + {" ", 0}, + {"", 0}, + {"Aaaa", 0}, + {"Bbbb", 1}, + {"Dddd", 2}, + {"dddd", 2}, + {"dDDD", 2}, + {"Eeee", 3}, + {"Zzzz", 4}, + } + for i, tt := range tests { + if id, err := getScriptID(idx, b(tt.in)); id != tt.out { + t.Errorf("%d:%s: found %d; want %d", i, tt.in, id, tt.out) + } else if id == 0 && err == nil { + t.Errorf("%d:%s: no error; expected one", i, tt.in) + } + } +} + +func TestIsPrivateUse(t *testing.T) { + type test struct { + s string + private bool + } + tests := []test{ + {"en", false}, + {"und", false}, + {"pzn", false}, + {"qaa", true}, + {"qtz", true}, + {"qua", false}, + } + for i, tt := range tests { + x, _ := getLangID([]byte(tt.s)) + if b := x.IsPrivateUse(); b != tt.private { + t.Errorf("%d: langID.IsPrivateUse(%s) was %v; want %v", i, tt.s, b, tt.private) + } + } + tests = []test{ + {"001", false}, + {"419", false}, + {"899", false}, + {"900", false}, + {"957", false}, + {"958", true}, + {"AA", true}, + {"AC", false}, + {"EU", false}, // CLDR grouping, exceptionally reserved in ISO. + {"QU", true}, // Canonicalizes to EU, User-assigned in ISO. + {"QO", true}, // CLDR grouping, User-assigned in ISO. + {"QA", false}, + {"QM", true}, + {"QZ", true}, + {"XA", true}, + {"XK", true}, // Assigned to Kosovo in CLDR, User-assigned in ISO. + {"XZ", true}, + {"ZW", false}, + {"ZZ", true}, + } + for i, tt := range tests { + x, _ := getRegionID([]byte(tt.s)) + if b := x.IsPrivateUse(); b != tt.private { + t.Errorf("%d: regionID.IsPrivateUse(%s) was %v; want %v", i, tt.s, b, tt.private) + } + } + tests = []test{ + {"Latn", false}, + {"Laaa", false}, // invalid + {"Qaaa", true}, + {"Qabx", true}, + {"Qaby", false}, + {"Zyyy", false}, + {"Zzzz", false}, + } + for i, tt := range tests { + x, _ := getScriptID(script, []byte(tt.s)) + if b := x.IsPrivateUse(); b != tt.private { + t.Errorf("%d: scriptID.IsPrivateUse(%s) was %v; want %v", i, tt.s, b, tt.private) + } + } +} diff --git a/vendor/golang.org/x/text/language/match_test.go b/vendor/golang.org/x/text/language/match_test.go new file mode 100644 index 000000000..8b60b07a3 --- /dev/null +++ b/vendor/golang.org/x/text/language/match_test.go @@ -0,0 +1,505 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language + +import ( + "bytes" + "flag" + "fmt" + "os" + "path" + "path/filepath" + "strings" + "testing" + + "golang.org/x/text/internal/testtext" + "golang.org/x/text/internal/ucd" +) + +var verbose = flag.Bool("verbose", false, "set to true to print the internal tables of matchers") + +func TestCompliance(t *testing.T) { + filepath.Walk("testdata", func(file string, info os.FileInfo, err error) error { + if info.IsDir() { + return nil + } + r, err := os.Open(file) + if err != nil { + t.Fatal(err) + } + ucd.Parse(r, func(p *ucd.Parser) { + name := strings.Replace(path.Join(p.String(0), p.String(1)), " ", "", -1) + if skip[name] { + return + } + t.Run(info.Name()+"/"+name, func(t *testing.T) { + supported := makeTagList(p.String(0)) + desired := makeTagList(p.String(1)) + gotCombined, index, conf := NewMatcher(supported).Match(desired...) + + gotMatch := supported[index] + wantMatch := mk(p.String(2)) + if gotMatch != wantMatch { + t.Fatalf("match: got %q; want %q (%v)", gotMatch, wantMatch, conf) + } + wantCombined, err := Raw.Parse(p.String(3)) + if err == nil && gotCombined != wantCombined { + t.Errorf("combined: got %q; want %q (%v)", gotCombined, wantCombined, conf) + } + }) + }) + return nil + }) +} + +var skip = map[string]bool{ + // TODO: bugs + // Honor the wildcard match. This may only be useful to select non-exact + // stuff. + "mul,af/nl": true, // match: got "af"; want "mul" + + // TODO: include other extensions. + // combined: got "en-GB-u-ca-buddhist-nu-arab"; want "en-GB-fonipa-t-m0-iso-i0-pinyin-u-ca-buddhist-nu-arab" + "und,en-GB-u-sd-gbsct/en-fonipa-u-nu-Arab-ca-buddhist-t-m0-iso-i0-pinyin": true, + + // Inconsistencies with Mark Davis' implementation where it is not clear + // which is better. + + // Inconsistencies in combined. I think the Go approach is more appropriate. + // We could use -u-rg- and -u-va- as alternative. + "und,fr/fr-BE-fonipa": true, // combined: got "fr"; want "fr-BE-fonipa" + "und,fr-CA/fr-BE-fonipa": true, // combined: got "fr-CA"; want "fr-BE-fonipa" + "und,fr-fonupa/fr-BE-fonipa": true, // combined: got "fr-fonupa"; want "fr-BE-fonipa" + "und,no/nn-BE-fonipa": true, // combined: got "no"; want "no-BE-fonipa" + "50,und,fr-CA-fonupa/fr-BE-fonipa": true, // combined: got "fr-CA-fonupa"; want "fr-BE-fonipa" + + // The initial number is a threshold. As we don't use scoring, we will not + // implement this. + "50,und,fr-Cyrl-CA-fonupa/fr-BE-fonipa": true, + // match: got "und"; want "fr-Cyrl-CA-fonupa" + // combined: got "und"; want "fr-Cyrl-BE-fonipa" + + // Other interesting cases to test: + // - Should same language or same script have the preference if there is + // usually no understanding of the other script? + // - More specific region in desired may replace enclosing supported. +} + +func makeTagList(s string) (tags []Tag) { + for _, s := range strings.Split(s, ",") { + tags = append(tags, mk(strings.TrimSpace(s))) + } + return tags +} + +func TestMatchStrings(t *testing.T) { + testCases := []struct { + supported string + desired string // strings separted by | + tag string + index int + }{{ + supported: "en", + desired: "", + tag: "en", + index: 0, + }, { + supported: "en", + desired: "nl", + tag: "en", + index: 0, + }, { + supported: "en,nl", + desired: "nl", + tag: "nl", + index: 1, + }, { + supported: "en,nl", + desired: "nl|en", + tag: "nl", + index: 1, + }, { + supported: "en-GB,nl", + desired: "en ; q=0.1,nl", + tag: "nl", + index: 1, + }, { + supported: "en-GB,nl", + desired: "en;q=0.005 | dk; q=0.1,nl ", + tag: "en-GB", + index: 0, + }, { + // do not match faulty tags with und + supported: "en,und", + desired: "|en", + tag: "en", + index: 0, + }} + for _, tc := range testCases { + t.Run(path.Join(tc.supported, tc.desired), func(t *testing.T) { + m := NewMatcher(makeTagList(tc.supported)) + tag, index := MatchStrings(m, strings.Split(tc.desired, "|")...) + if tag.String() != tc.tag || index != tc.index { + t.Errorf("got %v, %d; want %v, %d", tag, index, tc.tag, tc.index) + } + }) + } +} + +func TestAddLikelySubtags(t *testing.T) { + tests := []struct{ in, out string }{ + {"aa", "aa-Latn-ET"}, + {"aa-Latn", "aa-Latn-ET"}, + {"aa-Arab", "aa-Arab-ET"}, + {"aa-Arab-ER", "aa-Arab-ER"}, + {"kk", "kk-Cyrl-KZ"}, + {"kk-CN", "kk-Arab-CN"}, + {"cmn", "cmn"}, + {"zh-AU", "zh-Hant-AU"}, + {"zh-VN", "zh-Hant-VN"}, + {"zh-SG", "zh-Hans-SG"}, + {"zh-Hant", "zh-Hant-TW"}, + {"zh-Hani", "zh-Hani-CN"}, + {"und-Hani", "zh-Hani-CN"}, + {"und", "en-Latn-US"}, + {"und-GB", "en-Latn-GB"}, + {"und-CW", "pap-Latn-CW"}, + {"und-YT", "fr-Latn-YT"}, + {"und-Arab", "ar-Arab-EG"}, + {"und-AM", "hy-Armn-AM"}, + {"und-TW", "zh-Hant-TW"}, + {"und-002", "en-Latn-NG"}, + {"und-Latn-002", "en-Latn-NG"}, + {"en-Latn-002", "en-Latn-NG"}, + {"en-002", "en-Latn-NG"}, + {"en-001", "en-Latn-US"}, + {"und-003", "en-Latn-US"}, + {"und-GB", "en-Latn-GB"}, + {"Latn-001", "en-Latn-US"}, + {"en-001", "en-Latn-US"}, + {"es-419", "es-Latn-419"}, + {"he-145", "he-Hebr-IL"}, + {"ky-145", "ky-Latn-TR"}, + {"kk", "kk-Cyrl-KZ"}, + // Don't specialize duplicate and ambiguous matches. + {"kk-034", "kk-Arab-034"}, // Matches IR and AF. Both are Arab. + {"ku-145", "ku-Latn-TR"}, // Matches IQ, TR, and LB, but kk -> TR. + {"und-Arab-CC", "ms-Arab-CC"}, + {"und-Arab-GB", "ks-Arab-GB"}, + {"und-Hans-CC", "zh-Hans-CC"}, + {"und-CC", "en-Latn-CC"}, + {"sr", "sr-Cyrl-RS"}, + {"sr-151", "sr-Latn-151"}, // Matches RO and RU. + // We would like addLikelySubtags to generate the same results if the input + // only changes by adding tags that would otherwise have been added + // by the expansion. + // In other words: + // und-AA -> xx-Scrp-AA implies und-Scrp-AA -> xx-Scrp-AA + // und-AA -> xx-Scrp-AA implies xx-AA -> xx-Scrp-AA + // und-Scrp -> xx-Scrp-AA implies und-Scrp-AA -> xx-Scrp-AA + // und-Scrp -> xx-Scrp-AA implies xx-Scrp -> xx-Scrp-AA + // xx -> xx-Scrp-AA implies xx-Scrp -> xx-Scrp-AA + // xx -> xx-Scrp-AA implies xx-AA -> xx-Scrp-AA + // + // The algorithm specified in + // http://unicode.org/reports/tr35/tr35-9.html#Supplemental_Data, + // Section C.10, does not handle the first case. For example, + // the CLDR data contains an entry und-BJ -> fr-Latn-BJ, but not + // there is no rule for und-Latn-BJ. According to spec, und-Latn-BJ + // would expand to en-Latn-BJ, violating the aforementioned principle. + // We deviate from the spec by letting und-Scrp-AA expand to xx-Scrp-AA + // if a rule of the form und-AA -> xx-Scrp-AA is defined. + // Note that as of version 23, CLDR has some explicitly specified + // entries that do not conform to these rules. The implementation + // will not correct these explicit inconsistencies. A later versions of CLDR + // is supposed to fix this. + {"und-Latn-BJ", "fr-Latn-BJ"}, + {"und-Bugi-ID", "bug-Bugi-ID"}, + // regions, scripts and languages without definitions + {"und-Arab-AA", "ar-Arab-AA"}, + {"und-Afak-RE", "fr-Afak-RE"}, + {"und-Arab-GB", "ks-Arab-GB"}, + {"abp-Arab-GB", "abp-Arab-GB"}, + // script has preference over region + {"und-Arab-NL", "ar-Arab-NL"}, + {"zza", "zza-Latn-TR"}, + // preserve variants and extensions + {"de-1901", "de-Latn-DE-1901"}, + {"de-x-abc", "de-Latn-DE-x-abc"}, + {"de-1901-x-abc", "de-Latn-DE-1901-x-abc"}, + {"x-abc", "x-abc"}, // TODO: is this the desired behavior? + } + for i, tt := range tests { + in, _ := Parse(tt.in) + out, _ := Parse(tt.out) + in, _ = in.addLikelySubtags() + if in.String() != out.String() { + t.Errorf("%d: add(%s) was %s; want %s", i, tt.in, in, tt.out) + } + } +} +func TestMinimize(t *testing.T) { + tests := []struct{ in, out string }{ + {"aa", "aa"}, + {"aa-Latn", "aa"}, + {"aa-Latn-ET", "aa"}, + {"aa-ET", "aa"}, + {"aa-Arab", "aa-Arab"}, + {"aa-Arab-ER", "aa-Arab-ER"}, + {"aa-Arab-ET", "aa-Arab"}, + {"und", "und"}, + {"und-Latn", "und"}, + {"und-Latn-US", "und"}, + {"en-Latn-US", "en"}, + {"cmn", "cmn"}, + {"cmn-Hans", "cmn-Hans"}, + {"cmn-Hant", "cmn-Hant"}, + {"zh-AU", "zh-AU"}, + {"zh-VN", "zh-VN"}, + {"zh-SG", "zh-SG"}, + {"zh-Hant", "zh-Hant"}, + {"zh-Hant-TW", "zh-TW"}, + {"zh-Hans", "zh"}, + {"zh-Hani", "zh-Hani"}, + {"und-Hans", "und-Hans"}, + {"und-Hani", "und-Hani"}, + + {"und-CW", "und-CW"}, + {"und-YT", "und-YT"}, + {"und-Arab", "und-Arab"}, + {"und-AM", "und-AM"}, + {"und-Arab-CC", "und-Arab-CC"}, + {"und-CC", "und-CC"}, + {"und-Latn-BJ", "und-BJ"}, + {"und-Bugi-ID", "und-Bugi"}, + {"bug-Bugi-ID", "bug-Bugi"}, + // regions, scripts and languages without definitions + {"und-Arab-AA", "und-Arab-AA"}, + // preserve variants and extensions + {"de-Latn-1901", "de-1901"}, + {"de-Latn-x-abc", "de-x-abc"}, + {"de-DE-1901-x-abc", "de-1901-x-abc"}, + {"x-abc", "x-abc"}, // TODO: is this the desired behavior? + } + for i, tt := range tests { + in, _ := Parse(tt.in) + out, _ := Parse(tt.out) + min, _ := in.minimize() + if min.String() != out.String() { + t.Errorf("%d: min(%s) was %s; want %s", i, tt.in, min, tt.out) + } + max, _ := min.addLikelySubtags() + if x, _ := in.addLikelySubtags(); x.String() != max.String() { + t.Errorf("%d: max(min(%s)) = %s; want %s", i, tt.in, max, x) + } + } +} + +func TestRegionGroups(t *testing.T) { + testCases := []struct { + a, b string + distance uint8 + }{ + {"zh-TW", "zh-HK", 5}, + {"zh-MO", "zh-HK", 4}, + {"es-ES", "es-AR", 5}, + {"es-ES", "es", 4}, + {"es-419", "es-MX", 4}, + {"es-AR", "es-MX", 4}, + {"es-ES", "es-MX", 5}, + {"es-PT", "es-MX", 5}, + } + for _, tc := range testCases { + a := MustParse(tc.a) + aScript, _ := a.Script() + b := MustParse(tc.b) + bScript, _ := b.Script() + + if aScript != bScript { + t.Errorf("scripts differ: %q vs %q", aScript, bScript) + continue + } + d, _ := regionGroupDist(a.region, b.region, aScript.scriptID, a.lang) + if d != tc.distance { + t.Errorf("got %q; want %q", d, tc.distance) + } + } +} + +func TestIsParadigmLocale(t *testing.T) { + testCases := map[string]bool{ + "en-US": true, + "en-GB": true, + "en-VI": false, + "es-GB": false, + "es-ES": true, + "es-419": true, + } + for str, want := range testCases { + tag := Make(str) + got := isParadigmLocale(tag.lang, tag.region) + if got != want { + t.Errorf("isPL(%q) = %v; want %v", str, got, want) + } + } +} + +// Implementation of String methods for various types for debugging purposes. + +func (m *matcher) String() string { + w := &bytes.Buffer{} + fmt.Fprintln(w, "Default:", m.default_) + for tag, h := range m.index { + fmt.Fprintf(w, " %s: %v\n", tag, h) + } + return w.String() +} + +func (h *matchHeader) String() string { + w := &bytes.Buffer{} + fmt.Fprint(w, "haveTag: ") + for _, h := range h.haveTags { + fmt.Fprintf(w, "%v, ", h) + } + return w.String() +} + +func (t haveTag) String() string { + return fmt.Sprintf("%v:%d:%v:%v-%v|%v", t.tag, t.index, t.conf, t.maxRegion, t.maxScript, t.altScript) +} + +func TestBestMatchAlloc(t *testing.T) { + m := NewMatcher(makeTagList("en sr nl")) + // Go allocates when creating a list of tags from a single tag! + list := []Tag{English} + avg := testtext.AllocsPerRun(1, func() { + m.Match(list...) + }) + if avg > 0 { + t.Errorf("got %f; want 0", avg) + } +} + +var benchHave = []Tag{ + mk("en"), + mk("en-GB"), + mk("za"), + mk("zh-Hant"), + mk("zh-Hans-CN"), + mk("zh"), + mk("zh-HK"), + mk("ar-MK"), + mk("en-CA"), + mk("fr-CA"), + mk("fr-US"), + mk("fr-CH"), + mk("fr"), + mk("lt"), + mk("lv"), + mk("iw"), + mk("iw-NL"), + mk("he"), + mk("he-IT"), + mk("tlh"), + mk("ja"), + mk("ja-Jpan"), + mk("ja-Jpan-JP"), + mk("de"), + mk("de-CH"), + mk("de-AT"), + mk("de-DE"), + mk("sr"), + mk("sr-Latn"), + mk("sr-Cyrl"), + mk("sr-ME"), +} + +var benchWant = [][]Tag{ + []Tag{ + mk("en"), + }, + []Tag{ + mk("en-AU"), + mk("de-HK"), + mk("nl"), + mk("fy"), + mk("lv"), + }, + []Tag{ + mk("en-AU"), + mk("de-HK"), + mk("nl"), + mk("fy"), + }, + []Tag{ + mk("ja-Hant"), + mk("da-HK"), + mk("nl"), + mk("zh-TW"), + }, + []Tag{ + mk("ja-Hant"), + mk("da-HK"), + mk("nl"), + mk("hr"), + }, +} + +func BenchmarkMatch(b *testing.B) { + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + for _, want := range benchWant { + m.getBest(want...) + } + } +} + +func BenchmarkMatchExact(b *testing.B) { + want := mk("en") + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + m.getBest(want) + } +} + +func BenchmarkMatchAltLanguagePresent(b *testing.B) { + want := mk("hr") + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + m.getBest(want) + } +} + +func BenchmarkMatchAltLanguageNotPresent(b *testing.B) { + want := mk("nn") + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + m.getBest(want) + } +} + +func BenchmarkMatchAltScriptPresent(b *testing.B) { + want := mk("zh-Hant-CN") + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + m.getBest(want) + } +} + +func BenchmarkMatchAltScriptNotPresent(b *testing.B) { + want := mk("fr-Cyrl") + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + m.getBest(want) + } +} + +func BenchmarkMatchLimitedExact(b *testing.B) { + want := []Tag{mk("he-NL"), mk("iw-NL")} + m := newMatcher(benchHave, nil) + for i := 0; i < b.N; i++ { + m.getBest(want...) + } +} diff --git a/vendor/golang.org/x/text/language/parse_test.go b/vendor/golang.org/x/text/language/parse_test.go new file mode 100644 index 000000000..9b40eb444 --- /dev/null +++ b/vendor/golang.org/x/text/language/parse_test.go @@ -0,0 +1,517 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package language + +import ( + "bytes" + "strings" + "testing" + + "golang.org/x/text/internal/tag" +) + +type scanTest struct { + ok bool // true if scanning does not result in an error + in string + tok []string // the expected tokens +} + +var tests = []scanTest{ + {true, "", []string{}}, + {true, "1", []string{"1"}}, + {true, "en", []string{"en"}}, + {true, "root", []string{"root"}}, + {true, "maxchars", []string{"maxchars"}}, + {false, "bad/", []string{}}, + {false, "morethan8", []string{}}, + {false, "-", []string{}}, + {false, "----", []string{}}, + {false, "_", []string{}}, + {true, "en-US", []string{"en", "US"}}, + {true, "en_US", []string{"en", "US"}}, + {false, "en-US-", []string{"en", "US"}}, + {false, "en-US--", []string{"en", "US"}}, + {false, "en-US---", []string{"en", "US"}}, + {false, "en--US", []string{"en", "US"}}, + {false, "-en-US", []string{"en", "US"}}, + {false, "-en--US-", []string{"en", "US"}}, + {false, "-en--US-", []string{"en", "US"}}, + {false, "en-.-US", []string{"en", "US"}}, + {false, ".-en--US-.", []string{"en", "US"}}, + {false, "en-u.-US", []string{"en", "US"}}, + {true, "en-u1-US", []string{"en", "u1", "US"}}, + {true, "maxchar1_maxchar2-maxchar3", []string{"maxchar1", "maxchar2", "maxchar3"}}, + {false, "moreThan8-moreThan8-e", []string{"e"}}, +} + +func TestScan(t *testing.T) { + for i, tt := range tests { + scan := makeScannerString(tt.in) + for j := 0; !scan.done; j++ { + if j >= len(tt.tok) { + t.Errorf("%d: extra token %q", i, scan.token) + } else if tag.Compare(tt.tok[j], scan.token) != 0 { + t.Errorf("%d: token %d: found %q; want %q", i, j, scan.token, tt.tok[j]) + break + } + scan.scan() + } + if s := strings.Join(tt.tok, "-"); tag.Compare(s, bytes.Replace(scan.b, b("_"), b("-"), -1)) != 0 { + t.Errorf("%d: input: found %q; want %q", i, scan.b, s) + } + if (scan.err == nil) != tt.ok { + t.Errorf("%d: ok: found %v; want %v", i, scan.err == nil, tt.ok) + } + } +} + +func TestAcceptMinSize(t *testing.T) { + for i, tt := range tests { + // count number of successive tokens with a minimum size. + for sz := 1; sz <= 8; sz++ { + scan := makeScannerString(tt.in) + scan.end, scan.next = 0, 0 + end := scan.acceptMinSize(sz) + n := 0 + for i := 0; i < len(tt.tok) && len(tt.tok[i]) >= sz; i++ { + n += len(tt.tok[i]) + if i > 0 { + n++ + } + } + if end != n { + t.Errorf("%d:%d: found len %d; want %d", i, sz, end, n) + } + } + } +} + +type parseTest struct { + i int // the index of this test + in string + lang, script, region string + variants, ext string + extList []string // only used when more than one extension is present + invalid bool + rewrite bool // special rewrite not handled by parseTag + changed bool // string needed to be reformatted +} + +func parseTests() []parseTest { + tests := []parseTest{ + {in: "root", lang: "und"}, + {in: "und", lang: "und"}, + {in: "en", lang: "en"}, + {in: "xy", lang: "und", invalid: true}, + {in: "en-ZY", lang: "en", invalid: true}, + {in: "gsw", lang: "gsw"}, + {in: "sr_Latn", lang: "sr", script: "Latn"}, + {in: "af-Arab", lang: "af", script: "Arab"}, + {in: "nl-BE", lang: "nl", region: "BE"}, + {in: "es-419", lang: "es", region: "419"}, + {in: "und-001", lang: "und", region: "001"}, + {in: "de-latn-be", lang: "de", script: "Latn", region: "BE"}, + // Variants + {in: "de-1901", lang: "de", variants: "1901"}, + // Accept with unsuppressed script. + {in: "de-Latn-1901", lang: "de", script: "Latn", variants: "1901"}, + // Specialized. + {in: "sl-rozaj", lang: "sl", variants: "rozaj"}, + {in: "sl-rozaj-lipaw", lang: "sl", variants: "rozaj-lipaw"}, + {in: "sl-rozaj-biske", lang: "sl", variants: "rozaj-biske"}, + {in: "sl-rozaj-biske-1994", lang: "sl", variants: "rozaj-biske-1994"}, + {in: "sl-rozaj-1994", lang: "sl", variants: "rozaj-1994"}, + // Maximum number of variants while adhering to prefix rules. + {in: "sl-rozaj-biske-1994-alalc97-fonipa-fonupa-fonxsamp", lang: "sl", variants: "rozaj-biske-1994-alalc97-fonipa-fonupa-fonxsamp"}, + + // Sorting. + {in: "sl-1994-biske-rozaj", lang: "sl", variants: "rozaj-biske-1994", changed: true}, + {in: "sl-rozaj-biske-1994-alalc97-fonupa-fonipa-fonxsamp", lang: "sl", variants: "rozaj-biske-1994-alalc97-fonipa-fonupa-fonxsamp", changed: true}, + {in: "nl-fonxsamp-alalc97-fonipa-fonupa", lang: "nl", variants: "alalc97-fonipa-fonupa-fonxsamp", changed: true}, + + // Duplicates variants are removed, but not an error. + {in: "nl-fonupa-fonupa", lang: "nl", variants: "fonupa"}, + + // Variants that do not have correct prefixes. We still accept these. + {in: "de-Cyrl-1901", lang: "de", script: "Cyrl", variants: "1901"}, + {in: "sl-rozaj-lipaw-1994", lang: "sl", variants: "rozaj-lipaw-1994"}, + {in: "sl-1994-biske-rozaj-1994-biske-rozaj", lang: "sl", variants: "rozaj-biske-1994", changed: true}, + {in: "de-Cyrl-1901", lang: "de", script: "Cyrl", variants: "1901"}, + + // Invalid variant. + {in: "de-1902", lang: "de", variants: "", invalid: true}, + + {in: "EN_CYRL", lang: "en", script: "Cyrl"}, + // private use and extensions + {in: "x-a-b-c-d", ext: "x-a-b-c-d"}, + {in: "x_A.-B-C_D", ext: "x-b-c-d", invalid: true, changed: true}, + {in: "x-aa-bbbb-cccccccc-d", ext: "x-aa-bbbb-cccccccc-d"}, + {in: "en-c_cc-b-bbb-a-aaa", lang: "en", changed: true, extList: []string{"a-aaa", "b-bbb", "c-cc"}}, + {in: "en-x_cc-b-bbb-a-aaa", lang: "en", ext: "x-cc-b-bbb-a-aaa", changed: true}, + {in: "en-c_cc-b-bbb-a-aaa-x-x", lang: "en", changed: true, extList: []string{"a-aaa", "b-bbb", "c-cc", "x-x"}}, + {in: "en-v-c", lang: "en", ext: "", invalid: true}, + {in: "en-v-abcdefghi", lang: "en", ext: "", invalid: true}, + {in: "en-v-abc-x", lang: "en", ext: "v-abc", invalid: true}, + {in: "en-v-abc-x-", lang: "en", ext: "v-abc", invalid: true}, + {in: "en-v-abc-w-x-xx", lang: "en", extList: []string{"v-abc", "x-xx"}, invalid: true, changed: true}, + {in: "en-v-abc-w-y-yx", lang: "en", extList: []string{"v-abc", "y-yx"}, invalid: true, changed: true}, + {in: "en-v-c-abc", lang: "en", ext: "c-abc", invalid: true, changed: true}, + {in: "en-v-w-abc", lang: "en", ext: "w-abc", invalid: true, changed: true}, + {in: "en-v-x-abc", lang: "en", ext: "x-abc", invalid: true, changed: true}, + {in: "en-v-x-a", lang: "en", ext: "x-a", invalid: true, changed: true}, + {in: "en-9-aa-0-aa-z-bb-x-a", lang: "en", extList: []string{"0-aa", "9-aa", "z-bb", "x-a"}, changed: true}, + {in: "en-u-c", lang: "en", ext: "", invalid: true}, + {in: "en-u-co-phonebk", lang: "en", ext: "u-co-phonebk"}, + {in: "en-u-co-phonebk-ca", lang: "en", ext: "u-co-phonebk", invalid: true}, + {in: "en-u-nu-arabic-co-phonebk-ca", lang: "en", ext: "u-co-phonebk-nu-arabic", invalid: true, changed: true}, + {in: "en-u-nu-arabic-co-phonebk-ca-x", lang: "en", ext: "u-co-phonebk-nu-arabic", invalid: true, changed: true}, + {in: "en-u-nu-arabic-co-phonebk-ca-s", lang: "en", ext: "u-co-phonebk-nu-arabic", invalid: true, changed: true}, + {in: "en-u-nu-arabic-co-phonebk-ca-a12345678", lang: "en", ext: "u-co-phonebk-nu-arabic", invalid: true, changed: true}, + {in: "en-u-co-phonebook", lang: "en", ext: "", invalid: true}, + {in: "en-u-co-phonebook-cu-xau", lang: "en", ext: "u-cu-xau", invalid: true, changed: true}, + {in: "en-Cyrl-u-co-phonebk", lang: "en", script: "Cyrl", ext: "u-co-phonebk"}, + {in: "en-US-u-co-phonebk", lang: "en", region: "US", ext: "u-co-phonebk"}, + {in: "en-US-u-co-phonebk-cu-xau", lang: "en", region: "US", ext: "u-co-phonebk-cu-xau"}, + {in: "en-scotland-u-co-phonebk", lang: "en", variants: "scotland", ext: "u-co-phonebk"}, + {in: "en-u-cu-xua-co-phonebk", lang: "en", ext: "u-co-phonebk-cu-xua", changed: true}, + {in: "en-u-def-abc-cu-xua-co-phonebk", lang: "en", ext: "u-abc-def-co-phonebk-cu-xua", changed: true}, + {in: "en-u-def-abc", lang: "en", ext: "u-abc-def", changed: true}, + {in: "en-u-cu-xua-co-phonebk-a-cd", lang: "en", extList: []string{"a-cd", "u-co-phonebk-cu-xua"}, changed: true}, + // Invalid "u" extension. Drop invalid parts. + {in: "en-u-cu-co-phonebk", lang: "en", extList: []string{"u-co-phonebk"}, invalid: true, changed: true}, + {in: "en-u-cu-xau-co", lang: "en", extList: []string{"u-cu-xau"}, invalid: true}, + // We allow duplicate keys as the LDML spec does not explicitly prohibit it. + // TODO: Consider eliminating duplicates and returning an error. + {in: "en-u-cu-xau-co-phonebk-cu-xau", lang: "en", ext: "u-co-phonebk-cu-xau-cu-xau", changed: true}, + {in: "en-t-en-Cyrl-NL-fonipa", lang: "en", ext: "t-en-cyrl-nl-fonipa", changed: true}, + {in: "en-t-en-Cyrl-NL-fonipa-t0-abc-def", lang: "en", ext: "t-en-cyrl-nl-fonipa-t0-abc-def", changed: true}, + {in: "en-t-t0-abcd", lang: "en", ext: "t-t0-abcd"}, + // Not necessary to have changed here. + {in: "en-t-nl-abcd", lang: "en", ext: "t-nl", invalid: true}, + {in: "en-t-nl-latn", lang: "en", ext: "t-nl-latn"}, + {in: "en-t-t0-abcd-x-a", lang: "en", extList: []string{"t-t0-abcd", "x-a"}}, + // invalid + {in: "", lang: "und", invalid: true}, + {in: "-", lang: "und", invalid: true}, + {in: "x", lang: "und", invalid: true}, + {in: "x-", lang: "und", invalid: true}, + {in: "x--", lang: "und", invalid: true}, + {in: "a-a-b-c-d", lang: "und", invalid: true}, + {in: "en-", lang: "en", invalid: true}, + {in: "enne-", lang: "und", invalid: true}, + {in: "en.", lang: "und", invalid: true}, + {in: "en.-latn", lang: "und", invalid: true}, + {in: "en.-en", lang: "en", invalid: true}, + {in: "x-a-tooManyChars-c-d", ext: "x-a-c-d", invalid: true, changed: true}, + {in: "a-tooManyChars-c-d", lang: "und", invalid: true}, + // TODO: check key-value validity + // { in: "en-u-cu-xd", lang: "en", ext: "u-cu-xd", invalid: true }, + {in: "en-t-abcd", lang: "en", invalid: true}, + {in: "en-Latn-US-en", lang: "en", script: "Latn", region: "US", invalid: true}, + // rewrites (more tests in TestGrandfathered) + {in: "zh-min-nan", lang: "nan"}, + {in: "zh-yue", lang: "yue"}, + {in: "zh-xiang", lang: "hsn", rewrite: true}, + {in: "zh-guoyu", lang: "cmn", rewrite: true}, + {in: "iw", lang: "iw"}, + {in: "sgn-BE-FR", lang: "sfb", rewrite: true}, + {in: "i-klingon", lang: "tlh", rewrite: true}, + } + for i, tt := range tests { + tests[i].i = i + if tt.extList != nil { + tests[i].ext = strings.Join(tt.extList, "-") + } + if tt.ext != "" && tt.extList == nil { + tests[i].extList = []string{tt.ext} + } + } + return tests +} + +func TestParseExtensions(t *testing.T) { + for i, tt := range parseTests() { + if tt.ext == "" || tt.rewrite { + continue + } + scan := makeScannerString(tt.in) + if len(scan.b) > 1 && scan.b[1] != '-' { + scan.end = nextExtension(string(scan.b), 0) + scan.next = scan.end + 1 + scan.scan() + } + start := scan.start + scan.toLower(start, len(scan.b)) + parseExtensions(&scan) + ext := string(scan.b[start:]) + if ext != tt.ext { + t.Errorf("%d(%s): ext was %v; want %v", i, tt.in, ext, tt.ext) + } + if changed := !strings.HasPrefix(tt.in[start:], ext); changed != tt.changed { + t.Errorf("%d(%s): changed was %v; want %v", i, tt.in, changed, tt.changed) + } + } +} + +// partChecks runs checks for each part by calling the function returned by f. +func partChecks(t *testing.T, f func(*parseTest) (Tag, bool)) { + for i, tt := range parseTests() { + tag, skip := f(&tt) + if skip { + continue + } + if l, _ := getLangID(b(tt.lang)); l != tag.lang { + t.Errorf("%d: lang was %q; want %q", i, tag.lang, l) + } + if sc, _ := getScriptID(script, b(tt.script)); sc != tag.script { + t.Errorf("%d: script was %q; want %q", i, tag.script, sc) + } + if r, _ := getRegionID(b(tt.region)); r != tag.region { + t.Errorf("%d: region was %q; want %q", i, tag.region, r) + } + if tag.str == "" { + continue + } + p := int(tag.pVariant) + if p < int(tag.pExt) { + p++ + } + if s, g := tag.str[p:tag.pExt], tt.variants; s != g { + t.Errorf("%d: variants was %q; want %q", i, s, g) + } + p = int(tag.pExt) + if p > 0 && p < len(tag.str) { + p++ + } + if s, g := (tag.str)[p:], tt.ext; s != g { + t.Errorf("%d: extensions were %q; want %q", i, s, g) + } + } +} + +func TestParseTag(t *testing.T) { + partChecks(t, func(tt *parseTest) (id Tag, skip bool) { + if strings.HasPrefix(tt.in, "x-") || tt.rewrite { + return Tag{}, true + } + scan := makeScannerString(tt.in) + id, end := parseTag(&scan) + id.str = string(scan.b[:end]) + tt.ext = "" + tt.extList = []string{} + return id, false + }) +} + +func TestParse(t *testing.T) { + partChecks(t, func(tt *parseTest) (id Tag, skip bool) { + id, err := Raw.Parse(tt.in) + ext := "" + if id.str != "" { + if strings.HasPrefix(id.str, "x-") { + ext = id.str + } else if int(id.pExt) < len(id.str) && id.pExt > 0 { + ext = id.str[id.pExt+1:] + } + } + if tag, _ := Raw.Parse(id.String()); tag.String() != id.String() { + t.Errorf("%d:%s: reparse was %q; want %q", tt.i, tt.in, id.String(), tag.String()) + } + if ext != tt.ext { + t.Errorf("%d:%s: ext was %q; want %q", tt.i, tt.in, ext, tt.ext) + } + changed := id.str != "" && !strings.HasPrefix(tt.in, id.str) + if changed != tt.changed { + t.Errorf("%d:%s: changed was %v; want %v", tt.i, tt.in, changed, tt.changed) + } + if (err != nil) != tt.invalid { + t.Errorf("%d:%s: invalid was %v; want %v. Error: %v", tt.i, tt.in, err != nil, tt.invalid, err) + } + return id, false + }) +} + +func TestErrors(t *testing.T) { + mkInvalid := func(s string) error { + return mkErrInvalid([]byte(s)) + } + tests := []struct { + in string + out error + }{ + // invalid subtags. + {"ac", mkInvalid("ac")}, + {"AC", mkInvalid("ac")}, + {"aa-Uuuu", mkInvalid("Uuuu")}, + {"aa-AB", mkInvalid("AB")}, + // ill-formed wins over invalid. + {"ac-u", errSyntax}, + {"ac-u-ca", errSyntax}, + {"ac-u-ca-co-pinyin", errSyntax}, + {"noob", errSyntax}, + } + for _, tt := range tests { + _, err := Parse(tt.in) + if err != tt.out { + t.Errorf("%s: was %q; want %q", tt.in, err, tt.out) + } + } +} + +func TestCompose1(t *testing.T) { + partChecks(t, func(tt *parseTest) (id Tag, skip bool) { + l, _ := ParseBase(tt.lang) + s, _ := ParseScript(tt.script) + r, _ := ParseRegion(tt.region) + v := []Variant{} + for _, x := range strings.Split(tt.variants, "-") { + p, _ := ParseVariant(x) + v = append(v, p) + } + e := []Extension{} + for _, x := range tt.extList { + p, _ := ParseExtension(x) + e = append(e, p) + } + id, _ = Raw.Compose(l, s, r, v, e) + return id, false + }) +} + +func TestCompose2(t *testing.T) { + partChecks(t, func(tt *parseTest) (id Tag, skip bool) { + l, _ := ParseBase(tt.lang) + s, _ := ParseScript(tt.script) + r, _ := ParseRegion(tt.region) + p := []interface{}{l, s, r, s, r, l} + for _, x := range strings.Split(tt.variants, "-") { + v, _ := ParseVariant(x) + p = append(p, v) + } + for _, x := range tt.extList { + e, _ := ParseExtension(x) + p = append(p, e) + } + id, _ = Raw.Compose(p...) + return id, false + }) +} + +func TestCompose3(t *testing.T) { + partChecks(t, func(tt *parseTest) (id Tag, skip bool) { + id, _ = Raw.Parse(tt.in) + id, _ = Raw.Compose(id) + return id, false + }) +} + +func mk(s string) Tag { + return Raw.Make(s) +} + +func TestParseAcceptLanguage(t *testing.T) { + type res struct { + t Tag + q float32 + } + en := []res{{mk("en"), 1.0}} + tests := []struct { + out []res + in string + ok bool + }{ + {en, "en", true}, + {en, " en", true}, + {en, "en ", true}, + {en, " en ", true}, + {en, "en,", true}, + {en, ",en", true}, + {en, ",,,en,,,", true}, + {en, ",en;q=1", true}, + + // We allow an empty input, contrary to spec. + {nil, "", true}, + {[]res{{mk("aa"), 1}}, "aa;", true}, // allow unspecified weight + + // errors + {nil, ";", false}, + {nil, "$", false}, + {nil, "e;", false}, + {nil, "x;", false}, + {nil, "x", false}, + {nil, "ac", false}, // non-existing language + {nil, "aa;q", false}, + {nil, "aa;q=", false}, + {nil, "aa;q=.", false}, + + // odd fallbacks + { + []res{{mk("en"), 0.1}}, + " english ;q=.1", + true, + }, + { + []res{{mk("it"), 1.0}, {mk("de"), 1.0}, {mk("fr"), 1.0}}, + " italian, deutsch, french", + true, + }, + + // lists + { + []res{{mk("en"), 0.1}}, + "en;q=.1", + true, + }, + { + []res{{mk("mul"), 1.0}}, + "*", + true, + }, + { + []res{{mk("en"), 1.0}, {mk("de"), 1.0}}, + "en,de", + true, + }, + { + []res{{mk("en"), 1.0}, {mk("de"), .5}}, + "en,de;q=0.5", + true, + }, + { + []res{{mk("de"), 0.8}, {mk("en"), 0.5}}, + " en ; q = 0.5 , , de;q=0.8", + true, + }, + { + []res{{mk("en"), 1.0}, {mk("de"), 1.0}, {mk("fr"), 1.0}, {mk("tlh"), 1.0}}, + "en,de,fr,i-klingon", + true, + }, + // sorting + { + []res{{mk("tlh"), 0.4}, {mk("de"), 0.2}, {mk("fr"), 0.2}, {mk("en"), 0.1}}, + "en;q=0.1,de;q=0.2,fr;q=0.2,i-klingon;q=0.4", + true, + }, + // dropping + { + []res{{mk("fr"), 0.2}, {mk("en"), 0.1}}, + "en;q=0.1,de;q=0,fr;q=0.2,i-klingon;q=0.0", + true, + }, + } + for i, tt := range tests { + tags, qs, e := ParseAcceptLanguage(tt.in) + if e == nil != tt.ok { + t.Errorf("%d:%s:err: was %v; want %v", i, tt.in, e == nil, tt.ok) + } + for j, tag := range tags { + if out := tt.out[j]; !tag.equalTags(out.t) || qs[j] != out.q { + t.Errorf("%d:%s: was %s, %1f; want %s, %1f", i, tt.in, tag, qs[j], out.t, out.q) + break + } + } + } +} diff --git a/vendor/golang.org/x/text/runes/cond_test.go b/vendor/golang.org/x/text/runes/cond_test.go new file mode 100644 index 000000000..44cd36d0b --- /dev/null +++ b/vendor/golang.org/x/text/runes/cond_test.go @@ -0,0 +1,282 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runes + +import ( + "strings" + "testing" + "unicode" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + "golang.org/x/text/transform" +) + +var ( + toUpper = cases.Upper(language.Und) + toLower = cases.Lower(language.Und) +) + +type spanformer interface { + transform.SpanningTransformer +} + +func TestPredicate(t *testing.T) { + testConditional(t, func(rt *unicode.RangeTable, t, f spanformer) spanformer { + return If(Predicate(func(r rune) bool { + return unicode.Is(rt, r) + }), t, f) + }) +} + +func TestIn(t *testing.T) { + testConditional(t, func(rt *unicode.RangeTable, t, f spanformer) spanformer { + return If(In(rt), t, f) + }) +} + +func TestNotIn(t *testing.T) { + testConditional(t, func(rt *unicode.RangeTable, t, f spanformer) spanformer { + return If(NotIn(rt), f, t) + }) +} + +func testConditional(t *testing.T, f func(rt *unicode.RangeTable, t, f spanformer) spanformer) { + lower := f(unicode.Latin, toLower, toLower) + + for i, tt := range []transformTest{{ + desc: "empty", + szDst: large, + atEOF: true, + in: "", + out: "", + outFull: "", + t: lower, + }, { + desc: "small", + szDst: 1, + atEOF: true, + in: "B", + out: "b", + outFull: "b", + errSpan: transform.ErrEndOfSpan, + t: lower, + }, { + desc: "short dst", + szDst: 2, + atEOF: true, + in: "AAA", + out: "aa", + outFull: "aaa", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: lower, + }, { + desc: "short dst writing error", + szDst: 1, + atEOF: false, + in: "A\x80", + out: "a", + outFull: "a\x80", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: lower, + }, { + desc: "short dst writing incomplete rune", + szDst: 2, + atEOF: true, + in: "Σ\xc2", + out: "Σ", + outFull: "Σ\xc2", + err: transform.ErrShortDst, + t: f(unicode.Latin, toLower, nil), + }, { + desc: "short dst, longer", + szDst: 5, + atEOF: true, + in: "Hellø", + out: "Hell", + outFull: "Hellø", + err: transform.ErrShortDst, + // idem is used to test short buffers by forcing processing of full-rune increments. + t: f(unicode.Latin, Map(idem), nil), + }, { + desc: "short dst, longer, writing error", + szDst: 6, + atEOF: false, + in: "\x80Hello\x80", + out: "\x80Hello", + outFull: "\x80Hello\x80", + err: transform.ErrShortDst, + t: f(unicode.Latin, Map(idem), nil), + }, { + desc: "short src", + szDst: 2, + atEOF: false, + in: "A\xc2", + out: "a", + outFull: "a\xc2", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: lower, + }, { + desc: "short src no change", + szDst: 2, + atEOF: false, + in: "a\xc2", + out: "a", + outFull: "a\xc2", + err: transform.ErrShortSrc, + errSpan: transform.ErrShortSrc, + nSpan: 1, + t: lower, + }, { + desc: "invalid input, atEOF", + szDst: large, + atEOF: true, + in: "\x80", + out: "\x80", + outFull: "\x80", + t: lower, + }, { + desc: "invalid input, !atEOF", + szDst: large, + atEOF: false, + in: "\x80", + out: "\x80", + outFull: "\x80", + t: lower, + }, { + desc: "invalid input, incomplete rune atEOF", + szDst: large, + atEOF: true, + in: "\xc2", + out: "\xc2", + outFull: "\xc2", + t: lower, + }, { + desc: "nop", + szDst: large, + atEOF: true, + in: "Hello World!", + out: "Hello World!", + outFull: "Hello World!", + t: f(unicode.Latin, nil, nil), + }, { + desc: "nop in", + szDst: large, + atEOF: true, + in: "THIS IS α ΤΕΣΤ", + out: "this is α ΤΕΣΤ", + outFull: "this is α ΤΕΣΤ", + errSpan: transform.ErrEndOfSpan, + t: f(unicode.Greek, nil, toLower), + }, { + desc: "nop in latin", + szDst: large, + atEOF: true, + in: "THIS IS α ΤΕΣΤ", + out: "THIS IS α τεστ", + outFull: "THIS IS α τεστ", + errSpan: transform.ErrEndOfSpan, + t: f(unicode.Latin, nil, toLower), + }, { + desc: "nop not in", + szDst: large, + atEOF: true, + in: "THIS IS α ΤΕΣΤ", + out: "this is α ΤΕΣΤ", + outFull: "this is α ΤΕΣΤ", + errSpan: transform.ErrEndOfSpan, + t: f(unicode.Latin, toLower, nil), + }, { + desc: "pass atEOF is true when at end", + szDst: large, + atEOF: true, + in: "hello", + out: "HELLO", + outFull: "HELLO", + errSpan: transform.ErrEndOfSpan, + t: f(unicode.Latin, upperAtEOF{}, nil), + }, { + desc: "pass atEOF is true when at end of segment", + szDst: large, + atEOF: true, + in: "hello ", + out: "HELLO ", + outFull: "HELLO ", + errSpan: transform.ErrEndOfSpan, + t: f(unicode.Latin, upperAtEOF{}, nil), + }, { + desc: "don't pass atEOF is true when atEOF is false", + szDst: large, + atEOF: false, + in: "hello", + out: "", + outFull: "HELLO", + err: transform.ErrShortSrc, + errSpan: transform.ErrShortSrc, + t: f(unicode.Latin, upperAtEOF{}, nil), + }, { + desc: "pass atEOF is true when at end, no change", + szDst: large, + atEOF: true, + in: "HELLO", + out: "HELLO", + outFull: "HELLO", + t: f(unicode.Latin, upperAtEOF{}, nil), + }, { + desc: "pass atEOF is true when at end of segment, no change", + szDst: large, + atEOF: true, + in: "HELLO ", + out: "HELLO ", + outFull: "HELLO ", + t: f(unicode.Latin, upperAtEOF{}, nil), + }, { + desc: "large input ASCII", + szDst: 12000, + atEOF: false, + in: strings.Repeat("HELLO", 2000), + out: strings.Repeat("hello", 2000), + outFull: strings.Repeat("hello", 2000), + errSpan: transform.ErrEndOfSpan, + err: nil, + t: lower, + }, { + desc: "large input non-ASCII", + szDst: 12000, + atEOF: false, + in: strings.Repeat("\u3333", 2000), + out: strings.Repeat("\u3333", 2000), + outFull: strings.Repeat("\u3333", 2000), + err: nil, + t: lower, + }} { + tt.check(t, i) + } +} + +// upperAtEOF is a strange Transformer that converts text to uppercase, but only +// if atEOF is true. +type upperAtEOF struct{ transform.NopResetter } + +func (upperAtEOF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if !atEOF { + return 0, 0, transform.ErrShortSrc + } + return toUpper.Transform(dst, src, atEOF) +} + +func (upperAtEOF) Span(src []byte, atEOF bool) (n int, err error) { + if !atEOF { + return 0, transform.ErrShortSrc + } + return toUpper.Span(src, atEOF) +} + +func BenchmarkConditional(b *testing.B) { + doBench(b, If(In(unicode.Hangul), transform.Nop, transform.Nop)) +} diff --git a/vendor/golang.org/x/text/runes/example_test.go b/vendor/golang.org/x/text/runes/example_test.go new file mode 100644 index 000000000..a60bfd9d2 --- /dev/null +++ b/vendor/golang.org/x/text/runes/example_test.go @@ -0,0 +1,60 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runes_test + +import ( + "fmt" + "unicode" + + "golang.org/x/text/runes" + "golang.org/x/text/transform" + "golang.org/x/text/unicode/norm" + "golang.org/x/text/width" +) + +func ExampleRemove() { + t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) + s, _, _ := transform.String(t, "résumé") + fmt.Println(s) + + // Output: + // resume +} + +func ExampleMap() { + replaceHyphens := runes.Map(func(r rune) rune { + if unicode.Is(unicode.Hyphen, r) { + return '|' + } + return r + }) + s, _, _ := transform.String(replaceHyphens, "a-b‐c⸗d﹣e") + fmt.Println(s) + + // Output: + // a|b|c|d|e +} + +func ExampleIn() { + // Convert Latin characters to their canonical form, while keeping other + // width distinctions. + t := runes.If(runes.In(unicode.Latin), width.Fold, nil) + s, _, _ := transform.String(t, "アルアノリウ tech / アルアノリウ tech") + fmt.Println(s) + + // Output: + // アルアノリウ tech / アルアノリウ tech +} + +func ExampleIf() { + // Widen everything but ASCII. + isASCII := func(r rune) bool { return r <= unicode.MaxASCII } + t := runes.If(runes.Predicate(isASCII), nil, width.Widen) + s, _, _ := transform.String(t, "アルアノリウ tech / 中國 / 5₩") + fmt.Println(s) + + // Output: + // アルアノリウ tech / 中國 / 5₩ +} diff --git a/vendor/golang.org/x/text/runes/runes_test.go b/vendor/golang.org/x/text/runes/runes_test.go new file mode 100644 index 000000000..23c5bc952 --- /dev/null +++ b/vendor/golang.org/x/text/runes/runes_test.go @@ -0,0 +1,664 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runes + +import ( + "strings" + "testing" + "unicode/utf8" + + "golang.org/x/text/internal/testtext" + "golang.org/x/text/transform" +) + +type transformTest struct { + desc string + szDst int + atEOF bool + repl string + in string + out string // result string of first call to Transform + outFull string // transform of entire input string + err error + errSpan error + nSpan int + + t transform.SpanningTransformer +} + +const large = 10240 + +func (tt *transformTest) check(t *testing.T, i int) { + if tt.t == nil { + return + } + dst := make([]byte, tt.szDst) + src := []byte(tt.in) + nDst, nSrc, err := tt.t.Transform(dst, src, tt.atEOF) + if err != tt.err { + t.Errorf("%d:%s:error: got %v; want %v", i, tt.desc, err, tt.err) + } + if got := string(dst[:nDst]); got != tt.out { + t.Errorf("%d:%s:out: got %q; want %q", i, tt.desc, got, tt.out) + } + + // Calls tt.t.Transform for the remainder of the input. We use this to test + // the nSrc return value. + out := make([]byte, large) + n := copy(out, dst[:nDst]) + nDst, _, _ = tt.t.Transform(out[n:], src[nSrc:], true) + if got, want := string(out[:n+nDst]), tt.outFull; got != want { + t.Errorf("%d:%s:outFull: got %q; want %q", i, tt.desc, got, want) + } + + tt.t.Reset() + p := 0 + for ; p < len(tt.in) && p < len(tt.outFull) && tt.in[p] == tt.outFull[p]; p++ { + } + if tt.nSpan != 0 { + p = tt.nSpan + } + if n, err = tt.t.Span([]byte(tt.in), tt.atEOF); n != p || err != tt.errSpan { + t.Errorf("%d:%s:span: got %d, %v; want %d, %v", i, tt.desc, n, err, p, tt.errSpan) + } +} + +func idem(r rune) rune { return r } + +func TestMap(t *testing.T) { + runes := []rune{'a', 'ç', '中', '\U00012345', 'a'} + // Default mapper used for this test. + rotate := Map(func(r rune) rune { + for i, m := range runes { + if m == r { + return runes[i+1] + } + } + return r + }) + + for i, tt := range []transformTest{{ + desc: "empty", + szDst: large, + atEOF: true, + in: "", + out: "", + outFull: "", + t: rotate, + }, { + desc: "no change", + szDst: 1, + atEOF: true, + in: "b", + out: "b", + outFull: "b", + t: rotate, + }, { + desc: "short dst", + szDst: 2, + atEOF: true, + in: "aaaa", + out: "ç", + outFull: "çççç", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "short dst ascii, no change", + szDst: 2, + atEOF: true, + in: "bbb", + out: "bb", + outFull: "bbb", + err: transform.ErrShortDst, + t: rotate, + }, { + desc: "short dst writing error", + szDst: 2, + atEOF: false, + in: "a\x80", + out: "ç", + outFull: "ç\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "short dst writing incomplete rune", + szDst: 2, + atEOF: true, + in: "a\xc0", + out: "ç", + outFull: "ç\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "short dst, longer", + szDst: 5, + atEOF: true, + in: "Hellø", + out: "Hell", + outFull: "Hellø", + err: transform.ErrShortDst, + t: rotate, + }, { + desc: "short dst, single", + szDst: 1, + atEOF: false, + in: "ø", + out: "", + outFull: "ø", + err: transform.ErrShortDst, + t: Map(idem), + }, { + desc: "short dst, longer, writing error", + szDst: 8, + atEOF: false, + in: "\x80Hello\x80", + out: "\ufffdHello", + outFull: "\ufffdHello\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "short src", + szDst: 2, + atEOF: false, + in: "a\xc2", + out: "ç", + outFull: "ç\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "invalid input, atEOF", + szDst: large, + atEOF: true, + in: "\x80", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "invalid input, !atEOF", + szDst: large, + atEOF: false, + in: "\x80", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "incomplete rune !atEOF", + szDst: large, + atEOF: false, + in: "\xc2", + out: "", + outFull: "\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrShortSrc, + t: rotate, + }, { + desc: "invalid input, incomplete rune atEOF", + szDst: large, + atEOF: true, + in: "\xc2", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "misc correct", + szDst: large, + atEOF: true, + in: "a\U00012345 ç!", + out: "ça 中!", + outFull: "ça 中!", + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "misc correct and invalid", + szDst: large, + atEOF: true, + in: "Hello\x80 w\x80orl\xc0d!\xc0", + out: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", + outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "misc correct and invalid, short src", + szDst: large, + atEOF: false, + in: "Hello\x80 w\x80orl\xc0d!\xc2", + out: "Hello\ufffd w\ufffdorl\ufffdd!", + outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: rotate, + }, { + desc: "misc correct and invalid, short src, replacing RuneError", + szDst: large, + atEOF: false, + in: "Hel\ufffdlo\x80 w\x80orl\xc0d!\xc2", + out: "Hel?lo? w?orl?d!", + outFull: "Hel?lo? w?orl?d!?", + errSpan: transform.ErrEndOfSpan, + err: transform.ErrShortSrc, + t: Map(func(r rune) rune { + if r == utf8.RuneError { + return '?' + } + return r + }), + }} { + tt.check(t, i) + } +} + +func TestRemove(t *testing.T) { + remove := Remove(Predicate(func(r rune) bool { + return strings.ContainsRune("aeiou\u0300\uFF24\U00012345", r) + })) + + for i, tt := range []transformTest{ + 0: { + szDst: large, + atEOF: true, + in: "", + out: "", + outFull: "", + t: remove, + }, + 1: { + szDst: 0, + atEOF: true, + in: "aaaa", + out: "", + outFull: "", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 2: { + szDst: 1, + atEOF: true, + in: "aaaa", + out: "", + outFull: "", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 3: { + szDst: 1, + atEOF: true, + in: "baaaa", + out: "b", + outFull: "b", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 4: { + szDst: 2, + atEOF: true, + in: "açaaa", + out: "ç", + outFull: "ç", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 5: { + szDst: 2, + atEOF: true, + in: "aaaç", + out: "ç", + outFull: "ç", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 6: { + szDst: 2, + atEOF: false, + in: "a\x80", + out: "", + outFull: "\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 7: { + szDst: 1, + atEOF: true, + in: "a\xc0", + out: "", + outFull: "\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 8: { + szDst: 1, + atEOF: false, + in: "a\xc2", + out: "", + outFull: "\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 9: { + szDst: large, + atEOF: true, + in: "\x80", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 10: { + szDst: large, + atEOF: false, + in: "\x80", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 11: { + szDst: large, + atEOF: true, + in: "\xc2", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 12: { + szDst: large, + atEOF: false, + in: "\xc2", + out: "", + outFull: "\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrShortSrc, + t: remove, + }, + 13: { + szDst: large, + atEOF: true, + in: "Hello \U00012345world!", + out: "Hll wrld!", + outFull: "Hll wrld!", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 14: { + szDst: large, + atEOF: true, + in: "Hello\x80 w\x80orl\xc0d!\xc0", + out: "Hll\ufffd w\ufffdrl\ufffdd!\ufffd", + outFull: "Hll\ufffd w\ufffdrl\ufffdd!\ufffd", + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 15: { + szDst: large, + atEOF: false, + in: "Hello\x80 w\x80orl\xc0d!\xc2", + out: "Hll\ufffd w\ufffdrl\ufffdd!", + outFull: "Hll\ufffd w\ufffdrl\ufffdd!\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 16: { + szDst: large, + atEOF: false, + in: "Hel\ufffdlo\x80 w\x80orl\xc0d!\xc2", + out: "Hello world!", + outFull: "Hello world!", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: Remove(Predicate(func(r rune) bool { return r == utf8.RuneError })), + }, + 17: { + szDst: 4, + atEOF: true, + in: "Hellø", + out: "Hll", + outFull: "Hllø", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 18: { + szDst: 4, + atEOF: false, + in: "Hellø", + out: "Hll", + outFull: "Hllø", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 19: { + szDst: 8, + atEOF: false, + in: "\x80Hello\uFF24\x80", + out: "\ufffdHll", + outFull: "\ufffdHll\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: remove, + }, + 20: { + szDst: 8, + atEOF: false, + in: "Hllll", + out: "Hllll", + outFull: "Hllll", + t: remove, + }} { + tt.check(t, i) + } +} + +func TestReplaceIllFormed(t *testing.T) { + replace := ReplaceIllFormed() + + for i, tt := range []transformTest{ + 0: { + szDst: large, + atEOF: true, + in: "", + out: "", + outFull: "", + t: replace, + }, + 1: { + szDst: 1, + atEOF: true, + in: "aa", + out: "a", + outFull: "aa", + err: transform.ErrShortDst, + t: replace, + }, + 2: { + szDst: 1, + atEOF: true, + in: "a\x80", + out: "a", + outFull: "a\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 3: { + szDst: 1, + atEOF: true, + in: "a\xc2", + out: "a", + outFull: "a\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 4: { + szDst: large, + atEOF: true, + in: "\x80", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 5: { + szDst: large, + atEOF: false, + in: "\x80", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 6: { + szDst: large, + atEOF: true, + in: "\xc2", + out: "\ufffd", + outFull: "\ufffd", + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 7: { + szDst: large, + atEOF: false, + in: "\xc2", + out: "", + outFull: "\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrShortSrc, + t: replace, + }, + 8: { + szDst: large, + atEOF: true, + in: "Hello world!", + out: "Hello world!", + outFull: "Hello world!", + t: replace, + }, + 9: { + szDst: large, + atEOF: true, + in: "Hello\x80 w\x80orl\xc2d!\xc2", + out: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", + outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 10: { + szDst: large, + atEOF: false, + in: "Hello\x80 w\x80orl\xc2d!\xc2", + out: "Hello\ufffd w\ufffdorl\ufffdd!", + outFull: "Hello\ufffd w\ufffdorl\ufffdd!\ufffd", + err: transform.ErrShortSrc, + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 16: { + szDst: 10, + atEOF: false, + in: "\x80Hello\x80", + out: "\ufffdHello", + outFull: "\ufffdHello\ufffd", + err: transform.ErrShortDst, + errSpan: transform.ErrEndOfSpan, + t: replace, + }, + 17: { + szDst: 10, + atEOF: false, + in: "\ufffdHello\ufffd", + out: "\ufffdHello", + outFull: "\ufffdHello\ufffd", + err: transform.ErrShortDst, + t: replace, + }, + } { + tt.check(t, i) + } +} + +func TestMapAlloc(t *testing.T) { + if n := testtext.AllocsPerRun(3, func() { + Map(idem).Transform(nil, nil, false) + }); n > 0 { + t.Errorf("got %f; want 0", n) + } +} + +func rmNop(r rune) bool { return false } + +func TestRemoveAlloc(t *testing.T) { + if n := testtext.AllocsPerRun(3, func() { + Remove(Predicate(rmNop)).Transform(nil, nil, false) + }); n > 0 { + t.Errorf("got %f; want 0", n) + } +} + +func TestReplaceIllFormedAlloc(t *testing.T) { + if n := testtext.AllocsPerRun(3, func() { + ReplaceIllFormed().Transform(nil, nil, false) + }); n > 0 { + t.Errorf("got %f; want 0", n) + } +} + +func doBench(b *testing.B, t Transformer) { + for _, bc := range []struct{ name, data string }{ + {"ascii", testtext.ASCII}, + {"3byte", testtext.ThreeByteUTF8}, + } { + dst := make([]byte, 2*len(bc.data)) + src := []byte(bc.data) + + testtext.Bench(b, bc.name+"/transform", func(b *testing.B) { + b.SetBytes(int64(len(src))) + for i := 0; i < b.N; i++ { + t.Transform(dst, src, true) + } + }) + src = t.Bytes(src) + t.Reset() + testtext.Bench(b, bc.name+"/span", func(b *testing.B) { + b.SetBytes(int64(len(src))) + for i := 0; i < b.N; i++ { + t.Span(src, true) + } + }) + } +} + +func BenchmarkRemove(b *testing.B) { + doBench(b, Remove(Predicate(func(r rune) bool { return r == 'e' }))) +} + +func BenchmarkMapAll(b *testing.B) { + doBench(b, Map(func(r rune) rune { return 'a' })) +} + +func BenchmarkMapNone(b *testing.B) { + doBench(b, Map(func(r rune) rune { return r })) +} + +func BenchmarkReplaceIllFormed(b *testing.B) { + doBench(b, ReplaceIllFormed()) +} + +var ( + input = strings.Repeat("Thé qüick brøwn føx jumps øver the lazy døg. ", 100) +) diff --git a/vendor/golang.org/x/text/secure/bidirule/bench_test.go b/vendor/golang.org/x/text/secure/bidirule/bench_test.go new file mode 100644 index 000000000..2db922bfd --- /dev/null +++ b/vendor/golang.org/x/text/secure/bidirule/bench_test.go @@ -0,0 +1,54 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bidirule + +import ( + "testing" + + "golang.org/x/text/internal/testtext" +) + +var benchData = []struct{ name, data string }{ + {"ascii", "Scheveningen"}, + {"arabic", "دبي"}, + {"hangul", "다음과"}, +} + +func doBench(b *testing.B, fn func(b *testing.B, data string)) { + for _, d := range benchData { + testtext.Bench(b, d.name, func(b *testing.B) { fn(b, d.data) }) + } +} + +func BenchmarkSpan(b *testing.B) { + r := New() + doBench(b, func(b *testing.B, str string) { + b.SetBytes(int64(len(str))) + data := []byte(str) + for i := 0; i < b.N; i++ { + r.Reset() + r.Span(data, true) + } + }) +} + +func BenchmarkDirectionASCII(b *testing.B) { + doBench(b, func(b *testing.B, str string) { + b.SetBytes(int64(len(str))) + data := []byte(str) + for i := 0; i < b.N; i++ { + Direction(data) + } + }) +} + +func BenchmarkDirectionStringASCII(b *testing.B) { + doBench(b, func(b *testing.B, str string) { + b.SetBytes(int64(len(str))) + for i := 0; i < b.N; i++ { + DirectionString(str) + } + }) +} diff --git a/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0_test.go b/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0_test.go new file mode 100644 index 000000000..06ec5f5df --- /dev/null +++ b/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0_test.go @@ -0,0 +1,694 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.10 + +package bidirule + +import ( + "golang.org/x/text/transform" + "golang.org/x/text/unicode/bidi" +) + +var testCases = [][]ruleTest{ + // Go-specific rules. + // Invalid UTF-8 is invalid. + 0: []ruleTest{{ + in: "", + dir: bidi.LeftToRight, + }, { + in: "\x80", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 0, + }, { + in: "\xcc", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 0, + }, { + in: "abc\x80", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 3, + }, { + in: "abc\xcc", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 3, + }, { + in: "abc\xccdef", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 3, + }, { + in: "\xccdef", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 0, + }, { + in: strR + "\x80", + dir: bidi.RightToLeft, + err: ErrInvalid, + n: len(strR), + }, { + in: strR + "\xcc", + dir: bidi.RightToLeft, + err: ErrInvalid, + n: len(strR), + }, { + in: strAL + "\xcc" + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: len(strAL), + }, { + in: "\xcc" + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 0, + }}, + + // Rule 2.1: The first character must be a character with Bidi property L, + // R, or AL. If it has the R or AL property, it is an RTL label; if it has + // the L property, it is an LTR label. + 1: []ruleTest{{ + in: strL, + dir: bidi.LeftToRight, + }, { + in: strR, + dir: bidi.RightToLeft, + }, { + in: strAL, + dir: bidi.RightToLeft, + }, { + in: strAN, + dir: bidi.RightToLeft, + err: ErrInvalid, + }, { + in: strEN, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strEN), + }, { + in: strES, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strES), + }, { + in: strET, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strET), + }, { + in: strCS, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strCS), + }, { + in: strNSM, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strNSM), + }, { + in: strBN, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strBN), + }, { + in: strB, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strB), + }, { + in: strS, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strS), + }, { + in: strWS, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strWS), + }, { + in: strON, + dir: bidi.LeftToRight, + err: ErrInvalid, + n: len(strON), + }, { + in: strEN + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 3, + }, { + in: strES + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 2, + }, { + in: strET + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strCS + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strNSM + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 2, + }, { + in: strBN + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 3, + }, { + in: strB + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 3, + }, { + in: strS + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strWS + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strON + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }}, + + // Rule 2.2: In an RTL label, only characters with the Bidi properties R, + // AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. + 2: []ruleTest{{ + in: strR + strR + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strAL + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strAN + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strEN + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strES + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strCS + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strET + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strON + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strBN + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strNSM + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strL + strR, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strB + strR, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strS + strAL, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strWS + strAL, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strAL + strR + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strAL + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strAN + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strEN + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strES + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strCS + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strET + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strON + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strBN + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strNSM + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strL + strR, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strB + strR, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strS + strAL, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strWS + strAL, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }}, + + // Rule 2.3: In an RTL label, the end of the label must be a character with + // Bidi property R, AL, EN, or AN, followed by zero or more characters with + // Bidi property NSM. + 3: []ruleTest{{ + in: strR + strNSM, + dir: bidi.RightToLeft, + }, { + in: strR + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strAL + strNSM, + dir: bidi.RightToLeft, + }, { + in: strR + strEN + strNSM + strNSM, + dir: bidi.RightToLeft, + }, { + in: strR + strAN, + dir: bidi.RightToLeft, + }, { + in: strR + strES + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strES + strNSM), + err: ErrInvalid, + }, { + in: strR + strCS + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strCS + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strR + strET, + dir: bidi.RightToLeft, + n: len(strR + strET), + err: ErrInvalid, + }, { + in: strR + strON + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strON + strNSM), + err: ErrInvalid, + }, { + in: strR + strBN + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strBN + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strR + strL + strNSM, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strB + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strS, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strWS, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strAL + strNSM, + dir: bidi.RightToLeft, + }, { + in: strAL + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strAL + strNSM, + dir: bidi.RightToLeft, + }, { + in: strAL + strEN + strNSM + strNSM, + dir: bidi.RightToLeft, + }, { + in: strAL + strAN, + dir: bidi.RightToLeft, + }, { + in: strAL + strES + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strES + strNSM), + err: ErrInvalid, + }, { + in: strAL + strCS + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strCS + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strAL + strET, + dir: bidi.RightToLeft, + n: len(strAL + strET), + err: ErrInvalid, + }, { + in: strAL + strON + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strON + strNSM), + err: ErrInvalid, + }, { + in: strAL + strBN + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strBN + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strAL + strL + strNSM, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strB + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strS, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strWS, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }}, + + // Rule 2.4: In an RTL label, if an EN is present, no AN may be present, + // and vice versa. + 4: []ruleTest{{ + in: strR + strEN + strAN, + dir: bidi.RightToLeft, + n: len(strR + strEN), + err: ErrInvalid, + }, { + in: strR + strAN + strEN + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strAN), + err: ErrInvalid, + }, { + in: strAL + strEN + strAN, + dir: bidi.RightToLeft, + n: len(strAL + strEN), + err: ErrInvalid, + }, { + in: strAL + strAN + strEN + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strAN), + err: ErrInvalid, + }}, + + // Rule 2.5: In an LTR label, only characters with the Bidi properties L, + // EN, ES, CS, ET, ON, BN, or NSM are allowed. + 5: []ruleTest{{ + in: strL + strL + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strEN + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strES + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strCS + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strET + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strON + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strBN + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strNSM + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strR + strL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAL + strL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAN + strL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strB + strL, + dir: bidi.LeftToRight, + n: len(strL + strB + strL), + err: ErrInvalid, + }, { + in: strL + strB + strL + strR, + dir: bidi.RightToLeft, + n: len(strL + strB + strL), + err: ErrInvalid, + }, { + in: strL + strS + strL, + dir: bidi.LeftToRight, + n: len(strL + strS + strL), + err: ErrInvalid, + }, { + in: strL + strS + strL + strR, + dir: bidi.RightToLeft, + n: len(strL + strS + strL), + err: ErrInvalid, + }, { + in: strL + strWS + strL, + dir: bidi.LeftToRight, + n: len(strL + strWS + strL), + err: ErrInvalid, + }, { + in: strL + strWS + strL + strR, + dir: bidi.RightToLeft, + n: len(strL + strWS + strL), + err: ErrInvalid, + }}, + + // Rule 2.6: In an LTR label, the end of the label must be a character with + // Bidi property L or EN, followed by zero or more characters with Bidi + // property NSM. + 6: []ruleTest{{ + in: strL, + dir: bidi.LeftToRight, + }, { + in: strL + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strNSM + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strEN, + dir: bidi.LeftToRight, + }, { + in: strL + strEN + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strEN + strNSM + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strES, + dir: bidi.LeftToRight, + n: len(strL + strES), + err: ErrInvalid, + }, { + in: strL + strES + strR, + dir: bidi.RightToLeft, + n: len(strL + strES), + err: ErrInvalid, + }, { + in: strL + strCS, + dir: bidi.LeftToRight, + n: len(strL + strCS), + err: ErrInvalid, + }, { + in: strL + strCS + strR, + dir: bidi.RightToLeft, + n: len(strL + strCS), + err: ErrInvalid, + }, { + in: strL + strET, + dir: bidi.LeftToRight, + n: len(strL + strET), + err: ErrInvalid, + }, { + in: strL + strET + strR, + dir: bidi.RightToLeft, + n: len(strL + strET), + err: ErrInvalid, + }, { + in: strL + strON, + dir: bidi.LeftToRight, + n: len(strL + strON), + err: ErrInvalid, + }, { + in: strL + strON + strR, + dir: bidi.RightToLeft, + n: len(strL + strON), + err: ErrInvalid, + }, { + in: strL + strBN, + dir: bidi.LeftToRight, + n: len(strL + strBN), + err: ErrInvalid, + }, { + in: strL + strBN + strR, + dir: bidi.RightToLeft, + n: len(strL + strBN), + err: ErrInvalid, + }, { + in: strL + strR, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAN, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strB, + dir: bidi.LeftToRight, + n: len(strL + strB), + err: ErrInvalid, + }, { + in: strL + strB + strR, + dir: bidi.RightToLeft, + n: len(strL + strB), + err: ErrInvalid, + }, { + in: strL + strS, + dir: bidi.LeftToRight, + n: len(strL + strS), + err: ErrInvalid, + }, { + in: strL + strS + strR, + dir: bidi.RightToLeft, + n: len(strL + strS), + err: ErrInvalid, + }, { + in: strL + strWS, + dir: bidi.LeftToRight, + n: len(strL + strWS), + err: ErrInvalid, + }, { + in: strL + strWS + strR, + dir: bidi.RightToLeft, + n: len(strL + strWS), + err: ErrInvalid, + }}, + + // Incremental processing. + 9: []ruleTest{{ + in: "e\u0301", // é + dir: bidi.LeftToRight, + + pSrc: 2, + nSrc: 1, + err0: transform.ErrShortSrc, + }, { + in: "e\u1000f", // é + dir: bidi.LeftToRight, + + pSrc: 3, + nSrc: 1, + err0: transform.ErrShortSrc, + }, { + // Remain invalid once invalid. + in: strR + "ab", + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + + pSrc: len(strR) + 1, + nSrc: len(strR), + err0: ErrInvalid, + }, { + // Short destination + in: "abcdefghij", + dir: bidi.LeftToRight, + + pSrc: 10, + szDst: 5, + nSrc: 5, + err0: transform.ErrShortDst, + }, { + in: "\U000102f7", + dir: bidi.LeftToRight, + n: len("\U000102f7"), + err: ErrInvalid, + }, { + // Short destination splitting input rune + in: "e\u0301", + dir: bidi.LeftToRight, + + pSrc: 3, + szDst: 2, + nSrc: 1, + err0: transform.ErrShortDst, + }, { + // Unicode 10.0.0 IDNA test string. + in: "FAX\u2a77\U0001d186", + dir: bidi.LeftToRight, + n: len("FAX\u2a77\U0001d186"), + err: ErrInvalid, + }, { + in: "\x80\u0660", + dir: bidi.RightToLeft, + n: 0, + err: ErrInvalid, + }}, +} diff --git a/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0_test.go b/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0_test.go new file mode 100644 index 000000000..008874ed3 --- /dev/null +++ b/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0_test.go @@ -0,0 +1,668 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.10 + +package bidirule + +import ( + "golang.org/x/text/transform" + "golang.org/x/text/unicode/bidi" +) + +var testCases = [][]ruleTest{ + // Go-specific rules. + // Invalid UTF-8 is invalid. + 0: []ruleTest{{ + in: "", + dir: bidi.LeftToRight, + }, { + in: "\x80", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 0, + }, { + in: "\xcc", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 0, + }, { + in: "abc\x80", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 3, + }, { + in: "abc\xcc", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 3, + }, { + in: "abc\xccdef", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 3, + }, { + in: "\xccdef", + dir: bidi.LeftToRight, + err: ErrInvalid, + n: 0, + }, { + in: strR + "\x80", + dir: bidi.RightToLeft, + err: ErrInvalid, + n: len(strR), + }, { + in: strR + "\xcc", + dir: bidi.RightToLeft, + err: ErrInvalid, + n: len(strR), + }, { + in: strAL + "\xcc" + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: len(strAL), + }, { + in: "\xcc" + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 0, + }}, + + // Rule 2.1: The first character must be a character with Bidi property L, + // R, or AL. If it has the R or AL property, it is an RTL label; if it has + // the L property, it is an LTR label. + 1: []ruleTest{{ + in: strL, + dir: bidi.LeftToRight, + }, { + in: strR, + dir: bidi.RightToLeft, + }, { + in: strAL, + dir: bidi.RightToLeft, + }, { + in: strAN, + dir: bidi.RightToLeft, + err: ErrInvalid, + }, { + in: strEN, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strES, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strET, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strCS, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strNSM, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strBN, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strB, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strS, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strWS, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strON, + dir: bidi.LeftToRight, + err: nil, // not an RTL string + }, { + in: strEN + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 3, + }, { + in: strES + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 2, + }, { + in: strET + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strCS + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strNSM + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 2, + }, { + in: strBN + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 3, + }, { + in: strB + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 3, + }, { + in: strS + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strWS + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }, { + in: strON + strR, + dir: bidi.RightToLeft, + err: ErrInvalid, + n: 1, + }}, + + // Rule 2.2: In an RTL label, only characters with the Bidi properties R, + // AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. + 2: []ruleTest{{ + in: strR + strR + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strAL + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strAN + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strEN + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strES + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strCS + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strET + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strON + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strBN + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strNSM + strAL, + dir: bidi.RightToLeft, + }, { + in: strR + strL + strR, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strB + strR, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strS + strAL, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strWS + strAL, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strAL + strR + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strAL + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strAN + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strEN + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strES + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strCS + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strET + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strON + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strBN + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strNSM + strAL, + dir: bidi.RightToLeft, + }, { + in: strAL + strL + strR, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strB + strR, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strS + strAL, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strWS + strAL, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }}, + + // Rule 2.3: In an RTL label, the end of the label must be a character with + // Bidi property R, AL, EN, or AN, followed by zero or more characters with + // Bidi property NSM. + 3: []ruleTest{{ + in: strR + strNSM, + dir: bidi.RightToLeft, + }, { + in: strR + strR, + dir: bidi.RightToLeft, + }, { + in: strR + strAL + strNSM, + dir: bidi.RightToLeft, + }, { + in: strR + strEN + strNSM + strNSM, + dir: bidi.RightToLeft, + }, { + in: strR + strAN, + dir: bidi.RightToLeft, + }, { + in: strR + strES + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strES + strNSM), + err: ErrInvalid, + }, { + in: strR + strCS + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strCS + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strR + strET, + dir: bidi.RightToLeft, + n: len(strR + strET), + err: ErrInvalid, + }, { + in: strR + strON + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strON + strNSM), + err: ErrInvalid, + }, { + in: strR + strBN + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strBN + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strR + strL + strNSM, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strB + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strS, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strR + strWS, + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + }, { + in: strAL + strNSM, + dir: bidi.RightToLeft, + }, { + in: strAL + strR, + dir: bidi.RightToLeft, + }, { + in: strAL + strAL + strNSM, + dir: bidi.RightToLeft, + }, { + in: strAL + strEN + strNSM + strNSM, + dir: bidi.RightToLeft, + }, { + in: strAL + strAN, + dir: bidi.RightToLeft, + }, { + in: strAL + strES + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strES + strNSM), + err: ErrInvalid, + }, { + in: strAL + strCS + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strCS + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strAL + strET, + dir: bidi.RightToLeft, + n: len(strAL + strET), + err: ErrInvalid, + }, { + in: strAL + strON + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strON + strNSM), + err: ErrInvalid, + }, { + in: strAL + strBN + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strBN + strNSM + strNSM), + err: ErrInvalid, + }, { + in: strAL + strL + strNSM, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strB + strNSM + strNSM, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strS, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }, { + in: strAL + strWS, + dir: bidi.RightToLeft, + n: len(strAL), + err: ErrInvalid, + }}, + + // Rule 2.4: In an RTL label, if an EN is present, no AN may be present, + // and vice versa. + 4: []ruleTest{{ + in: strR + strEN + strAN, + dir: bidi.RightToLeft, + n: len(strR + strEN), + err: ErrInvalid, + }, { + in: strR + strAN + strEN + strNSM, + dir: bidi.RightToLeft, + n: len(strR + strAN), + err: ErrInvalid, + }, { + in: strAL + strEN + strAN, + dir: bidi.RightToLeft, + n: len(strAL + strEN), + err: ErrInvalid, + }, { + in: strAL + strAN + strEN + strNSM, + dir: bidi.RightToLeft, + n: len(strAL + strAN), + err: ErrInvalid, + }}, + + // Rule 2.5: In an LTR label, only characters with the Bidi properties L, + // EN, ES, CS, ET, ON, BN, or NSM are allowed. + 5: []ruleTest{{ + in: strL + strL + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strEN + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strES + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strCS + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strET + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strON + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strBN + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strNSM + strL, + dir: bidi.LeftToRight, + }, { + in: strL + strR + strL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAL + strL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAN + strL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strB + strL, + dir: bidi.LeftToRight, + n: len(strL + strAN + strL), + err: nil, + }, { + in: strL + strB + strL + strR, + dir: bidi.RightToLeft, + n: len(strL + strB + strL), + err: ErrInvalid, + }, { + in: strL + strS + strL, + dir: bidi.LeftToRight, + n: len(strL + strS + strL), + err: nil, + }, { + in: strL + strS + strL + strR, + dir: bidi.RightToLeft, + n: len(strL + strS + strL), + err: ErrInvalid, + }, { + in: strL + strWS + strL, + dir: bidi.LeftToRight, + n: len(strL + strWS + strL), + err: nil, + }, { + in: strL + strWS + strL + strR, + dir: bidi.RightToLeft, + n: len(strL + strWS + strL), + err: ErrInvalid, + }}, + + // Rule 2.6: In an LTR label, the end of the label must be a character with + // Bidi property L or EN, followed by zero or more characters with Bidi + // property NSM. + 6: []ruleTest{{ + in: strL, + dir: bidi.LeftToRight, + }, { + in: strL + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strNSM + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strEN, + dir: bidi.LeftToRight, + }, { + in: strL + strEN + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strEN + strNSM + strNSM, + dir: bidi.LeftToRight, + }, { + in: strL + strES, + dir: bidi.LeftToRight, + n: len(strL + strES), + err: nil, + }, { + in: strL + strES + strR, + dir: bidi.RightToLeft, + n: len(strL + strES), + err: ErrInvalid, + }, { + in: strL + strCS, + dir: bidi.LeftToRight, + n: len(strL + strCS), + err: nil, + }, { + in: strL + strCS + strR, + dir: bidi.RightToLeft, + n: len(strL + strCS), + err: ErrInvalid, + }, { + in: strL + strET, + dir: bidi.LeftToRight, + n: len(strL + strET), + err: nil, + }, { + in: strL + strET + strR, + dir: bidi.RightToLeft, + n: len(strL + strET), + err: ErrInvalid, + }, { + in: strL + strON, + dir: bidi.LeftToRight, + n: len(strL + strON), + err: nil, + }, { + in: strL + strON + strR, + dir: bidi.RightToLeft, + n: len(strL + strON), + err: ErrInvalid, + }, { + in: strL + strBN, + dir: bidi.LeftToRight, + n: len(strL + strBN), + err: nil, + }, { + in: strL + strBN + strR, + dir: bidi.RightToLeft, + n: len(strL + strBN), + err: ErrInvalid, + }, { + in: strL + strR, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAL, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strAN, + dir: bidi.RightToLeft, + n: len(strL), + err: ErrInvalid, + }, { + in: strL + strB, + dir: bidi.LeftToRight, + n: len(strL + strB), + err: nil, + }, { + in: strL + strB + strR, + dir: bidi.RightToLeft, + n: len(strL + strB), + err: ErrInvalid, + }, { + in: strL + strB, + dir: bidi.LeftToRight, + n: len(strL + strB), + err: nil, + }, { + in: strL + strB + strR, + dir: bidi.RightToLeft, + n: len(strL + strB), + err: ErrInvalid, + }, { + in: strL + strB, + dir: bidi.LeftToRight, + n: len(strL + strB), + err: nil, + }, { + in: strL + strB + strR, + dir: bidi.RightToLeft, + n: len(strL + strB), + err: ErrInvalid, + }}, + + // Incremental processing. + 9: []ruleTest{{ + in: "e\u0301", // é + dir: bidi.LeftToRight, + + pSrc: 2, + nSrc: 1, + err0: transform.ErrShortSrc, + }, { + in: "e\u1000f", // é + dir: bidi.LeftToRight, + + pSrc: 3, + nSrc: 1, + err0: transform.ErrShortSrc, + }, { + // Remain invalid once invalid. + in: strR + "ab", + dir: bidi.RightToLeft, + n: len(strR), + err: ErrInvalid, + + pSrc: len(strR) + 1, + nSrc: len(strR), + err0: ErrInvalid, + }, { + // Short destination + in: "abcdefghij", + dir: bidi.LeftToRight, + + pSrc: 10, + szDst: 5, + nSrc: 5, + err0: transform.ErrShortDst, + }, { + // Short destination splitting input rune + in: "e\u0301", + dir: bidi.LeftToRight, + + pSrc: 3, + szDst: 2, + nSrc: 1, + err0: transform.ErrShortDst, + }}, +} diff --git a/vendor/golang.org/x/text/secure/bidirule/bidirule_test.go b/vendor/golang.org/x/text/secure/bidirule/bidirule_test.go new file mode 100644 index 000000000..e8fde3383 --- /dev/null +++ b/vendor/golang.org/x/text/secure/bidirule/bidirule_test.go @@ -0,0 +1,168 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bidirule + +import ( + "fmt" + "testing" + + "golang.org/x/text/internal/testtext" + "golang.org/x/text/unicode/bidi" +) + +const ( + strL = "ABC" // Left to right - most letters in LTR scripts + strR = "עברית" // Right to left - most letters in non-Arabic RTL scripts + strAL = "دبي" // Arabic letters - most letters in the Arabic script + strEN = "123" // European Number (0-9, and Extended Arabic-Indic numbers) + strES = "+-" // European Number Separator (+ and -) + strET = "$" // European Number Terminator (currency symbols, the hash sign, the percent sign and so on) + strAN = "\u0660" // Arabic Number; this encompasses the Arabic-Indic numbers, but not the Extended Arabic-Indic numbers + strCS = "," // Common Number Separator (. , / : et al) + strNSM = "\u0300" // Nonspacing Mark - most combining accents + strBN = "\u200d" // Boundary Neutral - control characters (ZWNJ, ZWJ, and others) + strB = "\u2029" // Paragraph Separator + strS = "\u0009" // Segment Separator + strWS = " " // Whitespace, including the SPACE character + strON = "@" // Other Neutrals, including @, &, parentheses, MIDDLE DOT +) + +type ruleTest struct { + in string + dir bidi.Direction + n int // position at which the rule fails + err error + + // For tests that split the string in two. + pSrc int // number of source bytes to consume first + szDst int // size of destination buffer + nSrc int // source bytes consumed and bytes written + err0 error // error after first run +} + +func init() { + for rule, cases := range testCases { + for i, tc := range cases { + if tc.err == nil { + testCases[rule][i].n = len(tc.in) + } + } + } +} + +func doTests(t *testing.T, fn func(t *testing.T, tc ruleTest)) { + for rule, cases := range testCases { + for i, tc := range cases { + name := fmt.Sprintf("%d/%d:%+q:%s", rule, i, tc.in, tc.in) + testtext.Run(t, name, func(t *testing.T) { + fn(t, tc) + }) + } + } +} + +func TestDirection(t *testing.T) { + doTests(t, func(t *testing.T, tc ruleTest) { + dir := Direction([]byte(tc.in)) + if dir != tc.dir { + t.Errorf("dir was %v; want %v", dir, tc.dir) + } + }) +} + +func TestDirectionString(t *testing.T) { + doTests(t, func(t *testing.T, tc ruleTest) { + dir := DirectionString(tc.in) + if dir != tc.dir { + t.Errorf("dir was %v; want %v", dir, tc.dir) + } + }) +} + +func TestValid(t *testing.T) { + doTests(t, func(t *testing.T, tc ruleTest) { + got := Valid([]byte(tc.in)) + want := tc.err == nil + if got != want { + t.Fatalf("Valid: got %v; want %v", got, want) + } + + got = ValidString(tc.in) + want = tc.err == nil + if got != want { + t.Fatalf("Valid: got %v; want %v", got, want) + } + }) +} + +func TestSpan(t *testing.T) { + doTests(t, func(t *testing.T, tc ruleTest) { + // Skip tests that test for limited destination buffer size. + if tc.szDst > 0 { + return + } + + r := New() + src := []byte(tc.in) + + n, err := r.Span(src[:tc.pSrc], tc.pSrc == len(tc.in)) + if err != tc.err0 { + t.Errorf("err0 was %v; want %v", err, tc.err0) + } + if n != tc.nSrc { + t.Fatalf("nSrc was %d; want %d", n, tc.nSrc) + } + + n, err = r.Span(src[n:], true) + if err != tc.err { + t.Errorf("error was %v; want %v", err, tc.err) + } + if got := n + tc.nSrc; got != tc.n { + t.Errorf("n was %d; want %d", got, tc.n) + } + }) +} + +func TestTransform(t *testing.T) { + doTests(t, func(t *testing.T, tc ruleTest) { + r := New() + + src := []byte(tc.in) + dst := make([]byte, len(tc.in)) + if tc.szDst > 0 { + dst = make([]byte, tc.szDst) + } + + // First transform operates on a zero-length string for most tests. + nDst, nSrc, err := r.Transform(dst, src[:tc.pSrc], tc.pSrc == len(tc.in)) + if err != tc.err0 { + t.Errorf("err0 was %v; want %v", err, tc.err0) + } + if nDst != nSrc { + t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc) + } + if nSrc != tc.nSrc { + t.Fatalf("nSrc was %d; want %d", nSrc, tc.nSrc) + } + + dst1 := make([]byte, len(tc.in)) + copy(dst1, dst[:nDst]) + + nDst, nSrc, err = r.Transform(dst1[nDst:], src[nSrc:], true) + if err != tc.err { + t.Errorf("error was %v; want %v", err, tc.err) + } + if nDst != nSrc { + t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc) + } + n := nSrc + tc.nSrc + if n != tc.n { + t.Fatalf("n was %d; want %d", n, tc.n) + } + if got, want := string(dst1[:n]), tc.in[:tc.n]; got != want { + t.Errorf("got %+q; want %+q", got, want) + } + }) +} diff --git a/vendor/golang.org/x/text/secure/doc.go b/vendor/golang.org/x/text/secure/doc.go new file mode 100644 index 000000000..e531c3543 --- /dev/null +++ b/vendor/golang.org/x/text/secure/doc.go @@ -0,0 +1,6 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// secure is a repository of text security related packages. +package secure // import "golang.org/x/text/secure" diff --git a/vendor/golang.org/x/text/transform/examples_test.go b/vendor/golang.org/x/text/transform/examples_test.go new file mode 100644 index 000000000..f2e284dba --- /dev/null +++ b/vendor/golang.org/x/text/transform/examples_test.go @@ -0,0 +1,37 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transform_test + +import ( + "fmt" + "unicode" + + "golang.org/x/text/transform" + "golang.org/x/text/unicode/norm" +) + +func ExampleRemoveFunc() { + input := []byte(`tschüß; до свидания`) + + b := make([]byte, len(input)) + + t := transform.RemoveFunc(unicode.IsSpace) + n, _, _ := t.Transform(b, input, true) + fmt.Println(string(b[:n])) + + t = transform.RemoveFunc(func(r rune) bool { + return !unicode.Is(unicode.Latin, r) + }) + n, _, _ = t.Transform(b, input, true) + fmt.Println(string(b[:n])) + + n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true) + fmt.Println(string(b[:n])) + + // Output: + // tschüß;досвидания + // tschüß + // tschuß +} diff --git a/vendor/golang.org/x/text/transform/transform_test.go b/vendor/golang.org/x/text/transform/transform_test.go new file mode 100644 index 000000000..771633d1d --- /dev/null +++ b/vendor/golang.org/x/text/transform/transform_test.go @@ -0,0 +1,1317 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transform + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "strconv" + "strings" + "testing" + "time" + "unicode/utf8" + + "golang.org/x/text/internal/testtext" +) + +type lowerCaseASCII struct{ NopResetter } + +func (lowerCaseASCII) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + dst[i] = c + } + return n, n, err +} + +// lowerCaseASCIILookahead lowercases the string and reports ErrShortSrc as long +// as the input is not atEOF. +type lowerCaseASCIILookahead struct{ NopResetter } + +func (lowerCaseASCIILookahead) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + dst[i] = c + } + if !atEOF { + err = ErrShortSrc + } + return n, n, err +} + +var errYouMentionedX = errors.New("you mentioned X") + +type dontMentionX struct{ NopResetter } + +func (dontMentionX) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := len(src) + if n > len(dst) { + n, err = len(dst), ErrShortDst + } + for i, c := range src[:n] { + if c == 'X' { + return i, i, errYouMentionedX + } + dst[i] = c + } + return n, n, err +} + +var errAtEnd = errors.New("error after all text") + +type errorAtEnd struct{ NopResetter } + +func (errorAtEnd) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := copy(dst, src) + if n < len(src) { + return n, n, ErrShortDst + } + if atEOF { + return n, n, errAtEnd + } + return n, n, nil +} + +type replaceWithConstant struct { + replacement string + written int +} + +func (t *replaceWithConstant) Reset() { + t.written = 0 +} + +func (t *replaceWithConstant) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if atEOF { + nDst = copy(dst, t.replacement[t.written:]) + t.written += nDst + if t.written < len(t.replacement) { + err = ErrShortDst + } + } + return nDst, len(src), err +} + +type addAnXAtTheEnd struct{ NopResetter } + +func (addAnXAtTheEnd) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + n := copy(dst, src) + if n < len(src) { + return n, n, ErrShortDst + } + if !atEOF { + return n, n, nil + } + if len(dst) == n { + return n, n, ErrShortDst + } + dst[n] = 'X' + return n + 1, n, nil +} + +// doublerAtEOF is a strange Transformer that transforms "this" to "tthhiiss", +// but only if atEOF is true. +type doublerAtEOF struct{ NopResetter } + +func (doublerAtEOF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if !atEOF { + return 0, 0, ErrShortSrc + } + for i, c := range src { + if 2*i+2 >= len(dst) { + return 2 * i, i, ErrShortDst + } + dst[2*i+0] = c + dst[2*i+1] = c + } + return 2 * len(src), len(src), nil +} + +// rleDecode and rleEncode implement a toy run-length encoding: "aabbbbbbbbbb" +// is encoded as "2a10b". The decoding is assumed to not contain any numbers. + +type rleDecode struct{ NopResetter } + +func (rleDecode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { +loop: + for len(src) > 0 { + n := 0 + for i, c := range src { + if '0' <= c && c <= '9' { + n = 10*n + int(c-'0') + continue + } + if i == 0 { + return nDst, nSrc, errors.New("rleDecode: bad input") + } + if n > len(dst) { + return nDst, nSrc, ErrShortDst + } + for j := 0; j < n; j++ { + dst[j] = c + } + dst, src = dst[n:], src[i+1:] + nDst, nSrc = nDst+n, nSrc+i+1 + continue loop + } + if atEOF { + return nDst, nSrc, errors.New("rleDecode: bad input") + } + return nDst, nSrc, ErrShortSrc + } + return nDst, nSrc, nil +} + +type rleEncode struct { + NopResetter + + // allowStutter means that "xxxxxxxx" can be encoded as "5x3x" + // instead of always as "8x". + allowStutter bool +} + +func (e rleEncode) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + for len(src) > 0 { + n, c0 := len(src), src[0] + for i, c := range src[1:] { + if c != c0 { + n = i + 1 + break + } + } + if n == len(src) && !atEOF && !e.allowStutter { + return nDst, nSrc, ErrShortSrc + } + s := strconv.Itoa(n) + if len(s) >= len(dst) { + return nDst, nSrc, ErrShortDst + } + copy(dst, s) + dst[len(s)] = c0 + dst, src = dst[len(s)+1:], src[n:] + nDst, nSrc = nDst+len(s)+1, nSrc+n + } + return nDst, nSrc, nil +} + +// trickler consumes all input bytes, but writes a single byte at a time to dst. +type trickler []byte + +func (t *trickler) Reset() { + *t = nil +} + +func (t *trickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + *t = append(*t, src...) + if len(*t) == 0 { + return 0, 0, nil + } + if len(dst) == 0 { + return 0, len(src), ErrShortDst + } + dst[0] = (*t)[0] + *t = (*t)[1:] + if len(*t) > 0 { + err = ErrShortDst + } + return 1, len(src), err +} + +// delayedTrickler is like trickler, but delays writing output to dst. This is +// highly unlikely to be relevant in practice, but it seems like a good idea +// to have some tolerance as long as progress can be detected. +type delayedTrickler []byte + +func (t *delayedTrickler) Reset() { + *t = nil +} + +func (t *delayedTrickler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { + if len(*t) > 0 && len(dst) > 0 { + dst[0] = (*t)[0] + *t = (*t)[1:] + nDst = 1 + } + *t = append(*t, src...) + if len(*t) > 0 { + err = ErrShortDst + } + return nDst, len(src), err +} + +type testCase struct { + desc string + t Transformer + src string + dstSize int + srcSize int + ioSize int + wantStr string + wantErr error + wantIter int // number of iterations taken; 0 means we don't care. +} + +func (t testCase) String() string { + return tstr(t.t) + "; " + t.desc +} + +func tstr(t Transformer) string { + if stringer, ok := t.(fmt.Stringer); ok { + return stringer.String() + } + s := fmt.Sprintf("%T", t) + return s[1+strings.Index(s, "."):] +} + +func (c chain) String() string { + buf := &bytes.Buffer{} + buf.WriteString("Chain(") + for i, l := range c.link[:len(c.link)-1] { + if i != 0 { + fmt.Fprint(buf, ", ") + } + buf.WriteString(tstr(l.t)) + } + buf.WriteString(")") + return buf.String() +} + +var testCases = []testCase{ + { + desc: "empty", + t: lowerCaseASCII{}, + src: "", + dstSize: 100, + srcSize: 100, + wantStr: "", + }, + + { + desc: "basic", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small dst", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small src", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "small buffers", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "very small buffers", + t: lowerCaseASCII{}, + src: "Hello WORLD.", + dstSize: 1, + srcSize: 1, + wantStr: "hello world.", + }, + + { + desc: "small dst with lookahead", + t: lowerCaseASCIILookahead{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 100, + wantStr: "hello world.", + }, + + { + desc: "small src with lookahead", + t: lowerCaseASCIILookahead{}, + src: "Hello WORLD.", + dstSize: 100, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "small buffers with lookahead", + t: lowerCaseASCIILookahead{}, + src: "Hello WORLD.", + dstSize: 3, + srcSize: 4, + wantStr: "hello world.", + }, + + { + desc: "very small buffers with lookahead", + t: lowerCaseASCIILookahead{}, + src: "Hello WORLD.", + dstSize: 1, + srcSize: 2, + wantStr: "hello world.", + }, + + { + desc: "user error", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 100, + srcSize: 100, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "user error at end", + t: errorAtEnd{}, + src: "All goes well until it doesn't.", + dstSize: 100, + srcSize: 100, + wantStr: "All goes well until it doesn't.", + wantErr: errAtEnd, + }, + + { + desc: "user error at end, incremental", + t: errorAtEnd{}, + src: "All goes well until it doesn't.", + dstSize: 10, + srcSize: 10, + wantStr: "All goes well until it doesn't.", + wantErr: errAtEnd, + }, + + { + desc: "replace entire non-empty string with one byte", + t: &replaceWithConstant{replacement: "X"}, + src: "none of this will be copied", + dstSize: 1, + srcSize: 10, + wantStr: "X", + }, + + { + desc: "replace entire empty string with one byte", + t: &replaceWithConstant{replacement: "X"}, + src: "", + dstSize: 1, + srcSize: 10, + wantStr: "X", + }, + + { + desc: "replace entire empty string with seven bytes", + t: &replaceWithConstant{replacement: "ABCDEFG"}, + src: "", + dstSize: 3, + srcSize: 10, + wantStr: "ABCDEFG", + }, + + { + desc: "add an X (initialBufSize-1)", + t: addAnXAtTheEnd{}, + src: aaa[:initialBufSize-1], + dstSize: 10, + srcSize: 10, + wantStr: aaa[:initialBufSize-1] + "X", + }, + + { + desc: "add an X (initialBufSize+0)", + t: addAnXAtTheEnd{}, + src: aaa[:initialBufSize+0], + dstSize: 10, + srcSize: 10, + wantStr: aaa[:initialBufSize+0] + "X", + }, + + { + desc: "add an X (initialBufSize+1)", + t: addAnXAtTheEnd{}, + src: aaa[:initialBufSize+1], + dstSize: 10, + srcSize: 10, + wantStr: aaa[:initialBufSize+1] + "X", + }, + + { + desc: "small buffers", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 10, + srcSize: 10, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "very small buffers", + t: dontMentionX{}, + src: "The First Rule of Transform Club: don't mention Mister X, ever.", + dstSize: 1, + srcSize: 1, + wantStr: "The First Rule of Transform Club: don't mention Mister ", + wantErr: errYouMentionedX, + }, + + { + desc: "only transform at EOF", + t: doublerAtEOF{}, + src: "this", + dstSize: 100, + srcSize: 100, + wantStr: "tthhiiss", + }, + + { + desc: "basic", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 100, + wantStr: "abbcccddddddddddeeeeeeeeeeeg", + }, + + { + desc: "long", + t: rleDecode{}, + src: "12a23b34c45d56e99z", + dstSize: 100, + srcSize: 100, + wantStr: strings.Repeat("a", 12) + + strings.Repeat("b", 23) + + strings.Repeat("c", 34) + + strings.Repeat("d", 45) + + strings.Repeat("e", 56) + + strings.Repeat("z", 99), + }, + + { + desc: "tight buffers", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 11, + srcSize: 3, + wantStr: "abbcccddddddddddeeeeeeeeeeeg", + }, + + { + desc: "short dst", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 10, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: ErrShortDst, + }, + + { + desc: "short src", + t: rleDecode{}, + src: "1a2b3c10d11e0f1g", + dstSize: 11, + srcSize: 2, + ioSize: 2, + wantStr: "abbccc", + wantErr: ErrShortSrc, + }, + + { + desc: "basic", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b3c10d11e1g", + }, + + { + desc: "long", + t: rleEncode{}, + src: strings.Repeat("a", 12) + + strings.Repeat("b", 23) + + strings.Repeat("c", 34) + + strings.Repeat("d", 45) + + strings.Repeat("e", 56) + + strings.Repeat("z", 99), + dstSize: 100, + srcSize: 100, + wantStr: "12a23b34c45d56e99z", + }, + + { + desc: "tight buffers", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 12, + wantStr: "1a2b3c10d11e1g", + }, + + { + desc: "short dst", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 2, + srcSize: 12, + wantStr: "1a2b3c", + wantErr: ErrShortDst, + }, + + { + desc: "short src", + t: rleEncode{}, + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 11, + ioSize: 11, + wantStr: "1a2b3c10d", + wantErr: ErrShortSrc, + }, + + { + desc: "allowStutter = false", + t: rleEncode{allowStutter: false}, + src: "aaaabbbbbbbbccccddddd", + dstSize: 10, + srcSize: 10, + wantStr: "4a8b4c5d", + }, + + { + desc: "allowStutter = true", + t: rleEncode{allowStutter: true}, + src: "aaaabbbbbbbbccccddddd", + dstSize: 10, + srcSize: 10, + ioSize: 10, + wantStr: "4a6b2b4c4d1d", + }, + + { + desc: "trickler", + t: &trickler{}, + src: "abcdefghijklm", + dstSize: 3, + srcSize: 15, + wantStr: "abcdefghijklm", + }, + + { + desc: "delayedTrickler", + t: &delayedTrickler{}, + src: "abcdefghijklm", + dstSize: 3, + srcSize: 15, + wantStr: "abcdefghijklm", + }, +} + +func TestReader(t *testing.T) { + for _, tc := range testCases { + testtext.Run(t, tc.desc, func(t *testing.T) { + r := NewReader(strings.NewReader(tc.src), tc.t) + // Differently sized dst and src buffers are not part of the + // exported API. We override them manually. + r.dst = make([]byte, tc.dstSize) + r.src = make([]byte, tc.srcSize) + got, err := ioutil.ReadAll(r) + str := string(got) + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("\ngot %q, %v\nwant %q, %v", str, err, tc.wantStr, tc.wantErr) + } + }) + } +} + +func TestWriter(t *testing.T) { + tests := append(testCases, chainTests()...) + for _, tc := range tests { + sizes := []int{1, 2, 3, 4, 5, 10, 100, 1000} + if tc.ioSize > 0 { + sizes = []int{tc.ioSize} + } + for _, sz := range sizes { + testtext.Run(t, fmt.Sprintf("%s/%d", tc.desc, sz), func(t *testing.T) { + bb := &bytes.Buffer{} + w := NewWriter(bb, tc.t) + // Differently sized dst and src buffers are not part of the + // exported API. We override them manually. + w.dst = make([]byte, tc.dstSize) + w.src = make([]byte, tc.srcSize) + src := make([]byte, sz) + var err error + for b := tc.src; len(b) > 0 && err == nil; { + n := copy(src, b) + b = b[n:] + m := 0 + m, err = w.Write(src[:n]) + if m != n && err == nil { + t.Errorf("did not consume all bytes %d < %d", m, n) + } + } + if err == nil { + err = w.Close() + } + str := bb.String() + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("\ngot %q, %v\nwant %q, %v", str, err, tc.wantStr, tc.wantErr) + } + }) + } + } +} + +func TestNop(t *testing.T) { + testCases := []struct { + str string + dstSize int + err error + }{ + {"", 0, nil}, + {"", 10, nil}, + {"a", 0, ErrShortDst}, + {"a", 1, nil}, + {"a", 10, nil}, + } + for i, tc := range testCases { + dst := make([]byte, tc.dstSize) + nDst, nSrc, err := Nop.Transform(dst, []byte(tc.str), true) + want := tc.str + if tc.dstSize < len(want) { + want = want[:tc.dstSize] + } + if got := string(dst[:nDst]); got != want || err != tc.err || nSrc != nDst { + t.Errorf("%d:\ngot %q, %d, %v\nwant %q, %d, %v", i, got, nSrc, err, want, nDst, tc.err) + } + } +} + +func TestDiscard(t *testing.T) { + testCases := []struct { + str string + dstSize int + }{ + {"", 0}, + {"", 10}, + {"a", 0}, + {"ab", 10}, + } + for i, tc := range testCases { + nDst, nSrc, err := Discard.Transform(make([]byte, tc.dstSize), []byte(tc.str), true) + if nDst != 0 || nSrc != len(tc.str) || err != nil { + t.Errorf("%d:\ngot %q, %d, %v\nwant 0, %d, nil", i, nDst, nSrc, err, len(tc.str)) + } + } +} + +// mkChain creates a Chain transformer. x must be alternating between transformer +// and bufSize, like T, (sz, T)* +func mkChain(x ...interface{}) *chain { + t := []Transformer{} + for i := 0; i < len(x); i += 2 { + t = append(t, x[i].(Transformer)) + } + c := Chain(t...).(*chain) + for i, j := 1, 1; i < len(x); i, j = i+2, j+1 { + c.link[j].b = make([]byte, x[i].(int)) + } + return c +} + +func chainTests() []testCase { + return []testCase{ + { + desc: "nil error", + t: mkChain(rleEncode{}, 100, lowerCaseASCII{}), + src: "ABB", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b", + wantErr: nil, + wantIter: 1, + }, + + { + desc: "short dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}), + src: "1a2b3c10d11e0f1g", + dstSize: 10, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: ErrShortDst, + }, + + { + desc: "short internal dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop), + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: errShortInternal, + }, + + { + desc: "short internal dst buffer from input", + t: mkChain(rleDecode{}, 10, Nop), + src: "1a2b3c10d11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "abbcccdddddddddd", + wantErr: errShortInternal, + }, + + { + desc: "empty short internal dst buffer", + t: mkChain(lowerCaseASCII{}, 3, rleDecode{}, 10, Nop), + src: "4a7b11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "aaaabbbbbbb", + wantErr: errShortInternal, + }, + + { + desc: "empty short internal dst buffer from input", + t: mkChain(rleDecode{}, 10, Nop), + src: "4a7b11e0f1g", + dstSize: 100, + srcSize: 3, + wantStr: "aaaabbbbbbb", + wantErr: errShortInternal, + }, + + { + desc: "short internal src buffer after full dst buffer", + t: mkChain(Nop, 5, rleEncode{}, 10, Nop), + src: "cccccddddd", + dstSize: 100, + srcSize: 100, + wantStr: "", + wantErr: errShortInternal, + wantIter: 1, + }, + + { + desc: "short internal src buffer after short dst buffer; test lastFull", + t: mkChain(rleDecode{}, 5, rleEncode{}, 4, Nop), + src: "2a1b4c6d", + dstSize: 100, + srcSize: 100, + wantStr: "2a1b", + wantErr: errShortInternal, + }, + + { + desc: "short internal src buffer after successful complete fill", + t: mkChain(Nop, 3, rleDecode{}), + src: "123a4b", + dstSize: 4, + srcSize: 3, + wantStr: "", + wantErr: errShortInternal, + wantIter: 1, + }, + + { + desc: "short internal src buffer after short dst buffer; test lastFull", + t: mkChain(rleDecode{}, 5, rleEncode{}), + src: "2a1b4c6d", + dstSize: 4, + srcSize: 100, + wantStr: "2a1b", + wantErr: errShortInternal, + }, + + { + desc: "short src buffer", + t: mkChain(rleEncode{}, 5, Nop), + src: "abbcccddddeeeee", + dstSize: 4, + srcSize: 4, + ioSize: 4, + wantStr: "1a2b3c", + wantErr: ErrShortSrc, + }, + + { + desc: "process all in one go", + t: mkChain(rleEncode{}, 5, Nop), + src: "abbcccddddeeeeeffffff", + dstSize: 100, + srcSize: 100, + wantStr: "1a2b3c4d5e6f", + wantErr: nil, + wantIter: 1, + }, + + { + desc: "complete processing downstream after error", + t: mkChain(dontMentionX{}, 2, rleDecode{}, 5, Nop), + src: "3a4b5eX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "aaabbbbeeeee", + wantErr: errYouMentionedX, + }, + + { + desc: "return downstream fatal errors first (followed by short dst)", + t: mkChain(dontMentionX{}, 8, rleDecode{}, 4, Nop), + src: "3a4b5eX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "aaabbbb", + wantErr: errShortInternal, + }, + + { + desc: "return downstream fatal errors first (followed by short src)", + t: mkChain(dontMentionX{}, 5, Nop, 1, rleDecode{}), + src: "1a5bX", + dstSize: 100, + srcSize: 100, + ioSize: 100, + wantStr: "", + wantErr: errShortInternal, + }, + + { + desc: "short internal", + t: mkChain(Nop, 11, rleEncode{}, 3, Nop), + src: "abbcccddddddddddeeeeeeeeeeeg", + dstSize: 3, + srcSize: 100, + wantStr: "1a2b3c10d", + wantErr: errShortInternal, + }, + } +} + +func doTransform(tc testCase) (res string, iter int, err error) { + tc.t.Reset() + dst := make([]byte, tc.dstSize) + out, in := make([]byte, 0, 2*len(tc.src)), []byte(tc.src) + for { + iter++ + src, atEOF := in, true + if len(src) > tc.srcSize { + src, atEOF = src[:tc.srcSize], false + } + nDst, nSrc, err := tc.t.Transform(dst, src, atEOF) + out = append(out, dst[:nDst]...) + in = in[nSrc:] + switch { + case err == nil && len(in) != 0: + case err == ErrShortSrc && nSrc > 0: + case err == ErrShortDst && (nDst > 0 || nSrc > 0): + default: + return string(out), iter, err + } + } +} + +func TestChain(t *testing.T) { + if c, ok := Chain().(nop); !ok { + t.Errorf("empty chain: %v; want Nop", c) + } + + // Test Chain for a single Transformer. + for _, tc := range testCases { + tc.t = Chain(tc.t) + str, _, err := doTransform(tc) + if str != tc.wantStr || err != tc.wantErr { + t.Errorf("%s:\ngot %q, %v\nwant %q, %v", tc, str, err, tc.wantStr, tc.wantErr) + } + } + + tests := chainTests() + sizes := []int{1, 2, 3, 4, 5, 7, 10, 100, 1000} + addTest := func(tc testCase, t *chain) { + if t.link[0].t != tc.t && tc.wantErr == ErrShortSrc { + tc.wantErr = errShortInternal + } + if t.link[len(t.link)-2].t != tc.t && tc.wantErr == ErrShortDst { + tc.wantErr = errShortInternal + } + tc.t = t + tests = append(tests, tc) + } + for _, tc := range testCases { + for _, sz := range sizes { + tt := tc + tt.dstSize = sz + addTest(tt, mkChain(tc.t, tc.dstSize, Nop)) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 2, Nop)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop)) + if sz >= tc.dstSize && (tc.wantErr != ErrShortDst || sz == tc.dstSize) { + addTest(tt, mkChain(Nop, tc.srcSize, tc.t)) + addTest(tt, mkChain(Nop, 100, Nop, tc.srcSize, tc.t)) + } + } + } + for _, tc := range testCases { + tt := tc + tt.dstSize = 1 + tt.wantStr = "" + addTest(tt, mkChain(tc.t, tc.dstSize, Discard)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Discard)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, tc.dstSize, Discard)) + } + for _, tc := range testCases { + tt := tc + tt.dstSize = 100 + tt.wantStr = strings.Replace(tc.src, "0f", "", -1) + // Chain encoders and decoders. + if _, ok := tc.t.(rleEncode); ok && tc.wantErr == nil { + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 1000, rleDecode{})) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, tc.dstSize, rleDecode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{})) + // decoding needs larger destinations + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, rleDecode{}, 100, Nop)) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleDecode{}, 100, Nop)) + } else if _, ok := tc.t.(rleDecode); ok && tc.wantErr == nil { + // The internal buffer size may need to be the sum of the maximum segment + // size of the two encoders! + addTest(tt, mkChain(tc.t, 2*tc.dstSize, rleEncode{})) + addTest(tt, mkChain(tc.t, tc.dstSize, Nop, 101, rleEncode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 100, rleEncode{})) + addTest(tt, mkChain(Nop, tc.srcSize, tc.t, tc.dstSize, Nop, 200, rleEncode{}, 100, Nop)) + } + } + for _, tc := range tests { + str, iter, err := doTransform(tc) + mi := tc.wantIter != 0 && tc.wantIter != iter + if str != tc.wantStr || err != tc.wantErr || mi { + t.Errorf("%s:\ngot iter:%d, %q, %v\nwant iter:%d, %q, %v", tc, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr) + } + break + } +} + +func TestRemoveFunc(t *testing.T) { + filter := RemoveFunc(func(r rune) bool { + return strings.IndexRune("ab\u0300\u1234,", r) != -1 + }) + tests := []testCase{ + { + src: ",", + wantStr: "", + }, + + { + src: "c", + wantStr: "c", + }, + + { + src: "\u2345", + wantStr: "\u2345", + }, + + { + src: "tschüß", + wantStr: "tschüß", + }, + + { + src: ",до,свидания,", + wantStr: "досвидания", + }, + + { + src: "a\xbd\xb2=\xbc ⌘", + wantStr: "\uFFFD\uFFFD=\uFFFD ⌘", + }, + + { + // If we didn't replace illegal bytes with RuneError, the result + // would be \u0300 or the code would need to be more complex. + src: "\xcc\u0300\x80", + wantStr: "\uFFFD\uFFFD", + }, + + { + src: "\xcc\u0300\x80", + dstSize: 3, + wantStr: "\uFFFD\uFFFD", + wantIter: 2, + }, + + { + // Test a long buffer greater than the internal buffer size + src: "hello\xcc\xcc\xccworld", + srcSize: 13, + wantStr: "hello\uFFFD\uFFFD\uFFFDworld", + wantIter: 1, + }, + + { + src: "\u2345", + dstSize: 2, + wantStr: "", + wantErr: ErrShortDst, + }, + + { + src: "\xcc", + dstSize: 2, + wantStr: "", + wantErr: ErrShortDst, + }, + + { + src: "\u0300", + dstSize: 2, + srcSize: 1, + wantStr: "", + wantErr: ErrShortSrc, + }, + + { + t: RemoveFunc(func(r rune) bool { + return r == utf8.RuneError + }), + src: "\xcc\u0300\x80", + wantStr: "\u0300", + }, + } + + for _, tc := range tests { + tc.desc = tc.src + if tc.t == nil { + tc.t = filter + } + if tc.dstSize == 0 { + tc.dstSize = 100 + } + if tc.srcSize == 0 { + tc.srcSize = 100 + } + str, iter, err := doTransform(tc) + mi := tc.wantIter != 0 && tc.wantIter != iter + if str != tc.wantStr || err != tc.wantErr || mi { + t.Errorf("%+q:\ngot iter:%d, %+q, %v\nwant iter:%d, %+q, %v", tc.src, iter, str, err, tc.wantIter, tc.wantStr, tc.wantErr) + } + + tc.src = str + idem, _, _ := doTransform(tc) + if str != idem { + t.Errorf("%+q: found %+q; want %+q", tc.src, idem, str) + } + } +} + +func testString(t *testing.T, f func(Transformer, string) (string, int, error)) { + for _, tt := range append(testCases, chainTests()...) { + if tt.desc == "allowStutter = true" { + // We don't have control over the buffer size, so we eliminate tests + // that depend on a specific buffer size being set. + continue + } + if tt.wantErr == ErrShortDst || tt.wantErr == ErrShortSrc { + // The result string will be different. + continue + } + testtext.Run(t, tt.desc, func(t *testing.T) { + got, n, err := f(tt.t, tt.src) + if tt.wantErr != err { + t.Errorf("error: got %v; want %v", err, tt.wantErr) + } + // Check that err == nil implies that n == len(tt.src). Note that vice + // versa isn't necessarily true. + if err == nil && n != len(tt.src) { + t.Errorf("err == nil: got %d bytes, want %d", n, err) + } + if got != tt.wantStr { + t.Errorf("string: got %q; want %q", got, tt.wantStr) + } + }) + } +} + +func TestBytes(t *testing.T) { + testString(t, func(z Transformer, s string) (string, int, error) { + b, n, err := Bytes(z, []byte(s)) + return string(b), n, err + }) +} + +func TestAppend(t *testing.T) { + // Create a bunch of subtests for different buffer sizes. + testCases := [][]byte{ + nil, + make([]byte, 0, 0), + make([]byte, 0, 1), + make([]byte, 1, 1), + make([]byte, 1, 5), + make([]byte, 100, 100), + make([]byte, 100, 200), + } + for _, tc := range testCases { + testString(t, func(z Transformer, s string) (string, int, error) { + b, n, err := Append(z, tc, []byte(s)) + return string(b[len(tc):]), n, err + }) + } +} + +func TestString(t *testing.T) { + testtext.Run(t, "transform", func(t *testing.T) { testString(t, String) }) + + // Overrun the internal destination buffer. + for i, s := range []string{ + aaa[:1*initialBufSize-1], + aaa[:1*initialBufSize+0], + aaa[:1*initialBufSize+1], + AAA[:1*initialBufSize-1], + AAA[:1*initialBufSize+0], + AAA[:1*initialBufSize+1], + AAA[:2*initialBufSize-1], + AAA[:2*initialBufSize+0], + AAA[:2*initialBufSize+1], + aaa[:1*initialBufSize-2] + "A", + aaa[:1*initialBufSize-1] + "A", + aaa[:1*initialBufSize+0] + "A", + aaa[:1*initialBufSize+1] + "A", + } { + testtext.Run(t, fmt.Sprint("dst buffer test using lower/", i), func(t *testing.T) { + got, _, _ := String(lowerCaseASCII{}, s) + if want := strings.ToLower(s); got != want { + t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want)) + } + }) + } + + // Overrun the internal source buffer. + for i, s := range []string{ + aaa[:1*initialBufSize-1], + aaa[:1*initialBufSize+0], + aaa[:1*initialBufSize+1], + aaa[:2*initialBufSize+1], + aaa[:2*initialBufSize+0], + aaa[:2*initialBufSize+1], + } { + testtext.Run(t, fmt.Sprint("src buffer test using rleEncode/", i), func(t *testing.T) { + got, _, _ := String(rleEncode{}, s) + if want := fmt.Sprintf("%da", len(s)); got != want { + t.Errorf("got %s (%d); want %s (%d)", got, len(got), want, len(want)) + } + }) + } + + // Test allocations for non-changing strings. + // Note we still need to allocate a single buffer. + for i, s := range []string{ + "", + "123456789", + aaa[:initialBufSize-1], + aaa[:initialBufSize+0], + aaa[:initialBufSize+1], + aaa[:10*initialBufSize], + } { + testtext.Run(t, fmt.Sprint("alloc/", i), func(t *testing.T) { + if n := testtext.AllocsPerRun(5, func() { String(&lowerCaseASCIILookahead{}, s) }); n > 1 { + t.Errorf("#allocs was %f; want 1", n) + } + }) + } +} + +// TestBytesAllocation tests that buffer growth stays limited with the trickler +// transformer, which behaves oddly but within spec. In case buffer growth is +// not correctly handled, the test will either panic with a failed allocation or +// thrash. To ensure the tests terminate under the last condition, we time out +// after some sufficiently long period of time. +func TestBytesAllocation(t *testing.T) { + done := make(chan bool) + go func() { + in := bytes.Repeat([]byte{'a'}, 1000) + tr := trickler(make([]byte, 1)) + Bytes(&tr, in) + done <- true + }() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Error("time out, likely due to excessive allocation") + } +} + +// TestStringAllocation tests that buffer growth stays limited with the trickler +// transformer, which behaves oddly but within spec. In case buffer growth is +// not correctly handled, the test will either panic with a failed allocation or +// thrash. To ensure the tests terminate under the last condition, we time out +// after some sufficiently long period of time. +func TestStringAllocation(t *testing.T) { + done := make(chan bool) + go func() { + tr := trickler(make([]byte, 1)) + String(&tr, aaa[:1000]) + done <- true + }() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Error("time out, likely due to excessive allocation") + } +} + +func BenchmarkStringLowerEmpty(b *testing.B) { + for i := 0; i < b.N; i++ { + String(&lowerCaseASCIILookahead{}, "") + } +} + +func BenchmarkStringLowerIdentical(b *testing.B) { + for i := 0; i < b.N; i++ { + String(&lowerCaseASCIILookahead{}, aaa[:4096]) + } +} + +func BenchmarkStringLowerChanged(b *testing.B) { + for i := 0; i < b.N; i++ { + String(&lowerCaseASCIILookahead{}, AAA[:4096]) + } +} + +var ( + aaa = strings.Repeat("a", 4096) + AAA = strings.Repeat("A", 4096) +) diff --git a/vendor/golang.org/x/text/unicode/bidi/core_test.go b/vendor/golang.org/x/text/unicode/bidi/core_test.go new file mode 100644 index 000000000..f28d386c8 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/core_test.go @@ -0,0 +1,224 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bidi + +import ( + "flag" + "fmt" + "log" + "strconv" + "strings" + "testing" + + "golang.org/x/text/internal/gen" + "golang.org/x/text/internal/testtext" + "golang.org/x/text/internal/ucd" + "golang.org/x/text/unicode/norm" +) + +var testLevels = flag.Bool("levels", false, "enable testing of levels") + +// TestBidiCore performs the tests in BidiTest.txt. +// See http://www.unicode.org/Public/UCD/latest/ucd/BidiTest.txt. +func TestBidiCore(t *testing.T) { + testtext.SkipIfNotLong(t) + + r := gen.OpenUCDFile("BidiTest.txt") + defer r.Close() + + var wantLevels, wantOrder []string + p := ucd.New(r, ucd.Part(func(p *ucd.Parser) { + s := strings.Split(p.String(0), ":") + switch s[0] { + case "Levels": + wantLevels = strings.Fields(s[1]) + case "Reorder": + wantOrder = strings.Fields(s[1]) + default: + log.Fatalf("Unknown part %q.", s[0]) + } + })) + + for p.Next() { + types := []Class{} + for _, s := range p.Strings(0) { + types = append(types, bidiClass[s]) + } + // We ignore the bracketing part of the algorithm. + pairTypes := make([]bracketType, len(types)) + pairValues := make([]rune, len(types)) + + for i := uint(0); i < 3; i++ { + if p.Uint(1)&(1<<i) == 0 { + continue + } + lev := level(int(i) - 1) + par := newParagraph(types, pairTypes, pairValues, lev) + + if *testLevels { + levels := par.getLevels([]int{len(types)}) + for i, s := range wantLevels { + if s == "x" { + continue + } + l, _ := strconv.ParseUint(s, 10, 8) + if level(l)&1 != levels[i]&1 { + t.Errorf("%s:%d:levels: got %v; want %v", p.String(0), lev, levels, wantLevels) + break + } + } + } + + order := par.getReordering([]int{len(types)}) + gotOrder := filterOrder(types, order) + if got, want := fmt.Sprint(gotOrder), fmt.Sprint(wantOrder); got != want { + t.Errorf("%s:%d:order: got %v; want %v\noriginal %v", p.String(0), lev, got, want, order) + } + } + } + if err := p.Err(); err != nil { + log.Fatal(err) + } +} + +var removeClasses = map[Class]bool{ + LRO: true, + RLO: true, + RLE: true, + LRE: true, + PDF: true, + BN: true, +} + +// TestBidiCharacters performs the tests in BidiCharacterTest.txt. +// See http://www.unicode.org/Public/UCD/latest/ucd/BidiCharacterTest.txt +func TestBidiCharacters(t *testing.T) { + testtext.SkipIfNotLong(t) + + ucd.Parse(gen.OpenUCDFile("BidiCharacterTest.txt"), func(p *ucd.Parser) { + var ( + types []Class + pairTypes []bracketType + pairValues []rune + parLevel level + + wantLevel = level(p.Int(2)) + wantLevels = p.Strings(3) + wantVisualOrder = p.Strings(4) + ) + + switch l := p.Int(1); l { + case 0, 1: + parLevel = level(l) + case 2: + parLevel = implicitLevel + default: + // Spec says to ignore unknown parts. + } + + runes := p.Runes(0) + + for _, r := range runes { + // Assign the bracket type. + if d := norm.NFKD.PropertiesString(string(r)).Decomposition(); d != nil { + r = []rune(string(d))[0] + } + p, _ := LookupRune(r) + + // Assign the class for this rune. + types = append(types, p.Class()) + + switch { + case !p.IsBracket(): + pairTypes = append(pairTypes, bpNone) + pairValues = append(pairValues, 0) + case p.IsOpeningBracket(): + pairTypes = append(pairTypes, bpOpen) + pairValues = append(pairValues, r) + default: + pairTypes = append(pairTypes, bpClose) + pairValues = append(pairValues, p.reverseBracket(r)) + } + } + par := newParagraph(types, pairTypes, pairValues, parLevel) + + // Test results: + if got := par.embeddingLevel; got != wantLevel { + t.Errorf("%v:level: got %d; want %d", string(runes), got, wantLevel) + } + + if *testLevels { + gotLevels := getLevelStrings(types, par.getLevels([]int{len(types)})) + if got, want := fmt.Sprint(gotLevels), fmt.Sprint(wantLevels); got != want { + t.Errorf("%04X %q:%d: got %v; want %v\nval: %x\npair: %v", runes, string(runes), parLevel, got, want, pairValues, pairTypes) + } + } + + order := par.getReordering([]int{len(types)}) + order = filterOrder(types, order) + if got, want := fmt.Sprint(order), fmt.Sprint(wantVisualOrder); got != want { + t.Errorf("%04X %q:%d: got %v; want %v\ngot order: %s", runes, string(runes), parLevel, got, want, reorder(runes, order)) + } + }) +} + +func getLevelStrings(cl []Class, levels []level) []string { + var results []string + for i, l := range levels { + if !removeClasses[cl[i]] { + results = append(results, fmt.Sprint(l)) + } else { + results = append(results, "x") + } + } + return results +} + +func filterOrder(cl []Class, order []int) []int { + no := []int{} + for _, o := range order { + if !removeClasses[cl[o]] { + no = append(no, o) + } + } + return no +} + +func reorder(r []rune, order []int) string { + nr := make([]rune, len(order)) + for i, o := range order { + nr[i] = r[o] + } + return string(nr) +} + +// bidiClass names and codes taken from class "bc" in +// http://www.unicode.org/Public/8.0.0/ucd/PropertyValueAliases.txt +var bidiClass = map[string]Class{ + "AL": AL, // classArabicLetter, + "AN": AN, // classArabicNumber, + "B": B, // classParagraphSeparator, + "BN": BN, // classBoundaryNeutral, + "CS": CS, // classCommonSeparator, + "EN": EN, // classEuropeanNumber, + "ES": ES, // classEuropeanSeparator, + "ET": ET, // classEuropeanTerminator, + "L": L, // classLeftToRight, + "NSM": NSM, // classNonspacingMark, + "ON": ON, // classOtherNeutral, + "R": R, // classRightToLeft, + "S": S, // classSegmentSeparator, + "WS": WS, // classWhiteSpace, + + "LRO": LRO, // classLeftToRightOverride, + "RLO": RLO, // classRightToLeftOverride, + "LRE": LRE, // classLeftToRightEmbedding, + "RLE": RLE, // classRightToLeftEmbedding, + "PDF": PDF, // classPopDirectionalFormat, + "LRI": LRI, // classLeftToRightIsolate, + "RLI": RLI, // classRightToLeftIsolate, + "FSI": FSI, // classFirstStrongIsolate, + "PDI": PDI, // classPopDirectionalIsolate, +} diff --git a/vendor/golang.org/x/text/unicode/bidi/ranges_test.go b/vendor/golang.org/x/text/unicode/bidi/ranges_test.go new file mode 100644 index 000000000..bfaecd502 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/ranges_test.go @@ -0,0 +1,53 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package bidi + +import ( + "unicode" + + "golang.org/x/text/internal/gen" + "golang.org/x/text/internal/ucd" + "golang.org/x/text/unicode/rangetable" +) + +// These tables are hand-extracted from: +// http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedBidiClass.txt +func visitDefaults(fn func(r rune, c Class)) { + // first write default values for ranges listed above. + visitRunes(fn, AL, []rune{ + 0x0600, 0x07BF, // Arabic + 0x08A0, 0x08FF, // Arabic Extended-A + 0xFB50, 0xFDCF, // Arabic Presentation Forms + 0xFDF0, 0xFDFF, + 0xFE70, 0xFEFF, + 0x0001EE00, 0x0001EEFF, // Arabic Mathematical Alpha Symbols + }) + visitRunes(fn, R, []rune{ + 0x0590, 0x05FF, // Hebrew + 0x07C0, 0x089F, // Nko et al. + 0xFB1D, 0xFB4F, + 0x00010800, 0x00010FFF, // Cypriot Syllabary et. al. + 0x0001E800, 0x0001EDFF, + 0x0001EF00, 0x0001EFFF, + }) + visitRunes(fn, ET, []rune{ // European Terminator + 0x20A0, 0x20Cf, // Currency symbols + }) + rangetable.Visit(unicode.Noncharacter_Code_Point, func(r rune) { + fn(r, BN) // Boundary Neutral + }) + ucd.Parse(gen.OpenUCDFile("DerivedCoreProperties.txt"), func(p *ucd.Parser) { + if p.String(1) == "Default_Ignorable_Code_Point" { + fn(p.Rune(0), BN) // Boundary Neutral + } + }) +} + +func visitRunes(fn func(r rune, c Class), c Class, runes []rune) { + for i := 0; i < len(runes); i += 2 { + lo, hi := runes[i], runes[i+1] + for j := lo; j <= hi; j++ { + fn(j, c) + } + } +} diff --git a/vendor/golang.org/x/text/unicode/bidi/tables_test.go b/vendor/golang.org/x/text/unicode/bidi/tables_test.go new file mode 100644 index 000000000..356a4a58d --- /dev/null +++ b/vendor/golang.org/x/text/unicode/bidi/tables_test.go @@ -0,0 +1,82 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bidi + +import ( + "testing" + + "golang.org/x/text/internal/gen" + "golang.org/x/text/internal/testtext" + "golang.org/x/text/internal/ucd" +) + +var labels = []string{ + AL: "AL", + AN: "AN", + B: "B", + BN: "BN", + CS: "CS", + EN: "EN", + ES: "ES", + ET: "ET", + L: "L", + NSM: "NSM", + ON: "ON", + R: "R", + S: "S", + WS: "WS", + + LRO: "LRO", + RLO: "RLO", + LRE: "LRE", + RLE: "RLE", + PDF: "PDF", + LRI: "LRI", + RLI: "RLI", + FSI: "FSI", + PDI: "PDI", +} + +func TestTables(t *testing.T) { + testtext.SkipIfNotLong(t) + + ucd.Parse(gen.OpenUCDFile("BidiBrackets.txt"), func(p *ucd.Parser) { + r1 := p.Rune(0) + want := p.Rune(1) + + e, _ := LookupRune(r1) + if got := e.reverseBracket(r1); got != want { + t.Errorf("Reverse(%U) = %U; want %U", r1, got, want) + } + }) + + done := map[rune]bool{} + test := func(name string, r rune, want string) { + str := string(r) + e, _ := LookupString(str) + if got := labels[e.Class()]; got != want { + t.Errorf("%s:%U: got %s; want %s", name, r, got, want) + } + if e2, sz := LookupRune(r); e != e2 || sz != len(str) { + t.Errorf("LookupRune(%U) = %v, %d; want %v, %d", r, e2, e, sz, len(str)) + } + if e2, sz := Lookup([]byte(str)); e != e2 || sz != len(str) { + t.Errorf("Lookup(%U) = %v, %d; want %v, %d", r, e2, e, sz, len(str)) + } + done[r] = true + } + + // Insert the derived BiDi properties. + ucd.Parse(gen.OpenUCDFile("extracted/DerivedBidiClass.txt"), func(p *ucd.Parser) { + r := p.Rune(0) + test("derived", r, p.String(1)) + }) + visitDefaults(func(r rune, c Class) { + if !done[r] { + test("default", r, labels[c]) + } + }) + +} diff --git a/vendor/golang.org/x/text/unicode/cldr/cldr_test.go b/vendor/golang.org/x/text/unicode/cldr/cldr_test.go new file mode 100644 index 000000000..951028d7e --- /dev/null +++ b/vendor/golang.org/x/text/unicode/cldr/cldr_test.go @@ -0,0 +1,27 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cldr + +import "testing" + +func TestParseDraft(t *testing.T) { + tests := []struct { + in string + draft Draft + err bool + }{ + {"unconfirmed", Unconfirmed, false}, + {"provisional", Provisional, false}, + {"contributed", Contributed, false}, + {"approved", Approved, false}, + {"", Approved, false}, + {"foo", Approved, true}, + } + for _, tt := range tests { + if d, err := ParseDraft(tt.in); d != tt.draft || (err != nil) != tt.err { + t.Errorf("%q: was %v, %v; want %v, %v", tt.in, d, err != nil, tt.draft, tt.err) + } + } +} diff --git a/vendor/golang.org/x/text/unicode/cldr/collate_test.go b/vendor/golang.org/x/text/unicode/cldr/collate_test.go new file mode 100644 index 000000000..f6721639a --- /dev/null +++ b/vendor/golang.org/x/text/unicode/cldr/collate_test.go @@ -0,0 +1,275 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cldr + +import ( + "fmt" + "strings" + "testing" +) + +// A recorder implements the RuleProcessor interface, whereby its methods +// simply record the invocations. +type recorder struct { + calls []string +} + +func (r *recorder) Reset(anchor string, before int) error { + if before > 5 { + return fmt.Errorf("before %d > 5", before) + } + r.calls = append(r.calls, fmt.Sprintf("R:%s-%d", anchor, before)) + return nil +} + +func (r *recorder) Insert(level int, str, context, extend string) error { + s := fmt.Sprintf("O:%d:%s", level, str) + if context != "" { + s += "|" + context + } + if extend != "" { + s += "/" + extend + } + r.calls = append(r.calls, s) + return nil +} + +func (r *recorder) Index(id string) { + r.calls = append(r.calls, fmt.Sprintf("I:%s", id)) +} + +func (r *recorder) Error(err error) { + r.calls = append(r.calls, fmt.Sprintf("E:%v", err)) +} + +func TestRuleProcessor(t *testing.T) { + for _, tt := range []struct { + desc string + in string + out string + }{ + {desc: "empty"}, + {desc: "whitespace and comments only", + in: ` + + + # adsfads +# adfadf + `, + }, + { + desc: "reset anchor", + in: ` + & a + &b # + & [ before 3 ] c + & [before 4] d & ee + & [first tertiary ignorable] + &'g' + & 'h''h'h'h' + &'\u0069' # LATIN SMALL LETTER I + `, + out: ` + R:a-0 + R:b-0 + R:c-3 + R:d-4 + R:ee-0 + R:<first tertiary ignorable/>-0 + R:g-0 + R:hhhh-0 + R:i-0 + `, + }, + { + desc: "ordering", + in: ` + & 0 + < 1 <<''2# +<<< 3'3''33'3# + <<<<4 + = 5 << 6 | s + <<<< 7 / z + << 8'' | s / ch + `, + out: ` + R:0-0 + O:1:1 + O:2:'2 + O:3:33333 + O:4:4 + O:5:5 + O:2:6|s + O:4:7/z + O:2:8'|s/ch + `, + }, + { + desc: "index", + in: "< '\ufdd0'A", + out: "I:A", + }, + { + desc: "sequence", + in: ` + & 0 + <<* 1234 + <* a-cde-f + =* q-q + `, + out: ` + R:0-0 + O:2:1 + O:2:2 + O:2:3 + O:2:4 + O:1:a + O:1:b + O:1:c + O:1:d + O:1:e + O:1:f + O:5:q + `, + }, + { + desc: "compact", + in: "&B<t<<<T<s<<<S<e<<<E", + out: ` + R:B-0 + O:1:t + O:3:T + O:1:s + O:3:S + O:1:e + O:3:E + `, + }, + { + desc: "err operator", + in: "a", + out: "E:1: illegal operator 'a'", + }, + { + desc: "err line number", + in: `& a + << b + a`, + out: ` + R:a-0 + O:2:b + E:3: illegal operator 'a'`, + }, + { + desc: "err empty anchor", + in: " & ", + out: "E:1: missing string", + }, + { + desc: "err anchor invalid special 1", + in: " & [ foo ", + out: "E:1: unmatched bracket", + }, + { + desc: "err anchor invalid special 2", + in: "&[", + out: "E:1: unmatched bracket", + }, + { + desc: "err anchor invalid before 1", + in: "&[before a]", + out: `E:1: strconv.ParseUint: parsing "a": invalid syntax`, + }, + { + desc: "err anchor invalid before 2", + in: "&[before 12]", + out: `E:1: strconv.ParseUint: parsing "12": value out of range`, + }, + { + desc: "err anchor invalid before 3", + in: "&[before 2]", + out: "E:1: missing string", + }, + { + desc: "err anchor invalid before 4", + in: "&[before 6] a", + out: "E:1: before 6 > 5", + }, + { + desc: "err empty order", + in: " < ", + out: "E:1: missing string", + }, + { + desc: "err empty identity", + in: " = ", + out: "E:1: missing string", + }, + { + desc: "err empty context", + in: " < a | ", + out: "E:1: missing string after context", + }, + { + desc: "err empty extend", + in: " < a / ", + out: "E:1: missing string after extension", + }, + { + desc: "err empty sequence", + in: " <* ", + out: "E:1: empty sequence", + }, + { + desc: "err sequence 1", + in: " <* -a", + out: "E:1: range without starter value", + }, + { + desc: "err sequence 3", + in: " <* a-a-b", + out: `O:1:a + E:1: range without starter value + `, + }, + { + desc: "err sequence 3", + in: " <* b-a", + out: `O:1:b + E:1: invalid range 'b'-'a' + `, + }, + { + desc: "err unmatched quote", + in: " < 'b", + out: ` E:1: unmatched single quote + `, + }, + } { + rec := &recorder{} + err := Collation{ + Cr: []*Common{ + {hidden: hidden{CharData: tt.in}}, + }, + }.Process(rec) + if err != nil { + rec.Error(err) + } + got := rec.calls + want := strings.Split(strings.TrimSpace(tt.out), "\n") + if tt.out == "" { + want = nil + } + if len(got) != len(want) { + t.Errorf("%s: nResults: got %d; want %d", tt.desc, len(got), len(want)) + continue + } + for i, g := range got { + if want := strings.TrimSpace(want[i]); g != want { + t.Errorf("%s:%d: got %q; want %q", tt.desc, i, g, want) + } + } + } +} diff --git a/vendor/golang.org/x/text/unicode/cldr/data_test.go b/vendor/golang.org/x/text/unicode/cldr/data_test.go new file mode 100644 index 000000000..166218962 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/cldr/data_test.go @@ -0,0 +1,186 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cldr + +// This file contains test data. + +import ( + "io" + "strings" +) + +type testLoader struct { +} + +func (t testLoader) Len() int { + return len(testFiles) +} + +func (t testLoader) Path(i int) string { + return testPaths[i] +} + +func (t testLoader) Reader(i int) (io.ReadCloser, error) { + return &reader{*strings.NewReader(testFiles[i])}, nil +} + +// reader adds a dummy Close method to strings.Reader so that it +// satisfies the io.ReadCloser interface. +type reader struct { + strings.Reader +} + +func (r reader) Close() error { + return nil +} + +var ( + testFiles = []string{de_xml, gsw_xml, root_xml} + testPaths = []string{ + "common/main/de.xml", + "common/main/gsw.xml", + "common/main/root.xml", + } +) + +var root_xml = `<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd"> +<ldml> + <identity> + <language type="root"/> + <generation date="now"/> + </identity> + <characters> + <exemplarCharacters>[]</exemplarCharacters> + <exemplarCharacters type="auxiliary">[]</exemplarCharacters> + <exemplarCharacters type="punctuation">[\- ‐ – — … ' ‘ ‚ &quot; “ „ \&amp; #]</exemplarCharacters> + <ellipsis type="final">{0}…</ellipsis> + <ellipsis type="initial">…{0}</ellipsis> + <moreInformation>?</moreInformation> + </characters> + <dates> + <calendars> + <default choice="gregorian"/> + <calendar type="buddhist"> + <months> + <alias source="locale" path="../../calendar[@type='gregorian']/months"/> + </months> + </calendar> + <calendar type="chinese"> + <months> + <alias source="locale" path="../../calendar[@type='gregorian']/months"/> + </months> + </calendar> + <calendar type="gregorian"> + <months> + <default choice="format"/> + <monthContext type="format"> + <default choice="wide"/> + <monthWidth type="narrow"> + <alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/> + </monthWidth> + <monthWidth type="wide"> + <month type="1">11</month> + <month type="2">22</month> + <month type="3">33</month> + <month type="4">44</month> + </monthWidth> + </monthContext> + <monthContext type="stand-alone"> + <monthWidth type="narrow"> + <month type="1">1</month> + <month type="2">2</month> + <month type="3">3</month> + <month type="4">4</month> + </monthWidth> + <monthWidth type="wide"> + <alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/> + </monthWidth> + </monthContext> + </months> + </calendar> + </calendars> + </dates> +</ldml> +` + +var de_xml = `<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd"> +<ldml> + <identity> + <language type="de"/> + </identity> + <characters> + <exemplarCharacters>[a ä b c d e ö p q r s ß t u ü v w x y z]</exemplarCharacters> + <exemplarCharacters type="auxiliary">[á à ă]</exemplarCharacters> + <exemplarCharacters type="index">[A B C D E F G H Z]</exemplarCharacters> + <ellipsis type="final">{0} …</ellipsis> + <ellipsis type="initial">… {0}</ellipsis> + <moreInformation>?</moreInformation> + <stopwords> + <stopwordList type="collation" draft="provisional">der die das</stopwordList> + </stopwords> + </characters> + <dates> + <calendars> + <calendar type="buddhist"> + <months> + <monthContext type="format"> + <monthWidth type="narrow"> + <month type="3">BBB</month> + </monthWidth> + <monthWidth type="wide"> + <month type="3">bbb</month> + </monthWidth> + </monthContext> + </months> + </calendar> + <calendar type="gregorian"> + <months> + <monthContext type="format"> + <monthWidth type="narrow"> + <month type="3">M</month> + <month type="4">A</month> + </monthWidth> + <monthWidth type="wide"> + <month type="3">Maerz</month> + <month type="4">April</month> + <month type="5">Mai</month> + </monthWidth> + </monthContext> + <monthContext type="stand-alone"> + <monthWidth type="narrow"> + <month type="3">m</month> + <month type="5">m</month> + </monthWidth> + <monthWidth type="wide"> + <month type="4">april</month> + <month type="5">mai</month> + </monthWidth> + </monthContext> + </months> + </calendar> + </calendars> + </dates> + <posix> + <messages> + <yesstr>yes:y</yesstr> + <nostr>no:n</nostr> + </messages> + </posix> +</ldml> +` + +var gsw_xml = `<?xml version="1.0" encoding="UTF-8" ?> +<!DOCTYPE ldml SYSTEM "../../common/dtd/ldml.dtd"> +<ldml> + <identity> + <language type="gsw"/> + </identity> + <posix> + <alias source="de" path="//ldml/posix"/> + </posix> +</ldml> +` diff --git a/vendor/golang.org/x/text/unicode/cldr/examples_test.go b/vendor/golang.org/x/text/unicode/cldr/examples_test.go new file mode 100644 index 000000000..1a69b0073 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/cldr/examples_test.go @@ -0,0 +1,21 @@ +package cldr_test + +import ( + "fmt" + + "golang.org/x/text/unicode/cldr" +) + +func ExampleSlice() { + var dr *cldr.CLDR // assume this is initialized + + x, _ := dr.LDML("en") + cs := x.Collations.Collation + // remove all but the default + cldr.MakeSlice(&cs).Filter(func(e cldr.Elem) bool { + return e.GetCommon().Type != x.Collations.Default() + }) + for i, c := range cs { + fmt.Println(i, c.Type) + } +} diff --git a/vendor/golang.org/x/text/unicode/cldr/resolve_test.go b/vendor/golang.org/x/text/unicode/cldr/resolve_test.go new file mode 100644 index 000000000..3d8edaec8 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/cldr/resolve_test.go @@ -0,0 +1,368 @@ +package cldr + +import ( + "fmt" + "log" + "reflect" + "testing" +) + +func failOnError(err error) { + if err != nil { + log.Panic(err) + } +} + +func data() *CLDR { + d := Decoder{} + data, err := d.Decode(testLoader{}) + failOnError(err) + return data +} + +type h struct { + A string `xml:"ha,attr"` + E string `xml:"he"` + D string `xml:",chardata"` + X string +} + +type fieldTest struct { + Common + To string `xml:"to,attr"` + Key string `xml:"key,attr"` + E string `xml:"e"` + D string `xml:",chardata"` + X string + h +} + +var testStruct = fieldTest{ + Common: Common{ + name: "mapping", // exclude "type" as distinguishing attribute + Type: "foo", + Alt: "foo", + }, + To: "nyc", + Key: "k", + E: "E", + D: "D", + h: h{ + A: "A", + E: "E", + D: "D", + }, +} + +func TestIter(t *testing.T) { + tests := map[string]string{ + "Type": "foo", + "Alt": "foo", + "To": "nyc", + "A": "A", + "Alias": "<nil>", + } + k := 0 + for i := iter(reflect.ValueOf(testStruct)); !i.done(); i.next() { + v := i.value() + if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.String { + v = v.Elem() + } + name := i.field().Name + if w, ok := tests[name]; ok { + s := fmt.Sprint(v.Interface()) + if w != s { + t.Errorf("value: found %q; want %q", w, s) + } + delete(tests, name) + } + k++ + } + if len(tests) != 0 { + t.Errorf("missing fields: %v", tests) + } +} + +func TestFindField(t *testing.T) { + tests := []struct { + name, val string + exist bool + }{ + {"type", "foo", true}, + {"alt", "foo", true}, + {"to", "nyc", true}, + {"he", "E", true}, + {"q", "", false}, + } + vf := reflect.ValueOf(testStruct) + for i, tt := range tests { + v, err := findField(vf, tt.name) + if (err == nil) != tt.exist { + t.Errorf("%d: field %q present is %v; want %v", i, tt.name, err == nil, tt.exist) + } else if tt.exist { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + continue + } + v = v.Elem() + } + if v.String() != tt.val { + t.Errorf("%d: found value %q; want %q", i, v.String(), tt.val) + } + } + } +} + +var keyTests = []struct { + exclude []string + key string +}{ + {[]string{}, "alt=foo;key=k;to=nyc"}, + {[]string{"type"}, "alt=foo;key=k;to=nyc"}, + {[]string{"choice"}, "alt=foo;key=k;to=nyc"}, + {[]string{"alt"}, "key=k;to=nyc"}, + {[]string{"a"}, "alt=foo;key=k;to=nyc"}, + {[]string{"to"}, "alt=foo;key=k"}, + {[]string{"alt", "to"}, "key=k"}, + {[]string{"alt", "to", "key"}, ""}, +} + +func TestAttrKey(t *testing.T) { + v := reflect.ValueOf(&testStruct) + for i, tt := range keyTests { + key := attrKey(v, tt.exclude...) + if key != tt.key { + t.Errorf("%d: found %q, want %q", i, key, tt.key) + } + } +} + +func TestKey(t *testing.T) { + for i, tt := range keyTests { + key := Key(&testStruct, tt.exclude...) + if key != tt.key { + t.Errorf("%d: found %q, want %q", i, key, tt.key) + } + } +} + +func testEnclosing(t *testing.T, x *LDML, name string) { + eq := func(a, b Elem, i int) { + for ; i > 0; i-- { + b = b.enclosing() + } + if a != b { + t.Errorf("%s: found path %q, want %q", name, getPath(a), getPath(b)) + } + } + eq(x, x, 0) + eq(x, x.Identity, 1) + eq(x, x.Dates.Calendars, 2) + eq(x, x.Dates.Calendars.Calendar[0], 3) + eq(x, x.Dates.Calendars.Calendar[1], 3) + //eq(x, x.Dates.Calendars.Calendar[0].Months, 4) + eq(x, x.Dates.Calendars.Calendar[1].Months, 4) +} + +func TestEnclosing(t *testing.T) { + testEnclosing(t, data().RawLDML("de"), "enclosing-raw") + de, _ := data().LDML("de") + testEnclosing(t, de, "enclosing") +} + +func TestDeepCopy(t *testing.T) { + eq := func(have, want string) { + if have != want { + t.Errorf("found %q; want %q", have, want) + } + } + x, _ := data().LDML("de") + vc := deepCopy(reflect.ValueOf(x)) + c := vc.Interface().(*LDML) + linkEnclosing(nil, c) + if x == c { + t.Errorf("did not copy") + } + + eq(c.name, "ldml") + eq(c.Dates.name, "dates") + testEnclosing(t, c, "deepCopy") +} + +type getTest struct { + loc string + path string + field string // used in combination with length + data string + altData string // used for buddhist calendar if value != "" + typ string + length int + missing bool +} + +const ( + budMon = "dates/calendars/calendar[@type='buddhist']/months/" + chnMon = "dates/calendars/calendar[@type='chinese']/months/" + greMon = "dates/calendars/calendar[@type='gregorian']/months/" +) + +func monthVal(path, context, width string, month int) string { + const format = "%s/monthContext[@type='%s']/monthWidth[@type='%s']/month[@type='%d']" + return fmt.Sprintf(format, path, context, width, month) +} + +var rootGetTests = []getTest{ + {loc: "root", path: "identity/language", typ: "root"}, + {loc: "root", path: "characters/moreInformation", data: "?"}, + {loc: "root", path: "characters", field: "exemplarCharacters", length: 3}, + {loc: "root", path: greMon, field: "monthContext", length: 2}, + {loc: "root", path: greMon + "monthContext[@type='format']/monthWidth[@type='narrow']", field: "month", length: 4}, + {loc: "root", path: greMon + "monthContext[@type='stand-alone']/monthWidth[@type='wide']", field: "month", length: 4}, + // unescaping character data + {loc: "root", path: "characters/exemplarCharacters[@type='punctuation']", data: `[\- ‐ – — … ' ‘ ‚ " “ „ \& #]`}, + // default resolution + {loc: "root", path: "dates/calendars/calendar", typ: "gregorian"}, + // alias resolution + {loc: "root", path: budMon, field: "monthContext", length: 2}, + // crossing but non-circular alias resolution + {loc: "root", path: budMon + "monthContext[@type='format']/monthWidth[@type='narrow']", field: "month", length: 4}, + {loc: "root", path: budMon + "monthContext[@type='stand-alone']/monthWidth[@type='wide']", field: "month", length: 4}, + {loc: "root", path: monthVal(greMon, "format", "wide", 1), data: "11"}, + {loc: "root", path: monthVal(greMon, "format", "narrow", 2), data: "2"}, + {loc: "root", path: monthVal(greMon, "stand-alone", "wide", 3), data: "33"}, + {loc: "root", path: monthVal(greMon, "stand-alone", "narrow", 4), data: "4"}, + {loc: "root", path: monthVal(budMon, "format", "wide", 1), data: "11"}, + {loc: "root", path: monthVal(budMon, "format", "narrow", 2), data: "2"}, + {loc: "root", path: monthVal(budMon, "stand-alone", "wide", 3), data: "33"}, + {loc: "root", path: monthVal(budMon, "stand-alone", "narrow", 4), data: "4"}, +} + +// 19 +var deGetTests = []getTest{ + {loc: "de", path: "identity/language", typ: "de"}, + {loc: "de", path: "posix", length: 2}, + {loc: "de", path: "characters", field: "exemplarCharacters", length: 4}, + {loc: "de", path: "characters/exemplarCharacters[@type='auxiliary']", data: `[á à ă]`}, + // identity is a blocking element, so de should not inherit generation from root. + {loc: "de", path: "identity/generation", missing: true}, + // default resolution + {loc: "root", path: "dates/calendars/calendar", typ: "gregorian"}, + + // absolute path alias resolution + {loc: "gsw", path: "posix", field: "messages", length: 1}, + {loc: "gsw", path: "posix/messages/yesstr", data: "yes:y"}, +} + +// 27(greMon) - 52(budMon) - 77(chnMon) +func calGetTests(s string) []getTest { + tests := []getTest{ + {loc: "de", path: s, length: 2}, + {loc: "de", path: s + "monthContext[@type='format']/monthWidth[@type='wide']", field: "month", length: 5}, + {loc: "de", path: monthVal(s, "format", "wide", 1), data: "11"}, + {loc: "de", path: monthVal(s, "format", "wide", 2), data: "22"}, + {loc: "de", path: monthVal(s, "format", "wide", 3), data: "Maerz", altData: "bbb"}, + {loc: "de", path: monthVal(s, "format", "wide", 4), data: "April"}, + {loc: "de", path: monthVal(s, "format", "wide", 5), data: "Mai"}, + + {loc: "de", path: s + "monthContext[@type='format']/monthWidth[@type='narrow']", field: "month", length: 5}, + {loc: "de", path: monthVal(s, "format", "narrow", 1), data: "1"}, + {loc: "de", path: monthVal(s, "format", "narrow", 2), data: "2"}, + {loc: "de", path: monthVal(s, "format", "narrow", 3), data: "M", altData: "BBB"}, + {loc: "de", path: monthVal(s, "format", "narrow", 4), data: "A"}, + {loc: "de", path: monthVal(s, "format", "narrow", 5), data: "m"}, + + {loc: "de", path: s + "monthContext[@type='stand-alone']/monthWidth[@type='wide']", field: "month", length: 5}, + {loc: "de", path: monthVal(s, "stand-alone", "wide", 1), data: "11"}, + {loc: "de", path: monthVal(s, "stand-alone", "wide", 2), data: "22"}, + {loc: "de", path: monthVal(s, "stand-alone", "wide", 3), data: "Maerz", altData: "bbb"}, + {loc: "de", path: monthVal(s, "stand-alone", "wide", 4), data: "april"}, + {loc: "de", path: monthVal(s, "stand-alone", "wide", 5), data: "mai"}, + + {loc: "de", path: s + "monthContext[@type='stand-alone']/monthWidth[@type='narrow']", field: "month", length: 5}, + {loc: "de", path: monthVal(s, "stand-alone", "narrow", 1), data: "1"}, + {loc: "de", path: monthVal(s, "stand-alone", "narrow", 2), data: "2"}, + {loc: "de", path: monthVal(s, "stand-alone", "narrow", 3), data: "m"}, + {loc: "de", path: monthVal(s, "stand-alone", "narrow", 4), data: "4"}, + {loc: "de", path: monthVal(s, "stand-alone", "narrow", 5), data: "m"}, + } + if s == budMon { + for i, t := range tests { + if t.altData != "" { + tests[i].data = t.altData + } + } + } + return tests +} + +var getTests = append(rootGetTests, + append(deGetTests, + append(calGetTests(greMon), + append(calGetTests(budMon), + calGetTests(chnMon)...)...)...)...) + +func TestPath(t *testing.T) { + d := data() + for i, tt := range getTests { + x, _ := d.LDML(tt.loc) + e, err := walkXPath(x, tt.path) + if err != nil { + if !tt.missing { + t.Errorf("%d:error: %v %v", i, err, tt.missing) + } + continue + } + if tt.missing { + t.Errorf("%d: missing is %v; want %v", i, e == nil, tt.missing) + continue + } + if tt.data != "" && e.GetCommon().Data() != tt.data { + t.Errorf("%d: data is %v; want %v", i, e.GetCommon().Data(), tt.data) + continue + } + if tt.typ != "" && e.GetCommon().Type != tt.typ { + t.Errorf("%d: type is %v; want %v", i, e.GetCommon().Type, tt.typ) + continue + } + if tt.field != "" { + slice, _ := findField(reflect.ValueOf(e), tt.field) + if slice.Len() != tt.length { + t.Errorf("%d: length is %v; want %v", i, slice.Len(), tt.length) + continue + } + } + } +} + +func TestGet(t *testing.T) { + d := data() + for i, tt := range getTests { + x, _ := d.LDML(tt.loc) + e, err := Get(x, tt.path) + if err != nil { + if !tt.missing { + t.Errorf("%d:error: %v %v", i, err, tt.missing) + } + continue + } + if tt.missing { + t.Errorf("%d: missing is %v; want %v", i, e == nil, tt.missing) + continue + } + if tt.data != "" && e.GetCommon().Data() != tt.data { + t.Errorf("%d: data is %v; want %v", i, e.GetCommon().Data(), tt.data) + continue + } + if tt.typ != "" && e.GetCommon().Type != tt.typ { + t.Errorf("%d: type is %v; want %v", i, e.GetCommon().Type, tt.typ) + continue + } + if tt.field != "" { + slice, _ := findField(reflect.ValueOf(e), tt.field) + if slice.Len() != tt.length { + t.Errorf("%d: length is %v; want %v", i, slice.Len(), tt.length) + continue + } + } + } +} diff --git a/vendor/golang.org/x/text/unicode/cldr/slice_test.go b/vendor/golang.org/x/text/unicode/cldr/slice_test.go new file mode 100644 index 000000000..3d487d3bd --- /dev/null +++ b/vendor/golang.org/x/text/unicode/cldr/slice_test.go @@ -0,0 +1,175 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cldr + +import ( + "reflect" + "testing" +) + +type testSlice []*Common + +func mkElem(alt, typ, ref string) *Common { + return &Common{ + Type: typ, + Reference: ref, + Alt: alt, + } +} + +var ( + testSlice1 = testSlice{ + mkElem("1", "a", "i.a"), + mkElem("1", "b", "i.b"), + mkElem("1", "c", "i.c"), + mkElem("2", "b", "ii"), + mkElem("3", "c", "iii"), + mkElem("4", "a", "iv.a"), + mkElem("4", "d", "iv.d"), + } + testSliceE = testSlice{} +) + +func panics(f func()) (panics bool) { + defer func() { + if err := recover(); err != nil { + panics = true + } + }() + f() + return panics +} + +func TestMakeSlice(t *testing.T) { + foo := 1 + bar := []int{} + tests := []struct { + i interface{} + panics bool + err string + }{ + {&foo, true, "should panic when passed a pointer to the wrong type"}, + {&bar, true, "should panic when slice element of the wrong type"}, + {testSlice1, true, "should panic when passed a slice"}, + {&testSlice1, false, "should not panic"}, + } + for i, tt := range tests { + if panics(func() { MakeSlice(tt.i) }) != tt.panics { + t.Errorf("%d: %s", i, tt.err) + } + } +} + +var anyOfTests = []struct { + sl testSlice + values []string + n int +}{ + {testSliceE, []string{}, 0}, + {testSliceE, []string{"1", "2", "3"}, 0}, + {testSlice1, []string{}, 0}, + {testSlice1, []string{"1"}, 3}, + {testSlice1, []string{"2"}, 1}, + {testSlice1, []string{"5"}, 0}, + {testSlice1, []string{"1", "2", "3"}, 5}, +} + +func TestSelectAnyOf(t *testing.T) { + for i, tt := range anyOfTests { + sl := tt.sl + s := MakeSlice(&sl) + s.SelectAnyOf("alt", tt.values...) + if len(sl) != tt.n { + t.Errorf("%d: found len == %d; want %d", i, len(sl), tt.n) + } + } + sl := testSlice1 + s := MakeSlice(&sl) + if !panics(func() { s.SelectAnyOf("foo") }) { + t.Errorf("should panic on non-existing attribute") + } +} + +func TestFilter(t *testing.T) { + for i, tt := range anyOfTests { + sl := tt.sl + s := MakeSlice(&sl) + s.Filter(func(e Elem) bool { + v, _ := findField(reflect.ValueOf(e), "alt") + return in(tt.values, v.String()) + }) + if len(sl) != tt.n { + t.Errorf("%d: found len == %d; want %d", i, len(sl), tt.n) + } + } +} + +func TestGroup(t *testing.T) { + f := func(excl ...string) func(Elem) string { + return func(e Elem) string { + return Key(e, excl...) + } + } + tests := []struct { + sl testSlice + f func(Elem) string + lens []int + }{ + {testSliceE, f(), []int{}}, + {testSlice1, f(), []int{1, 1, 1, 1, 1, 1, 1}}, + {testSlice1, f("type"), []int{3, 1, 1, 2}}, + {testSlice1, f("alt"), []int{2, 2, 2, 1}}, + {testSlice1, f("alt", "type"), []int{7}}, + {testSlice1, f("alt", "type"), []int{7}}, + } + for i, tt := range tests { + sl := tt.sl + s := MakeSlice(&sl) + g := s.Group(tt.f) + if len(tt.lens) != len(g) { + t.Errorf("%d: found %d; want %d", i, len(g), len(tt.lens)) + continue + } + for j, v := range tt.lens { + if n := g[j].Value().Len(); n != v { + t.Errorf("%d: found %d for length of group %d; want %d", i, n, j, v) + } + } + } +} + +func TestSelectOnePerGroup(t *testing.T) { + tests := []struct { + sl testSlice + attr string + values []string + refs []string + }{ + {testSliceE, "alt", []string{"1"}, []string{}}, + {testSliceE, "type", []string{"a"}, []string{}}, + {testSlice1, "alt", []string{"2", "3", "1"}, []string{"i.a", "ii", "iii"}}, + {testSlice1, "alt", []string{"1", "4"}, []string{"i.a", "i.b", "i.c", "iv.d"}}, + {testSlice1, "type", []string{"c", "d"}, []string{"i.c", "iii", "iv.d"}}, + } + for i, tt := range tests { + sl := tt.sl + s := MakeSlice(&sl) + s.SelectOnePerGroup(tt.attr, tt.values) + if len(sl) != len(tt.refs) { + t.Errorf("%d: found result length %d; want %d", i, len(sl), len(tt.refs)) + continue + } + for j, e := range sl { + if tt.refs[j] != e.Reference { + t.Errorf("%d:%d found %s; want %s", i, j, e.Reference, tt.refs[i]) + } + } + } + sl := testSlice1 + s := MakeSlice(&sl) + if !panics(func() { s.SelectOnePerGroup("foo", nil) }) { + t.Errorf("should panic on non-existing attribute") + } +} diff --git a/vendor/golang.org/x/text/unicode/doc.go b/vendor/golang.org/x/text/unicode/doc.go new file mode 100644 index 000000000..e8f1032d0 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/doc.go @@ -0,0 +1,8 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// unicode holds packages with implementations of Unicode standards that are +// mostly used as building blocks for other packages in golang.org/x/text, +// layout engines, or are otherwise more low-level in nature. +package unicode diff --git a/vendor/golang.org/x/text/unicode/norm/composition_test.go b/vendor/golang.org/x/text/unicode/norm/composition_test.go new file mode 100644 index 000000000..11684069d --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/composition_test.go @@ -0,0 +1,130 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import "testing" + +// TestCase is used for most tests. +type TestCase struct { + in []rune + out []rune +} + +func runTests(t *testing.T, name string, fm Form, tests []TestCase) { + rb := reorderBuffer{} + rb.init(fm, nil) + for i, test := range tests { + rb.setFlusher(nil, appendFlush) + for j, rune := range test.in { + b := []byte(string(rune)) + src := inputBytes(b) + info := rb.f.info(src, 0) + if j == 0 { + rb.ss.first(info) + } else { + rb.ss.next(info) + } + if rb.insertFlush(src, 0, info) < 0 { + t.Errorf("%s:%d: insert failed for rune %d", name, i, j) + } + } + rb.doFlush() + was := string(rb.out) + want := string(test.out) + if len(was) != len(want) { + t.Errorf("%s:%d: length = %d; want %d", name, i, len(was), len(want)) + } + if was != want { + k, pfx := pidx(was, want) + t.Errorf("%s:%d: \nwas %s%+q; \nwant %s%+q", name, i, pfx, was[k:], pfx, want[k:]) + } + } +} + +func TestFlush(t *testing.T) { + const ( + hello = "Hello " + world = "world!" + ) + buf := make([]byte, maxByteBufferSize) + p := copy(buf, hello) + out := buf[p:] + rb := reorderBuffer{} + rb.initString(NFC, world) + if i := rb.flushCopy(out); i != 0 { + t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", i) + } + + for i := range world { + // No need to set streamSafe values for this test. + rb.insertFlush(rb.src, i, rb.f.info(rb.src, i)) + n := rb.flushCopy(out) + out = out[n:] + p += n + } + + was := buf[:p] + want := hello + world + if string(was) != want { + t.Errorf(`output after flush was "%s"; want "%s"`, string(was), want) + } + if rb.nrune != 0 { + t.Errorf("non-null size of info buffer (rb.nrune == %d)", rb.nrune) + } + if rb.nbyte != 0 { + t.Errorf("non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte) + } +} + +var insertTests = []TestCase{ + {[]rune{'a'}, []rune{'a'}}, + {[]rune{0x300}, []rune{0x300}}, + {[]rune{0x300, 0x316}, []rune{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220 + {[]rune{0x316, 0x300}, []rune{0x316, 0x300}}, + {[]rune{0x41, 0x316, 0x300}, []rune{0x41, 0x316, 0x300}}, + {[]rune{0x41, 0x300, 0x316}, []rune{0x41, 0x316, 0x300}}, + {[]rune{0x300, 0x316, 0x41}, []rune{0x316, 0x300, 0x41}}, + {[]rune{0x41, 0x300, 0x40, 0x316}, []rune{0x41, 0x300, 0x40, 0x316}}, +} + +func TestInsert(t *testing.T) { + runTests(t, "TestInsert", NFD, insertTests) +} + +var decompositionNFDTest = []TestCase{ + {[]rune{0xC0}, []rune{0x41, 0x300}}, + {[]rune{0xAC00}, []rune{0x1100, 0x1161}}, + {[]rune{0x01C4}, []rune{0x01C4}}, + {[]rune{0x320E}, []rune{0x320E}}, + {[]rune("음ẻ과"), []rune{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}}, +} + +var decompositionNFKDTest = []TestCase{ + {[]rune{0xC0}, []rune{0x41, 0x300}}, + {[]rune{0xAC00}, []rune{0x1100, 0x1161}}, + {[]rune{0x01C4}, []rune{0x44, 0x5A, 0x030C}}, + {[]rune{0x320E}, []rune{0x28, 0x1100, 0x1161, 0x29}}, +} + +func TestDecomposition(t *testing.T) { + runTests(t, "TestDecompositionNFD", NFD, decompositionNFDTest) + runTests(t, "TestDecompositionNFKD", NFKD, decompositionNFKDTest) +} + +var compositionTest = []TestCase{ + {[]rune{0x41, 0x300}, []rune{0xC0}}, + {[]rune{0x41, 0x316}, []rune{0x41, 0x316}}, + {[]rune{0x41, 0x300, 0x35D}, []rune{0xC0, 0x35D}}, + {[]rune{0x41, 0x316, 0x300}, []rune{0xC0, 0x316}}, + // blocking starter + {[]rune{0x41, 0x316, 0x40, 0x300}, []rune{0x41, 0x316, 0x40, 0x300}}, + {[]rune{0x1100, 0x1161}, []rune{0xAC00}}, + // parenthesized Hangul, alternate between ASCII and Hangul. + {[]rune{0x28, 0x1100, 0x1161, 0x29}, []rune{0x28, 0xAC00, 0x29}}, +} + +func TestComposition(t *testing.T) { + runTests(t, "TestComposition", NFC, compositionTest) +} diff --git a/vendor/golang.org/x/text/unicode/norm/data10.0.0_test.go b/vendor/golang.org/x/text/unicode/norm/data10.0.0_test.go new file mode 100644 index 000000000..1d0f73dc1 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/data10.0.0_test.go @@ -0,0 +1,7424 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// +build go1.10 + +package norm + +const ( + Yes = iota + No + Maybe +) + +type formData struct { + qc uint8 + combinesForward bool + decomposition string +} + +type runeData struct { + r rune + ccc uint8 + nLead uint8 + nTrail uint8 + f [2]formData // 0: canonical; 1: compatibility +} + +func f(qc uint8, cf bool, dec string) [2]formData { + return [2]formData{{qc, cf, dec}, {qc, cf, dec}} +} + +func g(qc, qck uint8, cf, cfk bool, d, dk string) [2]formData { + return [2]formData{{qc, cf, d}, {qck, cfk, dk}} +} + +var testData = []runeData{ + {0x0, 0, 0, 0, f(Yes, false, "")}, + {0x3c, 0, 0, 0, f(Yes, true, "")}, + {0x3f, 0, 0, 0, f(Yes, false, "")}, + {0x41, 0, 0, 0, f(Yes, true, "")}, + {0x51, 0, 0, 0, f(Yes, false, "")}, + {0x52, 0, 0, 0, f(Yes, true, "")}, + {0x5b, 0, 0, 0, f(Yes, false, "")}, + {0x61, 0, 0, 0, f(Yes, true, "")}, + {0x71, 0, 0, 0, f(Yes, false, "")}, + {0x72, 0, 0, 0, f(Yes, true, "")}, + {0x7b, 0, 0, 0, f(Yes, false, "")}, + {0xa0, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0xa1, 0, 0, 0, f(Yes, false, "")}, + {0xa8, 0, 0, 1, g(Yes, No, true, false, "", " ̈")}, + {0xa9, 0, 0, 0, f(Yes, false, "")}, + {0xaa, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0xab, 0, 0, 0, f(Yes, false, "")}, + {0xaf, 0, 0, 1, g(Yes, No, false, false, "", " ̄")}, + {0xb0, 0, 0, 0, f(Yes, false, "")}, + {0xb2, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0xb3, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0xb4, 0, 0, 1, g(Yes, No, false, false, "", " ́")}, + {0xb5, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0xb6, 0, 0, 0, f(Yes, false, "")}, + {0xb8, 0, 0, 1, g(Yes, No, false, false, "", " ̧")}, + {0xb9, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0xba, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0xbb, 0, 0, 0, f(Yes, false, "")}, + {0xbc, 0, 0, 0, g(Yes, No, false, false, "", "1⁄4")}, + {0xbd, 0, 0, 0, g(Yes, No, false, false, "", "1⁄2")}, + {0xbe, 0, 0, 0, g(Yes, No, false, false, "", "3⁄4")}, + {0xbf, 0, 0, 0, f(Yes, false, "")}, + {0xc0, 0, 0, 1, f(Yes, false, "À")}, + {0xc1, 0, 0, 1, f(Yes, false, "Á")}, + {0xc2, 0, 0, 1, f(Yes, true, "Â")}, + {0xc3, 0, 0, 1, f(Yes, false, "Ã")}, + {0xc4, 0, 0, 1, f(Yes, true, "Ä")}, + {0xc5, 0, 0, 1, f(Yes, true, "Å")}, + {0xc6, 0, 0, 0, f(Yes, true, "")}, + {0xc7, 0, 0, 1, f(Yes, true, "Ç")}, + {0xc8, 0, 0, 1, f(Yes, false, "È")}, + {0xc9, 0, 0, 1, f(Yes, false, "É")}, + {0xca, 0, 0, 1, f(Yes, true, "Ê")}, + {0xcb, 0, 0, 1, f(Yes, false, "Ë")}, + {0xcc, 0, 0, 1, f(Yes, false, "Ì")}, + {0xcd, 0, 0, 1, f(Yes, false, "Í")}, + {0xce, 0, 0, 1, f(Yes, false, "Î")}, + {0xcf, 0, 0, 1, f(Yes, true, "Ï")}, + {0xd0, 0, 0, 0, f(Yes, false, "")}, + {0xd1, 0, 0, 1, f(Yes, false, "Ñ")}, + {0xd2, 0, 0, 1, f(Yes, false, "Ò")}, + {0xd3, 0, 0, 1, f(Yes, false, "Ó")}, + {0xd4, 0, 0, 1, f(Yes, true, "Ô")}, + {0xd5, 0, 0, 1, f(Yes, true, "Õ")}, + {0xd6, 0, 0, 1, f(Yes, true, "Ö")}, + {0xd7, 0, 0, 0, f(Yes, false, "")}, + {0xd8, 0, 0, 0, f(Yes, true, "")}, + {0xd9, 0, 0, 1, f(Yes, false, "Ù")}, + {0xda, 0, 0, 1, f(Yes, false, "Ú")}, + {0xdb, 0, 0, 1, f(Yes, false, "Û")}, + {0xdc, 0, 0, 1, f(Yes, true, "Ü")}, + {0xdd, 0, 0, 1, f(Yes, false, "Ý")}, + {0xde, 0, 0, 0, f(Yes, false, "")}, + {0xe0, 0, 0, 1, f(Yes, false, "à")}, + {0xe1, 0, 0, 1, f(Yes, false, "á")}, + {0xe2, 0, 0, 1, f(Yes, true, "â")}, + {0xe3, 0, 0, 1, f(Yes, false, "ã")}, + {0xe4, 0, 0, 1, f(Yes, true, "ä")}, + {0xe5, 0, 0, 1, f(Yes, true, "å")}, + {0xe6, 0, 0, 0, f(Yes, true, "")}, + {0xe7, 0, 0, 1, f(Yes, true, "ç")}, + {0xe8, 0, 0, 1, f(Yes, false, "è")}, + {0xe9, 0, 0, 1, f(Yes, false, "é")}, + {0xea, 0, 0, 1, f(Yes, true, "ê")}, + {0xeb, 0, 0, 1, f(Yes, false, "ë")}, + {0xec, 0, 0, 1, f(Yes, false, "ì")}, + {0xed, 0, 0, 1, f(Yes, false, "í")}, + {0xee, 0, 0, 1, f(Yes, false, "î")}, + {0xef, 0, 0, 1, f(Yes, true, "ï")}, + {0xf0, 0, 0, 0, f(Yes, false, "")}, + {0xf1, 0, 0, 1, f(Yes, false, "ñ")}, + {0xf2, 0, 0, 1, f(Yes, false, "ò")}, + {0xf3, 0, 0, 1, f(Yes, false, "ó")}, + {0xf4, 0, 0, 1, f(Yes, true, "ô")}, + {0xf5, 0, 0, 1, f(Yes, true, "õ")}, + {0xf6, 0, 0, 1, f(Yes, true, "ö")}, + {0xf7, 0, 0, 0, f(Yes, false, "")}, + {0xf8, 0, 0, 0, f(Yes, true, "")}, + {0xf9, 0, 0, 1, f(Yes, false, "ù")}, + {0xfa, 0, 0, 1, f(Yes, false, "ú")}, + {0xfb, 0, 0, 1, f(Yes, false, "û")}, + {0xfc, 0, 0, 1, f(Yes, true, "ü")}, + {0xfd, 0, 0, 1, f(Yes, false, "ý")}, + {0xfe, 0, 0, 0, f(Yes, false, "")}, + {0xff, 0, 0, 1, f(Yes, false, "ÿ")}, + {0x100, 0, 0, 1, f(Yes, false, "Ā")}, + {0x101, 0, 0, 1, f(Yes, false, "ā")}, + {0x102, 0, 0, 1, f(Yes, true, "Ă")}, + {0x103, 0, 0, 1, f(Yes, true, "ă")}, + {0x104, 0, 0, 1, f(Yes, false, "Ą")}, + {0x105, 0, 0, 1, f(Yes, false, "ą")}, + {0x106, 0, 0, 1, f(Yes, false, "Ć")}, + {0x107, 0, 0, 1, f(Yes, false, "ć")}, + {0x108, 0, 0, 1, f(Yes, false, "Ĉ")}, + {0x109, 0, 0, 1, f(Yes, false, "ĉ")}, + {0x10a, 0, 0, 1, f(Yes, false, "Ċ")}, + {0x10b, 0, 0, 1, f(Yes, false, "ċ")}, + {0x10c, 0, 0, 1, f(Yes, false, "Č")}, + {0x10d, 0, 0, 1, f(Yes, false, "č")}, + {0x10e, 0, 0, 1, f(Yes, false, "Ď")}, + {0x10f, 0, 0, 1, f(Yes, false, "ď")}, + {0x110, 0, 0, 0, f(Yes, false, "")}, + {0x112, 0, 0, 1, f(Yes, true, "Ē")}, + {0x113, 0, 0, 1, f(Yes, true, "ē")}, + {0x114, 0, 0, 1, f(Yes, false, "Ĕ")}, + {0x115, 0, 0, 1, f(Yes, false, "ĕ")}, + {0x116, 0, 0, 1, f(Yes, false, "Ė")}, + {0x117, 0, 0, 1, f(Yes, false, "ė")}, + {0x118, 0, 0, 1, f(Yes, false, "Ę")}, + {0x119, 0, 0, 1, f(Yes, false, "ę")}, + {0x11a, 0, 0, 1, f(Yes, false, "Ě")}, + {0x11b, 0, 0, 1, f(Yes, false, "ě")}, + {0x11c, 0, 0, 1, f(Yes, false, "Ĝ")}, + {0x11d, 0, 0, 1, f(Yes, false, "ĝ")}, + {0x11e, 0, 0, 1, f(Yes, false, "Ğ")}, + {0x11f, 0, 0, 1, f(Yes, false, "ğ")}, + {0x120, 0, 0, 1, f(Yes, false, "Ġ")}, + {0x121, 0, 0, 1, f(Yes, false, "ġ")}, + {0x122, 0, 0, 1, f(Yes, false, "Ģ")}, + {0x123, 0, 0, 1, f(Yes, false, "ģ")}, + {0x124, 0, 0, 1, f(Yes, false, "Ĥ")}, + {0x125, 0, 0, 1, f(Yes, false, "ĥ")}, + {0x126, 0, 0, 0, f(Yes, false, "")}, + {0x128, 0, 0, 1, f(Yes, false, "Ĩ")}, + {0x129, 0, 0, 1, f(Yes, false, "ĩ")}, + {0x12a, 0, 0, 1, f(Yes, false, "Ī")}, + {0x12b, 0, 0, 1, f(Yes, false, "ī")}, + {0x12c, 0, 0, 1, f(Yes, false, "Ĭ")}, + {0x12d, 0, 0, 1, f(Yes, false, "ĭ")}, + {0x12e, 0, 0, 1, f(Yes, false, "Į")}, + {0x12f, 0, 0, 1, f(Yes, false, "į")}, + {0x130, 0, 0, 1, f(Yes, false, "İ")}, + {0x131, 0, 0, 0, f(Yes, false, "")}, + {0x132, 0, 0, 0, g(Yes, No, false, false, "", "IJ")}, + {0x133, 0, 0, 0, g(Yes, No, false, false, "", "ij")}, + {0x134, 0, 0, 1, f(Yes, false, "Ĵ")}, + {0x135, 0, 0, 1, f(Yes, false, "ĵ")}, + {0x136, 0, 0, 1, f(Yes, false, "Ķ")}, + {0x137, 0, 0, 1, f(Yes, false, "ķ")}, + {0x138, 0, 0, 0, f(Yes, false, "")}, + {0x139, 0, 0, 1, f(Yes, false, "Ĺ")}, + {0x13a, 0, 0, 1, f(Yes, false, "ĺ")}, + {0x13b, 0, 0, 1, f(Yes, false, "Ļ")}, + {0x13c, 0, 0, 1, f(Yes, false, "ļ")}, + {0x13d, 0, 0, 1, f(Yes, false, "Ľ")}, + {0x13e, 0, 0, 1, f(Yes, false, "ľ")}, + {0x13f, 0, 0, 0, g(Yes, No, false, false, "", "L·")}, + {0x140, 0, 0, 0, g(Yes, No, false, false, "", "l·")}, + {0x141, 0, 0, 0, f(Yes, false, "")}, + {0x143, 0, 0, 1, f(Yes, false, "Ń")}, + {0x144, 0, 0, 1, f(Yes, false, "ń")}, + {0x145, 0, 0, 1, f(Yes, false, "Ņ")}, + {0x146, 0, 0, 1, f(Yes, false, "ņ")}, + {0x147, 0, 0, 1, f(Yes, false, "Ň")}, + {0x148, 0, 0, 1, f(Yes, false, "ň")}, + {0x149, 0, 0, 0, g(Yes, No, false, false, "", "ʼn")}, + {0x14a, 0, 0, 0, f(Yes, false, "")}, + {0x14c, 0, 0, 1, f(Yes, true, "Ō")}, + {0x14d, 0, 0, 1, f(Yes, true, "ō")}, + {0x14e, 0, 0, 1, f(Yes, false, "Ŏ")}, + {0x14f, 0, 0, 1, f(Yes, false, "ŏ")}, + {0x150, 0, 0, 1, f(Yes, false, "Ő")}, + {0x151, 0, 0, 1, f(Yes, false, "ő")}, + {0x152, 0, 0, 0, f(Yes, false, "")}, + {0x154, 0, 0, 1, f(Yes, false, "Ŕ")}, + {0x155, 0, 0, 1, f(Yes, false, "ŕ")}, + {0x156, 0, 0, 1, f(Yes, false, "Ŗ")}, + {0x157, 0, 0, 1, f(Yes, false, "ŗ")}, + {0x158, 0, 0, 1, f(Yes, false, "Ř")}, + {0x159, 0, 0, 1, f(Yes, false, "ř")}, + {0x15a, 0, 0, 1, f(Yes, true, "Ś")}, + {0x15b, 0, 0, 1, f(Yes, true, "ś")}, + {0x15c, 0, 0, 1, f(Yes, false, "Ŝ")}, + {0x15d, 0, 0, 1, f(Yes, false, "ŝ")}, + {0x15e, 0, 0, 1, f(Yes, false, "Ş")}, + {0x15f, 0, 0, 1, f(Yes, false, "ş")}, + {0x160, 0, 0, 1, f(Yes, true, "Š")}, + {0x161, 0, 0, 1, f(Yes, true, "š")}, + {0x162, 0, 0, 1, f(Yes, false, "Ţ")}, + {0x163, 0, 0, 1, f(Yes, false, "ţ")}, + {0x164, 0, 0, 1, f(Yes, false, "Ť")}, + {0x165, 0, 0, 1, f(Yes, false, "ť")}, + {0x166, 0, 0, 0, f(Yes, false, "")}, + {0x168, 0, 0, 1, f(Yes, true, "Ũ")}, + {0x169, 0, 0, 1, f(Yes, true, "ũ")}, + {0x16a, 0, 0, 1, f(Yes, true, "Ū")}, + {0x16b, 0, 0, 1, f(Yes, true, "ū")}, + {0x16c, 0, 0, 1, f(Yes, false, "Ŭ")}, + {0x16d, 0, 0, 1, f(Yes, false, "ŭ")}, + {0x16e, 0, 0, 1, f(Yes, false, "Ů")}, + {0x16f, 0, 0, 1, f(Yes, false, "ů")}, + {0x170, 0, 0, 1, f(Yes, false, "Ű")}, + {0x171, 0, 0, 1, f(Yes, false, "ű")}, + {0x172, 0, 0, 1, f(Yes, false, "Ų")}, + {0x173, 0, 0, 1, f(Yes, false, "ų")}, + {0x174, 0, 0, 1, f(Yes, false, "Ŵ")}, + {0x175, 0, 0, 1, f(Yes, false, "ŵ")}, + {0x176, 0, 0, 1, f(Yes, false, "Ŷ")}, + {0x177, 0, 0, 1, f(Yes, false, "ŷ")}, + {0x178, 0, 0, 1, f(Yes, false, "Ÿ")}, + {0x179, 0, 0, 1, f(Yes, false, "Ź")}, + {0x17a, 0, 0, 1, f(Yes, false, "ź")}, + {0x17b, 0, 0, 1, f(Yes, false, "Ż")}, + {0x17c, 0, 0, 1, f(Yes, false, "ż")}, + {0x17d, 0, 0, 1, f(Yes, false, "Ž")}, + {0x17e, 0, 0, 1, f(Yes, false, "ž")}, + {0x17f, 0, 0, 0, g(Yes, No, true, false, "", "s")}, + {0x180, 0, 0, 0, f(Yes, false, "")}, + {0x1a0, 0, 0, 1, f(Yes, true, "Ơ")}, + {0x1a1, 0, 0, 1, f(Yes, true, "ơ")}, + {0x1a2, 0, 0, 0, f(Yes, false, "")}, + {0x1af, 0, 0, 1, f(Yes, true, "Ư")}, + {0x1b0, 0, 0, 1, f(Yes, true, "ư")}, + {0x1b1, 0, 0, 0, f(Yes, false, "")}, + {0x1b7, 0, 0, 0, f(Yes, true, "")}, + {0x1b8, 0, 0, 0, f(Yes, false, "")}, + {0x1c4, 0, 0, 1, g(Yes, No, false, false, "", "DŽ")}, + {0x1c5, 0, 0, 1, g(Yes, No, false, false, "", "Dž")}, + {0x1c6, 0, 0, 1, g(Yes, No, false, false, "", "dž")}, + {0x1c7, 0, 0, 0, g(Yes, No, false, false, "", "LJ")}, + {0x1c8, 0, 0, 0, g(Yes, No, false, false, "", "Lj")}, + {0x1c9, 0, 0, 0, g(Yes, No, false, false, "", "lj")}, + {0x1ca, 0, 0, 0, g(Yes, No, false, false, "", "NJ")}, + {0x1cb, 0, 0, 0, g(Yes, No, false, false, "", "Nj")}, + {0x1cc, 0, 0, 0, g(Yes, No, false, false, "", "nj")}, + {0x1cd, 0, 0, 1, f(Yes, false, "Ǎ")}, + {0x1ce, 0, 0, 1, f(Yes, false, "ǎ")}, + {0x1cf, 0, 0, 1, f(Yes, false, "Ǐ")}, + {0x1d0, 0, 0, 1, f(Yes, false, "ǐ")}, + {0x1d1, 0, 0, 1, f(Yes, false, "Ǒ")}, + {0x1d2, 0, 0, 1, f(Yes, false, "ǒ")}, + {0x1d3, 0, 0, 1, f(Yes, false, "Ǔ")}, + {0x1d4, 0, 0, 1, f(Yes, false, "ǔ")}, + {0x1d5, 0, 0, 2, f(Yes, false, "Ǖ")}, + {0x1d6, 0, 0, 2, f(Yes, false, "ǖ")}, + {0x1d7, 0, 0, 2, f(Yes, false, "Ǘ")}, + {0x1d8, 0, 0, 2, f(Yes, false, "ǘ")}, + {0x1d9, 0, 0, 2, f(Yes, false, "Ǚ")}, + {0x1da, 0, 0, 2, f(Yes, false, "ǚ")}, + {0x1db, 0, 0, 2, f(Yes, false, "Ǜ")}, + {0x1dc, 0, 0, 2, f(Yes, false, "ǜ")}, + {0x1dd, 0, 0, 0, f(Yes, false, "")}, + {0x1de, 0, 0, 2, f(Yes, false, "Ǟ")}, + {0x1df, 0, 0, 2, f(Yes, false, "ǟ")}, + {0x1e0, 0, 0, 2, f(Yes, false, "Ǡ")}, + {0x1e1, 0, 0, 2, f(Yes, false, "ǡ")}, + {0x1e2, 0, 0, 1, f(Yes, false, "Ǣ")}, + {0x1e3, 0, 0, 1, f(Yes, false, "ǣ")}, + {0x1e4, 0, 0, 0, f(Yes, false, "")}, + {0x1e6, 0, 0, 1, f(Yes, false, "Ǧ")}, + {0x1e7, 0, 0, 1, f(Yes, false, "ǧ")}, + {0x1e8, 0, 0, 1, f(Yes, false, "Ǩ")}, + {0x1e9, 0, 0, 1, f(Yes, false, "ǩ")}, + {0x1ea, 0, 0, 1, f(Yes, true, "Ǫ")}, + {0x1eb, 0, 0, 1, f(Yes, true, "ǫ")}, + {0x1ec, 0, 0, 2, f(Yes, false, "Ǭ")}, + {0x1ed, 0, 0, 2, f(Yes, false, "ǭ")}, + {0x1ee, 0, 0, 1, f(Yes, false, "Ǯ")}, + {0x1ef, 0, 0, 1, f(Yes, false, "ǯ")}, + {0x1f0, 0, 0, 1, f(Yes, false, "ǰ")}, + {0x1f1, 0, 0, 0, g(Yes, No, false, false, "", "DZ")}, + {0x1f2, 0, 0, 0, g(Yes, No, false, false, "", "Dz")}, + {0x1f3, 0, 0, 0, g(Yes, No, false, false, "", "dz")}, + {0x1f4, 0, 0, 1, f(Yes, false, "Ǵ")}, + {0x1f5, 0, 0, 1, f(Yes, false, "ǵ")}, + {0x1f6, 0, 0, 0, f(Yes, false, "")}, + {0x1f8, 0, 0, 1, f(Yes, false, "Ǹ")}, + {0x1f9, 0, 0, 1, f(Yes, false, "ǹ")}, + {0x1fa, 0, 0, 2, f(Yes, false, "Ǻ")}, + {0x1fb, 0, 0, 2, f(Yes, false, "ǻ")}, + {0x1fc, 0, 0, 1, f(Yes, false, "Ǽ")}, + {0x1fd, 0, 0, 1, f(Yes, false, "ǽ")}, + {0x1fe, 0, 0, 1, f(Yes, false, "Ǿ")}, + {0x1ff, 0, 0, 1, f(Yes, false, "ǿ")}, + {0x200, 0, 0, 1, f(Yes, false, "Ȁ")}, + {0x201, 0, 0, 1, f(Yes, false, "ȁ")}, + {0x202, 0, 0, 1, f(Yes, false, "Ȃ")}, + {0x203, 0, 0, 1, f(Yes, false, "ȃ")}, + {0x204, 0, 0, 1, f(Yes, false, "Ȅ")}, + {0x205, 0, 0, 1, f(Yes, false, "ȅ")}, + {0x206, 0, 0, 1, f(Yes, false, "Ȇ")}, + {0x207, 0, 0, 1, f(Yes, false, "ȇ")}, + {0x208, 0, 0, 1, f(Yes, false, "Ȉ")}, + {0x209, 0, 0, 1, f(Yes, false, "ȉ")}, + {0x20a, 0, 0, 1, f(Yes, false, "Ȋ")}, + {0x20b, 0, 0, 1, f(Yes, false, "ȋ")}, + {0x20c, 0, 0, 1, f(Yes, false, "Ȍ")}, + {0x20d, 0, 0, 1, f(Yes, false, "ȍ")}, + {0x20e, 0, 0, 1, f(Yes, false, "Ȏ")}, + {0x20f, 0, 0, 1, f(Yes, false, "ȏ")}, + {0x210, 0, 0, 1, f(Yes, false, "Ȑ")}, + {0x211, 0, 0, 1, f(Yes, false, "ȑ")}, + {0x212, 0, 0, 1, f(Yes, false, "Ȓ")}, + {0x213, 0, 0, 1, f(Yes, false, "ȓ")}, + {0x214, 0, 0, 1, f(Yes, false, "Ȕ")}, + {0x215, 0, 0, 1, f(Yes, false, "ȕ")}, + {0x216, 0, 0, 1, f(Yes, false, "Ȗ")}, + {0x217, 0, 0, 1, f(Yes, false, "ȗ")}, + {0x218, 0, 0, 1, f(Yes, false, "Ș")}, + {0x219, 0, 0, 1, f(Yes, false, "ș")}, + {0x21a, 0, 0, 1, f(Yes, false, "Ț")}, + {0x21b, 0, 0, 1, f(Yes, false, "ț")}, + {0x21c, 0, 0, 0, f(Yes, false, "")}, + {0x21e, 0, 0, 1, f(Yes, false, "Ȟ")}, + {0x21f, 0, 0, 1, f(Yes, false, "ȟ")}, + {0x220, 0, 0, 0, f(Yes, false, "")}, + {0x226, 0, 0, 1, f(Yes, true, "Ȧ")}, + {0x227, 0, 0, 1, f(Yes, true, "ȧ")}, + {0x228, 0, 0, 1, f(Yes, true, "Ȩ")}, + {0x229, 0, 0, 1, f(Yes, true, "ȩ")}, + {0x22a, 0, 0, 2, f(Yes, false, "Ȫ")}, + {0x22b, 0, 0, 2, f(Yes, false, "ȫ")}, + {0x22c, 0, 0, 2, f(Yes, false, "Ȭ")}, + {0x22d, 0, 0, 2, f(Yes, false, "ȭ")}, + {0x22e, 0, 0, 1, f(Yes, true, "Ȯ")}, + {0x22f, 0, 0, 1, f(Yes, true, "ȯ")}, + {0x230, 0, 0, 2, f(Yes, false, "Ȱ")}, + {0x231, 0, 0, 2, f(Yes, false, "ȱ")}, + {0x232, 0, 0, 1, f(Yes, false, "Ȳ")}, + {0x233, 0, 0, 1, f(Yes, false, "ȳ")}, + {0x234, 0, 0, 0, f(Yes, false, "")}, + {0x292, 0, 0, 0, f(Yes, true, "")}, + {0x293, 0, 0, 0, f(Yes, false, "")}, + {0x2b0, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x2b1, 0, 0, 0, g(Yes, No, false, false, "", "ɦ")}, + {0x2b2, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x2b3, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x2b4, 0, 0, 0, g(Yes, No, false, false, "", "ɹ")}, + {0x2b5, 0, 0, 0, g(Yes, No, false, false, "", "ɻ")}, + {0x2b6, 0, 0, 0, g(Yes, No, false, false, "", "ʁ")}, + {0x2b7, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x2b8, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x2b9, 0, 0, 0, f(Yes, false, "")}, + {0x2d8, 0, 0, 1, g(Yes, No, false, false, "", " ̆")}, + {0x2d9, 0, 0, 1, g(Yes, No, false, false, "", " ̇")}, + {0x2da, 0, 0, 1, g(Yes, No, false, false, "", " ̊")}, + {0x2db, 0, 0, 1, g(Yes, No, false, false, "", " ̨")}, + {0x2dc, 0, 0, 1, g(Yes, No, false, false, "", " ̃")}, + {0x2dd, 0, 0, 1, g(Yes, No, false, false, "", " ̋")}, + {0x2de, 0, 0, 0, f(Yes, false, "")}, + {0x2e0, 0, 0, 0, g(Yes, No, false, false, "", "ɣ")}, + {0x2e1, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x2e2, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x2e3, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x2e4, 0, 0, 0, g(Yes, No, false, false, "", "ʕ")}, + {0x2e5, 0, 0, 0, f(Yes, false, "")}, + {0x300, 230, 1, 1, f(Maybe, false, "")}, + {0x305, 230, 1, 1, f(Yes, false, "")}, + {0x306, 230, 1, 1, f(Maybe, false, "")}, + {0x30d, 230, 1, 1, f(Yes, false, "")}, + {0x30f, 230, 1, 1, f(Maybe, false, "")}, + {0x310, 230, 1, 1, f(Yes, false, "")}, + {0x311, 230, 1, 1, f(Maybe, false, "")}, + {0x312, 230, 1, 1, f(Yes, false, "")}, + {0x313, 230, 1, 1, f(Maybe, false, "")}, + {0x315, 232, 1, 1, f(Yes, false, "")}, + {0x316, 220, 1, 1, f(Yes, false, "")}, + {0x31a, 232, 1, 1, f(Yes, false, "")}, + {0x31b, 216, 1, 1, f(Maybe, false, "")}, + {0x31c, 220, 1, 1, f(Yes, false, "")}, + {0x321, 202, 1, 1, f(Yes, false, "")}, + {0x323, 220, 1, 1, f(Maybe, false, "")}, + {0x327, 202, 1, 1, f(Maybe, false, "")}, + {0x329, 220, 1, 1, f(Yes, false, "")}, + {0x32d, 220, 1, 1, f(Maybe, false, "")}, + {0x32f, 220, 1, 1, f(Yes, false, "")}, + {0x330, 220, 1, 1, f(Maybe, false, "")}, + {0x332, 220, 1, 1, f(Yes, false, "")}, + {0x334, 1, 1, 1, f(Yes, false, "")}, + {0x338, 1, 1, 1, f(Maybe, false, "")}, + {0x339, 220, 1, 1, f(Yes, false, "")}, + {0x33d, 230, 1, 1, f(Yes, false, "")}, + {0x340, 230, 1, 1, f(No, false, "̀")}, + {0x341, 230, 1, 1, f(No, false, "́")}, + {0x342, 230, 1, 1, f(Maybe, false, "")}, + {0x343, 230, 1, 1, f(No, false, "̓")}, + {0x344, 230, 2, 2, f(No, false, "̈́")}, + {0x345, 240, 1, 1, f(Maybe, false, "")}, + {0x346, 230, 1, 1, f(Yes, false, "")}, + {0x347, 220, 1, 1, f(Yes, false, "")}, + {0x34a, 230, 1, 1, f(Yes, false, "")}, + {0x34d, 220, 1, 1, f(Yes, false, "")}, + {0x34f, 0, 0, 0, f(Yes, false, "")}, + {0x350, 230, 1, 1, f(Yes, false, "")}, + {0x353, 220, 1, 1, f(Yes, false, "")}, + {0x357, 230, 1, 1, f(Yes, false, "")}, + {0x358, 232, 1, 1, f(Yes, false, "")}, + {0x359, 220, 1, 1, f(Yes, false, "")}, + {0x35b, 230, 1, 1, f(Yes, false, "")}, + {0x35c, 233, 1, 1, f(Yes, false, "")}, + {0x35d, 234, 1, 1, f(Yes, false, "")}, + {0x35f, 233, 1, 1, f(Yes, false, "")}, + {0x360, 234, 1, 1, f(Yes, false, "")}, + {0x362, 233, 1, 1, f(Yes, false, "")}, + {0x363, 230, 1, 1, f(Yes, false, "")}, + {0x370, 0, 0, 0, f(Yes, false, "")}, + {0x374, 0, 0, 0, f(No, false, "ʹ")}, + {0x375, 0, 0, 0, f(Yes, false, "")}, + {0x37a, 0, 0, 1, g(Yes, No, false, false, "", " ͅ")}, + {0x37b, 0, 0, 0, f(Yes, false, "")}, + {0x37e, 0, 0, 0, f(No, false, ";")}, + {0x37f, 0, 0, 0, f(Yes, false, "")}, + {0x384, 0, 0, 1, g(Yes, No, false, false, "", " ́")}, + {0x385, 0, 0, 2, g(Yes, No, false, false, "΅", " ̈́")}, + {0x386, 0, 0, 1, f(Yes, false, "Ά")}, + {0x387, 0, 0, 0, f(No, false, "·")}, + {0x388, 0, 0, 1, f(Yes, false, "Έ")}, + {0x389, 0, 0, 1, f(Yes, false, "Ή")}, + {0x38a, 0, 0, 1, f(Yes, false, "Ί")}, + {0x38b, 0, 0, 0, f(Yes, false, "")}, + {0x38c, 0, 0, 1, f(Yes, false, "Ό")}, + {0x38d, 0, 0, 0, f(Yes, false, "")}, + {0x38e, 0, 0, 1, f(Yes, false, "Ύ")}, + {0x38f, 0, 0, 1, f(Yes, false, "Ώ")}, + {0x390, 0, 0, 2, f(Yes, false, "ΐ")}, + {0x391, 0, 0, 0, f(Yes, true, "")}, + {0x392, 0, 0, 0, f(Yes, false, "")}, + {0x395, 0, 0, 0, f(Yes, true, "")}, + {0x396, 0, 0, 0, f(Yes, false, "")}, + {0x397, 0, 0, 0, f(Yes, true, "")}, + {0x398, 0, 0, 0, f(Yes, false, "")}, + {0x399, 0, 0, 0, f(Yes, true, "")}, + {0x39a, 0, 0, 0, f(Yes, false, "")}, + {0x39f, 0, 0, 0, f(Yes, true, "")}, + {0x3a0, 0, 0, 0, f(Yes, false, "")}, + {0x3a1, 0, 0, 0, f(Yes, true, "")}, + {0x3a2, 0, 0, 0, f(Yes, false, "")}, + {0x3a5, 0, 0, 0, f(Yes, true, "")}, + {0x3a6, 0, 0, 0, f(Yes, false, "")}, + {0x3a9, 0, 0, 0, f(Yes, true, "")}, + {0x3aa, 0, 0, 1, f(Yes, false, "Ϊ")}, + {0x3ab, 0, 0, 1, f(Yes, false, "Ϋ")}, + {0x3ac, 0, 0, 1, f(Yes, true, "ά")}, + {0x3ad, 0, 0, 1, f(Yes, false, "έ")}, + {0x3ae, 0, 0, 1, f(Yes, true, "ή")}, + {0x3af, 0, 0, 1, f(Yes, false, "ί")}, + {0x3b0, 0, 0, 2, f(Yes, false, "ΰ")}, + {0x3b1, 0, 0, 0, f(Yes, true, "")}, + {0x3b2, 0, 0, 0, f(Yes, false, "")}, + {0x3b5, 0, 0, 0, f(Yes, true, "")}, + {0x3b6, 0, 0, 0, f(Yes, false, "")}, + {0x3b7, 0, 0, 0, f(Yes, true, "")}, + {0x3b8, 0, 0, 0, f(Yes, false, "")}, + {0x3b9, 0, 0, 0, f(Yes, true, "")}, + {0x3ba, 0, 0, 0, f(Yes, false, "")}, + {0x3bf, 0, 0, 0, f(Yes, true, "")}, + {0x3c0, 0, 0, 0, f(Yes, false, "")}, + {0x3c1, 0, 0, 0, f(Yes, true, "")}, + {0x3c2, 0, 0, 0, f(Yes, false, "")}, + {0x3c5, 0, 0, 0, f(Yes, true, "")}, + {0x3c6, 0, 0, 0, f(Yes, false, "")}, + {0x3c9, 0, 0, 0, f(Yes, true, "")}, + {0x3ca, 0, 0, 1, f(Yes, true, "ϊ")}, + {0x3cb, 0, 0, 1, f(Yes, true, "ϋ")}, + {0x3cc, 0, 0, 1, f(Yes, false, "ό")}, + {0x3cd, 0, 0, 1, f(Yes, false, "ύ")}, + {0x3ce, 0, 0, 1, f(Yes, true, "ώ")}, + {0x3cf, 0, 0, 0, f(Yes, false, "")}, + {0x3d0, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x3d1, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x3d2, 0, 0, 0, g(Yes, No, true, false, "", "Υ")}, + {0x3d3, 0, 0, 1, g(Yes, No, false, false, "ϓ", "Ύ")}, + {0x3d4, 0, 0, 1, g(Yes, No, false, false, "ϔ", "Ϋ")}, + {0x3d5, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x3d6, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x3d7, 0, 0, 0, f(Yes, false, "")}, + {0x3f0, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x3f1, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x3f2, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x3f3, 0, 0, 0, f(Yes, false, "")}, + {0x3f4, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x3f5, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x3f6, 0, 0, 0, f(Yes, false, "")}, + {0x3f9, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x3fa, 0, 0, 0, f(Yes, false, "")}, + {0x400, 0, 0, 1, f(Yes, false, "Ѐ")}, + {0x401, 0, 0, 1, f(Yes, false, "Ё")}, + {0x402, 0, 0, 0, f(Yes, false, "")}, + {0x403, 0, 0, 1, f(Yes, false, "Ѓ")}, + {0x404, 0, 0, 0, f(Yes, false, "")}, + {0x406, 0, 0, 0, f(Yes, true, "")}, + {0x407, 0, 0, 1, f(Yes, false, "Ї")}, + {0x408, 0, 0, 0, f(Yes, false, "")}, + {0x40c, 0, 0, 1, f(Yes, false, "Ќ")}, + {0x40d, 0, 0, 1, f(Yes, false, "Ѝ")}, + {0x40e, 0, 0, 1, f(Yes, false, "Ў")}, + {0x40f, 0, 0, 0, f(Yes, false, "")}, + {0x410, 0, 0, 0, f(Yes, true, "")}, + {0x411, 0, 0, 0, f(Yes, false, "")}, + {0x413, 0, 0, 0, f(Yes, true, "")}, + {0x414, 0, 0, 0, f(Yes, false, "")}, + {0x415, 0, 0, 0, f(Yes, true, "")}, + {0x419, 0, 0, 1, f(Yes, false, "Й")}, + {0x41a, 0, 0, 0, f(Yes, true, "")}, + {0x41b, 0, 0, 0, f(Yes, false, "")}, + {0x41e, 0, 0, 0, f(Yes, true, "")}, + {0x41f, 0, 0, 0, f(Yes, false, "")}, + {0x423, 0, 0, 0, f(Yes, true, "")}, + {0x424, 0, 0, 0, f(Yes, false, "")}, + {0x427, 0, 0, 0, f(Yes, true, "")}, + {0x428, 0, 0, 0, f(Yes, false, "")}, + {0x42b, 0, 0, 0, f(Yes, true, "")}, + {0x42c, 0, 0, 0, f(Yes, false, "")}, + {0x42d, 0, 0, 0, f(Yes, true, "")}, + {0x42e, 0, 0, 0, f(Yes, false, "")}, + {0x430, 0, 0, 0, f(Yes, true, "")}, + {0x431, 0, 0, 0, f(Yes, false, "")}, + {0x433, 0, 0, 0, f(Yes, true, "")}, + {0x434, 0, 0, 0, f(Yes, false, "")}, + {0x435, 0, 0, 0, f(Yes, true, "")}, + {0x439, 0, 0, 1, f(Yes, false, "й")}, + {0x43a, 0, 0, 0, f(Yes, true, "")}, + {0x43b, 0, 0, 0, f(Yes, false, "")}, + {0x43e, 0, 0, 0, f(Yes, true, "")}, + {0x43f, 0, 0, 0, f(Yes, false, "")}, + {0x443, 0, 0, 0, f(Yes, true, "")}, + {0x444, 0, 0, 0, f(Yes, false, "")}, + {0x447, 0, 0, 0, f(Yes, true, "")}, + {0x448, 0, 0, 0, f(Yes, false, "")}, + {0x44b, 0, 0, 0, f(Yes, true, "")}, + {0x44c, 0, 0, 0, f(Yes, false, "")}, + {0x44d, 0, 0, 0, f(Yes, true, "")}, + {0x44e, 0, 0, 0, f(Yes, false, "")}, + {0x450, 0, 0, 1, f(Yes, false, "ѐ")}, + {0x451, 0, 0, 1, f(Yes, false, "ё")}, + {0x452, 0, 0, 0, f(Yes, false, "")}, + {0x453, 0, 0, 1, f(Yes, false, "ѓ")}, + {0x454, 0, 0, 0, f(Yes, false, "")}, + {0x456, 0, 0, 0, f(Yes, true, "")}, + {0x457, 0, 0, 1, f(Yes, false, "ї")}, + {0x458, 0, 0, 0, f(Yes, false, "")}, + {0x45c, 0, 0, 1, f(Yes, false, "ќ")}, + {0x45d, 0, 0, 1, f(Yes, false, "ѝ")}, + {0x45e, 0, 0, 1, f(Yes, false, "ў")}, + {0x45f, 0, 0, 0, f(Yes, false, "")}, + {0x474, 0, 0, 0, f(Yes, true, "")}, + {0x476, 0, 0, 1, f(Yes, false, "Ѷ")}, + {0x477, 0, 0, 1, f(Yes, false, "ѷ")}, + {0x478, 0, 0, 0, f(Yes, false, "")}, + {0x483, 230, 1, 1, f(Yes, false, "")}, + {0x488, 0, 0, 0, f(Yes, false, "")}, + {0x4c1, 0, 0, 1, f(Yes, false, "Ӂ")}, + {0x4c2, 0, 0, 1, f(Yes, false, "ӂ")}, + {0x4c3, 0, 0, 0, f(Yes, false, "")}, + {0x4d0, 0, 0, 1, f(Yes, false, "Ӑ")}, + {0x4d1, 0, 0, 1, f(Yes, false, "ӑ")}, + {0x4d2, 0, 0, 1, f(Yes, false, "Ӓ")}, + {0x4d3, 0, 0, 1, f(Yes, false, "ӓ")}, + {0x4d4, 0, 0, 0, f(Yes, false, "")}, + {0x4d6, 0, 0, 1, f(Yes, false, "Ӗ")}, + {0x4d7, 0, 0, 1, f(Yes, false, "ӗ")}, + {0x4d8, 0, 0, 0, f(Yes, true, "")}, + {0x4da, 0, 0, 1, f(Yes, false, "Ӛ")}, + {0x4db, 0, 0, 1, f(Yes, false, "ӛ")}, + {0x4dc, 0, 0, 1, f(Yes, false, "Ӝ")}, + {0x4dd, 0, 0, 1, f(Yes, false, "ӝ")}, + {0x4de, 0, 0, 1, f(Yes, false, "Ӟ")}, + {0x4df, 0, 0, 1, f(Yes, false, "ӟ")}, + {0x4e0, 0, 0, 0, f(Yes, false, "")}, + {0x4e2, 0, 0, 1, f(Yes, false, "Ӣ")}, + {0x4e3, 0, 0, 1, f(Yes, false, "ӣ")}, + {0x4e4, 0, 0, 1, f(Yes, false, "Ӥ")}, + {0x4e5, 0, 0, 1, f(Yes, false, "ӥ")}, + {0x4e6, 0, 0, 1, f(Yes, false, "Ӧ")}, + {0x4e7, 0, 0, 1, f(Yes, false, "ӧ")}, + {0x4e8, 0, 0, 0, f(Yes, true, "")}, + {0x4ea, 0, 0, 1, f(Yes, false, "Ӫ")}, + {0x4eb, 0, 0, 1, f(Yes, false, "ӫ")}, + {0x4ec, 0, 0, 1, f(Yes, false, "Ӭ")}, + {0x4ed, 0, 0, 1, f(Yes, false, "ӭ")}, + {0x4ee, 0, 0, 1, f(Yes, false, "Ӯ")}, + {0x4ef, 0, 0, 1, f(Yes, false, "ӯ")}, + {0x4f0, 0, 0, 1, f(Yes, false, "Ӱ")}, + {0x4f1, 0, 0, 1, f(Yes, false, "ӱ")}, + {0x4f2, 0, 0, 1, f(Yes, false, "Ӳ")}, + {0x4f3, 0, 0, 1, f(Yes, false, "ӳ")}, + {0x4f4, 0, 0, 1, f(Yes, false, "Ӵ")}, + {0x4f5, 0, 0, 1, f(Yes, false, "ӵ")}, + {0x4f6, 0, 0, 0, f(Yes, false, "")}, + {0x4f8, 0, 0, 1, f(Yes, false, "Ӹ")}, + {0x4f9, 0, 0, 1, f(Yes, false, "ӹ")}, + {0x4fa, 0, 0, 0, f(Yes, false, "")}, + {0x587, 0, 0, 0, g(Yes, No, false, false, "", "եւ")}, + {0x588, 0, 0, 0, f(Yes, false, "")}, + {0x591, 220, 1, 1, f(Yes, false, "")}, + {0x592, 230, 1, 1, f(Yes, false, "")}, + {0x596, 220, 1, 1, f(Yes, false, "")}, + {0x597, 230, 1, 1, f(Yes, false, "")}, + {0x59a, 222, 1, 1, f(Yes, false, "")}, + {0x59b, 220, 1, 1, f(Yes, false, "")}, + {0x59c, 230, 1, 1, f(Yes, false, "")}, + {0x5a2, 220, 1, 1, f(Yes, false, "")}, + {0x5a8, 230, 1, 1, f(Yes, false, "")}, + {0x5aa, 220, 1, 1, f(Yes, false, "")}, + {0x5ab, 230, 1, 1, f(Yes, false, "")}, + {0x5ad, 222, 1, 1, f(Yes, false, "")}, + {0x5ae, 228, 1, 1, f(Yes, false, "")}, + {0x5af, 230, 1, 1, f(Yes, false, "")}, + {0x5b0, 10, 1, 1, f(Yes, false, "")}, + {0x5b1, 11, 1, 1, f(Yes, false, "")}, + {0x5b2, 12, 1, 1, f(Yes, false, "")}, + {0x5b3, 13, 1, 1, f(Yes, false, "")}, + {0x5b4, 14, 1, 1, f(Yes, false, "")}, + {0x5b5, 15, 1, 1, f(Yes, false, "")}, + {0x5b6, 16, 1, 1, f(Yes, false, "")}, + {0x5b7, 17, 1, 1, f(Yes, false, "")}, + {0x5b8, 18, 1, 1, f(Yes, false, "")}, + {0x5b9, 19, 1, 1, f(Yes, false, "")}, + {0x5bb, 20, 1, 1, f(Yes, false, "")}, + {0x5bc, 21, 1, 1, f(Yes, false, "")}, + {0x5bd, 22, 1, 1, f(Yes, false, "")}, + {0x5be, 0, 0, 0, f(Yes, false, "")}, + {0x5bf, 23, 1, 1, f(Yes, false, "")}, + {0x5c0, 0, 0, 0, f(Yes, false, "")}, + {0x5c1, 24, 1, 1, f(Yes, false, "")}, + {0x5c2, 25, 1, 1, f(Yes, false, "")}, + {0x5c3, 0, 0, 0, f(Yes, false, "")}, + {0x5c4, 230, 1, 1, f(Yes, false, "")}, + {0x5c5, 220, 1, 1, f(Yes, false, "")}, + {0x5c6, 0, 0, 0, f(Yes, false, "")}, + {0x5c7, 18, 1, 1, f(Yes, false, "")}, + {0x5c8, 0, 0, 0, f(Yes, false, "")}, + {0x610, 230, 1, 1, f(Yes, false, "")}, + {0x618, 30, 1, 1, f(Yes, false, "")}, + {0x619, 31, 1, 1, f(Yes, false, "")}, + {0x61a, 32, 1, 1, f(Yes, false, "")}, + {0x61b, 0, 0, 0, f(Yes, false, "")}, + {0x622, 0, 0, 1, f(Yes, false, "آ")}, + {0x623, 0, 0, 1, f(Yes, false, "أ")}, + {0x624, 0, 0, 1, f(Yes, false, "ؤ")}, + {0x625, 0, 0, 1, f(Yes, false, "إ")}, + {0x626, 0, 0, 1, f(Yes, false, "ئ")}, + {0x627, 0, 0, 0, f(Yes, true, "")}, + {0x628, 0, 0, 0, f(Yes, false, "")}, + {0x648, 0, 0, 0, f(Yes, true, "")}, + {0x649, 0, 0, 0, f(Yes, false, "")}, + {0x64a, 0, 0, 0, f(Yes, true, "")}, + {0x64b, 27, 1, 1, f(Yes, false, "")}, + {0x64c, 28, 1, 1, f(Yes, false, "")}, + {0x64d, 29, 1, 1, f(Yes, false, "")}, + {0x64e, 30, 1, 1, f(Yes, false, "")}, + {0x64f, 31, 1, 1, f(Yes, false, "")}, + {0x650, 32, 1, 1, f(Yes, false, "")}, + {0x651, 33, 1, 1, f(Yes, false, "")}, + {0x652, 34, 1, 1, f(Yes, false, "")}, + {0x653, 230, 1, 1, f(Maybe, false, "")}, + {0x655, 220, 1, 1, f(Maybe, false, "")}, + {0x656, 220, 1, 1, f(Yes, false, "")}, + {0x657, 230, 1, 1, f(Yes, false, "")}, + {0x65c, 220, 1, 1, f(Yes, false, "")}, + {0x65d, 230, 1, 1, f(Yes, false, "")}, + {0x65f, 220, 1, 1, f(Yes, false, "")}, + {0x660, 0, 0, 0, f(Yes, false, "")}, + {0x670, 35, 1, 1, f(Yes, false, "")}, + {0x671, 0, 0, 0, f(Yes, false, "")}, + {0x675, 0, 0, 0, g(Yes, No, false, false, "", "اٴ")}, + {0x676, 0, 0, 0, g(Yes, No, false, false, "", "وٴ")}, + {0x677, 0, 0, 0, g(Yes, No, false, false, "", "ۇٴ")}, + {0x678, 0, 0, 0, g(Yes, No, false, false, "", "يٴ")}, + {0x679, 0, 0, 0, f(Yes, false, "")}, + {0x6c0, 0, 0, 1, f(Yes, false, "ۀ")}, + {0x6c1, 0, 0, 0, f(Yes, true, "")}, + {0x6c2, 0, 0, 1, f(Yes, false, "ۂ")}, + {0x6c3, 0, 0, 0, f(Yes, false, "")}, + {0x6d2, 0, 0, 0, f(Yes, true, "")}, + {0x6d3, 0, 0, 1, f(Yes, false, "ۓ")}, + {0x6d4, 0, 0, 0, f(Yes, false, "")}, + {0x6d5, 0, 0, 0, f(Yes, true, "")}, + {0x6d6, 230, 1, 1, f(Yes, false, "")}, + {0x6dd, 0, 0, 0, f(Yes, false, "")}, + {0x6df, 230, 1, 1, f(Yes, false, "")}, + {0x6e3, 220, 1, 1, f(Yes, false, "")}, + {0x6e4, 230, 1, 1, f(Yes, false, "")}, + {0x6e5, 0, 0, 0, f(Yes, false, "")}, + {0x6e7, 230, 1, 1, f(Yes, false, "")}, + {0x6e9, 0, 0, 0, f(Yes, false, "")}, + {0x6ea, 220, 1, 1, f(Yes, false, "")}, + {0x6eb, 230, 1, 1, f(Yes, false, "")}, + {0x6ed, 220, 1, 1, f(Yes, false, "")}, + {0x6ee, 0, 0, 0, f(Yes, false, "")}, + {0x711, 36, 1, 1, f(Yes, false, "")}, + {0x712, 0, 0, 0, f(Yes, false, "")}, + {0x730, 230, 1, 1, f(Yes, false, "")}, + {0x731, 220, 1, 1, f(Yes, false, "")}, + {0x732, 230, 1, 1, f(Yes, false, "")}, + {0x734, 220, 1, 1, f(Yes, false, "")}, + {0x735, 230, 1, 1, f(Yes, false, "")}, + {0x737, 220, 1, 1, f(Yes, false, "")}, + {0x73a, 230, 1, 1, f(Yes, false, "")}, + {0x73b, 220, 1, 1, f(Yes, false, "")}, + {0x73d, 230, 1, 1, f(Yes, false, "")}, + {0x73e, 220, 1, 1, f(Yes, false, "")}, + {0x73f, 230, 1, 1, f(Yes, false, "")}, + {0x742, 220, 1, 1, f(Yes, false, "")}, + {0x743, 230, 1, 1, f(Yes, false, "")}, + {0x744, 220, 1, 1, f(Yes, false, "")}, + {0x745, 230, 1, 1, f(Yes, false, "")}, + {0x746, 220, 1, 1, f(Yes, false, "")}, + {0x747, 230, 1, 1, f(Yes, false, "")}, + {0x748, 220, 1, 1, f(Yes, false, "")}, + {0x749, 230, 1, 1, f(Yes, false, "")}, + {0x74b, 0, 0, 0, f(Yes, false, "")}, + {0x7eb, 230, 1, 1, f(Yes, false, "")}, + {0x7f2, 220, 1, 1, f(Yes, false, "")}, + {0x7f3, 230, 1, 1, f(Yes, false, "")}, + {0x7f4, 0, 0, 0, f(Yes, false, "")}, + {0x816, 230, 1, 1, f(Yes, false, "")}, + {0x81a, 0, 0, 0, f(Yes, false, "")}, + {0x81b, 230, 1, 1, f(Yes, false, "")}, + {0x824, 0, 0, 0, f(Yes, false, "")}, + {0x825, 230, 1, 1, f(Yes, false, "")}, + {0x828, 0, 0, 0, f(Yes, false, "")}, + {0x829, 230, 1, 1, f(Yes, false, "")}, + {0x82e, 0, 0, 0, f(Yes, false, "")}, + {0x859, 220, 1, 1, f(Yes, false, "")}, + {0x85c, 0, 0, 0, f(Yes, false, "")}, + {0x8d4, 230, 1, 1, f(Yes, false, "")}, + {0x8e2, 0, 0, 0, f(Yes, false, "")}, + {0x8e3, 220, 1, 1, f(Yes, false, "")}, + {0x8e4, 230, 1, 1, f(Yes, false, "")}, + {0x8e6, 220, 1, 1, f(Yes, false, "")}, + {0x8e7, 230, 1, 1, f(Yes, false, "")}, + {0x8e9, 220, 1, 1, f(Yes, false, "")}, + {0x8ea, 230, 1, 1, f(Yes, false, "")}, + {0x8ed, 220, 1, 1, f(Yes, false, "")}, + {0x8f0, 27, 1, 1, f(Yes, false, "")}, + {0x8f1, 28, 1, 1, f(Yes, false, "")}, + {0x8f2, 29, 1, 1, f(Yes, false, "")}, + {0x8f3, 230, 1, 1, f(Yes, false, "")}, + {0x8f6, 220, 1, 1, f(Yes, false, "")}, + {0x8f7, 230, 1, 1, f(Yes, false, "")}, + {0x8f9, 220, 1, 1, f(Yes, false, "")}, + {0x8fb, 230, 1, 1, f(Yes, false, "")}, + {0x900, 0, 0, 0, f(Yes, false, "")}, + {0x928, 0, 0, 0, f(Yes, true, "")}, + {0x929, 0, 0, 1, f(Yes, false, "ऩ")}, + {0x92a, 0, 0, 0, f(Yes, false, "")}, + {0x930, 0, 0, 0, f(Yes, true, "")}, + {0x931, 0, 0, 1, f(Yes, false, "ऱ")}, + {0x932, 0, 0, 0, f(Yes, false, "")}, + {0x933, 0, 0, 0, f(Yes, true, "")}, + {0x934, 0, 0, 1, f(Yes, false, "ऴ")}, + {0x935, 0, 0, 0, f(Yes, false, "")}, + {0x93c, 7, 1, 1, f(Maybe, false, "")}, + {0x93d, 0, 0, 0, f(Yes, false, "")}, + {0x94d, 9, 1, 1, f(Yes, false, "")}, + {0x94e, 0, 0, 0, f(Yes, false, "")}, + {0x951, 230, 1, 1, f(Yes, false, "")}, + {0x952, 220, 1, 1, f(Yes, false, "")}, + {0x953, 230, 1, 1, f(Yes, false, "")}, + {0x955, 0, 0, 0, f(Yes, false, "")}, + {0x958, 0, 0, 1, f(No, false, "क़")}, + {0x959, 0, 0, 1, f(No, false, "ख़")}, + {0x95a, 0, 0, 1, f(No, false, "ग़")}, + {0x95b, 0, 0, 1, f(No, false, "ज़")}, + {0x95c, 0, 0, 1, f(No, false, "ड़")}, + {0x95d, 0, 0, 1, f(No, false, "ढ़")}, + {0x95e, 0, 0, 1, f(No, false, "फ़")}, + {0x95f, 0, 0, 1, f(No, false, "य़")}, + {0x960, 0, 0, 0, f(Yes, false, "")}, + {0x9bc, 7, 1, 1, f(Yes, false, "")}, + {0x9bd, 0, 0, 0, f(Yes, false, "")}, + {0x9be, 0, 1, 1, f(Maybe, false, "")}, + {0x9bf, 0, 0, 0, f(Yes, false, "")}, + {0x9c7, 0, 0, 0, f(Yes, true, "")}, + {0x9c8, 0, 0, 0, f(Yes, false, "")}, + {0x9cb, 0, 0, 1, f(Yes, false, "ো")}, + {0x9cc, 0, 0, 1, f(Yes, false, "ৌ")}, + {0x9cd, 9, 1, 1, f(Yes, false, "")}, + {0x9ce, 0, 0, 0, f(Yes, false, "")}, + {0x9d7, 0, 1, 1, f(Maybe, false, "")}, + {0x9d8, 0, 0, 0, f(Yes, false, "")}, + {0x9dc, 0, 0, 1, f(No, false, "ড়")}, + {0x9dd, 0, 0, 1, f(No, false, "ঢ়")}, + {0x9de, 0, 0, 0, f(Yes, false, "")}, + {0x9df, 0, 0, 1, f(No, false, "য়")}, + {0x9e0, 0, 0, 0, f(Yes, false, "")}, + {0xa33, 0, 0, 1, f(No, false, "ਲ਼")}, + {0xa34, 0, 0, 0, f(Yes, false, "")}, + {0xa36, 0, 0, 1, f(No, false, "ਸ਼")}, + {0xa37, 0, 0, 0, f(Yes, false, "")}, + {0xa3c, 7, 1, 1, f(Yes, false, "")}, + {0xa3d, 0, 0, 0, f(Yes, false, "")}, + {0xa4d, 9, 1, 1, f(Yes, false, "")}, + {0xa4e, 0, 0, 0, f(Yes, false, "")}, + {0xa59, 0, 0, 1, f(No, false, "ਖ਼")}, + {0xa5a, 0, 0, 1, f(No, false, "ਗ਼")}, + {0xa5b, 0, 0, 1, f(No, false, "ਜ਼")}, + {0xa5c, 0, 0, 0, f(Yes, false, "")}, + {0xa5e, 0, 0, 1, f(No, false, "ਫ਼")}, + {0xa5f, 0, 0, 0, f(Yes, false, "")}, + {0xabc, 7, 1, 1, f(Yes, false, "")}, + {0xabd, 0, 0, 0, f(Yes, false, "")}, + {0xacd, 9, 1, 1, f(Yes, false, "")}, + {0xace, 0, 0, 0, f(Yes, false, "")}, + {0xb3c, 7, 1, 1, f(Yes, false, "")}, + {0xb3d, 0, 0, 0, f(Yes, false, "")}, + {0xb3e, 0, 1, 1, f(Maybe, false, "")}, + {0xb3f, 0, 0, 0, f(Yes, false, "")}, + {0xb47, 0, 0, 0, f(Yes, true, "")}, + {0xb48, 0, 0, 1, f(Yes, false, "ୈ")}, + {0xb49, 0, 0, 0, f(Yes, false, "")}, + {0xb4b, 0, 0, 1, f(Yes, false, "ୋ")}, + {0xb4c, 0, 0, 1, f(Yes, false, "ୌ")}, + {0xb4d, 9, 1, 1, f(Yes, false, "")}, + {0xb4e, 0, 0, 0, f(Yes, false, "")}, + {0xb56, 0, 1, 1, f(Maybe, false, "")}, + {0xb58, 0, 0, 0, f(Yes, false, "")}, + {0xb5c, 0, 0, 1, f(No, false, "ଡ଼")}, + {0xb5d, 0, 0, 1, f(No, false, "ଢ଼")}, + {0xb5e, 0, 0, 0, f(Yes, false, "")}, + {0xb92, 0, 0, 0, f(Yes, true, "")}, + {0xb93, 0, 0, 0, f(Yes, false, "")}, + {0xb94, 0, 0, 1, f(Yes, false, "ஔ")}, + {0xb95, 0, 0, 0, f(Yes, false, "")}, + {0xbbe, 0, 1, 1, f(Maybe, false, "")}, + {0xbbf, 0, 0, 0, f(Yes, false, "")}, + {0xbc6, 0, 0, 0, f(Yes, true, "")}, + {0xbc8, 0, 0, 0, f(Yes, false, "")}, + {0xbca, 0, 0, 1, f(Yes, false, "ொ")}, + {0xbcb, 0, 0, 1, f(Yes, false, "ோ")}, + {0xbcc, 0, 0, 1, f(Yes, false, "ௌ")}, + {0xbcd, 9, 1, 1, f(Yes, false, "")}, + {0xbce, 0, 0, 0, f(Yes, false, "")}, + {0xbd7, 0, 1, 1, f(Maybe, false, "")}, + {0xbd8, 0, 0, 0, f(Yes, false, "")}, + {0xc46, 0, 0, 0, f(Yes, true, "")}, + {0xc47, 0, 0, 0, f(Yes, false, "")}, + {0xc48, 0, 0, 1, f(Yes, false, "ై")}, + {0xc49, 0, 0, 0, f(Yes, false, "")}, + {0xc4d, 9, 1, 1, f(Yes, false, "")}, + {0xc4e, 0, 0, 0, f(Yes, false, "")}, + {0xc55, 84, 1, 1, f(Yes, false, "")}, + {0xc56, 91, 1, 1, f(Maybe, false, "")}, + {0xc57, 0, 0, 0, f(Yes, false, "")}, + {0xcbc, 7, 1, 1, f(Yes, false, "")}, + {0xcbd, 0, 0, 0, f(Yes, false, "")}, + {0xcbf, 0, 0, 0, f(Yes, true, "")}, + {0xcc0, 0, 0, 1, f(Yes, false, "ೀ")}, + {0xcc1, 0, 0, 0, f(Yes, false, "")}, + {0xcc2, 0, 1, 1, f(Maybe, false, "")}, + {0xcc3, 0, 0, 0, f(Yes, false, "")}, + {0xcc6, 0, 0, 0, f(Yes, true, "")}, + {0xcc7, 0, 0, 1, f(Yes, false, "ೇ")}, + {0xcc8, 0, 0, 1, f(Yes, false, "ೈ")}, + {0xcc9, 0, 0, 0, f(Yes, false, "")}, + {0xcca, 0, 0, 1, f(Yes, true, "ೊ")}, + {0xccb, 0, 0, 2, f(Yes, false, "ೋ")}, + {0xccc, 0, 0, 0, f(Yes, false, "")}, + {0xccd, 9, 1, 1, f(Yes, false, "")}, + {0xcce, 0, 0, 0, f(Yes, false, "")}, + {0xcd5, 0, 1, 1, f(Maybe, false, "")}, + {0xcd7, 0, 0, 0, f(Yes, false, "")}, + {0xd3b, 9, 1, 1, f(Yes, false, "")}, + {0xd3d, 0, 0, 0, f(Yes, false, "")}, + {0xd3e, 0, 1, 1, f(Maybe, false, "")}, + {0xd3f, 0, 0, 0, f(Yes, false, "")}, + {0xd46, 0, 0, 0, f(Yes, true, "")}, + {0xd48, 0, 0, 0, f(Yes, false, "")}, + {0xd4a, 0, 0, 1, f(Yes, false, "ൊ")}, + {0xd4b, 0, 0, 1, f(Yes, false, "ോ")}, + {0xd4c, 0, 0, 1, f(Yes, false, "ൌ")}, + {0xd4d, 9, 1, 1, f(Yes, false, "")}, + {0xd4e, 0, 0, 0, f(Yes, false, "")}, + {0xd57, 0, 1, 1, f(Maybe, false, "")}, + {0xd58, 0, 0, 0, f(Yes, false, "")}, + {0xdca, 9, 1, 1, f(Maybe, false, "")}, + {0xdcb, 0, 0, 0, f(Yes, false, "")}, + {0xdcf, 0, 1, 1, f(Maybe, false, "")}, + {0xdd0, 0, 0, 0, f(Yes, false, "")}, + {0xdd9, 0, 0, 0, f(Yes, true, "")}, + {0xdda, 0, 0, 1, f(Yes, false, "ේ")}, + {0xddb, 0, 0, 0, f(Yes, false, "")}, + {0xddc, 0, 0, 1, f(Yes, true, "ො")}, + {0xddd, 0, 0, 2, f(Yes, false, "ෝ")}, + {0xdde, 0, 0, 1, f(Yes, false, "ෞ")}, + {0xddf, 0, 1, 1, f(Maybe, false, "")}, + {0xde0, 0, 0, 0, f(Yes, false, "")}, + {0xe33, 0, 0, 0, g(Yes, No, false, false, "", "ํา")}, + {0xe34, 0, 0, 0, f(Yes, false, "")}, + {0xe38, 103, 1, 1, f(Yes, false, "")}, + {0xe3a, 9, 1, 1, f(Yes, false, "")}, + {0xe3b, 0, 0, 0, f(Yes, false, "")}, + {0xe48, 107, 1, 1, f(Yes, false, "")}, + {0xe4c, 0, 0, 0, f(Yes, false, "")}, + {0xeb3, 0, 0, 0, g(Yes, No, false, false, "", "ໍາ")}, + {0xeb4, 0, 0, 0, f(Yes, false, "")}, + {0xeb8, 118, 1, 1, f(Yes, false, "")}, + {0xeba, 0, 0, 0, f(Yes, false, "")}, + {0xec8, 122, 1, 1, f(Yes, false, "")}, + {0xecc, 0, 0, 0, f(Yes, false, "")}, + {0xedc, 0, 0, 0, g(Yes, No, false, false, "", "ຫນ")}, + {0xedd, 0, 0, 0, g(Yes, No, false, false, "", "ຫມ")}, + {0xede, 0, 0, 0, f(Yes, false, "")}, + {0xf0c, 0, 0, 0, g(Yes, No, false, false, "", "་")}, + {0xf0d, 0, 0, 0, f(Yes, false, "")}, + {0xf18, 220, 1, 1, f(Yes, false, "")}, + {0xf1a, 0, 0, 0, f(Yes, false, "")}, + {0xf35, 220, 1, 1, f(Yes, false, "")}, + {0xf36, 0, 0, 0, f(Yes, false, "")}, + {0xf37, 220, 1, 1, f(Yes, false, "")}, + {0xf38, 0, 0, 0, f(Yes, false, "")}, + {0xf39, 216, 1, 1, f(Yes, false, "")}, + {0xf3a, 0, 0, 0, f(Yes, false, "")}, + {0xf43, 0, 0, 0, f(No, false, "གྷ")}, + {0xf44, 0, 0, 0, f(Yes, false, "")}, + {0xf4d, 0, 0, 0, f(No, false, "ཌྷ")}, + {0xf4e, 0, 0, 0, f(Yes, false, "")}, + {0xf52, 0, 0, 0, f(No, false, "དྷ")}, + {0xf53, 0, 0, 0, f(Yes, false, "")}, + {0xf57, 0, 0, 0, f(No, false, "བྷ")}, + {0xf58, 0, 0, 0, f(Yes, false, "")}, + {0xf5c, 0, 0, 0, f(No, false, "ཛྷ")}, + {0xf5d, 0, 0, 0, f(Yes, false, "")}, + {0xf69, 0, 0, 0, f(No, false, "ཀྵ")}, + {0xf6a, 0, 0, 0, f(Yes, false, "")}, + {0xf71, 129, 1, 1, f(Yes, false, "")}, + {0xf72, 130, 1, 1, f(Yes, false, "")}, + {0xf73, 0, 2, 2, f(No, false, "ཱི")}, + {0xf74, 132, 1, 1, f(Yes, false, "")}, + {0xf75, 0, 2, 2, f(No, false, "ཱུ")}, + {0xf76, 0, 0, 1, f(No, false, "ྲྀ")}, + {0xf77, 0, 0, 2, g(Yes, No, false, false, "", "ྲཱྀ")}, + {0xf78, 0, 0, 1, f(No, false, "ླྀ")}, + {0xf79, 0, 0, 2, g(Yes, No, false, false, "", "ླཱྀ")}, + {0xf7a, 130, 1, 1, f(Yes, false, "")}, + {0xf7e, 0, 0, 0, f(Yes, false, "")}, + {0xf80, 130, 1, 1, f(Yes, false, "")}, + {0xf81, 0, 2, 2, f(No, false, "ཱྀ")}, + {0xf82, 230, 1, 1, f(Yes, false, "")}, + {0xf84, 9, 1, 1, f(Yes, false, "")}, + {0xf85, 0, 0, 0, f(Yes, false, "")}, + {0xf86, 230, 1, 1, f(Yes, false, "")}, + {0xf88, 0, 0, 0, f(Yes, false, "")}, + {0xf93, 0, 0, 0, f(No, false, "ྒྷ")}, + {0xf94, 0, 0, 0, f(Yes, false, "")}, + {0xf9d, 0, 0, 0, f(No, false, "ྜྷ")}, + {0xf9e, 0, 0, 0, f(Yes, false, "")}, + {0xfa2, 0, 0, 0, f(No, false, "ྡྷ")}, + {0xfa3, 0, 0, 0, f(Yes, false, "")}, + {0xfa7, 0, 0, 0, f(No, false, "ྦྷ")}, + {0xfa8, 0, 0, 0, f(Yes, false, "")}, + {0xfac, 0, 0, 0, f(No, false, "ྫྷ")}, + {0xfad, 0, 0, 0, f(Yes, false, "")}, + {0xfb9, 0, 0, 0, f(No, false, "ྐྵ")}, + {0xfba, 0, 0, 0, f(Yes, false, "")}, + {0xfc6, 220, 1, 1, f(Yes, false, "")}, + {0xfc7, 0, 0, 0, f(Yes, false, "")}, + {0x1025, 0, 0, 0, f(Yes, true, "")}, + {0x1026, 0, 0, 1, f(Yes, false, "ဦ")}, + {0x1027, 0, 0, 0, f(Yes, false, "")}, + {0x102e, 0, 1, 1, f(Maybe, false, "")}, + {0x102f, 0, 0, 0, f(Yes, false, "")}, + {0x1037, 7, 1, 1, f(Yes, false, "")}, + {0x1038, 0, 0, 0, f(Yes, false, "")}, + {0x1039, 9, 1, 1, f(Yes, false, "")}, + {0x103b, 0, 0, 0, f(Yes, false, "")}, + {0x108d, 220, 1, 1, f(Yes, false, "")}, + {0x108e, 0, 0, 0, f(Yes, false, "")}, + {0x10fc, 0, 0, 0, g(Yes, No, false, false, "", "ნ")}, + {0x10fd, 0, 0, 0, f(Yes, false, "")}, + {0x1100, 0, 0, 0, f(Yes, true, "")}, + {0x1113, 0, 0, 0, f(Yes, false, "")}, + {0x1161, 0, 1, 1, f(Maybe, true, "")}, + {0x1176, 0, 0, 0, f(Yes, false, "")}, + {0x11a8, 0, 1, 1, f(Maybe, false, "")}, + {0x11c3, 0, 0, 0, f(Yes, false, "")}, + {0x135d, 230, 1, 1, f(Yes, false, "")}, + {0x1360, 0, 0, 0, f(Yes, false, "")}, + {0x1714, 9, 1, 1, f(Yes, false, "")}, + {0x1715, 0, 0, 0, f(Yes, false, "")}, + {0x1734, 9, 1, 1, f(Yes, false, "")}, + {0x1735, 0, 0, 0, f(Yes, false, "")}, + {0x17d2, 9, 1, 1, f(Yes, false, "")}, + {0x17d3, 0, 0, 0, f(Yes, false, "")}, + {0x17dd, 230, 1, 1, f(Yes, false, "")}, + {0x17de, 0, 0, 0, f(Yes, false, "")}, + {0x18a9, 228, 1, 1, f(Yes, false, "")}, + {0x18aa, 0, 0, 0, f(Yes, false, "")}, + {0x1939, 222, 1, 1, f(Yes, false, "")}, + {0x193a, 230, 1, 1, f(Yes, false, "")}, + {0x193b, 220, 1, 1, f(Yes, false, "")}, + {0x193c, 0, 0, 0, f(Yes, false, "")}, + {0x1a17, 230, 1, 1, f(Yes, false, "")}, + {0x1a18, 220, 1, 1, f(Yes, false, "")}, + {0x1a19, 0, 0, 0, f(Yes, false, "")}, + {0x1a60, 9, 1, 1, f(Yes, false, "")}, + {0x1a61, 0, 0, 0, f(Yes, false, "")}, + {0x1a75, 230, 1, 1, f(Yes, false, "")}, + {0x1a7d, 0, 0, 0, f(Yes, false, "")}, + {0x1a7f, 220, 1, 1, f(Yes, false, "")}, + {0x1a80, 0, 0, 0, f(Yes, false, "")}, + {0x1ab0, 230, 1, 1, f(Yes, false, "")}, + {0x1ab5, 220, 1, 1, f(Yes, false, "")}, + {0x1abb, 230, 1, 1, f(Yes, false, "")}, + {0x1abd, 220, 1, 1, f(Yes, false, "")}, + {0x1abe, 0, 0, 0, f(Yes, false, "")}, + {0x1b05, 0, 0, 0, f(Yes, true, "")}, + {0x1b06, 0, 0, 1, f(Yes, false, "ᬆ")}, + {0x1b07, 0, 0, 0, f(Yes, true, "")}, + {0x1b08, 0, 0, 1, f(Yes, false, "ᬈ")}, + {0x1b09, 0, 0, 0, f(Yes, true, "")}, + {0x1b0a, 0, 0, 1, f(Yes, false, "ᬊ")}, + {0x1b0b, 0, 0, 0, f(Yes, true, "")}, + {0x1b0c, 0, 0, 1, f(Yes, false, "ᬌ")}, + {0x1b0d, 0, 0, 0, f(Yes, true, "")}, + {0x1b0e, 0, 0, 1, f(Yes, false, "ᬎ")}, + {0x1b0f, 0, 0, 0, f(Yes, false, "")}, + {0x1b11, 0, 0, 0, f(Yes, true, "")}, + {0x1b12, 0, 0, 1, f(Yes, false, "ᬒ")}, + {0x1b13, 0, 0, 0, f(Yes, false, "")}, + {0x1b34, 7, 1, 1, f(Yes, false, "")}, + {0x1b35, 0, 1, 1, f(Maybe, false, "")}, + {0x1b36, 0, 0, 0, f(Yes, false, "")}, + {0x1b3a, 0, 0, 0, f(Yes, true, "")}, + {0x1b3b, 0, 0, 1, f(Yes, false, "ᬻ")}, + {0x1b3c, 0, 0, 0, f(Yes, true, "")}, + {0x1b3d, 0, 0, 1, f(Yes, false, "ᬽ")}, + {0x1b3e, 0, 0, 0, f(Yes, true, "")}, + {0x1b40, 0, 0, 1, f(Yes, false, "ᭀ")}, + {0x1b41, 0, 0, 1, f(Yes, false, "ᭁ")}, + {0x1b42, 0, 0, 0, f(Yes, true, "")}, + {0x1b43, 0, 0, 1, f(Yes, false, "ᭃ")}, + {0x1b44, 9, 1, 1, f(Yes, false, "")}, + {0x1b45, 0, 0, 0, f(Yes, false, "")}, + {0x1b6b, 230, 1, 1, f(Yes, false, "")}, + {0x1b6c, 220, 1, 1, f(Yes, false, "")}, + {0x1b6d, 230, 1, 1, f(Yes, false, "")}, + {0x1b74, 0, 0, 0, f(Yes, false, "")}, + {0x1baa, 9, 1, 1, f(Yes, false, "")}, + {0x1bac, 0, 0, 0, f(Yes, false, "")}, + {0x1be6, 7, 1, 1, f(Yes, false, "")}, + {0x1be7, 0, 0, 0, f(Yes, false, "")}, + {0x1bf2, 9, 1, 1, f(Yes, false, "")}, + {0x1bf4, 0, 0, 0, f(Yes, false, "")}, + {0x1c37, 7, 1, 1, f(Yes, false, "")}, + {0x1c38, 0, 0, 0, f(Yes, false, "")}, + {0x1cd0, 230, 1, 1, f(Yes, false, "")}, + {0x1cd3, 0, 0, 0, f(Yes, false, "")}, + {0x1cd4, 1, 1, 1, f(Yes, false, "")}, + {0x1cd5, 220, 1, 1, f(Yes, false, "")}, + {0x1cda, 230, 1, 1, f(Yes, false, "")}, + {0x1cdc, 220, 1, 1, f(Yes, false, "")}, + {0x1ce0, 230, 1, 1, f(Yes, false, "")}, + {0x1ce1, 0, 0, 0, f(Yes, false, "")}, + {0x1ce2, 1, 1, 1, f(Yes, false, "")}, + {0x1ce9, 0, 0, 0, f(Yes, false, "")}, + {0x1ced, 220, 1, 1, f(Yes, false, "")}, + {0x1cee, 0, 0, 0, f(Yes, false, "")}, + {0x1cf4, 230, 1, 1, f(Yes, false, "")}, + {0x1cf5, 0, 0, 0, f(Yes, false, "")}, + {0x1cf8, 230, 1, 1, f(Yes, false, "")}, + {0x1cfa, 0, 0, 0, f(Yes, false, "")}, + {0x1d2c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d2d, 0, 0, 0, g(Yes, No, false, false, "", "Æ")}, + {0x1d2e, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d2f, 0, 0, 0, f(Yes, false, "")}, + {0x1d30, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d31, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d32, 0, 0, 0, g(Yes, No, false, false, "", "Ǝ")}, + {0x1d33, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d34, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d35, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d36, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d37, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d38, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d39, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d3a, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d3b, 0, 0, 0, f(Yes, false, "")}, + {0x1d3c, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d3d, 0, 0, 0, g(Yes, No, false, false, "", "Ȣ")}, + {0x1d3e, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d3f, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d40, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d41, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d42, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d43, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d44, 0, 0, 0, g(Yes, No, false, false, "", "ɐ")}, + {0x1d45, 0, 0, 0, g(Yes, No, false, false, "", "ɑ")}, + {0x1d46, 0, 0, 0, g(Yes, No, false, false, "", "ᴂ")}, + {0x1d47, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d48, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d49, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d4a, 0, 0, 0, g(Yes, No, false, false, "", "ə")}, + {0x1d4b, 0, 0, 0, g(Yes, No, false, false, "", "ɛ")}, + {0x1d4c, 0, 0, 0, g(Yes, No, false, false, "", "ɜ")}, + {0x1d4d, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d4e, 0, 0, 0, f(Yes, false, "")}, + {0x1d4f, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d50, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d51, 0, 0, 0, g(Yes, No, false, false, "", "ŋ")}, + {0x1d52, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d53, 0, 0, 0, g(Yes, No, false, false, "", "ɔ")}, + {0x1d54, 0, 0, 0, g(Yes, No, false, false, "", "ᴖ")}, + {0x1d55, 0, 0, 0, g(Yes, No, false, false, "", "ᴗ")}, + {0x1d56, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d57, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d58, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d59, 0, 0, 0, g(Yes, No, false, false, "", "ᴝ")}, + {0x1d5a, 0, 0, 0, g(Yes, No, false, false, "", "ɯ")}, + {0x1d5b, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d5c, 0, 0, 0, g(Yes, No, false, false, "", "ᴥ")}, + {0x1d5d, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d5e, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d5f, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d60, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d61, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d62, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d63, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d64, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d65, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d66, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d67, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d68, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d69, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d6a, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d6b, 0, 0, 0, f(Yes, false, "")}, + {0x1d78, 0, 0, 0, g(Yes, No, false, false, "", "н")}, + {0x1d79, 0, 0, 0, f(Yes, false, "")}, + {0x1d9b, 0, 0, 0, g(Yes, No, false, false, "", "ɒ")}, + {0x1d9c, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d9d, 0, 0, 0, g(Yes, No, false, false, "", "ɕ")}, + {0x1d9e, 0, 0, 0, g(Yes, No, false, false, "", "ð")}, + {0x1d9f, 0, 0, 0, g(Yes, No, false, false, "", "ɜ")}, + {0x1da0, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1da1, 0, 0, 0, g(Yes, No, false, false, "", "ɟ")}, + {0x1da2, 0, 0, 0, g(Yes, No, false, false, "", "ɡ")}, + {0x1da3, 0, 0, 0, g(Yes, No, false, false, "", "ɥ")}, + {0x1da4, 0, 0, 0, g(Yes, No, false, false, "", "ɨ")}, + {0x1da5, 0, 0, 0, g(Yes, No, false, false, "", "ɩ")}, + {0x1da6, 0, 0, 0, g(Yes, No, false, false, "", "ɪ")}, + {0x1da7, 0, 0, 0, g(Yes, No, false, false, "", "ᵻ")}, + {0x1da8, 0, 0, 0, g(Yes, No, false, false, "", "ʝ")}, + {0x1da9, 0, 0, 0, g(Yes, No, false, false, "", "ɭ")}, + {0x1daa, 0, 0, 0, g(Yes, No, false, false, "", "ᶅ")}, + {0x1dab, 0, 0, 0, g(Yes, No, false, false, "", "ʟ")}, + {0x1dac, 0, 0, 0, g(Yes, No, false, false, "", "ɱ")}, + {0x1dad, 0, 0, 0, g(Yes, No, false, false, "", "ɰ")}, + {0x1dae, 0, 0, 0, g(Yes, No, false, false, "", "ɲ")}, + {0x1daf, 0, 0, 0, g(Yes, No, false, false, "", "ɳ")}, + {0x1db0, 0, 0, 0, g(Yes, No, false, false, "", "ɴ")}, + {0x1db1, 0, 0, 0, g(Yes, No, false, false, "", "ɵ")}, + {0x1db2, 0, 0, 0, g(Yes, No, false, false, "", "ɸ")}, + {0x1db3, 0, 0, 0, g(Yes, No, false, false, "", "ʂ")}, + {0x1db4, 0, 0, 0, g(Yes, No, false, false, "", "ʃ")}, + {0x1db5, 0, 0, 0, g(Yes, No, false, false, "", "ƫ")}, + {0x1db6, 0, 0, 0, g(Yes, No, false, false, "", "ʉ")}, + {0x1db7, 0, 0, 0, g(Yes, No, false, false, "", "ʊ")}, + {0x1db8, 0, 0, 0, g(Yes, No, false, false, "", "ᴜ")}, + {0x1db9, 0, 0, 0, g(Yes, No, false, false, "", "ʋ")}, + {0x1dba, 0, 0, 0, g(Yes, No, false, false, "", "ʌ")}, + {0x1dbb, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1dbc, 0, 0, 0, g(Yes, No, false, false, "", "ʐ")}, + {0x1dbd, 0, 0, 0, g(Yes, No, false, false, "", "ʑ")}, + {0x1dbe, 0, 0, 0, g(Yes, No, false, false, "", "ʒ")}, + {0x1dbf, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1dc0, 230, 1, 1, f(Yes, false, "")}, + {0x1dc2, 220, 1, 1, f(Yes, false, "")}, + {0x1dc3, 230, 1, 1, f(Yes, false, "")}, + {0x1dca, 220, 1, 1, f(Yes, false, "")}, + {0x1dcb, 230, 1, 1, f(Yes, false, "")}, + {0x1dcd, 234, 1, 1, f(Yes, false, "")}, + {0x1dce, 214, 1, 1, f(Yes, false, "")}, + {0x1dcf, 220, 1, 1, f(Yes, false, "")}, + {0x1dd0, 202, 1, 1, f(Yes, false, "")}, + {0x1dd1, 230, 1, 1, f(Yes, false, "")}, + {0x1df6, 232, 1, 1, f(Yes, false, "")}, + {0x1df7, 228, 1, 1, f(Yes, false, "")}, + {0x1df9, 220, 1, 1, f(Yes, false, "")}, + {0x1dfa, 0, 0, 0, f(Yes, false, "")}, + {0x1dfb, 230, 1, 1, f(Yes, false, "")}, + {0x1dfc, 233, 1, 1, f(Yes, false, "")}, + {0x1dfd, 220, 1, 1, f(Yes, false, "")}, + {0x1dfe, 230, 1, 1, f(Yes, false, "")}, + {0x1dff, 220, 1, 1, f(Yes, false, "")}, + {0x1e00, 0, 0, 1, f(Yes, false, "Ḁ")}, + {0x1e01, 0, 0, 1, f(Yes, false, "ḁ")}, + {0x1e02, 0, 0, 1, f(Yes, false, "Ḃ")}, + {0x1e03, 0, 0, 1, f(Yes, false, "ḃ")}, + {0x1e04, 0, 0, 1, f(Yes, false, "Ḅ")}, + {0x1e05, 0, 0, 1, f(Yes, false, "ḅ")}, + {0x1e06, 0, 0, 1, f(Yes, false, "Ḇ")}, + {0x1e07, 0, 0, 1, f(Yes, false, "ḇ")}, + {0x1e08, 0, 0, 2, f(Yes, false, "Ḉ")}, + {0x1e09, 0, 0, 2, f(Yes, false, "ḉ")}, + {0x1e0a, 0, 0, 1, f(Yes, false, "Ḋ")}, + {0x1e0b, 0, 0, 1, f(Yes, false, "ḋ")}, + {0x1e0c, 0, 0, 1, f(Yes, false, "Ḍ")}, + {0x1e0d, 0, 0, 1, f(Yes, false, "ḍ")}, + {0x1e0e, 0, 0, 1, f(Yes, false, "Ḏ")}, + {0x1e0f, 0, 0, 1, f(Yes, false, "ḏ")}, + {0x1e10, 0, 0, 1, f(Yes, false, "Ḑ")}, + {0x1e11, 0, 0, 1, f(Yes, false, "ḑ")}, + {0x1e12, 0, 0, 1, f(Yes, false, "Ḓ")}, + {0x1e13, 0, 0, 1, f(Yes, false, "ḓ")}, + {0x1e14, 0, 0, 2, f(Yes, false, "Ḕ")}, + {0x1e15, 0, 0, 2, f(Yes, false, "ḕ")}, + {0x1e16, 0, 0, 2, f(Yes, false, "Ḗ")}, + {0x1e17, 0, 0, 2, f(Yes, false, "ḗ")}, + {0x1e18, 0, 0, 1, f(Yes, false, "Ḙ")}, + {0x1e19, 0, 0, 1, f(Yes, false, "ḙ")}, + {0x1e1a, 0, 0, 1, f(Yes, false, "Ḛ")}, + {0x1e1b, 0, 0, 1, f(Yes, false, "ḛ")}, + {0x1e1c, 0, 0, 2, f(Yes, false, "Ḝ")}, + {0x1e1d, 0, 0, 2, f(Yes, false, "ḝ")}, + {0x1e1e, 0, 0, 1, f(Yes, false, "Ḟ")}, + {0x1e1f, 0, 0, 1, f(Yes, false, "ḟ")}, + {0x1e20, 0, 0, 1, f(Yes, false, "Ḡ")}, + {0x1e21, 0, 0, 1, f(Yes, false, "ḡ")}, + {0x1e22, 0, 0, 1, f(Yes, false, "Ḣ")}, + {0x1e23, 0, 0, 1, f(Yes, false, "ḣ")}, + {0x1e24, 0, 0, 1, f(Yes, false, "Ḥ")}, + {0x1e25, 0, 0, 1, f(Yes, false, "ḥ")}, + {0x1e26, 0, 0, 1, f(Yes, false, "Ḧ")}, + {0x1e27, 0, 0, 1, f(Yes, false, "ḧ")}, + {0x1e28, 0, 0, 1, f(Yes, false, "Ḩ")}, + {0x1e29, 0, 0, 1, f(Yes, false, "ḩ")}, + {0x1e2a, 0, 0, 1, f(Yes, false, "Ḫ")}, + {0x1e2b, 0, 0, 1, f(Yes, false, "ḫ")}, + {0x1e2c, 0, 0, 1, f(Yes, false, "Ḭ")}, + {0x1e2d, 0, 0, 1, f(Yes, false, "ḭ")}, + {0x1e2e, 0, 0, 2, f(Yes, false, "Ḯ")}, + {0x1e2f, 0, 0, 2, f(Yes, false, "ḯ")}, + {0x1e30, 0, 0, 1, f(Yes, false, "Ḱ")}, + {0x1e31, 0, 0, 1, f(Yes, false, "ḱ")}, + {0x1e32, 0, 0, 1, f(Yes, false, "Ḳ")}, + {0x1e33, 0, 0, 1, f(Yes, false, "ḳ")}, + {0x1e34, 0, 0, 1, f(Yes, false, "Ḵ")}, + {0x1e35, 0, 0, 1, f(Yes, false, "ḵ")}, + {0x1e36, 0, 0, 1, f(Yes, true, "Ḷ")}, + {0x1e37, 0, 0, 1, f(Yes, true, "ḷ")}, + {0x1e38, 0, 0, 2, f(Yes, false, "Ḹ")}, + {0x1e39, 0, 0, 2, f(Yes, false, "ḹ")}, + {0x1e3a, 0, 0, 1, f(Yes, false, "Ḻ")}, + {0x1e3b, 0, 0, 1, f(Yes, false, "ḻ")}, + {0x1e3c, 0, 0, 1, f(Yes, false, "Ḽ")}, + {0x1e3d, 0, 0, 1, f(Yes, false, "ḽ")}, + {0x1e3e, 0, 0, 1, f(Yes, false, "Ḿ")}, + {0x1e3f, 0, 0, 1, f(Yes, false, "ḿ")}, + {0x1e40, 0, 0, 1, f(Yes, false, "Ṁ")}, + {0x1e41, 0, 0, 1, f(Yes, false, "ṁ")}, + {0x1e42, 0, 0, 1, f(Yes, false, "Ṃ")}, + {0x1e43, 0, 0, 1, f(Yes, false, "ṃ")}, + {0x1e44, 0, 0, 1, f(Yes, false, "Ṅ")}, + {0x1e45, 0, 0, 1, f(Yes, false, "ṅ")}, + {0x1e46, 0, 0, 1, f(Yes, false, "Ṇ")}, + {0x1e47, 0, 0, 1, f(Yes, false, "ṇ")}, + {0x1e48, 0, 0, 1, f(Yes, false, "Ṉ")}, + {0x1e49, 0, 0, 1, f(Yes, false, "ṉ")}, + {0x1e4a, 0, 0, 1, f(Yes, false, "Ṋ")}, + {0x1e4b, 0, 0, 1, f(Yes, false, "ṋ")}, + {0x1e4c, 0, 0, 2, f(Yes, false, "Ṍ")}, + {0x1e4d, 0, 0, 2, f(Yes, false, "ṍ")}, + {0x1e4e, 0, 0, 2, f(Yes, false, "Ṏ")}, + {0x1e4f, 0, 0, 2, f(Yes, false, "ṏ")}, + {0x1e50, 0, 0, 2, f(Yes, false, "Ṑ")}, + {0x1e51, 0, 0, 2, f(Yes, false, "ṑ")}, + {0x1e52, 0, 0, 2, f(Yes, false, "Ṓ")}, + {0x1e53, 0, 0, 2, f(Yes, false, "ṓ")}, + {0x1e54, 0, 0, 1, f(Yes, false, "Ṕ")}, + {0x1e55, 0, 0, 1, f(Yes, false, "ṕ")}, + {0x1e56, 0, 0, 1, f(Yes, false, "Ṗ")}, + {0x1e57, 0, 0, 1, f(Yes, false, "ṗ")}, + {0x1e58, 0, 0, 1, f(Yes, false, "Ṙ")}, + {0x1e59, 0, 0, 1, f(Yes, false, "ṙ")}, + {0x1e5a, 0, 0, 1, f(Yes, true, "Ṛ")}, + {0x1e5b, 0, 0, 1, f(Yes, true, "ṛ")}, + {0x1e5c, 0, 0, 2, f(Yes, false, "Ṝ")}, + {0x1e5d, 0, 0, 2, f(Yes, false, "ṝ")}, + {0x1e5e, 0, 0, 1, f(Yes, false, "Ṟ")}, + {0x1e5f, 0, 0, 1, f(Yes, false, "ṟ")}, + {0x1e60, 0, 0, 1, f(Yes, false, "Ṡ")}, + {0x1e61, 0, 0, 1, f(Yes, false, "ṡ")}, + {0x1e62, 0, 0, 1, f(Yes, true, "Ṣ")}, + {0x1e63, 0, 0, 1, f(Yes, true, "ṣ")}, + {0x1e64, 0, 0, 2, f(Yes, false, "Ṥ")}, + {0x1e65, 0, 0, 2, f(Yes, false, "ṥ")}, + {0x1e66, 0, 0, 2, f(Yes, false, "Ṧ")}, + {0x1e67, 0, 0, 2, f(Yes, false, "ṧ")}, + {0x1e68, 0, 0, 2, f(Yes, false, "Ṩ")}, + {0x1e69, 0, 0, 2, f(Yes, false, "ṩ")}, + {0x1e6a, 0, 0, 1, f(Yes, false, "Ṫ")}, + {0x1e6b, 0, 0, 1, f(Yes, false, "ṫ")}, + {0x1e6c, 0, 0, 1, f(Yes, false, "Ṭ")}, + {0x1e6d, 0, 0, 1, f(Yes, false, "ṭ")}, + {0x1e6e, 0, 0, 1, f(Yes, false, "Ṯ")}, + {0x1e6f, 0, 0, 1, f(Yes, false, "ṯ")}, + {0x1e70, 0, 0, 1, f(Yes, false, "Ṱ")}, + {0x1e71, 0, 0, 1, f(Yes, false, "ṱ")}, + {0x1e72, 0, 0, 1, f(Yes, false, "Ṳ")}, + {0x1e73, 0, 0, 1, f(Yes, false, "ṳ")}, + {0x1e74, 0, 0, 1, f(Yes, false, "Ṵ")}, + {0x1e75, 0, 0, 1, f(Yes, false, "ṵ")}, + {0x1e76, 0, 0, 1, f(Yes, false, "Ṷ")}, + {0x1e77, 0, 0, 1, f(Yes, false, "ṷ")}, + {0x1e78, 0, 0, 2, f(Yes, false, "Ṹ")}, + {0x1e79, 0, 0, 2, f(Yes, false, "ṹ")}, + {0x1e7a, 0, 0, 2, f(Yes, false, "Ṻ")}, + {0x1e7b, 0, 0, 2, f(Yes, false, "ṻ")}, + {0x1e7c, 0, 0, 1, f(Yes, false, "Ṽ")}, + {0x1e7d, 0, 0, 1, f(Yes, false, "ṽ")}, + {0x1e7e, 0, 0, 1, f(Yes, false, "Ṿ")}, + {0x1e7f, 0, 0, 1, f(Yes, false, "ṿ")}, + {0x1e80, 0, 0, 1, f(Yes, false, "Ẁ")}, + {0x1e81, 0, 0, 1, f(Yes, false, "ẁ")}, + {0x1e82, 0, 0, 1, f(Yes, false, "Ẃ")}, + {0x1e83, 0, 0, 1, f(Yes, false, "ẃ")}, + {0x1e84, 0, 0, 1, f(Yes, false, "Ẅ")}, + {0x1e85, 0, 0, 1, f(Yes, false, "ẅ")}, + {0x1e86, 0, 0, 1, f(Yes, false, "Ẇ")}, + {0x1e87, 0, 0, 1, f(Yes, false, "ẇ")}, + {0x1e88, 0, 0, 1, f(Yes, false, "Ẉ")}, + {0x1e89, 0, 0, 1, f(Yes, false, "ẉ")}, + {0x1e8a, 0, 0, 1, f(Yes, false, "Ẋ")}, + {0x1e8b, 0, 0, 1, f(Yes, false, "ẋ")}, + {0x1e8c, 0, 0, 1, f(Yes, false, "Ẍ")}, + {0x1e8d, 0, 0, 1, f(Yes, false, "ẍ")}, + {0x1e8e, 0, 0, 1, f(Yes, false, "Ẏ")}, + {0x1e8f, 0, 0, 1, f(Yes, false, "ẏ")}, + {0x1e90, 0, 0, 1, f(Yes, false, "Ẑ")}, + {0x1e91, 0, 0, 1, f(Yes, false, "ẑ")}, + {0x1e92, 0, 0, 1, f(Yes, false, "Ẓ")}, + {0x1e93, 0, 0, 1, f(Yes, false, "ẓ")}, + {0x1e94, 0, 0, 1, f(Yes, false, "Ẕ")}, + {0x1e95, 0, 0, 1, f(Yes, false, "ẕ")}, + {0x1e96, 0, 0, 1, f(Yes, false, "ẖ")}, + {0x1e97, 0, 0, 1, f(Yes, false, "ẗ")}, + {0x1e98, 0, 0, 1, f(Yes, false, "ẘ")}, + {0x1e99, 0, 0, 1, f(Yes, false, "ẙ")}, + {0x1e9a, 0, 0, 0, g(Yes, No, false, false, "", "aʾ")}, + {0x1e9b, 0, 0, 1, g(Yes, No, false, false, "ẛ", "ṡ")}, + {0x1e9c, 0, 0, 0, f(Yes, false, "")}, + {0x1ea0, 0, 0, 1, f(Yes, true, "Ạ")}, + {0x1ea1, 0, 0, 1, f(Yes, true, "ạ")}, + {0x1ea2, 0, 0, 1, f(Yes, false, "Ả")}, + {0x1ea3, 0, 0, 1, f(Yes, false, "ả")}, + {0x1ea4, 0, 0, 2, f(Yes, false, "Ấ")}, + {0x1ea5, 0, 0, 2, f(Yes, false, "ấ")}, + {0x1ea6, 0, 0, 2, f(Yes, false, "Ầ")}, + {0x1ea7, 0, 0, 2, f(Yes, false, "ầ")}, + {0x1ea8, 0, 0, 2, f(Yes, false, "Ẩ")}, + {0x1ea9, 0, 0, 2, f(Yes, false, "ẩ")}, + {0x1eaa, 0, 0, 2, f(Yes, false, "Ẫ")}, + {0x1eab, 0, 0, 2, f(Yes, false, "ẫ")}, + {0x1eac, 0, 0, 2, f(Yes, false, "Ậ")}, + {0x1ead, 0, 0, 2, f(Yes, false, "ậ")}, + {0x1eae, 0, 0, 2, f(Yes, false, "Ắ")}, + {0x1eaf, 0, 0, 2, f(Yes, false, "ắ")}, + {0x1eb0, 0, 0, 2, f(Yes, false, "Ằ")}, + {0x1eb1, 0, 0, 2, f(Yes, false, "ằ")}, + {0x1eb2, 0, 0, 2, f(Yes, false, "Ẳ")}, + {0x1eb3, 0, 0, 2, f(Yes, false, "ẳ")}, + {0x1eb4, 0, 0, 2, f(Yes, false, "Ẵ")}, + {0x1eb5, 0, 0, 2, f(Yes, false, "ẵ")}, + {0x1eb6, 0, 0, 2, f(Yes, false, "Ặ")}, + {0x1eb7, 0, 0, 2, f(Yes, false, "ặ")}, + {0x1eb8, 0, 0, 1, f(Yes, true, "Ẹ")}, + {0x1eb9, 0, 0, 1, f(Yes, true, "ẹ")}, + {0x1eba, 0, 0, 1, f(Yes, false, "Ẻ")}, + {0x1ebb, 0, 0, 1, f(Yes, false, "ẻ")}, + {0x1ebc, 0, 0, 1, f(Yes, false, "Ẽ")}, + {0x1ebd, 0, 0, 1, f(Yes, false, "ẽ")}, + {0x1ebe, 0, 0, 2, f(Yes, false, "Ế")}, + {0x1ebf, 0, 0, 2, f(Yes, false, "ế")}, + {0x1ec0, 0, 0, 2, f(Yes, false, "Ề")}, + {0x1ec1, 0, 0, 2, f(Yes, false, "ề")}, + {0x1ec2, 0, 0, 2, f(Yes, false, "Ể")}, + {0x1ec3, 0, 0, 2, f(Yes, false, "ể")}, + {0x1ec4, 0, 0, 2, f(Yes, false, "Ễ")}, + {0x1ec5, 0, 0, 2, f(Yes, false, "ễ")}, + {0x1ec6, 0, 0, 2, f(Yes, false, "Ệ")}, + {0x1ec7, 0, 0, 2, f(Yes, false, "ệ")}, + {0x1ec8, 0, 0, 1, f(Yes, false, "Ỉ")}, + {0x1ec9, 0, 0, 1, f(Yes, false, "ỉ")}, + {0x1eca, 0, 0, 1, f(Yes, false, "Ị")}, + {0x1ecb, 0, 0, 1, f(Yes, false, "ị")}, + {0x1ecc, 0, 0, 1, f(Yes, true, "Ọ")}, + {0x1ecd, 0, 0, 1, f(Yes, true, "ọ")}, + {0x1ece, 0, 0, 1, f(Yes, false, "Ỏ")}, + {0x1ecf, 0, 0, 1, f(Yes, false, "ỏ")}, + {0x1ed0, 0, 0, 2, f(Yes, false, "Ố")}, + {0x1ed1, 0, 0, 2, f(Yes, false, "ố")}, + {0x1ed2, 0, 0, 2, f(Yes, false, "Ồ")}, + {0x1ed3, 0, 0, 2, f(Yes, false, "ồ")}, + {0x1ed4, 0, 0, 2, f(Yes, false, "Ổ")}, + {0x1ed5, 0, 0, 2, f(Yes, false, "ổ")}, + {0x1ed6, 0, 0, 2, f(Yes, false, "Ỗ")}, + {0x1ed7, 0, 0, 2, f(Yes, false, "ỗ")}, + {0x1ed8, 0, 0, 2, f(Yes, false, "Ộ")}, + {0x1ed9, 0, 0, 2, f(Yes, false, "ộ")}, + {0x1eda, 0, 0, 2, f(Yes, false, "Ớ")}, + {0x1edb, 0, 0, 2, f(Yes, false, "ớ")}, + {0x1edc, 0, 0, 2, f(Yes, false, "Ờ")}, + {0x1edd, 0, 0, 2, f(Yes, false, "ờ")}, + {0x1ede, 0, 0, 2, f(Yes, false, "Ở")}, + {0x1edf, 0, 0, 2, f(Yes, false, "ở")}, + {0x1ee0, 0, 0, 2, f(Yes, false, "Ỡ")}, + {0x1ee1, 0, 0, 2, f(Yes, false, "ỡ")}, + {0x1ee2, 0, 0, 2, f(Yes, false, "Ợ")}, + {0x1ee3, 0, 0, 2, f(Yes, false, "ợ")}, + {0x1ee4, 0, 0, 1, f(Yes, false, "Ụ")}, + {0x1ee5, 0, 0, 1, f(Yes, false, "ụ")}, + {0x1ee6, 0, 0, 1, f(Yes, false, "Ủ")}, + {0x1ee7, 0, 0, 1, f(Yes, false, "ủ")}, + {0x1ee8, 0, 0, 2, f(Yes, false, "Ứ")}, + {0x1ee9, 0, 0, 2, f(Yes, false, "ứ")}, + {0x1eea, 0, 0, 2, f(Yes, false, "Ừ")}, + {0x1eeb, 0, 0, 2, f(Yes, false, "ừ")}, + {0x1eec, 0, 0, 2, f(Yes, false, "Ử")}, + {0x1eed, 0, 0, 2, f(Yes, false, "ử")}, + {0x1eee, 0, 0, 2, f(Yes, false, "Ữ")}, + {0x1eef, 0, 0, 2, f(Yes, false, "ữ")}, + {0x1ef0, 0, 0, 2, f(Yes, false, "Ự")}, + {0x1ef1, 0, 0, 2, f(Yes, false, "ự")}, + {0x1ef2, 0, 0, 1, f(Yes, false, "Ỳ")}, + {0x1ef3, 0, 0, 1, f(Yes, false, "ỳ")}, + {0x1ef4, 0, 0, 1, f(Yes, false, "Ỵ")}, + {0x1ef5, 0, 0, 1, f(Yes, false, "ỵ")}, + {0x1ef6, 0, 0, 1, f(Yes, false, "Ỷ")}, + {0x1ef7, 0, 0, 1, f(Yes, false, "ỷ")}, + {0x1ef8, 0, 0, 1, f(Yes, false, "Ỹ")}, + {0x1ef9, 0, 0, 1, f(Yes, false, "ỹ")}, + {0x1efa, 0, 0, 0, f(Yes, false, "")}, + {0x1f00, 0, 0, 1, f(Yes, true, "ἀ")}, + {0x1f01, 0, 0, 1, f(Yes, true, "ἁ")}, + {0x1f02, 0, 0, 2, f(Yes, true, "ἂ")}, + {0x1f03, 0, 0, 2, f(Yes, true, "ἃ")}, + {0x1f04, 0, 0, 2, f(Yes, true, "ἄ")}, + {0x1f05, 0, 0, 2, f(Yes, true, "ἅ")}, + {0x1f06, 0, 0, 2, f(Yes, true, "ἆ")}, + {0x1f07, 0, 0, 2, f(Yes, true, "ἇ")}, + {0x1f08, 0, 0, 1, f(Yes, true, "Ἀ")}, + {0x1f09, 0, 0, 1, f(Yes, true, "Ἁ")}, + {0x1f0a, 0, 0, 2, f(Yes, true, "Ἂ")}, + {0x1f0b, 0, 0, 2, f(Yes, true, "Ἃ")}, + {0x1f0c, 0, 0, 2, f(Yes, true, "Ἄ")}, + {0x1f0d, 0, 0, 2, f(Yes, true, "Ἅ")}, + {0x1f0e, 0, 0, 2, f(Yes, true, "Ἆ")}, + {0x1f0f, 0, 0, 2, f(Yes, true, "Ἇ")}, + {0x1f10, 0, 0, 1, f(Yes, true, "ἐ")}, + {0x1f11, 0, 0, 1, f(Yes, true, "ἑ")}, + {0x1f12, 0, 0, 2, f(Yes, false, "ἒ")}, + {0x1f13, 0, 0, 2, f(Yes, false, "ἓ")}, + {0x1f14, 0, 0, 2, f(Yes, false, "ἔ")}, + {0x1f15, 0, 0, 2, f(Yes, false, "ἕ")}, + {0x1f16, 0, 0, 0, f(Yes, false, "")}, + {0x1f18, 0, 0, 1, f(Yes, true, "Ἐ")}, + {0x1f19, 0, 0, 1, f(Yes, true, "Ἑ")}, + {0x1f1a, 0, 0, 2, f(Yes, false, "Ἒ")}, + {0x1f1b, 0, 0, 2, f(Yes, false, "Ἓ")}, + {0x1f1c, 0, 0, 2, f(Yes, false, "Ἔ")}, + {0x1f1d, 0, 0, 2, f(Yes, false, "Ἕ")}, + {0x1f1e, 0, 0, 0, f(Yes, false, "")}, + {0x1f20, 0, 0, 1, f(Yes, true, "ἠ")}, + {0x1f21, 0, 0, 1, f(Yes, true, "ἡ")}, + {0x1f22, 0, 0, 2, f(Yes, true, "ἢ")}, + {0x1f23, 0, 0, 2, f(Yes, true, "ἣ")}, + {0x1f24, 0, 0, 2, f(Yes, true, "ἤ")}, + {0x1f25, 0, 0, 2, f(Yes, true, "ἥ")}, + {0x1f26, 0, 0, 2, f(Yes, true, "ἦ")}, + {0x1f27, 0, 0, 2, f(Yes, true, "ἧ")}, + {0x1f28, 0, 0, 1, f(Yes, true, "Ἠ")}, + {0x1f29, 0, 0, 1, f(Yes, true, "Ἡ")}, + {0x1f2a, 0, 0, 2, f(Yes, true, "Ἢ")}, + {0x1f2b, 0, 0, 2, f(Yes, true, "Ἣ")}, + {0x1f2c, 0, 0, 2, f(Yes, true, "Ἤ")}, + {0x1f2d, 0, 0, 2, f(Yes, true, "Ἥ")}, + {0x1f2e, 0, 0, 2, f(Yes, true, "Ἦ")}, + {0x1f2f, 0, 0, 2, f(Yes, true, "Ἧ")}, + {0x1f30, 0, 0, 1, f(Yes, true, "ἰ")}, + {0x1f31, 0, 0, 1, f(Yes, true, "ἱ")}, + {0x1f32, 0, 0, 2, f(Yes, false, "ἲ")}, + {0x1f33, 0, 0, 2, f(Yes, false, "ἳ")}, + {0x1f34, 0, 0, 2, f(Yes, false, "ἴ")}, + {0x1f35, 0, 0, 2, f(Yes, false, "ἵ")}, + {0x1f36, 0, 0, 2, f(Yes, false, "ἶ")}, + {0x1f37, 0, 0, 2, f(Yes, false, "ἷ")}, + {0x1f38, 0, 0, 1, f(Yes, true, "Ἰ")}, + {0x1f39, 0, 0, 1, f(Yes, true, "Ἱ")}, + {0x1f3a, 0, 0, 2, f(Yes, false, "Ἲ")}, + {0x1f3b, 0, 0, 2, f(Yes, false, "Ἳ")}, + {0x1f3c, 0, 0, 2, f(Yes, false, "Ἴ")}, + {0x1f3d, 0, 0, 2, f(Yes, false, "Ἵ")}, + {0x1f3e, 0, 0, 2, f(Yes, false, "Ἶ")}, + {0x1f3f, 0, 0, 2, f(Yes, false, "Ἷ")}, + {0x1f40, 0, 0, 1, f(Yes, true, "ὀ")}, + {0x1f41, 0, 0, 1, f(Yes, true, "ὁ")}, + {0x1f42, 0, 0, 2, f(Yes, false, "ὂ")}, + {0x1f43, 0, 0, 2, f(Yes, false, "ὃ")}, + {0x1f44, 0, 0, 2, f(Yes, false, "ὄ")}, + {0x1f45, 0, 0, 2, f(Yes, false, "ὅ")}, + {0x1f46, 0, 0, 0, f(Yes, false, "")}, + {0x1f48, 0, 0, 1, f(Yes, true, "Ὀ")}, + {0x1f49, 0, 0, 1, f(Yes, true, "Ὁ")}, + {0x1f4a, 0, 0, 2, f(Yes, false, "Ὂ")}, + {0x1f4b, 0, 0, 2, f(Yes, false, "Ὃ")}, + {0x1f4c, 0, 0, 2, f(Yes, false, "Ὄ")}, + {0x1f4d, 0, 0, 2, f(Yes, false, "Ὅ")}, + {0x1f4e, 0, 0, 0, f(Yes, false, "")}, + {0x1f50, 0, 0, 1, f(Yes, true, "ὐ")}, + {0x1f51, 0, 0, 1, f(Yes, true, "ὑ")}, + {0x1f52, 0, 0, 2, f(Yes, false, "ὒ")}, + {0x1f53, 0, 0, 2, f(Yes, false, "ὓ")}, + {0x1f54, 0, 0, 2, f(Yes, false, "ὔ")}, + {0x1f55, 0, 0, 2, f(Yes, false, "ὕ")}, + {0x1f56, 0, 0, 2, f(Yes, false, "ὖ")}, + {0x1f57, 0, 0, 2, f(Yes, false, "ὗ")}, + {0x1f58, 0, 0, 0, f(Yes, false, "")}, + {0x1f59, 0, 0, 1, f(Yes, true, "Ὑ")}, + {0x1f5a, 0, 0, 0, f(Yes, false, "")}, + {0x1f5b, 0, 0, 2, f(Yes, false, "Ὓ")}, + {0x1f5c, 0, 0, 0, f(Yes, false, "")}, + {0x1f5d, 0, 0, 2, f(Yes, false, "Ὕ")}, + {0x1f5e, 0, 0, 0, f(Yes, false, "")}, + {0x1f5f, 0, 0, 2, f(Yes, false, "Ὗ")}, + {0x1f60, 0, 0, 1, f(Yes, true, "ὠ")}, + {0x1f61, 0, 0, 1, f(Yes, true, "ὡ")}, + {0x1f62, 0, 0, 2, f(Yes, true, "ὢ")}, + {0x1f63, 0, 0, 2, f(Yes, true, "ὣ")}, + {0x1f64, 0, 0, 2, f(Yes, true, "ὤ")}, + {0x1f65, 0, 0, 2, f(Yes, true, "ὥ")}, + {0x1f66, 0, 0, 2, f(Yes, true, "ὦ")}, + {0x1f67, 0, 0, 2, f(Yes, true, "ὧ")}, + {0x1f68, 0, 0, 1, f(Yes, true, "Ὠ")}, + {0x1f69, 0, 0, 1, f(Yes, true, "Ὡ")}, + {0x1f6a, 0, 0, 2, f(Yes, true, "Ὢ")}, + {0x1f6b, 0, 0, 2, f(Yes, true, "Ὣ")}, + {0x1f6c, 0, 0, 2, f(Yes, true, "Ὤ")}, + {0x1f6d, 0, 0, 2, f(Yes, true, "Ὥ")}, + {0x1f6e, 0, 0, 2, f(Yes, true, "Ὦ")}, + {0x1f6f, 0, 0, 2, f(Yes, true, "Ὧ")}, + {0x1f70, 0, 0, 1, f(Yes, true, "ὰ")}, + {0x1f71, 0, 0, 1, f(No, false, "ά")}, + {0x1f72, 0, 0, 1, f(Yes, false, "ὲ")}, + {0x1f73, 0, 0, 1, f(No, false, "έ")}, + {0x1f74, 0, 0, 1, f(Yes, true, "ὴ")}, + {0x1f75, 0, 0, 1, f(No, false, "ή")}, + {0x1f76, 0, 0, 1, f(Yes, false, "ὶ")}, + {0x1f77, 0, 0, 1, f(No, false, "ί")}, + {0x1f78, 0, 0, 1, f(Yes, false, "ὸ")}, + {0x1f79, 0, 0, 1, f(No, false, "ό")}, + {0x1f7a, 0, 0, 1, f(Yes, false, "ὺ")}, + {0x1f7b, 0, 0, 1, f(No, false, "ύ")}, + {0x1f7c, 0, 0, 1, f(Yes, true, "ὼ")}, + {0x1f7d, 0, 0, 1, f(No, false, "ώ")}, + {0x1f7e, 0, 0, 0, f(Yes, false, "")}, + {0x1f80, 0, 0, 2, f(Yes, false, "ᾀ")}, + {0x1f81, 0, 0, 2, f(Yes, false, "ᾁ")}, + {0x1f82, 0, 0, 3, f(Yes, false, "ᾂ")}, + {0x1f83, 0, 0, 3, f(Yes, false, "ᾃ")}, + {0x1f84, 0, 0, 3, f(Yes, false, "ᾄ")}, + {0x1f85, 0, 0, 3, f(Yes, false, "ᾅ")}, + {0x1f86, 0, 0, 3, f(Yes, false, "ᾆ")}, + {0x1f87, 0, 0, 3, f(Yes, false, "ᾇ")}, + {0x1f88, 0, 0, 2, f(Yes, false, "ᾈ")}, + {0x1f89, 0, 0, 2, f(Yes, false, "ᾉ")}, + {0x1f8a, 0, 0, 3, f(Yes, false, "ᾊ")}, + {0x1f8b, 0, 0, 3, f(Yes, false, "ᾋ")}, + {0x1f8c, 0, 0, 3, f(Yes, false, "ᾌ")}, + {0x1f8d, 0, 0, 3, f(Yes, false, "ᾍ")}, + {0x1f8e, 0, 0, 3, f(Yes, false, "ᾎ")}, + {0x1f8f, 0, 0, 3, f(Yes, false, "ᾏ")}, + {0x1f90, 0, 0, 2, f(Yes, false, "ᾐ")}, + {0x1f91, 0, 0, 2, f(Yes, false, "ᾑ")}, + {0x1f92, 0, 0, 3, f(Yes, false, "ᾒ")}, + {0x1f93, 0, 0, 3, f(Yes, false, "ᾓ")}, + {0x1f94, 0, 0, 3, f(Yes, false, "ᾔ")}, + {0x1f95, 0, 0, 3, f(Yes, false, "ᾕ")}, + {0x1f96, 0, 0, 3, f(Yes, false, "ᾖ")}, + {0x1f97, 0, 0, 3, f(Yes, false, "ᾗ")}, + {0x1f98, 0, 0, 2, f(Yes, false, "ᾘ")}, + {0x1f99, 0, 0, 2, f(Yes, false, "ᾙ")}, + {0x1f9a, 0, 0, 3, f(Yes, false, "ᾚ")}, + {0x1f9b, 0, 0, 3, f(Yes, false, "ᾛ")}, + {0x1f9c, 0, 0, 3, f(Yes, false, "ᾜ")}, + {0x1f9d, 0, 0, 3, f(Yes, false, "ᾝ")}, + {0x1f9e, 0, 0, 3, f(Yes, false, "ᾞ")}, + {0x1f9f, 0, 0, 3, f(Yes, false, "ᾟ")}, + {0x1fa0, 0, 0, 2, f(Yes, false, "ᾠ")}, + {0x1fa1, 0, 0, 2, f(Yes, false, "ᾡ")}, + {0x1fa2, 0, 0, 3, f(Yes, false, "ᾢ")}, + {0x1fa3, 0, 0, 3, f(Yes, false, "ᾣ")}, + {0x1fa4, 0, 0, 3, f(Yes, false, "ᾤ")}, + {0x1fa5, 0, 0, 3, f(Yes, false, "ᾥ")}, + {0x1fa6, 0, 0, 3, f(Yes, false, "ᾦ")}, + {0x1fa7, 0, 0, 3, f(Yes, false, "ᾧ")}, + {0x1fa8, 0, 0, 2, f(Yes, false, "ᾨ")}, + {0x1fa9, 0, 0, 2, f(Yes, false, "ᾩ")}, + {0x1faa, 0, 0, 3, f(Yes, false, "ᾪ")}, + {0x1fab, 0, 0, 3, f(Yes, false, "ᾫ")}, + {0x1fac, 0, 0, 3, f(Yes, false, "ᾬ")}, + {0x1fad, 0, 0, 3, f(Yes, false, "ᾭ")}, + {0x1fae, 0, 0, 3, f(Yes, false, "ᾮ")}, + {0x1faf, 0, 0, 3, f(Yes, false, "ᾯ")}, + {0x1fb0, 0, 0, 1, f(Yes, false, "ᾰ")}, + {0x1fb1, 0, 0, 1, f(Yes, false, "ᾱ")}, + {0x1fb2, 0, 0, 2, f(Yes, false, "ᾲ")}, + {0x1fb3, 0, 0, 1, f(Yes, false, "ᾳ")}, + {0x1fb4, 0, 0, 2, f(Yes, false, "ᾴ")}, + {0x1fb5, 0, 0, 0, f(Yes, false, "")}, + {0x1fb6, 0, 0, 1, f(Yes, true, "ᾶ")}, + {0x1fb7, 0, 0, 2, f(Yes, false, "ᾷ")}, + {0x1fb8, 0, 0, 1, f(Yes, false, "Ᾰ")}, + {0x1fb9, 0, 0, 1, f(Yes, false, "Ᾱ")}, + {0x1fba, 0, 0, 1, f(Yes, false, "Ὰ")}, + {0x1fbb, 0, 0, 1, f(No, false, "Ά")}, + {0x1fbc, 0, 0, 1, f(Yes, false, "ᾼ")}, + {0x1fbd, 0, 0, 1, g(Yes, No, false, false, "", " ̓")}, + {0x1fbe, 0, 0, 0, f(No, false, "ι")}, + {0x1fbf, 0, 0, 1, g(Yes, No, true, false, "", " ̓")}, + {0x1fc0, 0, 0, 1, g(Yes, No, false, false, "", " ͂")}, + {0x1fc1, 0, 0, 2, g(Yes, No, false, false, "῁", " ̈͂")}, + {0x1fc2, 0, 0, 2, f(Yes, false, "ῂ")}, + {0x1fc3, 0, 0, 1, f(Yes, false, "ῃ")}, + {0x1fc4, 0, 0, 2, f(Yes, false, "ῄ")}, + {0x1fc5, 0, 0, 0, f(Yes, false, "")}, + {0x1fc6, 0, 0, 1, f(Yes, true, "ῆ")}, + {0x1fc7, 0, 0, 2, f(Yes, false, "ῇ")}, + {0x1fc8, 0, 0, 1, f(Yes, false, "Ὲ")}, + {0x1fc9, 0, 0, 1, f(No, false, "Έ")}, + {0x1fca, 0, 0, 1, f(Yes, false, "Ὴ")}, + {0x1fcb, 0, 0, 1, f(No, false, "Ή")}, + {0x1fcc, 0, 0, 1, f(Yes, false, "ῌ")}, + {0x1fcd, 0, 0, 2, g(Yes, No, false, false, "῍", " ̓̀")}, + {0x1fce, 0, 0, 2, g(Yes, No, false, false, "῎", " ̓́")}, + {0x1fcf, 0, 0, 2, g(Yes, No, false, false, "῏", " ̓͂")}, + {0x1fd0, 0, 0, 1, f(Yes, false, "ῐ")}, + {0x1fd1, 0, 0, 1, f(Yes, false, "ῑ")}, + {0x1fd2, 0, 0, 2, f(Yes, false, "ῒ")}, + {0x1fd3, 0, 0, 2, f(No, false, "ΐ")}, + {0x1fd4, 0, 0, 0, f(Yes, false, "")}, + {0x1fd6, 0, 0, 1, f(Yes, false, "ῖ")}, + {0x1fd7, 0, 0, 2, f(Yes, false, "ῗ")}, + {0x1fd8, 0, 0, 1, f(Yes, false, "Ῐ")}, + {0x1fd9, 0, 0, 1, f(Yes, false, "Ῑ")}, + {0x1fda, 0, 0, 1, f(Yes, false, "Ὶ")}, + {0x1fdb, 0, 0, 1, f(No, false, "Ί")}, + {0x1fdc, 0, 0, 0, f(Yes, false, "")}, + {0x1fdd, 0, 0, 2, g(Yes, No, false, false, "῝", " ̔̀")}, + {0x1fde, 0, 0, 2, g(Yes, No, false, false, "῞", " ̔́")}, + {0x1fdf, 0, 0, 2, g(Yes, No, false, false, "῟", " ̔͂")}, + {0x1fe0, 0, 0, 1, f(Yes, false, "ῠ")}, + {0x1fe1, 0, 0, 1, f(Yes, false, "ῡ")}, + {0x1fe2, 0, 0, 2, f(Yes, false, "ῢ")}, + {0x1fe3, 0, 0, 2, f(No, false, "ΰ")}, + {0x1fe4, 0, 0, 1, f(Yes, false, "ῤ")}, + {0x1fe5, 0, 0, 1, f(Yes, false, "ῥ")}, + {0x1fe6, 0, 0, 1, f(Yes, false, "ῦ")}, + {0x1fe7, 0, 0, 2, f(Yes, false, "ῧ")}, + {0x1fe8, 0, 0, 1, f(Yes, false, "Ῠ")}, + {0x1fe9, 0, 0, 1, f(Yes, false, "Ῡ")}, + {0x1fea, 0, 0, 1, f(Yes, false, "Ὺ")}, + {0x1feb, 0, 0, 1, f(No, false, "Ύ")}, + {0x1fec, 0, 0, 1, f(Yes, false, "Ῥ")}, + {0x1fed, 0, 0, 2, g(Yes, No, false, false, "῭", " ̈̀")}, + {0x1fee, 0, 0, 2, g(No, No, false, false, "΅", " ̈́")}, + {0x1fef, 0, 0, 0, f(No, false, "`")}, + {0x1ff0, 0, 0, 0, f(Yes, false, "")}, + {0x1ff2, 0, 0, 2, f(Yes, false, "ῲ")}, + {0x1ff3, 0, 0, 1, f(Yes, false, "ῳ")}, + {0x1ff4, 0, 0, 2, f(Yes, false, "ῴ")}, + {0x1ff5, 0, 0, 0, f(Yes, false, "")}, + {0x1ff6, 0, 0, 1, f(Yes, true, "ῶ")}, + {0x1ff7, 0, 0, 2, f(Yes, false, "ῷ")}, + {0x1ff8, 0, 0, 1, f(Yes, false, "Ὸ")}, + {0x1ff9, 0, 0, 1, f(No, false, "Ό")}, + {0x1ffa, 0, 0, 1, f(Yes, false, "Ὼ")}, + {0x1ffb, 0, 0, 1, f(No, false, "Ώ")}, + {0x1ffc, 0, 0, 1, f(Yes, false, "ῼ")}, + {0x1ffd, 0, 0, 1, g(No, No, false, false, "´", " ́")}, + {0x1ffe, 0, 0, 1, g(Yes, No, true, false, "", " ̔")}, + {0x1fff, 0, 0, 0, f(Yes, false, "")}, + {0x2000, 0, 0, 0, g(No, No, false, false, "\u2002", " ")}, + {0x2001, 0, 0, 0, g(No, No, false, false, "\u2003", " ")}, + {0x2002, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x200b, 0, 0, 0, f(Yes, false, "")}, + {0x2011, 0, 0, 0, g(Yes, No, false, false, "", "‐")}, + {0x2012, 0, 0, 0, f(Yes, false, "")}, + {0x2017, 0, 0, 1, g(Yes, No, false, false, "", " ̳")}, + {0x2018, 0, 0, 0, f(Yes, false, "")}, + {0x2024, 0, 0, 0, g(Yes, No, false, false, "", ".")}, + {0x2025, 0, 0, 0, g(Yes, No, false, false, "", "..")}, + {0x2026, 0, 0, 0, g(Yes, No, false, false, "", "...")}, + {0x2027, 0, 0, 0, f(Yes, false, "")}, + {0x202f, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x2030, 0, 0, 0, f(Yes, false, "")}, + {0x2033, 0, 0, 0, g(Yes, No, false, false, "", "′′")}, + {0x2034, 0, 0, 0, g(Yes, No, false, false, "", "′′′")}, + {0x2035, 0, 0, 0, f(Yes, false, "")}, + {0x2036, 0, 0, 0, g(Yes, No, false, false, "", "‵‵")}, + {0x2037, 0, 0, 0, g(Yes, No, false, false, "", "‵‵‵")}, + {0x2038, 0, 0, 0, f(Yes, false, "")}, + {0x203c, 0, 0, 0, g(Yes, No, false, false, "", "!!")}, + {0x203d, 0, 0, 0, f(Yes, false, "")}, + {0x203e, 0, 0, 1, g(Yes, No, false, false, "", " ̅")}, + {0x203f, 0, 0, 0, f(Yes, false, "")}, + {0x2047, 0, 0, 0, g(Yes, No, false, false, "", "??")}, + {0x2048, 0, 0, 0, g(Yes, No, false, false, "", "?!")}, + {0x2049, 0, 0, 0, g(Yes, No, false, false, "", "!?")}, + {0x204a, 0, 0, 0, f(Yes, false, "")}, + {0x2057, 0, 0, 0, g(Yes, No, false, false, "", "′′′′")}, + {0x2058, 0, 0, 0, f(Yes, false, "")}, + {0x205f, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x2060, 0, 0, 0, f(Yes, false, "")}, + {0x2070, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x2071, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x2072, 0, 0, 0, f(Yes, false, "")}, + {0x2074, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x2075, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x2076, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x2077, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x2078, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x2079, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x207a, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0x207b, 0, 0, 0, g(Yes, No, false, false, "", "−")}, + {0x207c, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0x207d, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0x207e, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0x207f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x2080, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x2081, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x2082, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x2083, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x2084, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x2085, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x2086, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x2087, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x2088, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x2089, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x208a, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0x208b, 0, 0, 0, g(Yes, No, false, false, "", "−")}, + {0x208c, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0x208d, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0x208e, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0x208f, 0, 0, 0, f(Yes, false, "")}, + {0x2090, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x2091, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x2092, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x2093, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x2094, 0, 0, 0, g(Yes, No, false, false, "", "ə")}, + {0x2095, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x2096, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x2097, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x2098, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x2099, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x209a, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x209b, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x209c, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x209d, 0, 0, 0, f(Yes, false, "")}, + {0x20a8, 0, 0, 0, g(Yes, No, false, false, "", "Rs")}, + {0x20a9, 0, 0, 0, f(Yes, false, "")}, + {0x20d0, 230, 1, 1, f(Yes, false, "")}, + {0x20d2, 1, 1, 1, f(Yes, false, "")}, + {0x20d4, 230, 1, 1, f(Yes, false, "")}, + {0x20d8, 1, 1, 1, f(Yes, false, "")}, + {0x20db, 230, 1, 1, f(Yes, false, "")}, + {0x20dd, 0, 0, 0, f(Yes, false, "")}, + {0x20e1, 230, 1, 1, f(Yes, false, "")}, + {0x20e2, 0, 0, 0, f(Yes, false, "")}, + {0x20e5, 1, 1, 1, f(Yes, false, "")}, + {0x20e7, 230, 1, 1, f(Yes, false, "")}, + {0x20e8, 220, 1, 1, f(Yes, false, "")}, + {0x20e9, 230, 1, 1, f(Yes, false, "")}, + {0x20ea, 1, 1, 1, f(Yes, false, "")}, + {0x20ec, 220, 1, 1, f(Yes, false, "")}, + {0x20f0, 230, 1, 1, f(Yes, false, "")}, + {0x20f1, 0, 0, 0, f(Yes, false, "")}, + {0x2100, 0, 0, 0, g(Yes, No, false, false, "", "a/c")}, + {0x2101, 0, 0, 0, g(Yes, No, false, false, "", "a/s")}, + {0x2102, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x2103, 0, 0, 0, g(Yes, No, false, false, "", "°C")}, + {0x2104, 0, 0, 0, f(Yes, false, "")}, + {0x2105, 0, 0, 0, g(Yes, No, false, false, "", "c/o")}, + {0x2106, 0, 0, 0, g(Yes, No, false, false, "", "c/u")}, + {0x2107, 0, 0, 0, g(Yes, No, false, false, "", "Ɛ")}, + {0x2108, 0, 0, 0, f(Yes, false, "")}, + {0x2109, 0, 0, 0, g(Yes, No, false, false, "", "°F")}, + {0x210a, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x210b, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x210e, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x210f, 0, 0, 0, g(Yes, No, false, false, "", "ħ")}, + {0x2110, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x2112, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x2113, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x2114, 0, 0, 0, f(Yes, false, "")}, + {0x2115, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x2116, 0, 0, 0, g(Yes, No, false, false, "", "No")}, + {0x2117, 0, 0, 0, f(Yes, false, "")}, + {0x2119, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x211a, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x211b, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x211e, 0, 0, 0, f(Yes, false, "")}, + {0x2120, 0, 0, 0, g(Yes, No, false, false, "", "SM")}, + {0x2121, 0, 0, 0, g(Yes, No, false, false, "", "TEL")}, + {0x2122, 0, 0, 0, g(Yes, No, false, false, "", "TM")}, + {0x2123, 0, 0, 0, f(Yes, false, "")}, + {0x2124, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x2125, 0, 0, 0, f(Yes, false, "")}, + {0x2126, 0, 0, 0, f(No, false, "Ω")}, + {0x2127, 0, 0, 0, f(Yes, false, "")}, + {0x2128, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x2129, 0, 0, 0, f(Yes, false, "")}, + {0x212a, 0, 0, 0, f(No, false, "K")}, + {0x212b, 0, 0, 1, f(No, false, "Å")}, + {0x212c, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x212d, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x212e, 0, 0, 0, f(Yes, false, "")}, + {0x212f, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x2130, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x2131, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x2132, 0, 0, 0, f(Yes, false, "")}, + {0x2133, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x2134, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x2135, 0, 0, 0, g(Yes, No, false, false, "", "א")}, + {0x2136, 0, 0, 0, g(Yes, No, false, false, "", "ב")}, + {0x2137, 0, 0, 0, g(Yes, No, false, false, "", "ג")}, + {0x2138, 0, 0, 0, g(Yes, No, false, false, "", "ד")}, + {0x2139, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x213a, 0, 0, 0, f(Yes, false, "")}, + {0x213b, 0, 0, 0, g(Yes, No, false, false, "", "FAX")}, + {0x213c, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x213d, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x213e, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x213f, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x2140, 0, 0, 0, g(Yes, No, false, false, "", "∑")}, + {0x2141, 0, 0, 0, f(Yes, false, "")}, + {0x2145, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x2146, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x2147, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x2148, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x2149, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x214a, 0, 0, 0, f(Yes, false, "")}, + {0x2150, 0, 0, 0, g(Yes, No, false, false, "", "1⁄7")}, + {0x2151, 0, 0, 0, g(Yes, No, false, false, "", "1⁄9")}, + {0x2152, 0, 0, 0, g(Yes, No, false, false, "", "1⁄10")}, + {0x2153, 0, 0, 0, g(Yes, No, false, false, "", "1⁄3")}, + {0x2154, 0, 0, 0, g(Yes, No, false, false, "", "2⁄3")}, + {0x2155, 0, 0, 0, g(Yes, No, false, false, "", "1⁄5")}, + {0x2156, 0, 0, 0, g(Yes, No, false, false, "", "2⁄5")}, + {0x2157, 0, 0, 0, g(Yes, No, false, false, "", "3⁄5")}, + {0x2158, 0, 0, 0, g(Yes, No, false, false, "", "4⁄5")}, + {0x2159, 0, 0, 0, g(Yes, No, false, false, "", "1⁄6")}, + {0x215a, 0, 0, 0, g(Yes, No, false, false, "", "5⁄6")}, + {0x215b, 0, 0, 0, g(Yes, No, false, false, "", "1⁄8")}, + {0x215c, 0, 0, 0, g(Yes, No, false, false, "", "3⁄8")}, + {0x215d, 0, 0, 0, g(Yes, No, false, false, "", "5⁄8")}, + {0x215e, 0, 0, 0, g(Yes, No, false, false, "", "7⁄8")}, + {0x215f, 0, 0, 0, g(Yes, No, false, false, "", "1⁄")}, + {0x2160, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x2161, 0, 0, 0, g(Yes, No, false, false, "", "II")}, + {0x2162, 0, 0, 0, g(Yes, No, false, false, "", "III")}, + {0x2163, 0, 0, 0, g(Yes, No, false, false, "", "IV")}, + {0x2164, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x2165, 0, 0, 0, g(Yes, No, false, false, "", "VI")}, + {0x2166, 0, 0, 0, g(Yes, No, false, false, "", "VII")}, + {0x2167, 0, 0, 0, g(Yes, No, false, false, "", "VIII")}, + {0x2168, 0, 0, 0, g(Yes, No, false, false, "", "IX")}, + {0x2169, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x216a, 0, 0, 0, g(Yes, No, false, false, "", "XI")}, + {0x216b, 0, 0, 0, g(Yes, No, false, false, "", "XII")}, + {0x216c, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x216d, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x216e, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x216f, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x2170, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x2171, 0, 0, 0, g(Yes, No, false, false, "", "ii")}, + {0x2172, 0, 0, 0, g(Yes, No, false, false, "", "iii")}, + {0x2173, 0, 0, 0, g(Yes, No, false, false, "", "iv")}, + {0x2174, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x2175, 0, 0, 0, g(Yes, No, false, false, "", "vi")}, + {0x2176, 0, 0, 0, g(Yes, No, false, false, "", "vii")}, + {0x2177, 0, 0, 0, g(Yes, No, false, false, "", "viii")}, + {0x2178, 0, 0, 0, g(Yes, No, false, false, "", "ix")}, + {0x2179, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x217a, 0, 0, 0, g(Yes, No, false, false, "", "xi")}, + {0x217b, 0, 0, 0, g(Yes, No, false, false, "", "xii")}, + {0x217c, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x217d, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x217e, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x217f, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x2180, 0, 0, 0, f(Yes, false, "")}, + {0x2189, 0, 0, 0, g(Yes, No, false, false, "", "0⁄3")}, + {0x218a, 0, 0, 0, f(Yes, false, "")}, + {0x2190, 0, 0, 0, f(Yes, true, "")}, + {0x2191, 0, 0, 0, f(Yes, false, "")}, + {0x2192, 0, 0, 0, f(Yes, true, "")}, + {0x2193, 0, 0, 0, f(Yes, false, "")}, + {0x2194, 0, 0, 0, f(Yes, true, "")}, + {0x2195, 0, 0, 0, f(Yes, false, "")}, + {0x219a, 0, 0, 1, f(Yes, false, "↚")}, + {0x219b, 0, 0, 1, f(Yes, false, "↛")}, + {0x219c, 0, 0, 0, f(Yes, false, "")}, + {0x21ae, 0, 0, 1, f(Yes, false, "↮")}, + {0x21af, 0, 0, 0, f(Yes, false, "")}, + {0x21cd, 0, 0, 1, f(Yes, false, "⇍")}, + {0x21ce, 0, 0, 1, f(Yes, false, "⇎")}, + {0x21cf, 0, 0, 1, f(Yes, false, "⇏")}, + {0x21d0, 0, 0, 0, f(Yes, true, "")}, + {0x21d1, 0, 0, 0, f(Yes, false, "")}, + {0x21d2, 0, 0, 0, f(Yes, true, "")}, + {0x21d3, 0, 0, 0, f(Yes, false, "")}, + {0x21d4, 0, 0, 0, f(Yes, true, "")}, + {0x21d5, 0, 0, 0, f(Yes, false, "")}, + {0x2203, 0, 0, 0, f(Yes, true, "")}, + {0x2204, 0, 0, 1, f(Yes, false, "∄")}, + {0x2205, 0, 0, 0, f(Yes, false, "")}, + {0x2208, 0, 0, 0, f(Yes, true, "")}, + {0x2209, 0, 0, 1, f(Yes, false, "∉")}, + {0x220a, 0, 0, 0, f(Yes, false, "")}, + {0x220b, 0, 0, 0, f(Yes, true, "")}, + {0x220c, 0, 0, 1, f(Yes, false, "∌")}, + {0x220d, 0, 0, 0, f(Yes, false, "")}, + {0x2223, 0, 0, 0, f(Yes, true, "")}, + {0x2224, 0, 0, 1, f(Yes, false, "∤")}, + {0x2225, 0, 0, 0, f(Yes, true, "")}, + {0x2226, 0, 0, 1, f(Yes, false, "∦")}, + {0x2227, 0, 0, 0, f(Yes, false, "")}, + {0x222c, 0, 0, 0, g(Yes, No, false, false, "", "∫∫")}, + {0x222d, 0, 0, 0, g(Yes, No, false, false, "", "∫∫∫")}, + {0x222e, 0, 0, 0, f(Yes, false, "")}, + {0x222f, 0, 0, 0, g(Yes, No, false, false, "", "∮∮")}, + {0x2230, 0, 0, 0, g(Yes, No, false, false, "", "∮∮∮")}, + {0x2231, 0, 0, 0, f(Yes, false, "")}, + {0x223c, 0, 0, 0, f(Yes, true, "")}, + {0x223d, 0, 0, 0, f(Yes, false, "")}, + {0x2241, 0, 0, 1, f(Yes, false, "≁")}, + {0x2242, 0, 0, 0, f(Yes, false, "")}, + {0x2243, 0, 0, 0, f(Yes, true, "")}, + {0x2244, 0, 0, 1, f(Yes, false, "≄")}, + {0x2245, 0, 0, 0, f(Yes, true, "")}, + {0x2246, 0, 0, 0, f(Yes, false, "")}, + {0x2247, 0, 0, 1, f(Yes, false, "≇")}, + {0x2248, 0, 0, 0, f(Yes, true, "")}, + {0x2249, 0, 0, 1, f(Yes, false, "≉")}, + {0x224a, 0, 0, 0, f(Yes, false, "")}, + {0x224d, 0, 0, 0, f(Yes, true, "")}, + {0x224e, 0, 0, 0, f(Yes, false, "")}, + {0x2260, 0, 0, 1, f(Yes, false, "≠")}, + {0x2261, 0, 0, 0, f(Yes, true, "")}, + {0x2262, 0, 0, 1, f(Yes, false, "≢")}, + {0x2263, 0, 0, 0, f(Yes, false, "")}, + {0x2264, 0, 0, 0, f(Yes, true, "")}, + {0x2266, 0, 0, 0, f(Yes, false, "")}, + {0x226d, 0, 0, 1, f(Yes, false, "≭")}, + {0x226e, 0, 0, 1, f(Yes, false, "≮")}, + {0x226f, 0, 0, 1, f(Yes, false, "≯")}, + {0x2270, 0, 0, 1, f(Yes, false, "≰")}, + {0x2271, 0, 0, 1, f(Yes, false, "≱")}, + {0x2272, 0, 0, 0, f(Yes, true, "")}, + {0x2274, 0, 0, 1, f(Yes, false, "≴")}, + {0x2275, 0, 0, 1, f(Yes, false, "≵")}, + {0x2276, 0, 0, 0, f(Yes, true, "")}, + {0x2278, 0, 0, 1, f(Yes, false, "≸")}, + {0x2279, 0, 0, 1, f(Yes, false, "≹")}, + {0x227a, 0, 0, 0, f(Yes, true, "")}, + {0x227e, 0, 0, 0, f(Yes, false, "")}, + {0x2280, 0, 0, 1, f(Yes, false, "⊀")}, + {0x2281, 0, 0, 1, f(Yes, false, "⊁")}, + {0x2282, 0, 0, 0, f(Yes, true, "")}, + {0x2284, 0, 0, 1, f(Yes, false, "⊄")}, + {0x2285, 0, 0, 1, f(Yes, false, "⊅")}, + {0x2286, 0, 0, 0, f(Yes, true, "")}, + {0x2288, 0, 0, 1, f(Yes, false, "⊈")}, + {0x2289, 0, 0, 1, f(Yes, false, "⊉")}, + {0x228a, 0, 0, 0, f(Yes, false, "")}, + {0x2291, 0, 0, 0, f(Yes, true, "")}, + {0x2293, 0, 0, 0, f(Yes, false, "")}, + {0x22a2, 0, 0, 0, f(Yes, true, "")}, + {0x22a3, 0, 0, 0, f(Yes, false, "")}, + {0x22a8, 0, 0, 0, f(Yes, true, "")}, + {0x22aa, 0, 0, 0, f(Yes, false, "")}, + {0x22ab, 0, 0, 0, f(Yes, true, "")}, + {0x22ac, 0, 0, 1, f(Yes, false, "⊬")}, + {0x22ad, 0, 0, 1, f(Yes, false, "⊭")}, + {0x22ae, 0, 0, 1, f(Yes, false, "⊮")}, + {0x22af, 0, 0, 1, f(Yes, false, "⊯")}, + {0x22b0, 0, 0, 0, f(Yes, false, "")}, + {0x22b2, 0, 0, 0, f(Yes, true, "")}, + {0x22b6, 0, 0, 0, f(Yes, false, "")}, + {0x22e0, 0, 0, 1, f(Yes, false, "⋠")}, + {0x22e1, 0, 0, 1, f(Yes, false, "⋡")}, + {0x22e2, 0, 0, 1, f(Yes, false, "⋢")}, + {0x22e3, 0, 0, 1, f(Yes, false, "⋣")}, + {0x22e4, 0, 0, 0, f(Yes, false, "")}, + {0x22ea, 0, 0, 1, f(Yes, false, "⋪")}, + {0x22eb, 0, 0, 1, f(Yes, false, "⋫")}, + {0x22ec, 0, 0, 1, f(Yes, false, "⋬")}, + {0x22ed, 0, 0, 1, f(Yes, false, "⋭")}, + {0x22ee, 0, 0, 0, f(Yes, false, "")}, + {0x2329, 0, 0, 0, f(No, false, "〈")}, + {0x232a, 0, 0, 0, f(No, false, "〉")}, + {0x232b, 0, 0, 0, f(Yes, false, "")}, + {0x2460, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x2461, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x2462, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x2463, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x2464, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x2465, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x2466, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x2467, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x2468, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x2469, 0, 0, 0, g(Yes, No, false, false, "", "10")}, + {0x246a, 0, 0, 0, g(Yes, No, false, false, "", "11")}, + {0x246b, 0, 0, 0, g(Yes, No, false, false, "", "12")}, + {0x246c, 0, 0, 0, g(Yes, No, false, false, "", "13")}, + {0x246d, 0, 0, 0, g(Yes, No, false, false, "", "14")}, + {0x246e, 0, 0, 0, g(Yes, No, false, false, "", "15")}, + {0x246f, 0, 0, 0, g(Yes, No, false, false, "", "16")}, + {0x2470, 0, 0, 0, g(Yes, No, false, false, "", "17")}, + {0x2471, 0, 0, 0, g(Yes, No, false, false, "", "18")}, + {0x2472, 0, 0, 0, g(Yes, No, false, false, "", "19")}, + {0x2473, 0, 0, 0, g(Yes, No, false, false, "", "20")}, + {0x2474, 0, 0, 0, g(Yes, No, false, false, "", "(1)")}, + {0x2475, 0, 0, 0, g(Yes, No, false, false, "", "(2)")}, + {0x2476, 0, 0, 0, g(Yes, No, false, false, "", "(3)")}, + {0x2477, 0, 0, 0, g(Yes, No, false, false, "", "(4)")}, + {0x2478, 0, 0, 0, g(Yes, No, false, false, "", "(5)")}, + {0x2479, 0, 0, 0, g(Yes, No, false, false, "", "(6)")}, + {0x247a, 0, 0, 0, g(Yes, No, false, false, "", "(7)")}, + {0x247b, 0, 0, 0, g(Yes, No, false, false, "", "(8)")}, + {0x247c, 0, 0, 0, g(Yes, No, false, false, "", "(9)")}, + {0x247d, 0, 0, 0, g(Yes, No, false, false, "", "(10)")}, + {0x247e, 0, 0, 0, g(Yes, No, false, false, "", "(11)")}, + {0x247f, 0, 0, 0, g(Yes, No, false, false, "", "(12)")}, + {0x2480, 0, 0, 0, g(Yes, No, false, false, "", "(13)")}, + {0x2481, 0, 0, 0, g(Yes, No, false, false, "", "(14)")}, + {0x2482, 0, 0, 0, g(Yes, No, false, false, "", "(15)")}, + {0x2483, 0, 0, 0, g(Yes, No, false, false, "", "(16)")}, + {0x2484, 0, 0, 0, g(Yes, No, false, false, "", "(17)")}, + {0x2485, 0, 0, 0, g(Yes, No, false, false, "", "(18)")}, + {0x2486, 0, 0, 0, g(Yes, No, false, false, "", "(19)")}, + {0x2487, 0, 0, 0, g(Yes, No, false, false, "", "(20)")}, + {0x2488, 0, 0, 0, g(Yes, No, false, false, "", "1.")}, + {0x2489, 0, 0, 0, g(Yes, No, false, false, "", "2.")}, + {0x248a, 0, 0, 0, g(Yes, No, false, false, "", "3.")}, + {0x248b, 0, 0, 0, g(Yes, No, false, false, "", "4.")}, + {0x248c, 0, 0, 0, g(Yes, No, false, false, "", "5.")}, + {0x248d, 0, 0, 0, g(Yes, No, false, false, "", "6.")}, + {0x248e, 0, 0, 0, g(Yes, No, false, false, "", "7.")}, + {0x248f, 0, 0, 0, g(Yes, No, false, false, "", "8.")}, + {0x2490, 0, 0, 0, g(Yes, No, false, false, "", "9.")}, + {0x2491, 0, 0, 0, g(Yes, No, false, false, "", "10.")}, + {0x2492, 0, 0, 0, g(Yes, No, false, false, "", "11.")}, + {0x2493, 0, 0, 0, g(Yes, No, false, false, "", "12.")}, + {0x2494, 0, 0, 0, g(Yes, No, false, false, "", "13.")}, + {0x2495, 0, 0, 0, g(Yes, No, false, false, "", "14.")}, + {0x2496, 0, 0, 0, g(Yes, No, false, false, "", "15.")}, + {0x2497, 0, 0, 0, g(Yes, No, false, false, "", "16.")}, + {0x2498, 0, 0, 0, g(Yes, No, false, false, "", "17.")}, + {0x2499, 0, 0, 0, g(Yes, No, false, false, "", "18.")}, + {0x249a, 0, 0, 0, g(Yes, No, false, false, "", "19.")}, + {0x249b, 0, 0, 0, g(Yes, No, false, false, "", "20.")}, + {0x249c, 0, 0, 0, g(Yes, No, false, false, "", "(a)")}, + {0x249d, 0, 0, 0, g(Yes, No, false, false, "", "(b)")}, + {0x249e, 0, 0, 0, g(Yes, No, false, false, "", "(c)")}, + {0x249f, 0, 0, 0, g(Yes, No, false, false, "", "(d)")}, + {0x24a0, 0, 0, 0, g(Yes, No, false, false, "", "(e)")}, + {0x24a1, 0, 0, 0, g(Yes, No, false, false, "", "(f)")}, + {0x24a2, 0, 0, 0, g(Yes, No, false, false, "", "(g)")}, + {0x24a3, 0, 0, 0, g(Yes, No, false, false, "", "(h)")}, + {0x24a4, 0, 0, 0, g(Yes, No, false, false, "", "(i)")}, + {0x24a5, 0, 0, 0, g(Yes, No, false, false, "", "(j)")}, + {0x24a6, 0, 0, 0, g(Yes, No, false, false, "", "(k)")}, + {0x24a7, 0, 0, 0, g(Yes, No, false, false, "", "(l)")}, + {0x24a8, 0, 0, 0, g(Yes, No, false, false, "", "(m)")}, + {0x24a9, 0, 0, 0, g(Yes, No, false, false, "", "(n)")}, + {0x24aa, 0, 0, 0, g(Yes, No, false, false, "", "(o)")}, + {0x24ab, 0, 0, 0, g(Yes, No, false, false, "", "(p)")}, + {0x24ac, 0, 0, 0, g(Yes, No, false, false, "", "(q)")}, + {0x24ad, 0, 0, 0, g(Yes, No, false, false, "", "(r)")}, + {0x24ae, 0, 0, 0, g(Yes, No, false, false, "", "(s)")}, + {0x24af, 0, 0, 0, g(Yes, No, false, false, "", "(t)")}, + {0x24b0, 0, 0, 0, g(Yes, No, false, false, "", "(u)")}, + {0x24b1, 0, 0, 0, g(Yes, No, false, false, "", "(v)")}, + {0x24b2, 0, 0, 0, g(Yes, No, false, false, "", "(w)")}, + {0x24b3, 0, 0, 0, g(Yes, No, false, false, "", "(x)")}, + {0x24b4, 0, 0, 0, g(Yes, No, false, false, "", "(y)")}, + {0x24b5, 0, 0, 0, g(Yes, No, false, false, "", "(z)")}, + {0x24b6, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x24b7, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x24b8, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x24b9, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x24ba, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x24bb, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x24bc, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x24bd, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x24be, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x24bf, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x24c0, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x24c1, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x24c2, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x24c3, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x24c4, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x24c5, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x24c6, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x24c7, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x24c8, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x24c9, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x24ca, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x24cb, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x24cc, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x24cd, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x24ce, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x24cf, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x24d0, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x24d1, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x24d2, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x24d3, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x24d4, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x24d5, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x24d6, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x24d7, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x24d8, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x24d9, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x24da, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x24db, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x24dc, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x24dd, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x24de, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x24df, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x24e0, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x24e1, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x24e2, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x24e3, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x24e4, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x24e5, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x24e6, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x24e7, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x24e8, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x24e9, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x24ea, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x24eb, 0, 0, 0, f(Yes, false, "")}, + {0x2a0c, 0, 0, 0, g(Yes, No, false, false, "", "∫∫∫∫")}, + {0x2a0d, 0, 0, 0, f(Yes, false, "")}, + {0x2a74, 0, 0, 0, g(Yes, No, false, false, "", "::=")}, + {0x2a75, 0, 0, 0, g(Yes, No, false, false, "", "==")}, + {0x2a76, 0, 0, 0, g(Yes, No, false, false, "", "===")}, + {0x2a77, 0, 0, 0, f(Yes, false, "")}, + {0x2adc, 0, 0, 1, f(No, false, "⫝̸")}, + {0x2add, 0, 0, 0, f(Yes, false, "")}, + {0x2c7c, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x2c7d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x2c7e, 0, 0, 0, f(Yes, false, "")}, + {0x2cef, 230, 1, 1, f(Yes, false, "")}, + {0x2cf2, 0, 0, 0, f(Yes, false, "")}, + {0x2d6f, 0, 0, 0, g(Yes, No, false, false, "", "ⵡ")}, + {0x2d70, 0, 0, 0, f(Yes, false, "")}, + {0x2d7f, 9, 1, 1, f(Yes, false, "")}, + {0x2d80, 0, 0, 0, f(Yes, false, "")}, + {0x2de0, 230, 1, 1, f(Yes, false, "")}, + {0x2e00, 0, 0, 0, f(Yes, false, "")}, + {0x2e9f, 0, 0, 0, g(Yes, No, false, false, "", "母")}, + {0x2ea0, 0, 0, 0, f(Yes, false, "")}, + {0x2ef3, 0, 0, 0, g(Yes, No, false, false, "", "龟")}, + {0x2ef4, 0, 0, 0, f(Yes, false, "")}, + {0x2f00, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x2f01, 0, 0, 0, g(Yes, No, false, false, "", "丨")}, + {0x2f02, 0, 0, 0, g(Yes, No, false, false, "", "丶")}, + {0x2f03, 0, 0, 0, g(Yes, No, false, false, "", "丿")}, + {0x2f04, 0, 0, 0, g(Yes, No, false, false, "", "乙")}, + {0x2f05, 0, 0, 0, g(Yes, No, false, false, "", "亅")}, + {0x2f06, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x2f07, 0, 0, 0, g(Yes, No, false, false, "", "亠")}, + {0x2f08, 0, 0, 0, g(Yes, No, false, false, "", "人")}, + {0x2f09, 0, 0, 0, g(Yes, No, false, false, "", "儿")}, + {0x2f0a, 0, 0, 0, g(Yes, No, false, false, "", "入")}, + {0x2f0b, 0, 0, 0, g(Yes, No, false, false, "", "八")}, + {0x2f0c, 0, 0, 0, g(Yes, No, false, false, "", "冂")}, + {0x2f0d, 0, 0, 0, g(Yes, No, false, false, "", "冖")}, + {0x2f0e, 0, 0, 0, g(Yes, No, false, false, "", "冫")}, + {0x2f0f, 0, 0, 0, g(Yes, No, false, false, "", "几")}, + {0x2f10, 0, 0, 0, g(Yes, No, false, false, "", "凵")}, + {0x2f11, 0, 0, 0, g(Yes, No, false, false, "", "刀")}, + {0x2f12, 0, 0, 0, g(Yes, No, false, false, "", "力")}, + {0x2f13, 0, 0, 0, g(Yes, No, false, false, "", "勹")}, + {0x2f14, 0, 0, 0, g(Yes, No, false, false, "", "匕")}, + {0x2f15, 0, 0, 0, g(Yes, No, false, false, "", "匚")}, + {0x2f16, 0, 0, 0, g(Yes, No, false, false, "", "匸")}, + {0x2f17, 0, 0, 0, g(Yes, No, false, false, "", "十")}, + {0x2f18, 0, 0, 0, g(Yes, No, false, false, "", "卜")}, + {0x2f19, 0, 0, 0, g(Yes, No, false, false, "", "卩")}, + {0x2f1a, 0, 0, 0, g(Yes, No, false, false, "", "厂")}, + {0x2f1b, 0, 0, 0, g(Yes, No, false, false, "", "厶")}, + {0x2f1c, 0, 0, 0, g(Yes, No, false, false, "", "又")}, + {0x2f1d, 0, 0, 0, g(Yes, No, false, false, "", "口")}, + {0x2f1e, 0, 0, 0, g(Yes, No, false, false, "", "囗")}, + {0x2f1f, 0, 0, 0, g(Yes, No, false, false, "", "土")}, + {0x2f20, 0, 0, 0, g(Yes, No, false, false, "", "士")}, + {0x2f21, 0, 0, 0, g(Yes, No, false, false, "", "夂")}, + {0x2f22, 0, 0, 0, g(Yes, No, false, false, "", "夊")}, + {0x2f23, 0, 0, 0, g(Yes, No, false, false, "", "夕")}, + {0x2f24, 0, 0, 0, g(Yes, No, false, false, "", "大")}, + {0x2f25, 0, 0, 0, g(Yes, No, false, false, "", "女")}, + {0x2f26, 0, 0, 0, g(Yes, No, false, false, "", "子")}, + {0x2f27, 0, 0, 0, g(Yes, No, false, false, "", "宀")}, + {0x2f28, 0, 0, 0, g(Yes, No, false, false, "", "寸")}, + {0x2f29, 0, 0, 0, g(Yes, No, false, false, "", "小")}, + {0x2f2a, 0, 0, 0, g(Yes, No, false, false, "", "尢")}, + {0x2f2b, 0, 0, 0, g(Yes, No, false, false, "", "尸")}, + {0x2f2c, 0, 0, 0, g(Yes, No, false, false, "", "屮")}, + {0x2f2d, 0, 0, 0, g(Yes, No, false, false, "", "山")}, + {0x2f2e, 0, 0, 0, g(Yes, No, false, false, "", "巛")}, + {0x2f2f, 0, 0, 0, g(Yes, No, false, false, "", "工")}, + {0x2f30, 0, 0, 0, g(Yes, No, false, false, "", "己")}, + {0x2f31, 0, 0, 0, g(Yes, No, false, false, "", "巾")}, + {0x2f32, 0, 0, 0, g(Yes, No, false, false, "", "干")}, + {0x2f33, 0, 0, 0, g(Yes, No, false, false, "", "幺")}, + {0x2f34, 0, 0, 0, g(Yes, No, false, false, "", "广")}, + {0x2f35, 0, 0, 0, g(Yes, No, false, false, "", "廴")}, + {0x2f36, 0, 0, 0, g(Yes, No, false, false, "", "廾")}, + {0x2f37, 0, 0, 0, g(Yes, No, false, false, "", "弋")}, + {0x2f38, 0, 0, 0, g(Yes, No, false, false, "", "弓")}, + {0x2f39, 0, 0, 0, g(Yes, No, false, false, "", "彐")}, + {0x2f3a, 0, 0, 0, g(Yes, No, false, false, "", "彡")}, + {0x2f3b, 0, 0, 0, g(Yes, No, false, false, "", "彳")}, + {0x2f3c, 0, 0, 0, g(Yes, No, false, false, "", "心")}, + {0x2f3d, 0, 0, 0, g(Yes, No, false, false, "", "戈")}, + {0x2f3e, 0, 0, 0, g(Yes, No, false, false, "", "戶")}, + {0x2f3f, 0, 0, 0, g(Yes, No, false, false, "", "手")}, + {0x2f40, 0, 0, 0, g(Yes, No, false, false, "", "支")}, + {0x2f41, 0, 0, 0, g(Yes, No, false, false, "", "攴")}, + {0x2f42, 0, 0, 0, g(Yes, No, false, false, "", "文")}, + {0x2f43, 0, 0, 0, g(Yes, No, false, false, "", "斗")}, + {0x2f44, 0, 0, 0, g(Yes, No, false, false, "", "斤")}, + {0x2f45, 0, 0, 0, g(Yes, No, false, false, "", "方")}, + {0x2f46, 0, 0, 0, g(Yes, No, false, false, "", "无")}, + {0x2f47, 0, 0, 0, g(Yes, No, false, false, "", "日")}, + {0x2f48, 0, 0, 0, g(Yes, No, false, false, "", "曰")}, + {0x2f49, 0, 0, 0, g(Yes, No, false, false, "", "月")}, + {0x2f4a, 0, 0, 0, g(Yes, No, false, false, "", "木")}, + {0x2f4b, 0, 0, 0, g(Yes, No, false, false, "", "欠")}, + {0x2f4c, 0, 0, 0, g(Yes, No, false, false, "", "止")}, + {0x2f4d, 0, 0, 0, g(Yes, No, false, false, "", "歹")}, + {0x2f4e, 0, 0, 0, g(Yes, No, false, false, "", "殳")}, + {0x2f4f, 0, 0, 0, g(Yes, No, false, false, "", "毋")}, + {0x2f50, 0, 0, 0, g(Yes, No, false, false, "", "比")}, + {0x2f51, 0, 0, 0, g(Yes, No, false, false, "", "毛")}, + {0x2f52, 0, 0, 0, g(Yes, No, false, false, "", "氏")}, + {0x2f53, 0, 0, 0, g(Yes, No, false, false, "", "气")}, + {0x2f54, 0, 0, 0, g(Yes, No, false, false, "", "水")}, + {0x2f55, 0, 0, 0, g(Yes, No, false, false, "", "火")}, + {0x2f56, 0, 0, 0, g(Yes, No, false, false, "", "爪")}, + {0x2f57, 0, 0, 0, g(Yes, No, false, false, "", "父")}, + {0x2f58, 0, 0, 0, g(Yes, No, false, false, "", "爻")}, + {0x2f59, 0, 0, 0, g(Yes, No, false, false, "", "爿")}, + {0x2f5a, 0, 0, 0, g(Yes, No, false, false, "", "片")}, + {0x2f5b, 0, 0, 0, g(Yes, No, false, false, "", "牙")}, + {0x2f5c, 0, 0, 0, g(Yes, No, false, false, "", "牛")}, + {0x2f5d, 0, 0, 0, g(Yes, No, false, false, "", "犬")}, + {0x2f5e, 0, 0, 0, g(Yes, No, false, false, "", "玄")}, + {0x2f5f, 0, 0, 0, g(Yes, No, false, false, "", "玉")}, + {0x2f60, 0, 0, 0, g(Yes, No, false, false, "", "瓜")}, + {0x2f61, 0, 0, 0, g(Yes, No, false, false, "", "瓦")}, + {0x2f62, 0, 0, 0, g(Yes, No, false, false, "", "甘")}, + {0x2f63, 0, 0, 0, g(Yes, No, false, false, "", "生")}, + {0x2f64, 0, 0, 0, g(Yes, No, false, false, "", "用")}, + {0x2f65, 0, 0, 0, g(Yes, No, false, false, "", "田")}, + {0x2f66, 0, 0, 0, g(Yes, No, false, false, "", "疋")}, + {0x2f67, 0, 0, 0, g(Yes, No, false, false, "", "疒")}, + {0x2f68, 0, 0, 0, g(Yes, No, false, false, "", "癶")}, + {0x2f69, 0, 0, 0, g(Yes, No, false, false, "", "白")}, + {0x2f6a, 0, 0, 0, g(Yes, No, false, false, "", "皮")}, + {0x2f6b, 0, 0, 0, g(Yes, No, false, false, "", "皿")}, + {0x2f6c, 0, 0, 0, g(Yes, No, false, false, "", "目")}, + {0x2f6d, 0, 0, 0, g(Yes, No, false, false, "", "矛")}, + {0x2f6e, 0, 0, 0, g(Yes, No, false, false, "", "矢")}, + {0x2f6f, 0, 0, 0, g(Yes, No, false, false, "", "石")}, + {0x2f70, 0, 0, 0, g(Yes, No, false, false, "", "示")}, + {0x2f71, 0, 0, 0, g(Yes, No, false, false, "", "禸")}, + {0x2f72, 0, 0, 0, g(Yes, No, false, false, "", "禾")}, + {0x2f73, 0, 0, 0, g(Yes, No, false, false, "", "穴")}, + {0x2f74, 0, 0, 0, g(Yes, No, false, false, "", "立")}, + {0x2f75, 0, 0, 0, g(Yes, No, false, false, "", "竹")}, + {0x2f76, 0, 0, 0, g(Yes, No, false, false, "", "米")}, + {0x2f77, 0, 0, 0, g(Yes, No, false, false, "", "糸")}, + {0x2f78, 0, 0, 0, g(Yes, No, false, false, "", "缶")}, + {0x2f79, 0, 0, 0, g(Yes, No, false, false, "", "网")}, + {0x2f7a, 0, 0, 0, g(Yes, No, false, false, "", "羊")}, + {0x2f7b, 0, 0, 0, g(Yes, No, false, false, "", "羽")}, + {0x2f7c, 0, 0, 0, g(Yes, No, false, false, "", "老")}, + {0x2f7d, 0, 0, 0, g(Yes, No, false, false, "", "而")}, + {0x2f7e, 0, 0, 0, g(Yes, No, false, false, "", "耒")}, + {0x2f7f, 0, 0, 0, g(Yes, No, false, false, "", "耳")}, + {0x2f80, 0, 0, 0, g(Yes, No, false, false, "", "聿")}, + {0x2f81, 0, 0, 0, g(Yes, No, false, false, "", "肉")}, + {0x2f82, 0, 0, 0, g(Yes, No, false, false, "", "臣")}, + {0x2f83, 0, 0, 0, g(Yes, No, false, false, "", "自")}, + {0x2f84, 0, 0, 0, g(Yes, No, false, false, "", "至")}, + {0x2f85, 0, 0, 0, g(Yes, No, false, false, "", "臼")}, + {0x2f86, 0, 0, 0, g(Yes, No, false, false, "", "舌")}, + {0x2f87, 0, 0, 0, g(Yes, No, false, false, "", "舛")}, + {0x2f88, 0, 0, 0, g(Yes, No, false, false, "", "舟")}, + {0x2f89, 0, 0, 0, g(Yes, No, false, false, "", "艮")}, + {0x2f8a, 0, 0, 0, g(Yes, No, false, false, "", "色")}, + {0x2f8b, 0, 0, 0, g(Yes, No, false, false, "", "艸")}, + {0x2f8c, 0, 0, 0, g(Yes, No, false, false, "", "虍")}, + {0x2f8d, 0, 0, 0, g(Yes, No, false, false, "", "虫")}, + {0x2f8e, 0, 0, 0, g(Yes, No, false, false, "", "血")}, + {0x2f8f, 0, 0, 0, g(Yes, No, false, false, "", "行")}, + {0x2f90, 0, 0, 0, g(Yes, No, false, false, "", "衣")}, + {0x2f91, 0, 0, 0, g(Yes, No, false, false, "", "襾")}, + {0x2f92, 0, 0, 0, g(Yes, No, false, false, "", "見")}, + {0x2f93, 0, 0, 0, g(Yes, No, false, false, "", "角")}, + {0x2f94, 0, 0, 0, g(Yes, No, false, false, "", "言")}, + {0x2f95, 0, 0, 0, g(Yes, No, false, false, "", "谷")}, + {0x2f96, 0, 0, 0, g(Yes, No, false, false, "", "豆")}, + {0x2f97, 0, 0, 0, g(Yes, No, false, false, "", "豕")}, + {0x2f98, 0, 0, 0, g(Yes, No, false, false, "", "豸")}, + {0x2f99, 0, 0, 0, g(Yes, No, false, false, "", "貝")}, + {0x2f9a, 0, 0, 0, g(Yes, No, false, false, "", "赤")}, + {0x2f9b, 0, 0, 0, g(Yes, No, false, false, "", "走")}, + {0x2f9c, 0, 0, 0, g(Yes, No, false, false, "", "足")}, + {0x2f9d, 0, 0, 0, g(Yes, No, false, false, "", "身")}, + {0x2f9e, 0, 0, 0, g(Yes, No, false, false, "", "車")}, + {0x2f9f, 0, 0, 0, g(Yes, No, false, false, "", "辛")}, + {0x2fa0, 0, 0, 0, g(Yes, No, false, false, "", "辰")}, + {0x2fa1, 0, 0, 0, g(Yes, No, false, false, "", "辵")}, + {0x2fa2, 0, 0, 0, g(Yes, No, false, false, "", "邑")}, + {0x2fa3, 0, 0, 0, g(Yes, No, false, false, "", "酉")}, + {0x2fa4, 0, 0, 0, g(Yes, No, false, false, "", "釆")}, + {0x2fa5, 0, 0, 0, g(Yes, No, false, false, "", "里")}, + {0x2fa6, 0, 0, 0, g(Yes, No, false, false, "", "金")}, + {0x2fa7, 0, 0, 0, g(Yes, No, false, false, "", "長")}, + {0x2fa8, 0, 0, 0, g(Yes, No, false, false, "", "門")}, + {0x2fa9, 0, 0, 0, g(Yes, No, false, false, "", "阜")}, + {0x2faa, 0, 0, 0, g(Yes, No, false, false, "", "隶")}, + {0x2fab, 0, 0, 0, g(Yes, No, false, false, "", "隹")}, + {0x2fac, 0, 0, 0, g(Yes, No, false, false, "", "雨")}, + {0x2fad, 0, 0, 0, g(Yes, No, false, false, "", "靑")}, + {0x2fae, 0, 0, 0, g(Yes, No, false, false, "", "非")}, + {0x2faf, 0, 0, 0, g(Yes, No, false, false, "", "面")}, + {0x2fb0, 0, 0, 0, g(Yes, No, false, false, "", "革")}, + {0x2fb1, 0, 0, 0, g(Yes, No, false, false, "", "韋")}, + {0x2fb2, 0, 0, 0, g(Yes, No, false, false, "", "韭")}, + {0x2fb3, 0, 0, 0, g(Yes, No, false, false, "", "音")}, + {0x2fb4, 0, 0, 0, g(Yes, No, false, false, "", "頁")}, + {0x2fb5, 0, 0, 0, g(Yes, No, false, false, "", "風")}, + {0x2fb6, 0, 0, 0, g(Yes, No, false, false, "", "飛")}, + {0x2fb7, 0, 0, 0, g(Yes, No, false, false, "", "食")}, + {0x2fb8, 0, 0, 0, g(Yes, No, false, false, "", "首")}, + {0x2fb9, 0, 0, 0, g(Yes, No, false, false, "", "香")}, + {0x2fba, 0, 0, 0, g(Yes, No, false, false, "", "馬")}, + {0x2fbb, 0, 0, 0, g(Yes, No, false, false, "", "骨")}, + {0x2fbc, 0, 0, 0, g(Yes, No, false, false, "", "高")}, + {0x2fbd, 0, 0, 0, g(Yes, No, false, false, "", "髟")}, + {0x2fbe, 0, 0, 0, g(Yes, No, false, false, "", "鬥")}, + {0x2fbf, 0, 0, 0, g(Yes, No, false, false, "", "鬯")}, + {0x2fc0, 0, 0, 0, g(Yes, No, false, false, "", "鬲")}, + {0x2fc1, 0, 0, 0, g(Yes, No, false, false, "", "鬼")}, + {0x2fc2, 0, 0, 0, g(Yes, No, false, false, "", "魚")}, + {0x2fc3, 0, 0, 0, g(Yes, No, false, false, "", "鳥")}, + {0x2fc4, 0, 0, 0, g(Yes, No, false, false, "", "鹵")}, + {0x2fc5, 0, 0, 0, g(Yes, No, false, false, "", "鹿")}, + {0x2fc6, 0, 0, 0, g(Yes, No, false, false, "", "麥")}, + {0x2fc7, 0, 0, 0, g(Yes, No, false, false, "", "麻")}, + {0x2fc8, 0, 0, 0, g(Yes, No, false, false, "", "黃")}, + {0x2fc9, 0, 0, 0, g(Yes, No, false, false, "", "黍")}, + {0x2fca, 0, 0, 0, g(Yes, No, false, false, "", "黑")}, + {0x2fcb, 0, 0, 0, g(Yes, No, false, false, "", "黹")}, + {0x2fcc, 0, 0, 0, g(Yes, No, false, false, "", "黽")}, + {0x2fcd, 0, 0, 0, g(Yes, No, false, false, "", "鼎")}, + {0x2fce, 0, 0, 0, g(Yes, No, false, false, "", "鼓")}, + {0x2fcf, 0, 0, 0, g(Yes, No, false, false, "", "鼠")}, + {0x2fd0, 0, 0, 0, g(Yes, No, false, false, "", "鼻")}, + {0x2fd1, 0, 0, 0, g(Yes, No, false, false, "", "齊")}, + {0x2fd2, 0, 0, 0, g(Yes, No, false, false, "", "齒")}, + {0x2fd3, 0, 0, 0, g(Yes, No, false, false, "", "龍")}, + {0x2fd4, 0, 0, 0, g(Yes, No, false, false, "", "龜")}, + {0x2fd5, 0, 0, 0, g(Yes, No, false, false, "", "龠")}, + {0x2fd6, 0, 0, 0, f(Yes, false, "")}, + {0x3000, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x3001, 0, 0, 0, f(Yes, false, "")}, + {0x302a, 218, 1, 1, f(Yes, false, "")}, + {0x302b, 228, 1, 1, f(Yes, false, "")}, + {0x302c, 232, 1, 1, f(Yes, false, "")}, + {0x302d, 222, 1, 1, f(Yes, false, "")}, + {0x302e, 224, 1, 1, f(Yes, false, "")}, + {0x3030, 0, 0, 0, f(Yes, false, "")}, + {0x3036, 0, 0, 0, g(Yes, No, false, false, "", "〒")}, + {0x3037, 0, 0, 0, f(Yes, false, "")}, + {0x3038, 0, 0, 0, g(Yes, No, false, false, "", "十")}, + {0x3039, 0, 0, 0, g(Yes, No, false, false, "", "卄")}, + {0x303a, 0, 0, 0, g(Yes, No, false, false, "", "卅")}, + {0x303b, 0, 0, 0, f(Yes, false, "")}, + {0x3046, 0, 0, 0, f(Yes, true, "")}, + {0x3047, 0, 0, 0, f(Yes, false, "")}, + {0x304b, 0, 0, 0, f(Yes, true, "")}, + {0x304c, 0, 0, 1, f(Yes, false, "が")}, + {0x304d, 0, 0, 0, f(Yes, true, "")}, + {0x304e, 0, 0, 1, f(Yes, false, "ぎ")}, + {0x304f, 0, 0, 0, f(Yes, true, "")}, + {0x3050, 0, 0, 1, f(Yes, false, "ぐ")}, + {0x3051, 0, 0, 0, f(Yes, true, "")}, + {0x3052, 0, 0, 1, f(Yes, false, "げ")}, + {0x3053, 0, 0, 0, f(Yes, true, "")}, + {0x3054, 0, 0, 1, f(Yes, false, "ご")}, + {0x3055, 0, 0, 0, f(Yes, true, "")}, + {0x3056, 0, 0, 1, f(Yes, false, "ざ")}, + {0x3057, 0, 0, 0, f(Yes, true, "")}, + {0x3058, 0, 0, 1, f(Yes, false, "じ")}, + {0x3059, 0, 0, 0, f(Yes, true, "")}, + {0x305a, 0, 0, 1, f(Yes, false, "ず")}, + {0x305b, 0, 0, 0, f(Yes, true, "")}, + {0x305c, 0, 0, 1, f(Yes, false, "ぜ")}, + {0x305d, 0, 0, 0, f(Yes, true, "")}, + {0x305e, 0, 0, 1, f(Yes, false, "ぞ")}, + {0x305f, 0, 0, 0, f(Yes, true, "")}, + {0x3060, 0, 0, 1, f(Yes, false, "だ")}, + {0x3061, 0, 0, 0, f(Yes, true, "")}, + {0x3062, 0, 0, 1, f(Yes, false, "ぢ")}, + {0x3063, 0, 0, 0, f(Yes, false, "")}, + {0x3064, 0, 0, 0, f(Yes, true, "")}, + {0x3065, 0, 0, 1, f(Yes, false, "づ")}, + {0x3066, 0, 0, 0, f(Yes, true, "")}, + {0x3067, 0, 0, 1, f(Yes, false, "で")}, + {0x3068, 0, 0, 0, f(Yes, true, "")}, + {0x3069, 0, 0, 1, f(Yes, false, "ど")}, + {0x306a, 0, 0, 0, f(Yes, false, "")}, + {0x306f, 0, 0, 0, f(Yes, true, "")}, + {0x3070, 0, 0, 1, f(Yes, false, "ば")}, + {0x3071, 0, 0, 1, f(Yes, false, "ぱ")}, + {0x3072, 0, 0, 0, f(Yes, true, "")}, + {0x3073, 0, 0, 1, f(Yes, false, "び")}, + {0x3074, 0, 0, 1, f(Yes, false, "ぴ")}, + {0x3075, 0, 0, 0, f(Yes, true, "")}, + {0x3076, 0, 0, 1, f(Yes, false, "ぶ")}, + {0x3077, 0, 0, 1, f(Yes, false, "ぷ")}, + {0x3078, 0, 0, 0, f(Yes, true, "")}, + {0x3079, 0, 0, 1, f(Yes, false, "べ")}, + {0x307a, 0, 0, 1, f(Yes, false, "ぺ")}, + {0x307b, 0, 0, 0, f(Yes, true, "")}, + {0x307c, 0, 0, 1, f(Yes, false, "ぼ")}, + {0x307d, 0, 0, 1, f(Yes, false, "ぽ")}, + {0x307e, 0, 0, 0, f(Yes, false, "")}, + {0x3094, 0, 0, 1, f(Yes, false, "ゔ")}, + {0x3095, 0, 0, 0, f(Yes, false, "")}, + {0x3099, 8, 1, 1, f(Maybe, false, "")}, + {0x309b, 0, 0, 1, g(Yes, No, false, false, "", " ゙")}, + {0x309c, 0, 0, 1, g(Yes, No, false, false, "", " ゚")}, + {0x309d, 0, 0, 0, f(Yes, true, "")}, + {0x309e, 0, 0, 1, f(Yes, false, "ゞ")}, + {0x309f, 0, 0, 0, g(Yes, No, false, false, "", "より")}, + {0x30a0, 0, 0, 0, f(Yes, false, "")}, + {0x30a6, 0, 0, 0, f(Yes, true, "")}, + {0x30a7, 0, 0, 0, f(Yes, false, "")}, + {0x30ab, 0, 0, 0, f(Yes, true, "")}, + {0x30ac, 0, 0, 1, f(Yes, false, "ガ")}, + {0x30ad, 0, 0, 0, f(Yes, true, "")}, + {0x30ae, 0, 0, 1, f(Yes, false, "ギ")}, + {0x30af, 0, 0, 0, f(Yes, true, "")}, + {0x30b0, 0, 0, 1, f(Yes, false, "グ")}, + {0x30b1, 0, 0, 0, f(Yes, true, "")}, + {0x30b2, 0, 0, 1, f(Yes, false, "ゲ")}, + {0x30b3, 0, 0, 0, f(Yes, true, "")}, + {0x30b4, 0, 0, 1, f(Yes, false, "ゴ")}, + {0x30b5, 0, 0, 0, f(Yes, true, "")}, + {0x30b6, 0, 0, 1, f(Yes, false, "ザ")}, + {0x30b7, 0, 0, 0, f(Yes, true, "")}, + {0x30b8, 0, 0, 1, f(Yes, false, "ジ")}, + {0x30b9, 0, 0, 0, f(Yes, true, "")}, + {0x30ba, 0, 0, 1, f(Yes, false, "ズ")}, + {0x30bb, 0, 0, 0, f(Yes, true, "")}, + {0x30bc, 0, 0, 1, f(Yes, false, "ゼ")}, + {0x30bd, 0, 0, 0, f(Yes, true, "")}, + {0x30be, 0, 0, 1, f(Yes, false, "ゾ")}, + {0x30bf, 0, 0, 0, f(Yes, true, "")}, + {0x30c0, 0, 0, 1, f(Yes, false, "ダ")}, + {0x30c1, 0, 0, 0, f(Yes, true, "")}, + {0x30c2, 0, 0, 1, f(Yes, false, "ヂ")}, + {0x30c3, 0, 0, 0, f(Yes, false, "")}, + {0x30c4, 0, 0, 0, f(Yes, true, "")}, + {0x30c5, 0, 0, 1, f(Yes, false, "ヅ")}, + {0x30c6, 0, 0, 0, f(Yes, true, "")}, + {0x30c7, 0, 0, 1, f(Yes, false, "デ")}, + {0x30c8, 0, 0, 0, f(Yes, true, "")}, + {0x30c9, 0, 0, 1, f(Yes, false, "ド")}, + {0x30ca, 0, 0, 0, f(Yes, false, "")}, + {0x30cf, 0, 0, 0, f(Yes, true, "")}, + {0x30d0, 0, 0, 1, f(Yes, false, "バ")}, + {0x30d1, 0, 0, 1, f(Yes, false, "パ")}, + {0x30d2, 0, 0, 0, f(Yes, true, "")}, + {0x30d3, 0, 0, 1, f(Yes, false, "ビ")}, + {0x30d4, 0, 0, 1, f(Yes, false, "ピ")}, + {0x30d5, 0, 0, 0, f(Yes, true, "")}, + {0x30d6, 0, 0, 1, f(Yes, false, "ブ")}, + {0x30d7, 0, 0, 1, f(Yes, false, "プ")}, + {0x30d8, 0, 0, 0, f(Yes, true, "")}, + {0x30d9, 0, 0, 1, f(Yes, false, "ベ")}, + {0x30da, 0, 0, 1, f(Yes, false, "ペ")}, + {0x30db, 0, 0, 0, f(Yes, true, "")}, + {0x30dc, 0, 0, 1, f(Yes, false, "ボ")}, + {0x30dd, 0, 0, 1, f(Yes, false, "ポ")}, + {0x30de, 0, 0, 0, f(Yes, false, "")}, + {0x30ef, 0, 0, 0, f(Yes, true, "")}, + {0x30f3, 0, 0, 0, f(Yes, false, "")}, + {0x30f4, 0, 0, 1, f(Yes, false, "ヴ")}, + {0x30f5, 0, 0, 0, f(Yes, false, "")}, + {0x30f7, 0, 0, 1, f(Yes, false, "ヷ")}, + {0x30f8, 0, 0, 1, f(Yes, false, "ヸ")}, + {0x30f9, 0, 0, 1, f(Yes, false, "ヹ")}, + {0x30fa, 0, 0, 1, f(Yes, false, "ヺ")}, + {0x30fb, 0, 0, 0, f(Yes, false, "")}, + {0x30fd, 0, 0, 0, f(Yes, true, "")}, + {0x30fe, 0, 0, 1, f(Yes, false, "ヾ")}, + {0x30ff, 0, 0, 0, g(Yes, No, false, false, "", "コト")}, + {0x3100, 0, 0, 0, f(Yes, false, "")}, + {0x3131, 0, 0, 0, g(Yes, No, false, false, "", "ᄀ")}, + {0x3132, 0, 0, 0, g(Yes, No, false, false, "", "ᄁ")}, + {0x3133, 0, 1, 1, g(Yes, No, false, false, "", "ᆪ")}, + {0x3134, 0, 0, 0, g(Yes, No, false, false, "", "ᄂ")}, + {0x3135, 0, 1, 1, g(Yes, No, false, false, "", "ᆬ")}, + {0x3136, 0, 1, 1, g(Yes, No, false, false, "", "ᆭ")}, + {0x3137, 0, 0, 0, g(Yes, No, false, false, "", "ᄃ")}, + {0x3138, 0, 0, 0, g(Yes, No, false, false, "", "ᄄ")}, + {0x3139, 0, 0, 0, g(Yes, No, false, false, "", "ᄅ")}, + {0x313a, 0, 1, 1, g(Yes, No, false, false, "", "ᆰ")}, + {0x313b, 0, 1, 1, g(Yes, No, false, false, "", "ᆱ")}, + {0x313c, 0, 1, 1, g(Yes, No, false, false, "", "ᆲ")}, + {0x313d, 0, 1, 1, g(Yes, No, false, false, "", "ᆳ")}, + {0x313e, 0, 1, 1, g(Yes, No, false, false, "", "ᆴ")}, + {0x313f, 0, 1, 1, g(Yes, No, false, false, "", "ᆵ")}, + {0x3140, 0, 0, 0, g(Yes, No, false, false, "", "ᄚ")}, + {0x3141, 0, 0, 0, g(Yes, No, false, false, "", "ᄆ")}, + {0x3142, 0, 0, 0, g(Yes, No, false, false, "", "ᄇ")}, + {0x3143, 0, 0, 0, g(Yes, No, false, false, "", "ᄈ")}, + {0x3144, 0, 0, 0, g(Yes, No, false, false, "", "ᄡ")}, + {0x3145, 0, 0, 0, g(Yes, No, false, false, "", "ᄉ")}, + {0x3146, 0, 0, 0, g(Yes, No, false, false, "", "ᄊ")}, + {0x3147, 0, 0, 0, g(Yes, No, false, false, "", "ᄋ")}, + {0x3148, 0, 0, 0, g(Yes, No, false, false, "", "ᄌ")}, + {0x3149, 0, 0, 0, g(Yes, No, false, false, "", "ᄍ")}, + {0x314a, 0, 0, 0, g(Yes, No, false, false, "", "ᄎ")}, + {0x314b, 0, 0, 0, g(Yes, No, false, false, "", "ᄏ")}, + {0x314c, 0, 0, 0, g(Yes, No, false, false, "", "ᄐ")}, + {0x314d, 0, 0, 0, g(Yes, No, false, false, "", "ᄑ")}, + {0x314e, 0, 0, 0, g(Yes, No, false, false, "", "ᄒ")}, + {0x314f, 0, 1, 1, g(Yes, No, false, false, "", "ᅡ")}, + {0x3150, 0, 1, 1, g(Yes, No, false, false, "", "ᅢ")}, + {0x3151, 0, 1, 1, g(Yes, No, false, false, "", "ᅣ")}, + {0x3152, 0, 1, 1, g(Yes, No, false, false, "", "ᅤ")}, + {0x3153, 0, 1, 1, g(Yes, No, false, false, "", "ᅥ")}, + {0x3154, 0, 1, 1, g(Yes, No, false, false, "", "ᅦ")}, + {0x3155, 0, 1, 1, g(Yes, No, false, false, "", "ᅧ")}, + {0x3156, 0, 1, 1, g(Yes, No, false, false, "", "ᅨ")}, + {0x3157, 0, 1, 1, g(Yes, No, false, false, "", "ᅩ")}, + {0x3158, 0, 1, 1, g(Yes, No, false, false, "", "ᅪ")}, + {0x3159, 0, 1, 1, g(Yes, No, false, false, "", "ᅫ")}, + {0x315a, 0, 1, 1, g(Yes, No, false, false, "", "ᅬ")}, + {0x315b, 0, 1, 1, g(Yes, No, false, false, "", "ᅭ")}, + {0x315c, 0, 1, 1, g(Yes, No, false, false, "", "ᅮ")}, + {0x315d, 0, 1, 1, g(Yes, No, false, false, "", "ᅯ")}, + {0x315e, 0, 1, 1, g(Yes, No, false, false, "", "ᅰ")}, + {0x315f, 0, 1, 1, g(Yes, No, false, false, "", "ᅱ")}, + {0x3160, 0, 1, 1, g(Yes, No, false, false, "", "ᅲ")}, + {0x3161, 0, 1, 1, g(Yes, No, false, false, "", "ᅳ")}, + {0x3162, 0, 1, 1, g(Yes, No, false, false, "", "ᅴ")}, + {0x3163, 0, 1, 1, g(Yes, No, false, false, "", "ᅵ")}, + {0x3164, 0, 0, 0, g(Yes, No, false, false, "", "ᅠ")}, + {0x3165, 0, 0, 0, g(Yes, No, false, false, "", "ᄔ")}, + {0x3166, 0, 0, 0, g(Yes, No, false, false, "", "ᄕ")}, + {0x3167, 0, 0, 0, g(Yes, No, false, false, "", "ᇇ")}, + {0x3168, 0, 0, 0, g(Yes, No, false, false, "", "ᇈ")}, + {0x3169, 0, 0, 0, g(Yes, No, false, false, "", "ᇌ")}, + {0x316a, 0, 0, 0, g(Yes, No, false, false, "", "ᇎ")}, + {0x316b, 0, 0, 0, g(Yes, No, false, false, "", "ᇓ")}, + {0x316c, 0, 0, 0, g(Yes, No, false, false, "", "ᇗ")}, + {0x316d, 0, 0, 0, g(Yes, No, false, false, "", "ᇙ")}, + {0x316e, 0, 0, 0, g(Yes, No, false, false, "", "ᄜ")}, + {0x316f, 0, 0, 0, g(Yes, No, false, false, "", "ᇝ")}, + {0x3170, 0, 0, 0, g(Yes, No, false, false, "", "ᇟ")}, + {0x3171, 0, 0, 0, g(Yes, No, false, false, "", "ᄝ")}, + {0x3172, 0, 0, 0, g(Yes, No, false, false, "", "ᄞ")}, + {0x3173, 0, 0, 0, g(Yes, No, false, false, "", "ᄠ")}, + {0x3174, 0, 0, 0, g(Yes, No, false, false, "", "ᄢ")}, + {0x3175, 0, 0, 0, g(Yes, No, false, false, "", "ᄣ")}, + {0x3176, 0, 0, 0, g(Yes, No, false, false, "", "ᄧ")}, + {0x3177, 0, 0, 0, g(Yes, No, false, false, "", "ᄩ")}, + {0x3178, 0, 0, 0, g(Yes, No, false, false, "", "ᄫ")}, + {0x3179, 0, 0, 0, g(Yes, No, false, false, "", "ᄬ")}, + {0x317a, 0, 0, 0, g(Yes, No, false, false, "", "ᄭ")}, + {0x317b, 0, 0, 0, g(Yes, No, false, false, "", "ᄮ")}, + {0x317c, 0, 0, 0, g(Yes, No, false, false, "", "ᄯ")}, + {0x317d, 0, 0, 0, g(Yes, No, false, false, "", "ᄲ")}, + {0x317e, 0, 0, 0, g(Yes, No, false, false, "", "ᄶ")}, + {0x317f, 0, 0, 0, g(Yes, No, false, false, "", "ᅀ")}, + {0x3180, 0, 0, 0, g(Yes, No, false, false, "", "ᅇ")}, + {0x3181, 0, 0, 0, g(Yes, No, false, false, "", "ᅌ")}, + {0x3182, 0, 0, 0, g(Yes, No, false, false, "", "ᇱ")}, + {0x3183, 0, 0, 0, g(Yes, No, false, false, "", "ᇲ")}, + {0x3184, 0, 0, 0, g(Yes, No, false, false, "", "ᅗ")}, + {0x3185, 0, 0, 0, g(Yes, No, false, false, "", "ᅘ")}, + {0x3186, 0, 0, 0, g(Yes, No, false, false, "", "ᅙ")}, + {0x3187, 0, 0, 0, g(Yes, No, false, false, "", "ᆄ")}, + {0x3188, 0, 0, 0, g(Yes, No, false, false, "", "ᆅ")}, + {0x3189, 0, 0, 0, g(Yes, No, false, false, "", "ᆈ")}, + {0x318a, 0, 0, 0, g(Yes, No, false, false, "", "ᆑ")}, + {0x318b, 0, 0, 0, g(Yes, No, false, false, "", "ᆒ")}, + {0x318c, 0, 0, 0, g(Yes, No, false, false, "", "ᆔ")}, + {0x318d, 0, 0, 0, g(Yes, No, false, false, "", "ᆞ")}, + {0x318e, 0, 0, 0, g(Yes, No, false, false, "", "ᆡ")}, + {0x318f, 0, 0, 0, f(Yes, false, "")}, + {0x3192, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x3193, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x3194, 0, 0, 0, g(Yes, No, false, false, "", "三")}, + {0x3195, 0, 0, 0, g(Yes, No, false, false, "", "四")}, + {0x3196, 0, 0, 0, g(Yes, No, false, false, "", "上")}, + {0x3197, 0, 0, 0, g(Yes, No, false, false, "", "中")}, + {0x3198, 0, 0, 0, g(Yes, No, false, false, "", "下")}, + {0x3199, 0, 0, 0, g(Yes, No, false, false, "", "甲")}, + {0x319a, 0, 0, 0, g(Yes, No, false, false, "", "乙")}, + {0x319b, 0, 0, 0, g(Yes, No, false, false, "", "丙")}, + {0x319c, 0, 0, 0, g(Yes, No, false, false, "", "丁")}, + {0x319d, 0, 0, 0, g(Yes, No, false, false, "", "天")}, + {0x319e, 0, 0, 0, g(Yes, No, false, false, "", "地")}, + {0x319f, 0, 0, 0, g(Yes, No, false, false, "", "人")}, + {0x31a0, 0, 0, 0, f(Yes, false, "")}, + {0x3200, 0, 0, 0, g(Yes, No, false, false, "", "(ᄀ)")}, + {0x3201, 0, 0, 0, g(Yes, No, false, false, "", "(ᄂ)")}, + {0x3202, 0, 0, 0, g(Yes, No, false, false, "", "(ᄃ)")}, + {0x3203, 0, 0, 0, g(Yes, No, false, false, "", "(ᄅ)")}, + {0x3204, 0, 0, 0, g(Yes, No, false, false, "", "(ᄆ)")}, + {0x3205, 0, 0, 0, g(Yes, No, false, false, "", "(ᄇ)")}, + {0x3206, 0, 0, 0, g(Yes, No, false, false, "", "(ᄉ)")}, + {0x3207, 0, 0, 0, g(Yes, No, false, false, "", "(ᄋ)")}, + {0x3208, 0, 0, 0, g(Yes, No, false, false, "", "(ᄌ)")}, + {0x3209, 0, 0, 0, g(Yes, No, false, false, "", "(ᄎ)")}, + {0x320a, 0, 0, 0, g(Yes, No, false, false, "", "(ᄏ)")}, + {0x320b, 0, 0, 0, g(Yes, No, false, false, "", "(ᄐ)")}, + {0x320c, 0, 0, 0, g(Yes, No, false, false, "", "(ᄑ)")}, + {0x320d, 0, 0, 0, g(Yes, No, false, false, "", "(ᄒ)")}, + {0x320e, 0, 0, 0, g(Yes, No, false, false, "", "(가)")}, + {0x320f, 0, 0, 0, g(Yes, No, false, false, "", "(나)")}, + {0x3210, 0, 0, 0, g(Yes, No, false, false, "", "(다)")}, + {0x3211, 0, 0, 0, g(Yes, No, false, false, "", "(라)")}, + {0x3212, 0, 0, 0, g(Yes, No, false, false, "", "(마)")}, + {0x3213, 0, 0, 0, g(Yes, No, false, false, "", "(바)")}, + {0x3214, 0, 0, 0, g(Yes, No, false, false, "", "(사)")}, + {0x3215, 0, 0, 0, g(Yes, No, false, false, "", "(아)")}, + {0x3216, 0, 0, 0, g(Yes, No, false, false, "", "(자)")}, + {0x3217, 0, 0, 0, g(Yes, No, false, false, "", "(차)")}, + {0x3218, 0, 0, 0, g(Yes, No, false, false, "", "(카)")}, + {0x3219, 0, 0, 0, g(Yes, No, false, false, "", "(타)")}, + {0x321a, 0, 0, 0, g(Yes, No, false, false, "", "(파)")}, + {0x321b, 0, 0, 0, g(Yes, No, false, false, "", "(하)")}, + {0x321c, 0, 0, 0, g(Yes, No, false, false, "", "(주)")}, + {0x321d, 0, 0, 0, g(Yes, No, false, false, "", "(오전)")}, + {0x321e, 0, 0, 0, g(Yes, No, false, false, "", "(오후)")}, + {0x321f, 0, 0, 0, f(Yes, false, "")}, + {0x3220, 0, 0, 0, g(Yes, No, false, false, "", "(一)")}, + {0x3221, 0, 0, 0, g(Yes, No, false, false, "", "(二)")}, + {0x3222, 0, 0, 0, g(Yes, No, false, false, "", "(三)")}, + {0x3223, 0, 0, 0, g(Yes, No, false, false, "", "(四)")}, + {0x3224, 0, 0, 0, g(Yes, No, false, false, "", "(五)")}, + {0x3225, 0, 0, 0, g(Yes, No, false, false, "", "(六)")}, + {0x3226, 0, 0, 0, g(Yes, No, false, false, "", "(七)")}, + {0x3227, 0, 0, 0, g(Yes, No, false, false, "", "(八)")}, + {0x3228, 0, 0, 0, g(Yes, No, false, false, "", "(九)")}, + {0x3229, 0, 0, 0, g(Yes, No, false, false, "", "(十)")}, + {0x322a, 0, 0, 0, g(Yes, No, false, false, "", "(月)")}, + {0x322b, 0, 0, 0, g(Yes, No, false, false, "", "(火)")}, + {0x322c, 0, 0, 0, g(Yes, No, false, false, "", "(水)")}, + {0x322d, 0, 0, 0, g(Yes, No, false, false, "", "(木)")}, + {0x322e, 0, 0, 0, g(Yes, No, false, false, "", "(金)")}, + {0x322f, 0, 0, 0, g(Yes, No, false, false, "", "(土)")}, + {0x3230, 0, 0, 0, g(Yes, No, false, false, "", "(日)")}, + {0x3231, 0, 0, 0, g(Yes, No, false, false, "", "(株)")}, + {0x3232, 0, 0, 0, g(Yes, No, false, false, "", "(有)")}, + {0x3233, 0, 0, 0, g(Yes, No, false, false, "", "(社)")}, + {0x3234, 0, 0, 0, g(Yes, No, false, false, "", "(名)")}, + {0x3235, 0, 0, 0, g(Yes, No, false, false, "", "(特)")}, + {0x3236, 0, 0, 0, g(Yes, No, false, false, "", "(財)")}, + {0x3237, 0, 0, 0, g(Yes, No, false, false, "", "(祝)")}, + {0x3238, 0, 0, 0, g(Yes, No, false, false, "", "(労)")}, + {0x3239, 0, 0, 0, g(Yes, No, false, false, "", "(代)")}, + {0x323a, 0, 0, 0, g(Yes, No, false, false, "", "(呼)")}, + {0x323b, 0, 0, 0, g(Yes, No, false, false, "", "(学)")}, + {0x323c, 0, 0, 0, g(Yes, No, false, false, "", "(監)")}, + {0x323d, 0, 0, 0, g(Yes, No, false, false, "", "(企)")}, + {0x323e, 0, 0, 0, g(Yes, No, false, false, "", "(資)")}, + {0x323f, 0, 0, 0, g(Yes, No, false, false, "", "(協)")}, + {0x3240, 0, 0, 0, g(Yes, No, false, false, "", "(祭)")}, + {0x3241, 0, 0, 0, g(Yes, No, false, false, "", "(休)")}, + {0x3242, 0, 0, 0, g(Yes, No, false, false, "", "(自)")}, + {0x3243, 0, 0, 0, g(Yes, No, false, false, "", "(至)")}, + {0x3244, 0, 0, 0, g(Yes, No, false, false, "", "問")}, + {0x3245, 0, 0, 0, g(Yes, No, false, false, "", "幼")}, + {0x3246, 0, 0, 0, g(Yes, No, false, false, "", "文")}, + {0x3247, 0, 0, 0, g(Yes, No, false, false, "", "箏")}, + {0x3248, 0, 0, 0, f(Yes, false, "")}, + {0x3250, 0, 0, 0, g(Yes, No, false, false, "", "PTE")}, + {0x3251, 0, 0, 0, g(Yes, No, false, false, "", "21")}, + {0x3252, 0, 0, 0, g(Yes, No, false, false, "", "22")}, + {0x3253, 0, 0, 0, g(Yes, No, false, false, "", "23")}, + {0x3254, 0, 0, 0, g(Yes, No, false, false, "", "24")}, + {0x3255, 0, 0, 0, g(Yes, No, false, false, "", "25")}, + {0x3256, 0, 0, 0, g(Yes, No, false, false, "", "26")}, + {0x3257, 0, 0, 0, g(Yes, No, false, false, "", "27")}, + {0x3258, 0, 0, 0, g(Yes, No, false, false, "", "28")}, + {0x3259, 0, 0, 0, g(Yes, No, false, false, "", "29")}, + {0x325a, 0, 0, 0, g(Yes, No, false, false, "", "30")}, + {0x325b, 0, 0, 0, g(Yes, No, false, false, "", "31")}, + {0x325c, 0, 0, 0, g(Yes, No, false, false, "", "32")}, + {0x325d, 0, 0, 0, g(Yes, No, false, false, "", "33")}, + {0x325e, 0, 0, 0, g(Yes, No, false, false, "", "34")}, + {0x325f, 0, 0, 0, g(Yes, No, false, false, "", "35")}, + {0x3260, 0, 0, 0, g(Yes, No, false, false, "", "ᄀ")}, + {0x3261, 0, 0, 0, g(Yes, No, false, false, "", "ᄂ")}, + {0x3262, 0, 0, 0, g(Yes, No, false, false, "", "ᄃ")}, + {0x3263, 0, 0, 0, g(Yes, No, false, false, "", "ᄅ")}, + {0x3264, 0, 0, 0, g(Yes, No, false, false, "", "ᄆ")}, + {0x3265, 0, 0, 0, g(Yes, No, false, false, "", "ᄇ")}, + {0x3266, 0, 0, 0, g(Yes, No, false, false, "", "ᄉ")}, + {0x3267, 0, 0, 0, g(Yes, No, false, false, "", "ᄋ")}, + {0x3268, 0, 0, 0, g(Yes, No, false, false, "", "ᄌ")}, + {0x3269, 0, 0, 0, g(Yes, No, false, false, "", "ᄎ")}, + {0x326a, 0, 0, 0, g(Yes, No, false, false, "", "ᄏ")}, + {0x326b, 0, 0, 0, g(Yes, No, false, false, "", "ᄐ")}, + {0x326c, 0, 0, 0, g(Yes, No, false, false, "", "ᄑ")}, + {0x326d, 0, 0, 0, g(Yes, No, false, false, "", "ᄒ")}, + {0x326e, 0, 0, 1, g(Yes, No, false, false, "", "가")}, + {0x326f, 0, 0, 1, g(Yes, No, false, false, "", "나")}, + {0x3270, 0, 0, 1, g(Yes, No, false, false, "", "다")}, + {0x3271, 0, 0, 1, g(Yes, No, false, false, "", "라")}, + {0x3272, 0, 0, 1, g(Yes, No, false, false, "", "마")}, + {0x3273, 0, 0, 1, g(Yes, No, false, false, "", "바")}, + {0x3274, 0, 0, 1, g(Yes, No, false, false, "", "사")}, + {0x3275, 0, 0, 1, g(Yes, No, false, false, "", "아")}, + {0x3276, 0, 0, 1, g(Yes, No, false, false, "", "자")}, + {0x3277, 0, 0, 1, g(Yes, No, false, false, "", "차")}, + {0x3278, 0, 0, 1, g(Yes, No, false, false, "", "카")}, + {0x3279, 0, 0, 1, g(Yes, No, false, false, "", "타")}, + {0x327a, 0, 0, 1, g(Yes, No, false, false, "", "파")}, + {0x327b, 0, 0, 1, g(Yes, No, false, false, "", "하")}, + {0x327c, 0, 0, 1, g(Yes, No, false, false, "", "참고")}, + {0x327d, 0, 0, 1, g(Yes, No, false, false, "", "주의")}, + {0x327e, 0, 0, 1, g(Yes, No, false, false, "", "우")}, + {0x327f, 0, 0, 0, f(Yes, false, "")}, + {0x3280, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x3281, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x3282, 0, 0, 0, g(Yes, No, false, false, "", "三")}, + {0x3283, 0, 0, 0, g(Yes, No, false, false, "", "四")}, + {0x3284, 0, 0, 0, g(Yes, No, false, false, "", "五")}, + {0x3285, 0, 0, 0, g(Yes, No, false, false, "", "六")}, + {0x3286, 0, 0, 0, g(Yes, No, false, false, "", "七")}, + {0x3287, 0, 0, 0, g(Yes, No, false, false, "", "八")}, + {0x3288, 0, 0, 0, g(Yes, No, false, false, "", "九")}, + {0x3289, 0, 0, 0, g(Yes, No, false, false, "", "十")}, + {0x328a, 0, 0, 0, g(Yes, No, false, false, "", "月")}, + {0x328b, 0, 0, 0, g(Yes, No, false, false, "", "火")}, + {0x328c, 0, 0, 0, g(Yes, No, false, false, "", "水")}, + {0x328d, 0, 0, 0, g(Yes, No, false, false, "", "木")}, + {0x328e, 0, 0, 0, g(Yes, No, false, false, "", "金")}, + {0x328f, 0, 0, 0, g(Yes, No, false, false, "", "土")}, + {0x3290, 0, 0, 0, g(Yes, No, false, false, "", "日")}, + {0x3291, 0, 0, 0, g(Yes, No, false, false, "", "株")}, + {0x3292, 0, 0, 0, g(Yes, No, false, false, "", "有")}, + {0x3293, 0, 0, 0, g(Yes, No, false, false, "", "社")}, + {0x3294, 0, 0, 0, g(Yes, No, false, false, "", "名")}, + {0x3295, 0, 0, 0, g(Yes, No, false, false, "", "特")}, + {0x3296, 0, 0, 0, g(Yes, No, false, false, "", "財")}, + {0x3297, 0, 0, 0, g(Yes, No, false, false, "", "祝")}, + {0x3298, 0, 0, 0, g(Yes, No, false, false, "", "労")}, + {0x3299, 0, 0, 0, g(Yes, No, false, false, "", "秘")}, + {0x329a, 0, 0, 0, g(Yes, No, false, false, "", "男")}, + {0x329b, 0, 0, 0, g(Yes, No, false, false, "", "女")}, + {0x329c, 0, 0, 0, g(Yes, No, false, false, "", "適")}, + {0x329d, 0, 0, 0, g(Yes, No, false, false, "", "優")}, + {0x329e, 0, 0, 0, g(Yes, No, false, false, "", "印")}, + {0x329f, 0, 0, 0, g(Yes, No, false, false, "", "注")}, + {0x32a0, 0, 0, 0, g(Yes, No, false, false, "", "項")}, + {0x32a1, 0, 0, 0, g(Yes, No, false, false, "", "休")}, + {0x32a2, 0, 0, 0, g(Yes, No, false, false, "", "写")}, + {0x32a3, 0, 0, 0, g(Yes, No, false, false, "", "正")}, + {0x32a4, 0, 0, 0, g(Yes, No, false, false, "", "上")}, + {0x32a5, 0, 0, 0, g(Yes, No, false, false, "", "中")}, + {0x32a6, 0, 0, 0, g(Yes, No, false, false, "", "下")}, + {0x32a7, 0, 0, 0, g(Yes, No, false, false, "", "左")}, + {0x32a8, 0, 0, 0, g(Yes, No, false, false, "", "右")}, + {0x32a9, 0, 0, 0, g(Yes, No, false, false, "", "医")}, + {0x32aa, 0, 0, 0, g(Yes, No, false, false, "", "宗")}, + {0x32ab, 0, 0, 0, g(Yes, No, false, false, "", "学")}, + {0x32ac, 0, 0, 0, g(Yes, No, false, false, "", "監")}, + {0x32ad, 0, 0, 0, g(Yes, No, false, false, "", "企")}, + {0x32ae, 0, 0, 0, g(Yes, No, false, false, "", "資")}, + {0x32af, 0, 0, 0, g(Yes, No, false, false, "", "協")}, + {0x32b0, 0, 0, 0, g(Yes, No, false, false, "", "夜")}, + {0x32b1, 0, 0, 0, g(Yes, No, false, false, "", "36")}, + {0x32b2, 0, 0, 0, g(Yes, No, false, false, "", "37")}, + {0x32b3, 0, 0, 0, g(Yes, No, false, false, "", "38")}, + {0x32b4, 0, 0, 0, g(Yes, No, false, false, "", "39")}, + {0x32b5, 0, 0, 0, g(Yes, No, false, false, "", "40")}, + {0x32b6, 0, 0, 0, g(Yes, No, false, false, "", "41")}, + {0x32b7, 0, 0, 0, g(Yes, No, false, false, "", "42")}, + {0x32b8, 0, 0, 0, g(Yes, No, false, false, "", "43")}, + {0x32b9, 0, 0, 0, g(Yes, No, false, false, "", "44")}, + {0x32ba, 0, 0, 0, g(Yes, No, false, false, "", "45")}, + {0x32bb, 0, 0, 0, g(Yes, No, false, false, "", "46")}, + {0x32bc, 0, 0, 0, g(Yes, No, false, false, "", "47")}, + {0x32bd, 0, 0, 0, g(Yes, No, false, false, "", "48")}, + {0x32be, 0, 0, 0, g(Yes, No, false, false, "", "49")}, + {0x32bf, 0, 0, 0, g(Yes, No, false, false, "", "50")}, + {0x32c0, 0, 0, 0, g(Yes, No, false, false, "", "1月")}, + {0x32c1, 0, 0, 0, g(Yes, No, false, false, "", "2月")}, + {0x32c2, 0, 0, 0, g(Yes, No, false, false, "", "3月")}, + {0x32c3, 0, 0, 0, g(Yes, No, false, false, "", "4月")}, + {0x32c4, 0, 0, 0, g(Yes, No, false, false, "", "5月")}, + {0x32c5, 0, 0, 0, g(Yes, No, false, false, "", "6月")}, + {0x32c6, 0, 0, 0, g(Yes, No, false, false, "", "7月")}, + {0x32c7, 0, 0, 0, g(Yes, No, false, false, "", "8月")}, + {0x32c8, 0, 0, 0, g(Yes, No, false, false, "", "9月")}, + {0x32c9, 0, 0, 0, g(Yes, No, false, false, "", "10月")}, + {0x32ca, 0, 0, 0, g(Yes, No, false, false, "", "11月")}, + {0x32cb, 0, 0, 0, g(Yes, No, false, false, "", "12月")}, + {0x32cc, 0, 0, 0, g(Yes, No, false, false, "", "Hg")}, + {0x32cd, 0, 0, 0, g(Yes, No, false, false, "", "erg")}, + {0x32ce, 0, 0, 0, g(Yes, No, false, false, "", "eV")}, + {0x32cf, 0, 0, 0, g(Yes, No, false, false, "", "LTD")}, + {0x32d0, 0, 0, 0, g(Yes, No, false, false, "", "ア")}, + {0x32d1, 0, 0, 0, g(Yes, No, false, false, "", "イ")}, + {0x32d2, 0, 0, 0, g(Yes, No, false, false, "", "ウ")}, + {0x32d3, 0, 0, 0, g(Yes, No, false, false, "", "エ")}, + {0x32d4, 0, 0, 0, g(Yes, No, false, false, "", "オ")}, + {0x32d5, 0, 0, 0, g(Yes, No, false, false, "", "カ")}, + {0x32d6, 0, 0, 0, g(Yes, No, false, false, "", "キ")}, + {0x32d7, 0, 0, 0, g(Yes, No, false, false, "", "ク")}, + {0x32d8, 0, 0, 0, g(Yes, No, false, false, "", "ケ")}, + {0x32d9, 0, 0, 0, g(Yes, No, false, false, "", "コ")}, + {0x32da, 0, 0, 0, g(Yes, No, false, false, "", "サ")}, + {0x32db, 0, 0, 0, g(Yes, No, false, false, "", "シ")}, + {0x32dc, 0, 0, 0, g(Yes, No, false, false, "", "ス")}, + {0x32dd, 0, 0, 0, g(Yes, No, false, false, "", "セ")}, + {0x32de, 0, 0, 0, g(Yes, No, false, false, "", "ソ")}, + {0x32df, 0, 0, 0, g(Yes, No, false, false, "", "タ")}, + {0x32e0, 0, 0, 0, g(Yes, No, false, false, "", "チ")}, + {0x32e1, 0, 0, 0, g(Yes, No, false, false, "", "ツ")}, + {0x32e2, 0, 0, 0, g(Yes, No, false, false, "", "テ")}, + {0x32e3, 0, 0, 0, g(Yes, No, false, false, "", "ト")}, + {0x32e4, 0, 0, 0, g(Yes, No, false, false, "", "ナ")}, + {0x32e5, 0, 0, 0, g(Yes, No, false, false, "", "ニ")}, + {0x32e6, 0, 0, 0, g(Yes, No, false, false, "", "ヌ")}, + {0x32e7, 0, 0, 0, g(Yes, No, false, false, "", "ネ")}, + {0x32e8, 0, 0, 0, g(Yes, No, false, false, "", "ノ")}, + {0x32e9, 0, 0, 0, g(Yes, No, false, false, "", "ハ")}, + {0x32ea, 0, 0, 0, g(Yes, No, false, false, "", "ヒ")}, + {0x32eb, 0, 0, 0, g(Yes, No, false, false, "", "フ")}, + {0x32ec, 0, 0, 0, g(Yes, No, false, false, "", "ヘ")}, + {0x32ed, 0, 0, 0, g(Yes, No, false, false, "", "ホ")}, + {0x32ee, 0, 0, 0, g(Yes, No, false, false, "", "マ")}, + {0x32ef, 0, 0, 0, g(Yes, No, false, false, "", "ミ")}, + {0x32f0, 0, 0, 0, g(Yes, No, false, false, "", "ム")}, + {0x32f1, 0, 0, 0, g(Yes, No, false, false, "", "メ")}, + {0x32f2, 0, 0, 0, g(Yes, No, false, false, "", "モ")}, + {0x32f3, 0, 0, 0, g(Yes, No, false, false, "", "ヤ")}, + {0x32f4, 0, 0, 0, g(Yes, No, false, false, "", "ユ")}, + {0x32f5, 0, 0, 0, g(Yes, No, false, false, "", "ヨ")}, + {0x32f6, 0, 0, 0, g(Yes, No, false, false, "", "ラ")}, + {0x32f7, 0, 0, 0, g(Yes, No, false, false, "", "リ")}, + {0x32f8, 0, 0, 0, g(Yes, No, false, false, "", "ル")}, + {0x32f9, 0, 0, 0, g(Yes, No, false, false, "", "レ")}, + {0x32fa, 0, 0, 0, g(Yes, No, false, false, "", "ロ")}, + {0x32fb, 0, 0, 0, g(Yes, No, false, false, "", "ワ")}, + {0x32fc, 0, 0, 0, g(Yes, No, false, false, "", "ヰ")}, + {0x32fd, 0, 0, 0, g(Yes, No, false, false, "", "ヱ")}, + {0x32fe, 0, 0, 0, g(Yes, No, false, false, "", "ヲ")}, + {0x32ff, 0, 0, 0, f(Yes, false, "")}, + {0x3300, 0, 0, 0, g(Yes, No, false, false, "", "アパート")}, + {0x3301, 0, 0, 0, g(Yes, No, false, false, "", "アルファ")}, + {0x3302, 0, 0, 0, g(Yes, No, false, false, "", "アンペア")}, + {0x3303, 0, 0, 0, g(Yes, No, false, false, "", "アール")}, + {0x3304, 0, 0, 1, g(Yes, No, false, false, "", "イニング")}, + {0x3305, 0, 0, 0, g(Yes, No, false, false, "", "インチ")}, + {0x3306, 0, 0, 0, g(Yes, No, false, false, "", "ウォン")}, + {0x3307, 0, 0, 1, g(Yes, No, false, false, "", "エスクード")}, + {0x3308, 0, 0, 0, g(Yes, No, false, false, "", "エーカー")}, + {0x3309, 0, 0, 0, g(Yes, No, false, false, "", "オンス")}, + {0x330a, 0, 0, 0, g(Yes, No, false, false, "", "オーム")}, + {0x330b, 0, 0, 0, g(Yes, No, false, false, "", "カイリ")}, + {0x330c, 0, 0, 0, g(Yes, No, false, false, "", "カラット")}, + {0x330d, 0, 0, 0, g(Yes, No, false, false, "", "カロリー")}, + {0x330e, 0, 0, 0, g(Yes, No, false, false, "", "ガロン")}, + {0x330f, 0, 0, 0, g(Yes, No, false, false, "", "ガンマ")}, + {0x3310, 0, 0, 1, g(Yes, No, false, false, "", "ギガ")}, + {0x3311, 0, 0, 0, g(Yes, No, false, false, "", "ギニー")}, + {0x3312, 0, 0, 0, g(Yes, No, false, false, "", "キュリー")}, + {0x3313, 0, 0, 0, g(Yes, No, false, false, "", "ギルダー")}, + {0x3314, 0, 0, 0, g(Yes, No, false, false, "", "キロ")}, + {0x3315, 0, 0, 0, g(Yes, No, false, false, "", "キログラム")}, + {0x3316, 0, 0, 0, g(Yes, No, false, false, "", "キロメートル")}, + {0x3317, 0, 0, 0, g(Yes, No, false, false, "", "キロワット")}, + {0x3318, 0, 0, 0, g(Yes, No, false, false, "", "グラム")}, + {0x3319, 0, 0, 0, g(Yes, No, false, false, "", "グラムトン")}, + {0x331a, 0, 0, 0, g(Yes, No, false, false, "", "クルゼイロ")}, + {0x331b, 0, 0, 0, g(Yes, No, false, false, "", "クローネ")}, + {0x331c, 0, 0, 0, g(Yes, No, false, false, "", "ケース")}, + {0x331d, 0, 0, 0, g(Yes, No, false, false, "", "コルナ")}, + {0x331e, 0, 0, 1, g(Yes, No, false, false, "", "コーポ")}, + {0x331f, 0, 0, 0, g(Yes, No, false, false, "", "サイクル")}, + {0x3320, 0, 0, 0, g(Yes, No, false, false, "", "サンチーム")}, + {0x3321, 0, 0, 1, g(Yes, No, false, false, "", "シリング")}, + {0x3322, 0, 0, 0, g(Yes, No, false, false, "", "センチ")}, + {0x3323, 0, 0, 0, g(Yes, No, false, false, "", "セント")}, + {0x3324, 0, 0, 0, g(Yes, No, false, false, "", "ダース")}, + {0x3325, 0, 0, 0, g(Yes, No, false, false, "", "デシ")}, + {0x3326, 0, 0, 0, g(Yes, No, false, false, "", "ドル")}, + {0x3327, 0, 0, 0, g(Yes, No, false, false, "", "トン")}, + {0x3328, 0, 0, 0, g(Yes, No, false, false, "", "ナノ")}, + {0x3329, 0, 0, 0, g(Yes, No, false, false, "", "ノット")}, + {0x332a, 0, 0, 0, g(Yes, No, false, false, "", "ハイツ")}, + {0x332b, 0, 0, 0, g(Yes, No, false, false, "", "パーセント")}, + {0x332c, 0, 0, 0, g(Yes, No, false, false, "", "パーツ")}, + {0x332d, 0, 0, 0, g(Yes, No, false, false, "", "バーレル")}, + {0x332e, 0, 0, 0, g(Yes, No, false, false, "", "ピアストル")}, + {0x332f, 0, 0, 0, g(Yes, No, false, false, "", "ピクル")}, + {0x3330, 0, 0, 0, g(Yes, No, false, false, "", "ピコ")}, + {0x3331, 0, 0, 0, g(Yes, No, false, false, "", "ビル")}, + {0x3332, 0, 0, 1, g(Yes, No, false, false, "", "ファラッド")}, + {0x3333, 0, 0, 0, g(Yes, No, false, false, "", "フィート")}, + {0x3334, 0, 0, 0, g(Yes, No, false, false, "", "ブッシェル")}, + {0x3335, 0, 0, 0, g(Yes, No, false, false, "", "フラン")}, + {0x3336, 0, 0, 0, g(Yes, No, false, false, "", "ヘクタール")}, + {0x3337, 0, 0, 0, g(Yes, No, false, false, "", "ペソ")}, + {0x3338, 0, 0, 0, g(Yes, No, false, false, "", "ペニヒ")}, + {0x3339, 0, 0, 0, g(Yes, No, false, false, "", "ヘルツ")}, + {0x333a, 0, 0, 0, g(Yes, No, false, false, "", "ペンス")}, + {0x333b, 0, 0, 1, g(Yes, No, false, false, "", "ページ")}, + {0x333c, 0, 0, 0, g(Yes, No, false, false, "", "ベータ")}, + {0x333d, 0, 0, 0, g(Yes, No, false, false, "", "ポイント")}, + {0x333e, 0, 0, 0, g(Yes, No, false, false, "", "ボルト")}, + {0x333f, 0, 0, 0, g(Yes, No, false, false, "", "ホン")}, + {0x3340, 0, 0, 1, g(Yes, No, false, false, "", "ポンド")}, + {0x3341, 0, 0, 0, g(Yes, No, false, false, "", "ホール")}, + {0x3342, 0, 0, 0, g(Yes, No, false, false, "", "ホーン")}, + {0x3343, 0, 0, 0, g(Yes, No, false, false, "", "マイクロ")}, + {0x3344, 0, 0, 0, g(Yes, No, false, false, "", "マイル")}, + {0x3345, 0, 0, 0, g(Yes, No, false, false, "", "マッハ")}, + {0x3346, 0, 0, 0, g(Yes, No, false, false, "", "マルク")}, + {0x3347, 0, 0, 0, g(Yes, No, false, false, "", "マンション")}, + {0x3348, 0, 0, 0, g(Yes, No, false, false, "", "ミクロン")}, + {0x3349, 0, 0, 0, g(Yes, No, false, false, "", "ミリ")}, + {0x334a, 0, 0, 0, g(Yes, No, false, false, "", "ミリバール")}, + {0x334b, 0, 0, 1, g(Yes, No, false, false, "", "メガ")}, + {0x334c, 0, 0, 0, g(Yes, No, false, false, "", "メガトン")}, + {0x334d, 0, 0, 0, g(Yes, No, false, false, "", "メートル")}, + {0x334e, 0, 0, 1, g(Yes, No, false, false, "", "ヤード")}, + {0x334f, 0, 0, 0, g(Yes, No, false, false, "", "ヤール")}, + {0x3350, 0, 0, 0, g(Yes, No, false, false, "", "ユアン")}, + {0x3351, 0, 0, 0, g(Yes, No, false, false, "", "リットル")}, + {0x3352, 0, 0, 0, g(Yes, No, false, false, "", "リラ")}, + {0x3353, 0, 0, 0, g(Yes, No, false, false, "", "ルピー")}, + {0x3354, 0, 0, 0, g(Yes, No, false, false, "", "ルーブル")}, + {0x3355, 0, 0, 0, g(Yes, No, false, false, "", "レム")}, + {0x3356, 0, 0, 0, g(Yes, No, false, false, "", "レントゲン")}, + {0x3357, 0, 0, 0, g(Yes, No, false, false, "", "ワット")}, + {0x3358, 0, 0, 0, g(Yes, No, false, false, "", "0点")}, + {0x3359, 0, 0, 0, g(Yes, No, false, false, "", "1点")}, + {0x335a, 0, 0, 0, g(Yes, No, false, false, "", "2点")}, + {0x335b, 0, 0, 0, g(Yes, No, false, false, "", "3点")}, + {0x335c, 0, 0, 0, g(Yes, No, false, false, "", "4点")}, + {0x335d, 0, 0, 0, g(Yes, No, false, false, "", "5点")}, + {0x335e, 0, 0, 0, g(Yes, No, false, false, "", "6点")}, + {0x335f, 0, 0, 0, g(Yes, No, false, false, "", "7点")}, + {0x3360, 0, 0, 0, g(Yes, No, false, false, "", "8点")}, + {0x3361, 0, 0, 0, g(Yes, No, false, false, "", "9点")}, + {0x3362, 0, 0, 0, g(Yes, No, false, false, "", "10点")}, + {0x3363, 0, 0, 0, g(Yes, No, false, false, "", "11点")}, + {0x3364, 0, 0, 0, g(Yes, No, false, false, "", "12点")}, + {0x3365, 0, 0, 0, g(Yes, No, false, false, "", "13点")}, + {0x3366, 0, 0, 0, g(Yes, No, false, false, "", "14点")}, + {0x3367, 0, 0, 0, g(Yes, No, false, false, "", "15点")}, + {0x3368, 0, 0, 0, g(Yes, No, false, false, "", "16点")}, + {0x3369, 0, 0, 0, g(Yes, No, false, false, "", "17点")}, + {0x336a, 0, 0, 0, g(Yes, No, false, false, "", "18点")}, + {0x336b, 0, 0, 0, g(Yes, No, false, false, "", "19点")}, + {0x336c, 0, 0, 0, g(Yes, No, false, false, "", "20点")}, + {0x336d, 0, 0, 0, g(Yes, No, false, false, "", "21点")}, + {0x336e, 0, 0, 0, g(Yes, No, false, false, "", "22点")}, + {0x336f, 0, 0, 0, g(Yes, No, false, false, "", "23点")}, + {0x3370, 0, 0, 0, g(Yes, No, false, false, "", "24点")}, + {0x3371, 0, 0, 0, g(Yes, No, false, false, "", "hPa")}, + {0x3372, 0, 0, 0, g(Yes, No, false, false, "", "da")}, + {0x3373, 0, 0, 0, g(Yes, No, false, false, "", "AU")}, + {0x3374, 0, 0, 0, g(Yes, No, false, false, "", "bar")}, + {0x3375, 0, 0, 0, g(Yes, No, false, false, "", "oV")}, + {0x3376, 0, 0, 0, g(Yes, No, false, false, "", "pc")}, + {0x3377, 0, 0, 0, g(Yes, No, false, false, "", "dm")}, + {0x3378, 0, 0, 0, g(Yes, No, false, false, "", "dm2")}, + {0x3379, 0, 0, 0, g(Yes, No, false, false, "", "dm3")}, + {0x337a, 0, 0, 0, g(Yes, No, false, false, "", "IU")}, + {0x337b, 0, 0, 0, g(Yes, No, false, false, "", "平成")}, + {0x337c, 0, 0, 0, g(Yes, No, false, false, "", "昭和")}, + {0x337d, 0, 0, 0, g(Yes, No, false, false, "", "大正")}, + {0x337e, 0, 0, 0, g(Yes, No, false, false, "", "明治")}, + {0x337f, 0, 0, 0, g(Yes, No, false, false, "", "株式会社")}, + {0x3380, 0, 0, 0, g(Yes, No, false, false, "", "pA")}, + {0x3381, 0, 0, 0, g(Yes, No, false, false, "", "nA")}, + {0x3382, 0, 0, 0, g(Yes, No, false, false, "", "μA")}, + {0x3383, 0, 0, 0, g(Yes, No, false, false, "", "mA")}, + {0x3384, 0, 0, 0, g(Yes, No, false, false, "", "kA")}, + {0x3385, 0, 0, 0, g(Yes, No, false, false, "", "KB")}, + {0x3386, 0, 0, 0, g(Yes, No, false, false, "", "MB")}, + {0x3387, 0, 0, 0, g(Yes, No, false, false, "", "GB")}, + {0x3388, 0, 0, 0, g(Yes, No, false, false, "", "cal")}, + {0x3389, 0, 0, 0, g(Yes, No, false, false, "", "kcal")}, + {0x338a, 0, 0, 0, g(Yes, No, false, false, "", "pF")}, + {0x338b, 0, 0, 0, g(Yes, No, false, false, "", "nF")}, + {0x338c, 0, 0, 0, g(Yes, No, false, false, "", "μF")}, + {0x338d, 0, 0, 0, g(Yes, No, false, false, "", "μg")}, + {0x338e, 0, 0, 0, g(Yes, No, false, false, "", "mg")}, + {0x338f, 0, 0, 0, g(Yes, No, false, false, "", "kg")}, + {0x3390, 0, 0, 0, g(Yes, No, false, false, "", "Hz")}, + {0x3391, 0, 0, 0, g(Yes, No, false, false, "", "kHz")}, + {0x3392, 0, 0, 0, g(Yes, No, false, false, "", "MHz")}, + {0x3393, 0, 0, 0, g(Yes, No, false, false, "", "GHz")}, + {0x3394, 0, 0, 0, g(Yes, No, false, false, "", "THz")}, + {0x3395, 0, 0, 0, g(Yes, No, false, false, "", "μl")}, + {0x3396, 0, 0, 0, g(Yes, No, false, false, "", "ml")}, + {0x3397, 0, 0, 0, g(Yes, No, false, false, "", "dl")}, + {0x3398, 0, 0, 0, g(Yes, No, false, false, "", "kl")}, + {0x3399, 0, 0, 0, g(Yes, No, false, false, "", "fm")}, + {0x339a, 0, 0, 0, g(Yes, No, false, false, "", "nm")}, + {0x339b, 0, 0, 0, g(Yes, No, false, false, "", "μm")}, + {0x339c, 0, 0, 0, g(Yes, No, false, false, "", "mm")}, + {0x339d, 0, 0, 0, g(Yes, No, false, false, "", "cm")}, + {0x339e, 0, 0, 0, g(Yes, No, false, false, "", "km")}, + {0x339f, 0, 0, 0, g(Yes, No, false, false, "", "mm2")}, + {0x33a0, 0, 0, 0, g(Yes, No, false, false, "", "cm2")}, + {0x33a1, 0, 0, 0, g(Yes, No, false, false, "", "m2")}, + {0x33a2, 0, 0, 0, g(Yes, No, false, false, "", "km2")}, + {0x33a3, 0, 0, 0, g(Yes, No, false, false, "", "mm3")}, + {0x33a4, 0, 0, 0, g(Yes, No, false, false, "", "cm3")}, + {0x33a5, 0, 0, 0, g(Yes, No, false, false, "", "m3")}, + {0x33a6, 0, 0, 0, g(Yes, No, false, false, "", "km3")}, + {0x33a7, 0, 0, 0, g(Yes, No, false, false, "", "m∕s")}, + {0x33a8, 0, 0, 0, g(Yes, No, false, false, "", "m∕s2")}, + {0x33a9, 0, 0, 0, g(Yes, No, false, false, "", "Pa")}, + {0x33aa, 0, 0, 0, g(Yes, No, false, false, "", "kPa")}, + {0x33ab, 0, 0, 0, g(Yes, No, false, false, "", "MPa")}, + {0x33ac, 0, 0, 0, g(Yes, No, false, false, "", "GPa")}, + {0x33ad, 0, 0, 0, g(Yes, No, false, false, "", "rad")}, + {0x33ae, 0, 0, 0, g(Yes, No, false, false, "", "rad∕s")}, + {0x33af, 0, 0, 0, g(Yes, No, false, false, "", "rad∕s2")}, + {0x33b0, 0, 0, 0, g(Yes, No, false, false, "", "ps")}, + {0x33b1, 0, 0, 0, g(Yes, No, false, false, "", "ns")}, + {0x33b2, 0, 0, 0, g(Yes, No, false, false, "", "μs")}, + {0x33b3, 0, 0, 0, g(Yes, No, false, false, "", "ms")}, + {0x33b4, 0, 0, 0, g(Yes, No, false, false, "", "pV")}, + {0x33b5, 0, 0, 0, g(Yes, No, false, false, "", "nV")}, + {0x33b6, 0, 0, 0, g(Yes, No, false, false, "", "μV")}, + {0x33b7, 0, 0, 0, g(Yes, No, false, false, "", "mV")}, + {0x33b8, 0, 0, 0, g(Yes, No, false, false, "", "kV")}, + {0x33b9, 0, 0, 0, g(Yes, No, false, false, "", "MV")}, + {0x33ba, 0, 0, 0, g(Yes, No, false, false, "", "pW")}, + {0x33bb, 0, 0, 0, g(Yes, No, false, false, "", "nW")}, + {0x33bc, 0, 0, 0, g(Yes, No, false, false, "", "μW")}, + {0x33bd, 0, 0, 0, g(Yes, No, false, false, "", "mW")}, + {0x33be, 0, 0, 0, g(Yes, No, false, false, "", "kW")}, + {0x33bf, 0, 0, 0, g(Yes, No, false, false, "", "MW")}, + {0x33c0, 0, 0, 0, g(Yes, No, false, false, "", "kΩ")}, + {0x33c1, 0, 0, 0, g(Yes, No, false, false, "", "MΩ")}, + {0x33c2, 0, 0, 0, g(Yes, No, false, false, "", "a.m.")}, + {0x33c3, 0, 0, 0, g(Yes, No, false, false, "", "Bq")}, + {0x33c4, 0, 0, 0, g(Yes, No, false, false, "", "cc")}, + {0x33c5, 0, 0, 0, g(Yes, No, false, false, "", "cd")}, + {0x33c6, 0, 0, 0, g(Yes, No, false, false, "", "C∕kg")}, + {0x33c7, 0, 0, 0, g(Yes, No, false, false, "", "Co.")}, + {0x33c8, 0, 0, 0, g(Yes, No, false, false, "", "dB")}, + {0x33c9, 0, 0, 0, g(Yes, No, false, false, "", "Gy")}, + {0x33ca, 0, 0, 0, g(Yes, No, false, false, "", "ha")}, + {0x33cb, 0, 0, 0, g(Yes, No, false, false, "", "HP")}, + {0x33cc, 0, 0, 0, g(Yes, No, false, false, "", "in")}, + {0x33cd, 0, 0, 0, g(Yes, No, false, false, "", "KK")}, + {0x33ce, 0, 0, 0, g(Yes, No, false, false, "", "KM")}, + {0x33cf, 0, 0, 0, g(Yes, No, false, false, "", "kt")}, + {0x33d0, 0, 0, 0, g(Yes, No, false, false, "", "lm")}, + {0x33d1, 0, 0, 0, g(Yes, No, false, false, "", "ln")}, + {0x33d2, 0, 0, 0, g(Yes, No, false, false, "", "log")}, + {0x33d3, 0, 0, 0, g(Yes, No, false, false, "", "lx")}, + {0x33d4, 0, 0, 0, g(Yes, No, false, false, "", "mb")}, + {0x33d5, 0, 0, 0, g(Yes, No, false, false, "", "mil")}, + {0x33d6, 0, 0, 0, g(Yes, No, false, false, "", "mol")}, + {0x33d7, 0, 0, 0, g(Yes, No, false, false, "", "PH")}, + {0x33d8, 0, 0, 0, g(Yes, No, false, false, "", "p.m.")}, + {0x33d9, 0, 0, 0, g(Yes, No, false, false, "", "PPM")}, + {0x33da, 0, 0, 0, g(Yes, No, false, false, "", "PR")}, + {0x33db, 0, 0, 0, g(Yes, No, false, false, "", "sr")}, + {0x33dc, 0, 0, 0, g(Yes, No, false, false, "", "Sv")}, + {0x33dd, 0, 0, 0, g(Yes, No, false, false, "", "Wb")}, + {0x33de, 0, 0, 0, g(Yes, No, false, false, "", "V∕m")}, + {0x33df, 0, 0, 0, g(Yes, No, false, false, "", "A∕m")}, + {0x33e0, 0, 0, 0, g(Yes, No, false, false, "", "1日")}, + {0x33e1, 0, 0, 0, g(Yes, No, false, false, "", "2日")}, + {0x33e2, 0, 0, 0, g(Yes, No, false, false, "", "3日")}, + {0x33e3, 0, 0, 0, g(Yes, No, false, false, "", "4日")}, + {0x33e4, 0, 0, 0, g(Yes, No, false, false, "", "5日")}, + {0x33e5, 0, 0, 0, g(Yes, No, false, false, "", "6日")}, + {0x33e6, 0, 0, 0, g(Yes, No, false, false, "", "7日")}, + {0x33e7, 0, 0, 0, g(Yes, No, false, false, "", "8日")}, + {0x33e8, 0, 0, 0, g(Yes, No, false, false, "", "9日")}, + {0x33e9, 0, 0, 0, g(Yes, No, false, false, "", "10日")}, + {0x33ea, 0, 0, 0, g(Yes, No, false, false, "", "11日")}, + {0x33eb, 0, 0, 0, g(Yes, No, false, false, "", "12日")}, + {0x33ec, 0, 0, 0, g(Yes, No, false, false, "", "13日")}, + {0x33ed, 0, 0, 0, g(Yes, No, false, false, "", "14日")}, + {0x33ee, 0, 0, 0, g(Yes, No, false, false, "", "15日")}, + {0x33ef, 0, 0, 0, g(Yes, No, false, false, "", "16日")}, + {0x33f0, 0, 0, 0, g(Yes, No, false, false, "", "17日")}, + {0x33f1, 0, 0, 0, g(Yes, No, false, false, "", "18日")}, + {0x33f2, 0, 0, 0, g(Yes, No, false, false, "", "19日")}, + {0x33f3, 0, 0, 0, g(Yes, No, false, false, "", "20日")}, + {0x33f4, 0, 0, 0, g(Yes, No, false, false, "", "21日")}, + {0x33f5, 0, 0, 0, g(Yes, No, false, false, "", "22日")}, + {0x33f6, 0, 0, 0, g(Yes, No, false, false, "", "23日")}, + {0x33f7, 0, 0, 0, g(Yes, No, false, false, "", "24日")}, + {0x33f8, 0, 0, 0, g(Yes, No, false, false, "", "25日")}, + {0x33f9, 0, 0, 0, g(Yes, No, false, false, "", "26日")}, + {0x33fa, 0, 0, 0, g(Yes, No, false, false, "", "27日")}, + {0x33fb, 0, 0, 0, g(Yes, No, false, false, "", "28日")}, + {0x33fc, 0, 0, 0, g(Yes, No, false, false, "", "29日")}, + {0x33fd, 0, 0, 0, g(Yes, No, false, false, "", "30日")}, + {0x33fe, 0, 0, 0, g(Yes, No, false, false, "", "31日")}, + {0x33ff, 0, 0, 0, g(Yes, No, false, false, "", "gal")}, + {0x3400, 0, 0, 0, f(Yes, false, "")}, + {0xa66f, 230, 1, 1, f(Yes, false, "")}, + {0xa670, 0, 0, 0, f(Yes, false, "")}, + {0xa674, 230, 1, 1, f(Yes, false, "")}, + {0xa67e, 0, 0, 0, f(Yes, false, "")}, + {0xa69c, 0, 0, 0, g(Yes, No, false, false, "", "ъ")}, + {0xa69d, 0, 0, 0, g(Yes, No, false, false, "", "ь")}, + {0xa69e, 230, 1, 1, f(Yes, false, "")}, + {0xa6a0, 0, 0, 0, f(Yes, false, "")}, + {0xa6f0, 230, 1, 1, f(Yes, false, "")}, + {0xa6f2, 0, 0, 0, f(Yes, false, "")}, + {0xa770, 0, 0, 0, g(Yes, No, false, false, "", "ꝯ")}, + {0xa771, 0, 0, 0, f(Yes, false, "")}, + {0xa7f8, 0, 0, 0, g(Yes, No, false, false, "", "Ħ")}, + {0xa7f9, 0, 0, 0, g(Yes, No, false, false, "", "œ")}, + {0xa7fa, 0, 0, 0, f(Yes, false, "")}, + {0xa806, 9, 1, 1, f(Yes, false, "")}, + {0xa807, 0, 0, 0, f(Yes, false, "")}, + {0xa8c4, 9, 1, 1, f(Yes, false, "")}, + {0xa8c5, 0, 0, 0, f(Yes, false, "")}, + {0xa8e0, 230, 1, 1, f(Yes, false, "")}, + {0xa8f2, 0, 0, 0, f(Yes, false, "")}, + {0xa92b, 220, 1, 1, f(Yes, false, "")}, + {0xa92e, 0, 0, 0, f(Yes, false, "")}, + {0xa953, 9, 1, 1, f(Yes, false, "")}, + {0xa954, 0, 0, 0, f(Yes, false, "")}, + {0xa9b3, 7, 1, 1, f(Yes, false, "")}, + {0xa9b4, 0, 0, 0, f(Yes, false, "")}, + {0xa9c0, 9, 1, 1, f(Yes, false, "")}, + {0xa9c1, 0, 0, 0, f(Yes, false, "")}, + {0xaab0, 230, 1, 1, f(Yes, false, "")}, + {0xaab1, 0, 0, 0, f(Yes, false, "")}, + {0xaab2, 230, 1, 1, f(Yes, false, "")}, + {0xaab4, 220, 1, 1, f(Yes, false, "")}, + {0xaab5, 0, 0, 0, f(Yes, false, "")}, + {0xaab7, 230, 1, 1, f(Yes, false, "")}, + {0xaab9, 0, 0, 0, f(Yes, false, "")}, + {0xaabe, 230, 1, 1, f(Yes, false, "")}, + {0xaac0, 0, 0, 0, f(Yes, false, "")}, + {0xaac1, 230, 1, 1, f(Yes, false, "")}, + {0xaac2, 0, 0, 0, f(Yes, false, "")}, + {0xaaf6, 9, 1, 1, f(Yes, false, "")}, + {0xaaf7, 0, 0, 0, f(Yes, false, "")}, + {0xab5c, 0, 0, 0, g(Yes, No, false, false, "", "ꜧ")}, + {0xab5d, 0, 0, 0, g(Yes, No, false, false, "", "ꬷ")}, + {0xab5e, 0, 0, 0, g(Yes, No, false, false, "", "ɫ")}, + {0xab5f, 0, 0, 0, g(Yes, No, false, false, "", "ꭒ")}, + {0xab60, 0, 0, 0, f(Yes, false, "")}, + {0xabed, 9, 1, 1, f(Yes, false, "")}, + {0xabee, 0, 0, 0, f(Yes, false, "")}, + {0xac00, 0, 0, 1, f(Yes, true, "")}, + {0xac01, 0, 0, 2, f(Yes, false, "")}, + {0xac1c, 0, 0, 1, f(Yes, true, "")}, + {0xac1d, 0, 0, 2, f(Yes, false, "")}, + {0xac38, 0, 0, 1, f(Yes, true, "")}, + {0xac39, 0, 0, 2, f(Yes, false, "")}, + {0xac54, 0, 0, 1, f(Yes, true, "")}, + {0xac55, 0, 0, 2, f(Yes, false, "")}, + {0xac70, 0, 0, 1, f(Yes, true, "")}, + {0xac71, 0, 0, 2, f(Yes, false, "")}, + {0xac8c, 0, 0, 1, f(Yes, true, "")}, + {0xac8d, 0, 0, 2, f(Yes, false, "")}, + {0xaca8, 0, 0, 1, f(Yes, true, "")}, + {0xaca9, 0, 0, 2, f(Yes, false, "")}, + {0xacc4, 0, 0, 1, f(Yes, true, "")}, + {0xacc5, 0, 0, 2, f(Yes, false, "")}, + {0xace0, 0, 0, 1, f(Yes, true, "")}, + {0xace1, 0, 0, 2, f(Yes, false, "")}, + {0xacfc, 0, 0, 1, f(Yes, true, "")}, + {0xacfd, 0, 0, 2, f(Yes, false, "")}, + {0xad18, 0, 0, 1, f(Yes, true, "")}, + {0xad19, 0, 0, 2, f(Yes, false, "")}, + {0xad34, 0, 0, 1, f(Yes, true, "")}, + {0xad35, 0, 0, 2, f(Yes, false, "")}, + {0xad50, 0, 0, 1, f(Yes, true, "")}, + {0xad51, 0, 0, 2, f(Yes, false, "")}, + {0xad6c, 0, 0, 1, f(Yes, true, "")}, + {0xad6d, 0, 0, 2, f(Yes, false, "")}, + {0xad88, 0, 0, 1, f(Yes, true, "")}, + {0xad89, 0, 0, 2, f(Yes, false, "")}, + {0xada4, 0, 0, 1, f(Yes, true, "")}, + {0xada5, 0, 0, 2, f(Yes, false, "")}, + {0xadc0, 0, 0, 1, f(Yes, true, "")}, + {0xadc1, 0, 0, 2, f(Yes, false, "")}, + {0xaddc, 0, 0, 1, f(Yes, true, "")}, + {0xaddd, 0, 0, 2, f(Yes, false, "")}, + {0xadf8, 0, 0, 1, f(Yes, true, "")}, + {0xadf9, 0, 0, 2, f(Yes, false, "")}, + {0xae14, 0, 0, 1, f(Yes, true, "")}, + {0xae15, 0, 0, 2, f(Yes, false, "")}, + {0xae30, 0, 0, 1, f(Yes, true, "")}, + {0xae31, 0, 0, 2, f(Yes, false, "")}, + {0xae4c, 0, 0, 1, f(Yes, true, "")}, + {0xae4d, 0, 0, 2, f(Yes, false, "")}, + {0xae68, 0, 0, 1, f(Yes, true, "")}, + {0xae69, 0, 0, 2, f(Yes, false, "")}, + {0xae84, 0, 0, 1, f(Yes, true, "")}, + {0xae85, 0, 0, 2, f(Yes, false, "")}, + {0xaea0, 0, 0, 1, f(Yes, true, "")}, + {0xaea1, 0, 0, 2, f(Yes, false, "")}, + {0xaebc, 0, 0, 1, f(Yes, true, "")}, + {0xaebd, 0, 0, 2, f(Yes, false, "")}, + {0xaed8, 0, 0, 1, f(Yes, true, "")}, + {0xaed9, 0, 0, 2, f(Yes, false, "")}, + {0xaef4, 0, 0, 1, f(Yes, true, "")}, + {0xaef5, 0, 0, 2, f(Yes, false, "")}, + {0xaf10, 0, 0, 1, f(Yes, true, "")}, + {0xaf11, 0, 0, 2, f(Yes, false, "")}, + {0xaf2c, 0, 0, 1, f(Yes, true, "")}, + {0xaf2d, 0, 0, 2, f(Yes, false, "")}, + {0xaf48, 0, 0, 1, f(Yes, true, "")}, + {0xaf49, 0, 0, 2, f(Yes, false, "")}, + {0xaf64, 0, 0, 1, f(Yes, true, "")}, + {0xaf65, 0, 0, 2, f(Yes, false, "")}, + {0xaf80, 0, 0, 1, f(Yes, true, "")}, + {0xaf81, 0, 0, 2, f(Yes, false, "")}, + {0xaf9c, 0, 0, 1, f(Yes, true, "")}, + {0xaf9d, 0, 0, 2, f(Yes, false, "")}, + {0xafb8, 0, 0, 1, f(Yes, true, "")}, + {0xafb9, 0, 0, 2, f(Yes, false, "")}, + {0xafd4, 0, 0, 1, f(Yes, true, "")}, + {0xafd5, 0, 0, 2, f(Yes, false, "")}, + {0xaff0, 0, 0, 1, f(Yes, true, "")}, + {0xaff1, 0, 0, 2, f(Yes, false, "")}, + {0xb00c, 0, 0, 1, f(Yes, true, "")}, + {0xb00d, 0, 0, 2, f(Yes, false, "")}, + {0xb028, 0, 0, 1, f(Yes, true, "")}, + {0xb029, 0, 0, 2, f(Yes, false, "")}, + {0xb044, 0, 0, 1, f(Yes, true, "")}, + {0xb045, 0, 0, 2, f(Yes, false, "")}, + {0xb060, 0, 0, 1, f(Yes, true, "")}, + {0xb061, 0, 0, 2, f(Yes, false, "")}, + {0xb07c, 0, 0, 1, f(Yes, true, "")}, + {0xb07d, 0, 0, 2, f(Yes, false, "")}, + {0xb098, 0, 0, 1, f(Yes, true, "")}, + {0xb099, 0, 0, 2, f(Yes, false, "")}, + {0xb0b4, 0, 0, 1, f(Yes, true, "")}, + {0xb0b5, 0, 0, 2, f(Yes, false, "")}, + {0xb0d0, 0, 0, 1, f(Yes, true, "")}, + {0xb0d1, 0, 0, 2, f(Yes, false, "")}, + {0xb0ec, 0, 0, 1, f(Yes, true, "")}, + {0xb0ed, 0, 0, 2, f(Yes, false, "")}, + {0xb108, 0, 0, 1, f(Yes, true, "")}, + {0xb109, 0, 0, 2, f(Yes, false, "")}, + {0xb124, 0, 0, 1, f(Yes, true, "")}, + {0xb125, 0, 0, 2, f(Yes, false, "")}, + {0xb140, 0, 0, 1, f(Yes, true, "")}, + {0xb141, 0, 0, 2, f(Yes, false, "")}, + {0xb15c, 0, 0, 1, f(Yes, true, "")}, + {0xb15d, 0, 0, 2, f(Yes, false, "")}, + {0xb178, 0, 0, 1, f(Yes, true, "")}, + {0xb179, 0, 0, 2, f(Yes, false, "")}, + {0xb194, 0, 0, 1, f(Yes, true, "")}, + {0xb195, 0, 0, 2, f(Yes, false, "")}, + {0xb1b0, 0, 0, 1, f(Yes, true, "")}, + {0xb1b1, 0, 0, 2, f(Yes, false, "")}, + {0xb1cc, 0, 0, 1, f(Yes, true, "")}, + {0xb1cd, 0, 0, 2, f(Yes, false, "")}, + {0xb1e8, 0, 0, 1, f(Yes, true, "")}, + {0xb1e9, 0, 0, 2, f(Yes, false, "")}, + {0xb204, 0, 0, 1, f(Yes, true, "")}, + {0xb205, 0, 0, 2, f(Yes, false, "")}, + {0xb220, 0, 0, 1, f(Yes, true, "")}, + {0xb221, 0, 0, 2, f(Yes, false, "")}, + {0xb23c, 0, 0, 1, f(Yes, true, "")}, + {0xb23d, 0, 0, 2, f(Yes, false, "")}, + {0xb258, 0, 0, 1, f(Yes, true, "")}, + {0xb259, 0, 0, 2, f(Yes, false, "")}, + {0xb274, 0, 0, 1, f(Yes, true, "")}, + {0xb275, 0, 0, 2, f(Yes, false, "")}, + {0xb290, 0, 0, 1, f(Yes, true, "")}, + {0xb291, 0, 0, 2, f(Yes, false, "")}, + {0xb2ac, 0, 0, 1, f(Yes, true, "")}, + {0xb2ad, 0, 0, 2, f(Yes, false, "")}, + {0xb2c8, 0, 0, 1, f(Yes, true, "")}, + {0xb2c9, 0, 0, 2, f(Yes, false, "")}, + {0xb2e4, 0, 0, 1, f(Yes, true, "")}, + {0xb2e5, 0, 0, 2, f(Yes, false, "")}, + {0xb300, 0, 0, 1, f(Yes, true, "")}, + {0xb301, 0, 0, 2, f(Yes, false, "")}, + {0xb31c, 0, 0, 1, f(Yes, true, "")}, + {0xb31d, 0, 0, 2, f(Yes, false, "")}, + {0xb338, 0, 0, 1, f(Yes, true, "")}, + {0xb339, 0, 0, 2, f(Yes, false, "")}, + {0xb354, 0, 0, 1, f(Yes, true, "")}, + {0xb355, 0, 0, 2, f(Yes, false, "")}, + {0xb370, 0, 0, 1, f(Yes, true, "")}, + {0xb371, 0, 0, 2, f(Yes, false, "")}, + {0xb38c, 0, 0, 1, f(Yes, true, "")}, + {0xb38d, 0, 0, 2, f(Yes, false, "")}, + {0xb3a8, 0, 0, 1, f(Yes, true, "")}, + {0xb3a9, 0, 0, 2, f(Yes, false, "")}, + {0xb3c4, 0, 0, 1, f(Yes, true, "")}, + {0xb3c5, 0, 0, 2, f(Yes, false, "")}, + {0xb3e0, 0, 0, 1, f(Yes, true, "")}, + {0xb3e1, 0, 0, 2, f(Yes, false, "")}, + {0xb3fc, 0, 0, 1, f(Yes, true, "")}, + {0xb3fd, 0, 0, 2, f(Yes, false, "")}, + {0xb418, 0, 0, 1, f(Yes, true, "")}, + {0xb419, 0, 0, 2, f(Yes, false, "")}, + {0xb434, 0, 0, 1, f(Yes, true, "")}, + {0xb435, 0, 0, 2, f(Yes, false, "")}, + {0xb450, 0, 0, 1, f(Yes, true, "")}, + {0xb451, 0, 0, 2, f(Yes, false, "")}, + {0xb46c, 0, 0, 1, f(Yes, true, "")}, + {0xb46d, 0, 0, 2, f(Yes, false, "")}, + {0xb488, 0, 0, 1, f(Yes, true, "")}, + {0xb489, 0, 0, 2, f(Yes, false, "")}, + {0xb4a4, 0, 0, 1, f(Yes, true, "")}, + {0xb4a5, 0, 0, 2, f(Yes, false, "")}, + {0xb4c0, 0, 0, 1, f(Yes, true, "")}, + {0xb4c1, 0, 0, 2, f(Yes, false, "")}, + {0xb4dc, 0, 0, 1, f(Yes, true, "")}, + {0xb4dd, 0, 0, 2, f(Yes, false, "")}, + {0xb4f8, 0, 0, 1, f(Yes, true, "")}, + {0xb4f9, 0, 0, 2, f(Yes, false, "")}, + {0xb514, 0, 0, 1, f(Yes, true, "")}, + {0xb515, 0, 0, 2, f(Yes, false, "")}, + {0xb530, 0, 0, 1, f(Yes, true, "")}, + {0xb531, 0, 0, 2, f(Yes, false, "")}, + {0xb54c, 0, 0, 1, f(Yes, true, "")}, + {0xb54d, 0, 0, 2, f(Yes, false, "")}, + {0xb568, 0, 0, 1, f(Yes, true, "")}, + {0xb569, 0, 0, 2, f(Yes, false, "")}, + {0xb584, 0, 0, 1, f(Yes, true, "")}, + {0xb585, 0, 0, 2, f(Yes, false, "")}, + {0xb5a0, 0, 0, 1, f(Yes, true, "")}, + {0xb5a1, 0, 0, 2, f(Yes, false, "")}, + {0xb5bc, 0, 0, 1, f(Yes, true, "")}, + {0xb5bd, 0, 0, 2, f(Yes, false, "")}, + {0xb5d8, 0, 0, 1, f(Yes, true, "")}, + {0xb5d9, 0, 0, 2, f(Yes, false, "")}, + {0xb5f4, 0, 0, 1, f(Yes, true, "")}, + {0xb5f5, 0, 0, 2, f(Yes, false, "")}, + {0xb610, 0, 0, 1, f(Yes, true, "")}, + {0xb611, 0, 0, 2, f(Yes, false, "")}, + {0xb62c, 0, 0, 1, f(Yes, true, "")}, + {0xb62d, 0, 0, 2, f(Yes, false, "")}, + {0xb648, 0, 0, 1, f(Yes, true, "")}, + {0xb649, 0, 0, 2, f(Yes, false, "")}, + {0xb664, 0, 0, 1, f(Yes, true, "")}, + {0xb665, 0, 0, 2, f(Yes, false, "")}, + {0xb680, 0, 0, 1, f(Yes, true, "")}, + {0xb681, 0, 0, 2, f(Yes, false, "")}, + {0xb69c, 0, 0, 1, f(Yes, true, "")}, + {0xb69d, 0, 0, 2, f(Yes, false, "")}, + {0xb6b8, 0, 0, 1, f(Yes, true, "")}, + {0xb6b9, 0, 0, 2, f(Yes, false, "")}, + {0xb6d4, 0, 0, 1, f(Yes, true, "")}, + {0xb6d5, 0, 0, 2, f(Yes, false, "")}, + {0xb6f0, 0, 0, 1, f(Yes, true, "")}, + {0xb6f1, 0, 0, 2, f(Yes, false, "")}, + {0xb70c, 0, 0, 1, f(Yes, true, "")}, + {0xb70d, 0, 0, 2, f(Yes, false, "")}, + {0xb728, 0, 0, 1, f(Yes, true, "")}, + {0xb729, 0, 0, 2, f(Yes, false, "")}, + {0xb744, 0, 0, 1, f(Yes, true, "")}, + {0xb745, 0, 0, 2, f(Yes, false, "")}, + {0xb760, 0, 0, 1, f(Yes, true, "")}, + {0xb761, 0, 0, 2, f(Yes, false, "")}, + {0xb77c, 0, 0, 1, f(Yes, true, "")}, + {0xb77d, 0, 0, 2, f(Yes, false, "")}, + {0xb798, 0, 0, 1, f(Yes, true, "")}, + {0xb799, 0, 0, 2, f(Yes, false, "")}, + {0xb7b4, 0, 0, 1, f(Yes, true, "")}, + {0xb7b5, 0, 0, 2, f(Yes, false, "")}, + {0xb7d0, 0, 0, 1, f(Yes, true, "")}, + {0xb7d1, 0, 0, 2, f(Yes, false, "")}, + {0xb7ec, 0, 0, 1, f(Yes, true, "")}, + {0xb7ed, 0, 0, 2, f(Yes, false, "")}, + {0xb808, 0, 0, 1, f(Yes, true, "")}, + {0xb809, 0, 0, 2, f(Yes, false, "")}, + {0xb824, 0, 0, 1, f(Yes, true, "")}, + {0xb825, 0, 0, 2, f(Yes, false, "")}, + {0xb840, 0, 0, 1, f(Yes, true, "")}, + {0xb841, 0, 0, 2, f(Yes, false, "")}, + {0xb85c, 0, 0, 1, f(Yes, true, "")}, + {0xb85d, 0, 0, 2, f(Yes, false, "")}, + {0xb878, 0, 0, 1, f(Yes, true, "")}, + {0xb879, 0, 0, 2, f(Yes, false, "")}, + {0xb894, 0, 0, 1, f(Yes, true, "")}, + {0xb895, 0, 0, 2, f(Yes, false, "")}, + {0xb8b0, 0, 0, 1, f(Yes, true, "")}, + {0xb8b1, 0, 0, 2, f(Yes, false, "")}, + {0xb8cc, 0, 0, 1, f(Yes, true, "")}, + {0xb8cd, 0, 0, 2, f(Yes, false, "")}, + {0xb8e8, 0, 0, 1, f(Yes, true, "")}, + {0xb8e9, 0, 0, 2, f(Yes, false, "")}, + {0xb904, 0, 0, 1, f(Yes, true, "")}, + {0xb905, 0, 0, 2, f(Yes, false, "")}, + {0xb920, 0, 0, 1, f(Yes, true, "")}, + {0xb921, 0, 0, 2, f(Yes, false, "")}, + {0xb93c, 0, 0, 1, f(Yes, true, "")}, + {0xb93d, 0, 0, 2, f(Yes, false, "")}, + {0xb958, 0, 0, 1, f(Yes, true, "")}, + {0xb959, 0, 0, 2, f(Yes, false, "")}, + {0xb974, 0, 0, 1, f(Yes, true, "")}, + {0xb975, 0, 0, 2, f(Yes, false, "")}, + {0xb990, 0, 0, 1, f(Yes, true, "")}, + {0xb991, 0, 0, 2, f(Yes, false, "")}, + {0xb9ac, 0, 0, 1, f(Yes, true, "")}, + {0xb9ad, 0, 0, 2, f(Yes, false, "")}, + {0xb9c8, 0, 0, 1, f(Yes, true, "")}, + {0xb9c9, 0, 0, 2, f(Yes, false, "")}, + {0xb9e4, 0, 0, 1, f(Yes, true, "")}, + {0xb9e5, 0, 0, 2, f(Yes, false, "")}, + {0xba00, 0, 0, 1, f(Yes, true, "")}, + {0xba01, 0, 0, 2, f(Yes, false, "")}, + {0xba1c, 0, 0, 1, f(Yes, true, "")}, + {0xba1d, 0, 0, 2, f(Yes, false, "")}, + {0xba38, 0, 0, 1, f(Yes, true, "")}, + {0xba39, 0, 0, 2, f(Yes, false, "")}, + {0xba54, 0, 0, 1, f(Yes, true, "")}, + {0xba55, 0, 0, 2, f(Yes, false, "")}, + {0xba70, 0, 0, 1, f(Yes, true, "")}, + {0xba71, 0, 0, 2, f(Yes, false, "")}, + {0xba8c, 0, 0, 1, f(Yes, true, "")}, + {0xba8d, 0, 0, 2, f(Yes, false, "")}, + {0xbaa8, 0, 0, 1, f(Yes, true, "")}, + {0xbaa9, 0, 0, 2, f(Yes, false, "")}, + {0xbac4, 0, 0, 1, f(Yes, true, "")}, + {0xbac5, 0, 0, 2, f(Yes, false, "")}, + {0xbae0, 0, 0, 1, f(Yes, true, "")}, + {0xbae1, 0, 0, 2, f(Yes, false, "")}, + {0xbafc, 0, 0, 1, f(Yes, true, "")}, + {0xbafd, 0, 0, 2, f(Yes, false, "")}, + {0xbb18, 0, 0, 1, f(Yes, true, "")}, + {0xbb19, 0, 0, 2, f(Yes, false, "")}, + {0xbb34, 0, 0, 1, f(Yes, true, "")}, + {0xbb35, 0, 0, 2, f(Yes, false, "")}, + {0xbb50, 0, 0, 1, f(Yes, true, "")}, + {0xbb51, 0, 0, 2, f(Yes, false, "")}, + {0xbb6c, 0, 0, 1, f(Yes, true, "")}, + {0xbb6d, 0, 0, 2, f(Yes, false, "")}, + {0xbb88, 0, 0, 1, f(Yes, true, "")}, + {0xbb89, 0, 0, 2, f(Yes, false, "")}, + {0xbba4, 0, 0, 1, f(Yes, true, "")}, + {0xbba5, 0, 0, 2, f(Yes, false, "")}, + {0xbbc0, 0, 0, 1, f(Yes, true, "")}, + {0xbbc1, 0, 0, 2, f(Yes, false, "")}, + {0xbbdc, 0, 0, 1, f(Yes, true, "")}, + {0xbbdd, 0, 0, 2, f(Yes, false, "")}, + {0xbbf8, 0, 0, 1, f(Yes, true, "")}, + {0xbbf9, 0, 0, 2, f(Yes, false, "")}, + {0xbc14, 0, 0, 1, f(Yes, true, "")}, + {0xbc15, 0, 0, 2, f(Yes, false, "")}, + {0xbc30, 0, 0, 1, f(Yes, true, "")}, + {0xbc31, 0, 0, 2, f(Yes, false, "")}, + {0xbc4c, 0, 0, 1, f(Yes, true, "")}, + {0xbc4d, 0, 0, 2, f(Yes, false, "")}, + {0xbc68, 0, 0, 1, f(Yes, true, "")}, + {0xbc69, 0, 0, 2, f(Yes, false, "")}, + {0xbc84, 0, 0, 1, f(Yes, true, "")}, + {0xbc85, 0, 0, 2, f(Yes, false, "")}, + {0xbca0, 0, 0, 1, f(Yes, true, "")}, + {0xbca1, 0, 0, 2, f(Yes, false, "")}, + {0xbcbc, 0, 0, 1, f(Yes, true, "")}, + {0xbcbd, 0, 0, 2, f(Yes, false, "")}, + {0xbcd8, 0, 0, 1, f(Yes, true, "")}, + {0xbcd9, 0, 0, 2, f(Yes, false, "")}, + {0xbcf4, 0, 0, 1, f(Yes, true, "")}, + {0xbcf5, 0, 0, 2, f(Yes, false, "")}, + {0xbd10, 0, 0, 1, f(Yes, true, "")}, + {0xbd11, 0, 0, 2, f(Yes, false, "")}, + {0xbd2c, 0, 0, 1, f(Yes, true, "")}, + {0xbd2d, 0, 0, 2, f(Yes, false, "")}, + {0xbd48, 0, 0, 1, f(Yes, true, "")}, + {0xbd49, 0, 0, 2, f(Yes, false, "")}, + {0xbd64, 0, 0, 1, f(Yes, true, "")}, + {0xbd65, 0, 0, 2, f(Yes, false, "")}, + {0xbd80, 0, 0, 1, f(Yes, true, "")}, + {0xbd81, 0, 0, 2, f(Yes, false, "")}, + {0xbd9c, 0, 0, 1, f(Yes, true, "")}, + {0xbd9d, 0, 0, 2, f(Yes, false, "")}, + {0xbdb8, 0, 0, 1, f(Yes, true, "")}, + {0xbdb9, 0, 0, 2, f(Yes, false, "")}, + {0xbdd4, 0, 0, 1, f(Yes, true, "")}, + {0xbdd5, 0, 0, 2, f(Yes, false, "")}, + {0xbdf0, 0, 0, 1, f(Yes, true, "")}, + {0xbdf1, 0, 0, 2, f(Yes, false, "")}, + {0xbe0c, 0, 0, 1, f(Yes, true, "")}, + {0xbe0d, 0, 0, 2, f(Yes, false, "")}, + {0xbe28, 0, 0, 1, f(Yes, true, "")}, + {0xbe29, 0, 0, 2, f(Yes, false, "")}, + {0xbe44, 0, 0, 1, f(Yes, true, "")}, + {0xbe45, 0, 0, 2, f(Yes, false, "")}, + {0xbe60, 0, 0, 1, f(Yes, true, "")}, + {0xbe61, 0, 0, 2, f(Yes, false, "")}, + {0xbe7c, 0, 0, 1, f(Yes, true, "")}, + {0xbe7d, 0, 0, 2, f(Yes, false, "")}, + {0xbe98, 0, 0, 1, f(Yes, true, "")}, + {0xbe99, 0, 0, 2, f(Yes, false, "")}, + {0xbeb4, 0, 0, 1, f(Yes, true, "")}, + {0xbeb5, 0, 0, 2, f(Yes, false, "")}, + {0xbed0, 0, 0, 1, f(Yes, true, "")}, + {0xbed1, 0, 0, 2, f(Yes, false, "")}, + {0xbeec, 0, 0, 1, f(Yes, true, "")}, + {0xbeed, 0, 0, 2, f(Yes, false, "")}, + {0xbf08, 0, 0, 1, f(Yes, true, "")}, + {0xbf09, 0, 0, 2, f(Yes, false, "")}, + {0xbf24, 0, 0, 1, f(Yes, true, "")}, + {0xbf25, 0, 0, 2, f(Yes, false, "")}, + {0xbf40, 0, 0, 1, f(Yes, true, "")}, + {0xbf41, 0, 0, 2, f(Yes, false, "")}, + {0xbf5c, 0, 0, 1, f(Yes, true, "")}, + {0xbf5d, 0, 0, 2, f(Yes, false, "")}, + {0xbf78, 0, 0, 1, f(Yes, true, "")}, + {0xbf79, 0, 0, 2, f(Yes, false, "")}, + {0xbf94, 0, 0, 1, f(Yes, true, "")}, + {0xbf95, 0, 0, 2, f(Yes, false, "")}, + {0xbfb0, 0, 0, 1, f(Yes, true, "")}, + {0xbfb1, 0, 0, 2, f(Yes, false, "")}, + {0xbfcc, 0, 0, 1, f(Yes, true, "")}, + {0xbfcd, 0, 0, 2, f(Yes, false, "")}, + {0xbfe8, 0, 0, 1, f(Yes, true, "")}, + {0xbfe9, 0, 0, 2, f(Yes, false, "")}, + {0xc004, 0, 0, 1, f(Yes, true, "")}, + {0xc005, 0, 0, 2, f(Yes, false, "")}, + {0xc020, 0, 0, 1, f(Yes, true, "")}, + {0xc021, 0, 0, 2, f(Yes, false, "")}, + {0xc03c, 0, 0, 1, f(Yes, true, "")}, + {0xc03d, 0, 0, 2, f(Yes, false, "")}, + {0xc058, 0, 0, 1, f(Yes, true, "")}, + {0xc059, 0, 0, 2, f(Yes, false, "")}, + {0xc074, 0, 0, 1, f(Yes, true, "")}, + {0xc075, 0, 0, 2, f(Yes, false, "")}, + {0xc090, 0, 0, 1, f(Yes, true, "")}, + {0xc091, 0, 0, 2, f(Yes, false, "")}, + {0xc0ac, 0, 0, 1, f(Yes, true, "")}, + {0xc0ad, 0, 0, 2, f(Yes, false, "")}, + {0xc0c8, 0, 0, 1, f(Yes, true, "")}, + {0xc0c9, 0, 0, 2, f(Yes, false, "")}, + {0xc0e4, 0, 0, 1, f(Yes, true, "")}, + {0xc0e5, 0, 0, 2, f(Yes, false, "")}, + {0xc100, 0, 0, 1, f(Yes, true, "")}, + {0xc101, 0, 0, 2, f(Yes, false, "")}, + {0xc11c, 0, 0, 1, f(Yes, true, "")}, + {0xc11d, 0, 0, 2, f(Yes, false, "")}, + {0xc138, 0, 0, 1, f(Yes, true, "")}, + {0xc139, 0, 0, 2, f(Yes, false, "")}, + {0xc154, 0, 0, 1, f(Yes, true, "")}, + {0xc155, 0, 0, 2, f(Yes, false, "")}, + {0xc170, 0, 0, 1, f(Yes, true, "")}, + {0xc171, 0, 0, 2, f(Yes, false, "")}, + {0xc18c, 0, 0, 1, f(Yes, true, "")}, + {0xc18d, 0, 0, 2, f(Yes, false, "")}, + {0xc1a8, 0, 0, 1, f(Yes, true, "")}, + {0xc1a9, 0, 0, 2, f(Yes, false, "")}, + {0xc1c4, 0, 0, 1, f(Yes, true, "")}, + {0xc1c5, 0, 0, 2, f(Yes, false, "")}, + {0xc1e0, 0, 0, 1, f(Yes, true, "")}, + {0xc1e1, 0, 0, 2, f(Yes, false, "")}, + {0xc1fc, 0, 0, 1, f(Yes, true, "")}, + {0xc1fd, 0, 0, 2, f(Yes, false, "")}, + {0xc218, 0, 0, 1, f(Yes, true, "")}, + {0xc219, 0, 0, 2, f(Yes, false, "")}, + {0xc234, 0, 0, 1, f(Yes, true, "")}, + {0xc235, 0, 0, 2, f(Yes, false, "")}, + {0xc250, 0, 0, 1, f(Yes, true, "")}, + {0xc251, 0, 0, 2, f(Yes, false, "")}, + {0xc26c, 0, 0, 1, f(Yes, true, "")}, + {0xc26d, 0, 0, 2, f(Yes, false, "")}, + {0xc288, 0, 0, 1, f(Yes, true, "")}, + {0xc289, 0, 0, 2, f(Yes, false, "")}, + {0xc2a4, 0, 0, 1, f(Yes, true, "")}, + {0xc2a5, 0, 0, 2, f(Yes, false, "")}, + {0xc2c0, 0, 0, 1, f(Yes, true, "")}, + {0xc2c1, 0, 0, 2, f(Yes, false, "")}, + {0xc2dc, 0, 0, 1, f(Yes, true, "")}, + {0xc2dd, 0, 0, 2, f(Yes, false, "")}, + {0xc2f8, 0, 0, 1, f(Yes, true, "")}, + {0xc2f9, 0, 0, 2, f(Yes, false, "")}, + {0xc314, 0, 0, 1, f(Yes, true, "")}, + {0xc315, 0, 0, 2, f(Yes, false, "")}, + {0xc330, 0, 0, 1, f(Yes, true, "")}, + {0xc331, 0, 0, 2, f(Yes, false, "")}, + {0xc34c, 0, 0, 1, f(Yes, true, "")}, + {0xc34d, 0, 0, 2, f(Yes, false, "")}, + {0xc368, 0, 0, 1, f(Yes, true, "")}, + {0xc369, 0, 0, 2, f(Yes, false, "")}, + {0xc384, 0, 0, 1, f(Yes, true, "")}, + {0xc385, 0, 0, 2, f(Yes, false, "")}, + {0xc3a0, 0, 0, 1, f(Yes, true, "")}, + {0xc3a1, 0, 0, 2, f(Yes, false, "")}, + {0xc3bc, 0, 0, 1, f(Yes, true, "")}, + {0xc3bd, 0, 0, 2, f(Yes, false, "")}, + {0xc3d8, 0, 0, 1, f(Yes, true, "")}, + {0xc3d9, 0, 0, 2, f(Yes, false, "")}, + {0xc3f4, 0, 0, 1, f(Yes, true, "")}, + {0xc3f5, 0, 0, 2, f(Yes, false, "")}, + {0xc410, 0, 0, 1, f(Yes, true, "")}, + {0xc411, 0, 0, 2, f(Yes, false, "")}, + {0xc42c, 0, 0, 1, f(Yes, true, "")}, + {0xc42d, 0, 0, 2, f(Yes, false, "")}, + {0xc448, 0, 0, 1, f(Yes, true, "")}, + {0xc449, 0, 0, 2, f(Yes, false, "")}, + {0xc464, 0, 0, 1, f(Yes, true, "")}, + {0xc465, 0, 0, 2, f(Yes, false, "")}, + {0xc480, 0, 0, 1, f(Yes, true, "")}, + {0xc481, 0, 0, 2, f(Yes, false, "")}, + {0xc49c, 0, 0, 1, f(Yes, true, "")}, + {0xc49d, 0, 0, 2, f(Yes, false, "")}, + {0xc4b8, 0, 0, 1, f(Yes, true, "")}, + {0xc4b9, 0, 0, 2, f(Yes, false, "")}, + {0xc4d4, 0, 0, 1, f(Yes, true, "")}, + {0xc4d5, 0, 0, 2, f(Yes, false, "")}, + {0xc4f0, 0, 0, 1, f(Yes, true, "")}, + {0xc4f1, 0, 0, 2, f(Yes, false, "")}, + {0xc50c, 0, 0, 1, f(Yes, true, "")}, + {0xc50d, 0, 0, 2, f(Yes, false, "")}, + {0xc528, 0, 0, 1, f(Yes, true, "")}, + {0xc529, 0, 0, 2, f(Yes, false, "")}, + {0xc544, 0, 0, 1, f(Yes, true, "")}, + {0xc545, 0, 0, 2, f(Yes, false, "")}, + {0xc560, 0, 0, 1, f(Yes, true, "")}, + {0xc561, 0, 0, 2, f(Yes, false, "")}, + {0xc57c, 0, 0, 1, f(Yes, true, "")}, + {0xc57d, 0, 0, 2, f(Yes, false, "")}, + {0xc598, 0, 0, 1, f(Yes, true, "")}, + {0xc599, 0, 0, 2, f(Yes, false, "")}, + {0xc5b4, 0, 0, 1, f(Yes, true, "")}, + {0xc5b5, 0, 0, 2, f(Yes, false, "")}, + {0xc5d0, 0, 0, 1, f(Yes, true, "")}, + {0xc5d1, 0, 0, 2, f(Yes, false, "")}, + {0xc5ec, 0, 0, 1, f(Yes, true, "")}, + {0xc5ed, 0, 0, 2, f(Yes, false, "")}, + {0xc608, 0, 0, 1, f(Yes, true, "")}, + {0xc609, 0, 0, 2, f(Yes, false, "")}, + {0xc624, 0, 0, 1, f(Yes, true, "")}, + {0xc625, 0, 0, 2, f(Yes, false, "")}, + {0xc640, 0, 0, 1, f(Yes, true, "")}, + {0xc641, 0, 0, 2, f(Yes, false, "")}, + {0xc65c, 0, 0, 1, f(Yes, true, "")}, + {0xc65d, 0, 0, 2, f(Yes, false, "")}, + {0xc678, 0, 0, 1, f(Yes, true, "")}, + {0xc679, 0, 0, 2, f(Yes, false, "")}, + {0xc694, 0, 0, 1, f(Yes, true, "")}, + {0xc695, 0, 0, 2, f(Yes, false, "")}, + {0xc6b0, 0, 0, 1, f(Yes, true, "")}, + {0xc6b1, 0, 0, 2, f(Yes, false, "")}, + {0xc6cc, 0, 0, 1, f(Yes, true, "")}, + {0xc6cd, 0, 0, 2, f(Yes, false, "")}, + {0xc6e8, 0, 0, 1, f(Yes, true, "")}, + {0xc6e9, 0, 0, 2, f(Yes, false, "")}, + {0xc704, 0, 0, 1, f(Yes, true, "")}, + {0xc705, 0, 0, 2, f(Yes, false, "")}, + {0xc720, 0, 0, 1, f(Yes, true, "")}, + {0xc721, 0, 0, 2, f(Yes, false, "")}, + {0xc73c, 0, 0, 1, f(Yes, true, "")}, + {0xc73d, 0, 0, 2, f(Yes, false, "")}, + {0xc758, 0, 0, 1, f(Yes, true, "")}, + {0xc759, 0, 0, 2, f(Yes, false, "")}, + {0xc774, 0, 0, 1, f(Yes, true, "")}, + {0xc775, 0, 0, 2, f(Yes, false, "")}, + {0xc790, 0, 0, 1, f(Yes, true, "")}, + {0xc791, 0, 0, 2, f(Yes, false, "")}, + {0xc7ac, 0, 0, 1, f(Yes, true, "")}, + {0xc7ad, 0, 0, 2, f(Yes, false, "")}, + {0xc7c8, 0, 0, 1, f(Yes, true, "")}, + {0xc7c9, 0, 0, 2, f(Yes, false, "")}, + {0xc7e4, 0, 0, 1, f(Yes, true, "")}, + {0xc7e5, 0, 0, 2, f(Yes, false, "")}, + {0xc800, 0, 0, 1, f(Yes, true, "")}, + {0xc801, 0, 0, 2, f(Yes, false, "")}, + {0xc81c, 0, 0, 1, f(Yes, true, "")}, + {0xc81d, 0, 0, 2, f(Yes, false, "")}, + {0xc838, 0, 0, 1, f(Yes, true, "")}, + {0xc839, 0, 0, 2, f(Yes, false, "")}, + {0xc854, 0, 0, 1, f(Yes, true, "")}, + {0xc855, 0, 0, 2, f(Yes, false, "")}, + {0xc870, 0, 0, 1, f(Yes, true, "")}, + {0xc871, 0, 0, 2, f(Yes, false, "")}, + {0xc88c, 0, 0, 1, f(Yes, true, "")}, + {0xc88d, 0, 0, 2, f(Yes, false, "")}, + {0xc8a8, 0, 0, 1, f(Yes, true, "")}, + {0xc8a9, 0, 0, 2, f(Yes, false, "")}, + {0xc8c4, 0, 0, 1, f(Yes, true, "")}, + {0xc8c5, 0, 0, 2, f(Yes, false, "")}, + {0xc8e0, 0, 0, 1, f(Yes, true, "")}, + {0xc8e1, 0, 0, 2, f(Yes, false, "")}, + {0xc8fc, 0, 0, 1, f(Yes, true, "")}, + {0xc8fd, 0, 0, 2, f(Yes, false, "")}, + {0xc918, 0, 0, 1, f(Yes, true, "")}, + {0xc919, 0, 0, 2, f(Yes, false, "")}, + {0xc934, 0, 0, 1, f(Yes, true, "")}, + {0xc935, 0, 0, 2, f(Yes, false, "")}, + {0xc950, 0, 0, 1, f(Yes, true, "")}, + {0xc951, 0, 0, 2, f(Yes, false, "")}, + {0xc96c, 0, 0, 1, f(Yes, true, "")}, + {0xc96d, 0, 0, 2, f(Yes, false, "")}, + {0xc988, 0, 0, 1, f(Yes, true, "")}, + {0xc989, 0, 0, 2, f(Yes, false, "")}, + {0xc9a4, 0, 0, 1, f(Yes, true, "")}, + {0xc9a5, 0, 0, 2, f(Yes, false, "")}, + {0xc9c0, 0, 0, 1, f(Yes, true, "")}, + {0xc9c1, 0, 0, 2, f(Yes, false, "")}, + {0xc9dc, 0, 0, 1, f(Yes, true, "")}, + {0xc9dd, 0, 0, 2, f(Yes, false, "")}, + {0xc9f8, 0, 0, 1, f(Yes, true, "")}, + {0xc9f9, 0, 0, 2, f(Yes, false, "")}, + {0xca14, 0, 0, 1, f(Yes, true, "")}, + {0xca15, 0, 0, 2, f(Yes, false, "")}, + {0xca30, 0, 0, 1, f(Yes, true, "")}, + {0xca31, 0, 0, 2, f(Yes, false, "")}, + {0xca4c, 0, 0, 1, f(Yes, true, "")}, + {0xca4d, 0, 0, 2, f(Yes, false, "")}, + {0xca68, 0, 0, 1, f(Yes, true, "")}, + {0xca69, 0, 0, 2, f(Yes, false, "")}, + {0xca84, 0, 0, 1, f(Yes, true, "")}, + {0xca85, 0, 0, 2, f(Yes, false, "")}, + {0xcaa0, 0, 0, 1, f(Yes, true, "")}, + {0xcaa1, 0, 0, 2, f(Yes, false, "")}, + {0xcabc, 0, 0, 1, f(Yes, true, "")}, + {0xcabd, 0, 0, 2, f(Yes, false, "")}, + {0xcad8, 0, 0, 1, f(Yes, true, "")}, + {0xcad9, 0, 0, 2, f(Yes, false, "")}, + {0xcaf4, 0, 0, 1, f(Yes, true, "")}, + {0xcaf5, 0, 0, 2, f(Yes, false, "")}, + {0xcb10, 0, 0, 1, f(Yes, true, "")}, + {0xcb11, 0, 0, 2, f(Yes, false, "")}, + {0xcb2c, 0, 0, 1, f(Yes, true, "")}, + {0xcb2d, 0, 0, 2, f(Yes, false, "")}, + {0xcb48, 0, 0, 1, f(Yes, true, "")}, + {0xcb49, 0, 0, 2, f(Yes, false, "")}, + {0xcb64, 0, 0, 1, f(Yes, true, "")}, + {0xcb65, 0, 0, 2, f(Yes, false, "")}, + {0xcb80, 0, 0, 1, f(Yes, true, "")}, + {0xcb81, 0, 0, 2, f(Yes, false, "")}, + {0xcb9c, 0, 0, 1, f(Yes, true, "")}, + {0xcb9d, 0, 0, 2, f(Yes, false, "")}, + {0xcbb8, 0, 0, 1, f(Yes, true, "")}, + {0xcbb9, 0, 0, 2, f(Yes, false, "")}, + {0xcbd4, 0, 0, 1, f(Yes, true, "")}, + {0xcbd5, 0, 0, 2, f(Yes, false, "")}, + {0xcbf0, 0, 0, 1, f(Yes, true, "")}, + {0xcbf1, 0, 0, 2, f(Yes, false, "")}, + {0xcc0c, 0, 0, 1, f(Yes, true, "")}, + {0xcc0d, 0, 0, 2, f(Yes, false, "")}, + {0xcc28, 0, 0, 1, f(Yes, true, "")}, + {0xcc29, 0, 0, 2, f(Yes, false, "")}, + {0xcc44, 0, 0, 1, f(Yes, true, "")}, + {0xcc45, 0, 0, 2, f(Yes, false, "")}, + {0xcc60, 0, 0, 1, f(Yes, true, "")}, + {0xcc61, 0, 0, 2, f(Yes, false, "")}, + {0xcc7c, 0, 0, 1, f(Yes, true, "")}, + {0xcc7d, 0, 0, 2, f(Yes, false, "")}, + {0xcc98, 0, 0, 1, f(Yes, true, "")}, + {0xcc99, 0, 0, 2, f(Yes, false, "")}, + {0xccb4, 0, 0, 1, f(Yes, true, "")}, + {0xccb5, 0, 0, 2, f(Yes, false, "")}, + {0xccd0, 0, 0, 1, f(Yes, true, "")}, + {0xccd1, 0, 0, 2, f(Yes, false, "")}, + {0xccec, 0, 0, 1, f(Yes, true, "")}, + {0xcced, 0, 0, 2, f(Yes, false, "")}, + {0xcd08, 0, 0, 1, f(Yes, true, "")}, + {0xcd09, 0, 0, 2, f(Yes, false, "")}, + {0xcd24, 0, 0, 1, f(Yes, true, "")}, + {0xcd25, 0, 0, 2, f(Yes, false, "")}, + {0xcd40, 0, 0, 1, f(Yes, true, "")}, + {0xcd41, 0, 0, 2, f(Yes, false, "")}, + {0xcd5c, 0, 0, 1, f(Yes, true, "")}, + {0xcd5d, 0, 0, 2, f(Yes, false, "")}, + {0xcd78, 0, 0, 1, f(Yes, true, "")}, + {0xcd79, 0, 0, 2, f(Yes, false, "")}, + {0xcd94, 0, 0, 1, f(Yes, true, "")}, + {0xcd95, 0, 0, 2, f(Yes, false, "")}, + {0xcdb0, 0, 0, 1, f(Yes, true, "")}, + {0xcdb1, 0, 0, 2, f(Yes, false, "")}, + {0xcdcc, 0, 0, 1, f(Yes, true, "")}, + {0xcdcd, 0, 0, 2, f(Yes, false, "")}, + {0xcde8, 0, 0, 1, f(Yes, true, "")}, + {0xcde9, 0, 0, 2, f(Yes, false, "")}, + {0xce04, 0, 0, 1, f(Yes, true, "")}, + {0xce05, 0, 0, 2, f(Yes, false, "")}, + {0xce20, 0, 0, 1, f(Yes, true, "")}, + {0xce21, 0, 0, 2, f(Yes, false, "")}, + {0xce3c, 0, 0, 1, f(Yes, true, "")}, + {0xce3d, 0, 0, 2, f(Yes, false, "")}, + {0xce58, 0, 0, 1, f(Yes, true, "")}, + {0xce59, 0, 0, 2, f(Yes, false, "")}, + {0xce74, 0, 0, 1, f(Yes, true, "")}, + {0xce75, 0, 0, 2, f(Yes, false, "")}, + {0xce90, 0, 0, 1, f(Yes, true, "")}, + {0xce91, 0, 0, 2, f(Yes, false, "")}, + {0xceac, 0, 0, 1, f(Yes, true, "")}, + {0xcead, 0, 0, 2, f(Yes, false, "")}, + {0xcec8, 0, 0, 1, f(Yes, true, "")}, + {0xcec9, 0, 0, 2, f(Yes, false, "")}, + {0xcee4, 0, 0, 1, f(Yes, true, "")}, + {0xcee5, 0, 0, 2, f(Yes, false, "")}, + {0xcf00, 0, 0, 1, f(Yes, true, "")}, + {0xcf01, 0, 0, 2, f(Yes, false, "")}, + {0xcf1c, 0, 0, 1, f(Yes, true, "")}, + {0xcf1d, 0, 0, 2, f(Yes, false, "")}, + {0xcf38, 0, 0, 1, f(Yes, true, "")}, + {0xcf39, 0, 0, 2, f(Yes, false, "")}, + {0xcf54, 0, 0, 1, f(Yes, true, "")}, + {0xcf55, 0, 0, 2, f(Yes, false, "")}, + {0xcf70, 0, 0, 1, f(Yes, true, "")}, + {0xcf71, 0, 0, 2, f(Yes, false, "")}, + {0xcf8c, 0, 0, 1, f(Yes, true, "")}, + {0xcf8d, 0, 0, 2, f(Yes, false, "")}, + {0xcfa8, 0, 0, 1, f(Yes, true, "")}, + {0xcfa9, 0, 0, 2, f(Yes, false, "")}, + {0xcfc4, 0, 0, 1, f(Yes, true, "")}, + {0xcfc5, 0, 0, 2, f(Yes, false, "")}, + {0xcfe0, 0, 0, 1, f(Yes, true, "")}, + {0xcfe1, 0, 0, 2, f(Yes, false, "")}, + {0xcffc, 0, 0, 1, f(Yes, true, "")}, + {0xcffd, 0, 0, 2, f(Yes, false, "")}, + {0xd018, 0, 0, 1, f(Yes, true, "")}, + {0xd019, 0, 0, 2, f(Yes, false, "")}, + {0xd034, 0, 0, 1, f(Yes, true, "")}, + {0xd035, 0, 0, 2, f(Yes, false, "")}, + {0xd050, 0, 0, 1, f(Yes, true, "")}, + {0xd051, 0, 0, 2, f(Yes, false, "")}, + {0xd06c, 0, 0, 1, f(Yes, true, "")}, + {0xd06d, 0, 0, 2, f(Yes, false, "")}, + {0xd088, 0, 0, 1, f(Yes, true, "")}, + {0xd089, 0, 0, 2, f(Yes, false, "")}, + {0xd0a4, 0, 0, 1, f(Yes, true, "")}, + {0xd0a5, 0, 0, 2, f(Yes, false, "")}, + {0xd0c0, 0, 0, 1, f(Yes, true, "")}, + {0xd0c1, 0, 0, 2, f(Yes, false, "")}, + {0xd0dc, 0, 0, 1, f(Yes, true, "")}, + {0xd0dd, 0, 0, 2, f(Yes, false, "")}, + {0xd0f8, 0, 0, 1, f(Yes, true, "")}, + {0xd0f9, 0, 0, 2, f(Yes, false, "")}, + {0xd114, 0, 0, 1, f(Yes, true, "")}, + {0xd115, 0, 0, 2, f(Yes, false, "")}, + {0xd130, 0, 0, 1, f(Yes, true, "")}, + {0xd131, 0, 0, 2, f(Yes, false, "")}, + {0xd14c, 0, 0, 1, f(Yes, true, "")}, + {0xd14d, 0, 0, 2, f(Yes, false, "")}, + {0xd168, 0, 0, 1, f(Yes, true, "")}, + {0xd169, 0, 0, 2, f(Yes, false, "")}, + {0xd184, 0, 0, 1, f(Yes, true, "")}, + {0xd185, 0, 0, 2, f(Yes, false, "")}, + {0xd1a0, 0, 0, 1, f(Yes, true, "")}, + {0xd1a1, 0, 0, 2, f(Yes, false, "")}, + {0xd1bc, 0, 0, 1, f(Yes, true, "")}, + {0xd1bd, 0, 0, 2, f(Yes, false, "")}, + {0xd1d8, 0, 0, 1, f(Yes, true, "")}, + {0xd1d9, 0, 0, 2, f(Yes, false, "")}, + {0xd1f4, 0, 0, 1, f(Yes, true, "")}, + {0xd1f5, 0, 0, 2, f(Yes, false, "")}, + {0xd210, 0, 0, 1, f(Yes, true, "")}, + {0xd211, 0, 0, 2, f(Yes, false, "")}, + {0xd22c, 0, 0, 1, f(Yes, true, "")}, + {0xd22d, 0, 0, 2, f(Yes, false, "")}, + {0xd248, 0, 0, 1, f(Yes, true, "")}, + {0xd249, 0, 0, 2, f(Yes, false, "")}, + {0xd264, 0, 0, 1, f(Yes, true, "")}, + {0xd265, 0, 0, 2, f(Yes, false, "")}, + {0xd280, 0, 0, 1, f(Yes, true, "")}, + {0xd281, 0, 0, 2, f(Yes, false, "")}, + {0xd29c, 0, 0, 1, f(Yes, true, "")}, + {0xd29d, 0, 0, 2, f(Yes, false, "")}, + {0xd2b8, 0, 0, 1, f(Yes, true, "")}, + {0xd2b9, 0, 0, 2, f(Yes, false, "")}, + {0xd2d4, 0, 0, 1, f(Yes, true, "")}, + {0xd2d5, 0, 0, 2, f(Yes, false, "")}, + {0xd2f0, 0, 0, 1, f(Yes, true, "")}, + {0xd2f1, 0, 0, 2, f(Yes, false, "")}, + {0xd30c, 0, 0, 1, f(Yes, true, "")}, + {0xd30d, 0, 0, 2, f(Yes, false, "")}, + {0xd328, 0, 0, 1, f(Yes, true, "")}, + {0xd329, 0, 0, 2, f(Yes, false, "")}, + {0xd344, 0, 0, 1, f(Yes, true, "")}, + {0xd345, 0, 0, 2, f(Yes, false, "")}, + {0xd360, 0, 0, 1, f(Yes, true, "")}, + {0xd361, 0, 0, 2, f(Yes, false, "")}, + {0xd37c, 0, 0, 1, f(Yes, true, "")}, + {0xd37d, 0, 0, 2, f(Yes, false, "")}, + {0xd398, 0, 0, 1, f(Yes, true, "")}, + {0xd399, 0, 0, 2, f(Yes, false, "")}, + {0xd3b4, 0, 0, 1, f(Yes, true, "")}, + {0xd3b5, 0, 0, 2, f(Yes, false, "")}, + {0xd3d0, 0, 0, 1, f(Yes, true, "")}, + {0xd3d1, 0, 0, 2, f(Yes, false, "")}, + {0xd3ec, 0, 0, 1, f(Yes, true, "")}, + {0xd3ed, 0, 0, 2, f(Yes, false, "")}, + {0xd408, 0, 0, 1, f(Yes, true, "")}, + {0xd409, 0, 0, 2, f(Yes, false, "")}, + {0xd424, 0, 0, 1, f(Yes, true, "")}, + {0xd425, 0, 0, 2, f(Yes, false, "")}, + {0xd440, 0, 0, 1, f(Yes, true, "")}, + {0xd441, 0, 0, 2, f(Yes, false, "")}, + {0xd45c, 0, 0, 1, f(Yes, true, "")}, + {0xd45d, 0, 0, 2, f(Yes, false, "")}, + {0xd478, 0, 0, 1, f(Yes, true, "")}, + {0xd479, 0, 0, 2, f(Yes, false, "")}, + {0xd494, 0, 0, 1, f(Yes, true, "")}, + {0xd495, 0, 0, 2, f(Yes, false, "")}, + {0xd4b0, 0, 0, 1, f(Yes, true, "")}, + {0xd4b1, 0, 0, 2, f(Yes, false, "")}, + {0xd4cc, 0, 0, 1, f(Yes, true, "")}, + {0xd4cd, 0, 0, 2, f(Yes, false, "")}, + {0xd4e8, 0, 0, 1, f(Yes, true, "")}, + {0xd4e9, 0, 0, 2, f(Yes, false, "")}, + {0xd504, 0, 0, 1, f(Yes, true, "")}, + {0xd505, 0, 0, 2, f(Yes, false, "")}, + {0xd520, 0, 0, 1, f(Yes, true, "")}, + {0xd521, 0, 0, 2, f(Yes, false, "")}, + {0xd53c, 0, 0, 1, f(Yes, true, "")}, + {0xd53d, 0, 0, 2, f(Yes, false, "")}, + {0xd558, 0, 0, 1, f(Yes, true, "")}, + {0xd559, 0, 0, 2, f(Yes, false, "")}, + {0xd574, 0, 0, 1, f(Yes, true, "")}, + {0xd575, 0, 0, 2, f(Yes, false, "")}, + {0xd590, 0, 0, 1, f(Yes, true, "")}, + {0xd591, 0, 0, 2, f(Yes, false, "")}, + {0xd5ac, 0, 0, 1, f(Yes, true, "")}, + {0xd5ad, 0, 0, 2, f(Yes, false, "")}, + {0xd5c8, 0, 0, 1, f(Yes, true, "")}, + {0xd5c9, 0, 0, 2, f(Yes, false, "")}, + {0xd5e4, 0, 0, 1, f(Yes, true, "")}, + {0xd5e5, 0, 0, 2, f(Yes, false, "")}, + {0xd600, 0, 0, 1, f(Yes, true, "")}, + {0xd601, 0, 0, 2, f(Yes, false, "")}, + {0xd61c, 0, 0, 1, f(Yes, true, "")}, + {0xd61d, 0, 0, 2, f(Yes, false, "")}, + {0xd638, 0, 0, 1, f(Yes, true, "")}, + {0xd639, 0, 0, 2, f(Yes, false, "")}, + {0xd654, 0, 0, 1, f(Yes, true, "")}, + {0xd655, 0, 0, 2, f(Yes, false, "")}, + {0xd670, 0, 0, 1, f(Yes, true, "")}, + {0xd671, 0, 0, 2, f(Yes, false, "")}, + {0xd68c, 0, 0, 1, f(Yes, true, "")}, + {0xd68d, 0, 0, 2, f(Yes, false, "")}, + {0xd6a8, 0, 0, 1, f(Yes, true, "")}, + {0xd6a9, 0, 0, 2, f(Yes, false, "")}, + {0xd6c4, 0, 0, 1, f(Yes, true, "")}, + {0xd6c5, 0, 0, 2, f(Yes, false, "")}, + {0xd6e0, 0, 0, 1, f(Yes, true, "")}, + {0xd6e1, 0, 0, 2, f(Yes, false, "")}, + {0xd6fc, 0, 0, 1, f(Yes, true, "")}, + {0xd6fd, 0, 0, 2, f(Yes, false, "")}, + {0xd718, 0, 0, 1, f(Yes, true, "")}, + {0xd719, 0, 0, 2, f(Yes, false, "")}, + {0xd734, 0, 0, 1, f(Yes, true, "")}, + {0xd735, 0, 0, 2, f(Yes, false, "")}, + {0xd750, 0, 0, 1, f(Yes, true, "")}, + {0xd751, 0, 0, 2, f(Yes, false, "")}, + {0xd76c, 0, 0, 1, f(Yes, true, "")}, + {0xd76d, 0, 0, 2, f(Yes, false, "")}, + {0xd788, 0, 0, 1, f(Yes, true, "")}, + {0xd789, 0, 0, 2, f(Yes, false, "")}, + {0xd7a4, 0, 0, 0, f(Yes, false, "")}, + {0xf900, 0, 0, 0, f(No, false, "豈")}, + {0xf901, 0, 0, 0, f(No, false, "更")}, + {0xf902, 0, 0, 0, f(No, false, "車")}, + {0xf903, 0, 0, 0, f(No, false, "賈")}, + {0xf904, 0, 0, 0, f(No, false, "滑")}, + {0xf905, 0, 0, 0, f(No, false, "串")}, + {0xf906, 0, 0, 0, f(No, false, "句")}, + {0xf907, 0, 0, 0, f(No, false, "龜")}, + {0xf909, 0, 0, 0, f(No, false, "契")}, + {0xf90a, 0, 0, 0, f(No, false, "金")}, + {0xf90b, 0, 0, 0, f(No, false, "喇")}, + {0xf90c, 0, 0, 0, f(No, false, "奈")}, + {0xf90d, 0, 0, 0, f(No, false, "懶")}, + {0xf90e, 0, 0, 0, f(No, false, "癩")}, + {0xf90f, 0, 0, 0, f(No, false, "羅")}, + {0xf910, 0, 0, 0, f(No, false, "蘿")}, + {0xf911, 0, 0, 0, f(No, false, "螺")}, + {0xf912, 0, 0, 0, f(No, false, "裸")}, + {0xf913, 0, 0, 0, f(No, false, "邏")}, + {0xf914, 0, 0, 0, f(No, false, "樂")}, + {0xf915, 0, 0, 0, f(No, false, "洛")}, + {0xf916, 0, 0, 0, f(No, false, "烙")}, + {0xf917, 0, 0, 0, f(No, false, "珞")}, + {0xf918, 0, 0, 0, f(No, false, "落")}, + {0xf919, 0, 0, 0, f(No, false, "酪")}, + {0xf91a, 0, 0, 0, f(No, false, "駱")}, + {0xf91b, 0, 0, 0, f(No, false, "亂")}, + {0xf91c, 0, 0, 0, f(No, false, "卵")}, + {0xf91d, 0, 0, 0, f(No, false, "欄")}, + {0xf91e, 0, 0, 0, f(No, false, "爛")}, + {0xf91f, 0, 0, 0, f(No, false, "蘭")}, + {0xf920, 0, 0, 0, f(No, false, "鸞")}, + {0xf921, 0, 0, 0, f(No, false, "嵐")}, + {0xf922, 0, 0, 0, f(No, false, "濫")}, + {0xf923, 0, 0, 0, f(No, false, "藍")}, + {0xf924, 0, 0, 0, f(No, false, "襤")}, + {0xf925, 0, 0, 0, f(No, false, "拉")}, + {0xf926, 0, 0, 0, f(No, false, "臘")}, + {0xf927, 0, 0, 0, f(No, false, "蠟")}, + {0xf928, 0, 0, 0, f(No, false, "廊")}, + {0xf929, 0, 0, 0, f(No, false, "朗")}, + {0xf92a, 0, 0, 0, f(No, false, "浪")}, + {0xf92b, 0, 0, 0, f(No, false, "狼")}, + {0xf92c, 0, 0, 0, f(No, false, "郎")}, + {0xf92d, 0, 0, 0, f(No, false, "來")}, + {0xf92e, 0, 0, 0, f(No, false, "冷")}, + {0xf92f, 0, 0, 0, f(No, false, "勞")}, + {0xf930, 0, 0, 0, f(No, false, "擄")}, + {0xf931, 0, 0, 0, f(No, false, "櫓")}, + {0xf932, 0, 0, 0, f(No, false, "爐")}, + {0xf933, 0, 0, 0, f(No, false, "盧")}, + {0xf934, 0, 0, 0, f(No, false, "老")}, + {0xf935, 0, 0, 0, f(No, false, "蘆")}, + {0xf936, 0, 0, 0, f(No, false, "虜")}, + {0xf937, 0, 0, 0, f(No, false, "路")}, + {0xf938, 0, 0, 0, f(No, false, "露")}, + {0xf939, 0, 0, 0, f(No, false, "魯")}, + {0xf93a, 0, 0, 0, f(No, false, "鷺")}, + {0xf93b, 0, 0, 0, f(No, false, "碌")}, + {0xf93c, 0, 0, 0, f(No, false, "祿")}, + {0xf93d, 0, 0, 0, f(No, false, "綠")}, + {0xf93e, 0, 0, 0, f(No, false, "菉")}, + {0xf93f, 0, 0, 0, f(No, false, "錄")}, + {0xf940, 0, 0, 0, f(No, false, "鹿")}, + {0xf941, 0, 0, 0, f(No, false, "論")}, + {0xf942, 0, 0, 0, f(No, false, "壟")}, + {0xf943, 0, 0, 0, f(No, false, "弄")}, + {0xf944, 0, 0, 0, f(No, false, "籠")}, + {0xf945, 0, 0, 0, f(No, false, "聾")}, + {0xf946, 0, 0, 0, f(No, false, "牢")}, + {0xf947, 0, 0, 0, f(No, false, "磊")}, + {0xf948, 0, 0, 0, f(No, false, "賂")}, + {0xf949, 0, 0, 0, f(No, false, "雷")}, + {0xf94a, 0, 0, 0, f(No, false, "壘")}, + {0xf94b, 0, 0, 0, f(No, false, "屢")}, + {0xf94c, 0, 0, 0, f(No, false, "樓")}, + {0xf94d, 0, 0, 0, f(No, false, "淚")}, + {0xf94e, 0, 0, 0, f(No, false, "漏")}, + {0xf94f, 0, 0, 0, f(No, false, "累")}, + {0xf950, 0, 0, 0, f(No, false, "縷")}, + {0xf951, 0, 0, 0, f(No, false, "陋")}, + {0xf952, 0, 0, 0, f(No, false, "勒")}, + {0xf953, 0, 0, 0, f(No, false, "肋")}, + {0xf954, 0, 0, 0, f(No, false, "凜")}, + {0xf955, 0, 0, 0, f(No, false, "凌")}, + {0xf956, 0, 0, 0, f(No, false, "稜")}, + {0xf957, 0, 0, 0, f(No, false, "綾")}, + {0xf958, 0, 0, 0, f(No, false, "菱")}, + {0xf959, 0, 0, 0, f(No, false, "陵")}, + {0xf95a, 0, 0, 0, f(No, false, "讀")}, + {0xf95b, 0, 0, 0, f(No, false, "拏")}, + {0xf95c, 0, 0, 0, f(No, false, "樂")}, + {0xf95d, 0, 0, 0, f(No, false, "諾")}, + {0xf95e, 0, 0, 0, f(No, false, "丹")}, + {0xf95f, 0, 0, 0, f(No, false, "寧")}, + {0xf960, 0, 0, 0, f(No, false, "怒")}, + {0xf961, 0, 0, 0, f(No, false, "率")}, + {0xf962, 0, 0, 0, f(No, false, "異")}, + {0xf963, 0, 0, 0, f(No, false, "北")}, + {0xf964, 0, 0, 0, f(No, false, "磻")}, + {0xf965, 0, 0, 0, f(No, false, "便")}, + {0xf966, 0, 0, 0, f(No, false, "復")}, + {0xf967, 0, 0, 0, f(No, false, "不")}, + {0xf968, 0, 0, 0, f(No, false, "泌")}, + {0xf969, 0, 0, 0, f(No, false, "數")}, + {0xf96a, 0, 0, 0, f(No, false, "索")}, + {0xf96b, 0, 0, 0, f(No, false, "參")}, + {0xf96c, 0, 0, 0, f(No, false, "塞")}, + {0xf96d, 0, 0, 0, f(No, false, "省")}, + {0xf96e, 0, 0, 0, f(No, false, "葉")}, + {0xf96f, 0, 0, 0, f(No, false, "說")}, + {0xf970, 0, 0, 0, f(No, false, "殺")}, + {0xf971, 0, 0, 0, f(No, false, "辰")}, + {0xf972, 0, 0, 0, f(No, false, "沈")}, + {0xf973, 0, 0, 0, f(No, false, "拾")}, + {0xf974, 0, 0, 0, f(No, false, "若")}, + {0xf975, 0, 0, 0, f(No, false, "掠")}, + {0xf976, 0, 0, 0, f(No, false, "略")}, + {0xf977, 0, 0, 0, f(No, false, "亮")}, + {0xf978, 0, 0, 0, f(No, false, "兩")}, + {0xf979, 0, 0, 0, f(No, false, "凉")}, + {0xf97a, 0, 0, 0, f(No, false, "梁")}, + {0xf97b, 0, 0, 0, f(No, false, "糧")}, + {0xf97c, 0, 0, 0, f(No, false, "良")}, + {0xf97d, 0, 0, 0, f(No, false, "諒")}, + {0xf97e, 0, 0, 0, f(No, false, "量")}, + {0xf97f, 0, 0, 0, f(No, false, "勵")}, + {0xf980, 0, 0, 0, f(No, false, "呂")}, + {0xf981, 0, 0, 0, f(No, false, "女")}, + {0xf982, 0, 0, 0, f(No, false, "廬")}, + {0xf983, 0, 0, 0, f(No, false, "旅")}, + {0xf984, 0, 0, 0, f(No, false, "濾")}, + {0xf985, 0, 0, 0, f(No, false, "礪")}, + {0xf986, 0, 0, 0, f(No, false, "閭")}, + {0xf987, 0, 0, 0, f(No, false, "驪")}, + {0xf988, 0, 0, 0, f(No, false, "麗")}, + {0xf989, 0, 0, 0, f(No, false, "黎")}, + {0xf98a, 0, 0, 0, f(No, false, "力")}, + {0xf98b, 0, 0, 0, f(No, false, "曆")}, + {0xf98c, 0, 0, 0, f(No, false, "歷")}, + {0xf98d, 0, 0, 0, f(No, false, "轢")}, + {0xf98e, 0, 0, 0, f(No, false, "年")}, + {0xf98f, 0, 0, 0, f(No, false, "憐")}, + {0xf990, 0, 0, 0, f(No, false, "戀")}, + {0xf991, 0, 0, 0, f(No, false, "撚")}, + {0xf992, 0, 0, 0, f(No, false, "漣")}, + {0xf993, 0, 0, 0, f(No, false, "煉")}, + {0xf994, 0, 0, 0, f(No, false, "璉")}, + {0xf995, 0, 0, 0, f(No, false, "秊")}, + {0xf996, 0, 0, 0, f(No, false, "練")}, + {0xf997, 0, 0, 0, f(No, false, "聯")}, + {0xf998, 0, 0, 0, f(No, false, "輦")}, + {0xf999, 0, 0, 0, f(No, false, "蓮")}, + {0xf99a, 0, 0, 0, f(No, false, "連")}, + {0xf99b, 0, 0, 0, f(No, false, "鍊")}, + {0xf99c, 0, 0, 0, f(No, false, "列")}, + {0xf99d, 0, 0, 0, f(No, false, "劣")}, + {0xf99e, 0, 0, 0, f(No, false, "咽")}, + {0xf99f, 0, 0, 0, f(No, false, "烈")}, + {0xf9a0, 0, 0, 0, f(No, false, "裂")}, + {0xf9a1, 0, 0, 0, f(No, false, "說")}, + {0xf9a2, 0, 0, 0, f(No, false, "廉")}, + {0xf9a3, 0, 0, 0, f(No, false, "念")}, + {0xf9a4, 0, 0, 0, f(No, false, "捻")}, + {0xf9a5, 0, 0, 0, f(No, false, "殮")}, + {0xf9a6, 0, 0, 0, f(No, false, "簾")}, + {0xf9a7, 0, 0, 0, f(No, false, "獵")}, + {0xf9a8, 0, 0, 0, f(No, false, "令")}, + {0xf9a9, 0, 0, 0, f(No, false, "囹")}, + {0xf9aa, 0, 0, 0, f(No, false, "寧")}, + {0xf9ab, 0, 0, 0, f(No, false, "嶺")}, + {0xf9ac, 0, 0, 0, f(No, false, "怜")}, + {0xf9ad, 0, 0, 0, f(No, false, "玲")}, + {0xf9ae, 0, 0, 0, f(No, false, "瑩")}, + {0xf9af, 0, 0, 0, f(No, false, "羚")}, + {0xf9b0, 0, 0, 0, f(No, false, "聆")}, + {0xf9b1, 0, 0, 0, f(No, false, "鈴")}, + {0xf9b2, 0, 0, 0, f(No, false, "零")}, + {0xf9b3, 0, 0, 0, f(No, false, "靈")}, + {0xf9b4, 0, 0, 0, f(No, false, "領")}, + {0xf9b5, 0, 0, 0, f(No, false, "例")}, + {0xf9b6, 0, 0, 0, f(No, false, "禮")}, + {0xf9b7, 0, 0, 0, f(No, false, "醴")}, + {0xf9b8, 0, 0, 0, f(No, false, "隸")}, + {0xf9b9, 0, 0, 0, f(No, false, "惡")}, + {0xf9ba, 0, 0, 0, f(No, false, "了")}, + {0xf9bb, 0, 0, 0, f(No, false, "僚")}, + {0xf9bc, 0, 0, 0, f(No, false, "寮")}, + {0xf9bd, 0, 0, 0, f(No, false, "尿")}, + {0xf9be, 0, 0, 0, f(No, false, "料")}, + {0xf9bf, 0, 0, 0, f(No, false, "樂")}, + {0xf9c0, 0, 0, 0, f(No, false, "燎")}, + {0xf9c1, 0, 0, 0, f(No, false, "療")}, + {0xf9c2, 0, 0, 0, f(No, false, "蓼")}, + {0xf9c3, 0, 0, 0, f(No, false, "遼")}, + {0xf9c4, 0, 0, 0, f(No, false, "龍")}, + {0xf9c5, 0, 0, 0, f(No, false, "暈")}, + {0xf9c6, 0, 0, 0, f(No, false, "阮")}, + {0xf9c7, 0, 0, 0, f(No, false, "劉")}, + {0xf9c8, 0, 0, 0, f(No, false, "杻")}, + {0xf9c9, 0, 0, 0, f(No, false, "柳")}, + {0xf9ca, 0, 0, 0, f(No, false, "流")}, + {0xf9cb, 0, 0, 0, f(No, false, "溜")}, + {0xf9cc, 0, 0, 0, f(No, false, "琉")}, + {0xf9cd, 0, 0, 0, f(No, false, "留")}, + {0xf9ce, 0, 0, 0, f(No, false, "硫")}, + {0xf9cf, 0, 0, 0, f(No, false, "紐")}, + {0xf9d0, 0, 0, 0, f(No, false, "類")}, + {0xf9d1, 0, 0, 0, f(No, false, "六")}, + {0xf9d2, 0, 0, 0, f(No, false, "戮")}, + {0xf9d3, 0, 0, 0, f(No, false, "陸")}, + {0xf9d4, 0, 0, 0, f(No, false, "倫")}, + {0xf9d5, 0, 0, 0, f(No, false, "崙")}, + {0xf9d6, 0, 0, 0, f(No, false, "淪")}, + {0xf9d7, 0, 0, 0, f(No, false, "輪")}, + {0xf9d8, 0, 0, 0, f(No, false, "律")}, + {0xf9d9, 0, 0, 0, f(No, false, "慄")}, + {0xf9da, 0, 0, 0, f(No, false, "栗")}, + {0xf9db, 0, 0, 0, f(No, false, "率")}, + {0xf9dc, 0, 0, 0, f(No, false, "隆")}, + {0xf9dd, 0, 0, 0, f(No, false, "利")}, + {0xf9de, 0, 0, 0, f(No, false, "吏")}, + {0xf9df, 0, 0, 0, f(No, false, "履")}, + {0xf9e0, 0, 0, 0, f(No, false, "易")}, + {0xf9e1, 0, 0, 0, f(No, false, "李")}, + {0xf9e2, 0, 0, 0, f(No, false, "梨")}, + {0xf9e3, 0, 0, 0, f(No, false, "泥")}, + {0xf9e4, 0, 0, 0, f(No, false, "理")}, + {0xf9e5, 0, 0, 0, f(No, false, "痢")}, + {0xf9e6, 0, 0, 0, f(No, false, "罹")}, + {0xf9e7, 0, 0, 0, f(No, false, "裏")}, + {0xf9e8, 0, 0, 0, f(No, false, "裡")}, + {0xf9e9, 0, 0, 0, f(No, false, "里")}, + {0xf9ea, 0, 0, 0, f(No, false, "離")}, + {0xf9eb, 0, 0, 0, f(No, false, "匿")}, + {0xf9ec, 0, 0, 0, f(No, false, "溺")}, + {0xf9ed, 0, 0, 0, f(No, false, "吝")}, + {0xf9ee, 0, 0, 0, f(No, false, "燐")}, + {0xf9ef, 0, 0, 0, f(No, false, "璘")}, + {0xf9f0, 0, 0, 0, f(No, false, "藺")}, + {0xf9f1, 0, 0, 0, f(No, false, "隣")}, + {0xf9f2, 0, 0, 0, f(No, false, "鱗")}, + {0xf9f3, 0, 0, 0, f(No, false, "麟")}, + {0xf9f4, 0, 0, 0, f(No, false, "林")}, + {0xf9f5, 0, 0, 0, f(No, false, "淋")}, + {0xf9f6, 0, 0, 0, f(No, false, "臨")}, + {0xf9f7, 0, 0, 0, f(No, false, "立")}, + {0xf9f8, 0, 0, 0, f(No, false, "笠")}, + {0xf9f9, 0, 0, 0, f(No, false, "粒")}, + {0xf9fa, 0, 0, 0, f(No, false, "狀")}, + {0xf9fb, 0, 0, 0, f(No, false, "炙")}, + {0xf9fc, 0, 0, 0, f(No, false, "識")}, + {0xf9fd, 0, 0, 0, f(No, false, "什")}, + {0xf9fe, 0, 0, 0, f(No, false, "茶")}, + {0xf9ff, 0, 0, 0, f(No, false, "刺")}, + {0xfa00, 0, 0, 0, f(No, false, "切")}, + {0xfa01, 0, 0, 0, f(No, false, "度")}, + {0xfa02, 0, 0, 0, f(No, false, "拓")}, + {0xfa03, 0, 0, 0, f(No, false, "糖")}, + {0xfa04, 0, 0, 0, f(No, false, "宅")}, + {0xfa05, 0, 0, 0, f(No, false, "洞")}, + {0xfa06, 0, 0, 0, f(No, false, "暴")}, + {0xfa07, 0, 0, 0, f(No, false, "輻")}, + {0xfa08, 0, 0, 0, f(No, false, "行")}, + {0xfa09, 0, 0, 0, f(No, false, "降")}, + {0xfa0a, 0, 0, 0, f(No, false, "見")}, + {0xfa0b, 0, 0, 0, f(No, false, "廓")}, + {0xfa0c, 0, 0, 0, f(No, false, "兀")}, + {0xfa0d, 0, 0, 0, f(No, false, "嗀")}, + {0xfa0e, 0, 0, 0, f(Yes, false, "")}, + {0xfa10, 0, 0, 0, f(No, false, "塚")}, + {0xfa11, 0, 0, 0, f(Yes, false, "")}, + {0xfa12, 0, 0, 0, f(No, false, "晴")}, + {0xfa13, 0, 0, 0, f(Yes, false, "")}, + {0xfa15, 0, 0, 0, f(No, false, "凞")}, + {0xfa16, 0, 0, 0, f(No, false, "猪")}, + {0xfa17, 0, 0, 0, f(No, false, "益")}, + {0xfa18, 0, 0, 0, f(No, false, "礼")}, + {0xfa19, 0, 0, 0, f(No, false, "神")}, + {0xfa1a, 0, 0, 0, f(No, false, "祥")}, + {0xfa1b, 0, 0, 0, f(No, false, "福")}, + {0xfa1c, 0, 0, 0, f(No, false, "靖")}, + {0xfa1d, 0, 0, 0, f(No, false, "精")}, + {0xfa1e, 0, 0, 0, f(No, false, "羽")}, + {0xfa1f, 0, 0, 0, f(Yes, false, "")}, + {0xfa20, 0, 0, 0, f(No, false, "蘒")}, + {0xfa21, 0, 0, 0, f(Yes, false, "")}, + {0xfa22, 0, 0, 0, f(No, false, "諸")}, + {0xfa23, 0, 0, 0, f(Yes, false, "")}, + {0xfa25, 0, 0, 0, f(No, false, "逸")}, + {0xfa26, 0, 0, 0, f(No, false, "都")}, + {0xfa27, 0, 0, 0, f(Yes, false, "")}, + {0xfa2a, 0, 0, 0, f(No, false, "飯")}, + {0xfa2b, 0, 0, 0, f(No, false, "飼")}, + {0xfa2c, 0, 0, 0, f(No, false, "館")}, + {0xfa2d, 0, 0, 0, f(No, false, "鶴")}, + {0xfa2e, 0, 0, 0, f(No, false, "郞")}, + {0xfa2f, 0, 0, 0, f(No, false, "隷")}, + {0xfa30, 0, 0, 0, f(No, false, "侮")}, + {0xfa31, 0, 0, 0, f(No, false, "僧")}, + {0xfa32, 0, 0, 0, f(No, false, "免")}, + {0xfa33, 0, 0, 0, f(No, false, "勉")}, + {0xfa34, 0, 0, 0, f(No, false, "勤")}, + {0xfa35, 0, 0, 0, f(No, false, "卑")}, + {0xfa36, 0, 0, 0, f(No, false, "喝")}, + {0xfa37, 0, 0, 0, f(No, false, "嘆")}, + {0xfa38, 0, 0, 0, f(No, false, "器")}, + {0xfa39, 0, 0, 0, f(No, false, "塀")}, + {0xfa3a, 0, 0, 0, f(No, false, "墨")}, + {0xfa3b, 0, 0, 0, f(No, false, "層")}, + {0xfa3c, 0, 0, 0, f(No, false, "屮")}, + {0xfa3d, 0, 0, 0, f(No, false, "悔")}, + {0xfa3e, 0, 0, 0, f(No, false, "慨")}, + {0xfa3f, 0, 0, 0, f(No, false, "憎")}, + {0xfa40, 0, 0, 0, f(No, false, "懲")}, + {0xfa41, 0, 0, 0, f(No, false, "敏")}, + {0xfa42, 0, 0, 0, f(No, false, "既")}, + {0xfa43, 0, 0, 0, f(No, false, "暑")}, + {0xfa44, 0, 0, 0, f(No, false, "梅")}, + {0xfa45, 0, 0, 0, f(No, false, "海")}, + {0xfa46, 0, 0, 0, f(No, false, "渚")}, + {0xfa47, 0, 0, 0, f(No, false, "漢")}, + {0xfa48, 0, 0, 0, f(No, false, "煮")}, + {0xfa49, 0, 0, 0, f(No, false, "爫")}, + {0xfa4a, 0, 0, 0, f(No, false, "琢")}, + {0xfa4b, 0, 0, 0, f(No, false, "碑")}, + {0xfa4c, 0, 0, 0, f(No, false, "社")}, + {0xfa4d, 0, 0, 0, f(No, false, "祉")}, + {0xfa4e, 0, 0, 0, f(No, false, "祈")}, + {0xfa4f, 0, 0, 0, f(No, false, "祐")}, + {0xfa50, 0, 0, 0, f(No, false, "祖")}, + {0xfa51, 0, 0, 0, f(No, false, "祝")}, + {0xfa52, 0, 0, 0, f(No, false, "禍")}, + {0xfa53, 0, 0, 0, f(No, false, "禎")}, + {0xfa54, 0, 0, 0, f(No, false, "穀")}, + {0xfa55, 0, 0, 0, f(No, false, "突")}, + {0xfa56, 0, 0, 0, f(No, false, "節")}, + {0xfa57, 0, 0, 0, f(No, false, "練")}, + {0xfa58, 0, 0, 0, f(No, false, "縉")}, + {0xfa59, 0, 0, 0, f(No, false, "繁")}, + {0xfa5a, 0, 0, 0, f(No, false, "署")}, + {0xfa5b, 0, 0, 0, f(No, false, "者")}, + {0xfa5c, 0, 0, 0, f(No, false, "臭")}, + {0xfa5d, 0, 0, 0, f(No, false, "艹")}, + {0xfa5f, 0, 0, 0, f(No, false, "著")}, + {0xfa60, 0, 0, 0, f(No, false, "褐")}, + {0xfa61, 0, 0, 0, f(No, false, "視")}, + {0xfa62, 0, 0, 0, f(No, false, "謁")}, + {0xfa63, 0, 0, 0, f(No, false, "謹")}, + {0xfa64, 0, 0, 0, f(No, false, "賓")}, + {0xfa65, 0, 0, 0, f(No, false, "贈")}, + {0xfa66, 0, 0, 0, f(No, false, "辶")}, + {0xfa67, 0, 0, 0, f(No, false, "逸")}, + {0xfa68, 0, 0, 0, f(No, false, "難")}, + {0xfa69, 0, 0, 0, f(No, false, "響")}, + {0xfa6a, 0, 0, 0, f(No, false, "頻")}, + {0xfa6b, 0, 0, 0, f(No, false, "恵")}, + {0xfa6c, 0, 0, 0, f(No, false, "𤋮")}, + {0xfa6d, 0, 0, 0, f(No, false, "舘")}, + {0xfa6e, 0, 0, 0, f(Yes, false, "")}, + {0xfa70, 0, 0, 0, f(No, false, "並")}, + {0xfa71, 0, 0, 0, f(No, false, "况")}, + {0xfa72, 0, 0, 0, f(No, false, "全")}, + {0xfa73, 0, 0, 0, f(No, false, "侀")}, + {0xfa74, 0, 0, 0, f(No, false, "充")}, + {0xfa75, 0, 0, 0, f(No, false, "冀")}, + {0xfa76, 0, 0, 0, f(No, false, "勇")}, + {0xfa77, 0, 0, 0, f(No, false, "勺")}, + {0xfa78, 0, 0, 0, f(No, false, "喝")}, + {0xfa79, 0, 0, 0, f(No, false, "啕")}, + {0xfa7a, 0, 0, 0, f(No, false, "喙")}, + {0xfa7b, 0, 0, 0, f(No, false, "嗢")}, + {0xfa7c, 0, 0, 0, f(No, false, "塚")}, + {0xfa7d, 0, 0, 0, f(No, false, "墳")}, + {0xfa7e, 0, 0, 0, f(No, false, "奄")}, + {0xfa7f, 0, 0, 0, f(No, false, "奔")}, + {0xfa80, 0, 0, 0, f(No, false, "婢")}, + {0xfa81, 0, 0, 0, f(No, false, "嬨")}, + {0xfa82, 0, 0, 0, f(No, false, "廒")}, + {0xfa83, 0, 0, 0, f(No, false, "廙")}, + {0xfa84, 0, 0, 0, f(No, false, "彩")}, + {0xfa85, 0, 0, 0, f(No, false, "徭")}, + {0xfa86, 0, 0, 0, f(No, false, "惘")}, + {0xfa87, 0, 0, 0, f(No, false, "慎")}, + {0xfa88, 0, 0, 0, f(No, false, "愈")}, + {0xfa89, 0, 0, 0, f(No, false, "憎")}, + {0xfa8a, 0, 0, 0, f(No, false, "慠")}, + {0xfa8b, 0, 0, 0, f(No, false, "懲")}, + {0xfa8c, 0, 0, 0, f(No, false, "戴")}, + {0xfa8d, 0, 0, 0, f(No, false, "揄")}, + {0xfa8e, 0, 0, 0, f(No, false, "搜")}, + {0xfa8f, 0, 0, 0, f(No, false, "摒")}, + {0xfa90, 0, 0, 0, f(No, false, "敖")}, + {0xfa91, 0, 0, 0, f(No, false, "晴")}, + {0xfa92, 0, 0, 0, f(No, false, "朗")}, + {0xfa93, 0, 0, 0, f(No, false, "望")}, + {0xfa94, 0, 0, 0, f(No, false, "杖")}, + {0xfa95, 0, 0, 0, f(No, false, "歹")}, + {0xfa96, 0, 0, 0, f(No, false, "殺")}, + {0xfa97, 0, 0, 0, f(No, false, "流")}, + {0xfa98, 0, 0, 0, f(No, false, "滛")}, + {0xfa99, 0, 0, 0, f(No, false, "滋")}, + {0xfa9a, 0, 0, 0, f(No, false, "漢")}, + {0xfa9b, 0, 0, 0, f(No, false, "瀞")}, + {0xfa9c, 0, 0, 0, f(No, false, "煮")}, + {0xfa9d, 0, 0, 0, f(No, false, "瞧")}, + {0xfa9e, 0, 0, 0, f(No, false, "爵")}, + {0xfa9f, 0, 0, 0, f(No, false, "犯")}, + {0xfaa0, 0, 0, 0, f(No, false, "猪")}, + {0xfaa1, 0, 0, 0, f(No, false, "瑱")}, + {0xfaa2, 0, 0, 0, f(No, false, "甆")}, + {0xfaa3, 0, 0, 0, f(No, false, "画")}, + {0xfaa4, 0, 0, 0, f(No, false, "瘝")}, + {0xfaa5, 0, 0, 0, f(No, false, "瘟")}, + {0xfaa6, 0, 0, 0, f(No, false, "益")}, + {0xfaa7, 0, 0, 0, f(No, false, "盛")}, + {0xfaa8, 0, 0, 0, f(No, false, "直")}, + {0xfaa9, 0, 0, 0, f(No, false, "睊")}, + {0xfaaa, 0, 0, 0, f(No, false, "着")}, + {0xfaab, 0, 0, 0, f(No, false, "磌")}, + {0xfaac, 0, 0, 0, f(No, false, "窱")}, + {0xfaad, 0, 0, 0, f(No, false, "節")}, + {0xfaae, 0, 0, 0, f(No, false, "类")}, + {0xfaaf, 0, 0, 0, f(No, false, "絛")}, + {0xfab0, 0, 0, 0, f(No, false, "練")}, + {0xfab1, 0, 0, 0, f(No, false, "缾")}, + {0xfab2, 0, 0, 0, f(No, false, "者")}, + {0xfab3, 0, 0, 0, f(No, false, "荒")}, + {0xfab4, 0, 0, 0, f(No, false, "華")}, + {0xfab5, 0, 0, 0, f(No, false, "蝹")}, + {0xfab6, 0, 0, 0, f(No, false, "襁")}, + {0xfab7, 0, 0, 0, f(No, false, "覆")}, + {0xfab8, 0, 0, 0, f(No, false, "視")}, + {0xfab9, 0, 0, 0, f(No, false, "調")}, + {0xfaba, 0, 0, 0, f(No, false, "諸")}, + {0xfabb, 0, 0, 0, f(No, false, "請")}, + {0xfabc, 0, 0, 0, f(No, false, "謁")}, + {0xfabd, 0, 0, 0, f(No, false, "諾")}, + {0xfabe, 0, 0, 0, f(No, false, "諭")}, + {0xfabf, 0, 0, 0, f(No, false, "謹")}, + {0xfac0, 0, 0, 0, f(No, false, "變")}, + {0xfac1, 0, 0, 0, f(No, false, "贈")}, + {0xfac2, 0, 0, 0, f(No, false, "輸")}, + {0xfac3, 0, 0, 0, f(No, false, "遲")}, + {0xfac4, 0, 0, 0, f(No, false, "醙")}, + {0xfac5, 0, 0, 0, f(No, false, "鉶")}, + {0xfac6, 0, 0, 0, f(No, false, "陼")}, + {0xfac7, 0, 0, 0, f(No, false, "難")}, + {0xfac8, 0, 0, 0, f(No, false, "靖")}, + {0xfac9, 0, 0, 0, f(No, false, "韛")}, + {0xfaca, 0, 0, 0, f(No, false, "響")}, + {0xfacb, 0, 0, 0, f(No, false, "頋")}, + {0xfacc, 0, 0, 0, f(No, false, "頻")}, + {0xfacd, 0, 0, 0, f(No, false, "鬒")}, + {0xface, 0, 0, 0, f(No, false, "龜")}, + {0xfacf, 0, 0, 0, f(No, false, "𢡊")}, + {0xfad0, 0, 0, 0, f(No, false, "𢡄")}, + {0xfad1, 0, 0, 0, f(No, false, "𣏕")}, + {0xfad2, 0, 0, 0, f(No, false, "㮝")}, + {0xfad3, 0, 0, 0, f(No, false, "䀘")}, + {0xfad4, 0, 0, 0, f(No, false, "䀹")}, + {0xfad5, 0, 0, 0, f(No, false, "𥉉")}, + {0xfad6, 0, 0, 0, f(No, false, "𥳐")}, + {0xfad7, 0, 0, 0, f(No, false, "𧻓")}, + {0xfad8, 0, 0, 0, f(No, false, "齃")}, + {0xfad9, 0, 0, 0, f(No, false, "龎")}, + {0xfada, 0, 0, 0, f(Yes, false, "")}, + {0xfb00, 0, 0, 0, g(Yes, No, false, false, "", "ff")}, + {0xfb01, 0, 0, 0, g(Yes, No, false, false, "", "fi")}, + {0xfb02, 0, 0, 0, g(Yes, No, false, false, "", "fl")}, + {0xfb03, 0, 0, 0, g(Yes, No, false, false, "", "ffi")}, + {0xfb04, 0, 0, 0, g(Yes, No, false, false, "", "ffl")}, + {0xfb05, 0, 0, 0, g(Yes, No, false, false, "", "st")}, + {0xfb07, 0, 0, 0, f(Yes, false, "")}, + {0xfb13, 0, 0, 0, g(Yes, No, false, false, "", "մն")}, + {0xfb14, 0, 0, 0, g(Yes, No, false, false, "", "մե")}, + {0xfb15, 0, 0, 0, g(Yes, No, false, false, "", "մի")}, + {0xfb16, 0, 0, 0, g(Yes, No, false, false, "", "վն")}, + {0xfb17, 0, 0, 0, g(Yes, No, false, false, "", "մխ")}, + {0xfb18, 0, 0, 0, f(Yes, false, "")}, + {0xfb1d, 0, 0, 1, f(No, false, "יִ")}, + {0xfb1e, 26, 1, 1, f(Yes, false, "")}, + {0xfb1f, 0, 0, 1, f(No, false, "ײַ")}, + {0xfb20, 0, 0, 0, g(Yes, No, false, false, "", "ע")}, + {0xfb21, 0, 0, 0, g(Yes, No, false, false, "", "א")}, + {0xfb22, 0, 0, 0, g(Yes, No, false, false, "", "ד")}, + {0xfb23, 0, 0, 0, g(Yes, No, false, false, "", "ה")}, + {0xfb24, 0, 0, 0, g(Yes, No, false, false, "", "כ")}, + {0xfb25, 0, 0, 0, g(Yes, No, false, false, "", "ל")}, + {0xfb26, 0, 0, 0, g(Yes, No, false, false, "", "ם")}, + {0xfb27, 0, 0, 0, g(Yes, No, false, false, "", "ר")}, + {0xfb28, 0, 0, 0, g(Yes, No, false, false, "", "ת")}, + {0xfb29, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0xfb2a, 0, 0, 1, f(No, false, "שׁ")}, + {0xfb2b, 0, 0, 1, f(No, false, "שׂ")}, + {0xfb2c, 0, 0, 2, f(No, false, "שּׁ")}, + {0xfb2d, 0, 0, 2, f(No, false, "שּׂ")}, + {0xfb2e, 0, 0, 1, f(No, false, "אַ")}, + {0xfb2f, 0, 0, 1, f(No, false, "אָ")}, + {0xfb30, 0, 0, 1, f(No, false, "אּ")}, + {0xfb31, 0, 0, 1, f(No, false, "בּ")}, + {0xfb32, 0, 0, 1, f(No, false, "גּ")}, + {0xfb33, 0, 0, 1, f(No, false, "דּ")}, + {0xfb34, 0, 0, 1, f(No, false, "הּ")}, + {0xfb35, 0, 0, 1, f(No, false, "וּ")}, + {0xfb36, 0, 0, 1, f(No, false, "זּ")}, + {0xfb37, 0, 0, 0, f(Yes, false, "")}, + {0xfb38, 0, 0, 1, f(No, false, "טּ")}, + {0xfb39, 0, 0, 1, f(No, false, "יּ")}, + {0xfb3a, 0, 0, 1, f(No, false, "ךּ")}, + {0xfb3b, 0, 0, 1, f(No, false, "כּ")}, + {0xfb3c, 0, 0, 1, f(No, false, "לּ")}, + {0xfb3d, 0, 0, 0, f(Yes, false, "")}, + {0xfb3e, 0, 0, 1, f(No, false, "מּ")}, + {0xfb3f, 0, 0, 0, f(Yes, false, "")}, + {0xfb40, 0, 0, 1, f(No, false, "נּ")}, + {0xfb41, 0, 0, 1, f(No, false, "סּ")}, + {0xfb42, 0, 0, 0, f(Yes, false, "")}, + {0xfb43, 0, 0, 1, f(No, false, "ףּ")}, + {0xfb44, 0, 0, 1, f(No, false, "פּ")}, + {0xfb45, 0, 0, 0, f(Yes, false, "")}, + {0xfb46, 0, 0, 1, f(No, false, "צּ")}, + {0xfb47, 0, 0, 1, f(No, false, "קּ")}, + {0xfb48, 0, 0, 1, f(No, false, "רּ")}, + {0xfb49, 0, 0, 1, f(No, false, "שּ")}, + {0xfb4a, 0, 0, 1, f(No, false, "תּ")}, + {0xfb4b, 0, 0, 1, f(No, false, "וֹ")}, + {0xfb4c, 0, 0, 1, f(No, false, "בֿ")}, + {0xfb4d, 0, 0, 1, f(No, false, "כֿ")}, + {0xfb4e, 0, 0, 1, f(No, false, "פֿ")}, + {0xfb4f, 0, 0, 0, g(Yes, No, false, false, "", "אל")}, + {0xfb50, 0, 0, 0, g(Yes, No, false, false, "", "ٱ")}, + {0xfb52, 0, 0, 0, g(Yes, No, false, false, "", "ٻ")}, + {0xfb56, 0, 0, 0, g(Yes, No, false, false, "", "پ")}, + {0xfb5a, 0, 0, 0, g(Yes, No, false, false, "", "ڀ")}, + {0xfb5e, 0, 0, 0, g(Yes, No, false, false, "", "ٺ")}, + {0xfb62, 0, 0, 0, g(Yes, No, false, false, "", "ٿ")}, + {0xfb66, 0, 0, 0, g(Yes, No, false, false, "", "ٹ")}, + {0xfb6a, 0, 0, 0, g(Yes, No, false, false, "", "ڤ")}, + {0xfb6e, 0, 0, 0, g(Yes, No, false, false, "", "ڦ")}, + {0xfb72, 0, 0, 0, g(Yes, No, false, false, "", "ڄ")}, + {0xfb76, 0, 0, 0, g(Yes, No, false, false, "", "ڃ")}, + {0xfb7a, 0, 0, 0, g(Yes, No, false, false, "", "چ")}, + {0xfb7e, 0, 0, 0, g(Yes, No, false, false, "", "ڇ")}, + {0xfb82, 0, 0, 0, g(Yes, No, false, false, "", "ڍ")}, + {0xfb84, 0, 0, 0, g(Yes, No, false, false, "", "ڌ")}, + {0xfb86, 0, 0, 0, g(Yes, No, false, false, "", "ڎ")}, + {0xfb88, 0, 0, 0, g(Yes, No, false, false, "", "ڈ")}, + {0xfb8a, 0, 0, 0, g(Yes, No, false, false, "", "ژ")}, + {0xfb8c, 0, 0, 0, g(Yes, No, false, false, "", "ڑ")}, + {0xfb8e, 0, 0, 0, g(Yes, No, false, false, "", "ک")}, + {0xfb92, 0, 0, 0, g(Yes, No, false, false, "", "گ")}, + {0xfb96, 0, 0, 0, g(Yes, No, false, false, "", "ڳ")}, + {0xfb9a, 0, 0, 0, g(Yes, No, false, false, "", "ڱ")}, + {0xfb9e, 0, 0, 0, g(Yes, No, false, false, "", "ں")}, + {0xfba0, 0, 0, 0, g(Yes, No, false, false, "", "ڻ")}, + {0xfba4, 0, 0, 1, g(Yes, No, false, false, "", "ۀ")}, + {0xfba6, 0, 0, 0, g(Yes, No, false, false, "", "ہ")}, + {0xfbaa, 0, 0, 0, g(Yes, No, false, false, "", "ھ")}, + {0xfbae, 0, 0, 0, g(Yes, No, false, false, "", "ے")}, + {0xfbb0, 0, 0, 1, g(Yes, No, false, false, "", "ۓ")}, + {0xfbb2, 0, 0, 0, f(Yes, false, "")}, + {0xfbd3, 0, 0, 0, g(Yes, No, false, false, "", "ڭ")}, + {0xfbd7, 0, 0, 0, g(Yes, No, false, false, "", "ۇ")}, + {0xfbd9, 0, 0, 0, g(Yes, No, false, false, "", "ۆ")}, + {0xfbdb, 0, 0, 0, g(Yes, No, false, false, "", "ۈ")}, + {0xfbdd, 0, 0, 0, g(Yes, No, false, false, "", "ۇٴ")}, + {0xfbde, 0, 0, 0, g(Yes, No, false, false, "", "ۋ")}, + {0xfbe0, 0, 0, 0, g(Yes, No, false, false, "", "ۅ")}, + {0xfbe2, 0, 0, 0, g(Yes, No, false, false, "", "ۉ")}, + {0xfbe4, 0, 0, 0, g(Yes, No, false, false, "", "ې")}, + {0xfbe8, 0, 0, 0, g(Yes, No, false, false, "", "ى")}, + {0xfbea, 0, 0, 0, g(Yes, No, false, false, "", "ئا")}, + {0xfbec, 0, 0, 0, g(Yes, No, false, false, "", "ئە")}, + {0xfbee, 0, 0, 0, g(Yes, No, false, false, "", "ئو")}, + {0xfbf0, 0, 0, 0, g(Yes, No, false, false, "", "ئۇ")}, + {0xfbf2, 0, 0, 0, g(Yes, No, false, false, "", "ئۆ")}, + {0xfbf4, 0, 0, 0, g(Yes, No, false, false, "", "ئۈ")}, + {0xfbf6, 0, 0, 0, g(Yes, No, false, false, "", "ئې")}, + {0xfbf9, 0, 0, 0, g(Yes, No, false, false, "", "ئى")}, + {0xfbfc, 0, 0, 0, g(Yes, No, false, false, "", "ی")}, + {0xfc00, 0, 0, 0, g(Yes, No, false, false, "", "ئج")}, + {0xfc01, 0, 0, 0, g(Yes, No, false, false, "", "ئح")}, + {0xfc02, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfc03, 0, 0, 0, g(Yes, No, false, false, "", "ئى")}, + {0xfc04, 0, 0, 0, g(Yes, No, false, false, "", "ئي")}, + {0xfc05, 0, 0, 0, g(Yes, No, false, false, "", "بج")}, + {0xfc06, 0, 0, 0, g(Yes, No, false, false, "", "بح")}, + {0xfc07, 0, 0, 0, g(Yes, No, false, false, "", "بخ")}, + {0xfc08, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfc09, 0, 0, 0, g(Yes, No, false, false, "", "بى")}, + {0xfc0a, 0, 0, 0, g(Yes, No, false, false, "", "بي")}, + {0xfc0b, 0, 0, 0, g(Yes, No, false, false, "", "تج")}, + {0xfc0c, 0, 0, 0, g(Yes, No, false, false, "", "تح")}, + {0xfc0d, 0, 0, 0, g(Yes, No, false, false, "", "تخ")}, + {0xfc0e, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfc0f, 0, 0, 0, g(Yes, No, false, false, "", "تى")}, + {0xfc10, 0, 0, 0, g(Yes, No, false, false, "", "تي")}, + {0xfc11, 0, 0, 0, g(Yes, No, false, false, "", "ثج")}, + {0xfc12, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfc13, 0, 0, 0, g(Yes, No, false, false, "", "ثى")}, + {0xfc14, 0, 0, 0, g(Yes, No, false, false, "", "ثي")}, + {0xfc15, 0, 0, 0, g(Yes, No, false, false, "", "جح")}, + {0xfc16, 0, 0, 0, g(Yes, No, false, false, "", "جم")}, + {0xfc17, 0, 0, 0, g(Yes, No, false, false, "", "حج")}, + {0xfc18, 0, 0, 0, g(Yes, No, false, false, "", "حم")}, + {0xfc19, 0, 0, 0, g(Yes, No, false, false, "", "خج")}, + {0xfc1a, 0, 0, 0, g(Yes, No, false, false, "", "خح")}, + {0xfc1b, 0, 0, 0, g(Yes, No, false, false, "", "خم")}, + {0xfc1c, 0, 0, 0, g(Yes, No, false, false, "", "سج")}, + {0xfc1d, 0, 0, 0, g(Yes, No, false, false, "", "سح")}, + {0xfc1e, 0, 0, 0, g(Yes, No, false, false, "", "سخ")}, + {0xfc1f, 0, 0, 0, g(Yes, No, false, false, "", "سم")}, + {0xfc20, 0, 0, 0, g(Yes, No, false, false, "", "صح")}, + {0xfc21, 0, 0, 0, g(Yes, No, false, false, "", "صم")}, + {0xfc22, 0, 0, 0, g(Yes, No, false, false, "", "ضج")}, + {0xfc23, 0, 0, 0, g(Yes, No, false, false, "", "ضح")}, + {0xfc24, 0, 0, 0, g(Yes, No, false, false, "", "ضخ")}, + {0xfc25, 0, 0, 0, g(Yes, No, false, false, "", "ضم")}, + {0xfc26, 0, 0, 0, g(Yes, No, false, false, "", "طح")}, + {0xfc27, 0, 0, 0, g(Yes, No, false, false, "", "طم")}, + {0xfc28, 0, 0, 0, g(Yes, No, false, false, "", "ظم")}, + {0xfc29, 0, 0, 0, g(Yes, No, false, false, "", "عج")}, + {0xfc2a, 0, 0, 0, g(Yes, No, false, false, "", "عم")}, + {0xfc2b, 0, 0, 0, g(Yes, No, false, false, "", "غج")}, + {0xfc2c, 0, 0, 0, g(Yes, No, false, false, "", "غم")}, + {0xfc2d, 0, 0, 0, g(Yes, No, false, false, "", "فج")}, + {0xfc2e, 0, 0, 0, g(Yes, No, false, false, "", "فح")}, + {0xfc2f, 0, 0, 0, g(Yes, No, false, false, "", "فخ")}, + {0xfc30, 0, 0, 0, g(Yes, No, false, false, "", "فم")}, + {0xfc31, 0, 0, 0, g(Yes, No, false, false, "", "فى")}, + {0xfc32, 0, 0, 0, g(Yes, No, false, false, "", "في")}, + {0xfc33, 0, 0, 0, g(Yes, No, false, false, "", "قح")}, + {0xfc34, 0, 0, 0, g(Yes, No, false, false, "", "قم")}, + {0xfc35, 0, 0, 0, g(Yes, No, false, false, "", "قى")}, + {0xfc36, 0, 0, 0, g(Yes, No, false, false, "", "قي")}, + {0xfc37, 0, 0, 0, g(Yes, No, false, false, "", "كا")}, + {0xfc38, 0, 0, 0, g(Yes, No, false, false, "", "كج")}, + {0xfc39, 0, 0, 0, g(Yes, No, false, false, "", "كح")}, + {0xfc3a, 0, 0, 0, g(Yes, No, false, false, "", "كخ")}, + {0xfc3b, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfc3c, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfc3d, 0, 0, 0, g(Yes, No, false, false, "", "كى")}, + {0xfc3e, 0, 0, 0, g(Yes, No, false, false, "", "كي")}, + {0xfc3f, 0, 0, 0, g(Yes, No, false, false, "", "لج")}, + {0xfc40, 0, 0, 0, g(Yes, No, false, false, "", "لح")}, + {0xfc41, 0, 0, 0, g(Yes, No, false, false, "", "لخ")}, + {0xfc42, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfc43, 0, 0, 0, g(Yes, No, false, false, "", "لى")}, + {0xfc44, 0, 0, 0, g(Yes, No, false, false, "", "لي")}, + {0xfc45, 0, 0, 0, g(Yes, No, false, false, "", "مج")}, + {0xfc46, 0, 0, 0, g(Yes, No, false, false, "", "مح")}, + {0xfc47, 0, 0, 0, g(Yes, No, false, false, "", "مخ")}, + {0xfc48, 0, 0, 0, g(Yes, No, false, false, "", "مم")}, + {0xfc49, 0, 0, 0, g(Yes, No, false, false, "", "مى")}, + {0xfc4a, 0, 0, 0, g(Yes, No, false, false, "", "مي")}, + {0xfc4b, 0, 0, 0, g(Yes, No, false, false, "", "نج")}, + {0xfc4c, 0, 0, 0, g(Yes, No, false, false, "", "نح")}, + {0xfc4d, 0, 0, 0, g(Yes, No, false, false, "", "نخ")}, + {0xfc4e, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfc4f, 0, 0, 0, g(Yes, No, false, false, "", "نى")}, + {0xfc50, 0, 0, 0, g(Yes, No, false, false, "", "ني")}, + {0xfc51, 0, 0, 0, g(Yes, No, false, false, "", "هج")}, + {0xfc52, 0, 0, 0, g(Yes, No, false, false, "", "هم")}, + {0xfc53, 0, 0, 0, g(Yes, No, false, false, "", "هى")}, + {0xfc54, 0, 0, 0, g(Yes, No, false, false, "", "هي")}, + {0xfc55, 0, 0, 0, g(Yes, No, false, false, "", "يج")}, + {0xfc56, 0, 0, 0, g(Yes, No, false, false, "", "يح")}, + {0xfc57, 0, 0, 0, g(Yes, No, false, false, "", "يخ")}, + {0xfc58, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfc59, 0, 0, 0, g(Yes, No, false, false, "", "يى")}, + {0xfc5a, 0, 0, 0, g(Yes, No, false, false, "", "يي")}, + {0xfc5b, 0, 0, 1, g(Yes, No, false, false, "", "ذٰ")}, + {0xfc5c, 0, 0, 1, g(Yes, No, false, false, "", "رٰ")}, + {0xfc5d, 0, 0, 1, g(Yes, No, false, false, "", "ىٰ")}, + {0xfc5e, 0, 0, 2, g(Yes, No, false, false, "", " ٌّ")}, + {0xfc5f, 0, 0, 2, g(Yes, No, false, false, "", " ٍّ")}, + {0xfc60, 0, 0, 2, g(Yes, No, false, false, "", " َّ")}, + {0xfc61, 0, 0, 2, g(Yes, No, false, false, "", " ُّ")}, + {0xfc62, 0, 0, 2, g(Yes, No, false, false, "", " ِّ")}, + {0xfc63, 0, 0, 2, g(Yes, No, false, false, "", " ّٰ")}, + {0xfc64, 0, 0, 0, g(Yes, No, false, false, "", "ئر")}, + {0xfc65, 0, 0, 0, g(Yes, No, false, false, "", "ئز")}, + {0xfc66, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfc67, 0, 0, 0, g(Yes, No, false, false, "", "ئن")}, + {0xfc68, 0, 0, 0, g(Yes, No, false, false, "", "ئى")}, + {0xfc69, 0, 0, 0, g(Yes, No, false, false, "", "ئي")}, + {0xfc6a, 0, 0, 0, g(Yes, No, false, false, "", "بر")}, + {0xfc6b, 0, 0, 0, g(Yes, No, false, false, "", "بز")}, + {0xfc6c, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfc6d, 0, 0, 0, g(Yes, No, false, false, "", "بن")}, + {0xfc6e, 0, 0, 0, g(Yes, No, false, false, "", "بى")}, + {0xfc6f, 0, 0, 0, g(Yes, No, false, false, "", "بي")}, + {0xfc70, 0, 0, 0, g(Yes, No, false, false, "", "تر")}, + {0xfc71, 0, 0, 0, g(Yes, No, false, false, "", "تز")}, + {0xfc72, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfc73, 0, 0, 0, g(Yes, No, false, false, "", "تن")}, + {0xfc74, 0, 0, 0, g(Yes, No, false, false, "", "تى")}, + {0xfc75, 0, 0, 0, g(Yes, No, false, false, "", "تي")}, + {0xfc76, 0, 0, 0, g(Yes, No, false, false, "", "ثر")}, + {0xfc77, 0, 0, 0, g(Yes, No, false, false, "", "ثز")}, + {0xfc78, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfc79, 0, 0, 0, g(Yes, No, false, false, "", "ثن")}, + {0xfc7a, 0, 0, 0, g(Yes, No, false, false, "", "ثى")}, + {0xfc7b, 0, 0, 0, g(Yes, No, false, false, "", "ثي")}, + {0xfc7c, 0, 0, 0, g(Yes, No, false, false, "", "فى")}, + {0xfc7d, 0, 0, 0, g(Yes, No, false, false, "", "في")}, + {0xfc7e, 0, 0, 0, g(Yes, No, false, false, "", "قى")}, + {0xfc7f, 0, 0, 0, g(Yes, No, false, false, "", "قي")}, + {0xfc80, 0, 0, 0, g(Yes, No, false, false, "", "كا")}, + {0xfc81, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfc82, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfc83, 0, 0, 0, g(Yes, No, false, false, "", "كى")}, + {0xfc84, 0, 0, 0, g(Yes, No, false, false, "", "كي")}, + {0xfc85, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfc86, 0, 0, 0, g(Yes, No, false, false, "", "لى")}, + {0xfc87, 0, 0, 0, g(Yes, No, false, false, "", "لي")}, + {0xfc88, 0, 0, 0, g(Yes, No, false, false, "", "ما")}, + {0xfc89, 0, 0, 0, g(Yes, No, false, false, "", "مم")}, + {0xfc8a, 0, 0, 0, g(Yes, No, false, false, "", "نر")}, + {0xfc8b, 0, 0, 0, g(Yes, No, false, false, "", "نز")}, + {0xfc8c, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfc8d, 0, 0, 0, g(Yes, No, false, false, "", "نن")}, + {0xfc8e, 0, 0, 0, g(Yes, No, false, false, "", "نى")}, + {0xfc8f, 0, 0, 0, g(Yes, No, false, false, "", "ني")}, + {0xfc90, 0, 0, 1, g(Yes, No, false, false, "", "ىٰ")}, + {0xfc91, 0, 0, 0, g(Yes, No, false, false, "", "ير")}, + {0xfc92, 0, 0, 0, g(Yes, No, false, false, "", "يز")}, + {0xfc93, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfc94, 0, 0, 0, g(Yes, No, false, false, "", "ين")}, + {0xfc95, 0, 0, 0, g(Yes, No, false, false, "", "يى")}, + {0xfc96, 0, 0, 0, g(Yes, No, false, false, "", "يي")}, + {0xfc97, 0, 0, 0, g(Yes, No, false, false, "", "ئج")}, + {0xfc98, 0, 0, 0, g(Yes, No, false, false, "", "ئح")}, + {0xfc99, 0, 0, 0, g(Yes, No, false, false, "", "ئخ")}, + {0xfc9a, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfc9b, 0, 0, 0, g(Yes, No, false, false, "", "ئه")}, + {0xfc9c, 0, 0, 0, g(Yes, No, false, false, "", "بج")}, + {0xfc9d, 0, 0, 0, g(Yes, No, false, false, "", "بح")}, + {0xfc9e, 0, 0, 0, g(Yes, No, false, false, "", "بخ")}, + {0xfc9f, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfca0, 0, 0, 0, g(Yes, No, false, false, "", "به")}, + {0xfca1, 0, 0, 0, g(Yes, No, false, false, "", "تج")}, + {0xfca2, 0, 0, 0, g(Yes, No, false, false, "", "تح")}, + {0xfca3, 0, 0, 0, g(Yes, No, false, false, "", "تخ")}, + {0xfca4, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfca5, 0, 0, 0, g(Yes, No, false, false, "", "ته")}, + {0xfca6, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfca7, 0, 0, 0, g(Yes, No, false, false, "", "جح")}, + {0xfca8, 0, 0, 0, g(Yes, No, false, false, "", "جم")}, + {0xfca9, 0, 0, 0, g(Yes, No, false, false, "", "حج")}, + {0xfcaa, 0, 0, 0, g(Yes, No, false, false, "", "حم")}, + {0xfcab, 0, 0, 0, g(Yes, No, false, false, "", "خج")}, + {0xfcac, 0, 0, 0, g(Yes, No, false, false, "", "خم")}, + {0xfcad, 0, 0, 0, g(Yes, No, false, false, "", "سج")}, + {0xfcae, 0, 0, 0, g(Yes, No, false, false, "", "سح")}, + {0xfcaf, 0, 0, 0, g(Yes, No, false, false, "", "سخ")}, + {0xfcb0, 0, 0, 0, g(Yes, No, false, false, "", "سم")}, + {0xfcb1, 0, 0, 0, g(Yes, No, false, false, "", "صح")}, + {0xfcb2, 0, 0, 0, g(Yes, No, false, false, "", "صخ")}, + {0xfcb3, 0, 0, 0, g(Yes, No, false, false, "", "صم")}, + {0xfcb4, 0, 0, 0, g(Yes, No, false, false, "", "ضج")}, + {0xfcb5, 0, 0, 0, g(Yes, No, false, false, "", "ضح")}, + {0xfcb6, 0, 0, 0, g(Yes, No, false, false, "", "ضخ")}, + {0xfcb7, 0, 0, 0, g(Yes, No, false, false, "", "ضم")}, + {0xfcb8, 0, 0, 0, g(Yes, No, false, false, "", "طح")}, + {0xfcb9, 0, 0, 0, g(Yes, No, false, false, "", "ظم")}, + {0xfcba, 0, 0, 0, g(Yes, No, false, false, "", "عج")}, + {0xfcbb, 0, 0, 0, g(Yes, No, false, false, "", "عم")}, + {0xfcbc, 0, 0, 0, g(Yes, No, false, false, "", "غج")}, + {0xfcbd, 0, 0, 0, g(Yes, No, false, false, "", "غم")}, + {0xfcbe, 0, 0, 0, g(Yes, No, false, false, "", "فج")}, + {0xfcbf, 0, 0, 0, g(Yes, No, false, false, "", "فح")}, + {0xfcc0, 0, 0, 0, g(Yes, No, false, false, "", "فخ")}, + {0xfcc1, 0, 0, 0, g(Yes, No, false, false, "", "فم")}, + {0xfcc2, 0, 0, 0, g(Yes, No, false, false, "", "قح")}, + {0xfcc3, 0, 0, 0, g(Yes, No, false, false, "", "قم")}, + {0xfcc4, 0, 0, 0, g(Yes, No, false, false, "", "كج")}, + {0xfcc5, 0, 0, 0, g(Yes, No, false, false, "", "كح")}, + {0xfcc6, 0, 0, 0, g(Yes, No, false, false, "", "كخ")}, + {0xfcc7, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfcc8, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfcc9, 0, 0, 0, g(Yes, No, false, false, "", "لج")}, + {0xfcca, 0, 0, 0, g(Yes, No, false, false, "", "لح")}, + {0xfccb, 0, 0, 0, g(Yes, No, false, false, "", "لخ")}, + {0xfccc, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfccd, 0, 0, 0, g(Yes, No, false, false, "", "له")}, + {0xfcce, 0, 0, 0, g(Yes, No, false, false, "", "مج")}, + {0xfccf, 0, 0, 0, g(Yes, No, false, false, "", "مح")}, + {0xfcd0, 0, 0, 0, g(Yes, No, false, false, "", "مخ")}, + {0xfcd1, 0, 0, 0, g(Yes, No, false, false, "", "مم")}, + {0xfcd2, 0, 0, 0, g(Yes, No, false, false, "", "نج")}, + {0xfcd3, 0, 0, 0, g(Yes, No, false, false, "", "نح")}, + {0xfcd4, 0, 0, 0, g(Yes, No, false, false, "", "نخ")}, + {0xfcd5, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfcd6, 0, 0, 0, g(Yes, No, false, false, "", "نه")}, + {0xfcd7, 0, 0, 0, g(Yes, No, false, false, "", "هج")}, + {0xfcd8, 0, 0, 0, g(Yes, No, false, false, "", "هم")}, + {0xfcd9, 0, 0, 1, g(Yes, No, false, false, "", "هٰ")}, + {0xfcda, 0, 0, 0, g(Yes, No, false, false, "", "يج")}, + {0xfcdb, 0, 0, 0, g(Yes, No, false, false, "", "يح")}, + {0xfcdc, 0, 0, 0, g(Yes, No, false, false, "", "يخ")}, + {0xfcdd, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfcde, 0, 0, 0, g(Yes, No, false, false, "", "يه")}, + {0xfcdf, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfce0, 0, 0, 0, g(Yes, No, false, false, "", "ئه")}, + {0xfce1, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfce2, 0, 0, 0, g(Yes, No, false, false, "", "به")}, + {0xfce3, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfce4, 0, 0, 0, g(Yes, No, false, false, "", "ته")}, + {0xfce5, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfce6, 0, 0, 0, g(Yes, No, false, false, "", "ثه")}, + {0xfce7, 0, 0, 0, g(Yes, No, false, false, "", "سم")}, + {0xfce8, 0, 0, 0, g(Yes, No, false, false, "", "سه")}, + {0xfce9, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfcea, 0, 0, 0, g(Yes, No, false, false, "", "شه")}, + {0xfceb, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfcec, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfced, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfcee, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfcef, 0, 0, 0, g(Yes, No, false, false, "", "نه")}, + {0xfcf0, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfcf1, 0, 0, 0, g(Yes, No, false, false, "", "يه")}, + {0xfcf2, 0, 0, 2, g(Yes, No, false, false, "", "ـَّ")}, + {0xfcf3, 0, 0, 2, g(Yes, No, false, false, "", "ـُّ")}, + {0xfcf4, 0, 0, 2, g(Yes, No, false, false, "", "ـِّ")}, + {0xfcf5, 0, 0, 0, g(Yes, No, false, false, "", "طى")}, + {0xfcf6, 0, 0, 0, g(Yes, No, false, false, "", "طي")}, + {0xfcf7, 0, 0, 0, g(Yes, No, false, false, "", "عى")}, + {0xfcf8, 0, 0, 0, g(Yes, No, false, false, "", "عي")}, + {0xfcf9, 0, 0, 0, g(Yes, No, false, false, "", "غى")}, + {0xfcfa, 0, 0, 0, g(Yes, No, false, false, "", "غي")}, + {0xfcfb, 0, 0, 0, g(Yes, No, false, false, "", "سى")}, + {0xfcfc, 0, 0, 0, g(Yes, No, false, false, "", "سي")}, + {0xfcfd, 0, 0, 0, g(Yes, No, false, false, "", "شى")}, + {0xfcfe, 0, 0, 0, g(Yes, No, false, false, "", "شي")}, + {0xfcff, 0, 0, 0, g(Yes, No, false, false, "", "حى")}, + {0xfd00, 0, 0, 0, g(Yes, No, false, false, "", "حي")}, + {0xfd01, 0, 0, 0, g(Yes, No, false, false, "", "جى")}, + {0xfd02, 0, 0, 0, g(Yes, No, false, false, "", "جي")}, + {0xfd03, 0, 0, 0, g(Yes, No, false, false, "", "خى")}, + {0xfd04, 0, 0, 0, g(Yes, No, false, false, "", "خي")}, + {0xfd05, 0, 0, 0, g(Yes, No, false, false, "", "صى")}, + {0xfd06, 0, 0, 0, g(Yes, No, false, false, "", "صي")}, + {0xfd07, 0, 0, 0, g(Yes, No, false, false, "", "ضى")}, + {0xfd08, 0, 0, 0, g(Yes, No, false, false, "", "ضي")}, + {0xfd09, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd0a, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd0b, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd0c, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfd0d, 0, 0, 0, g(Yes, No, false, false, "", "شر")}, + {0xfd0e, 0, 0, 0, g(Yes, No, false, false, "", "سر")}, + {0xfd0f, 0, 0, 0, g(Yes, No, false, false, "", "صر")}, + {0xfd10, 0, 0, 0, g(Yes, No, false, false, "", "ضر")}, + {0xfd11, 0, 0, 0, g(Yes, No, false, false, "", "طى")}, + {0xfd12, 0, 0, 0, g(Yes, No, false, false, "", "طي")}, + {0xfd13, 0, 0, 0, g(Yes, No, false, false, "", "عى")}, + {0xfd14, 0, 0, 0, g(Yes, No, false, false, "", "عي")}, + {0xfd15, 0, 0, 0, g(Yes, No, false, false, "", "غى")}, + {0xfd16, 0, 0, 0, g(Yes, No, false, false, "", "غي")}, + {0xfd17, 0, 0, 0, g(Yes, No, false, false, "", "سى")}, + {0xfd18, 0, 0, 0, g(Yes, No, false, false, "", "سي")}, + {0xfd19, 0, 0, 0, g(Yes, No, false, false, "", "شى")}, + {0xfd1a, 0, 0, 0, g(Yes, No, false, false, "", "شي")}, + {0xfd1b, 0, 0, 0, g(Yes, No, false, false, "", "حى")}, + {0xfd1c, 0, 0, 0, g(Yes, No, false, false, "", "حي")}, + {0xfd1d, 0, 0, 0, g(Yes, No, false, false, "", "جى")}, + {0xfd1e, 0, 0, 0, g(Yes, No, false, false, "", "جي")}, + {0xfd1f, 0, 0, 0, g(Yes, No, false, false, "", "خى")}, + {0xfd20, 0, 0, 0, g(Yes, No, false, false, "", "خي")}, + {0xfd21, 0, 0, 0, g(Yes, No, false, false, "", "صى")}, + {0xfd22, 0, 0, 0, g(Yes, No, false, false, "", "صي")}, + {0xfd23, 0, 0, 0, g(Yes, No, false, false, "", "ضى")}, + {0xfd24, 0, 0, 0, g(Yes, No, false, false, "", "ضي")}, + {0xfd25, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd26, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd27, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd28, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfd29, 0, 0, 0, g(Yes, No, false, false, "", "شر")}, + {0xfd2a, 0, 0, 0, g(Yes, No, false, false, "", "سر")}, + {0xfd2b, 0, 0, 0, g(Yes, No, false, false, "", "صر")}, + {0xfd2c, 0, 0, 0, g(Yes, No, false, false, "", "ضر")}, + {0xfd2d, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd2e, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd2f, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd30, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfd31, 0, 0, 0, g(Yes, No, false, false, "", "سه")}, + {0xfd32, 0, 0, 0, g(Yes, No, false, false, "", "شه")}, + {0xfd33, 0, 0, 0, g(Yes, No, false, false, "", "طم")}, + {0xfd34, 0, 0, 0, g(Yes, No, false, false, "", "سج")}, + {0xfd35, 0, 0, 0, g(Yes, No, false, false, "", "سح")}, + {0xfd36, 0, 0, 0, g(Yes, No, false, false, "", "سخ")}, + {0xfd37, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd38, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd39, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd3a, 0, 0, 0, g(Yes, No, false, false, "", "طم")}, + {0xfd3b, 0, 0, 0, g(Yes, No, false, false, "", "ظم")}, + {0xfd3c, 0, 0, 1, g(Yes, No, false, false, "", "اً")}, + {0xfd3e, 0, 0, 0, f(Yes, false, "")}, + {0xfd50, 0, 0, 0, g(Yes, No, false, false, "", "تجم")}, + {0xfd51, 0, 0, 0, g(Yes, No, false, false, "", "تحج")}, + {0xfd53, 0, 0, 0, g(Yes, No, false, false, "", "تحم")}, + {0xfd54, 0, 0, 0, g(Yes, No, false, false, "", "تخم")}, + {0xfd55, 0, 0, 0, g(Yes, No, false, false, "", "تمج")}, + {0xfd56, 0, 0, 0, g(Yes, No, false, false, "", "تمح")}, + {0xfd57, 0, 0, 0, g(Yes, No, false, false, "", "تمخ")}, + {0xfd58, 0, 0, 0, g(Yes, No, false, false, "", "جمح")}, + {0xfd5a, 0, 0, 0, g(Yes, No, false, false, "", "حمي")}, + {0xfd5b, 0, 0, 0, g(Yes, No, false, false, "", "حمى")}, + {0xfd5c, 0, 0, 0, g(Yes, No, false, false, "", "سحج")}, + {0xfd5d, 0, 0, 0, g(Yes, No, false, false, "", "سجح")}, + {0xfd5e, 0, 0, 0, g(Yes, No, false, false, "", "سجى")}, + {0xfd5f, 0, 0, 0, g(Yes, No, false, false, "", "سمح")}, + {0xfd61, 0, 0, 0, g(Yes, No, false, false, "", "سمج")}, + {0xfd62, 0, 0, 0, g(Yes, No, false, false, "", "سمم")}, + {0xfd64, 0, 0, 0, g(Yes, No, false, false, "", "صحح")}, + {0xfd66, 0, 0, 0, g(Yes, No, false, false, "", "صمم")}, + {0xfd67, 0, 0, 0, g(Yes, No, false, false, "", "شحم")}, + {0xfd69, 0, 0, 0, g(Yes, No, false, false, "", "شجي")}, + {0xfd6a, 0, 0, 0, g(Yes, No, false, false, "", "شمخ")}, + {0xfd6c, 0, 0, 0, g(Yes, No, false, false, "", "شمم")}, + {0xfd6e, 0, 0, 0, g(Yes, No, false, false, "", "ضحى")}, + {0xfd6f, 0, 0, 0, g(Yes, No, false, false, "", "ضخم")}, + {0xfd71, 0, 0, 0, g(Yes, No, false, false, "", "طمح")}, + {0xfd73, 0, 0, 0, g(Yes, No, false, false, "", "طمم")}, + {0xfd74, 0, 0, 0, g(Yes, No, false, false, "", "طمي")}, + {0xfd75, 0, 0, 0, g(Yes, No, false, false, "", "عجم")}, + {0xfd76, 0, 0, 0, g(Yes, No, false, false, "", "عمم")}, + {0xfd78, 0, 0, 0, g(Yes, No, false, false, "", "عمى")}, + {0xfd79, 0, 0, 0, g(Yes, No, false, false, "", "غمم")}, + {0xfd7a, 0, 0, 0, g(Yes, No, false, false, "", "غمي")}, + {0xfd7b, 0, 0, 0, g(Yes, No, false, false, "", "غمى")}, + {0xfd7c, 0, 0, 0, g(Yes, No, false, false, "", "فخم")}, + {0xfd7e, 0, 0, 0, g(Yes, No, false, false, "", "قمح")}, + {0xfd7f, 0, 0, 0, g(Yes, No, false, false, "", "قمم")}, + {0xfd80, 0, 0, 0, g(Yes, No, false, false, "", "لحم")}, + {0xfd81, 0, 0, 0, g(Yes, No, false, false, "", "لحي")}, + {0xfd82, 0, 0, 0, g(Yes, No, false, false, "", "لحى")}, + {0xfd83, 0, 0, 0, g(Yes, No, false, false, "", "لجج")}, + {0xfd85, 0, 0, 0, g(Yes, No, false, false, "", "لخم")}, + {0xfd87, 0, 0, 0, g(Yes, No, false, false, "", "لمح")}, + {0xfd89, 0, 0, 0, g(Yes, No, false, false, "", "محج")}, + {0xfd8a, 0, 0, 0, g(Yes, No, false, false, "", "محم")}, + {0xfd8b, 0, 0, 0, g(Yes, No, false, false, "", "محي")}, + {0xfd8c, 0, 0, 0, g(Yes, No, false, false, "", "مجح")}, + {0xfd8d, 0, 0, 0, g(Yes, No, false, false, "", "مجم")}, + {0xfd8e, 0, 0, 0, g(Yes, No, false, false, "", "مخج")}, + {0xfd8f, 0, 0, 0, g(Yes, No, false, false, "", "مخم")}, + {0xfd90, 0, 0, 0, f(Yes, false, "")}, + {0xfd92, 0, 0, 0, g(Yes, No, false, false, "", "مجخ")}, + {0xfd93, 0, 0, 0, g(Yes, No, false, false, "", "همج")}, + {0xfd94, 0, 0, 0, g(Yes, No, false, false, "", "همم")}, + {0xfd95, 0, 0, 0, g(Yes, No, false, false, "", "نحم")}, + {0xfd96, 0, 0, 0, g(Yes, No, false, false, "", "نحى")}, + {0xfd97, 0, 0, 0, g(Yes, No, false, false, "", "نجم")}, + {0xfd99, 0, 0, 0, g(Yes, No, false, false, "", "نجى")}, + {0xfd9a, 0, 0, 0, g(Yes, No, false, false, "", "نمي")}, + {0xfd9b, 0, 0, 0, g(Yes, No, false, false, "", "نمى")}, + {0xfd9c, 0, 0, 0, g(Yes, No, false, false, "", "يمم")}, + {0xfd9e, 0, 0, 0, g(Yes, No, false, false, "", "بخي")}, + {0xfd9f, 0, 0, 0, g(Yes, No, false, false, "", "تجي")}, + {0xfda0, 0, 0, 0, g(Yes, No, false, false, "", "تجى")}, + {0xfda1, 0, 0, 0, g(Yes, No, false, false, "", "تخي")}, + {0xfda2, 0, 0, 0, g(Yes, No, false, false, "", "تخى")}, + {0xfda3, 0, 0, 0, g(Yes, No, false, false, "", "تمي")}, + {0xfda4, 0, 0, 0, g(Yes, No, false, false, "", "تمى")}, + {0xfda5, 0, 0, 0, g(Yes, No, false, false, "", "جمي")}, + {0xfda6, 0, 0, 0, g(Yes, No, false, false, "", "جحى")}, + {0xfda7, 0, 0, 0, g(Yes, No, false, false, "", "جمى")}, + {0xfda8, 0, 0, 0, g(Yes, No, false, false, "", "سخى")}, + {0xfda9, 0, 0, 0, g(Yes, No, false, false, "", "صحي")}, + {0xfdaa, 0, 0, 0, g(Yes, No, false, false, "", "شحي")}, + {0xfdab, 0, 0, 0, g(Yes, No, false, false, "", "ضحي")}, + {0xfdac, 0, 0, 0, g(Yes, No, false, false, "", "لجي")}, + {0xfdad, 0, 0, 0, g(Yes, No, false, false, "", "لمي")}, + {0xfdae, 0, 0, 0, g(Yes, No, false, false, "", "يحي")}, + {0xfdaf, 0, 0, 0, g(Yes, No, false, false, "", "يجي")}, + {0xfdb0, 0, 0, 0, g(Yes, No, false, false, "", "يمي")}, + {0xfdb1, 0, 0, 0, g(Yes, No, false, false, "", "ممي")}, + {0xfdb2, 0, 0, 0, g(Yes, No, false, false, "", "قمي")}, + {0xfdb3, 0, 0, 0, g(Yes, No, false, false, "", "نحي")}, + {0xfdb4, 0, 0, 0, g(Yes, No, false, false, "", "قمح")}, + {0xfdb5, 0, 0, 0, g(Yes, No, false, false, "", "لحم")}, + {0xfdb6, 0, 0, 0, g(Yes, No, false, false, "", "عمي")}, + {0xfdb7, 0, 0, 0, g(Yes, No, false, false, "", "كمي")}, + {0xfdb8, 0, 0, 0, g(Yes, No, false, false, "", "نجح")}, + {0xfdb9, 0, 0, 0, g(Yes, No, false, false, "", "مخي")}, + {0xfdba, 0, 0, 0, g(Yes, No, false, false, "", "لجم")}, + {0xfdbb, 0, 0, 0, g(Yes, No, false, false, "", "كمم")}, + {0xfdbc, 0, 0, 0, g(Yes, No, false, false, "", "لجم")}, + {0xfdbd, 0, 0, 0, g(Yes, No, false, false, "", "نجح")}, + {0xfdbe, 0, 0, 0, g(Yes, No, false, false, "", "جحي")}, + {0xfdbf, 0, 0, 0, g(Yes, No, false, false, "", "حجي")}, + {0xfdc0, 0, 0, 0, g(Yes, No, false, false, "", "مجي")}, + {0xfdc1, 0, 0, 0, g(Yes, No, false, false, "", "فمي")}, + {0xfdc2, 0, 0, 0, g(Yes, No, false, false, "", "بحي")}, + {0xfdc3, 0, 0, 0, g(Yes, No, false, false, "", "كمم")}, + {0xfdc4, 0, 0, 0, g(Yes, No, false, false, "", "عجم")}, + {0xfdc5, 0, 0, 0, g(Yes, No, false, false, "", "صمم")}, + {0xfdc6, 0, 0, 0, g(Yes, No, false, false, "", "سخي")}, + {0xfdc7, 0, 0, 0, g(Yes, No, false, false, "", "نجي")}, + {0xfdc8, 0, 0, 0, f(Yes, false, "")}, + {0xfdf0, 0, 0, 0, g(Yes, No, false, false, "", "صلے")}, + {0xfdf1, 0, 0, 0, g(Yes, No, false, false, "", "قلے")}, + {0xfdf2, 0, 0, 0, g(Yes, No, false, false, "", "الله")}, + {0xfdf3, 0, 0, 0, g(Yes, No, false, false, "", "اكبر")}, + {0xfdf4, 0, 0, 0, g(Yes, No, false, false, "", "محمد")}, + {0xfdf5, 0, 0, 0, g(Yes, No, false, false, "", "صلعم")}, + {0xfdf6, 0, 0, 0, g(Yes, No, false, false, "", "رسول")}, + {0xfdf7, 0, 0, 0, g(Yes, No, false, false, "", "عليه")}, + {0xfdf8, 0, 0, 0, g(Yes, No, false, false, "", "وسلم")}, + {0xfdf9, 0, 0, 0, g(Yes, No, false, false, "", "صلى")}, + {0xfdfa, 0, 0, 0, g(Yes, No, false, false, "", "صلى الله عليه وسلم")}, + {0xfdfb, 0, 0, 0, g(Yes, No, false, false, "", "جل جلاله")}, + {0xfdfc, 0, 0, 0, g(Yes, No, false, false, "", "ریال")}, + {0xfdfd, 0, 0, 0, f(Yes, false, "")}, + {0xfe10, 0, 0, 0, g(Yes, No, false, false, "", ",")}, + {0xfe11, 0, 0, 0, g(Yes, No, false, false, "", "、")}, + {0xfe12, 0, 0, 0, g(Yes, No, false, false, "", "。")}, + {0xfe13, 0, 0, 0, g(Yes, No, false, false, "", ":")}, + {0xfe14, 0, 0, 0, g(Yes, No, false, false, "", ";")}, + {0xfe15, 0, 0, 0, g(Yes, No, false, false, "", "!")}, + {0xfe16, 0, 0, 0, g(Yes, No, false, false, "", "?")}, + {0xfe17, 0, 0, 0, g(Yes, No, false, false, "", "〖")}, + {0xfe18, 0, 0, 0, g(Yes, No, false, false, "", "〗")}, + {0xfe19, 0, 0, 0, g(Yes, No, false, false, "", "...")}, + {0xfe1a, 0, 0, 0, f(Yes, false, "")}, + {0xfe20, 230, 1, 1, f(Yes, false, "")}, + {0xfe27, 220, 1, 1, f(Yes, false, "")}, + {0xfe2e, 230, 1, 1, f(Yes, false, "")}, + {0xfe30, 0, 0, 0, g(Yes, No, false, false, "", "..")}, + {0xfe31, 0, 0, 0, g(Yes, No, false, false, "", "—")}, + {0xfe32, 0, 0, 0, g(Yes, No, false, false, "", "–")}, + {0xfe33, 0, 0, 0, g(Yes, No, false, false, "", "_")}, + {0xfe35, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0xfe36, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0xfe37, 0, 0, 0, g(Yes, No, false, false, "", "{")}, + {0xfe38, 0, 0, 0, g(Yes, No, false, false, "", "}")}, + {0xfe39, 0, 0, 0, g(Yes, No, false, false, "", "〔")}, + {0xfe3a, 0, 0, 0, g(Yes, No, false, false, "", "〕")}, + {0xfe3b, 0, 0, 0, g(Yes, No, false, false, "", "【")}, + {0xfe3c, 0, 0, 0, g(Yes, No, false, false, "", "】")}, + {0xfe3d, 0, 0, 0, g(Yes, No, false, false, "", "《")}, + {0xfe3e, 0, 0, 0, g(Yes, No, false, false, "", "》")}, + {0xfe3f, 0, 0, 0, g(Yes, No, false, false, "", "〈")}, + {0xfe40, 0, 0, 0, g(Yes, No, false, false, "", "〉")}, + {0xfe41, 0, 0, 0, g(Yes, No, false, false, "", "「")}, + {0xfe42, 0, 0, 0, g(Yes, No, false, false, "", "」")}, + {0xfe43, 0, 0, 0, g(Yes, No, false, false, "", "『")}, + {0xfe44, 0, 0, 0, g(Yes, No, false, false, "", "』")}, + {0xfe45, 0, 0, 0, f(Yes, false, "")}, + {0xfe47, 0, 0, 0, g(Yes, No, false, false, "", "[")}, + {0xfe48, 0, 0, 0, g(Yes, No, false, false, "", "]")}, + {0xfe49, 0, 0, 1, g(Yes, No, false, false, "", " ̅")}, + {0xfe4d, 0, 0, 0, g(Yes, No, false, false, "", "_")}, + {0xfe50, 0, 0, 0, g(Yes, No, false, false, "", ",")}, + {0xfe51, 0, 0, 0, g(Yes, No, false, false, "", "、")}, + {0xfe52, 0, 0, 0, g(Yes, No, false, false, "", ".")}, + {0xfe53, 0, 0, 0, f(Yes, false, "")}, + {0xfe54, 0, 0, 0, g(Yes, No, false, false, "", ";")}, + {0xfe55, 0, 0, 0, g(Yes, No, false, false, "", ":")}, + {0xfe56, 0, 0, 0, g(Yes, No, false, false, "", "?")}, + {0xfe57, 0, 0, 0, g(Yes, No, false, false, "", "!")}, + {0xfe58, 0, 0, 0, g(Yes, No, false, false, "", "—")}, + {0xfe59, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0xfe5a, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0xfe5b, 0, 0, 0, g(Yes, No, false, false, "", "{")}, + {0xfe5c, 0, 0, 0, g(Yes, No, false, false, "", "}")}, + {0xfe5d, 0, 0, 0, g(Yes, No, false, false, "", "〔")}, + {0xfe5e, 0, 0, 0, g(Yes, No, false, false, "", "〕")}, + {0xfe5f, 0, 0, 0, g(Yes, No, false, false, "", "#")}, + {0xfe60, 0, 0, 0, g(Yes, No, false, false, "", "&")}, + {0xfe61, 0, 0, 0, g(Yes, No, false, false, "", "*")}, + {0xfe62, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0xfe63, 0, 0, 0, g(Yes, No, false, false, "", "-")}, + {0xfe64, 0, 0, 0, g(Yes, No, false, false, "", "<")}, + {0xfe65, 0, 0, 0, g(Yes, No, false, false, "", ">")}, + {0xfe66, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0xfe67, 0, 0, 0, f(Yes, false, "")}, + {0xfe68, 0, 0, 0, g(Yes, No, false, false, "", "\\")}, + {0xfe69, 0, 0, 0, g(Yes, No, false, false, "", "$")}, + {0xfe6a, 0, 0, 0, g(Yes, No, false, false, "", "%")}, + {0xfe6b, 0, 0, 0, g(Yes, No, false, false, "", "@")}, + {0xfe6c, 0, 0, 0, f(Yes, false, "")}, + {0xfe70, 0, 0, 1, g(Yes, No, false, false, "", " ً")}, + {0xfe71, 0, 0, 1, g(Yes, No, false, false, "", "ـً")}, + {0xfe72, 0, 0, 1, g(Yes, No, false, false, "", " ٌ")}, + {0xfe73, 0, 0, 0, f(Yes, false, "")}, + {0xfe74, 0, 0, 1, g(Yes, No, false, false, "", " ٍ")}, + {0xfe75, 0, 0, 0, f(Yes, false, "")}, + {0xfe76, 0, 0, 1, g(Yes, No, false, false, "", " َ")}, + {0xfe77, 0, 0, 1, g(Yes, No, false, false, "", "ـَ")}, + {0xfe78, 0, 0, 1, g(Yes, No, false, false, "", " ُ")}, + {0xfe79, 0, 0, 1, g(Yes, No, false, false, "", "ـُ")}, + {0xfe7a, 0, 0, 1, g(Yes, No, false, false, "", " ِ")}, + {0xfe7b, 0, 0, 1, g(Yes, No, false, false, "", "ـِ")}, + {0xfe7c, 0, 0, 1, g(Yes, No, false, false, "", " ّ")}, + {0xfe7d, 0, 0, 1, g(Yes, No, false, false, "", "ـّ")}, + {0xfe7e, 0, 0, 1, g(Yes, No, false, false, "", " ْ")}, + {0xfe7f, 0, 0, 1, g(Yes, No, false, false, "", "ـْ")}, + {0xfe80, 0, 0, 0, g(Yes, No, false, false, "", "ء")}, + {0xfe81, 0, 0, 1, g(Yes, No, false, false, "", "آ")}, + {0xfe83, 0, 0, 1, g(Yes, No, false, false, "", "أ")}, + {0xfe85, 0, 0, 1, g(Yes, No, false, false, "", "ؤ")}, + {0xfe87, 0, 0, 1, g(Yes, No, false, false, "", "إ")}, + {0xfe89, 0, 0, 1, g(Yes, No, false, false, "", "ئ")}, + {0xfe8d, 0, 0, 0, g(Yes, No, false, false, "", "ا")}, + {0xfe8f, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0xfe93, 0, 0, 0, g(Yes, No, false, false, "", "ة")}, + {0xfe95, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0xfe99, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0xfe9d, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0xfea1, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0xfea5, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0xfea9, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0xfeab, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0xfead, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0xfeaf, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0xfeb1, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0xfeb5, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0xfeb9, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0xfebd, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0xfec1, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0xfec5, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0xfec9, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0xfecd, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0xfed1, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0xfed5, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0xfed9, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0xfedd, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0xfee1, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0xfee5, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0xfee9, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0xfeed, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0xfeef, 0, 0, 0, g(Yes, No, false, false, "", "ى")}, + {0xfef1, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0xfef5, 0, 0, 1, g(Yes, No, false, false, "", "لآ")}, + {0xfef7, 0, 0, 1, g(Yes, No, false, false, "", "لأ")}, + {0xfef9, 0, 0, 1, g(Yes, No, false, false, "", "لإ")}, + {0xfefb, 0, 0, 0, g(Yes, No, false, false, "", "لا")}, + {0xfefd, 0, 0, 0, f(Yes, false, "")}, + {0xff01, 0, 0, 0, g(Yes, No, false, false, "", "!")}, + {0xff02, 0, 0, 0, g(Yes, No, false, false, "", "\"")}, + {0xff03, 0, 0, 0, g(Yes, No, false, false, "", "#")}, + {0xff04, 0, 0, 0, g(Yes, No, false, false, "", "$")}, + {0xff05, 0, 0, 0, g(Yes, No, false, false, "", "%")}, + {0xff06, 0, 0, 0, g(Yes, No, false, false, "", "&")}, + {0xff07, 0, 0, 0, g(Yes, No, false, false, "", "'")}, + {0xff08, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0xff09, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0xff0a, 0, 0, 0, g(Yes, No, false, false, "", "*")}, + {0xff0b, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0xff0c, 0, 0, 0, g(Yes, No, false, false, "", ",")}, + {0xff0d, 0, 0, 0, g(Yes, No, false, false, "", "-")}, + {0xff0e, 0, 0, 0, g(Yes, No, false, false, "", ".")}, + {0xff0f, 0, 0, 0, g(Yes, No, false, false, "", "/")}, + {0xff10, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0xff11, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0xff12, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0xff13, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0xff14, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0xff15, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0xff16, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0xff17, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0xff18, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0xff19, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0xff1a, 0, 0, 0, g(Yes, No, false, false, "", ":")}, + {0xff1b, 0, 0, 0, g(Yes, No, false, false, "", ";")}, + {0xff1c, 0, 0, 0, g(Yes, No, false, false, "", "<")}, + {0xff1d, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0xff1e, 0, 0, 0, g(Yes, No, false, false, "", ">")}, + {0xff1f, 0, 0, 0, g(Yes, No, false, false, "", "?")}, + {0xff20, 0, 0, 0, g(Yes, No, false, false, "", "@")}, + {0xff21, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0xff22, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0xff23, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0xff24, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0xff25, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0xff26, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0xff27, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0xff28, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0xff29, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0xff2a, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0xff2b, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0xff2c, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0xff2d, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0xff2e, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0xff2f, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0xff30, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0xff31, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0xff32, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0xff33, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0xff34, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0xff35, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0xff36, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0xff37, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0xff38, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0xff39, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0xff3a, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0xff3b, 0, 0, 0, g(Yes, No, false, false, "", "[")}, + {0xff3c, 0, 0, 0, g(Yes, No, false, false, "", "\\")}, + {0xff3d, 0, 0, 0, g(Yes, No, false, false, "", "]")}, + {0xff3e, 0, 0, 0, g(Yes, No, false, false, "", "^")}, + {0xff3f, 0, 0, 0, g(Yes, No, false, false, "", "_")}, + {0xff40, 0, 0, 0, g(Yes, No, false, false, "", "`")}, + {0xff41, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0xff42, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0xff43, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0xff44, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0xff45, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0xff46, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0xff47, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0xff48, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0xff49, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0xff4a, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0xff4b, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0xff4c, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0xff4d, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0xff4e, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0xff4f, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0xff50, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0xff51, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0xff52, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0xff53, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0xff54, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0xff55, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0xff56, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0xff57, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0xff58, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0xff59, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0xff5a, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0xff5b, 0, 0, 0, g(Yes, No, false, false, "", "{")}, + {0xff5c, 0, 0, 0, g(Yes, No, false, false, "", "|")}, + {0xff5d, 0, 0, 0, g(Yes, No, false, false, "", "}")}, + {0xff5e, 0, 0, 0, g(Yes, No, false, false, "", "~")}, + {0xff5f, 0, 0, 0, g(Yes, No, false, false, "", "⦅")}, + {0xff60, 0, 0, 0, g(Yes, No, false, false, "", "⦆")}, + {0xff61, 0, 0, 0, g(Yes, No, false, false, "", "。")}, + {0xff62, 0, 0, 0, g(Yes, No, false, false, "", "「")}, + {0xff63, 0, 0, 0, g(Yes, No, false, false, "", "」")}, + {0xff64, 0, 0, 0, g(Yes, No, false, false, "", "、")}, + {0xff65, 0, 0, 0, g(Yes, No, false, false, "", "・")}, + {0xff66, 0, 0, 0, g(Yes, No, false, false, "", "ヲ")}, + {0xff67, 0, 0, 0, g(Yes, No, false, false, "", "ァ")}, + {0xff68, 0, 0, 0, g(Yes, No, false, false, "", "ィ")}, + {0xff69, 0, 0, 0, g(Yes, No, false, false, "", "ゥ")}, + {0xff6a, 0, 0, 0, g(Yes, No, false, false, "", "ェ")}, + {0xff6b, 0, 0, 0, g(Yes, No, false, false, "", "ォ")}, + {0xff6c, 0, 0, 0, g(Yes, No, false, false, "", "ャ")}, + {0xff6d, 0, 0, 0, g(Yes, No, false, false, "", "ュ")}, + {0xff6e, 0, 0, 0, g(Yes, No, false, false, "", "ョ")}, + {0xff6f, 0, 0, 0, g(Yes, No, false, false, "", "ッ")}, + {0xff70, 0, 0, 0, g(Yes, No, false, false, "", "ー")}, + {0xff71, 0, 0, 0, g(Yes, No, false, false, "", "ア")}, + {0xff72, 0, 0, 0, g(Yes, No, false, false, "", "イ")}, + {0xff73, 0, 0, 0, g(Yes, No, false, false, "", "ウ")}, + {0xff74, 0, 0, 0, g(Yes, No, false, false, "", "エ")}, + {0xff75, 0, 0, 0, g(Yes, No, false, false, "", "オ")}, + {0xff76, 0, 0, 0, g(Yes, No, false, false, "", "カ")}, + {0xff77, 0, 0, 0, g(Yes, No, false, false, "", "キ")}, + {0xff78, 0, 0, 0, g(Yes, No, false, false, "", "ク")}, + {0xff79, 0, 0, 0, g(Yes, No, false, false, "", "ケ")}, + {0xff7a, 0, 0, 0, g(Yes, No, false, false, "", "コ")}, + {0xff7b, 0, 0, 0, g(Yes, No, false, false, "", "サ")}, + {0xff7c, 0, 0, 0, g(Yes, No, false, false, "", "シ")}, + {0xff7d, 0, 0, 0, g(Yes, No, false, false, "", "ス")}, + {0xff7e, 0, 0, 0, g(Yes, No, false, false, "", "セ")}, + {0xff7f, 0, 0, 0, g(Yes, No, false, false, "", "ソ")}, + {0xff80, 0, 0, 0, g(Yes, No, false, false, "", "タ")}, + {0xff81, 0, 0, 0, g(Yes, No, false, false, "", "チ")}, + {0xff82, 0, 0, 0, g(Yes, No, false, false, "", "ツ")}, + {0xff83, 0, 0, 0, g(Yes, No, false, false, "", "テ")}, + {0xff84, 0, 0, 0, g(Yes, No, false, false, "", "ト")}, + {0xff85, 0, 0, 0, g(Yes, No, false, false, "", "ナ")}, + {0xff86, 0, 0, 0, g(Yes, No, false, false, "", "ニ")}, + {0xff87, 0, 0, 0, g(Yes, No, false, false, "", "ヌ")}, + {0xff88, 0, 0, 0, g(Yes, No, false, false, "", "ネ")}, + {0xff89, 0, 0, 0, g(Yes, No, false, false, "", "ノ")}, + {0xff8a, 0, 0, 0, g(Yes, No, false, false, "", "ハ")}, + {0xff8b, 0, 0, 0, g(Yes, No, false, false, "", "ヒ")}, + {0xff8c, 0, 0, 0, g(Yes, No, false, false, "", "フ")}, + {0xff8d, 0, 0, 0, g(Yes, No, false, false, "", "ヘ")}, + {0xff8e, 0, 0, 0, g(Yes, No, false, false, "", "ホ")}, + {0xff8f, 0, 0, 0, g(Yes, No, false, false, "", "マ")}, + {0xff90, 0, 0, 0, g(Yes, No, false, false, "", "ミ")}, + {0xff91, 0, 0, 0, g(Yes, No, false, false, "", "ム")}, + {0xff92, 0, 0, 0, g(Yes, No, false, false, "", "メ")}, + {0xff93, 0, 0, 0, g(Yes, No, false, false, "", "モ")}, + {0xff94, 0, 0, 0, g(Yes, No, false, false, "", "ヤ")}, + {0xff95, 0, 0, 0, g(Yes, No, false, false, "", "ユ")}, + {0xff96, 0, 0, 0, g(Yes, No, false, false, "", "ヨ")}, + {0xff97, 0, 0, 0, g(Yes, No, false, false, "", "ラ")}, + {0xff98, 0, 0, 0, g(Yes, No, false, false, "", "リ")}, + {0xff99, 0, 0, 0, g(Yes, No, false, false, "", "ル")}, + {0xff9a, 0, 0, 0, g(Yes, No, false, false, "", "レ")}, + {0xff9b, 0, 0, 0, g(Yes, No, false, false, "", "ロ")}, + {0xff9c, 0, 0, 0, g(Yes, No, false, false, "", "ワ")}, + {0xff9d, 0, 0, 0, g(Yes, No, false, false, "", "ン")}, + {0xff9e, 0, 1, 1, g(Yes, No, false, false, "", "゙")}, + {0xff9f, 0, 1, 1, g(Yes, No, false, false, "", "゚")}, + {0xffa0, 0, 0, 0, g(Yes, No, false, false, "", "ᅠ")}, + {0xffa1, 0, 0, 0, g(Yes, No, false, false, "", "ᄀ")}, + {0xffa2, 0, 0, 0, g(Yes, No, false, false, "", "ᄁ")}, + {0xffa3, 0, 1, 1, g(Yes, No, false, false, "", "ᆪ")}, + {0xffa4, 0, 0, 0, g(Yes, No, false, false, "", "ᄂ")}, + {0xffa5, 0, 1, 1, g(Yes, No, false, false, "", "ᆬ")}, + {0xffa6, 0, 1, 1, g(Yes, No, false, false, "", "ᆭ")}, + {0xffa7, 0, 0, 0, g(Yes, No, false, false, "", "ᄃ")}, + {0xffa8, 0, 0, 0, g(Yes, No, false, false, "", "ᄄ")}, + {0xffa9, 0, 0, 0, g(Yes, No, false, false, "", "ᄅ")}, + {0xffaa, 0, 1, 1, g(Yes, No, false, false, "", "ᆰ")}, + {0xffab, 0, 1, 1, g(Yes, No, false, false, "", "ᆱ")}, + {0xffac, 0, 1, 1, g(Yes, No, false, false, "", "ᆲ")}, + {0xffad, 0, 1, 1, g(Yes, No, false, false, "", "ᆳ")}, + {0xffae, 0, 1, 1, g(Yes, No, false, false, "", "ᆴ")}, + {0xffaf, 0, 1, 1, g(Yes, No, false, false, "", "ᆵ")}, + {0xffb0, 0, 0, 0, g(Yes, No, false, false, "", "ᄚ")}, + {0xffb1, 0, 0, 0, g(Yes, No, false, false, "", "ᄆ")}, + {0xffb2, 0, 0, 0, g(Yes, No, false, false, "", "ᄇ")}, + {0xffb3, 0, 0, 0, g(Yes, No, false, false, "", "ᄈ")}, + {0xffb4, 0, 0, 0, g(Yes, No, false, false, "", "ᄡ")}, + {0xffb5, 0, 0, 0, g(Yes, No, false, false, "", "ᄉ")}, + {0xffb6, 0, 0, 0, g(Yes, No, false, false, "", "ᄊ")}, + {0xffb7, 0, 0, 0, g(Yes, No, false, false, "", "ᄋ")}, + {0xffb8, 0, 0, 0, g(Yes, No, false, false, "", "ᄌ")}, + {0xffb9, 0, 0, 0, g(Yes, No, false, false, "", "ᄍ")}, + {0xffba, 0, 0, 0, g(Yes, No, false, false, "", "ᄎ")}, + {0xffbb, 0, 0, 0, g(Yes, No, false, false, "", "ᄏ")}, + {0xffbc, 0, 0, 0, g(Yes, No, false, false, "", "ᄐ")}, + {0xffbd, 0, 0, 0, g(Yes, No, false, false, "", "ᄑ")}, + {0xffbe, 0, 0, 0, g(Yes, No, false, false, "", "ᄒ")}, + {0xffbf, 0, 0, 0, f(Yes, false, "")}, + {0xffc2, 0, 1, 1, g(Yes, No, false, false, "", "ᅡ")}, + {0xffc3, 0, 1, 1, g(Yes, No, false, false, "", "ᅢ")}, + {0xffc4, 0, 1, 1, g(Yes, No, false, false, "", "ᅣ")}, + {0xffc5, 0, 1, 1, g(Yes, No, false, false, "", "ᅤ")}, + {0xffc6, 0, 1, 1, g(Yes, No, false, false, "", "ᅥ")}, + {0xffc7, 0, 1, 1, g(Yes, No, false, false, "", "ᅦ")}, + {0xffc8, 0, 0, 0, f(Yes, false, "")}, + {0xffca, 0, 1, 1, g(Yes, No, false, false, "", "ᅧ")}, + {0xffcb, 0, 1, 1, g(Yes, No, false, false, "", "ᅨ")}, + {0xffcc, 0, 1, 1, g(Yes, No, false, false, "", "ᅩ")}, + {0xffcd, 0, 1, 1, g(Yes, No, false, false, "", "ᅪ")}, + {0xffce, 0, 1, 1, g(Yes, No, false, false, "", "ᅫ")}, + {0xffcf, 0, 1, 1, g(Yes, No, false, false, "", "ᅬ")}, + {0xffd0, 0, 0, 0, f(Yes, false, "")}, + {0xffd2, 0, 1, 1, g(Yes, No, false, false, "", "ᅭ")}, + {0xffd3, 0, 1, 1, g(Yes, No, false, false, "", "ᅮ")}, + {0xffd4, 0, 1, 1, g(Yes, No, false, false, "", "ᅯ")}, + {0xffd5, 0, 1, 1, g(Yes, No, false, false, "", "ᅰ")}, + {0xffd6, 0, 1, 1, g(Yes, No, false, false, "", "ᅱ")}, + {0xffd7, 0, 1, 1, g(Yes, No, false, false, "", "ᅲ")}, + {0xffd8, 0, 0, 0, f(Yes, false, "")}, + {0xffda, 0, 1, 1, g(Yes, No, false, false, "", "ᅳ")}, + {0xffdb, 0, 1, 1, g(Yes, No, false, false, "", "ᅴ")}, + {0xffdc, 0, 1, 1, g(Yes, No, false, false, "", "ᅵ")}, + {0xffdd, 0, 0, 0, f(Yes, false, "")}, + {0xffe0, 0, 0, 0, g(Yes, No, false, false, "", "¢")}, + {0xffe1, 0, 0, 0, g(Yes, No, false, false, "", "£")}, + {0xffe2, 0, 0, 0, g(Yes, No, false, false, "", "¬")}, + {0xffe3, 0, 0, 1, g(Yes, No, false, false, "", " ̄")}, + {0xffe4, 0, 0, 0, g(Yes, No, false, false, "", "¦")}, + {0xffe5, 0, 0, 0, g(Yes, No, false, false, "", "¥")}, + {0xffe6, 0, 0, 0, g(Yes, No, false, false, "", "₩")}, + {0xffe7, 0, 0, 0, f(Yes, false, "")}, + {0xffe8, 0, 0, 0, g(Yes, No, false, false, "", "│")}, + {0xffe9, 0, 0, 0, g(Yes, No, false, false, "", "←")}, + {0xffea, 0, 0, 0, g(Yes, No, false, false, "", "↑")}, + {0xffeb, 0, 0, 0, g(Yes, No, false, false, "", "→")}, + {0xffec, 0, 0, 0, g(Yes, No, false, false, "", "↓")}, + {0xffed, 0, 0, 0, g(Yes, No, false, false, "", "■")}, + {0xffee, 0, 0, 0, g(Yes, No, false, false, "", "○")}, + {0xffef, 0, 0, 0, f(Yes, false, "")}, + {0x101fd, 220, 1, 1, f(Yes, false, "")}, + {0x101fe, 0, 0, 0, f(Yes, false, "")}, + {0x102e0, 220, 1, 1, f(Yes, false, "")}, + {0x102e1, 0, 0, 0, f(Yes, false, "")}, + {0x10376, 230, 1, 1, f(Yes, false, "")}, + {0x1037b, 0, 0, 0, f(Yes, false, "")}, + {0x10a0d, 220, 1, 1, f(Yes, false, "")}, + {0x10a0e, 0, 0, 0, f(Yes, false, "")}, + {0x10a0f, 230, 1, 1, f(Yes, false, "")}, + {0x10a10, 0, 0, 0, f(Yes, false, "")}, + {0x10a38, 230, 1, 1, f(Yes, false, "")}, + {0x10a39, 1, 1, 1, f(Yes, false, "")}, + {0x10a3a, 220, 1, 1, f(Yes, false, "")}, + {0x10a3b, 0, 0, 0, f(Yes, false, "")}, + {0x10a3f, 9, 1, 1, f(Yes, false, "")}, + {0x10a40, 0, 0, 0, f(Yes, false, "")}, + {0x10ae5, 230, 1, 1, f(Yes, false, "")}, + {0x10ae6, 220, 1, 1, f(Yes, false, "")}, + {0x10ae7, 0, 0, 0, f(Yes, false, "")}, + {0x11046, 9, 1, 1, f(Yes, false, "")}, + {0x11047, 0, 0, 0, f(Yes, false, "")}, + {0x1107f, 9, 1, 1, f(Yes, false, "")}, + {0x11080, 0, 0, 0, f(Yes, false, "")}, + {0x11099, 0, 0, 0, f(Yes, true, "")}, + {0x1109a, 0, 0, 1, f(Yes, false, "𑂚")}, + {0x1109b, 0, 0, 0, f(Yes, true, "")}, + {0x1109c, 0, 0, 1, f(Yes, false, "𑂜")}, + {0x1109d, 0, 0, 0, f(Yes, false, "")}, + {0x110a5, 0, 0, 0, f(Yes, true, "")}, + {0x110a6, 0, 0, 0, f(Yes, false, "")}, + {0x110ab, 0, 0, 1, f(Yes, false, "𑂫")}, + {0x110ac, 0, 0, 0, f(Yes, false, "")}, + {0x110b9, 9, 1, 1, f(Yes, false, "")}, + {0x110ba, 7, 1, 1, f(Maybe, false, "")}, + {0x110bb, 0, 0, 0, f(Yes, false, "")}, + {0x11100, 230, 1, 1, f(Yes, false, "")}, + {0x11103, 0, 0, 0, f(Yes, false, "")}, + {0x11127, 0, 1, 1, f(Maybe, false, "")}, + {0x11128, 0, 0, 0, f(Yes, false, "")}, + {0x1112e, 0, 0, 1, f(Yes, false, "𑄮")}, + {0x1112f, 0, 0, 1, f(Yes, false, "𑄯")}, + {0x11130, 0, 0, 0, f(Yes, false, "")}, + {0x11131, 0, 0, 0, f(Yes, true, "")}, + {0x11133, 9, 1, 1, f(Yes, false, "")}, + {0x11135, 0, 0, 0, f(Yes, false, "")}, + {0x11173, 7, 1, 1, f(Yes, false, "")}, + {0x11174, 0, 0, 0, f(Yes, false, "")}, + {0x111c0, 9, 1, 1, f(Yes, false, "")}, + {0x111c1, 0, 0, 0, f(Yes, false, "")}, + {0x111ca, 7, 1, 1, f(Yes, false, "")}, + {0x111cb, 0, 0, 0, f(Yes, false, "")}, + {0x11235, 9, 1, 1, f(Yes, false, "")}, + {0x11236, 7, 1, 1, f(Yes, false, "")}, + {0x11237, 0, 0, 0, f(Yes, false, "")}, + {0x112e9, 7, 1, 1, f(Yes, false, "")}, + {0x112ea, 9, 1, 1, f(Yes, false, "")}, + {0x112eb, 0, 0, 0, f(Yes, false, "")}, + {0x1133c, 7, 1, 1, f(Yes, false, "")}, + {0x1133d, 0, 0, 0, f(Yes, false, "")}, + {0x1133e, 0, 1, 1, f(Maybe, false, "")}, + {0x1133f, 0, 0, 0, f(Yes, false, "")}, + {0x11347, 0, 0, 0, f(Yes, true, "")}, + {0x11348, 0, 0, 0, f(Yes, false, "")}, + {0x1134b, 0, 0, 1, f(Yes, false, "𑍋")}, + {0x1134c, 0, 0, 1, f(Yes, false, "𑍌")}, + {0x1134d, 9, 1, 1, f(Yes, false, "")}, + {0x1134e, 0, 0, 0, f(Yes, false, "")}, + {0x11357, 0, 1, 1, f(Maybe, false, "")}, + {0x11358, 0, 0, 0, f(Yes, false, "")}, + {0x11366, 230, 1, 1, f(Yes, false, "")}, + {0x1136d, 0, 0, 0, f(Yes, false, "")}, + {0x11370, 230, 1, 1, f(Yes, false, "")}, + {0x11375, 0, 0, 0, f(Yes, false, "")}, + {0x11442, 9, 1, 1, f(Yes, false, "")}, + {0x11443, 0, 0, 0, f(Yes, false, "")}, + {0x11446, 7, 1, 1, f(Yes, false, "")}, + {0x11447, 0, 0, 0, f(Yes, false, "")}, + {0x114b0, 0, 1, 1, f(Maybe, false, "")}, + {0x114b1, 0, 0, 0, f(Yes, false, "")}, + {0x114b9, 0, 0, 0, f(Yes, true, "")}, + {0x114ba, 0, 1, 1, f(Maybe, false, "")}, + {0x114bb, 0, 0, 1, f(Yes, false, "𑒻")}, + {0x114bc, 0, 0, 1, f(Yes, false, "𑒼")}, + {0x114bd, 0, 1, 1, f(Maybe, false, "")}, + {0x114be, 0, 0, 1, f(Yes, false, "𑒾")}, + {0x114bf, 0, 0, 0, f(Yes, false, "")}, + {0x114c2, 9, 1, 1, f(Yes, false, "")}, + {0x114c3, 7, 1, 1, f(Yes, false, "")}, + {0x114c4, 0, 0, 0, f(Yes, false, "")}, + {0x115af, 0, 1, 1, f(Maybe, false, "")}, + {0x115b0, 0, 0, 0, f(Yes, false, "")}, + {0x115b8, 0, 0, 0, f(Yes, true, "")}, + {0x115ba, 0, 0, 1, f(Yes, false, "𑖺")}, + {0x115bb, 0, 0, 1, f(Yes, false, "𑖻")}, + {0x115bc, 0, 0, 0, f(Yes, false, "")}, + {0x115bf, 9, 1, 1, f(Yes, false, "")}, + {0x115c0, 7, 1, 1, f(Yes, false, "")}, + {0x115c1, 0, 0, 0, f(Yes, false, "")}, + {0x1163f, 9, 1, 1, f(Yes, false, "")}, + {0x11640, 0, 0, 0, f(Yes, false, "")}, + {0x116b6, 9, 1, 1, f(Yes, false, "")}, + {0x116b7, 7, 1, 1, f(Yes, false, "")}, + {0x116b8, 0, 0, 0, f(Yes, false, "")}, + {0x1172b, 9, 1, 1, f(Yes, false, "")}, + {0x1172c, 0, 0, 0, f(Yes, false, "")}, + {0x11a34, 9, 1, 1, f(Yes, false, "")}, + {0x11a35, 0, 0, 0, f(Yes, false, "")}, + {0x11a47, 9, 1, 1, f(Yes, false, "")}, + {0x11a48, 0, 0, 0, f(Yes, false, "")}, + {0x11a99, 9, 1, 1, f(Yes, false, "")}, + {0x11a9a, 0, 0, 0, f(Yes, false, "")}, + {0x11c3f, 9, 1, 1, f(Yes, false, "")}, + {0x11c40, 0, 0, 0, f(Yes, false, "")}, + {0x11d42, 7, 1, 1, f(Yes, false, "")}, + {0x11d43, 0, 0, 0, f(Yes, false, "")}, + {0x11d44, 9, 1, 1, f(Yes, false, "")}, + {0x11d46, 0, 0, 0, f(Yes, false, "")}, + {0x16af0, 1, 1, 1, f(Yes, false, "")}, + {0x16af5, 0, 0, 0, f(Yes, false, "")}, + {0x16b30, 230, 1, 1, f(Yes, false, "")}, + {0x16b37, 0, 0, 0, f(Yes, false, "")}, + {0x1bc9e, 1, 1, 1, f(Yes, false, "")}, + {0x1bc9f, 0, 0, 0, f(Yes, false, "")}, + {0x1d15e, 0, 0, 1, f(No, false, "𝅗𝅥")}, + {0x1d15f, 0, 0, 1, f(No, false, "𝅘𝅥")}, + {0x1d160, 0, 0, 2, f(No, false, "𝅘𝅥𝅮")}, + {0x1d161, 0, 0, 2, f(No, false, "𝅘𝅥𝅯")}, + {0x1d162, 0, 0, 2, f(No, false, "𝅘𝅥𝅰")}, + {0x1d163, 0, 0, 2, f(No, false, "𝅘𝅥𝅱")}, + {0x1d164, 0, 0, 2, f(No, false, "𝅘𝅥𝅲")}, + {0x1d165, 216, 1, 1, f(Yes, false, "")}, + {0x1d167, 1, 1, 1, f(Yes, false, "")}, + {0x1d16a, 0, 0, 0, f(Yes, false, "")}, + {0x1d16d, 226, 1, 1, f(Yes, false, "")}, + {0x1d16e, 216, 1, 1, f(Yes, false, "")}, + {0x1d173, 0, 0, 0, f(Yes, false, "")}, + {0x1d17b, 220, 1, 1, f(Yes, false, "")}, + {0x1d183, 0, 0, 0, f(Yes, false, "")}, + {0x1d185, 230, 1, 1, f(Yes, false, "")}, + {0x1d18a, 220, 1, 1, f(Yes, false, "")}, + {0x1d18c, 0, 0, 0, f(Yes, false, "")}, + {0x1d1aa, 230, 1, 1, f(Yes, false, "")}, + {0x1d1ae, 0, 0, 0, f(Yes, false, "")}, + {0x1d1bb, 0, 0, 1, f(No, false, "𝆹𝅥")}, + {0x1d1bc, 0, 0, 1, f(No, false, "𝆺𝅥")}, + {0x1d1bd, 0, 0, 2, f(No, false, "𝆹𝅥𝅮")}, + {0x1d1be, 0, 0, 2, f(No, false, "𝆺𝅥𝅮")}, + {0x1d1bf, 0, 0, 2, f(No, false, "𝆹𝅥𝅯")}, + {0x1d1c0, 0, 0, 2, f(No, false, "𝆺𝅥𝅯")}, + {0x1d1c1, 0, 0, 0, f(Yes, false, "")}, + {0x1d242, 230, 1, 1, f(Yes, false, "")}, + {0x1d245, 0, 0, 0, f(Yes, false, "")}, + {0x1d400, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d401, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d402, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d403, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d404, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d405, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d406, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d407, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d408, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d409, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d40a, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d40b, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d40c, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d40d, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d40e, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d40f, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d410, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d411, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d412, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d413, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d414, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d415, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d416, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d417, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d418, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d419, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d41a, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d41b, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d41c, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d41d, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d41e, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d41f, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d420, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d421, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d422, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d423, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d424, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d425, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d426, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d427, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d428, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d429, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d42a, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d42b, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d42c, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d42d, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d42e, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d42f, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d430, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d431, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d432, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d433, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d434, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d435, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d436, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d437, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d438, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d439, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d43a, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d43b, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d43c, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d43d, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d43e, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d43f, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d440, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d441, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d442, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d443, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d444, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d445, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d446, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d447, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d448, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d449, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d44a, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d44b, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d44c, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d44d, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d44e, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d44f, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d450, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d451, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d452, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d453, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d454, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d455, 0, 0, 0, f(Yes, false, "")}, + {0x1d456, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d457, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d458, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d459, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d45a, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d45b, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d45c, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d45d, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d45e, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d45f, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d460, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d461, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d462, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d463, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d464, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d465, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d466, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d467, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d468, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d469, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d46a, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d46b, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d46c, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d46d, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d46e, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d46f, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d470, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d471, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d472, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d473, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d474, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d475, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d476, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d477, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d478, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d479, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d47a, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d47b, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d47c, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d47d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d47e, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d47f, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d480, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d481, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d482, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d483, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d484, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d485, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d486, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d487, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d488, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d489, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d48a, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d48b, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d48c, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d48d, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d48e, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d48f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d490, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d491, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d492, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d493, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d494, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d495, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d496, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d497, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d498, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d499, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d49a, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d49b, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d49c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d49d, 0, 0, 0, f(Yes, false, "")}, + {0x1d49e, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d49f, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d4a0, 0, 0, 0, f(Yes, false, "")}, + {0x1d4a2, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d4a3, 0, 0, 0, f(Yes, false, "")}, + {0x1d4a5, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d4a6, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d4a7, 0, 0, 0, f(Yes, false, "")}, + {0x1d4a9, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d4aa, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d4ab, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d4ac, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d4ad, 0, 0, 0, f(Yes, false, "")}, + {0x1d4ae, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d4af, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d4b0, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d4b1, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d4b2, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d4b3, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d4b4, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d4b5, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d4b6, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d4b7, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d4b8, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d4b9, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d4ba, 0, 0, 0, f(Yes, false, "")}, + {0x1d4bb, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d4bc, 0, 0, 0, f(Yes, false, "")}, + {0x1d4bd, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d4be, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d4bf, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d4c0, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d4c1, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d4c2, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d4c3, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d4c4, 0, 0, 0, f(Yes, false, "")}, + {0x1d4c5, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d4c6, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d4c7, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d4c8, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d4c9, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d4ca, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d4cb, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d4cc, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d4cd, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d4ce, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d4cf, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d4d0, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d4d1, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d4d2, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d4d3, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d4d4, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d4d5, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d4d6, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d4d7, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d4d8, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d4d9, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d4da, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d4db, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d4dc, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d4dd, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d4de, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d4df, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d4e0, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d4e1, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d4e2, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d4e3, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d4e4, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d4e5, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d4e6, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d4e7, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d4e8, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d4e9, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d4ea, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d4eb, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d4ec, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d4ed, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d4ee, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d4ef, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d4f0, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d4f1, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d4f2, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d4f3, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d4f4, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d4f5, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d4f6, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d4f7, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d4f8, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d4f9, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d4fa, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d4fb, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d4fc, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d4fd, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d4fe, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d4ff, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d500, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d501, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d502, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d503, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d504, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d505, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d506, 0, 0, 0, f(Yes, false, "")}, + {0x1d507, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d508, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d509, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d50a, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d50b, 0, 0, 0, f(Yes, false, "")}, + {0x1d50d, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d50e, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d50f, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d510, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d511, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d512, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d513, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d514, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d515, 0, 0, 0, f(Yes, false, "")}, + {0x1d516, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d517, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d518, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d519, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d51a, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d51b, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d51c, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d51d, 0, 0, 0, f(Yes, false, "")}, + {0x1d51e, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d51f, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d520, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d521, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d522, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d523, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d524, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d525, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d526, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d527, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d528, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d529, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d52a, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d52b, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d52c, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d52d, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d52e, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d52f, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d530, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d531, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d532, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d533, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d534, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d535, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d536, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d537, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d538, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d539, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d53a, 0, 0, 0, f(Yes, false, "")}, + {0x1d53b, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d53c, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d53d, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d53e, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d53f, 0, 0, 0, f(Yes, false, "")}, + {0x1d540, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d541, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d542, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d543, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d544, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d545, 0, 0, 0, f(Yes, false, "")}, + {0x1d546, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d547, 0, 0, 0, f(Yes, false, "")}, + {0x1d54a, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d54b, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d54c, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d54d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d54e, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d54f, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d550, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d551, 0, 0, 0, f(Yes, false, "")}, + {0x1d552, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d553, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d554, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d555, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d556, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d557, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d558, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d559, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d55a, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d55b, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d55c, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d55d, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d55e, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d55f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d560, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d561, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d562, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d563, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d564, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d565, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d566, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d567, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d568, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d569, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d56a, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d56b, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d56c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d56d, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d56e, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d56f, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d570, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d571, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d572, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d573, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d574, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d575, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d576, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d577, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d578, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d579, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d57a, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d57b, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d57c, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d57d, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d57e, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d57f, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d580, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d581, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d582, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d583, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d584, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d585, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d586, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d587, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d588, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d589, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d58a, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d58b, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d58c, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d58d, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d58e, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d58f, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d590, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d591, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d592, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d593, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d594, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d595, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d596, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d597, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d598, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d599, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d59a, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d59b, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d59c, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d59d, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d59e, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d59f, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d5a0, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d5a1, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d5a2, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d5a3, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d5a4, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d5a5, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d5a6, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d5a7, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d5a8, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d5a9, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d5aa, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d5ab, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d5ac, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d5ad, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d5ae, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d5af, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d5b0, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d5b1, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d5b2, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d5b3, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d5b4, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d5b5, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d5b6, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d5b7, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d5b8, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d5b9, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d5ba, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d5bb, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d5bc, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d5bd, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d5be, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d5bf, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d5c0, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d5c1, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d5c2, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d5c3, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d5c4, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d5c5, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d5c6, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d5c7, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d5c8, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d5c9, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d5ca, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d5cb, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d5cc, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d5cd, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d5ce, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d5cf, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d5d0, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d5d1, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d5d2, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d5d3, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d5d4, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d5d5, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d5d6, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d5d7, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d5d8, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d5d9, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d5da, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d5db, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d5dc, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d5dd, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d5de, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d5df, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d5e0, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d5e1, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d5e2, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d5e3, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d5e4, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d5e5, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d5e6, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d5e7, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d5e8, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d5e9, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d5ea, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d5eb, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d5ec, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d5ed, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d5ee, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d5ef, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d5f0, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d5f1, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d5f2, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d5f3, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d5f4, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d5f5, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d5f6, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d5f7, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d5f8, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d5f9, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d5fa, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d5fb, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d5fc, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d5fd, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d5fe, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d5ff, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d600, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d601, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d602, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d603, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d604, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d605, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d606, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d607, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d608, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d609, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d60a, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d60b, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d60c, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d60d, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d60e, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d60f, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d610, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d611, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d612, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d613, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d614, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d615, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d616, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d617, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d618, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d619, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d61a, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d61b, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d61c, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d61d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d61e, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d61f, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d620, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d621, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d622, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d623, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d624, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d625, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d626, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d627, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d628, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d629, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d62a, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d62b, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d62c, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d62d, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d62e, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d62f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d630, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d631, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d632, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d633, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d634, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d635, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d636, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d637, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d638, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d639, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d63a, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d63b, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d63c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d63d, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d63e, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d63f, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d640, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d641, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d642, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d643, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d644, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d645, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d646, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d647, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d648, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d649, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d64a, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d64b, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d64c, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d64d, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d64e, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d64f, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d650, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d651, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d652, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d653, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d654, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d655, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d656, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d657, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d658, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d659, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d65a, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d65b, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d65c, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d65d, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d65e, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d65f, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d660, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d661, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d662, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d663, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d664, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d665, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d666, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d667, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d668, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d669, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d66a, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d66b, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d66c, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d66d, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d66e, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d66f, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d670, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d671, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d672, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d673, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d674, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d675, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d676, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d677, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d678, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d679, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d67a, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d67b, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d67c, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d67d, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d67e, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d67f, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d680, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d681, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d682, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d683, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d684, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d685, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d686, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d687, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d688, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d689, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d68a, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d68b, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d68c, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d68d, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d68e, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d68f, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d690, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d691, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d692, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d693, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d694, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d695, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d696, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d697, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d698, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d699, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d69a, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d69b, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d69c, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d69d, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d69e, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d69f, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d6a0, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d6a1, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d6a2, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d6a3, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d6a4, 0, 0, 0, g(Yes, No, false, false, "", "ı")}, + {0x1d6a5, 0, 0, 0, g(Yes, No, false, false, "", "ȷ")}, + {0x1d6a6, 0, 0, 0, f(Yes, false, "")}, + {0x1d6a8, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d6a9, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d6aa, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d6ab, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d6ac, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d6ad, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d6ae, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d6af, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6b0, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d6b1, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d6b2, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d6b3, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d6b4, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d6b5, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d6b6, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d6b7, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d6b8, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d6b9, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6ba, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d6bb, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d6bc, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d6bd, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d6be, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d6bf, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d6c0, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d6c1, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d6c2, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d6c3, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d6c4, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d6c5, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d6c6, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d6c7, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d6c8, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d6c9, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d6ca, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d6cb, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d6cc, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d6cd, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d6ce, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d6cf, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d6d0, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d6d1, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d6d2, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d6d3, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d6d4, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d6d5, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d6d6, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d6d7, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d6d8, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d6d9, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d6da, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d6db, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d6dc, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d6dd, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d6de, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d6df, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d6e0, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d6e1, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d6e2, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d6e3, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d6e4, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d6e5, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d6e6, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d6e7, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d6e8, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d6e9, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6ea, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d6eb, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d6ec, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d6ed, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d6ee, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d6ef, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d6f0, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d6f1, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d6f2, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d6f3, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6f4, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d6f5, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d6f6, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d6f7, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d6f8, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d6f9, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d6fa, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d6fb, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d6fc, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d6fd, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d6fe, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d6ff, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d700, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d701, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d702, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d703, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d704, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d705, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d706, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d707, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d708, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d709, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d70a, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d70b, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d70c, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d70d, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d70e, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d70f, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d710, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d711, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d712, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d713, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d714, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d715, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d716, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d717, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d718, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d719, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d71a, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d71b, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d71c, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d71d, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d71e, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d71f, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d720, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d721, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d722, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d723, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d724, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d725, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d726, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d727, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d728, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d729, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d72a, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d72b, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d72c, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d72d, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d72e, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d72f, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d730, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d731, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d732, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d733, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d734, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d735, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d736, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d737, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d738, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d739, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d73a, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d73b, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d73c, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d73d, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d73e, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d73f, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d740, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d741, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d742, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d743, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d744, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d745, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d746, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d747, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d748, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d749, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d74a, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d74b, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d74c, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d74d, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d74e, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d74f, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d750, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d751, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d752, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d753, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d754, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d755, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d756, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d757, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d758, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d759, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d75a, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d75b, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d75c, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d75d, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d75e, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d75f, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d760, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d761, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d762, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d763, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d764, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d765, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d766, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d767, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d768, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d769, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d76a, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d76b, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d76c, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d76d, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d76e, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d76f, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d770, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d771, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d772, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d773, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d774, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d775, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d776, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d777, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d778, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d779, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d77a, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d77b, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d77c, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d77d, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d77e, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d77f, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d780, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d781, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d782, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d783, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d784, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d785, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d786, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d787, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d788, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d789, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d78a, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d78b, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d78c, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d78d, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d78e, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d78f, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d790, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d791, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d792, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d793, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d794, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d795, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d796, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d797, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d798, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d799, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d79a, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d79b, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d79c, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d79d, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d79e, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d79f, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d7a0, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d7a1, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d7a2, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d7a3, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d7a4, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d7a5, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d7a6, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d7a7, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d7a8, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d7a9, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d7aa, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d7ab, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d7ac, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d7ad, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d7ae, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d7af, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d7b0, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d7b1, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d7b2, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d7b3, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d7b4, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d7b5, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d7b6, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d7b7, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d7b8, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d7b9, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d7ba, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d7bb, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d7bc, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d7bd, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d7be, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d7bf, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d7c0, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d7c1, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d7c2, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d7c3, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d7c4, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d7c5, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d7c6, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d7c7, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d7c8, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d7c9, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d7ca, 0, 0, 0, g(Yes, No, false, false, "", "Ϝ")}, + {0x1d7cb, 0, 0, 0, g(Yes, No, false, false, "", "ϝ")}, + {0x1d7cc, 0, 0, 0, f(Yes, false, "")}, + {0x1d7ce, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7cf, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7d0, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7d1, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7d2, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7d3, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7d4, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7d5, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7d6, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7d7, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7d8, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7d9, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7da, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7db, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7dc, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7dd, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7de, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7df, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7e0, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7e1, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7e2, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7e3, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7e4, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7e5, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7e6, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7e7, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7e8, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7e9, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7ea, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7eb, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7ec, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7ed, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7ee, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7ef, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7f0, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7f1, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7f2, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7f3, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7f4, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7f5, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7f6, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7f7, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7f8, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7f9, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7fa, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7fb, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7fc, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7fd, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7fe, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7ff, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d800, 0, 0, 0, f(Yes, false, "")}, + {0x1e000, 230, 1, 1, f(Yes, false, "")}, + {0x1e007, 0, 0, 0, f(Yes, false, "")}, + {0x1e008, 230, 1, 1, f(Yes, false, "")}, + {0x1e019, 0, 0, 0, f(Yes, false, "")}, + {0x1e01b, 230, 1, 1, f(Yes, false, "")}, + {0x1e022, 0, 0, 0, f(Yes, false, "")}, + {0x1e023, 230, 1, 1, f(Yes, false, "")}, + {0x1e025, 0, 0, 0, f(Yes, false, "")}, + {0x1e026, 230, 1, 1, f(Yes, false, "")}, + {0x1e02b, 0, 0, 0, f(Yes, false, "")}, + {0x1e8d0, 220, 1, 1, f(Yes, false, "")}, + {0x1e8d7, 0, 0, 0, f(Yes, false, "")}, + {0x1e944, 230, 1, 1, f(Yes, false, "")}, + {0x1e94a, 7, 1, 1, f(Yes, false, "")}, + {0x1e94b, 0, 0, 0, f(Yes, false, "")}, + {0x1ee00, 0, 0, 0, g(Yes, No, false, false, "", "ا")}, + {0x1ee01, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee02, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee03, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0x1ee04, 0, 0, 0, f(Yes, false, "")}, + {0x1ee05, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0x1ee06, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0x1ee07, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee08, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1ee09, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee0a, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0x1ee0b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee0c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee0d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee0e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee0f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee10, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee11, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee12, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee13, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0x1ee14, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee15, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee16, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee17, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee18, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0x1ee19, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee1a, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1ee1b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee1c, 0, 0, 0, g(Yes, No, false, false, "", "ٮ")}, + {0x1ee1d, 0, 0, 0, g(Yes, No, false, false, "", "ں")}, + {0x1ee1e, 0, 0, 0, g(Yes, No, false, false, "", "ڡ")}, + {0x1ee1f, 0, 0, 0, g(Yes, No, false, false, "", "ٯ")}, + {0x1ee20, 0, 0, 0, f(Yes, false, "")}, + {0x1ee21, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee22, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee23, 0, 0, 0, f(Yes, false, "")}, + {0x1ee24, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0x1ee25, 0, 0, 0, f(Yes, false, "")}, + {0x1ee27, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee28, 0, 0, 0, f(Yes, false, "")}, + {0x1ee29, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee2a, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0x1ee2b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee2c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee2d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee2e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee2f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee30, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee31, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee32, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee33, 0, 0, 0, f(Yes, false, "")}, + {0x1ee34, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee35, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee36, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee37, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee38, 0, 0, 0, f(Yes, false, "")}, + {0x1ee39, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee3a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee3b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee3c, 0, 0, 0, f(Yes, false, "")}, + {0x1ee42, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee43, 0, 0, 0, f(Yes, false, "")}, + {0x1ee47, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee48, 0, 0, 0, f(Yes, false, "")}, + {0x1ee49, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee4a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee4b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee4c, 0, 0, 0, f(Yes, false, "")}, + {0x1ee4d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee4e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee4f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee50, 0, 0, 0, f(Yes, false, "")}, + {0x1ee51, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee52, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee53, 0, 0, 0, f(Yes, false, "")}, + {0x1ee54, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee55, 0, 0, 0, f(Yes, false, "")}, + {0x1ee57, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee58, 0, 0, 0, f(Yes, false, "")}, + {0x1ee59, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee5a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee5b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee5c, 0, 0, 0, f(Yes, false, "")}, + {0x1ee5d, 0, 0, 0, g(Yes, No, false, false, "", "ں")}, + {0x1ee5e, 0, 0, 0, f(Yes, false, "")}, + {0x1ee5f, 0, 0, 0, g(Yes, No, false, false, "", "ٯ")}, + {0x1ee60, 0, 0, 0, f(Yes, false, "")}, + {0x1ee61, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee62, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee63, 0, 0, 0, f(Yes, false, "")}, + {0x1ee64, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0x1ee65, 0, 0, 0, f(Yes, false, "")}, + {0x1ee67, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee68, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1ee69, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee6a, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0x1ee6b, 0, 0, 0, f(Yes, false, "")}, + {0x1ee6c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee6d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee6e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee6f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee70, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee71, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee72, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee73, 0, 0, 0, f(Yes, false, "")}, + {0x1ee74, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee75, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee76, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee77, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee78, 0, 0, 0, f(Yes, false, "")}, + {0x1ee79, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee7a, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1ee7b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee7c, 0, 0, 0, g(Yes, No, false, false, "", "ٮ")}, + {0x1ee7d, 0, 0, 0, f(Yes, false, "")}, + {0x1ee7e, 0, 0, 0, g(Yes, No, false, false, "", "ڡ")}, + {0x1ee7f, 0, 0, 0, f(Yes, false, "")}, + {0x1ee80, 0, 0, 0, g(Yes, No, false, false, "", "ا")}, + {0x1ee81, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee82, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee83, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0x1ee84, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0x1ee85, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0x1ee86, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0x1ee87, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee88, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1ee89, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee8a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee8b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee8c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee8d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee8e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee8f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee90, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee91, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee92, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee93, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0x1ee94, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee95, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee96, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee97, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee98, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0x1ee99, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee9a, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1ee9b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee9c, 0, 0, 0, f(Yes, false, "")}, + {0x1eea1, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1eea2, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1eea3, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0x1eea4, 0, 0, 0, f(Yes, false, "")}, + {0x1eea5, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0x1eea6, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0x1eea7, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1eea8, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1eea9, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1eeaa, 0, 0, 0, f(Yes, false, "")}, + {0x1eeab, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1eeac, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1eead, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1eeae, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1eeaf, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1eeb0, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1eeb1, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1eeb2, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1eeb3, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0x1eeb4, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1eeb5, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1eeb6, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1eeb7, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1eeb8, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0x1eeb9, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1eeba, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1eebb, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1eebc, 0, 0, 0, f(Yes, false, "")}, + {0x1f100, 0, 0, 0, g(Yes, No, false, false, "", "0.")}, + {0x1f101, 0, 0, 0, g(Yes, No, false, false, "", "0,")}, + {0x1f102, 0, 0, 0, g(Yes, No, false, false, "", "1,")}, + {0x1f103, 0, 0, 0, g(Yes, No, false, false, "", "2,")}, + {0x1f104, 0, 0, 0, g(Yes, No, false, false, "", "3,")}, + {0x1f105, 0, 0, 0, g(Yes, No, false, false, "", "4,")}, + {0x1f106, 0, 0, 0, g(Yes, No, false, false, "", "5,")}, + {0x1f107, 0, 0, 0, g(Yes, No, false, false, "", "6,")}, + {0x1f108, 0, 0, 0, g(Yes, No, false, false, "", "7,")}, + {0x1f109, 0, 0, 0, g(Yes, No, false, false, "", "8,")}, + {0x1f10a, 0, 0, 0, g(Yes, No, false, false, "", "9,")}, + {0x1f10b, 0, 0, 0, f(Yes, false, "")}, + {0x1f110, 0, 0, 0, g(Yes, No, false, false, "", "(A)")}, + {0x1f111, 0, 0, 0, g(Yes, No, false, false, "", "(B)")}, + {0x1f112, 0, 0, 0, g(Yes, No, false, false, "", "(C)")}, + {0x1f113, 0, 0, 0, g(Yes, No, false, false, "", "(D)")}, + {0x1f114, 0, 0, 0, g(Yes, No, false, false, "", "(E)")}, + {0x1f115, 0, 0, 0, g(Yes, No, false, false, "", "(F)")}, + {0x1f116, 0, 0, 0, g(Yes, No, false, false, "", "(G)")}, + {0x1f117, 0, 0, 0, g(Yes, No, false, false, "", "(H)")}, + {0x1f118, 0, 0, 0, g(Yes, No, false, false, "", "(I)")}, + {0x1f119, 0, 0, 0, g(Yes, No, false, false, "", "(J)")}, + {0x1f11a, 0, 0, 0, g(Yes, No, false, false, "", "(K)")}, + {0x1f11b, 0, 0, 0, g(Yes, No, false, false, "", "(L)")}, + {0x1f11c, 0, 0, 0, g(Yes, No, false, false, "", "(M)")}, + {0x1f11d, 0, 0, 0, g(Yes, No, false, false, "", "(N)")}, + {0x1f11e, 0, 0, 0, g(Yes, No, false, false, "", "(O)")}, + {0x1f11f, 0, 0, 0, g(Yes, No, false, false, "", "(P)")}, + {0x1f120, 0, 0, 0, g(Yes, No, false, false, "", "(Q)")}, + {0x1f121, 0, 0, 0, g(Yes, No, false, false, "", "(R)")}, + {0x1f122, 0, 0, 0, g(Yes, No, false, false, "", "(S)")}, + {0x1f123, 0, 0, 0, g(Yes, No, false, false, "", "(T)")}, + {0x1f124, 0, 0, 0, g(Yes, No, false, false, "", "(U)")}, + {0x1f125, 0, 0, 0, g(Yes, No, false, false, "", "(V)")}, + {0x1f126, 0, 0, 0, g(Yes, No, false, false, "", "(W)")}, + {0x1f127, 0, 0, 0, g(Yes, No, false, false, "", "(X)")}, + {0x1f128, 0, 0, 0, g(Yes, No, false, false, "", "(Y)")}, + {0x1f129, 0, 0, 0, g(Yes, No, false, false, "", "(Z)")}, + {0x1f12a, 0, 0, 0, g(Yes, No, false, false, "", "〔S〕")}, + {0x1f12b, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1f12c, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1f12d, 0, 0, 0, g(Yes, No, false, false, "", "CD")}, + {0x1f12e, 0, 0, 0, g(Yes, No, false, false, "", "WZ")}, + {0x1f12f, 0, 0, 0, f(Yes, false, "")}, + {0x1f130, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1f131, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1f132, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1f133, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1f134, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1f135, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1f136, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1f137, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1f138, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1f139, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1f13a, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1f13b, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1f13c, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1f13d, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1f13e, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1f13f, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1f140, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1f141, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1f142, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1f143, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1f144, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1f145, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1f146, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1f147, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1f148, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1f149, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1f14a, 0, 0, 0, g(Yes, No, false, false, "", "HV")}, + {0x1f14b, 0, 0, 0, g(Yes, No, false, false, "", "MV")}, + {0x1f14c, 0, 0, 0, g(Yes, No, false, false, "", "SD")}, + {0x1f14d, 0, 0, 0, g(Yes, No, false, false, "", "SS")}, + {0x1f14e, 0, 0, 0, g(Yes, No, false, false, "", "PPV")}, + {0x1f14f, 0, 0, 0, g(Yes, No, false, false, "", "WC")}, + {0x1f150, 0, 0, 0, f(Yes, false, "")}, + {0x1f16a, 0, 0, 0, g(Yes, No, false, false, "", "MC")}, + {0x1f16b, 0, 0, 0, g(Yes, No, false, false, "", "MD")}, + {0x1f16c, 0, 0, 0, f(Yes, false, "")}, + {0x1f190, 0, 0, 0, g(Yes, No, false, false, "", "DJ")}, + {0x1f191, 0, 0, 0, f(Yes, false, "")}, + {0x1f200, 0, 0, 0, g(Yes, No, false, false, "", "ほか")}, + {0x1f201, 0, 0, 0, g(Yes, No, false, false, "", "ココ")}, + {0x1f202, 0, 0, 0, g(Yes, No, false, false, "", "サ")}, + {0x1f203, 0, 0, 0, f(Yes, false, "")}, + {0x1f210, 0, 0, 0, g(Yes, No, false, false, "", "手")}, + {0x1f211, 0, 0, 0, g(Yes, No, false, false, "", "字")}, + {0x1f212, 0, 0, 0, g(Yes, No, false, false, "", "双")}, + {0x1f213, 0, 0, 1, g(Yes, No, false, false, "", "デ")}, + {0x1f214, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x1f215, 0, 0, 0, g(Yes, No, false, false, "", "多")}, + {0x1f216, 0, 0, 0, g(Yes, No, false, false, "", "解")}, + {0x1f217, 0, 0, 0, g(Yes, No, false, false, "", "天")}, + {0x1f218, 0, 0, 0, g(Yes, No, false, false, "", "交")}, + {0x1f219, 0, 0, 0, g(Yes, No, false, false, "", "映")}, + {0x1f21a, 0, 0, 0, g(Yes, No, false, false, "", "無")}, + {0x1f21b, 0, 0, 0, g(Yes, No, false, false, "", "料")}, + {0x1f21c, 0, 0, 0, g(Yes, No, false, false, "", "前")}, + {0x1f21d, 0, 0, 0, g(Yes, No, false, false, "", "後")}, + {0x1f21e, 0, 0, 0, g(Yes, No, false, false, "", "再")}, + {0x1f21f, 0, 0, 0, g(Yes, No, false, false, "", "新")}, + {0x1f220, 0, 0, 0, g(Yes, No, false, false, "", "初")}, + {0x1f221, 0, 0, 0, g(Yes, No, false, false, "", "終")}, + {0x1f222, 0, 0, 0, g(Yes, No, false, false, "", "生")}, + {0x1f223, 0, 0, 0, g(Yes, No, false, false, "", "販")}, + {0x1f224, 0, 0, 0, g(Yes, No, false, false, "", "声")}, + {0x1f225, 0, 0, 0, g(Yes, No, false, false, "", "吹")}, + {0x1f226, 0, 0, 0, g(Yes, No, false, false, "", "演")}, + {0x1f227, 0, 0, 0, g(Yes, No, false, false, "", "投")}, + {0x1f228, 0, 0, 0, g(Yes, No, false, false, "", "捕")}, + {0x1f229, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x1f22a, 0, 0, 0, g(Yes, No, false, false, "", "三")}, + {0x1f22b, 0, 0, 0, g(Yes, No, false, false, "", "遊")}, + {0x1f22c, 0, 0, 0, g(Yes, No, false, false, "", "左")}, + {0x1f22d, 0, 0, 0, g(Yes, No, false, false, "", "中")}, + {0x1f22e, 0, 0, 0, g(Yes, No, false, false, "", "右")}, + {0x1f22f, 0, 0, 0, g(Yes, No, false, false, "", "指")}, + {0x1f230, 0, 0, 0, g(Yes, No, false, false, "", "走")}, + {0x1f231, 0, 0, 0, g(Yes, No, false, false, "", "打")}, + {0x1f232, 0, 0, 0, g(Yes, No, false, false, "", "禁")}, + {0x1f233, 0, 0, 0, g(Yes, No, false, false, "", "空")}, + {0x1f234, 0, 0, 0, g(Yes, No, false, false, "", "合")}, + {0x1f235, 0, 0, 0, g(Yes, No, false, false, "", "満")}, + {0x1f236, 0, 0, 0, g(Yes, No, false, false, "", "有")}, + {0x1f237, 0, 0, 0, g(Yes, No, false, false, "", "月")}, + {0x1f238, 0, 0, 0, g(Yes, No, false, false, "", "申")}, + {0x1f239, 0, 0, 0, g(Yes, No, false, false, "", "割")}, + {0x1f23a, 0, 0, 0, g(Yes, No, false, false, "", "営")}, + {0x1f23b, 0, 0, 0, g(Yes, No, false, false, "", "配")}, + {0x1f23c, 0, 0, 0, f(Yes, false, "")}, + {0x1f240, 0, 0, 0, g(Yes, No, false, false, "", "〔本〕")}, + {0x1f241, 0, 0, 0, g(Yes, No, false, false, "", "〔三〕")}, + {0x1f242, 0, 0, 0, g(Yes, No, false, false, "", "〔二〕")}, + {0x1f243, 0, 0, 0, g(Yes, No, false, false, "", "〔安〕")}, + {0x1f244, 0, 0, 0, g(Yes, No, false, false, "", "〔点〕")}, + {0x1f245, 0, 0, 0, g(Yes, No, false, false, "", "〔打〕")}, + {0x1f246, 0, 0, 0, g(Yes, No, false, false, "", "〔盗〕")}, + {0x1f247, 0, 0, 0, g(Yes, No, false, false, "", "〔勝〕")}, + {0x1f248, 0, 0, 0, g(Yes, No, false, false, "", "〔敗〕")}, + {0x1f249, 0, 0, 0, f(Yes, false, "")}, + {0x1f250, 0, 0, 0, g(Yes, No, false, false, "", "得")}, + {0x1f251, 0, 0, 0, g(Yes, No, false, false, "", "可")}, + {0x1f252, 0, 0, 0, f(Yes, false, "")}, + {0x2f800, 0, 0, 0, f(No, false, "丽")}, + {0x2f801, 0, 0, 0, f(No, false, "丸")}, + {0x2f802, 0, 0, 0, f(No, false, "乁")}, + {0x2f803, 0, 0, 0, f(No, false, "𠄢")}, + {0x2f804, 0, 0, 0, f(No, false, "你")}, + {0x2f805, 0, 0, 0, f(No, false, "侮")}, + {0x2f806, 0, 0, 0, f(No, false, "侻")}, + {0x2f807, 0, 0, 0, f(No, false, "倂")}, + {0x2f808, 0, 0, 0, f(No, false, "偺")}, + {0x2f809, 0, 0, 0, f(No, false, "備")}, + {0x2f80a, 0, 0, 0, f(No, false, "僧")}, + {0x2f80b, 0, 0, 0, f(No, false, "像")}, + {0x2f80c, 0, 0, 0, f(No, false, "㒞")}, + {0x2f80d, 0, 0, 0, f(No, false, "𠘺")}, + {0x2f80e, 0, 0, 0, f(No, false, "免")}, + {0x2f80f, 0, 0, 0, f(No, false, "兔")}, + {0x2f810, 0, 0, 0, f(No, false, "兤")}, + {0x2f811, 0, 0, 0, f(No, false, "具")}, + {0x2f812, 0, 0, 0, f(No, false, "𠔜")}, + {0x2f813, 0, 0, 0, f(No, false, "㒹")}, + {0x2f814, 0, 0, 0, f(No, false, "內")}, + {0x2f815, 0, 0, 0, f(No, false, "再")}, + {0x2f816, 0, 0, 0, f(No, false, "𠕋")}, + {0x2f817, 0, 0, 0, f(No, false, "冗")}, + {0x2f818, 0, 0, 0, f(No, false, "冤")}, + {0x2f819, 0, 0, 0, f(No, false, "仌")}, + {0x2f81a, 0, 0, 0, f(No, false, "冬")}, + {0x2f81b, 0, 0, 0, f(No, false, "况")}, + {0x2f81c, 0, 0, 0, f(No, false, "𩇟")}, + {0x2f81d, 0, 0, 0, f(No, false, "凵")}, + {0x2f81e, 0, 0, 0, f(No, false, "刃")}, + {0x2f81f, 0, 0, 0, f(No, false, "㓟")}, + {0x2f820, 0, 0, 0, f(No, false, "刻")}, + {0x2f821, 0, 0, 0, f(No, false, "剆")}, + {0x2f822, 0, 0, 0, f(No, false, "割")}, + {0x2f823, 0, 0, 0, f(No, false, "剷")}, + {0x2f824, 0, 0, 0, f(No, false, "㔕")}, + {0x2f825, 0, 0, 0, f(No, false, "勇")}, + {0x2f826, 0, 0, 0, f(No, false, "勉")}, + {0x2f827, 0, 0, 0, f(No, false, "勤")}, + {0x2f828, 0, 0, 0, f(No, false, "勺")}, + {0x2f829, 0, 0, 0, f(No, false, "包")}, + {0x2f82a, 0, 0, 0, f(No, false, "匆")}, + {0x2f82b, 0, 0, 0, f(No, false, "北")}, + {0x2f82c, 0, 0, 0, f(No, false, "卉")}, + {0x2f82d, 0, 0, 0, f(No, false, "卑")}, + {0x2f82e, 0, 0, 0, f(No, false, "博")}, + {0x2f82f, 0, 0, 0, f(No, false, "即")}, + {0x2f830, 0, 0, 0, f(No, false, "卽")}, + {0x2f831, 0, 0, 0, f(No, false, "卿")}, + {0x2f834, 0, 0, 0, f(No, false, "𠨬")}, + {0x2f835, 0, 0, 0, f(No, false, "灰")}, + {0x2f836, 0, 0, 0, f(No, false, "及")}, + {0x2f837, 0, 0, 0, f(No, false, "叟")}, + {0x2f838, 0, 0, 0, f(No, false, "𠭣")}, + {0x2f839, 0, 0, 0, f(No, false, "叫")}, + {0x2f83a, 0, 0, 0, f(No, false, "叱")}, + {0x2f83b, 0, 0, 0, f(No, false, "吆")}, + {0x2f83c, 0, 0, 0, f(No, false, "咞")}, + {0x2f83d, 0, 0, 0, f(No, false, "吸")}, + {0x2f83e, 0, 0, 0, f(No, false, "呈")}, + {0x2f83f, 0, 0, 0, f(No, false, "周")}, + {0x2f840, 0, 0, 0, f(No, false, "咢")}, + {0x2f841, 0, 0, 0, f(No, false, "哶")}, + {0x2f842, 0, 0, 0, f(No, false, "唐")}, + {0x2f843, 0, 0, 0, f(No, false, "啓")}, + {0x2f844, 0, 0, 0, f(No, false, "啣")}, + {0x2f845, 0, 0, 0, f(No, false, "善")}, + {0x2f847, 0, 0, 0, f(No, false, "喙")}, + {0x2f848, 0, 0, 0, f(No, false, "喫")}, + {0x2f849, 0, 0, 0, f(No, false, "喳")}, + {0x2f84a, 0, 0, 0, f(No, false, "嗂")}, + {0x2f84b, 0, 0, 0, f(No, false, "圖")}, + {0x2f84c, 0, 0, 0, f(No, false, "嘆")}, + {0x2f84d, 0, 0, 0, f(No, false, "圗")}, + {0x2f84e, 0, 0, 0, f(No, false, "噑")}, + {0x2f84f, 0, 0, 0, f(No, false, "噴")}, + {0x2f850, 0, 0, 0, f(No, false, "切")}, + {0x2f851, 0, 0, 0, f(No, false, "壮")}, + {0x2f852, 0, 0, 0, f(No, false, "城")}, + {0x2f853, 0, 0, 0, f(No, false, "埴")}, + {0x2f854, 0, 0, 0, f(No, false, "堍")}, + {0x2f855, 0, 0, 0, f(No, false, "型")}, + {0x2f856, 0, 0, 0, f(No, false, "堲")}, + {0x2f857, 0, 0, 0, f(No, false, "報")}, + {0x2f858, 0, 0, 0, f(No, false, "墬")}, + {0x2f859, 0, 0, 0, f(No, false, "𡓤")}, + {0x2f85a, 0, 0, 0, f(No, false, "売")}, + {0x2f85b, 0, 0, 0, f(No, false, "壷")}, + {0x2f85c, 0, 0, 0, f(No, false, "夆")}, + {0x2f85d, 0, 0, 0, f(No, false, "多")}, + {0x2f85e, 0, 0, 0, f(No, false, "夢")}, + {0x2f85f, 0, 0, 0, f(No, false, "奢")}, + {0x2f860, 0, 0, 0, f(No, false, "𡚨")}, + {0x2f861, 0, 0, 0, f(No, false, "𡛪")}, + {0x2f862, 0, 0, 0, f(No, false, "姬")}, + {0x2f863, 0, 0, 0, f(No, false, "娛")}, + {0x2f864, 0, 0, 0, f(No, false, "娧")}, + {0x2f865, 0, 0, 0, f(No, false, "姘")}, + {0x2f866, 0, 0, 0, f(No, false, "婦")}, + {0x2f867, 0, 0, 0, f(No, false, "㛮")}, + {0x2f868, 0, 0, 0, f(No, false, "㛼")}, + {0x2f869, 0, 0, 0, f(No, false, "嬈")}, + {0x2f86a, 0, 0, 0, f(No, false, "嬾")}, + {0x2f86c, 0, 0, 0, f(No, false, "𡧈")}, + {0x2f86d, 0, 0, 0, f(No, false, "寃")}, + {0x2f86e, 0, 0, 0, f(No, false, "寘")}, + {0x2f86f, 0, 0, 0, f(No, false, "寧")}, + {0x2f870, 0, 0, 0, f(No, false, "寳")}, + {0x2f871, 0, 0, 0, f(No, false, "𡬘")}, + {0x2f872, 0, 0, 0, f(No, false, "寿")}, + {0x2f873, 0, 0, 0, f(No, false, "将")}, + {0x2f874, 0, 0, 0, f(No, false, "当")}, + {0x2f875, 0, 0, 0, f(No, false, "尢")}, + {0x2f876, 0, 0, 0, f(No, false, "㞁")}, + {0x2f877, 0, 0, 0, f(No, false, "屠")}, + {0x2f878, 0, 0, 0, f(No, false, "屮")}, + {0x2f879, 0, 0, 0, f(No, false, "峀")}, + {0x2f87a, 0, 0, 0, f(No, false, "岍")}, + {0x2f87b, 0, 0, 0, f(No, false, "𡷤")}, + {0x2f87c, 0, 0, 0, f(No, false, "嵃")}, + {0x2f87d, 0, 0, 0, f(No, false, "𡷦")}, + {0x2f87e, 0, 0, 0, f(No, false, "嵮")}, + {0x2f87f, 0, 0, 0, f(No, false, "嵫")}, + {0x2f880, 0, 0, 0, f(No, false, "嵼")}, + {0x2f881, 0, 0, 0, f(No, false, "巡")}, + {0x2f882, 0, 0, 0, f(No, false, "巢")}, + {0x2f883, 0, 0, 0, f(No, false, "㠯")}, + {0x2f884, 0, 0, 0, f(No, false, "巽")}, + {0x2f885, 0, 0, 0, f(No, false, "帨")}, + {0x2f886, 0, 0, 0, f(No, false, "帽")}, + {0x2f887, 0, 0, 0, f(No, false, "幩")}, + {0x2f888, 0, 0, 0, f(No, false, "㡢")}, + {0x2f889, 0, 0, 0, f(No, false, "𢆃")}, + {0x2f88a, 0, 0, 0, f(No, false, "㡼")}, + {0x2f88b, 0, 0, 0, f(No, false, "庰")}, + {0x2f88c, 0, 0, 0, f(No, false, "庳")}, + {0x2f88d, 0, 0, 0, f(No, false, "庶")}, + {0x2f88e, 0, 0, 0, f(No, false, "廊")}, + {0x2f88f, 0, 0, 0, f(No, false, "𪎒")}, + {0x2f890, 0, 0, 0, f(No, false, "廾")}, + {0x2f891, 0, 0, 0, f(No, false, "𢌱")}, + {0x2f893, 0, 0, 0, f(No, false, "舁")}, + {0x2f894, 0, 0, 0, f(No, false, "弢")}, + {0x2f896, 0, 0, 0, f(No, false, "㣇")}, + {0x2f897, 0, 0, 0, f(No, false, "𣊸")}, + {0x2f898, 0, 0, 0, f(No, false, "𦇚")}, + {0x2f899, 0, 0, 0, f(No, false, "形")}, + {0x2f89a, 0, 0, 0, f(No, false, "彫")}, + {0x2f89b, 0, 0, 0, f(No, false, "㣣")}, + {0x2f89c, 0, 0, 0, f(No, false, "徚")}, + {0x2f89d, 0, 0, 0, f(No, false, "忍")}, + {0x2f89e, 0, 0, 0, f(No, false, "志")}, + {0x2f89f, 0, 0, 0, f(No, false, "忹")}, + {0x2f8a0, 0, 0, 0, f(No, false, "悁")}, + {0x2f8a1, 0, 0, 0, f(No, false, "㤺")}, + {0x2f8a2, 0, 0, 0, f(No, false, "㤜")}, + {0x2f8a3, 0, 0, 0, f(No, false, "悔")}, + {0x2f8a4, 0, 0, 0, f(No, false, "𢛔")}, + {0x2f8a5, 0, 0, 0, f(No, false, "惇")}, + {0x2f8a6, 0, 0, 0, f(No, false, "慈")}, + {0x2f8a7, 0, 0, 0, f(No, false, "慌")}, + {0x2f8a8, 0, 0, 0, f(No, false, "慎")}, + {0x2f8a9, 0, 0, 0, f(No, false, "慌")}, + {0x2f8aa, 0, 0, 0, f(No, false, "慺")}, + {0x2f8ab, 0, 0, 0, f(No, false, "憎")}, + {0x2f8ac, 0, 0, 0, f(No, false, "憲")}, + {0x2f8ad, 0, 0, 0, f(No, false, "憤")}, + {0x2f8ae, 0, 0, 0, f(No, false, "憯")}, + {0x2f8af, 0, 0, 0, f(No, false, "懞")}, + {0x2f8b0, 0, 0, 0, f(No, false, "懲")}, + {0x2f8b1, 0, 0, 0, f(No, false, "懶")}, + {0x2f8b2, 0, 0, 0, f(No, false, "成")}, + {0x2f8b3, 0, 0, 0, f(No, false, "戛")}, + {0x2f8b4, 0, 0, 0, f(No, false, "扝")}, + {0x2f8b5, 0, 0, 0, f(No, false, "抱")}, + {0x2f8b6, 0, 0, 0, f(No, false, "拔")}, + {0x2f8b7, 0, 0, 0, f(No, false, "捐")}, + {0x2f8b8, 0, 0, 0, f(No, false, "𢬌")}, + {0x2f8b9, 0, 0, 0, f(No, false, "挽")}, + {0x2f8ba, 0, 0, 0, f(No, false, "拼")}, + {0x2f8bb, 0, 0, 0, f(No, false, "捨")}, + {0x2f8bc, 0, 0, 0, f(No, false, "掃")}, + {0x2f8bd, 0, 0, 0, f(No, false, "揤")}, + {0x2f8be, 0, 0, 0, f(No, false, "𢯱")}, + {0x2f8bf, 0, 0, 0, f(No, false, "搢")}, + {0x2f8c0, 0, 0, 0, f(No, false, "揅")}, + {0x2f8c1, 0, 0, 0, f(No, false, "掩")}, + {0x2f8c2, 0, 0, 0, f(No, false, "㨮")}, + {0x2f8c3, 0, 0, 0, f(No, false, "摩")}, + {0x2f8c4, 0, 0, 0, f(No, false, "摾")}, + {0x2f8c5, 0, 0, 0, f(No, false, "撝")}, + {0x2f8c6, 0, 0, 0, f(No, false, "摷")}, + {0x2f8c7, 0, 0, 0, f(No, false, "㩬")}, + {0x2f8c8, 0, 0, 0, f(No, false, "敏")}, + {0x2f8c9, 0, 0, 0, f(No, false, "敬")}, + {0x2f8ca, 0, 0, 0, f(No, false, "𣀊")}, + {0x2f8cb, 0, 0, 0, f(No, false, "旣")}, + {0x2f8cc, 0, 0, 0, f(No, false, "書")}, + {0x2f8cd, 0, 0, 0, f(No, false, "晉")}, + {0x2f8ce, 0, 0, 0, f(No, false, "㬙")}, + {0x2f8cf, 0, 0, 0, f(No, false, "暑")}, + {0x2f8d0, 0, 0, 0, f(No, false, "㬈")}, + {0x2f8d1, 0, 0, 0, f(No, false, "㫤")}, + {0x2f8d2, 0, 0, 0, f(No, false, "冒")}, + {0x2f8d3, 0, 0, 0, f(No, false, "冕")}, + {0x2f8d4, 0, 0, 0, f(No, false, "最")}, + {0x2f8d5, 0, 0, 0, f(No, false, "暜")}, + {0x2f8d6, 0, 0, 0, f(No, false, "肭")}, + {0x2f8d7, 0, 0, 0, f(No, false, "䏙")}, + {0x2f8d8, 0, 0, 0, f(No, false, "朗")}, + {0x2f8d9, 0, 0, 0, f(No, false, "望")}, + {0x2f8da, 0, 0, 0, f(No, false, "朡")}, + {0x2f8db, 0, 0, 0, f(No, false, "杞")}, + {0x2f8dc, 0, 0, 0, f(No, false, "杓")}, + {0x2f8dd, 0, 0, 0, f(No, false, "𣏃")}, + {0x2f8de, 0, 0, 0, f(No, false, "㭉")}, + {0x2f8df, 0, 0, 0, f(No, false, "柺")}, + {0x2f8e0, 0, 0, 0, f(No, false, "枅")}, + {0x2f8e1, 0, 0, 0, f(No, false, "桒")}, + {0x2f8e2, 0, 0, 0, f(No, false, "梅")}, + {0x2f8e3, 0, 0, 0, f(No, false, "𣑭")}, + {0x2f8e4, 0, 0, 0, f(No, false, "梎")}, + {0x2f8e5, 0, 0, 0, f(No, false, "栟")}, + {0x2f8e6, 0, 0, 0, f(No, false, "椔")}, + {0x2f8e7, 0, 0, 0, f(No, false, "㮝")}, + {0x2f8e8, 0, 0, 0, f(No, false, "楂")}, + {0x2f8e9, 0, 0, 0, f(No, false, "榣")}, + {0x2f8ea, 0, 0, 0, f(No, false, "槪")}, + {0x2f8eb, 0, 0, 0, f(No, false, "檨")}, + {0x2f8ec, 0, 0, 0, f(No, false, "𣚣")}, + {0x2f8ed, 0, 0, 0, f(No, false, "櫛")}, + {0x2f8ee, 0, 0, 0, f(No, false, "㰘")}, + {0x2f8ef, 0, 0, 0, f(No, false, "次")}, + {0x2f8f0, 0, 0, 0, f(No, false, "𣢧")}, + {0x2f8f1, 0, 0, 0, f(No, false, "歔")}, + {0x2f8f2, 0, 0, 0, f(No, false, "㱎")}, + {0x2f8f3, 0, 0, 0, f(No, false, "歲")}, + {0x2f8f4, 0, 0, 0, f(No, false, "殟")}, + {0x2f8f5, 0, 0, 0, f(No, false, "殺")}, + {0x2f8f6, 0, 0, 0, f(No, false, "殻")}, + {0x2f8f7, 0, 0, 0, f(No, false, "𣪍")}, + {0x2f8f8, 0, 0, 0, f(No, false, "𡴋")}, + {0x2f8f9, 0, 0, 0, f(No, false, "𣫺")}, + {0x2f8fa, 0, 0, 0, f(No, false, "汎")}, + {0x2f8fb, 0, 0, 0, f(No, false, "𣲼")}, + {0x2f8fc, 0, 0, 0, f(No, false, "沿")}, + {0x2f8fd, 0, 0, 0, f(No, false, "泍")}, + {0x2f8fe, 0, 0, 0, f(No, false, "汧")}, + {0x2f8ff, 0, 0, 0, f(No, false, "洖")}, + {0x2f900, 0, 0, 0, f(No, false, "派")}, + {0x2f901, 0, 0, 0, f(No, false, "海")}, + {0x2f902, 0, 0, 0, f(No, false, "流")}, + {0x2f903, 0, 0, 0, f(No, false, "浩")}, + {0x2f904, 0, 0, 0, f(No, false, "浸")}, + {0x2f905, 0, 0, 0, f(No, false, "涅")}, + {0x2f906, 0, 0, 0, f(No, false, "𣴞")}, + {0x2f907, 0, 0, 0, f(No, false, "洴")}, + {0x2f908, 0, 0, 0, f(No, false, "港")}, + {0x2f909, 0, 0, 0, f(No, false, "湮")}, + {0x2f90a, 0, 0, 0, f(No, false, "㴳")}, + {0x2f90b, 0, 0, 0, f(No, false, "滋")}, + {0x2f90c, 0, 0, 0, f(No, false, "滇")}, + {0x2f90d, 0, 0, 0, f(No, false, "𣻑")}, + {0x2f90e, 0, 0, 0, f(No, false, "淹")}, + {0x2f90f, 0, 0, 0, f(No, false, "潮")}, + {0x2f910, 0, 0, 0, f(No, false, "𣽞")}, + {0x2f911, 0, 0, 0, f(No, false, "𣾎")}, + {0x2f912, 0, 0, 0, f(No, false, "濆")}, + {0x2f913, 0, 0, 0, f(No, false, "瀹")}, + {0x2f914, 0, 0, 0, f(No, false, "瀞")}, + {0x2f915, 0, 0, 0, f(No, false, "瀛")}, + {0x2f916, 0, 0, 0, f(No, false, "㶖")}, + {0x2f917, 0, 0, 0, f(No, false, "灊")}, + {0x2f918, 0, 0, 0, f(No, false, "災")}, + {0x2f919, 0, 0, 0, f(No, false, "灷")}, + {0x2f91a, 0, 0, 0, f(No, false, "炭")}, + {0x2f91b, 0, 0, 0, f(No, false, "𠔥")}, + {0x2f91c, 0, 0, 0, f(No, false, "煅")}, + {0x2f91d, 0, 0, 0, f(No, false, "𤉣")}, + {0x2f91e, 0, 0, 0, f(No, false, "熜")}, + {0x2f91f, 0, 0, 0, f(No, false, "𤎫")}, + {0x2f920, 0, 0, 0, f(No, false, "爨")}, + {0x2f921, 0, 0, 0, f(No, false, "爵")}, + {0x2f922, 0, 0, 0, f(No, false, "牐")}, + {0x2f923, 0, 0, 0, f(No, false, "𤘈")}, + {0x2f924, 0, 0, 0, f(No, false, "犀")}, + {0x2f925, 0, 0, 0, f(No, false, "犕")}, + {0x2f926, 0, 0, 0, f(No, false, "𤜵")}, + {0x2f927, 0, 0, 0, f(No, false, "𤠔")}, + {0x2f928, 0, 0, 0, f(No, false, "獺")}, + {0x2f929, 0, 0, 0, f(No, false, "王")}, + {0x2f92a, 0, 0, 0, f(No, false, "㺬")}, + {0x2f92b, 0, 0, 0, f(No, false, "玥")}, + {0x2f92c, 0, 0, 0, f(No, false, "㺸")}, + {0x2f92e, 0, 0, 0, f(No, false, "瑇")}, + {0x2f92f, 0, 0, 0, f(No, false, "瑜")}, + {0x2f930, 0, 0, 0, f(No, false, "瑱")}, + {0x2f931, 0, 0, 0, f(No, false, "璅")}, + {0x2f932, 0, 0, 0, f(No, false, "瓊")}, + {0x2f933, 0, 0, 0, f(No, false, "㼛")}, + {0x2f934, 0, 0, 0, f(No, false, "甤")}, + {0x2f935, 0, 0, 0, f(No, false, "𤰶")}, + {0x2f936, 0, 0, 0, f(No, false, "甾")}, + {0x2f937, 0, 0, 0, f(No, false, "𤲒")}, + {0x2f938, 0, 0, 0, f(No, false, "異")}, + {0x2f939, 0, 0, 0, f(No, false, "𢆟")}, + {0x2f93a, 0, 0, 0, f(No, false, "瘐")}, + {0x2f93b, 0, 0, 0, f(No, false, "𤾡")}, + {0x2f93c, 0, 0, 0, f(No, false, "𤾸")}, + {0x2f93d, 0, 0, 0, f(No, false, "𥁄")}, + {0x2f93e, 0, 0, 0, f(No, false, "㿼")}, + {0x2f93f, 0, 0, 0, f(No, false, "䀈")}, + {0x2f940, 0, 0, 0, f(No, false, "直")}, + {0x2f941, 0, 0, 0, f(No, false, "𥃳")}, + {0x2f942, 0, 0, 0, f(No, false, "𥃲")}, + {0x2f943, 0, 0, 0, f(No, false, "𥄙")}, + {0x2f944, 0, 0, 0, f(No, false, "𥄳")}, + {0x2f945, 0, 0, 0, f(No, false, "眞")}, + {0x2f946, 0, 0, 0, f(No, false, "真")}, + {0x2f948, 0, 0, 0, f(No, false, "睊")}, + {0x2f949, 0, 0, 0, f(No, false, "䀹")}, + {0x2f94a, 0, 0, 0, f(No, false, "瞋")}, + {0x2f94b, 0, 0, 0, f(No, false, "䁆")}, + {0x2f94c, 0, 0, 0, f(No, false, "䂖")}, + {0x2f94d, 0, 0, 0, f(No, false, "𥐝")}, + {0x2f94e, 0, 0, 0, f(No, false, "硎")}, + {0x2f94f, 0, 0, 0, f(No, false, "碌")}, + {0x2f950, 0, 0, 0, f(No, false, "磌")}, + {0x2f951, 0, 0, 0, f(No, false, "䃣")}, + {0x2f952, 0, 0, 0, f(No, false, "𥘦")}, + {0x2f953, 0, 0, 0, f(No, false, "祖")}, + {0x2f954, 0, 0, 0, f(No, false, "𥚚")}, + {0x2f955, 0, 0, 0, f(No, false, "𥛅")}, + {0x2f956, 0, 0, 0, f(No, false, "福")}, + {0x2f957, 0, 0, 0, f(No, false, "秫")}, + {0x2f958, 0, 0, 0, f(No, false, "䄯")}, + {0x2f959, 0, 0, 0, f(No, false, "穀")}, + {0x2f95a, 0, 0, 0, f(No, false, "穊")}, + {0x2f95b, 0, 0, 0, f(No, false, "穏")}, + {0x2f95c, 0, 0, 0, f(No, false, "𥥼")}, + {0x2f95d, 0, 0, 0, f(No, false, "𥪧")}, + {0x2f95f, 0, 0, 0, f(No, false, "竮")}, + {0x2f960, 0, 0, 0, f(No, false, "䈂")}, + {0x2f961, 0, 0, 0, f(No, false, "𥮫")}, + {0x2f962, 0, 0, 0, f(No, false, "篆")}, + {0x2f963, 0, 0, 0, f(No, false, "築")}, + {0x2f964, 0, 0, 0, f(No, false, "䈧")}, + {0x2f965, 0, 0, 0, f(No, false, "𥲀")}, + {0x2f966, 0, 0, 0, f(No, false, "糒")}, + {0x2f967, 0, 0, 0, f(No, false, "䊠")}, + {0x2f968, 0, 0, 0, f(No, false, "糨")}, + {0x2f969, 0, 0, 0, f(No, false, "糣")}, + {0x2f96a, 0, 0, 0, f(No, false, "紀")}, + {0x2f96b, 0, 0, 0, f(No, false, "𥾆")}, + {0x2f96c, 0, 0, 0, f(No, false, "絣")}, + {0x2f96d, 0, 0, 0, f(No, false, "䌁")}, + {0x2f96e, 0, 0, 0, f(No, false, "緇")}, + {0x2f96f, 0, 0, 0, f(No, false, "縂")}, + {0x2f970, 0, 0, 0, f(No, false, "繅")}, + {0x2f971, 0, 0, 0, f(No, false, "䌴")}, + {0x2f972, 0, 0, 0, f(No, false, "𦈨")}, + {0x2f973, 0, 0, 0, f(No, false, "𦉇")}, + {0x2f974, 0, 0, 0, f(No, false, "䍙")}, + {0x2f975, 0, 0, 0, f(No, false, "𦋙")}, + {0x2f976, 0, 0, 0, f(No, false, "罺")}, + {0x2f977, 0, 0, 0, f(No, false, "𦌾")}, + {0x2f978, 0, 0, 0, f(No, false, "羕")}, + {0x2f979, 0, 0, 0, f(No, false, "翺")}, + {0x2f97a, 0, 0, 0, f(No, false, "者")}, + {0x2f97b, 0, 0, 0, f(No, false, "𦓚")}, + {0x2f97c, 0, 0, 0, f(No, false, "𦔣")}, + {0x2f97d, 0, 0, 0, f(No, false, "聠")}, + {0x2f97e, 0, 0, 0, f(No, false, "𦖨")}, + {0x2f97f, 0, 0, 0, f(No, false, "聰")}, + {0x2f980, 0, 0, 0, f(No, false, "𣍟")}, + {0x2f981, 0, 0, 0, f(No, false, "䏕")}, + {0x2f982, 0, 0, 0, f(No, false, "育")}, + {0x2f983, 0, 0, 0, f(No, false, "脃")}, + {0x2f984, 0, 0, 0, f(No, false, "䐋")}, + {0x2f985, 0, 0, 0, f(No, false, "脾")}, + {0x2f986, 0, 0, 0, f(No, false, "媵")}, + {0x2f987, 0, 0, 0, f(No, false, "𦞧")}, + {0x2f988, 0, 0, 0, f(No, false, "𦞵")}, + {0x2f989, 0, 0, 0, f(No, false, "𣎓")}, + {0x2f98a, 0, 0, 0, f(No, false, "𣎜")}, + {0x2f98b, 0, 0, 0, f(No, false, "舁")}, + {0x2f98c, 0, 0, 0, f(No, false, "舄")}, + {0x2f98d, 0, 0, 0, f(No, false, "辞")}, + {0x2f98e, 0, 0, 0, f(No, false, "䑫")}, + {0x2f98f, 0, 0, 0, f(No, false, "芑")}, + {0x2f990, 0, 0, 0, f(No, false, "芋")}, + {0x2f991, 0, 0, 0, f(No, false, "芝")}, + {0x2f992, 0, 0, 0, f(No, false, "劳")}, + {0x2f993, 0, 0, 0, f(No, false, "花")}, + {0x2f994, 0, 0, 0, f(No, false, "芳")}, + {0x2f995, 0, 0, 0, f(No, false, "芽")}, + {0x2f996, 0, 0, 0, f(No, false, "苦")}, + {0x2f997, 0, 0, 0, f(No, false, "𦬼")}, + {0x2f998, 0, 0, 0, f(No, false, "若")}, + {0x2f999, 0, 0, 0, f(No, false, "茝")}, + {0x2f99a, 0, 0, 0, f(No, false, "荣")}, + {0x2f99b, 0, 0, 0, f(No, false, "莭")}, + {0x2f99c, 0, 0, 0, f(No, false, "茣")}, + {0x2f99d, 0, 0, 0, f(No, false, "莽")}, + {0x2f99e, 0, 0, 0, f(No, false, "菧")}, + {0x2f99f, 0, 0, 0, f(No, false, "著")}, + {0x2f9a0, 0, 0, 0, f(No, false, "荓")}, + {0x2f9a1, 0, 0, 0, f(No, false, "菊")}, + {0x2f9a2, 0, 0, 0, f(No, false, "菌")}, + {0x2f9a3, 0, 0, 0, f(No, false, "菜")}, + {0x2f9a4, 0, 0, 0, f(No, false, "𦰶")}, + {0x2f9a5, 0, 0, 0, f(No, false, "𦵫")}, + {0x2f9a6, 0, 0, 0, f(No, false, "𦳕")}, + {0x2f9a7, 0, 0, 0, f(No, false, "䔫")}, + {0x2f9a8, 0, 0, 0, f(No, false, "蓱")}, + {0x2f9a9, 0, 0, 0, f(No, false, "蓳")}, + {0x2f9aa, 0, 0, 0, f(No, false, "蔖")}, + {0x2f9ab, 0, 0, 0, f(No, false, "𧏊")}, + {0x2f9ac, 0, 0, 0, f(No, false, "蕤")}, + {0x2f9ad, 0, 0, 0, f(No, false, "𦼬")}, + {0x2f9ae, 0, 0, 0, f(No, false, "䕝")}, + {0x2f9af, 0, 0, 0, f(No, false, "䕡")}, + {0x2f9b0, 0, 0, 0, f(No, false, "𦾱")}, + {0x2f9b1, 0, 0, 0, f(No, false, "𧃒")}, + {0x2f9b2, 0, 0, 0, f(No, false, "䕫")}, + {0x2f9b3, 0, 0, 0, f(No, false, "虐")}, + {0x2f9b4, 0, 0, 0, f(No, false, "虜")}, + {0x2f9b5, 0, 0, 0, f(No, false, "虧")}, + {0x2f9b6, 0, 0, 0, f(No, false, "虩")}, + {0x2f9b7, 0, 0, 0, f(No, false, "蚩")}, + {0x2f9b8, 0, 0, 0, f(No, false, "蚈")}, + {0x2f9b9, 0, 0, 0, f(No, false, "蜎")}, + {0x2f9ba, 0, 0, 0, f(No, false, "蛢")}, + {0x2f9bb, 0, 0, 0, f(No, false, "蝹")}, + {0x2f9bc, 0, 0, 0, f(No, false, "蜨")}, + {0x2f9bd, 0, 0, 0, f(No, false, "蝫")}, + {0x2f9be, 0, 0, 0, f(No, false, "螆")}, + {0x2f9bf, 0, 0, 0, f(No, false, "䗗")}, + {0x2f9c0, 0, 0, 0, f(No, false, "蟡")}, + {0x2f9c1, 0, 0, 0, f(No, false, "蠁")}, + {0x2f9c2, 0, 0, 0, f(No, false, "䗹")}, + {0x2f9c3, 0, 0, 0, f(No, false, "衠")}, + {0x2f9c4, 0, 0, 0, f(No, false, "衣")}, + {0x2f9c5, 0, 0, 0, f(No, false, "𧙧")}, + {0x2f9c6, 0, 0, 0, f(No, false, "裗")}, + {0x2f9c7, 0, 0, 0, f(No, false, "裞")}, + {0x2f9c8, 0, 0, 0, f(No, false, "䘵")}, + {0x2f9c9, 0, 0, 0, f(No, false, "裺")}, + {0x2f9ca, 0, 0, 0, f(No, false, "㒻")}, + {0x2f9cb, 0, 0, 0, f(No, false, "𧢮")}, + {0x2f9cc, 0, 0, 0, f(No, false, "𧥦")}, + {0x2f9cd, 0, 0, 0, f(No, false, "䚾")}, + {0x2f9ce, 0, 0, 0, f(No, false, "䛇")}, + {0x2f9cf, 0, 0, 0, f(No, false, "誠")}, + {0x2f9d0, 0, 0, 0, f(No, false, "諭")}, + {0x2f9d1, 0, 0, 0, f(No, false, "變")}, + {0x2f9d2, 0, 0, 0, f(No, false, "豕")}, + {0x2f9d3, 0, 0, 0, f(No, false, "𧲨")}, + {0x2f9d4, 0, 0, 0, f(No, false, "貫")}, + {0x2f9d5, 0, 0, 0, f(No, false, "賁")}, + {0x2f9d6, 0, 0, 0, f(No, false, "贛")}, + {0x2f9d7, 0, 0, 0, f(No, false, "起")}, + {0x2f9d8, 0, 0, 0, f(No, false, "𧼯")}, + {0x2f9d9, 0, 0, 0, f(No, false, "𠠄")}, + {0x2f9da, 0, 0, 0, f(No, false, "跋")}, + {0x2f9db, 0, 0, 0, f(No, false, "趼")}, + {0x2f9dc, 0, 0, 0, f(No, false, "跰")}, + {0x2f9dd, 0, 0, 0, f(No, false, "𠣞")}, + {0x2f9de, 0, 0, 0, f(No, false, "軔")}, + {0x2f9df, 0, 0, 0, f(No, false, "輸")}, + {0x2f9e0, 0, 0, 0, f(No, false, "𨗒")}, + {0x2f9e1, 0, 0, 0, f(No, false, "𨗭")}, + {0x2f9e2, 0, 0, 0, f(No, false, "邔")}, + {0x2f9e3, 0, 0, 0, f(No, false, "郱")}, + {0x2f9e4, 0, 0, 0, f(No, false, "鄑")}, + {0x2f9e5, 0, 0, 0, f(No, false, "𨜮")}, + {0x2f9e6, 0, 0, 0, f(No, false, "鄛")}, + {0x2f9e7, 0, 0, 0, f(No, false, "鈸")}, + {0x2f9e8, 0, 0, 0, f(No, false, "鋗")}, + {0x2f9e9, 0, 0, 0, f(No, false, "鋘")}, + {0x2f9ea, 0, 0, 0, f(No, false, "鉼")}, + {0x2f9eb, 0, 0, 0, f(No, false, "鏹")}, + {0x2f9ec, 0, 0, 0, f(No, false, "鐕")}, + {0x2f9ed, 0, 0, 0, f(No, false, "𨯺")}, + {0x2f9ee, 0, 0, 0, f(No, false, "開")}, + {0x2f9ef, 0, 0, 0, f(No, false, "䦕")}, + {0x2f9f0, 0, 0, 0, f(No, false, "閷")}, + {0x2f9f1, 0, 0, 0, f(No, false, "𨵷")}, + {0x2f9f2, 0, 0, 0, f(No, false, "䧦")}, + {0x2f9f3, 0, 0, 0, f(No, false, "雃")}, + {0x2f9f4, 0, 0, 0, f(No, false, "嶲")}, + {0x2f9f5, 0, 0, 0, f(No, false, "霣")}, + {0x2f9f6, 0, 0, 0, f(No, false, "𩅅")}, + {0x2f9f7, 0, 0, 0, f(No, false, "𩈚")}, + {0x2f9f8, 0, 0, 0, f(No, false, "䩮")}, + {0x2f9f9, 0, 0, 0, f(No, false, "䩶")}, + {0x2f9fa, 0, 0, 0, f(No, false, "韠")}, + {0x2f9fb, 0, 0, 0, f(No, false, "𩐊")}, + {0x2f9fc, 0, 0, 0, f(No, false, "䪲")}, + {0x2f9fd, 0, 0, 0, f(No, false, "𩒖")}, + {0x2f9fe, 0, 0, 0, f(No, false, "頋")}, + {0x2fa00, 0, 0, 0, f(No, false, "頩")}, + {0x2fa01, 0, 0, 0, f(No, false, "𩖶")}, + {0x2fa02, 0, 0, 0, f(No, false, "飢")}, + {0x2fa03, 0, 0, 0, f(No, false, "䬳")}, + {0x2fa04, 0, 0, 0, f(No, false, "餩")}, + {0x2fa05, 0, 0, 0, f(No, false, "馧")}, + {0x2fa06, 0, 0, 0, f(No, false, "駂")}, + {0x2fa07, 0, 0, 0, f(No, false, "駾")}, + {0x2fa08, 0, 0, 0, f(No, false, "䯎")}, + {0x2fa09, 0, 0, 0, f(No, false, "𩬰")}, + {0x2fa0a, 0, 0, 0, f(No, false, "鬒")}, + {0x2fa0b, 0, 0, 0, f(No, false, "鱀")}, + {0x2fa0c, 0, 0, 0, f(No, false, "鳽")}, + {0x2fa0d, 0, 0, 0, f(No, false, "䳎")}, + {0x2fa0e, 0, 0, 0, f(No, false, "䳭")}, + {0x2fa0f, 0, 0, 0, f(No, false, "鵧")}, + {0x2fa10, 0, 0, 0, f(No, false, "𪃎")}, + {0x2fa11, 0, 0, 0, f(No, false, "䳸")}, + {0x2fa12, 0, 0, 0, f(No, false, "𪄅")}, + {0x2fa13, 0, 0, 0, f(No, false, "𪈎")}, + {0x2fa14, 0, 0, 0, f(No, false, "𪊑")}, + {0x2fa15, 0, 0, 0, f(No, false, "麻")}, + {0x2fa16, 0, 0, 0, f(No, false, "䵖")}, + {0x2fa17, 0, 0, 0, f(No, false, "黹")}, + {0x2fa18, 0, 0, 0, f(No, false, "黾")}, + {0x2fa19, 0, 0, 0, f(No, false, "鼅")}, + {0x2fa1a, 0, 0, 0, f(No, false, "鼏")}, + {0x2fa1b, 0, 0, 0, f(No, false, "鼖")}, + {0x2fa1c, 0, 0, 0, f(No, false, "鼻")}, + {0x2fa1d, 0, 0, 0, f(No, false, "𪘀")}, + {0x2fa1e, 0, 0, 0, f(Yes, false, "")}, +} diff --git a/vendor/golang.org/x/text/unicode/norm/data9.0.0_test.go b/vendor/golang.org/x/text/unicode/norm/data9.0.0_test.go new file mode 100644 index 000000000..b1be64d55 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/data9.0.0_test.go @@ -0,0 +1,7409 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// +build !go1.10 + +package norm + +const ( + Yes = iota + No + Maybe +) + +type formData struct { + qc uint8 + combinesForward bool + decomposition string +} + +type runeData struct { + r rune + ccc uint8 + nLead uint8 + nTrail uint8 + f [2]formData // 0: canonical; 1: compatibility +} + +func f(qc uint8, cf bool, dec string) [2]formData { + return [2]formData{{qc, cf, dec}, {qc, cf, dec}} +} + +func g(qc, qck uint8, cf, cfk bool, d, dk string) [2]formData { + return [2]formData{{qc, cf, d}, {qck, cfk, dk}} +} + +var testData = []runeData{ + {0x0, 0, 0, 0, f(Yes, false, "")}, + {0x3c, 0, 0, 0, f(Yes, true, "")}, + {0x3f, 0, 0, 0, f(Yes, false, "")}, + {0x41, 0, 0, 0, f(Yes, true, "")}, + {0x51, 0, 0, 0, f(Yes, false, "")}, + {0x52, 0, 0, 0, f(Yes, true, "")}, + {0x5b, 0, 0, 0, f(Yes, false, "")}, + {0x61, 0, 0, 0, f(Yes, true, "")}, + {0x71, 0, 0, 0, f(Yes, false, "")}, + {0x72, 0, 0, 0, f(Yes, true, "")}, + {0x7b, 0, 0, 0, f(Yes, false, "")}, + {0xa0, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0xa1, 0, 0, 0, f(Yes, false, "")}, + {0xa8, 0, 0, 1, g(Yes, No, true, false, "", " ̈")}, + {0xa9, 0, 0, 0, f(Yes, false, "")}, + {0xaa, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0xab, 0, 0, 0, f(Yes, false, "")}, + {0xaf, 0, 0, 1, g(Yes, No, false, false, "", " ̄")}, + {0xb0, 0, 0, 0, f(Yes, false, "")}, + {0xb2, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0xb3, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0xb4, 0, 0, 1, g(Yes, No, false, false, "", " ́")}, + {0xb5, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0xb6, 0, 0, 0, f(Yes, false, "")}, + {0xb8, 0, 0, 1, g(Yes, No, false, false, "", " ̧")}, + {0xb9, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0xba, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0xbb, 0, 0, 0, f(Yes, false, "")}, + {0xbc, 0, 0, 0, g(Yes, No, false, false, "", "1⁄4")}, + {0xbd, 0, 0, 0, g(Yes, No, false, false, "", "1⁄2")}, + {0xbe, 0, 0, 0, g(Yes, No, false, false, "", "3⁄4")}, + {0xbf, 0, 0, 0, f(Yes, false, "")}, + {0xc0, 0, 0, 1, f(Yes, false, "À")}, + {0xc1, 0, 0, 1, f(Yes, false, "Á")}, + {0xc2, 0, 0, 1, f(Yes, true, "Â")}, + {0xc3, 0, 0, 1, f(Yes, false, "Ã")}, + {0xc4, 0, 0, 1, f(Yes, true, "Ä")}, + {0xc5, 0, 0, 1, f(Yes, true, "Å")}, + {0xc6, 0, 0, 0, f(Yes, true, "")}, + {0xc7, 0, 0, 1, f(Yes, true, "Ç")}, + {0xc8, 0, 0, 1, f(Yes, false, "È")}, + {0xc9, 0, 0, 1, f(Yes, false, "É")}, + {0xca, 0, 0, 1, f(Yes, true, "Ê")}, + {0xcb, 0, 0, 1, f(Yes, false, "Ë")}, + {0xcc, 0, 0, 1, f(Yes, false, "Ì")}, + {0xcd, 0, 0, 1, f(Yes, false, "Í")}, + {0xce, 0, 0, 1, f(Yes, false, "Î")}, + {0xcf, 0, 0, 1, f(Yes, true, "Ï")}, + {0xd0, 0, 0, 0, f(Yes, false, "")}, + {0xd1, 0, 0, 1, f(Yes, false, "Ñ")}, + {0xd2, 0, 0, 1, f(Yes, false, "Ò")}, + {0xd3, 0, 0, 1, f(Yes, false, "Ó")}, + {0xd4, 0, 0, 1, f(Yes, true, "Ô")}, + {0xd5, 0, 0, 1, f(Yes, true, "Õ")}, + {0xd6, 0, 0, 1, f(Yes, true, "Ö")}, + {0xd7, 0, 0, 0, f(Yes, false, "")}, + {0xd8, 0, 0, 0, f(Yes, true, "")}, + {0xd9, 0, 0, 1, f(Yes, false, "Ù")}, + {0xda, 0, 0, 1, f(Yes, false, "Ú")}, + {0xdb, 0, 0, 1, f(Yes, false, "Û")}, + {0xdc, 0, 0, 1, f(Yes, true, "Ü")}, + {0xdd, 0, 0, 1, f(Yes, false, "Ý")}, + {0xde, 0, 0, 0, f(Yes, false, "")}, + {0xe0, 0, 0, 1, f(Yes, false, "à")}, + {0xe1, 0, 0, 1, f(Yes, false, "á")}, + {0xe2, 0, 0, 1, f(Yes, true, "â")}, + {0xe3, 0, 0, 1, f(Yes, false, "ã")}, + {0xe4, 0, 0, 1, f(Yes, true, "ä")}, + {0xe5, 0, 0, 1, f(Yes, true, "å")}, + {0xe6, 0, 0, 0, f(Yes, true, "")}, + {0xe7, 0, 0, 1, f(Yes, true, "ç")}, + {0xe8, 0, 0, 1, f(Yes, false, "è")}, + {0xe9, 0, 0, 1, f(Yes, false, "é")}, + {0xea, 0, 0, 1, f(Yes, true, "ê")}, + {0xeb, 0, 0, 1, f(Yes, false, "ë")}, + {0xec, 0, 0, 1, f(Yes, false, "ì")}, + {0xed, 0, 0, 1, f(Yes, false, "í")}, + {0xee, 0, 0, 1, f(Yes, false, "î")}, + {0xef, 0, 0, 1, f(Yes, true, "ï")}, + {0xf0, 0, 0, 0, f(Yes, false, "")}, + {0xf1, 0, 0, 1, f(Yes, false, "ñ")}, + {0xf2, 0, 0, 1, f(Yes, false, "ò")}, + {0xf3, 0, 0, 1, f(Yes, false, "ó")}, + {0xf4, 0, 0, 1, f(Yes, true, "ô")}, + {0xf5, 0, 0, 1, f(Yes, true, "õ")}, + {0xf6, 0, 0, 1, f(Yes, true, "ö")}, + {0xf7, 0, 0, 0, f(Yes, false, "")}, + {0xf8, 0, 0, 0, f(Yes, true, "")}, + {0xf9, 0, 0, 1, f(Yes, false, "ù")}, + {0xfa, 0, 0, 1, f(Yes, false, "ú")}, + {0xfb, 0, 0, 1, f(Yes, false, "û")}, + {0xfc, 0, 0, 1, f(Yes, true, "ü")}, + {0xfd, 0, 0, 1, f(Yes, false, "ý")}, + {0xfe, 0, 0, 0, f(Yes, false, "")}, + {0xff, 0, 0, 1, f(Yes, false, "ÿ")}, + {0x100, 0, 0, 1, f(Yes, false, "Ā")}, + {0x101, 0, 0, 1, f(Yes, false, "ā")}, + {0x102, 0, 0, 1, f(Yes, true, "Ă")}, + {0x103, 0, 0, 1, f(Yes, true, "ă")}, + {0x104, 0, 0, 1, f(Yes, false, "Ą")}, + {0x105, 0, 0, 1, f(Yes, false, "ą")}, + {0x106, 0, 0, 1, f(Yes, false, "Ć")}, + {0x107, 0, 0, 1, f(Yes, false, "ć")}, + {0x108, 0, 0, 1, f(Yes, false, "Ĉ")}, + {0x109, 0, 0, 1, f(Yes, false, "ĉ")}, + {0x10a, 0, 0, 1, f(Yes, false, "Ċ")}, + {0x10b, 0, 0, 1, f(Yes, false, "ċ")}, + {0x10c, 0, 0, 1, f(Yes, false, "Č")}, + {0x10d, 0, 0, 1, f(Yes, false, "č")}, + {0x10e, 0, 0, 1, f(Yes, false, "Ď")}, + {0x10f, 0, 0, 1, f(Yes, false, "ď")}, + {0x110, 0, 0, 0, f(Yes, false, "")}, + {0x112, 0, 0, 1, f(Yes, true, "Ē")}, + {0x113, 0, 0, 1, f(Yes, true, "ē")}, + {0x114, 0, 0, 1, f(Yes, false, "Ĕ")}, + {0x115, 0, 0, 1, f(Yes, false, "ĕ")}, + {0x116, 0, 0, 1, f(Yes, false, "Ė")}, + {0x117, 0, 0, 1, f(Yes, false, "ė")}, + {0x118, 0, 0, 1, f(Yes, false, "Ę")}, + {0x119, 0, 0, 1, f(Yes, false, "ę")}, + {0x11a, 0, 0, 1, f(Yes, false, "Ě")}, + {0x11b, 0, 0, 1, f(Yes, false, "ě")}, + {0x11c, 0, 0, 1, f(Yes, false, "Ĝ")}, + {0x11d, 0, 0, 1, f(Yes, false, "ĝ")}, + {0x11e, 0, 0, 1, f(Yes, false, "Ğ")}, + {0x11f, 0, 0, 1, f(Yes, false, "ğ")}, + {0x120, 0, 0, 1, f(Yes, false, "Ġ")}, + {0x121, 0, 0, 1, f(Yes, false, "ġ")}, + {0x122, 0, 0, 1, f(Yes, false, "Ģ")}, + {0x123, 0, 0, 1, f(Yes, false, "ģ")}, + {0x124, 0, 0, 1, f(Yes, false, "Ĥ")}, + {0x125, 0, 0, 1, f(Yes, false, "ĥ")}, + {0x126, 0, 0, 0, f(Yes, false, "")}, + {0x128, 0, 0, 1, f(Yes, false, "Ĩ")}, + {0x129, 0, 0, 1, f(Yes, false, "ĩ")}, + {0x12a, 0, 0, 1, f(Yes, false, "Ī")}, + {0x12b, 0, 0, 1, f(Yes, false, "ī")}, + {0x12c, 0, 0, 1, f(Yes, false, "Ĭ")}, + {0x12d, 0, 0, 1, f(Yes, false, "ĭ")}, + {0x12e, 0, 0, 1, f(Yes, false, "Į")}, + {0x12f, 0, 0, 1, f(Yes, false, "į")}, + {0x130, 0, 0, 1, f(Yes, false, "İ")}, + {0x131, 0, 0, 0, f(Yes, false, "")}, + {0x132, 0, 0, 0, g(Yes, No, false, false, "", "IJ")}, + {0x133, 0, 0, 0, g(Yes, No, false, false, "", "ij")}, + {0x134, 0, 0, 1, f(Yes, false, "Ĵ")}, + {0x135, 0, 0, 1, f(Yes, false, "ĵ")}, + {0x136, 0, 0, 1, f(Yes, false, "Ķ")}, + {0x137, 0, 0, 1, f(Yes, false, "ķ")}, + {0x138, 0, 0, 0, f(Yes, false, "")}, + {0x139, 0, 0, 1, f(Yes, false, "Ĺ")}, + {0x13a, 0, 0, 1, f(Yes, false, "ĺ")}, + {0x13b, 0, 0, 1, f(Yes, false, "Ļ")}, + {0x13c, 0, 0, 1, f(Yes, false, "ļ")}, + {0x13d, 0, 0, 1, f(Yes, false, "Ľ")}, + {0x13e, 0, 0, 1, f(Yes, false, "ľ")}, + {0x13f, 0, 0, 0, g(Yes, No, false, false, "", "L·")}, + {0x140, 0, 0, 0, g(Yes, No, false, false, "", "l·")}, + {0x141, 0, 0, 0, f(Yes, false, "")}, + {0x143, 0, 0, 1, f(Yes, false, "Ń")}, + {0x144, 0, 0, 1, f(Yes, false, "ń")}, + {0x145, 0, 0, 1, f(Yes, false, "Ņ")}, + {0x146, 0, 0, 1, f(Yes, false, "ņ")}, + {0x147, 0, 0, 1, f(Yes, false, "Ň")}, + {0x148, 0, 0, 1, f(Yes, false, "ň")}, + {0x149, 0, 0, 0, g(Yes, No, false, false, "", "ʼn")}, + {0x14a, 0, 0, 0, f(Yes, false, "")}, + {0x14c, 0, 0, 1, f(Yes, true, "Ō")}, + {0x14d, 0, 0, 1, f(Yes, true, "ō")}, + {0x14e, 0, 0, 1, f(Yes, false, "Ŏ")}, + {0x14f, 0, 0, 1, f(Yes, false, "ŏ")}, + {0x150, 0, 0, 1, f(Yes, false, "Ő")}, + {0x151, 0, 0, 1, f(Yes, false, "ő")}, + {0x152, 0, 0, 0, f(Yes, false, "")}, + {0x154, 0, 0, 1, f(Yes, false, "Ŕ")}, + {0x155, 0, 0, 1, f(Yes, false, "ŕ")}, + {0x156, 0, 0, 1, f(Yes, false, "Ŗ")}, + {0x157, 0, 0, 1, f(Yes, false, "ŗ")}, + {0x158, 0, 0, 1, f(Yes, false, "Ř")}, + {0x159, 0, 0, 1, f(Yes, false, "ř")}, + {0x15a, 0, 0, 1, f(Yes, true, "Ś")}, + {0x15b, 0, 0, 1, f(Yes, true, "ś")}, + {0x15c, 0, 0, 1, f(Yes, false, "Ŝ")}, + {0x15d, 0, 0, 1, f(Yes, false, "ŝ")}, + {0x15e, 0, 0, 1, f(Yes, false, "Ş")}, + {0x15f, 0, 0, 1, f(Yes, false, "ş")}, + {0x160, 0, 0, 1, f(Yes, true, "Š")}, + {0x161, 0, 0, 1, f(Yes, true, "š")}, + {0x162, 0, 0, 1, f(Yes, false, "Ţ")}, + {0x163, 0, 0, 1, f(Yes, false, "ţ")}, + {0x164, 0, 0, 1, f(Yes, false, "Ť")}, + {0x165, 0, 0, 1, f(Yes, false, "ť")}, + {0x166, 0, 0, 0, f(Yes, false, "")}, + {0x168, 0, 0, 1, f(Yes, true, "Ũ")}, + {0x169, 0, 0, 1, f(Yes, true, "ũ")}, + {0x16a, 0, 0, 1, f(Yes, true, "Ū")}, + {0x16b, 0, 0, 1, f(Yes, true, "ū")}, + {0x16c, 0, 0, 1, f(Yes, false, "Ŭ")}, + {0x16d, 0, 0, 1, f(Yes, false, "ŭ")}, + {0x16e, 0, 0, 1, f(Yes, false, "Ů")}, + {0x16f, 0, 0, 1, f(Yes, false, "ů")}, + {0x170, 0, 0, 1, f(Yes, false, "Ű")}, + {0x171, 0, 0, 1, f(Yes, false, "ű")}, + {0x172, 0, 0, 1, f(Yes, false, "Ų")}, + {0x173, 0, 0, 1, f(Yes, false, "ų")}, + {0x174, 0, 0, 1, f(Yes, false, "Ŵ")}, + {0x175, 0, 0, 1, f(Yes, false, "ŵ")}, + {0x176, 0, 0, 1, f(Yes, false, "Ŷ")}, + {0x177, 0, 0, 1, f(Yes, false, "ŷ")}, + {0x178, 0, 0, 1, f(Yes, false, "Ÿ")}, + {0x179, 0, 0, 1, f(Yes, false, "Ź")}, + {0x17a, 0, 0, 1, f(Yes, false, "ź")}, + {0x17b, 0, 0, 1, f(Yes, false, "Ż")}, + {0x17c, 0, 0, 1, f(Yes, false, "ż")}, + {0x17d, 0, 0, 1, f(Yes, false, "Ž")}, + {0x17e, 0, 0, 1, f(Yes, false, "ž")}, + {0x17f, 0, 0, 0, g(Yes, No, true, false, "", "s")}, + {0x180, 0, 0, 0, f(Yes, false, "")}, + {0x1a0, 0, 0, 1, f(Yes, true, "Ơ")}, + {0x1a1, 0, 0, 1, f(Yes, true, "ơ")}, + {0x1a2, 0, 0, 0, f(Yes, false, "")}, + {0x1af, 0, 0, 1, f(Yes, true, "Ư")}, + {0x1b0, 0, 0, 1, f(Yes, true, "ư")}, + {0x1b1, 0, 0, 0, f(Yes, false, "")}, + {0x1b7, 0, 0, 0, f(Yes, true, "")}, + {0x1b8, 0, 0, 0, f(Yes, false, "")}, + {0x1c4, 0, 0, 1, g(Yes, No, false, false, "", "DŽ")}, + {0x1c5, 0, 0, 1, g(Yes, No, false, false, "", "Dž")}, + {0x1c6, 0, 0, 1, g(Yes, No, false, false, "", "dž")}, + {0x1c7, 0, 0, 0, g(Yes, No, false, false, "", "LJ")}, + {0x1c8, 0, 0, 0, g(Yes, No, false, false, "", "Lj")}, + {0x1c9, 0, 0, 0, g(Yes, No, false, false, "", "lj")}, + {0x1ca, 0, 0, 0, g(Yes, No, false, false, "", "NJ")}, + {0x1cb, 0, 0, 0, g(Yes, No, false, false, "", "Nj")}, + {0x1cc, 0, 0, 0, g(Yes, No, false, false, "", "nj")}, + {0x1cd, 0, 0, 1, f(Yes, false, "Ǎ")}, + {0x1ce, 0, 0, 1, f(Yes, false, "ǎ")}, + {0x1cf, 0, 0, 1, f(Yes, false, "Ǐ")}, + {0x1d0, 0, 0, 1, f(Yes, false, "ǐ")}, + {0x1d1, 0, 0, 1, f(Yes, false, "Ǒ")}, + {0x1d2, 0, 0, 1, f(Yes, false, "ǒ")}, + {0x1d3, 0, 0, 1, f(Yes, false, "Ǔ")}, + {0x1d4, 0, 0, 1, f(Yes, false, "ǔ")}, + {0x1d5, 0, 0, 2, f(Yes, false, "Ǖ")}, + {0x1d6, 0, 0, 2, f(Yes, false, "ǖ")}, + {0x1d7, 0, 0, 2, f(Yes, false, "Ǘ")}, + {0x1d8, 0, 0, 2, f(Yes, false, "ǘ")}, + {0x1d9, 0, 0, 2, f(Yes, false, "Ǚ")}, + {0x1da, 0, 0, 2, f(Yes, false, "ǚ")}, + {0x1db, 0, 0, 2, f(Yes, false, "Ǜ")}, + {0x1dc, 0, 0, 2, f(Yes, false, "ǜ")}, + {0x1dd, 0, 0, 0, f(Yes, false, "")}, + {0x1de, 0, 0, 2, f(Yes, false, "Ǟ")}, + {0x1df, 0, 0, 2, f(Yes, false, "ǟ")}, + {0x1e0, 0, 0, 2, f(Yes, false, "Ǡ")}, + {0x1e1, 0, 0, 2, f(Yes, false, "ǡ")}, + {0x1e2, 0, 0, 1, f(Yes, false, "Ǣ")}, + {0x1e3, 0, 0, 1, f(Yes, false, "ǣ")}, + {0x1e4, 0, 0, 0, f(Yes, false, "")}, + {0x1e6, 0, 0, 1, f(Yes, false, "Ǧ")}, + {0x1e7, 0, 0, 1, f(Yes, false, "ǧ")}, + {0x1e8, 0, 0, 1, f(Yes, false, "Ǩ")}, + {0x1e9, 0, 0, 1, f(Yes, false, "ǩ")}, + {0x1ea, 0, 0, 1, f(Yes, true, "Ǫ")}, + {0x1eb, 0, 0, 1, f(Yes, true, "ǫ")}, + {0x1ec, 0, 0, 2, f(Yes, false, "Ǭ")}, + {0x1ed, 0, 0, 2, f(Yes, false, "ǭ")}, + {0x1ee, 0, 0, 1, f(Yes, false, "Ǯ")}, + {0x1ef, 0, 0, 1, f(Yes, false, "ǯ")}, + {0x1f0, 0, 0, 1, f(Yes, false, "ǰ")}, + {0x1f1, 0, 0, 0, g(Yes, No, false, false, "", "DZ")}, + {0x1f2, 0, 0, 0, g(Yes, No, false, false, "", "Dz")}, + {0x1f3, 0, 0, 0, g(Yes, No, false, false, "", "dz")}, + {0x1f4, 0, 0, 1, f(Yes, false, "Ǵ")}, + {0x1f5, 0, 0, 1, f(Yes, false, "ǵ")}, + {0x1f6, 0, 0, 0, f(Yes, false, "")}, + {0x1f8, 0, 0, 1, f(Yes, false, "Ǹ")}, + {0x1f9, 0, 0, 1, f(Yes, false, "ǹ")}, + {0x1fa, 0, 0, 2, f(Yes, false, "Ǻ")}, + {0x1fb, 0, 0, 2, f(Yes, false, "ǻ")}, + {0x1fc, 0, 0, 1, f(Yes, false, "Ǽ")}, + {0x1fd, 0, 0, 1, f(Yes, false, "ǽ")}, + {0x1fe, 0, 0, 1, f(Yes, false, "Ǿ")}, + {0x1ff, 0, 0, 1, f(Yes, false, "ǿ")}, + {0x200, 0, 0, 1, f(Yes, false, "Ȁ")}, + {0x201, 0, 0, 1, f(Yes, false, "ȁ")}, + {0x202, 0, 0, 1, f(Yes, false, "Ȃ")}, + {0x203, 0, 0, 1, f(Yes, false, "ȃ")}, + {0x204, 0, 0, 1, f(Yes, false, "Ȅ")}, + {0x205, 0, 0, 1, f(Yes, false, "ȅ")}, + {0x206, 0, 0, 1, f(Yes, false, "Ȇ")}, + {0x207, 0, 0, 1, f(Yes, false, "ȇ")}, + {0x208, 0, 0, 1, f(Yes, false, "Ȉ")}, + {0x209, 0, 0, 1, f(Yes, false, "ȉ")}, + {0x20a, 0, 0, 1, f(Yes, false, "Ȋ")}, + {0x20b, 0, 0, 1, f(Yes, false, "ȋ")}, + {0x20c, 0, 0, 1, f(Yes, false, "Ȍ")}, + {0x20d, 0, 0, 1, f(Yes, false, "ȍ")}, + {0x20e, 0, 0, 1, f(Yes, false, "Ȏ")}, + {0x20f, 0, 0, 1, f(Yes, false, "ȏ")}, + {0x210, 0, 0, 1, f(Yes, false, "Ȑ")}, + {0x211, 0, 0, 1, f(Yes, false, "ȑ")}, + {0x212, 0, 0, 1, f(Yes, false, "Ȓ")}, + {0x213, 0, 0, 1, f(Yes, false, "ȓ")}, + {0x214, 0, 0, 1, f(Yes, false, "Ȕ")}, + {0x215, 0, 0, 1, f(Yes, false, "ȕ")}, + {0x216, 0, 0, 1, f(Yes, false, "Ȗ")}, + {0x217, 0, 0, 1, f(Yes, false, "ȗ")}, + {0x218, 0, 0, 1, f(Yes, false, "Ș")}, + {0x219, 0, 0, 1, f(Yes, false, "ș")}, + {0x21a, 0, 0, 1, f(Yes, false, "Ț")}, + {0x21b, 0, 0, 1, f(Yes, false, "ț")}, + {0x21c, 0, 0, 0, f(Yes, false, "")}, + {0x21e, 0, 0, 1, f(Yes, false, "Ȟ")}, + {0x21f, 0, 0, 1, f(Yes, false, "ȟ")}, + {0x220, 0, 0, 0, f(Yes, false, "")}, + {0x226, 0, 0, 1, f(Yes, true, "Ȧ")}, + {0x227, 0, 0, 1, f(Yes, true, "ȧ")}, + {0x228, 0, 0, 1, f(Yes, true, "Ȩ")}, + {0x229, 0, 0, 1, f(Yes, true, "ȩ")}, + {0x22a, 0, 0, 2, f(Yes, false, "Ȫ")}, + {0x22b, 0, 0, 2, f(Yes, false, "ȫ")}, + {0x22c, 0, 0, 2, f(Yes, false, "Ȭ")}, + {0x22d, 0, 0, 2, f(Yes, false, "ȭ")}, + {0x22e, 0, 0, 1, f(Yes, true, "Ȯ")}, + {0x22f, 0, 0, 1, f(Yes, true, "ȯ")}, + {0x230, 0, 0, 2, f(Yes, false, "Ȱ")}, + {0x231, 0, 0, 2, f(Yes, false, "ȱ")}, + {0x232, 0, 0, 1, f(Yes, false, "Ȳ")}, + {0x233, 0, 0, 1, f(Yes, false, "ȳ")}, + {0x234, 0, 0, 0, f(Yes, false, "")}, + {0x292, 0, 0, 0, f(Yes, true, "")}, + {0x293, 0, 0, 0, f(Yes, false, "")}, + {0x2b0, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x2b1, 0, 0, 0, g(Yes, No, false, false, "", "ɦ")}, + {0x2b2, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x2b3, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x2b4, 0, 0, 0, g(Yes, No, false, false, "", "ɹ")}, + {0x2b5, 0, 0, 0, g(Yes, No, false, false, "", "ɻ")}, + {0x2b6, 0, 0, 0, g(Yes, No, false, false, "", "ʁ")}, + {0x2b7, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x2b8, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x2b9, 0, 0, 0, f(Yes, false, "")}, + {0x2d8, 0, 0, 1, g(Yes, No, false, false, "", " ̆")}, + {0x2d9, 0, 0, 1, g(Yes, No, false, false, "", " ̇")}, + {0x2da, 0, 0, 1, g(Yes, No, false, false, "", " ̊")}, + {0x2db, 0, 0, 1, g(Yes, No, false, false, "", " ̨")}, + {0x2dc, 0, 0, 1, g(Yes, No, false, false, "", " ̃")}, + {0x2dd, 0, 0, 1, g(Yes, No, false, false, "", " ̋")}, + {0x2de, 0, 0, 0, f(Yes, false, "")}, + {0x2e0, 0, 0, 0, g(Yes, No, false, false, "", "ɣ")}, + {0x2e1, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x2e2, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x2e3, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x2e4, 0, 0, 0, g(Yes, No, false, false, "", "ʕ")}, + {0x2e5, 0, 0, 0, f(Yes, false, "")}, + {0x300, 230, 1, 1, f(Maybe, false, "")}, + {0x305, 230, 1, 1, f(Yes, false, "")}, + {0x306, 230, 1, 1, f(Maybe, false, "")}, + {0x30d, 230, 1, 1, f(Yes, false, "")}, + {0x30f, 230, 1, 1, f(Maybe, false, "")}, + {0x310, 230, 1, 1, f(Yes, false, "")}, + {0x311, 230, 1, 1, f(Maybe, false, "")}, + {0x312, 230, 1, 1, f(Yes, false, "")}, + {0x313, 230, 1, 1, f(Maybe, false, "")}, + {0x315, 232, 1, 1, f(Yes, false, "")}, + {0x316, 220, 1, 1, f(Yes, false, "")}, + {0x31a, 232, 1, 1, f(Yes, false, "")}, + {0x31b, 216, 1, 1, f(Maybe, false, "")}, + {0x31c, 220, 1, 1, f(Yes, false, "")}, + {0x321, 202, 1, 1, f(Yes, false, "")}, + {0x323, 220, 1, 1, f(Maybe, false, "")}, + {0x327, 202, 1, 1, f(Maybe, false, "")}, + {0x329, 220, 1, 1, f(Yes, false, "")}, + {0x32d, 220, 1, 1, f(Maybe, false, "")}, + {0x32f, 220, 1, 1, f(Yes, false, "")}, + {0x330, 220, 1, 1, f(Maybe, false, "")}, + {0x332, 220, 1, 1, f(Yes, false, "")}, + {0x334, 1, 1, 1, f(Yes, false, "")}, + {0x338, 1, 1, 1, f(Maybe, false, "")}, + {0x339, 220, 1, 1, f(Yes, false, "")}, + {0x33d, 230, 1, 1, f(Yes, false, "")}, + {0x340, 230, 1, 1, f(No, false, "̀")}, + {0x341, 230, 1, 1, f(No, false, "́")}, + {0x342, 230, 1, 1, f(Maybe, false, "")}, + {0x343, 230, 1, 1, f(No, false, "̓")}, + {0x344, 230, 2, 2, f(No, false, "̈́")}, + {0x345, 240, 1, 1, f(Maybe, false, "")}, + {0x346, 230, 1, 1, f(Yes, false, "")}, + {0x347, 220, 1, 1, f(Yes, false, "")}, + {0x34a, 230, 1, 1, f(Yes, false, "")}, + {0x34d, 220, 1, 1, f(Yes, false, "")}, + {0x34f, 0, 0, 0, f(Yes, false, "")}, + {0x350, 230, 1, 1, f(Yes, false, "")}, + {0x353, 220, 1, 1, f(Yes, false, "")}, + {0x357, 230, 1, 1, f(Yes, false, "")}, + {0x358, 232, 1, 1, f(Yes, false, "")}, + {0x359, 220, 1, 1, f(Yes, false, "")}, + {0x35b, 230, 1, 1, f(Yes, false, "")}, + {0x35c, 233, 1, 1, f(Yes, false, "")}, + {0x35d, 234, 1, 1, f(Yes, false, "")}, + {0x35f, 233, 1, 1, f(Yes, false, "")}, + {0x360, 234, 1, 1, f(Yes, false, "")}, + {0x362, 233, 1, 1, f(Yes, false, "")}, + {0x363, 230, 1, 1, f(Yes, false, "")}, + {0x370, 0, 0, 0, f(Yes, false, "")}, + {0x374, 0, 0, 0, f(No, false, "ʹ")}, + {0x375, 0, 0, 0, f(Yes, false, "")}, + {0x37a, 0, 0, 1, g(Yes, No, false, false, "", " ͅ")}, + {0x37b, 0, 0, 0, f(Yes, false, "")}, + {0x37e, 0, 0, 0, f(No, false, ";")}, + {0x37f, 0, 0, 0, f(Yes, false, "")}, + {0x384, 0, 0, 1, g(Yes, No, false, false, "", " ́")}, + {0x385, 0, 0, 2, g(Yes, No, false, false, "΅", " ̈́")}, + {0x386, 0, 0, 1, f(Yes, false, "Ά")}, + {0x387, 0, 0, 0, f(No, false, "·")}, + {0x388, 0, 0, 1, f(Yes, false, "Έ")}, + {0x389, 0, 0, 1, f(Yes, false, "Ή")}, + {0x38a, 0, 0, 1, f(Yes, false, "Ί")}, + {0x38b, 0, 0, 0, f(Yes, false, "")}, + {0x38c, 0, 0, 1, f(Yes, false, "Ό")}, + {0x38d, 0, 0, 0, f(Yes, false, "")}, + {0x38e, 0, 0, 1, f(Yes, false, "Ύ")}, + {0x38f, 0, 0, 1, f(Yes, false, "Ώ")}, + {0x390, 0, 0, 2, f(Yes, false, "ΐ")}, + {0x391, 0, 0, 0, f(Yes, true, "")}, + {0x392, 0, 0, 0, f(Yes, false, "")}, + {0x395, 0, 0, 0, f(Yes, true, "")}, + {0x396, 0, 0, 0, f(Yes, false, "")}, + {0x397, 0, 0, 0, f(Yes, true, "")}, + {0x398, 0, 0, 0, f(Yes, false, "")}, + {0x399, 0, 0, 0, f(Yes, true, "")}, + {0x39a, 0, 0, 0, f(Yes, false, "")}, + {0x39f, 0, 0, 0, f(Yes, true, "")}, + {0x3a0, 0, 0, 0, f(Yes, false, "")}, + {0x3a1, 0, 0, 0, f(Yes, true, "")}, + {0x3a2, 0, 0, 0, f(Yes, false, "")}, + {0x3a5, 0, 0, 0, f(Yes, true, "")}, + {0x3a6, 0, 0, 0, f(Yes, false, "")}, + {0x3a9, 0, 0, 0, f(Yes, true, "")}, + {0x3aa, 0, 0, 1, f(Yes, false, "Ϊ")}, + {0x3ab, 0, 0, 1, f(Yes, false, "Ϋ")}, + {0x3ac, 0, 0, 1, f(Yes, true, "ά")}, + {0x3ad, 0, 0, 1, f(Yes, false, "έ")}, + {0x3ae, 0, 0, 1, f(Yes, true, "ή")}, + {0x3af, 0, 0, 1, f(Yes, false, "ί")}, + {0x3b0, 0, 0, 2, f(Yes, false, "ΰ")}, + {0x3b1, 0, 0, 0, f(Yes, true, "")}, + {0x3b2, 0, 0, 0, f(Yes, false, "")}, + {0x3b5, 0, 0, 0, f(Yes, true, "")}, + {0x3b6, 0, 0, 0, f(Yes, false, "")}, + {0x3b7, 0, 0, 0, f(Yes, true, "")}, + {0x3b8, 0, 0, 0, f(Yes, false, "")}, + {0x3b9, 0, 0, 0, f(Yes, true, "")}, + {0x3ba, 0, 0, 0, f(Yes, false, "")}, + {0x3bf, 0, 0, 0, f(Yes, true, "")}, + {0x3c0, 0, 0, 0, f(Yes, false, "")}, + {0x3c1, 0, 0, 0, f(Yes, true, "")}, + {0x3c2, 0, 0, 0, f(Yes, false, "")}, + {0x3c5, 0, 0, 0, f(Yes, true, "")}, + {0x3c6, 0, 0, 0, f(Yes, false, "")}, + {0x3c9, 0, 0, 0, f(Yes, true, "")}, + {0x3ca, 0, 0, 1, f(Yes, true, "ϊ")}, + {0x3cb, 0, 0, 1, f(Yes, true, "ϋ")}, + {0x3cc, 0, 0, 1, f(Yes, false, "ό")}, + {0x3cd, 0, 0, 1, f(Yes, false, "ύ")}, + {0x3ce, 0, 0, 1, f(Yes, true, "ώ")}, + {0x3cf, 0, 0, 0, f(Yes, false, "")}, + {0x3d0, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x3d1, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x3d2, 0, 0, 0, g(Yes, No, true, false, "", "Υ")}, + {0x3d3, 0, 0, 1, g(Yes, No, false, false, "ϓ", "Ύ")}, + {0x3d4, 0, 0, 1, g(Yes, No, false, false, "ϔ", "Ϋ")}, + {0x3d5, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x3d6, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x3d7, 0, 0, 0, f(Yes, false, "")}, + {0x3f0, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x3f1, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x3f2, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x3f3, 0, 0, 0, f(Yes, false, "")}, + {0x3f4, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x3f5, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x3f6, 0, 0, 0, f(Yes, false, "")}, + {0x3f9, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x3fa, 0, 0, 0, f(Yes, false, "")}, + {0x400, 0, 0, 1, f(Yes, false, "Ѐ")}, + {0x401, 0, 0, 1, f(Yes, false, "Ё")}, + {0x402, 0, 0, 0, f(Yes, false, "")}, + {0x403, 0, 0, 1, f(Yes, false, "Ѓ")}, + {0x404, 0, 0, 0, f(Yes, false, "")}, + {0x406, 0, 0, 0, f(Yes, true, "")}, + {0x407, 0, 0, 1, f(Yes, false, "Ї")}, + {0x408, 0, 0, 0, f(Yes, false, "")}, + {0x40c, 0, 0, 1, f(Yes, false, "Ќ")}, + {0x40d, 0, 0, 1, f(Yes, false, "Ѝ")}, + {0x40e, 0, 0, 1, f(Yes, false, "Ў")}, + {0x40f, 0, 0, 0, f(Yes, false, "")}, + {0x410, 0, 0, 0, f(Yes, true, "")}, + {0x411, 0, 0, 0, f(Yes, false, "")}, + {0x413, 0, 0, 0, f(Yes, true, "")}, + {0x414, 0, 0, 0, f(Yes, false, "")}, + {0x415, 0, 0, 0, f(Yes, true, "")}, + {0x419, 0, 0, 1, f(Yes, false, "Й")}, + {0x41a, 0, 0, 0, f(Yes, true, "")}, + {0x41b, 0, 0, 0, f(Yes, false, "")}, + {0x41e, 0, 0, 0, f(Yes, true, "")}, + {0x41f, 0, 0, 0, f(Yes, false, "")}, + {0x423, 0, 0, 0, f(Yes, true, "")}, + {0x424, 0, 0, 0, f(Yes, false, "")}, + {0x427, 0, 0, 0, f(Yes, true, "")}, + {0x428, 0, 0, 0, f(Yes, false, "")}, + {0x42b, 0, 0, 0, f(Yes, true, "")}, + {0x42c, 0, 0, 0, f(Yes, false, "")}, + {0x42d, 0, 0, 0, f(Yes, true, "")}, + {0x42e, 0, 0, 0, f(Yes, false, "")}, + {0x430, 0, 0, 0, f(Yes, true, "")}, + {0x431, 0, 0, 0, f(Yes, false, "")}, + {0x433, 0, 0, 0, f(Yes, true, "")}, + {0x434, 0, 0, 0, f(Yes, false, "")}, + {0x435, 0, 0, 0, f(Yes, true, "")}, + {0x439, 0, 0, 1, f(Yes, false, "й")}, + {0x43a, 0, 0, 0, f(Yes, true, "")}, + {0x43b, 0, 0, 0, f(Yes, false, "")}, + {0x43e, 0, 0, 0, f(Yes, true, "")}, + {0x43f, 0, 0, 0, f(Yes, false, "")}, + {0x443, 0, 0, 0, f(Yes, true, "")}, + {0x444, 0, 0, 0, f(Yes, false, "")}, + {0x447, 0, 0, 0, f(Yes, true, "")}, + {0x448, 0, 0, 0, f(Yes, false, "")}, + {0x44b, 0, 0, 0, f(Yes, true, "")}, + {0x44c, 0, 0, 0, f(Yes, false, "")}, + {0x44d, 0, 0, 0, f(Yes, true, "")}, + {0x44e, 0, 0, 0, f(Yes, false, "")}, + {0x450, 0, 0, 1, f(Yes, false, "ѐ")}, + {0x451, 0, 0, 1, f(Yes, false, "ё")}, + {0x452, 0, 0, 0, f(Yes, false, "")}, + {0x453, 0, 0, 1, f(Yes, false, "ѓ")}, + {0x454, 0, 0, 0, f(Yes, false, "")}, + {0x456, 0, 0, 0, f(Yes, true, "")}, + {0x457, 0, 0, 1, f(Yes, false, "ї")}, + {0x458, 0, 0, 0, f(Yes, false, "")}, + {0x45c, 0, 0, 1, f(Yes, false, "ќ")}, + {0x45d, 0, 0, 1, f(Yes, false, "ѝ")}, + {0x45e, 0, 0, 1, f(Yes, false, "ў")}, + {0x45f, 0, 0, 0, f(Yes, false, "")}, + {0x474, 0, 0, 0, f(Yes, true, "")}, + {0x476, 0, 0, 1, f(Yes, false, "Ѷ")}, + {0x477, 0, 0, 1, f(Yes, false, "ѷ")}, + {0x478, 0, 0, 0, f(Yes, false, "")}, + {0x483, 230, 1, 1, f(Yes, false, "")}, + {0x488, 0, 0, 0, f(Yes, false, "")}, + {0x4c1, 0, 0, 1, f(Yes, false, "Ӂ")}, + {0x4c2, 0, 0, 1, f(Yes, false, "ӂ")}, + {0x4c3, 0, 0, 0, f(Yes, false, "")}, + {0x4d0, 0, 0, 1, f(Yes, false, "Ӑ")}, + {0x4d1, 0, 0, 1, f(Yes, false, "ӑ")}, + {0x4d2, 0, 0, 1, f(Yes, false, "Ӓ")}, + {0x4d3, 0, 0, 1, f(Yes, false, "ӓ")}, + {0x4d4, 0, 0, 0, f(Yes, false, "")}, + {0x4d6, 0, 0, 1, f(Yes, false, "Ӗ")}, + {0x4d7, 0, 0, 1, f(Yes, false, "ӗ")}, + {0x4d8, 0, 0, 0, f(Yes, true, "")}, + {0x4da, 0, 0, 1, f(Yes, false, "Ӛ")}, + {0x4db, 0, 0, 1, f(Yes, false, "ӛ")}, + {0x4dc, 0, 0, 1, f(Yes, false, "Ӝ")}, + {0x4dd, 0, 0, 1, f(Yes, false, "ӝ")}, + {0x4de, 0, 0, 1, f(Yes, false, "Ӟ")}, + {0x4df, 0, 0, 1, f(Yes, false, "ӟ")}, + {0x4e0, 0, 0, 0, f(Yes, false, "")}, + {0x4e2, 0, 0, 1, f(Yes, false, "Ӣ")}, + {0x4e3, 0, 0, 1, f(Yes, false, "ӣ")}, + {0x4e4, 0, 0, 1, f(Yes, false, "Ӥ")}, + {0x4e5, 0, 0, 1, f(Yes, false, "ӥ")}, + {0x4e6, 0, 0, 1, f(Yes, false, "Ӧ")}, + {0x4e7, 0, 0, 1, f(Yes, false, "ӧ")}, + {0x4e8, 0, 0, 0, f(Yes, true, "")}, + {0x4ea, 0, 0, 1, f(Yes, false, "Ӫ")}, + {0x4eb, 0, 0, 1, f(Yes, false, "ӫ")}, + {0x4ec, 0, 0, 1, f(Yes, false, "Ӭ")}, + {0x4ed, 0, 0, 1, f(Yes, false, "ӭ")}, + {0x4ee, 0, 0, 1, f(Yes, false, "Ӯ")}, + {0x4ef, 0, 0, 1, f(Yes, false, "ӯ")}, + {0x4f0, 0, 0, 1, f(Yes, false, "Ӱ")}, + {0x4f1, 0, 0, 1, f(Yes, false, "ӱ")}, + {0x4f2, 0, 0, 1, f(Yes, false, "Ӳ")}, + {0x4f3, 0, 0, 1, f(Yes, false, "ӳ")}, + {0x4f4, 0, 0, 1, f(Yes, false, "Ӵ")}, + {0x4f5, 0, 0, 1, f(Yes, false, "ӵ")}, + {0x4f6, 0, 0, 0, f(Yes, false, "")}, + {0x4f8, 0, 0, 1, f(Yes, false, "Ӹ")}, + {0x4f9, 0, 0, 1, f(Yes, false, "ӹ")}, + {0x4fa, 0, 0, 0, f(Yes, false, "")}, + {0x587, 0, 0, 0, g(Yes, No, false, false, "", "եւ")}, + {0x588, 0, 0, 0, f(Yes, false, "")}, + {0x591, 220, 1, 1, f(Yes, false, "")}, + {0x592, 230, 1, 1, f(Yes, false, "")}, + {0x596, 220, 1, 1, f(Yes, false, "")}, + {0x597, 230, 1, 1, f(Yes, false, "")}, + {0x59a, 222, 1, 1, f(Yes, false, "")}, + {0x59b, 220, 1, 1, f(Yes, false, "")}, + {0x59c, 230, 1, 1, f(Yes, false, "")}, + {0x5a2, 220, 1, 1, f(Yes, false, "")}, + {0x5a8, 230, 1, 1, f(Yes, false, "")}, + {0x5aa, 220, 1, 1, f(Yes, false, "")}, + {0x5ab, 230, 1, 1, f(Yes, false, "")}, + {0x5ad, 222, 1, 1, f(Yes, false, "")}, + {0x5ae, 228, 1, 1, f(Yes, false, "")}, + {0x5af, 230, 1, 1, f(Yes, false, "")}, + {0x5b0, 10, 1, 1, f(Yes, false, "")}, + {0x5b1, 11, 1, 1, f(Yes, false, "")}, + {0x5b2, 12, 1, 1, f(Yes, false, "")}, + {0x5b3, 13, 1, 1, f(Yes, false, "")}, + {0x5b4, 14, 1, 1, f(Yes, false, "")}, + {0x5b5, 15, 1, 1, f(Yes, false, "")}, + {0x5b6, 16, 1, 1, f(Yes, false, "")}, + {0x5b7, 17, 1, 1, f(Yes, false, "")}, + {0x5b8, 18, 1, 1, f(Yes, false, "")}, + {0x5b9, 19, 1, 1, f(Yes, false, "")}, + {0x5bb, 20, 1, 1, f(Yes, false, "")}, + {0x5bc, 21, 1, 1, f(Yes, false, "")}, + {0x5bd, 22, 1, 1, f(Yes, false, "")}, + {0x5be, 0, 0, 0, f(Yes, false, "")}, + {0x5bf, 23, 1, 1, f(Yes, false, "")}, + {0x5c0, 0, 0, 0, f(Yes, false, "")}, + {0x5c1, 24, 1, 1, f(Yes, false, "")}, + {0x5c2, 25, 1, 1, f(Yes, false, "")}, + {0x5c3, 0, 0, 0, f(Yes, false, "")}, + {0x5c4, 230, 1, 1, f(Yes, false, "")}, + {0x5c5, 220, 1, 1, f(Yes, false, "")}, + {0x5c6, 0, 0, 0, f(Yes, false, "")}, + {0x5c7, 18, 1, 1, f(Yes, false, "")}, + {0x5c8, 0, 0, 0, f(Yes, false, "")}, + {0x610, 230, 1, 1, f(Yes, false, "")}, + {0x618, 30, 1, 1, f(Yes, false, "")}, + {0x619, 31, 1, 1, f(Yes, false, "")}, + {0x61a, 32, 1, 1, f(Yes, false, "")}, + {0x61b, 0, 0, 0, f(Yes, false, "")}, + {0x622, 0, 0, 1, f(Yes, false, "آ")}, + {0x623, 0, 0, 1, f(Yes, false, "أ")}, + {0x624, 0, 0, 1, f(Yes, false, "ؤ")}, + {0x625, 0, 0, 1, f(Yes, false, "إ")}, + {0x626, 0, 0, 1, f(Yes, false, "ئ")}, + {0x627, 0, 0, 0, f(Yes, true, "")}, + {0x628, 0, 0, 0, f(Yes, false, "")}, + {0x648, 0, 0, 0, f(Yes, true, "")}, + {0x649, 0, 0, 0, f(Yes, false, "")}, + {0x64a, 0, 0, 0, f(Yes, true, "")}, + {0x64b, 27, 1, 1, f(Yes, false, "")}, + {0x64c, 28, 1, 1, f(Yes, false, "")}, + {0x64d, 29, 1, 1, f(Yes, false, "")}, + {0x64e, 30, 1, 1, f(Yes, false, "")}, + {0x64f, 31, 1, 1, f(Yes, false, "")}, + {0x650, 32, 1, 1, f(Yes, false, "")}, + {0x651, 33, 1, 1, f(Yes, false, "")}, + {0x652, 34, 1, 1, f(Yes, false, "")}, + {0x653, 230, 1, 1, f(Maybe, false, "")}, + {0x655, 220, 1, 1, f(Maybe, false, "")}, + {0x656, 220, 1, 1, f(Yes, false, "")}, + {0x657, 230, 1, 1, f(Yes, false, "")}, + {0x65c, 220, 1, 1, f(Yes, false, "")}, + {0x65d, 230, 1, 1, f(Yes, false, "")}, + {0x65f, 220, 1, 1, f(Yes, false, "")}, + {0x660, 0, 0, 0, f(Yes, false, "")}, + {0x670, 35, 1, 1, f(Yes, false, "")}, + {0x671, 0, 0, 0, f(Yes, false, "")}, + {0x675, 0, 0, 0, g(Yes, No, false, false, "", "اٴ")}, + {0x676, 0, 0, 0, g(Yes, No, false, false, "", "وٴ")}, + {0x677, 0, 0, 0, g(Yes, No, false, false, "", "ۇٴ")}, + {0x678, 0, 0, 0, g(Yes, No, false, false, "", "يٴ")}, + {0x679, 0, 0, 0, f(Yes, false, "")}, + {0x6c0, 0, 0, 1, f(Yes, false, "ۀ")}, + {0x6c1, 0, 0, 0, f(Yes, true, "")}, + {0x6c2, 0, 0, 1, f(Yes, false, "ۂ")}, + {0x6c3, 0, 0, 0, f(Yes, false, "")}, + {0x6d2, 0, 0, 0, f(Yes, true, "")}, + {0x6d3, 0, 0, 1, f(Yes, false, "ۓ")}, + {0x6d4, 0, 0, 0, f(Yes, false, "")}, + {0x6d5, 0, 0, 0, f(Yes, true, "")}, + {0x6d6, 230, 1, 1, f(Yes, false, "")}, + {0x6dd, 0, 0, 0, f(Yes, false, "")}, + {0x6df, 230, 1, 1, f(Yes, false, "")}, + {0x6e3, 220, 1, 1, f(Yes, false, "")}, + {0x6e4, 230, 1, 1, f(Yes, false, "")}, + {0x6e5, 0, 0, 0, f(Yes, false, "")}, + {0x6e7, 230, 1, 1, f(Yes, false, "")}, + {0x6e9, 0, 0, 0, f(Yes, false, "")}, + {0x6ea, 220, 1, 1, f(Yes, false, "")}, + {0x6eb, 230, 1, 1, f(Yes, false, "")}, + {0x6ed, 220, 1, 1, f(Yes, false, "")}, + {0x6ee, 0, 0, 0, f(Yes, false, "")}, + {0x711, 36, 1, 1, f(Yes, false, "")}, + {0x712, 0, 0, 0, f(Yes, false, "")}, + {0x730, 230, 1, 1, f(Yes, false, "")}, + {0x731, 220, 1, 1, f(Yes, false, "")}, + {0x732, 230, 1, 1, f(Yes, false, "")}, + {0x734, 220, 1, 1, f(Yes, false, "")}, + {0x735, 230, 1, 1, f(Yes, false, "")}, + {0x737, 220, 1, 1, f(Yes, false, "")}, + {0x73a, 230, 1, 1, f(Yes, false, "")}, + {0x73b, 220, 1, 1, f(Yes, false, "")}, + {0x73d, 230, 1, 1, f(Yes, false, "")}, + {0x73e, 220, 1, 1, f(Yes, false, "")}, + {0x73f, 230, 1, 1, f(Yes, false, "")}, + {0x742, 220, 1, 1, f(Yes, false, "")}, + {0x743, 230, 1, 1, f(Yes, false, "")}, + {0x744, 220, 1, 1, f(Yes, false, "")}, + {0x745, 230, 1, 1, f(Yes, false, "")}, + {0x746, 220, 1, 1, f(Yes, false, "")}, + {0x747, 230, 1, 1, f(Yes, false, "")}, + {0x748, 220, 1, 1, f(Yes, false, "")}, + {0x749, 230, 1, 1, f(Yes, false, "")}, + {0x74b, 0, 0, 0, f(Yes, false, "")}, + {0x7eb, 230, 1, 1, f(Yes, false, "")}, + {0x7f2, 220, 1, 1, f(Yes, false, "")}, + {0x7f3, 230, 1, 1, f(Yes, false, "")}, + {0x7f4, 0, 0, 0, f(Yes, false, "")}, + {0x816, 230, 1, 1, f(Yes, false, "")}, + {0x81a, 0, 0, 0, f(Yes, false, "")}, + {0x81b, 230, 1, 1, f(Yes, false, "")}, + {0x824, 0, 0, 0, f(Yes, false, "")}, + {0x825, 230, 1, 1, f(Yes, false, "")}, + {0x828, 0, 0, 0, f(Yes, false, "")}, + {0x829, 230, 1, 1, f(Yes, false, "")}, + {0x82e, 0, 0, 0, f(Yes, false, "")}, + {0x859, 220, 1, 1, f(Yes, false, "")}, + {0x85c, 0, 0, 0, f(Yes, false, "")}, + {0x8d4, 230, 1, 1, f(Yes, false, "")}, + {0x8e2, 0, 0, 0, f(Yes, false, "")}, + {0x8e3, 220, 1, 1, f(Yes, false, "")}, + {0x8e4, 230, 1, 1, f(Yes, false, "")}, + {0x8e6, 220, 1, 1, f(Yes, false, "")}, + {0x8e7, 230, 1, 1, f(Yes, false, "")}, + {0x8e9, 220, 1, 1, f(Yes, false, "")}, + {0x8ea, 230, 1, 1, f(Yes, false, "")}, + {0x8ed, 220, 1, 1, f(Yes, false, "")}, + {0x8f0, 27, 1, 1, f(Yes, false, "")}, + {0x8f1, 28, 1, 1, f(Yes, false, "")}, + {0x8f2, 29, 1, 1, f(Yes, false, "")}, + {0x8f3, 230, 1, 1, f(Yes, false, "")}, + {0x8f6, 220, 1, 1, f(Yes, false, "")}, + {0x8f7, 230, 1, 1, f(Yes, false, "")}, + {0x8f9, 220, 1, 1, f(Yes, false, "")}, + {0x8fb, 230, 1, 1, f(Yes, false, "")}, + {0x900, 0, 0, 0, f(Yes, false, "")}, + {0x928, 0, 0, 0, f(Yes, true, "")}, + {0x929, 0, 0, 1, f(Yes, false, "ऩ")}, + {0x92a, 0, 0, 0, f(Yes, false, "")}, + {0x930, 0, 0, 0, f(Yes, true, "")}, + {0x931, 0, 0, 1, f(Yes, false, "ऱ")}, + {0x932, 0, 0, 0, f(Yes, false, "")}, + {0x933, 0, 0, 0, f(Yes, true, "")}, + {0x934, 0, 0, 1, f(Yes, false, "ऴ")}, + {0x935, 0, 0, 0, f(Yes, false, "")}, + {0x93c, 7, 1, 1, f(Maybe, false, "")}, + {0x93d, 0, 0, 0, f(Yes, false, "")}, + {0x94d, 9, 1, 1, f(Yes, false, "")}, + {0x94e, 0, 0, 0, f(Yes, false, "")}, + {0x951, 230, 1, 1, f(Yes, false, "")}, + {0x952, 220, 1, 1, f(Yes, false, "")}, + {0x953, 230, 1, 1, f(Yes, false, "")}, + {0x955, 0, 0, 0, f(Yes, false, "")}, + {0x958, 0, 0, 1, f(No, false, "क़")}, + {0x959, 0, 0, 1, f(No, false, "ख़")}, + {0x95a, 0, 0, 1, f(No, false, "ग़")}, + {0x95b, 0, 0, 1, f(No, false, "ज़")}, + {0x95c, 0, 0, 1, f(No, false, "ड़")}, + {0x95d, 0, 0, 1, f(No, false, "ढ़")}, + {0x95e, 0, 0, 1, f(No, false, "फ़")}, + {0x95f, 0, 0, 1, f(No, false, "य़")}, + {0x960, 0, 0, 0, f(Yes, false, "")}, + {0x9bc, 7, 1, 1, f(Yes, false, "")}, + {0x9bd, 0, 0, 0, f(Yes, false, "")}, + {0x9be, 0, 1, 1, f(Maybe, false, "")}, + {0x9bf, 0, 0, 0, f(Yes, false, "")}, + {0x9c7, 0, 0, 0, f(Yes, true, "")}, + {0x9c8, 0, 0, 0, f(Yes, false, "")}, + {0x9cb, 0, 0, 1, f(Yes, false, "ো")}, + {0x9cc, 0, 0, 1, f(Yes, false, "ৌ")}, + {0x9cd, 9, 1, 1, f(Yes, false, "")}, + {0x9ce, 0, 0, 0, f(Yes, false, "")}, + {0x9d7, 0, 1, 1, f(Maybe, false, "")}, + {0x9d8, 0, 0, 0, f(Yes, false, "")}, + {0x9dc, 0, 0, 1, f(No, false, "ড়")}, + {0x9dd, 0, 0, 1, f(No, false, "ঢ়")}, + {0x9de, 0, 0, 0, f(Yes, false, "")}, + {0x9df, 0, 0, 1, f(No, false, "য়")}, + {0x9e0, 0, 0, 0, f(Yes, false, "")}, + {0xa33, 0, 0, 1, f(No, false, "ਲ਼")}, + {0xa34, 0, 0, 0, f(Yes, false, "")}, + {0xa36, 0, 0, 1, f(No, false, "ਸ਼")}, + {0xa37, 0, 0, 0, f(Yes, false, "")}, + {0xa3c, 7, 1, 1, f(Yes, false, "")}, + {0xa3d, 0, 0, 0, f(Yes, false, "")}, + {0xa4d, 9, 1, 1, f(Yes, false, "")}, + {0xa4e, 0, 0, 0, f(Yes, false, "")}, + {0xa59, 0, 0, 1, f(No, false, "ਖ਼")}, + {0xa5a, 0, 0, 1, f(No, false, "ਗ਼")}, + {0xa5b, 0, 0, 1, f(No, false, "ਜ਼")}, + {0xa5c, 0, 0, 0, f(Yes, false, "")}, + {0xa5e, 0, 0, 1, f(No, false, "ਫ਼")}, + {0xa5f, 0, 0, 0, f(Yes, false, "")}, + {0xabc, 7, 1, 1, f(Yes, false, "")}, + {0xabd, 0, 0, 0, f(Yes, false, "")}, + {0xacd, 9, 1, 1, f(Yes, false, "")}, + {0xace, 0, 0, 0, f(Yes, false, "")}, + {0xb3c, 7, 1, 1, f(Yes, false, "")}, + {0xb3d, 0, 0, 0, f(Yes, false, "")}, + {0xb3e, 0, 1, 1, f(Maybe, false, "")}, + {0xb3f, 0, 0, 0, f(Yes, false, "")}, + {0xb47, 0, 0, 0, f(Yes, true, "")}, + {0xb48, 0, 0, 1, f(Yes, false, "ୈ")}, + {0xb49, 0, 0, 0, f(Yes, false, "")}, + {0xb4b, 0, 0, 1, f(Yes, false, "ୋ")}, + {0xb4c, 0, 0, 1, f(Yes, false, "ୌ")}, + {0xb4d, 9, 1, 1, f(Yes, false, "")}, + {0xb4e, 0, 0, 0, f(Yes, false, "")}, + {0xb56, 0, 1, 1, f(Maybe, false, "")}, + {0xb58, 0, 0, 0, f(Yes, false, "")}, + {0xb5c, 0, 0, 1, f(No, false, "ଡ଼")}, + {0xb5d, 0, 0, 1, f(No, false, "ଢ଼")}, + {0xb5e, 0, 0, 0, f(Yes, false, "")}, + {0xb92, 0, 0, 0, f(Yes, true, "")}, + {0xb93, 0, 0, 0, f(Yes, false, "")}, + {0xb94, 0, 0, 1, f(Yes, false, "ஔ")}, + {0xb95, 0, 0, 0, f(Yes, false, "")}, + {0xbbe, 0, 1, 1, f(Maybe, false, "")}, + {0xbbf, 0, 0, 0, f(Yes, false, "")}, + {0xbc6, 0, 0, 0, f(Yes, true, "")}, + {0xbc8, 0, 0, 0, f(Yes, false, "")}, + {0xbca, 0, 0, 1, f(Yes, false, "ொ")}, + {0xbcb, 0, 0, 1, f(Yes, false, "ோ")}, + {0xbcc, 0, 0, 1, f(Yes, false, "ௌ")}, + {0xbcd, 9, 1, 1, f(Yes, false, "")}, + {0xbce, 0, 0, 0, f(Yes, false, "")}, + {0xbd7, 0, 1, 1, f(Maybe, false, "")}, + {0xbd8, 0, 0, 0, f(Yes, false, "")}, + {0xc46, 0, 0, 0, f(Yes, true, "")}, + {0xc47, 0, 0, 0, f(Yes, false, "")}, + {0xc48, 0, 0, 1, f(Yes, false, "ై")}, + {0xc49, 0, 0, 0, f(Yes, false, "")}, + {0xc4d, 9, 1, 1, f(Yes, false, "")}, + {0xc4e, 0, 0, 0, f(Yes, false, "")}, + {0xc55, 84, 1, 1, f(Yes, false, "")}, + {0xc56, 91, 1, 1, f(Maybe, false, "")}, + {0xc57, 0, 0, 0, f(Yes, false, "")}, + {0xcbc, 7, 1, 1, f(Yes, false, "")}, + {0xcbd, 0, 0, 0, f(Yes, false, "")}, + {0xcbf, 0, 0, 0, f(Yes, true, "")}, + {0xcc0, 0, 0, 1, f(Yes, false, "ೀ")}, + {0xcc1, 0, 0, 0, f(Yes, false, "")}, + {0xcc2, 0, 1, 1, f(Maybe, false, "")}, + {0xcc3, 0, 0, 0, f(Yes, false, "")}, + {0xcc6, 0, 0, 0, f(Yes, true, "")}, + {0xcc7, 0, 0, 1, f(Yes, false, "ೇ")}, + {0xcc8, 0, 0, 1, f(Yes, false, "ೈ")}, + {0xcc9, 0, 0, 0, f(Yes, false, "")}, + {0xcca, 0, 0, 1, f(Yes, true, "ೊ")}, + {0xccb, 0, 0, 2, f(Yes, false, "ೋ")}, + {0xccc, 0, 0, 0, f(Yes, false, "")}, + {0xccd, 9, 1, 1, f(Yes, false, "")}, + {0xcce, 0, 0, 0, f(Yes, false, "")}, + {0xcd5, 0, 1, 1, f(Maybe, false, "")}, + {0xcd7, 0, 0, 0, f(Yes, false, "")}, + {0xd3e, 0, 1, 1, f(Maybe, false, "")}, + {0xd3f, 0, 0, 0, f(Yes, false, "")}, + {0xd46, 0, 0, 0, f(Yes, true, "")}, + {0xd48, 0, 0, 0, f(Yes, false, "")}, + {0xd4a, 0, 0, 1, f(Yes, false, "ൊ")}, + {0xd4b, 0, 0, 1, f(Yes, false, "ോ")}, + {0xd4c, 0, 0, 1, f(Yes, false, "ൌ")}, + {0xd4d, 9, 1, 1, f(Yes, false, "")}, + {0xd4e, 0, 0, 0, f(Yes, false, "")}, + {0xd57, 0, 1, 1, f(Maybe, false, "")}, + {0xd58, 0, 0, 0, f(Yes, false, "")}, + {0xdca, 9, 1, 1, f(Maybe, false, "")}, + {0xdcb, 0, 0, 0, f(Yes, false, "")}, + {0xdcf, 0, 1, 1, f(Maybe, false, "")}, + {0xdd0, 0, 0, 0, f(Yes, false, "")}, + {0xdd9, 0, 0, 0, f(Yes, true, "")}, + {0xdda, 0, 0, 1, f(Yes, false, "ේ")}, + {0xddb, 0, 0, 0, f(Yes, false, "")}, + {0xddc, 0, 0, 1, f(Yes, true, "ො")}, + {0xddd, 0, 0, 2, f(Yes, false, "ෝ")}, + {0xdde, 0, 0, 1, f(Yes, false, "ෞ")}, + {0xddf, 0, 1, 1, f(Maybe, false, "")}, + {0xde0, 0, 0, 0, f(Yes, false, "")}, + {0xe33, 0, 0, 0, g(Yes, No, false, false, "", "ํา")}, + {0xe34, 0, 0, 0, f(Yes, false, "")}, + {0xe38, 103, 1, 1, f(Yes, false, "")}, + {0xe3a, 9, 1, 1, f(Yes, false, "")}, + {0xe3b, 0, 0, 0, f(Yes, false, "")}, + {0xe48, 107, 1, 1, f(Yes, false, "")}, + {0xe4c, 0, 0, 0, f(Yes, false, "")}, + {0xeb3, 0, 0, 0, g(Yes, No, false, false, "", "ໍາ")}, + {0xeb4, 0, 0, 0, f(Yes, false, "")}, + {0xeb8, 118, 1, 1, f(Yes, false, "")}, + {0xeba, 0, 0, 0, f(Yes, false, "")}, + {0xec8, 122, 1, 1, f(Yes, false, "")}, + {0xecc, 0, 0, 0, f(Yes, false, "")}, + {0xedc, 0, 0, 0, g(Yes, No, false, false, "", "ຫນ")}, + {0xedd, 0, 0, 0, g(Yes, No, false, false, "", "ຫມ")}, + {0xede, 0, 0, 0, f(Yes, false, "")}, + {0xf0c, 0, 0, 0, g(Yes, No, false, false, "", "་")}, + {0xf0d, 0, 0, 0, f(Yes, false, "")}, + {0xf18, 220, 1, 1, f(Yes, false, "")}, + {0xf1a, 0, 0, 0, f(Yes, false, "")}, + {0xf35, 220, 1, 1, f(Yes, false, "")}, + {0xf36, 0, 0, 0, f(Yes, false, "")}, + {0xf37, 220, 1, 1, f(Yes, false, "")}, + {0xf38, 0, 0, 0, f(Yes, false, "")}, + {0xf39, 216, 1, 1, f(Yes, false, "")}, + {0xf3a, 0, 0, 0, f(Yes, false, "")}, + {0xf43, 0, 0, 0, f(No, false, "གྷ")}, + {0xf44, 0, 0, 0, f(Yes, false, "")}, + {0xf4d, 0, 0, 0, f(No, false, "ཌྷ")}, + {0xf4e, 0, 0, 0, f(Yes, false, "")}, + {0xf52, 0, 0, 0, f(No, false, "དྷ")}, + {0xf53, 0, 0, 0, f(Yes, false, "")}, + {0xf57, 0, 0, 0, f(No, false, "བྷ")}, + {0xf58, 0, 0, 0, f(Yes, false, "")}, + {0xf5c, 0, 0, 0, f(No, false, "ཛྷ")}, + {0xf5d, 0, 0, 0, f(Yes, false, "")}, + {0xf69, 0, 0, 0, f(No, false, "ཀྵ")}, + {0xf6a, 0, 0, 0, f(Yes, false, "")}, + {0xf71, 129, 1, 1, f(Yes, false, "")}, + {0xf72, 130, 1, 1, f(Yes, false, "")}, + {0xf73, 0, 2, 2, f(No, false, "ཱི")}, + {0xf74, 132, 1, 1, f(Yes, false, "")}, + {0xf75, 0, 2, 2, f(No, false, "ཱུ")}, + {0xf76, 0, 0, 1, f(No, false, "ྲྀ")}, + {0xf77, 0, 0, 2, g(Yes, No, false, false, "", "ྲཱྀ")}, + {0xf78, 0, 0, 1, f(No, false, "ླྀ")}, + {0xf79, 0, 0, 2, g(Yes, No, false, false, "", "ླཱྀ")}, + {0xf7a, 130, 1, 1, f(Yes, false, "")}, + {0xf7e, 0, 0, 0, f(Yes, false, "")}, + {0xf80, 130, 1, 1, f(Yes, false, "")}, + {0xf81, 0, 2, 2, f(No, false, "ཱྀ")}, + {0xf82, 230, 1, 1, f(Yes, false, "")}, + {0xf84, 9, 1, 1, f(Yes, false, "")}, + {0xf85, 0, 0, 0, f(Yes, false, "")}, + {0xf86, 230, 1, 1, f(Yes, false, "")}, + {0xf88, 0, 0, 0, f(Yes, false, "")}, + {0xf93, 0, 0, 0, f(No, false, "ྒྷ")}, + {0xf94, 0, 0, 0, f(Yes, false, "")}, + {0xf9d, 0, 0, 0, f(No, false, "ྜྷ")}, + {0xf9e, 0, 0, 0, f(Yes, false, "")}, + {0xfa2, 0, 0, 0, f(No, false, "ྡྷ")}, + {0xfa3, 0, 0, 0, f(Yes, false, "")}, + {0xfa7, 0, 0, 0, f(No, false, "ྦྷ")}, + {0xfa8, 0, 0, 0, f(Yes, false, "")}, + {0xfac, 0, 0, 0, f(No, false, "ྫྷ")}, + {0xfad, 0, 0, 0, f(Yes, false, "")}, + {0xfb9, 0, 0, 0, f(No, false, "ྐྵ")}, + {0xfba, 0, 0, 0, f(Yes, false, "")}, + {0xfc6, 220, 1, 1, f(Yes, false, "")}, + {0xfc7, 0, 0, 0, f(Yes, false, "")}, + {0x1025, 0, 0, 0, f(Yes, true, "")}, + {0x1026, 0, 0, 1, f(Yes, false, "ဦ")}, + {0x1027, 0, 0, 0, f(Yes, false, "")}, + {0x102e, 0, 1, 1, f(Maybe, false, "")}, + {0x102f, 0, 0, 0, f(Yes, false, "")}, + {0x1037, 7, 1, 1, f(Yes, false, "")}, + {0x1038, 0, 0, 0, f(Yes, false, "")}, + {0x1039, 9, 1, 1, f(Yes, false, "")}, + {0x103b, 0, 0, 0, f(Yes, false, "")}, + {0x108d, 220, 1, 1, f(Yes, false, "")}, + {0x108e, 0, 0, 0, f(Yes, false, "")}, + {0x10fc, 0, 0, 0, g(Yes, No, false, false, "", "ნ")}, + {0x10fd, 0, 0, 0, f(Yes, false, "")}, + {0x1100, 0, 0, 0, f(Yes, true, "")}, + {0x1113, 0, 0, 0, f(Yes, false, "")}, + {0x1161, 0, 1, 1, f(Maybe, true, "")}, + {0x1176, 0, 0, 0, f(Yes, false, "")}, + {0x11a8, 0, 1, 1, f(Maybe, false, "")}, + {0x11c3, 0, 0, 0, f(Yes, false, "")}, + {0x135d, 230, 1, 1, f(Yes, false, "")}, + {0x1360, 0, 0, 0, f(Yes, false, "")}, + {0x1714, 9, 1, 1, f(Yes, false, "")}, + {0x1715, 0, 0, 0, f(Yes, false, "")}, + {0x1734, 9, 1, 1, f(Yes, false, "")}, + {0x1735, 0, 0, 0, f(Yes, false, "")}, + {0x17d2, 9, 1, 1, f(Yes, false, "")}, + {0x17d3, 0, 0, 0, f(Yes, false, "")}, + {0x17dd, 230, 1, 1, f(Yes, false, "")}, + {0x17de, 0, 0, 0, f(Yes, false, "")}, + {0x18a9, 228, 1, 1, f(Yes, false, "")}, + {0x18aa, 0, 0, 0, f(Yes, false, "")}, + {0x1939, 222, 1, 1, f(Yes, false, "")}, + {0x193a, 230, 1, 1, f(Yes, false, "")}, + {0x193b, 220, 1, 1, f(Yes, false, "")}, + {0x193c, 0, 0, 0, f(Yes, false, "")}, + {0x1a17, 230, 1, 1, f(Yes, false, "")}, + {0x1a18, 220, 1, 1, f(Yes, false, "")}, + {0x1a19, 0, 0, 0, f(Yes, false, "")}, + {0x1a60, 9, 1, 1, f(Yes, false, "")}, + {0x1a61, 0, 0, 0, f(Yes, false, "")}, + {0x1a75, 230, 1, 1, f(Yes, false, "")}, + {0x1a7d, 0, 0, 0, f(Yes, false, "")}, + {0x1a7f, 220, 1, 1, f(Yes, false, "")}, + {0x1a80, 0, 0, 0, f(Yes, false, "")}, + {0x1ab0, 230, 1, 1, f(Yes, false, "")}, + {0x1ab5, 220, 1, 1, f(Yes, false, "")}, + {0x1abb, 230, 1, 1, f(Yes, false, "")}, + {0x1abd, 220, 1, 1, f(Yes, false, "")}, + {0x1abe, 0, 0, 0, f(Yes, false, "")}, + {0x1b05, 0, 0, 0, f(Yes, true, "")}, + {0x1b06, 0, 0, 1, f(Yes, false, "ᬆ")}, + {0x1b07, 0, 0, 0, f(Yes, true, "")}, + {0x1b08, 0, 0, 1, f(Yes, false, "ᬈ")}, + {0x1b09, 0, 0, 0, f(Yes, true, "")}, + {0x1b0a, 0, 0, 1, f(Yes, false, "ᬊ")}, + {0x1b0b, 0, 0, 0, f(Yes, true, "")}, + {0x1b0c, 0, 0, 1, f(Yes, false, "ᬌ")}, + {0x1b0d, 0, 0, 0, f(Yes, true, "")}, + {0x1b0e, 0, 0, 1, f(Yes, false, "ᬎ")}, + {0x1b0f, 0, 0, 0, f(Yes, false, "")}, + {0x1b11, 0, 0, 0, f(Yes, true, "")}, + {0x1b12, 0, 0, 1, f(Yes, false, "ᬒ")}, + {0x1b13, 0, 0, 0, f(Yes, false, "")}, + {0x1b34, 7, 1, 1, f(Yes, false, "")}, + {0x1b35, 0, 1, 1, f(Maybe, false, "")}, + {0x1b36, 0, 0, 0, f(Yes, false, "")}, + {0x1b3a, 0, 0, 0, f(Yes, true, "")}, + {0x1b3b, 0, 0, 1, f(Yes, false, "ᬻ")}, + {0x1b3c, 0, 0, 0, f(Yes, true, "")}, + {0x1b3d, 0, 0, 1, f(Yes, false, "ᬽ")}, + {0x1b3e, 0, 0, 0, f(Yes, true, "")}, + {0x1b40, 0, 0, 1, f(Yes, false, "ᭀ")}, + {0x1b41, 0, 0, 1, f(Yes, false, "ᭁ")}, + {0x1b42, 0, 0, 0, f(Yes, true, "")}, + {0x1b43, 0, 0, 1, f(Yes, false, "ᭃ")}, + {0x1b44, 9, 1, 1, f(Yes, false, "")}, + {0x1b45, 0, 0, 0, f(Yes, false, "")}, + {0x1b6b, 230, 1, 1, f(Yes, false, "")}, + {0x1b6c, 220, 1, 1, f(Yes, false, "")}, + {0x1b6d, 230, 1, 1, f(Yes, false, "")}, + {0x1b74, 0, 0, 0, f(Yes, false, "")}, + {0x1baa, 9, 1, 1, f(Yes, false, "")}, + {0x1bac, 0, 0, 0, f(Yes, false, "")}, + {0x1be6, 7, 1, 1, f(Yes, false, "")}, + {0x1be7, 0, 0, 0, f(Yes, false, "")}, + {0x1bf2, 9, 1, 1, f(Yes, false, "")}, + {0x1bf4, 0, 0, 0, f(Yes, false, "")}, + {0x1c37, 7, 1, 1, f(Yes, false, "")}, + {0x1c38, 0, 0, 0, f(Yes, false, "")}, + {0x1cd0, 230, 1, 1, f(Yes, false, "")}, + {0x1cd3, 0, 0, 0, f(Yes, false, "")}, + {0x1cd4, 1, 1, 1, f(Yes, false, "")}, + {0x1cd5, 220, 1, 1, f(Yes, false, "")}, + {0x1cda, 230, 1, 1, f(Yes, false, "")}, + {0x1cdc, 220, 1, 1, f(Yes, false, "")}, + {0x1ce0, 230, 1, 1, f(Yes, false, "")}, + {0x1ce1, 0, 0, 0, f(Yes, false, "")}, + {0x1ce2, 1, 1, 1, f(Yes, false, "")}, + {0x1ce9, 0, 0, 0, f(Yes, false, "")}, + {0x1ced, 220, 1, 1, f(Yes, false, "")}, + {0x1cee, 0, 0, 0, f(Yes, false, "")}, + {0x1cf4, 230, 1, 1, f(Yes, false, "")}, + {0x1cf5, 0, 0, 0, f(Yes, false, "")}, + {0x1cf8, 230, 1, 1, f(Yes, false, "")}, + {0x1cfa, 0, 0, 0, f(Yes, false, "")}, + {0x1d2c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d2d, 0, 0, 0, g(Yes, No, false, false, "", "Æ")}, + {0x1d2e, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d2f, 0, 0, 0, f(Yes, false, "")}, + {0x1d30, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d31, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d32, 0, 0, 0, g(Yes, No, false, false, "", "Ǝ")}, + {0x1d33, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d34, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d35, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d36, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d37, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d38, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d39, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d3a, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d3b, 0, 0, 0, f(Yes, false, "")}, + {0x1d3c, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d3d, 0, 0, 0, g(Yes, No, false, false, "", "Ȣ")}, + {0x1d3e, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d3f, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d40, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d41, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d42, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d43, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d44, 0, 0, 0, g(Yes, No, false, false, "", "ɐ")}, + {0x1d45, 0, 0, 0, g(Yes, No, false, false, "", "ɑ")}, + {0x1d46, 0, 0, 0, g(Yes, No, false, false, "", "ᴂ")}, + {0x1d47, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d48, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d49, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d4a, 0, 0, 0, g(Yes, No, false, false, "", "ə")}, + {0x1d4b, 0, 0, 0, g(Yes, No, false, false, "", "ɛ")}, + {0x1d4c, 0, 0, 0, g(Yes, No, false, false, "", "ɜ")}, + {0x1d4d, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d4e, 0, 0, 0, f(Yes, false, "")}, + {0x1d4f, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d50, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d51, 0, 0, 0, g(Yes, No, false, false, "", "ŋ")}, + {0x1d52, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d53, 0, 0, 0, g(Yes, No, false, false, "", "ɔ")}, + {0x1d54, 0, 0, 0, g(Yes, No, false, false, "", "ᴖ")}, + {0x1d55, 0, 0, 0, g(Yes, No, false, false, "", "ᴗ")}, + {0x1d56, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d57, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d58, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d59, 0, 0, 0, g(Yes, No, false, false, "", "ᴝ")}, + {0x1d5a, 0, 0, 0, g(Yes, No, false, false, "", "ɯ")}, + {0x1d5b, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d5c, 0, 0, 0, g(Yes, No, false, false, "", "ᴥ")}, + {0x1d5d, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d5e, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d5f, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d60, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d61, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d62, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d63, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d64, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d65, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d66, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d67, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d68, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d69, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d6a, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d6b, 0, 0, 0, f(Yes, false, "")}, + {0x1d78, 0, 0, 0, g(Yes, No, false, false, "", "н")}, + {0x1d79, 0, 0, 0, f(Yes, false, "")}, + {0x1d9b, 0, 0, 0, g(Yes, No, false, false, "", "ɒ")}, + {0x1d9c, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d9d, 0, 0, 0, g(Yes, No, false, false, "", "ɕ")}, + {0x1d9e, 0, 0, 0, g(Yes, No, false, false, "", "ð")}, + {0x1d9f, 0, 0, 0, g(Yes, No, false, false, "", "ɜ")}, + {0x1da0, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1da1, 0, 0, 0, g(Yes, No, false, false, "", "ɟ")}, + {0x1da2, 0, 0, 0, g(Yes, No, false, false, "", "ɡ")}, + {0x1da3, 0, 0, 0, g(Yes, No, false, false, "", "ɥ")}, + {0x1da4, 0, 0, 0, g(Yes, No, false, false, "", "ɨ")}, + {0x1da5, 0, 0, 0, g(Yes, No, false, false, "", "ɩ")}, + {0x1da6, 0, 0, 0, g(Yes, No, false, false, "", "ɪ")}, + {0x1da7, 0, 0, 0, g(Yes, No, false, false, "", "ᵻ")}, + {0x1da8, 0, 0, 0, g(Yes, No, false, false, "", "ʝ")}, + {0x1da9, 0, 0, 0, g(Yes, No, false, false, "", "ɭ")}, + {0x1daa, 0, 0, 0, g(Yes, No, false, false, "", "ᶅ")}, + {0x1dab, 0, 0, 0, g(Yes, No, false, false, "", "ʟ")}, + {0x1dac, 0, 0, 0, g(Yes, No, false, false, "", "ɱ")}, + {0x1dad, 0, 0, 0, g(Yes, No, false, false, "", "ɰ")}, + {0x1dae, 0, 0, 0, g(Yes, No, false, false, "", "ɲ")}, + {0x1daf, 0, 0, 0, g(Yes, No, false, false, "", "ɳ")}, + {0x1db0, 0, 0, 0, g(Yes, No, false, false, "", "ɴ")}, + {0x1db1, 0, 0, 0, g(Yes, No, false, false, "", "ɵ")}, + {0x1db2, 0, 0, 0, g(Yes, No, false, false, "", "ɸ")}, + {0x1db3, 0, 0, 0, g(Yes, No, false, false, "", "ʂ")}, + {0x1db4, 0, 0, 0, g(Yes, No, false, false, "", "ʃ")}, + {0x1db5, 0, 0, 0, g(Yes, No, false, false, "", "ƫ")}, + {0x1db6, 0, 0, 0, g(Yes, No, false, false, "", "ʉ")}, + {0x1db7, 0, 0, 0, g(Yes, No, false, false, "", "ʊ")}, + {0x1db8, 0, 0, 0, g(Yes, No, false, false, "", "ᴜ")}, + {0x1db9, 0, 0, 0, g(Yes, No, false, false, "", "ʋ")}, + {0x1dba, 0, 0, 0, g(Yes, No, false, false, "", "ʌ")}, + {0x1dbb, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1dbc, 0, 0, 0, g(Yes, No, false, false, "", "ʐ")}, + {0x1dbd, 0, 0, 0, g(Yes, No, false, false, "", "ʑ")}, + {0x1dbe, 0, 0, 0, g(Yes, No, false, false, "", "ʒ")}, + {0x1dbf, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1dc0, 230, 1, 1, f(Yes, false, "")}, + {0x1dc2, 220, 1, 1, f(Yes, false, "")}, + {0x1dc3, 230, 1, 1, f(Yes, false, "")}, + {0x1dca, 220, 1, 1, f(Yes, false, "")}, + {0x1dcb, 230, 1, 1, f(Yes, false, "")}, + {0x1dcd, 234, 1, 1, f(Yes, false, "")}, + {0x1dce, 214, 1, 1, f(Yes, false, "")}, + {0x1dcf, 220, 1, 1, f(Yes, false, "")}, + {0x1dd0, 202, 1, 1, f(Yes, false, "")}, + {0x1dd1, 230, 1, 1, f(Yes, false, "")}, + {0x1df6, 0, 0, 0, f(Yes, false, "")}, + {0x1dfb, 230, 1, 1, f(Yes, false, "")}, + {0x1dfc, 233, 1, 1, f(Yes, false, "")}, + {0x1dfd, 220, 1, 1, f(Yes, false, "")}, + {0x1dfe, 230, 1, 1, f(Yes, false, "")}, + {0x1dff, 220, 1, 1, f(Yes, false, "")}, + {0x1e00, 0, 0, 1, f(Yes, false, "Ḁ")}, + {0x1e01, 0, 0, 1, f(Yes, false, "ḁ")}, + {0x1e02, 0, 0, 1, f(Yes, false, "Ḃ")}, + {0x1e03, 0, 0, 1, f(Yes, false, "ḃ")}, + {0x1e04, 0, 0, 1, f(Yes, false, "Ḅ")}, + {0x1e05, 0, 0, 1, f(Yes, false, "ḅ")}, + {0x1e06, 0, 0, 1, f(Yes, false, "Ḇ")}, + {0x1e07, 0, 0, 1, f(Yes, false, "ḇ")}, + {0x1e08, 0, 0, 2, f(Yes, false, "Ḉ")}, + {0x1e09, 0, 0, 2, f(Yes, false, "ḉ")}, + {0x1e0a, 0, 0, 1, f(Yes, false, "Ḋ")}, + {0x1e0b, 0, 0, 1, f(Yes, false, "ḋ")}, + {0x1e0c, 0, 0, 1, f(Yes, false, "Ḍ")}, + {0x1e0d, 0, 0, 1, f(Yes, false, "ḍ")}, + {0x1e0e, 0, 0, 1, f(Yes, false, "Ḏ")}, + {0x1e0f, 0, 0, 1, f(Yes, false, "ḏ")}, + {0x1e10, 0, 0, 1, f(Yes, false, "Ḑ")}, + {0x1e11, 0, 0, 1, f(Yes, false, "ḑ")}, + {0x1e12, 0, 0, 1, f(Yes, false, "Ḓ")}, + {0x1e13, 0, 0, 1, f(Yes, false, "ḓ")}, + {0x1e14, 0, 0, 2, f(Yes, false, "Ḕ")}, + {0x1e15, 0, 0, 2, f(Yes, false, "ḕ")}, + {0x1e16, 0, 0, 2, f(Yes, false, "Ḗ")}, + {0x1e17, 0, 0, 2, f(Yes, false, "ḗ")}, + {0x1e18, 0, 0, 1, f(Yes, false, "Ḙ")}, + {0x1e19, 0, 0, 1, f(Yes, false, "ḙ")}, + {0x1e1a, 0, 0, 1, f(Yes, false, "Ḛ")}, + {0x1e1b, 0, 0, 1, f(Yes, false, "ḛ")}, + {0x1e1c, 0, 0, 2, f(Yes, false, "Ḝ")}, + {0x1e1d, 0, 0, 2, f(Yes, false, "ḝ")}, + {0x1e1e, 0, 0, 1, f(Yes, false, "Ḟ")}, + {0x1e1f, 0, 0, 1, f(Yes, false, "ḟ")}, + {0x1e20, 0, 0, 1, f(Yes, false, "Ḡ")}, + {0x1e21, 0, 0, 1, f(Yes, false, "ḡ")}, + {0x1e22, 0, 0, 1, f(Yes, false, "Ḣ")}, + {0x1e23, 0, 0, 1, f(Yes, false, "ḣ")}, + {0x1e24, 0, 0, 1, f(Yes, false, "Ḥ")}, + {0x1e25, 0, 0, 1, f(Yes, false, "ḥ")}, + {0x1e26, 0, 0, 1, f(Yes, false, "Ḧ")}, + {0x1e27, 0, 0, 1, f(Yes, false, "ḧ")}, + {0x1e28, 0, 0, 1, f(Yes, false, "Ḩ")}, + {0x1e29, 0, 0, 1, f(Yes, false, "ḩ")}, + {0x1e2a, 0, 0, 1, f(Yes, false, "Ḫ")}, + {0x1e2b, 0, 0, 1, f(Yes, false, "ḫ")}, + {0x1e2c, 0, 0, 1, f(Yes, false, "Ḭ")}, + {0x1e2d, 0, 0, 1, f(Yes, false, "ḭ")}, + {0x1e2e, 0, 0, 2, f(Yes, false, "Ḯ")}, + {0x1e2f, 0, 0, 2, f(Yes, false, "ḯ")}, + {0x1e30, 0, 0, 1, f(Yes, false, "Ḱ")}, + {0x1e31, 0, 0, 1, f(Yes, false, "ḱ")}, + {0x1e32, 0, 0, 1, f(Yes, false, "Ḳ")}, + {0x1e33, 0, 0, 1, f(Yes, false, "ḳ")}, + {0x1e34, 0, 0, 1, f(Yes, false, "Ḵ")}, + {0x1e35, 0, 0, 1, f(Yes, false, "ḵ")}, + {0x1e36, 0, 0, 1, f(Yes, true, "Ḷ")}, + {0x1e37, 0, 0, 1, f(Yes, true, "ḷ")}, + {0x1e38, 0, 0, 2, f(Yes, false, "Ḹ")}, + {0x1e39, 0, 0, 2, f(Yes, false, "ḹ")}, + {0x1e3a, 0, 0, 1, f(Yes, false, "Ḻ")}, + {0x1e3b, 0, 0, 1, f(Yes, false, "ḻ")}, + {0x1e3c, 0, 0, 1, f(Yes, false, "Ḽ")}, + {0x1e3d, 0, 0, 1, f(Yes, false, "ḽ")}, + {0x1e3e, 0, 0, 1, f(Yes, false, "Ḿ")}, + {0x1e3f, 0, 0, 1, f(Yes, false, "ḿ")}, + {0x1e40, 0, 0, 1, f(Yes, false, "Ṁ")}, + {0x1e41, 0, 0, 1, f(Yes, false, "ṁ")}, + {0x1e42, 0, 0, 1, f(Yes, false, "Ṃ")}, + {0x1e43, 0, 0, 1, f(Yes, false, "ṃ")}, + {0x1e44, 0, 0, 1, f(Yes, false, "Ṅ")}, + {0x1e45, 0, 0, 1, f(Yes, false, "ṅ")}, + {0x1e46, 0, 0, 1, f(Yes, false, "Ṇ")}, + {0x1e47, 0, 0, 1, f(Yes, false, "ṇ")}, + {0x1e48, 0, 0, 1, f(Yes, false, "Ṉ")}, + {0x1e49, 0, 0, 1, f(Yes, false, "ṉ")}, + {0x1e4a, 0, 0, 1, f(Yes, false, "Ṋ")}, + {0x1e4b, 0, 0, 1, f(Yes, false, "ṋ")}, + {0x1e4c, 0, 0, 2, f(Yes, false, "Ṍ")}, + {0x1e4d, 0, 0, 2, f(Yes, false, "ṍ")}, + {0x1e4e, 0, 0, 2, f(Yes, false, "Ṏ")}, + {0x1e4f, 0, 0, 2, f(Yes, false, "ṏ")}, + {0x1e50, 0, 0, 2, f(Yes, false, "Ṑ")}, + {0x1e51, 0, 0, 2, f(Yes, false, "ṑ")}, + {0x1e52, 0, 0, 2, f(Yes, false, "Ṓ")}, + {0x1e53, 0, 0, 2, f(Yes, false, "ṓ")}, + {0x1e54, 0, 0, 1, f(Yes, false, "Ṕ")}, + {0x1e55, 0, 0, 1, f(Yes, false, "ṕ")}, + {0x1e56, 0, 0, 1, f(Yes, false, "Ṗ")}, + {0x1e57, 0, 0, 1, f(Yes, false, "ṗ")}, + {0x1e58, 0, 0, 1, f(Yes, false, "Ṙ")}, + {0x1e59, 0, 0, 1, f(Yes, false, "ṙ")}, + {0x1e5a, 0, 0, 1, f(Yes, true, "Ṛ")}, + {0x1e5b, 0, 0, 1, f(Yes, true, "ṛ")}, + {0x1e5c, 0, 0, 2, f(Yes, false, "Ṝ")}, + {0x1e5d, 0, 0, 2, f(Yes, false, "ṝ")}, + {0x1e5e, 0, 0, 1, f(Yes, false, "Ṟ")}, + {0x1e5f, 0, 0, 1, f(Yes, false, "ṟ")}, + {0x1e60, 0, 0, 1, f(Yes, false, "Ṡ")}, + {0x1e61, 0, 0, 1, f(Yes, false, "ṡ")}, + {0x1e62, 0, 0, 1, f(Yes, true, "Ṣ")}, + {0x1e63, 0, 0, 1, f(Yes, true, "ṣ")}, + {0x1e64, 0, 0, 2, f(Yes, false, "Ṥ")}, + {0x1e65, 0, 0, 2, f(Yes, false, "ṥ")}, + {0x1e66, 0, 0, 2, f(Yes, false, "Ṧ")}, + {0x1e67, 0, 0, 2, f(Yes, false, "ṧ")}, + {0x1e68, 0, 0, 2, f(Yes, false, "Ṩ")}, + {0x1e69, 0, 0, 2, f(Yes, false, "ṩ")}, + {0x1e6a, 0, 0, 1, f(Yes, false, "Ṫ")}, + {0x1e6b, 0, 0, 1, f(Yes, false, "ṫ")}, + {0x1e6c, 0, 0, 1, f(Yes, false, "Ṭ")}, + {0x1e6d, 0, 0, 1, f(Yes, false, "ṭ")}, + {0x1e6e, 0, 0, 1, f(Yes, false, "Ṯ")}, + {0x1e6f, 0, 0, 1, f(Yes, false, "ṯ")}, + {0x1e70, 0, 0, 1, f(Yes, false, "Ṱ")}, + {0x1e71, 0, 0, 1, f(Yes, false, "ṱ")}, + {0x1e72, 0, 0, 1, f(Yes, false, "Ṳ")}, + {0x1e73, 0, 0, 1, f(Yes, false, "ṳ")}, + {0x1e74, 0, 0, 1, f(Yes, false, "Ṵ")}, + {0x1e75, 0, 0, 1, f(Yes, false, "ṵ")}, + {0x1e76, 0, 0, 1, f(Yes, false, "Ṷ")}, + {0x1e77, 0, 0, 1, f(Yes, false, "ṷ")}, + {0x1e78, 0, 0, 2, f(Yes, false, "Ṹ")}, + {0x1e79, 0, 0, 2, f(Yes, false, "ṹ")}, + {0x1e7a, 0, 0, 2, f(Yes, false, "Ṻ")}, + {0x1e7b, 0, 0, 2, f(Yes, false, "ṻ")}, + {0x1e7c, 0, 0, 1, f(Yes, false, "Ṽ")}, + {0x1e7d, 0, 0, 1, f(Yes, false, "ṽ")}, + {0x1e7e, 0, 0, 1, f(Yes, false, "Ṿ")}, + {0x1e7f, 0, 0, 1, f(Yes, false, "ṿ")}, + {0x1e80, 0, 0, 1, f(Yes, false, "Ẁ")}, + {0x1e81, 0, 0, 1, f(Yes, false, "ẁ")}, + {0x1e82, 0, 0, 1, f(Yes, false, "Ẃ")}, + {0x1e83, 0, 0, 1, f(Yes, false, "ẃ")}, + {0x1e84, 0, 0, 1, f(Yes, false, "Ẅ")}, + {0x1e85, 0, 0, 1, f(Yes, false, "ẅ")}, + {0x1e86, 0, 0, 1, f(Yes, false, "Ẇ")}, + {0x1e87, 0, 0, 1, f(Yes, false, "ẇ")}, + {0x1e88, 0, 0, 1, f(Yes, false, "Ẉ")}, + {0x1e89, 0, 0, 1, f(Yes, false, "ẉ")}, + {0x1e8a, 0, 0, 1, f(Yes, false, "Ẋ")}, + {0x1e8b, 0, 0, 1, f(Yes, false, "ẋ")}, + {0x1e8c, 0, 0, 1, f(Yes, false, "Ẍ")}, + {0x1e8d, 0, 0, 1, f(Yes, false, "ẍ")}, + {0x1e8e, 0, 0, 1, f(Yes, false, "Ẏ")}, + {0x1e8f, 0, 0, 1, f(Yes, false, "ẏ")}, + {0x1e90, 0, 0, 1, f(Yes, false, "Ẑ")}, + {0x1e91, 0, 0, 1, f(Yes, false, "ẑ")}, + {0x1e92, 0, 0, 1, f(Yes, false, "Ẓ")}, + {0x1e93, 0, 0, 1, f(Yes, false, "ẓ")}, + {0x1e94, 0, 0, 1, f(Yes, false, "Ẕ")}, + {0x1e95, 0, 0, 1, f(Yes, false, "ẕ")}, + {0x1e96, 0, 0, 1, f(Yes, false, "ẖ")}, + {0x1e97, 0, 0, 1, f(Yes, false, "ẗ")}, + {0x1e98, 0, 0, 1, f(Yes, false, "ẘ")}, + {0x1e99, 0, 0, 1, f(Yes, false, "ẙ")}, + {0x1e9a, 0, 0, 0, g(Yes, No, false, false, "", "aʾ")}, + {0x1e9b, 0, 0, 1, g(Yes, No, false, false, "ẛ", "ṡ")}, + {0x1e9c, 0, 0, 0, f(Yes, false, "")}, + {0x1ea0, 0, 0, 1, f(Yes, true, "Ạ")}, + {0x1ea1, 0, 0, 1, f(Yes, true, "ạ")}, + {0x1ea2, 0, 0, 1, f(Yes, false, "Ả")}, + {0x1ea3, 0, 0, 1, f(Yes, false, "ả")}, + {0x1ea4, 0, 0, 2, f(Yes, false, "Ấ")}, + {0x1ea5, 0, 0, 2, f(Yes, false, "ấ")}, + {0x1ea6, 0, 0, 2, f(Yes, false, "Ầ")}, + {0x1ea7, 0, 0, 2, f(Yes, false, "ầ")}, + {0x1ea8, 0, 0, 2, f(Yes, false, "Ẩ")}, + {0x1ea9, 0, 0, 2, f(Yes, false, "ẩ")}, + {0x1eaa, 0, 0, 2, f(Yes, false, "Ẫ")}, + {0x1eab, 0, 0, 2, f(Yes, false, "ẫ")}, + {0x1eac, 0, 0, 2, f(Yes, false, "Ậ")}, + {0x1ead, 0, 0, 2, f(Yes, false, "ậ")}, + {0x1eae, 0, 0, 2, f(Yes, false, "Ắ")}, + {0x1eaf, 0, 0, 2, f(Yes, false, "ắ")}, + {0x1eb0, 0, 0, 2, f(Yes, false, "Ằ")}, + {0x1eb1, 0, 0, 2, f(Yes, false, "ằ")}, + {0x1eb2, 0, 0, 2, f(Yes, false, "Ẳ")}, + {0x1eb3, 0, 0, 2, f(Yes, false, "ẳ")}, + {0x1eb4, 0, 0, 2, f(Yes, false, "Ẵ")}, + {0x1eb5, 0, 0, 2, f(Yes, false, "ẵ")}, + {0x1eb6, 0, 0, 2, f(Yes, false, "Ặ")}, + {0x1eb7, 0, 0, 2, f(Yes, false, "ặ")}, + {0x1eb8, 0, 0, 1, f(Yes, true, "Ẹ")}, + {0x1eb9, 0, 0, 1, f(Yes, true, "ẹ")}, + {0x1eba, 0, 0, 1, f(Yes, false, "Ẻ")}, + {0x1ebb, 0, 0, 1, f(Yes, false, "ẻ")}, + {0x1ebc, 0, 0, 1, f(Yes, false, "Ẽ")}, + {0x1ebd, 0, 0, 1, f(Yes, false, "ẽ")}, + {0x1ebe, 0, 0, 2, f(Yes, false, "Ế")}, + {0x1ebf, 0, 0, 2, f(Yes, false, "ế")}, + {0x1ec0, 0, 0, 2, f(Yes, false, "Ề")}, + {0x1ec1, 0, 0, 2, f(Yes, false, "ề")}, + {0x1ec2, 0, 0, 2, f(Yes, false, "Ể")}, + {0x1ec3, 0, 0, 2, f(Yes, false, "ể")}, + {0x1ec4, 0, 0, 2, f(Yes, false, "Ễ")}, + {0x1ec5, 0, 0, 2, f(Yes, false, "ễ")}, + {0x1ec6, 0, 0, 2, f(Yes, false, "Ệ")}, + {0x1ec7, 0, 0, 2, f(Yes, false, "ệ")}, + {0x1ec8, 0, 0, 1, f(Yes, false, "Ỉ")}, + {0x1ec9, 0, 0, 1, f(Yes, false, "ỉ")}, + {0x1eca, 0, 0, 1, f(Yes, false, "Ị")}, + {0x1ecb, 0, 0, 1, f(Yes, false, "ị")}, + {0x1ecc, 0, 0, 1, f(Yes, true, "Ọ")}, + {0x1ecd, 0, 0, 1, f(Yes, true, "ọ")}, + {0x1ece, 0, 0, 1, f(Yes, false, "Ỏ")}, + {0x1ecf, 0, 0, 1, f(Yes, false, "ỏ")}, + {0x1ed0, 0, 0, 2, f(Yes, false, "Ố")}, + {0x1ed1, 0, 0, 2, f(Yes, false, "ố")}, + {0x1ed2, 0, 0, 2, f(Yes, false, "Ồ")}, + {0x1ed3, 0, 0, 2, f(Yes, false, "ồ")}, + {0x1ed4, 0, 0, 2, f(Yes, false, "Ổ")}, + {0x1ed5, 0, 0, 2, f(Yes, false, "ổ")}, + {0x1ed6, 0, 0, 2, f(Yes, false, "Ỗ")}, + {0x1ed7, 0, 0, 2, f(Yes, false, "ỗ")}, + {0x1ed8, 0, 0, 2, f(Yes, false, "Ộ")}, + {0x1ed9, 0, 0, 2, f(Yes, false, "ộ")}, + {0x1eda, 0, 0, 2, f(Yes, false, "Ớ")}, + {0x1edb, 0, 0, 2, f(Yes, false, "ớ")}, + {0x1edc, 0, 0, 2, f(Yes, false, "Ờ")}, + {0x1edd, 0, 0, 2, f(Yes, false, "ờ")}, + {0x1ede, 0, 0, 2, f(Yes, false, "Ở")}, + {0x1edf, 0, 0, 2, f(Yes, false, "ở")}, + {0x1ee0, 0, 0, 2, f(Yes, false, "Ỡ")}, + {0x1ee1, 0, 0, 2, f(Yes, false, "ỡ")}, + {0x1ee2, 0, 0, 2, f(Yes, false, "Ợ")}, + {0x1ee3, 0, 0, 2, f(Yes, false, "ợ")}, + {0x1ee4, 0, 0, 1, f(Yes, false, "Ụ")}, + {0x1ee5, 0, 0, 1, f(Yes, false, "ụ")}, + {0x1ee6, 0, 0, 1, f(Yes, false, "Ủ")}, + {0x1ee7, 0, 0, 1, f(Yes, false, "ủ")}, + {0x1ee8, 0, 0, 2, f(Yes, false, "Ứ")}, + {0x1ee9, 0, 0, 2, f(Yes, false, "ứ")}, + {0x1eea, 0, 0, 2, f(Yes, false, "Ừ")}, + {0x1eeb, 0, 0, 2, f(Yes, false, "ừ")}, + {0x1eec, 0, 0, 2, f(Yes, false, "Ử")}, + {0x1eed, 0, 0, 2, f(Yes, false, "ử")}, + {0x1eee, 0, 0, 2, f(Yes, false, "Ữ")}, + {0x1eef, 0, 0, 2, f(Yes, false, "ữ")}, + {0x1ef0, 0, 0, 2, f(Yes, false, "Ự")}, + {0x1ef1, 0, 0, 2, f(Yes, false, "ự")}, + {0x1ef2, 0, 0, 1, f(Yes, false, "Ỳ")}, + {0x1ef3, 0, 0, 1, f(Yes, false, "ỳ")}, + {0x1ef4, 0, 0, 1, f(Yes, false, "Ỵ")}, + {0x1ef5, 0, 0, 1, f(Yes, false, "ỵ")}, + {0x1ef6, 0, 0, 1, f(Yes, false, "Ỷ")}, + {0x1ef7, 0, 0, 1, f(Yes, false, "ỷ")}, + {0x1ef8, 0, 0, 1, f(Yes, false, "Ỹ")}, + {0x1ef9, 0, 0, 1, f(Yes, false, "ỹ")}, + {0x1efa, 0, 0, 0, f(Yes, false, "")}, + {0x1f00, 0, 0, 1, f(Yes, true, "ἀ")}, + {0x1f01, 0, 0, 1, f(Yes, true, "ἁ")}, + {0x1f02, 0, 0, 2, f(Yes, true, "ἂ")}, + {0x1f03, 0, 0, 2, f(Yes, true, "ἃ")}, + {0x1f04, 0, 0, 2, f(Yes, true, "ἄ")}, + {0x1f05, 0, 0, 2, f(Yes, true, "ἅ")}, + {0x1f06, 0, 0, 2, f(Yes, true, "ἆ")}, + {0x1f07, 0, 0, 2, f(Yes, true, "ἇ")}, + {0x1f08, 0, 0, 1, f(Yes, true, "Ἀ")}, + {0x1f09, 0, 0, 1, f(Yes, true, "Ἁ")}, + {0x1f0a, 0, 0, 2, f(Yes, true, "Ἂ")}, + {0x1f0b, 0, 0, 2, f(Yes, true, "Ἃ")}, + {0x1f0c, 0, 0, 2, f(Yes, true, "Ἄ")}, + {0x1f0d, 0, 0, 2, f(Yes, true, "Ἅ")}, + {0x1f0e, 0, 0, 2, f(Yes, true, "Ἆ")}, + {0x1f0f, 0, 0, 2, f(Yes, true, "Ἇ")}, + {0x1f10, 0, 0, 1, f(Yes, true, "ἐ")}, + {0x1f11, 0, 0, 1, f(Yes, true, "ἑ")}, + {0x1f12, 0, 0, 2, f(Yes, false, "ἒ")}, + {0x1f13, 0, 0, 2, f(Yes, false, "ἓ")}, + {0x1f14, 0, 0, 2, f(Yes, false, "ἔ")}, + {0x1f15, 0, 0, 2, f(Yes, false, "ἕ")}, + {0x1f16, 0, 0, 0, f(Yes, false, "")}, + {0x1f18, 0, 0, 1, f(Yes, true, "Ἐ")}, + {0x1f19, 0, 0, 1, f(Yes, true, "Ἑ")}, + {0x1f1a, 0, 0, 2, f(Yes, false, "Ἒ")}, + {0x1f1b, 0, 0, 2, f(Yes, false, "Ἓ")}, + {0x1f1c, 0, 0, 2, f(Yes, false, "Ἔ")}, + {0x1f1d, 0, 0, 2, f(Yes, false, "Ἕ")}, + {0x1f1e, 0, 0, 0, f(Yes, false, "")}, + {0x1f20, 0, 0, 1, f(Yes, true, "ἠ")}, + {0x1f21, 0, 0, 1, f(Yes, true, "ἡ")}, + {0x1f22, 0, 0, 2, f(Yes, true, "ἢ")}, + {0x1f23, 0, 0, 2, f(Yes, true, "ἣ")}, + {0x1f24, 0, 0, 2, f(Yes, true, "ἤ")}, + {0x1f25, 0, 0, 2, f(Yes, true, "ἥ")}, + {0x1f26, 0, 0, 2, f(Yes, true, "ἦ")}, + {0x1f27, 0, 0, 2, f(Yes, true, "ἧ")}, + {0x1f28, 0, 0, 1, f(Yes, true, "Ἠ")}, + {0x1f29, 0, 0, 1, f(Yes, true, "Ἡ")}, + {0x1f2a, 0, 0, 2, f(Yes, true, "Ἢ")}, + {0x1f2b, 0, 0, 2, f(Yes, true, "Ἣ")}, + {0x1f2c, 0, 0, 2, f(Yes, true, "Ἤ")}, + {0x1f2d, 0, 0, 2, f(Yes, true, "Ἥ")}, + {0x1f2e, 0, 0, 2, f(Yes, true, "Ἦ")}, + {0x1f2f, 0, 0, 2, f(Yes, true, "Ἧ")}, + {0x1f30, 0, 0, 1, f(Yes, true, "ἰ")}, + {0x1f31, 0, 0, 1, f(Yes, true, "ἱ")}, + {0x1f32, 0, 0, 2, f(Yes, false, "ἲ")}, + {0x1f33, 0, 0, 2, f(Yes, false, "ἳ")}, + {0x1f34, 0, 0, 2, f(Yes, false, "ἴ")}, + {0x1f35, 0, 0, 2, f(Yes, false, "ἵ")}, + {0x1f36, 0, 0, 2, f(Yes, false, "ἶ")}, + {0x1f37, 0, 0, 2, f(Yes, false, "ἷ")}, + {0x1f38, 0, 0, 1, f(Yes, true, "Ἰ")}, + {0x1f39, 0, 0, 1, f(Yes, true, "Ἱ")}, + {0x1f3a, 0, 0, 2, f(Yes, false, "Ἲ")}, + {0x1f3b, 0, 0, 2, f(Yes, false, "Ἳ")}, + {0x1f3c, 0, 0, 2, f(Yes, false, "Ἴ")}, + {0x1f3d, 0, 0, 2, f(Yes, false, "Ἵ")}, + {0x1f3e, 0, 0, 2, f(Yes, false, "Ἶ")}, + {0x1f3f, 0, 0, 2, f(Yes, false, "Ἷ")}, + {0x1f40, 0, 0, 1, f(Yes, true, "ὀ")}, + {0x1f41, 0, 0, 1, f(Yes, true, "ὁ")}, + {0x1f42, 0, 0, 2, f(Yes, false, "ὂ")}, + {0x1f43, 0, 0, 2, f(Yes, false, "ὃ")}, + {0x1f44, 0, 0, 2, f(Yes, false, "ὄ")}, + {0x1f45, 0, 0, 2, f(Yes, false, "ὅ")}, + {0x1f46, 0, 0, 0, f(Yes, false, "")}, + {0x1f48, 0, 0, 1, f(Yes, true, "Ὀ")}, + {0x1f49, 0, 0, 1, f(Yes, true, "Ὁ")}, + {0x1f4a, 0, 0, 2, f(Yes, false, "Ὂ")}, + {0x1f4b, 0, 0, 2, f(Yes, false, "Ὃ")}, + {0x1f4c, 0, 0, 2, f(Yes, false, "Ὄ")}, + {0x1f4d, 0, 0, 2, f(Yes, false, "Ὅ")}, + {0x1f4e, 0, 0, 0, f(Yes, false, "")}, + {0x1f50, 0, 0, 1, f(Yes, true, "ὐ")}, + {0x1f51, 0, 0, 1, f(Yes, true, "ὑ")}, + {0x1f52, 0, 0, 2, f(Yes, false, "ὒ")}, + {0x1f53, 0, 0, 2, f(Yes, false, "ὓ")}, + {0x1f54, 0, 0, 2, f(Yes, false, "ὔ")}, + {0x1f55, 0, 0, 2, f(Yes, false, "ὕ")}, + {0x1f56, 0, 0, 2, f(Yes, false, "ὖ")}, + {0x1f57, 0, 0, 2, f(Yes, false, "ὗ")}, + {0x1f58, 0, 0, 0, f(Yes, false, "")}, + {0x1f59, 0, 0, 1, f(Yes, true, "Ὑ")}, + {0x1f5a, 0, 0, 0, f(Yes, false, "")}, + {0x1f5b, 0, 0, 2, f(Yes, false, "Ὓ")}, + {0x1f5c, 0, 0, 0, f(Yes, false, "")}, + {0x1f5d, 0, 0, 2, f(Yes, false, "Ὕ")}, + {0x1f5e, 0, 0, 0, f(Yes, false, "")}, + {0x1f5f, 0, 0, 2, f(Yes, false, "Ὗ")}, + {0x1f60, 0, 0, 1, f(Yes, true, "ὠ")}, + {0x1f61, 0, 0, 1, f(Yes, true, "ὡ")}, + {0x1f62, 0, 0, 2, f(Yes, true, "ὢ")}, + {0x1f63, 0, 0, 2, f(Yes, true, "ὣ")}, + {0x1f64, 0, 0, 2, f(Yes, true, "ὤ")}, + {0x1f65, 0, 0, 2, f(Yes, true, "ὥ")}, + {0x1f66, 0, 0, 2, f(Yes, true, "ὦ")}, + {0x1f67, 0, 0, 2, f(Yes, true, "ὧ")}, + {0x1f68, 0, 0, 1, f(Yes, true, "Ὠ")}, + {0x1f69, 0, 0, 1, f(Yes, true, "Ὡ")}, + {0x1f6a, 0, 0, 2, f(Yes, true, "Ὢ")}, + {0x1f6b, 0, 0, 2, f(Yes, true, "Ὣ")}, + {0x1f6c, 0, 0, 2, f(Yes, true, "Ὤ")}, + {0x1f6d, 0, 0, 2, f(Yes, true, "Ὥ")}, + {0x1f6e, 0, 0, 2, f(Yes, true, "Ὦ")}, + {0x1f6f, 0, 0, 2, f(Yes, true, "Ὧ")}, + {0x1f70, 0, 0, 1, f(Yes, true, "ὰ")}, + {0x1f71, 0, 0, 1, f(No, false, "ά")}, + {0x1f72, 0, 0, 1, f(Yes, false, "ὲ")}, + {0x1f73, 0, 0, 1, f(No, false, "έ")}, + {0x1f74, 0, 0, 1, f(Yes, true, "ὴ")}, + {0x1f75, 0, 0, 1, f(No, false, "ή")}, + {0x1f76, 0, 0, 1, f(Yes, false, "ὶ")}, + {0x1f77, 0, 0, 1, f(No, false, "ί")}, + {0x1f78, 0, 0, 1, f(Yes, false, "ὸ")}, + {0x1f79, 0, 0, 1, f(No, false, "ό")}, + {0x1f7a, 0, 0, 1, f(Yes, false, "ὺ")}, + {0x1f7b, 0, 0, 1, f(No, false, "ύ")}, + {0x1f7c, 0, 0, 1, f(Yes, true, "ὼ")}, + {0x1f7d, 0, 0, 1, f(No, false, "ώ")}, + {0x1f7e, 0, 0, 0, f(Yes, false, "")}, + {0x1f80, 0, 0, 2, f(Yes, false, "ᾀ")}, + {0x1f81, 0, 0, 2, f(Yes, false, "ᾁ")}, + {0x1f82, 0, 0, 3, f(Yes, false, "ᾂ")}, + {0x1f83, 0, 0, 3, f(Yes, false, "ᾃ")}, + {0x1f84, 0, 0, 3, f(Yes, false, "ᾄ")}, + {0x1f85, 0, 0, 3, f(Yes, false, "ᾅ")}, + {0x1f86, 0, 0, 3, f(Yes, false, "ᾆ")}, + {0x1f87, 0, 0, 3, f(Yes, false, "ᾇ")}, + {0x1f88, 0, 0, 2, f(Yes, false, "ᾈ")}, + {0x1f89, 0, 0, 2, f(Yes, false, "ᾉ")}, + {0x1f8a, 0, 0, 3, f(Yes, false, "ᾊ")}, + {0x1f8b, 0, 0, 3, f(Yes, false, "ᾋ")}, + {0x1f8c, 0, 0, 3, f(Yes, false, "ᾌ")}, + {0x1f8d, 0, 0, 3, f(Yes, false, "ᾍ")}, + {0x1f8e, 0, 0, 3, f(Yes, false, "ᾎ")}, + {0x1f8f, 0, 0, 3, f(Yes, false, "ᾏ")}, + {0x1f90, 0, 0, 2, f(Yes, false, "ᾐ")}, + {0x1f91, 0, 0, 2, f(Yes, false, "ᾑ")}, + {0x1f92, 0, 0, 3, f(Yes, false, "ᾒ")}, + {0x1f93, 0, 0, 3, f(Yes, false, "ᾓ")}, + {0x1f94, 0, 0, 3, f(Yes, false, "ᾔ")}, + {0x1f95, 0, 0, 3, f(Yes, false, "ᾕ")}, + {0x1f96, 0, 0, 3, f(Yes, false, "ᾖ")}, + {0x1f97, 0, 0, 3, f(Yes, false, "ᾗ")}, + {0x1f98, 0, 0, 2, f(Yes, false, "ᾘ")}, + {0x1f99, 0, 0, 2, f(Yes, false, "ᾙ")}, + {0x1f9a, 0, 0, 3, f(Yes, false, "ᾚ")}, + {0x1f9b, 0, 0, 3, f(Yes, false, "ᾛ")}, + {0x1f9c, 0, 0, 3, f(Yes, false, "ᾜ")}, + {0x1f9d, 0, 0, 3, f(Yes, false, "ᾝ")}, + {0x1f9e, 0, 0, 3, f(Yes, false, "ᾞ")}, + {0x1f9f, 0, 0, 3, f(Yes, false, "ᾟ")}, + {0x1fa0, 0, 0, 2, f(Yes, false, "ᾠ")}, + {0x1fa1, 0, 0, 2, f(Yes, false, "ᾡ")}, + {0x1fa2, 0, 0, 3, f(Yes, false, "ᾢ")}, + {0x1fa3, 0, 0, 3, f(Yes, false, "ᾣ")}, + {0x1fa4, 0, 0, 3, f(Yes, false, "ᾤ")}, + {0x1fa5, 0, 0, 3, f(Yes, false, "ᾥ")}, + {0x1fa6, 0, 0, 3, f(Yes, false, "ᾦ")}, + {0x1fa7, 0, 0, 3, f(Yes, false, "ᾧ")}, + {0x1fa8, 0, 0, 2, f(Yes, false, "ᾨ")}, + {0x1fa9, 0, 0, 2, f(Yes, false, "ᾩ")}, + {0x1faa, 0, 0, 3, f(Yes, false, "ᾪ")}, + {0x1fab, 0, 0, 3, f(Yes, false, "ᾫ")}, + {0x1fac, 0, 0, 3, f(Yes, false, "ᾬ")}, + {0x1fad, 0, 0, 3, f(Yes, false, "ᾭ")}, + {0x1fae, 0, 0, 3, f(Yes, false, "ᾮ")}, + {0x1faf, 0, 0, 3, f(Yes, false, "ᾯ")}, + {0x1fb0, 0, 0, 1, f(Yes, false, "ᾰ")}, + {0x1fb1, 0, 0, 1, f(Yes, false, "ᾱ")}, + {0x1fb2, 0, 0, 2, f(Yes, false, "ᾲ")}, + {0x1fb3, 0, 0, 1, f(Yes, false, "ᾳ")}, + {0x1fb4, 0, 0, 2, f(Yes, false, "ᾴ")}, + {0x1fb5, 0, 0, 0, f(Yes, false, "")}, + {0x1fb6, 0, 0, 1, f(Yes, true, "ᾶ")}, + {0x1fb7, 0, 0, 2, f(Yes, false, "ᾷ")}, + {0x1fb8, 0, 0, 1, f(Yes, false, "Ᾰ")}, + {0x1fb9, 0, 0, 1, f(Yes, false, "Ᾱ")}, + {0x1fba, 0, 0, 1, f(Yes, false, "Ὰ")}, + {0x1fbb, 0, 0, 1, f(No, false, "Ά")}, + {0x1fbc, 0, 0, 1, f(Yes, false, "ᾼ")}, + {0x1fbd, 0, 0, 1, g(Yes, No, false, false, "", " ̓")}, + {0x1fbe, 0, 0, 0, f(No, false, "ι")}, + {0x1fbf, 0, 0, 1, g(Yes, No, true, false, "", " ̓")}, + {0x1fc0, 0, 0, 1, g(Yes, No, false, false, "", " ͂")}, + {0x1fc1, 0, 0, 2, g(Yes, No, false, false, "῁", " ̈͂")}, + {0x1fc2, 0, 0, 2, f(Yes, false, "ῂ")}, + {0x1fc3, 0, 0, 1, f(Yes, false, "ῃ")}, + {0x1fc4, 0, 0, 2, f(Yes, false, "ῄ")}, + {0x1fc5, 0, 0, 0, f(Yes, false, "")}, + {0x1fc6, 0, 0, 1, f(Yes, true, "ῆ")}, + {0x1fc7, 0, 0, 2, f(Yes, false, "ῇ")}, + {0x1fc8, 0, 0, 1, f(Yes, false, "Ὲ")}, + {0x1fc9, 0, 0, 1, f(No, false, "Έ")}, + {0x1fca, 0, 0, 1, f(Yes, false, "Ὴ")}, + {0x1fcb, 0, 0, 1, f(No, false, "Ή")}, + {0x1fcc, 0, 0, 1, f(Yes, false, "ῌ")}, + {0x1fcd, 0, 0, 2, g(Yes, No, false, false, "῍", " ̓̀")}, + {0x1fce, 0, 0, 2, g(Yes, No, false, false, "῎", " ̓́")}, + {0x1fcf, 0, 0, 2, g(Yes, No, false, false, "῏", " ̓͂")}, + {0x1fd0, 0, 0, 1, f(Yes, false, "ῐ")}, + {0x1fd1, 0, 0, 1, f(Yes, false, "ῑ")}, + {0x1fd2, 0, 0, 2, f(Yes, false, "ῒ")}, + {0x1fd3, 0, 0, 2, f(No, false, "ΐ")}, + {0x1fd4, 0, 0, 0, f(Yes, false, "")}, + {0x1fd6, 0, 0, 1, f(Yes, false, "ῖ")}, + {0x1fd7, 0, 0, 2, f(Yes, false, "ῗ")}, + {0x1fd8, 0, 0, 1, f(Yes, false, "Ῐ")}, + {0x1fd9, 0, 0, 1, f(Yes, false, "Ῑ")}, + {0x1fda, 0, 0, 1, f(Yes, false, "Ὶ")}, + {0x1fdb, 0, 0, 1, f(No, false, "Ί")}, + {0x1fdc, 0, 0, 0, f(Yes, false, "")}, + {0x1fdd, 0, 0, 2, g(Yes, No, false, false, "῝", " ̔̀")}, + {0x1fde, 0, 0, 2, g(Yes, No, false, false, "῞", " ̔́")}, + {0x1fdf, 0, 0, 2, g(Yes, No, false, false, "῟", " ̔͂")}, + {0x1fe0, 0, 0, 1, f(Yes, false, "ῠ")}, + {0x1fe1, 0, 0, 1, f(Yes, false, "ῡ")}, + {0x1fe2, 0, 0, 2, f(Yes, false, "ῢ")}, + {0x1fe3, 0, 0, 2, f(No, false, "ΰ")}, + {0x1fe4, 0, 0, 1, f(Yes, false, "ῤ")}, + {0x1fe5, 0, 0, 1, f(Yes, false, "ῥ")}, + {0x1fe6, 0, 0, 1, f(Yes, false, "ῦ")}, + {0x1fe7, 0, 0, 2, f(Yes, false, "ῧ")}, + {0x1fe8, 0, 0, 1, f(Yes, false, "Ῠ")}, + {0x1fe9, 0, 0, 1, f(Yes, false, "Ῡ")}, + {0x1fea, 0, 0, 1, f(Yes, false, "Ὺ")}, + {0x1feb, 0, 0, 1, f(No, false, "Ύ")}, + {0x1fec, 0, 0, 1, f(Yes, false, "Ῥ")}, + {0x1fed, 0, 0, 2, g(Yes, No, false, false, "῭", " ̈̀")}, + {0x1fee, 0, 0, 2, g(No, No, false, false, "΅", " ̈́")}, + {0x1fef, 0, 0, 0, f(No, false, "`")}, + {0x1ff0, 0, 0, 0, f(Yes, false, "")}, + {0x1ff2, 0, 0, 2, f(Yes, false, "ῲ")}, + {0x1ff3, 0, 0, 1, f(Yes, false, "ῳ")}, + {0x1ff4, 0, 0, 2, f(Yes, false, "ῴ")}, + {0x1ff5, 0, 0, 0, f(Yes, false, "")}, + {0x1ff6, 0, 0, 1, f(Yes, true, "ῶ")}, + {0x1ff7, 0, 0, 2, f(Yes, false, "ῷ")}, + {0x1ff8, 0, 0, 1, f(Yes, false, "Ὸ")}, + {0x1ff9, 0, 0, 1, f(No, false, "Ό")}, + {0x1ffa, 0, 0, 1, f(Yes, false, "Ὼ")}, + {0x1ffb, 0, 0, 1, f(No, false, "Ώ")}, + {0x1ffc, 0, 0, 1, f(Yes, false, "ῼ")}, + {0x1ffd, 0, 0, 1, g(No, No, false, false, "´", " ́")}, + {0x1ffe, 0, 0, 1, g(Yes, No, true, false, "", " ̔")}, + {0x1fff, 0, 0, 0, f(Yes, false, "")}, + {0x2000, 0, 0, 0, g(No, No, false, false, "\u2002", " ")}, + {0x2001, 0, 0, 0, g(No, No, false, false, "\u2003", " ")}, + {0x2002, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x200b, 0, 0, 0, f(Yes, false, "")}, + {0x2011, 0, 0, 0, g(Yes, No, false, false, "", "‐")}, + {0x2012, 0, 0, 0, f(Yes, false, "")}, + {0x2017, 0, 0, 1, g(Yes, No, false, false, "", " ̳")}, + {0x2018, 0, 0, 0, f(Yes, false, "")}, + {0x2024, 0, 0, 0, g(Yes, No, false, false, "", ".")}, + {0x2025, 0, 0, 0, g(Yes, No, false, false, "", "..")}, + {0x2026, 0, 0, 0, g(Yes, No, false, false, "", "...")}, + {0x2027, 0, 0, 0, f(Yes, false, "")}, + {0x202f, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x2030, 0, 0, 0, f(Yes, false, "")}, + {0x2033, 0, 0, 0, g(Yes, No, false, false, "", "′′")}, + {0x2034, 0, 0, 0, g(Yes, No, false, false, "", "′′′")}, + {0x2035, 0, 0, 0, f(Yes, false, "")}, + {0x2036, 0, 0, 0, g(Yes, No, false, false, "", "‵‵")}, + {0x2037, 0, 0, 0, g(Yes, No, false, false, "", "‵‵‵")}, + {0x2038, 0, 0, 0, f(Yes, false, "")}, + {0x203c, 0, 0, 0, g(Yes, No, false, false, "", "!!")}, + {0x203d, 0, 0, 0, f(Yes, false, "")}, + {0x203e, 0, 0, 1, g(Yes, No, false, false, "", " ̅")}, + {0x203f, 0, 0, 0, f(Yes, false, "")}, + {0x2047, 0, 0, 0, g(Yes, No, false, false, "", "??")}, + {0x2048, 0, 0, 0, g(Yes, No, false, false, "", "?!")}, + {0x2049, 0, 0, 0, g(Yes, No, false, false, "", "!?")}, + {0x204a, 0, 0, 0, f(Yes, false, "")}, + {0x2057, 0, 0, 0, g(Yes, No, false, false, "", "′′′′")}, + {0x2058, 0, 0, 0, f(Yes, false, "")}, + {0x205f, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x2060, 0, 0, 0, f(Yes, false, "")}, + {0x2070, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x2071, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x2072, 0, 0, 0, f(Yes, false, "")}, + {0x2074, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x2075, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x2076, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x2077, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x2078, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x2079, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x207a, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0x207b, 0, 0, 0, g(Yes, No, false, false, "", "−")}, + {0x207c, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0x207d, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0x207e, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0x207f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x2080, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x2081, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x2082, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x2083, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x2084, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x2085, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x2086, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x2087, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x2088, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x2089, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x208a, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0x208b, 0, 0, 0, g(Yes, No, false, false, "", "−")}, + {0x208c, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0x208d, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0x208e, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0x208f, 0, 0, 0, f(Yes, false, "")}, + {0x2090, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x2091, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x2092, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x2093, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x2094, 0, 0, 0, g(Yes, No, false, false, "", "ə")}, + {0x2095, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x2096, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x2097, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x2098, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x2099, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x209a, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x209b, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x209c, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x209d, 0, 0, 0, f(Yes, false, "")}, + {0x20a8, 0, 0, 0, g(Yes, No, false, false, "", "Rs")}, + {0x20a9, 0, 0, 0, f(Yes, false, "")}, + {0x20d0, 230, 1, 1, f(Yes, false, "")}, + {0x20d2, 1, 1, 1, f(Yes, false, "")}, + {0x20d4, 230, 1, 1, f(Yes, false, "")}, + {0x20d8, 1, 1, 1, f(Yes, false, "")}, + {0x20db, 230, 1, 1, f(Yes, false, "")}, + {0x20dd, 0, 0, 0, f(Yes, false, "")}, + {0x20e1, 230, 1, 1, f(Yes, false, "")}, + {0x20e2, 0, 0, 0, f(Yes, false, "")}, + {0x20e5, 1, 1, 1, f(Yes, false, "")}, + {0x20e7, 230, 1, 1, f(Yes, false, "")}, + {0x20e8, 220, 1, 1, f(Yes, false, "")}, + {0x20e9, 230, 1, 1, f(Yes, false, "")}, + {0x20ea, 1, 1, 1, f(Yes, false, "")}, + {0x20ec, 220, 1, 1, f(Yes, false, "")}, + {0x20f0, 230, 1, 1, f(Yes, false, "")}, + {0x20f1, 0, 0, 0, f(Yes, false, "")}, + {0x2100, 0, 0, 0, g(Yes, No, false, false, "", "a/c")}, + {0x2101, 0, 0, 0, g(Yes, No, false, false, "", "a/s")}, + {0x2102, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x2103, 0, 0, 0, g(Yes, No, false, false, "", "°C")}, + {0x2104, 0, 0, 0, f(Yes, false, "")}, + {0x2105, 0, 0, 0, g(Yes, No, false, false, "", "c/o")}, + {0x2106, 0, 0, 0, g(Yes, No, false, false, "", "c/u")}, + {0x2107, 0, 0, 0, g(Yes, No, false, false, "", "Ɛ")}, + {0x2108, 0, 0, 0, f(Yes, false, "")}, + {0x2109, 0, 0, 0, g(Yes, No, false, false, "", "°F")}, + {0x210a, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x210b, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x210e, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x210f, 0, 0, 0, g(Yes, No, false, false, "", "ħ")}, + {0x2110, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x2112, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x2113, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x2114, 0, 0, 0, f(Yes, false, "")}, + {0x2115, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x2116, 0, 0, 0, g(Yes, No, false, false, "", "No")}, + {0x2117, 0, 0, 0, f(Yes, false, "")}, + {0x2119, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x211a, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x211b, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x211e, 0, 0, 0, f(Yes, false, "")}, + {0x2120, 0, 0, 0, g(Yes, No, false, false, "", "SM")}, + {0x2121, 0, 0, 0, g(Yes, No, false, false, "", "TEL")}, + {0x2122, 0, 0, 0, g(Yes, No, false, false, "", "TM")}, + {0x2123, 0, 0, 0, f(Yes, false, "")}, + {0x2124, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x2125, 0, 0, 0, f(Yes, false, "")}, + {0x2126, 0, 0, 0, f(No, false, "Ω")}, + {0x2127, 0, 0, 0, f(Yes, false, "")}, + {0x2128, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x2129, 0, 0, 0, f(Yes, false, "")}, + {0x212a, 0, 0, 0, f(No, false, "K")}, + {0x212b, 0, 0, 1, f(No, false, "Å")}, + {0x212c, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x212d, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x212e, 0, 0, 0, f(Yes, false, "")}, + {0x212f, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x2130, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x2131, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x2132, 0, 0, 0, f(Yes, false, "")}, + {0x2133, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x2134, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x2135, 0, 0, 0, g(Yes, No, false, false, "", "א")}, + {0x2136, 0, 0, 0, g(Yes, No, false, false, "", "ב")}, + {0x2137, 0, 0, 0, g(Yes, No, false, false, "", "ג")}, + {0x2138, 0, 0, 0, g(Yes, No, false, false, "", "ד")}, + {0x2139, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x213a, 0, 0, 0, f(Yes, false, "")}, + {0x213b, 0, 0, 0, g(Yes, No, false, false, "", "FAX")}, + {0x213c, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x213d, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x213e, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x213f, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x2140, 0, 0, 0, g(Yes, No, false, false, "", "∑")}, + {0x2141, 0, 0, 0, f(Yes, false, "")}, + {0x2145, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x2146, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x2147, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x2148, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x2149, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x214a, 0, 0, 0, f(Yes, false, "")}, + {0x2150, 0, 0, 0, g(Yes, No, false, false, "", "1⁄7")}, + {0x2151, 0, 0, 0, g(Yes, No, false, false, "", "1⁄9")}, + {0x2152, 0, 0, 0, g(Yes, No, false, false, "", "1⁄10")}, + {0x2153, 0, 0, 0, g(Yes, No, false, false, "", "1⁄3")}, + {0x2154, 0, 0, 0, g(Yes, No, false, false, "", "2⁄3")}, + {0x2155, 0, 0, 0, g(Yes, No, false, false, "", "1⁄5")}, + {0x2156, 0, 0, 0, g(Yes, No, false, false, "", "2⁄5")}, + {0x2157, 0, 0, 0, g(Yes, No, false, false, "", "3⁄5")}, + {0x2158, 0, 0, 0, g(Yes, No, false, false, "", "4⁄5")}, + {0x2159, 0, 0, 0, g(Yes, No, false, false, "", "1⁄6")}, + {0x215a, 0, 0, 0, g(Yes, No, false, false, "", "5⁄6")}, + {0x215b, 0, 0, 0, g(Yes, No, false, false, "", "1⁄8")}, + {0x215c, 0, 0, 0, g(Yes, No, false, false, "", "3⁄8")}, + {0x215d, 0, 0, 0, g(Yes, No, false, false, "", "5⁄8")}, + {0x215e, 0, 0, 0, g(Yes, No, false, false, "", "7⁄8")}, + {0x215f, 0, 0, 0, g(Yes, No, false, false, "", "1⁄")}, + {0x2160, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x2161, 0, 0, 0, g(Yes, No, false, false, "", "II")}, + {0x2162, 0, 0, 0, g(Yes, No, false, false, "", "III")}, + {0x2163, 0, 0, 0, g(Yes, No, false, false, "", "IV")}, + {0x2164, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x2165, 0, 0, 0, g(Yes, No, false, false, "", "VI")}, + {0x2166, 0, 0, 0, g(Yes, No, false, false, "", "VII")}, + {0x2167, 0, 0, 0, g(Yes, No, false, false, "", "VIII")}, + {0x2168, 0, 0, 0, g(Yes, No, false, false, "", "IX")}, + {0x2169, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x216a, 0, 0, 0, g(Yes, No, false, false, "", "XI")}, + {0x216b, 0, 0, 0, g(Yes, No, false, false, "", "XII")}, + {0x216c, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x216d, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x216e, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x216f, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x2170, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x2171, 0, 0, 0, g(Yes, No, false, false, "", "ii")}, + {0x2172, 0, 0, 0, g(Yes, No, false, false, "", "iii")}, + {0x2173, 0, 0, 0, g(Yes, No, false, false, "", "iv")}, + {0x2174, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x2175, 0, 0, 0, g(Yes, No, false, false, "", "vi")}, + {0x2176, 0, 0, 0, g(Yes, No, false, false, "", "vii")}, + {0x2177, 0, 0, 0, g(Yes, No, false, false, "", "viii")}, + {0x2178, 0, 0, 0, g(Yes, No, false, false, "", "ix")}, + {0x2179, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x217a, 0, 0, 0, g(Yes, No, false, false, "", "xi")}, + {0x217b, 0, 0, 0, g(Yes, No, false, false, "", "xii")}, + {0x217c, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x217d, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x217e, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x217f, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x2180, 0, 0, 0, f(Yes, false, "")}, + {0x2189, 0, 0, 0, g(Yes, No, false, false, "", "0⁄3")}, + {0x218a, 0, 0, 0, f(Yes, false, "")}, + {0x2190, 0, 0, 0, f(Yes, true, "")}, + {0x2191, 0, 0, 0, f(Yes, false, "")}, + {0x2192, 0, 0, 0, f(Yes, true, "")}, + {0x2193, 0, 0, 0, f(Yes, false, "")}, + {0x2194, 0, 0, 0, f(Yes, true, "")}, + {0x2195, 0, 0, 0, f(Yes, false, "")}, + {0x219a, 0, 0, 1, f(Yes, false, "↚")}, + {0x219b, 0, 0, 1, f(Yes, false, "↛")}, + {0x219c, 0, 0, 0, f(Yes, false, "")}, + {0x21ae, 0, 0, 1, f(Yes, false, "↮")}, + {0x21af, 0, 0, 0, f(Yes, false, "")}, + {0x21cd, 0, 0, 1, f(Yes, false, "⇍")}, + {0x21ce, 0, 0, 1, f(Yes, false, "⇎")}, + {0x21cf, 0, 0, 1, f(Yes, false, "⇏")}, + {0x21d0, 0, 0, 0, f(Yes, true, "")}, + {0x21d1, 0, 0, 0, f(Yes, false, "")}, + {0x21d2, 0, 0, 0, f(Yes, true, "")}, + {0x21d3, 0, 0, 0, f(Yes, false, "")}, + {0x21d4, 0, 0, 0, f(Yes, true, "")}, + {0x21d5, 0, 0, 0, f(Yes, false, "")}, + {0x2203, 0, 0, 0, f(Yes, true, "")}, + {0x2204, 0, 0, 1, f(Yes, false, "∄")}, + {0x2205, 0, 0, 0, f(Yes, false, "")}, + {0x2208, 0, 0, 0, f(Yes, true, "")}, + {0x2209, 0, 0, 1, f(Yes, false, "∉")}, + {0x220a, 0, 0, 0, f(Yes, false, "")}, + {0x220b, 0, 0, 0, f(Yes, true, "")}, + {0x220c, 0, 0, 1, f(Yes, false, "∌")}, + {0x220d, 0, 0, 0, f(Yes, false, "")}, + {0x2223, 0, 0, 0, f(Yes, true, "")}, + {0x2224, 0, 0, 1, f(Yes, false, "∤")}, + {0x2225, 0, 0, 0, f(Yes, true, "")}, + {0x2226, 0, 0, 1, f(Yes, false, "∦")}, + {0x2227, 0, 0, 0, f(Yes, false, "")}, + {0x222c, 0, 0, 0, g(Yes, No, false, false, "", "∫∫")}, + {0x222d, 0, 0, 0, g(Yes, No, false, false, "", "∫∫∫")}, + {0x222e, 0, 0, 0, f(Yes, false, "")}, + {0x222f, 0, 0, 0, g(Yes, No, false, false, "", "∮∮")}, + {0x2230, 0, 0, 0, g(Yes, No, false, false, "", "∮∮∮")}, + {0x2231, 0, 0, 0, f(Yes, false, "")}, + {0x223c, 0, 0, 0, f(Yes, true, "")}, + {0x223d, 0, 0, 0, f(Yes, false, "")}, + {0x2241, 0, 0, 1, f(Yes, false, "≁")}, + {0x2242, 0, 0, 0, f(Yes, false, "")}, + {0x2243, 0, 0, 0, f(Yes, true, "")}, + {0x2244, 0, 0, 1, f(Yes, false, "≄")}, + {0x2245, 0, 0, 0, f(Yes, true, "")}, + {0x2246, 0, 0, 0, f(Yes, false, "")}, + {0x2247, 0, 0, 1, f(Yes, false, "≇")}, + {0x2248, 0, 0, 0, f(Yes, true, "")}, + {0x2249, 0, 0, 1, f(Yes, false, "≉")}, + {0x224a, 0, 0, 0, f(Yes, false, "")}, + {0x224d, 0, 0, 0, f(Yes, true, "")}, + {0x224e, 0, 0, 0, f(Yes, false, "")}, + {0x2260, 0, 0, 1, f(Yes, false, "≠")}, + {0x2261, 0, 0, 0, f(Yes, true, "")}, + {0x2262, 0, 0, 1, f(Yes, false, "≢")}, + {0x2263, 0, 0, 0, f(Yes, false, "")}, + {0x2264, 0, 0, 0, f(Yes, true, "")}, + {0x2266, 0, 0, 0, f(Yes, false, "")}, + {0x226d, 0, 0, 1, f(Yes, false, "≭")}, + {0x226e, 0, 0, 1, f(Yes, false, "≮")}, + {0x226f, 0, 0, 1, f(Yes, false, "≯")}, + {0x2270, 0, 0, 1, f(Yes, false, "≰")}, + {0x2271, 0, 0, 1, f(Yes, false, "≱")}, + {0x2272, 0, 0, 0, f(Yes, true, "")}, + {0x2274, 0, 0, 1, f(Yes, false, "≴")}, + {0x2275, 0, 0, 1, f(Yes, false, "≵")}, + {0x2276, 0, 0, 0, f(Yes, true, "")}, + {0x2278, 0, 0, 1, f(Yes, false, "≸")}, + {0x2279, 0, 0, 1, f(Yes, false, "≹")}, + {0x227a, 0, 0, 0, f(Yes, true, "")}, + {0x227e, 0, 0, 0, f(Yes, false, "")}, + {0x2280, 0, 0, 1, f(Yes, false, "⊀")}, + {0x2281, 0, 0, 1, f(Yes, false, "⊁")}, + {0x2282, 0, 0, 0, f(Yes, true, "")}, + {0x2284, 0, 0, 1, f(Yes, false, "⊄")}, + {0x2285, 0, 0, 1, f(Yes, false, "⊅")}, + {0x2286, 0, 0, 0, f(Yes, true, "")}, + {0x2288, 0, 0, 1, f(Yes, false, "⊈")}, + {0x2289, 0, 0, 1, f(Yes, false, "⊉")}, + {0x228a, 0, 0, 0, f(Yes, false, "")}, + {0x2291, 0, 0, 0, f(Yes, true, "")}, + {0x2293, 0, 0, 0, f(Yes, false, "")}, + {0x22a2, 0, 0, 0, f(Yes, true, "")}, + {0x22a3, 0, 0, 0, f(Yes, false, "")}, + {0x22a8, 0, 0, 0, f(Yes, true, "")}, + {0x22aa, 0, 0, 0, f(Yes, false, "")}, + {0x22ab, 0, 0, 0, f(Yes, true, "")}, + {0x22ac, 0, 0, 1, f(Yes, false, "⊬")}, + {0x22ad, 0, 0, 1, f(Yes, false, "⊭")}, + {0x22ae, 0, 0, 1, f(Yes, false, "⊮")}, + {0x22af, 0, 0, 1, f(Yes, false, "⊯")}, + {0x22b0, 0, 0, 0, f(Yes, false, "")}, + {0x22b2, 0, 0, 0, f(Yes, true, "")}, + {0x22b6, 0, 0, 0, f(Yes, false, "")}, + {0x22e0, 0, 0, 1, f(Yes, false, "⋠")}, + {0x22e1, 0, 0, 1, f(Yes, false, "⋡")}, + {0x22e2, 0, 0, 1, f(Yes, false, "⋢")}, + {0x22e3, 0, 0, 1, f(Yes, false, "⋣")}, + {0x22e4, 0, 0, 0, f(Yes, false, "")}, + {0x22ea, 0, 0, 1, f(Yes, false, "⋪")}, + {0x22eb, 0, 0, 1, f(Yes, false, "⋫")}, + {0x22ec, 0, 0, 1, f(Yes, false, "⋬")}, + {0x22ed, 0, 0, 1, f(Yes, false, "⋭")}, + {0x22ee, 0, 0, 0, f(Yes, false, "")}, + {0x2329, 0, 0, 0, f(No, false, "〈")}, + {0x232a, 0, 0, 0, f(No, false, "〉")}, + {0x232b, 0, 0, 0, f(Yes, false, "")}, + {0x2460, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x2461, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x2462, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x2463, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x2464, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x2465, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x2466, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x2467, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x2468, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x2469, 0, 0, 0, g(Yes, No, false, false, "", "10")}, + {0x246a, 0, 0, 0, g(Yes, No, false, false, "", "11")}, + {0x246b, 0, 0, 0, g(Yes, No, false, false, "", "12")}, + {0x246c, 0, 0, 0, g(Yes, No, false, false, "", "13")}, + {0x246d, 0, 0, 0, g(Yes, No, false, false, "", "14")}, + {0x246e, 0, 0, 0, g(Yes, No, false, false, "", "15")}, + {0x246f, 0, 0, 0, g(Yes, No, false, false, "", "16")}, + {0x2470, 0, 0, 0, g(Yes, No, false, false, "", "17")}, + {0x2471, 0, 0, 0, g(Yes, No, false, false, "", "18")}, + {0x2472, 0, 0, 0, g(Yes, No, false, false, "", "19")}, + {0x2473, 0, 0, 0, g(Yes, No, false, false, "", "20")}, + {0x2474, 0, 0, 0, g(Yes, No, false, false, "", "(1)")}, + {0x2475, 0, 0, 0, g(Yes, No, false, false, "", "(2)")}, + {0x2476, 0, 0, 0, g(Yes, No, false, false, "", "(3)")}, + {0x2477, 0, 0, 0, g(Yes, No, false, false, "", "(4)")}, + {0x2478, 0, 0, 0, g(Yes, No, false, false, "", "(5)")}, + {0x2479, 0, 0, 0, g(Yes, No, false, false, "", "(6)")}, + {0x247a, 0, 0, 0, g(Yes, No, false, false, "", "(7)")}, + {0x247b, 0, 0, 0, g(Yes, No, false, false, "", "(8)")}, + {0x247c, 0, 0, 0, g(Yes, No, false, false, "", "(9)")}, + {0x247d, 0, 0, 0, g(Yes, No, false, false, "", "(10)")}, + {0x247e, 0, 0, 0, g(Yes, No, false, false, "", "(11)")}, + {0x247f, 0, 0, 0, g(Yes, No, false, false, "", "(12)")}, + {0x2480, 0, 0, 0, g(Yes, No, false, false, "", "(13)")}, + {0x2481, 0, 0, 0, g(Yes, No, false, false, "", "(14)")}, + {0x2482, 0, 0, 0, g(Yes, No, false, false, "", "(15)")}, + {0x2483, 0, 0, 0, g(Yes, No, false, false, "", "(16)")}, + {0x2484, 0, 0, 0, g(Yes, No, false, false, "", "(17)")}, + {0x2485, 0, 0, 0, g(Yes, No, false, false, "", "(18)")}, + {0x2486, 0, 0, 0, g(Yes, No, false, false, "", "(19)")}, + {0x2487, 0, 0, 0, g(Yes, No, false, false, "", "(20)")}, + {0x2488, 0, 0, 0, g(Yes, No, false, false, "", "1.")}, + {0x2489, 0, 0, 0, g(Yes, No, false, false, "", "2.")}, + {0x248a, 0, 0, 0, g(Yes, No, false, false, "", "3.")}, + {0x248b, 0, 0, 0, g(Yes, No, false, false, "", "4.")}, + {0x248c, 0, 0, 0, g(Yes, No, false, false, "", "5.")}, + {0x248d, 0, 0, 0, g(Yes, No, false, false, "", "6.")}, + {0x248e, 0, 0, 0, g(Yes, No, false, false, "", "7.")}, + {0x248f, 0, 0, 0, g(Yes, No, false, false, "", "8.")}, + {0x2490, 0, 0, 0, g(Yes, No, false, false, "", "9.")}, + {0x2491, 0, 0, 0, g(Yes, No, false, false, "", "10.")}, + {0x2492, 0, 0, 0, g(Yes, No, false, false, "", "11.")}, + {0x2493, 0, 0, 0, g(Yes, No, false, false, "", "12.")}, + {0x2494, 0, 0, 0, g(Yes, No, false, false, "", "13.")}, + {0x2495, 0, 0, 0, g(Yes, No, false, false, "", "14.")}, + {0x2496, 0, 0, 0, g(Yes, No, false, false, "", "15.")}, + {0x2497, 0, 0, 0, g(Yes, No, false, false, "", "16.")}, + {0x2498, 0, 0, 0, g(Yes, No, false, false, "", "17.")}, + {0x2499, 0, 0, 0, g(Yes, No, false, false, "", "18.")}, + {0x249a, 0, 0, 0, g(Yes, No, false, false, "", "19.")}, + {0x249b, 0, 0, 0, g(Yes, No, false, false, "", "20.")}, + {0x249c, 0, 0, 0, g(Yes, No, false, false, "", "(a)")}, + {0x249d, 0, 0, 0, g(Yes, No, false, false, "", "(b)")}, + {0x249e, 0, 0, 0, g(Yes, No, false, false, "", "(c)")}, + {0x249f, 0, 0, 0, g(Yes, No, false, false, "", "(d)")}, + {0x24a0, 0, 0, 0, g(Yes, No, false, false, "", "(e)")}, + {0x24a1, 0, 0, 0, g(Yes, No, false, false, "", "(f)")}, + {0x24a2, 0, 0, 0, g(Yes, No, false, false, "", "(g)")}, + {0x24a3, 0, 0, 0, g(Yes, No, false, false, "", "(h)")}, + {0x24a4, 0, 0, 0, g(Yes, No, false, false, "", "(i)")}, + {0x24a5, 0, 0, 0, g(Yes, No, false, false, "", "(j)")}, + {0x24a6, 0, 0, 0, g(Yes, No, false, false, "", "(k)")}, + {0x24a7, 0, 0, 0, g(Yes, No, false, false, "", "(l)")}, + {0x24a8, 0, 0, 0, g(Yes, No, false, false, "", "(m)")}, + {0x24a9, 0, 0, 0, g(Yes, No, false, false, "", "(n)")}, + {0x24aa, 0, 0, 0, g(Yes, No, false, false, "", "(o)")}, + {0x24ab, 0, 0, 0, g(Yes, No, false, false, "", "(p)")}, + {0x24ac, 0, 0, 0, g(Yes, No, false, false, "", "(q)")}, + {0x24ad, 0, 0, 0, g(Yes, No, false, false, "", "(r)")}, + {0x24ae, 0, 0, 0, g(Yes, No, false, false, "", "(s)")}, + {0x24af, 0, 0, 0, g(Yes, No, false, false, "", "(t)")}, + {0x24b0, 0, 0, 0, g(Yes, No, false, false, "", "(u)")}, + {0x24b1, 0, 0, 0, g(Yes, No, false, false, "", "(v)")}, + {0x24b2, 0, 0, 0, g(Yes, No, false, false, "", "(w)")}, + {0x24b3, 0, 0, 0, g(Yes, No, false, false, "", "(x)")}, + {0x24b4, 0, 0, 0, g(Yes, No, false, false, "", "(y)")}, + {0x24b5, 0, 0, 0, g(Yes, No, false, false, "", "(z)")}, + {0x24b6, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x24b7, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x24b8, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x24b9, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x24ba, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x24bb, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x24bc, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x24bd, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x24be, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x24bf, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x24c0, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x24c1, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x24c2, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x24c3, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x24c4, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x24c5, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x24c6, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x24c7, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x24c8, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x24c9, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x24ca, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x24cb, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x24cc, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x24cd, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x24ce, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x24cf, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x24d0, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x24d1, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x24d2, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x24d3, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x24d4, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x24d5, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x24d6, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x24d7, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x24d8, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x24d9, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x24da, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x24db, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x24dc, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x24dd, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x24de, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x24df, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x24e0, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x24e1, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x24e2, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x24e3, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x24e4, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x24e5, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x24e6, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x24e7, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x24e8, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x24e9, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x24ea, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x24eb, 0, 0, 0, f(Yes, false, "")}, + {0x2a0c, 0, 0, 0, g(Yes, No, false, false, "", "∫∫∫∫")}, + {0x2a0d, 0, 0, 0, f(Yes, false, "")}, + {0x2a74, 0, 0, 0, g(Yes, No, false, false, "", "::=")}, + {0x2a75, 0, 0, 0, g(Yes, No, false, false, "", "==")}, + {0x2a76, 0, 0, 0, g(Yes, No, false, false, "", "===")}, + {0x2a77, 0, 0, 0, f(Yes, false, "")}, + {0x2adc, 0, 0, 1, f(No, false, "⫝̸")}, + {0x2add, 0, 0, 0, f(Yes, false, "")}, + {0x2c7c, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x2c7d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x2c7e, 0, 0, 0, f(Yes, false, "")}, + {0x2cef, 230, 1, 1, f(Yes, false, "")}, + {0x2cf2, 0, 0, 0, f(Yes, false, "")}, + {0x2d6f, 0, 0, 0, g(Yes, No, false, false, "", "ⵡ")}, + {0x2d70, 0, 0, 0, f(Yes, false, "")}, + {0x2d7f, 9, 1, 1, f(Yes, false, "")}, + {0x2d80, 0, 0, 0, f(Yes, false, "")}, + {0x2de0, 230, 1, 1, f(Yes, false, "")}, + {0x2e00, 0, 0, 0, f(Yes, false, "")}, + {0x2e9f, 0, 0, 0, g(Yes, No, false, false, "", "母")}, + {0x2ea0, 0, 0, 0, f(Yes, false, "")}, + {0x2ef3, 0, 0, 0, g(Yes, No, false, false, "", "龟")}, + {0x2ef4, 0, 0, 0, f(Yes, false, "")}, + {0x2f00, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x2f01, 0, 0, 0, g(Yes, No, false, false, "", "丨")}, + {0x2f02, 0, 0, 0, g(Yes, No, false, false, "", "丶")}, + {0x2f03, 0, 0, 0, g(Yes, No, false, false, "", "丿")}, + {0x2f04, 0, 0, 0, g(Yes, No, false, false, "", "乙")}, + {0x2f05, 0, 0, 0, g(Yes, No, false, false, "", "亅")}, + {0x2f06, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x2f07, 0, 0, 0, g(Yes, No, false, false, "", "亠")}, + {0x2f08, 0, 0, 0, g(Yes, No, false, false, "", "人")}, + {0x2f09, 0, 0, 0, g(Yes, No, false, false, "", "儿")}, + {0x2f0a, 0, 0, 0, g(Yes, No, false, false, "", "入")}, + {0x2f0b, 0, 0, 0, g(Yes, No, false, false, "", "八")}, + {0x2f0c, 0, 0, 0, g(Yes, No, false, false, "", "冂")}, + {0x2f0d, 0, 0, 0, g(Yes, No, false, false, "", "冖")}, + {0x2f0e, 0, 0, 0, g(Yes, No, false, false, "", "冫")}, + {0x2f0f, 0, 0, 0, g(Yes, No, false, false, "", "几")}, + {0x2f10, 0, 0, 0, g(Yes, No, false, false, "", "凵")}, + {0x2f11, 0, 0, 0, g(Yes, No, false, false, "", "刀")}, + {0x2f12, 0, 0, 0, g(Yes, No, false, false, "", "力")}, + {0x2f13, 0, 0, 0, g(Yes, No, false, false, "", "勹")}, + {0x2f14, 0, 0, 0, g(Yes, No, false, false, "", "匕")}, + {0x2f15, 0, 0, 0, g(Yes, No, false, false, "", "匚")}, + {0x2f16, 0, 0, 0, g(Yes, No, false, false, "", "匸")}, + {0x2f17, 0, 0, 0, g(Yes, No, false, false, "", "十")}, + {0x2f18, 0, 0, 0, g(Yes, No, false, false, "", "卜")}, + {0x2f19, 0, 0, 0, g(Yes, No, false, false, "", "卩")}, + {0x2f1a, 0, 0, 0, g(Yes, No, false, false, "", "厂")}, + {0x2f1b, 0, 0, 0, g(Yes, No, false, false, "", "厶")}, + {0x2f1c, 0, 0, 0, g(Yes, No, false, false, "", "又")}, + {0x2f1d, 0, 0, 0, g(Yes, No, false, false, "", "口")}, + {0x2f1e, 0, 0, 0, g(Yes, No, false, false, "", "囗")}, + {0x2f1f, 0, 0, 0, g(Yes, No, false, false, "", "土")}, + {0x2f20, 0, 0, 0, g(Yes, No, false, false, "", "士")}, + {0x2f21, 0, 0, 0, g(Yes, No, false, false, "", "夂")}, + {0x2f22, 0, 0, 0, g(Yes, No, false, false, "", "夊")}, + {0x2f23, 0, 0, 0, g(Yes, No, false, false, "", "夕")}, + {0x2f24, 0, 0, 0, g(Yes, No, false, false, "", "大")}, + {0x2f25, 0, 0, 0, g(Yes, No, false, false, "", "女")}, + {0x2f26, 0, 0, 0, g(Yes, No, false, false, "", "子")}, + {0x2f27, 0, 0, 0, g(Yes, No, false, false, "", "宀")}, + {0x2f28, 0, 0, 0, g(Yes, No, false, false, "", "寸")}, + {0x2f29, 0, 0, 0, g(Yes, No, false, false, "", "小")}, + {0x2f2a, 0, 0, 0, g(Yes, No, false, false, "", "尢")}, + {0x2f2b, 0, 0, 0, g(Yes, No, false, false, "", "尸")}, + {0x2f2c, 0, 0, 0, g(Yes, No, false, false, "", "屮")}, + {0x2f2d, 0, 0, 0, g(Yes, No, false, false, "", "山")}, + {0x2f2e, 0, 0, 0, g(Yes, No, false, false, "", "巛")}, + {0x2f2f, 0, 0, 0, g(Yes, No, false, false, "", "工")}, + {0x2f30, 0, 0, 0, g(Yes, No, false, false, "", "己")}, + {0x2f31, 0, 0, 0, g(Yes, No, false, false, "", "巾")}, + {0x2f32, 0, 0, 0, g(Yes, No, false, false, "", "干")}, + {0x2f33, 0, 0, 0, g(Yes, No, false, false, "", "幺")}, + {0x2f34, 0, 0, 0, g(Yes, No, false, false, "", "广")}, + {0x2f35, 0, 0, 0, g(Yes, No, false, false, "", "廴")}, + {0x2f36, 0, 0, 0, g(Yes, No, false, false, "", "廾")}, + {0x2f37, 0, 0, 0, g(Yes, No, false, false, "", "弋")}, + {0x2f38, 0, 0, 0, g(Yes, No, false, false, "", "弓")}, + {0x2f39, 0, 0, 0, g(Yes, No, false, false, "", "彐")}, + {0x2f3a, 0, 0, 0, g(Yes, No, false, false, "", "彡")}, + {0x2f3b, 0, 0, 0, g(Yes, No, false, false, "", "彳")}, + {0x2f3c, 0, 0, 0, g(Yes, No, false, false, "", "心")}, + {0x2f3d, 0, 0, 0, g(Yes, No, false, false, "", "戈")}, + {0x2f3e, 0, 0, 0, g(Yes, No, false, false, "", "戶")}, + {0x2f3f, 0, 0, 0, g(Yes, No, false, false, "", "手")}, + {0x2f40, 0, 0, 0, g(Yes, No, false, false, "", "支")}, + {0x2f41, 0, 0, 0, g(Yes, No, false, false, "", "攴")}, + {0x2f42, 0, 0, 0, g(Yes, No, false, false, "", "文")}, + {0x2f43, 0, 0, 0, g(Yes, No, false, false, "", "斗")}, + {0x2f44, 0, 0, 0, g(Yes, No, false, false, "", "斤")}, + {0x2f45, 0, 0, 0, g(Yes, No, false, false, "", "方")}, + {0x2f46, 0, 0, 0, g(Yes, No, false, false, "", "无")}, + {0x2f47, 0, 0, 0, g(Yes, No, false, false, "", "日")}, + {0x2f48, 0, 0, 0, g(Yes, No, false, false, "", "曰")}, + {0x2f49, 0, 0, 0, g(Yes, No, false, false, "", "月")}, + {0x2f4a, 0, 0, 0, g(Yes, No, false, false, "", "木")}, + {0x2f4b, 0, 0, 0, g(Yes, No, false, false, "", "欠")}, + {0x2f4c, 0, 0, 0, g(Yes, No, false, false, "", "止")}, + {0x2f4d, 0, 0, 0, g(Yes, No, false, false, "", "歹")}, + {0x2f4e, 0, 0, 0, g(Yes, No, false, false, "", "殳")}, + {0x2f4f, 0, 0, 0, g(Yes, No, false, false, "", "毋")}, + {0x2f50, 0, 0, 0, g(Yes, No, false, false, "", "比")}, + {0x2f51, 0, 0, 0, g(Yes, No, false, false, "", "毛")}, + {0x2f52, 0, 0, 0, g(Yes, No, false, false, "", "氏")}, + {0x2f53, 0, 0, 0, g(Yes, No, false, false, "", "气")}, + {0x2f54, 0, 0, 0, g(Yes, No, false, false, "", "水")}, + {0x2f55, 0, 0, 0, g(Yes, No, false, false, "", "火")}, + {0x2f56, 0, 0, 0, g(Yes, No, false, false, "", "爪")}, + {0x2f57, 0, 0, 0, g(Yes, No, false, false, "", "父")}, + {0x2f58, 0, 0, 0, g(Yes, No, false, false, "", "爻")}, + {0x2f59, 0, 0, 0, g(Yes, No, false, false, "", "爿")}, + {0x2f5a, 0, 0, 0, g(Yes, No, false, false, "", "片")}, + {0x2f5b, 0, 0, 0, g(Yes, No, false, false, "", "牙")}, + {0x2f5c, 0, 0, 0, g(Yes, No, false, false, "", "牛")}, + {0x2f5d, 0, 0, 0, g(Yes, No, false, false, "", "犬")}, + {0x2f5e, 0, 0, 0, g(Yes, No, false, false, "", "玄")}, + {0x2f5f, 0, 0, 0, g(Yes, No, false, false, "", "玉")}, + {0x2f60, 0, 0, 0, g(Yes, No, false, false, "", "瓜")}, + {0x2f61, 0, 0, 0, g(Yes, No, false, false, "", "瓦")}, + {0x2f62, 0, 0, 0, g(Yes, No, false, false, "", "甘")}, + {0x2f63, 0, 0, 0, g(Yes, No, false, false, "", "生")}, + {0x2f64, 0, 0, 0, g(Yes, No, false, false, "", "用")}, + {0x2f65, 0, 0, 0, g(Yes, No, false, false, "", "田")}, + {0x2f66, 0, 0, 0, g(Yes, No, false, false, "", "疋")}, + {0x2f67, 0, 0, 0, g(Yes, No, false, false, "", "疒")}, + {0x2f68, 0, 0, 0, g(Yes, No, false, false, "", "癶")}, + {0x2f69, 0, 0, 0, g(Yes, No, false, false, "", "白")}, + {0x2f6a, 0, 0, 0, g(Yes, No, false, false, "", "皮")}, + {0x2f6b, 0, 0, 0, g(Yes, No, false, false, "", "皿")}, + {0x2f6c, 0, 0, 0, g(Yes, No, false, false, "", "目")}, + {0x2f6d, 0, 0, 0, g(Yes, No, false, false, "", "矛")}, + {0x2f6e, 0, 0, 0, g(Yes, No, false, false, "", "矢")}, + {0x2f6f, 0, 0, 0, g(Yes, No, false, false, "", "石")}, + {0x2f70, 0, 0, 0, g(Yes, No, false, false, "", "示")}, + {0x2f71, 0, 0, 0, g(Yes, No, false, false, "", "禸")}, + {0x2f72, 0, 0, 0, g(Yes, No, false, false, "", "禾")}, + {0x2f73, 0, 0, 0, g(Yes, No, false, false, "", "穴")}, + {0x2f74, 0, 0, 0, g(Yes, No, false, false, "", "立")}, + {0x2f75, 0, 0, 0, g(Yes, No, false, false, "", "竹")}, + {0x2f76, 0, 0, 0, g(Yes, No, false, false, "", "米")}, + {0x2f77, 0, 0, 0, g(Yes, No, false, false, "", "糸")}, + {0x2f78, 0, 0, 0, g(Yes, No, false, false, "", "缶")}, + {0x2f79, 0, 0, 0, g(Yes, No, false, false, "", "网")}, + {0x2f7a, 0, 0, 0, g(Yes, No, false, false, "", "羊")}, + {0x2f7b, 0, 0, 0, g(Yes, No, false, false, "", "羽")}, + {0x2f7c, 0, 0, 0, g(Yes, No, false, false, "", "老")}, + {0x2f7d, 0, 0, 0, g(Yes, No, false, false, "", "而")}, + {0x2f7e, 0, 0, 0, g(Yes, No, false, false, "", "耒")}, + {0x2f7f, 0, 0, 0, g(Yes, No, false, false, "", "耳")}, + {0x2f80, 0, 0, 0, g(Yes, No, false, false, "", "聿")}, + {0x2f81, 0, 0, 0, g(Yes, No, false, false, "", "肉")}, + {0x2f82, 0, 0, 0, g(Yes, No, false, false, "", "臣")}, + {0x2f83, 0, 0, 0, g(Yes, No, false, false, "", "自")}, + {0x2f84, 0, 0, 0, g(Yes, No, false, false, "", "至")}, + {0x2f85, 0, 0, 0, g(Yes, No, false, false, "", "臼")}, + {0x2f86, 0, 0, 0, g(Yes, No, false, false, "", "舌")}, + {0x2f87, 0, 0, 0, g(Yes, No, false, false, "", "舛")}, + {0x2f88, 0, 0, 0, g(Yes, No, false, false, "", "舟")}, + {0x2f89, 0, 0, 0, g(Yes, No, false, false, "", "艮")}, + {0x2f8a, 0, 0, 0, g(Yes, No, false, false, "", "色")}, + {0x2f8b, 0, 0, 0, g(Yes, No, false, false, "", "艸")}, + {0x2f8c, 0, 0, 0, g(Yes, No, false, false, "", "虍")}, + {0x2f8d, 0, 0, 0, g(Yes, No, false, false, "", "虫")}, + {0x2f8e, 0, 0, 0, g(Yes, No, false, false, "", "血")}, + {0x2f8f, 0, 0, 0, g(Yes, No, false, false, "", "行")}, + {0x2f90, 0, 0, 0, g(Yes, No, false, false, "", "衣")}, + {0x2f91, 0, 0, 0, g(Yes, No, false, false, "", "襾")}, + {0x2f92, 0, 0, 0, g(Yes, No, false, false, "", "見")}, + {0x2f93, 0, 0, 0, g(Yes, No, false, false, "", "角")}, + {0x2f94, 0, 0, 0, g(Yes, No, false, false, "", "言")}, + {0x2f95, 0, 0, 0, g(Yes, No, false, false, "", "谷")}, + {0x2f96, 0, 0, 0, g(Yes, No, false, false, "", "豆")}, + {0x2f97, 0, 0, 0, g(Yes, No, false, false, "", "豕")}, + {0x2f98, 0, 0, 0, g(Yes, No, false, false, "", "豸")}, + {0x2f99, 0, 0, 0, g(Yes, No, false, false, "", "貝")}, + {0x2f9a, 0, 0, 0, g(Yes, No, false, false, "", "赤")}, + {0x2f9b, 0, 0, 0, g(Yes, No, false, false, "", "走")}, + {0x2f9c, 0, 0, 0, g(Yes, No, false, false, "", "足")}, + {0x2f9d, 0, 0, 0, g(Yes, No, false, false, "", "身")}, + {0x2f9e, 0, 0, 0, g(Yes, No, false, false, "", "車")}, + {0x2f9f, 0, 0, 0, g(Yes, No, false, false, "", "辛")}, + {0x2fa0, 0, 0, 0, g(Yes, No, false, false, "", "辰")}, + {0x2fa1, 0, 0, 0, g(Yes, No, false, false, "", "辵")}, + {0x2fa2, 0, 0, 0, g(Yes, No, false, false, "", "邑")}, + {0x2fa3, 0, 0, 0, g(Yes, No, false, false, "", "酉")}, + {0x2fa4, 0, 0, 0, g(Yes, No, false, false, "", "釆")}, + {0x2fa5, 0, 0, 0, g(Yes, No, false, false, "", "里")}, + {0x2fa6, 0, 0, 0, g(Yes, No, false, false, "", "金")}, + {0x2fa7, 0, 0, 0, g(Yes, No, false, false, "", "長")}, + {0x2fa8, 0, 0, 0, g(Yes, No, false, false, "", "門")}, + {0x2fa9, 0, 0, 0, g(Yes, No, false, false, "", "阜")}, + {0x2faa, 0, 0, 0, g(Yes, No, false, false, "", "隶")}, + {0x2fab, 0, 0, 0, g(Yes, No, false, false, "", "隹")}, + {0x2fac, 0, 0, 0, g(Yes, No, false, false, "", "雨")}, + {0x2fad, 0, 0, 0, g(Yes, No, false, false, "", "靑")}, + {0x2fae, 0, 0, 0, g(Yes, No, false, false, "", "非")}, + {0x2faf, 0, 0, 0, g(Yes, No, false, false, "", "面")}, + {0x2fb0, 0, 0, 0, g(Yes, No, false, false, "", "革")}, + {0x2fb1, 0, 0, 0, g(Yes, No, false, false, "", "韋")}, + {0x2fb2, 0, 0, 0, g(Yes, No, false, false, "", "韭")}, + {0x2fb3, 0, 0, 0, g(Yes, No, false, false, "", "音")}, + {0x2fb4, 0, 0, 0, g(Yes, No, false, false, "", "頁")}, + {0x2fb5, 0, 0, 0, g(Yes, No, false, false, "", "風")}, + {0x2fb6, 0, 0, 0, g(Yes, No, false, false, "", "飛")}, + {0x2fb7, 0, 0, 0, g(Yes, No, false, false, "", "食")}, + {0x2fb8, 0, 0, 0, g(Yes, No, false, false, "", "首")}, + {0x2fb9, 0, 0, 0, g(Yes, No, false, false, "", "香")}, + {0x2fba, 0, 0, 0, g(Yes, No, false, false, "", "馬")}, + {0x2fbb, 0, 0, 0, g(Yes, No, false, false, "", "骨")}, + {0x2fbc, 0, 0, 0, g(Yes, No, false, false, "", "高")}, + {0x2fbd, 0, 0, 0, g(Yes, No, false, false, "", "髟")}, + {0x2fbe, 0, 0, 0, g(Yes, No, false, false, "", "鬥")}, + {0x2fbf, 0, 0, 0, g(Yes, No, false, false, "", "鬯")}, + {0x2fc0, 0, 0, 0, g(Yes, No, false, false, "", "鬲")}, + {0x2fc1, 0, 0, 0, g(Yes, No, false, false, "", "鬼")}, + {0x2fc2, 0, 0, 0, g(Yes, No, false, false, "", "魚")}, + {0x2fc3, 0, 0, 0, g(Yes, No, false, false, "", "鳥")}, + {0x2fc4, 0, 0, 0, g(Yes, No, false, false, "", "鹵")}, + {0x2fc5, 0, 0, 0, g(Yes, No, false, false, "", "鹿")}, + {0x2fc6, 0, 0, 0, g(Yes, No, false, false, "", "麥")}, + {0x2fc7, 0, 0, 0, g(Yes, No, false, false, "", "麻")}, + {0x2fc8, 0, 0, 0, g(Yes, No, false, false, "", "黃")}, + {0x2fc9, 0, 0, 0, g(Yes, No, false, false, "", "黍")}, + {0x2fca, 0, 0, 0, g(Yes, No, false, false, "", "黑")}, + {0x2fcb, 0, 0, 0, g(Yes, No, false, false, "", "黹")}, + {0x2fcc, 0, 0, 0, g(Yes, No, false, false, "", "黽")}, + {0x2fcd, 0, 0, 0, g(Yes, No, false, false, "", "鼎")}, + {0x2fce, 0, 0, 0, g(Yes, No, false, false, "", "鼓")}, + {0x2fcf, 0, 0, 0, g(Yes, No, false, false, "", "鼠")}, + {0x2fd0, 0, 0, 0, g(Yes, No, false, false, "", "鼻")}, + {0x2fd1, 0, 0, 0, g(Yes, No, false, false, "", "齊")}, + {0x2fd2, 0, 0, 0, g(Yes, No, false, false, "", "齒")}, + {0x2fd3, 0, 0, 0, g(Yes, No, false, false, "", "龍")}, + {0x2fd4, 0, 0, 0, g(Yes, No, false, false, "", "龜")}, + {0x2fd5, 0, 0, 0, g(Yes, No, false, false, "", "龠")}, + {0x2fd6, 0, 0, 0, f(Yes, false, "")}, + {0x3000, 0, 0, 0, g(Yes, No, false, false, "", " ")}, + {0x3001, 0, 0, 0, f(Yes, false, "")}, + {0x302a, 218, 1, 1, f(Yes, false, "")}, + {0x302b, 228, 1, 1, f(Yes, false, "")}, + {0x302c, 232, 1, 1, f(Yes, false, "")}, + {0x302d, 222, 1, 1, f(Yes, false, "")}, + {0x302e, 224, 1, 1, f(Yes, false, "")}, + {0x3030, 0, 0, 0, f(Yes, false, "")}, + {0x3036, 0, 0, 0, g(Yes, No, false, false, "", "〒")}, + {0x3037, 0, 0, 0, f(Yes, false, "")}, + {0x3038, 0, 0, 0, g(Yes, No, false, false, "", "十")}, + {0x3039, 0, 0, 0, g(Yes, No, false, false, "", "卄")}, + {0x303a, 0, 0, 0, g(Yes, No, false, false, "", "卅")}, + {0x303b, 0, 0, 0, f(Yes, false, "")}, + {0x3046, 0, 0, 0, f(Yes, true, "")}, + {0x3047, 0, 0, 0, f(Yes, false, "")}, + {0x304b, 0, 0, 0, f(Yes, true, "")}, + {0x304c, 0, 0, 1, f(Yes, false, "が")}, + {0x304d, 0, 0, 0, f(Yes, true, "")}, + {0x304e, 0, 0, 1, f(Yes, false, "ぎ")}, + {0x304f, 0, 0, 0, f(Yes, true, "")}, + {0x3050, 0, 0, 1, f(Yes, false, "ぐ")}, + {0x3051, 0, 0, 0, f(Yes, true, "")}, + {0x3052, 0, 0, 1, f(Yes, false, "げ")}, + {0x3053, 0, 0, 0, f(Yes, true, "")}, + {0x3054, 0, 0, 1, f(Yes, false, "ご")}, + {0x3055, 0, 0, 0, f(Yes, true, "")}, + {0x3056, 0, 0, 1, f(Yes, false, "ざ")}, + {0x3057, 0, 0, 0, f(Yes, true, "")}, + {0x3058, 0, 0, 1, f(Yes, false, "じ")}, + {0x3059, 0, 0, 0, f(Yes, true, "")}, + {0x305a, 0, 0, 1, f(Yes, false, "ず")}, + {0x305b, 0, 0, 0, f(Yes, true, "")}, + {0x305c, 0, 0, 1, f(Yes, false, "ぜ")}, + {0x305d, 0, 0, 0, f(Yes, true, "")}, + {0x305e, 0, 0, 1, f(Yes, false, "ぞ")}, + {0x305f, 0, 0, 0, f(Yes, true, "")}, + {0x3060, 0, 0, 1, f(Yes, false, "だ")}, + {0x3061, 0, 0, 0, f(Yes, true, "")}, + {0x3062, 0, 0, 1, f(Yes, false, "ぢ")}, + {0x3063, 0, 0, 0, f(Yes, false, "")}, + {0x3064, 0, 0, 0, f(Yes, true, "")}, + {0x3065, 0, 0, 1, f(Yes, false, "づ")}, + {0x3066, 0, 0, 0, f(Yes, true, "")}, + {0x3067, 0, 0, 1, f(Yes, false, "で")}, + {0x3068, 0, 0, 0, f(Yes, true, "")}, + {0x3069, 0, 0, 1, f(Yes, false, "ど")}, + {0x306a, 0, 0, 0, f(Yes, false, "")}, + {0x306f, 0, 0, 0, f(Yes, true, "")}, + {0x3070, 0, 0, 1, f(Yes, false, "ば")}, + {0x3071, 0, 0, 1, f(Yes, false, "ぱ")}, + {0x3072, 0, 0, 0, f(Yes, true, "")}, + {0x3073, 0, 0, 1, f(Yes, false, "び")}, + {0x3074, 0, 0, 1, f(Yes, false, "ぴ")}, + {0x3075, 0, 0, 0, f(Yes, true, "")}, + {0x3076, 0, 0, 1, f(Yes, false, "ぶ")}, + {0x3077, 0, 0, 1, f(Yes, false, "ぷ")}, + {0x3078, 0, 0, 0, f(Yes, true, "")}, + {0x3079, 0, 0, 1, f(Yes, false, "べ")}, + {0x307a, 0, 0, 1, f(Yes, false, "ぺ")}, + {0x307b, 0, 0, 0, f(Yes, true, "")}, + {0x307c, 0, 0, 1, f(Yes, false, "ぼ")}, + {0x307d, 0, 0, 1, f(Yes, false, "ぽ")}, + {0x307e, 0, 0, 0, f(Yes, false, "")}, + {0x3094, 0, 0, 1, f(Yes, false, "ゔ")}, + {0x3095, 0, 0, 0, f(Yes, false, "")}, + {0x3099, 8, 1, 1, f(Maybe, false, "")}, + {0x309b, 0, 0, 1, g(Yes, No, false, false, "", " ゙")}, + {0x309c, 0, 0, 1, g(Yes, No, false, false, "", " ゚")}, + {0x309d, 0, 0, 0, f(Yes, true, "")}, + {0x309e, 0, 0, 1, f(Yes, false, "ゞ")}, + {0x309f, 0, 0, 0, g(Yes, No, false, false, "", "より")}, + {0x30a0, 0, 0, 0, f(Yes, false, "")}, + {0x30a6, 0, 0, 0, f(Yes, true, "")}, + {0x30a7, 0, 0, 0, f(Yes, false, "")}, + {0x30ab, 0, 0, 0, f(Yes, true, "")}, + {0x30ac, 0, 0, 1, f(Yes, false, "ガ")}, + {0x30ad, 0, 0, 0, f(Yes, true, "")}, + {0x30ae, 0, 0, 1, f(Yes, false, "ギ")}, + {0x30af, 0, 0, 0, f(Yes, true, "")}, + {0x30b0, 0, 0, 1, f(Yes, false, "グ")}, + {0x30b1, 0, 0, 0, f(Yes, true, "")}, + {0x30b2, 0, 0, 1, f(Yes, false, "ゲ")}, + {0x30b3, 0, 0, 0, f(Yes, true, "")}, + {0x30b4, 0, 0, 1, f(Yes, false, "ゴ")}, + {0x30b5, 0, 0, 0, f(Yes, true, "")}, + {0x30b6, 0, 0, 1, f(Yes, false, "ザ")}, + {0x30b7, 0, 0, 0, f(Yes, true, "")}, + {0x30b8, 0, 0, 1, f(Yes, false, "ジ")}, + {0x30b9, 0, 0, 0, f(Yes, true, "")}, + {0x30ba, 0, 0, 1, f(Yes, false, "ズ")}, + {0x30bb, 0, 0, 0, f(Yes, true, "")}, + {0x30bc, 0, 0, 1, f(Yes, false, "ゼ")}, + {0x30bd, 0, 0, 0, f(Yes, true, "")}, + {0x30be, 0, 0, 1, f(Yes, false, "ゾ")}, + {0x30bf, 0, 0, 0, f(Yes, true, "")}, + {0x30c0, 0, 0, 1, f(Yes, false, "ダ")}, + {0x30c1, 0, 0, 0, f(Yes, true, "")}, + {0x30c2, 0, 0, 1, f(Yes, false, "ヂ")}, + {0x30c3, 0, 0, 0, f(Yes, false, "")}, + {0x30c4, 0, 0, 0, f(Yes, true, "")}, + {0x30c5, 0, 0, 1, f(Yes, false, "ヅ")}, + {0x30c6, 0, 0, 0, f(Yes, true, "")}, + {0x30c7, 0, 0, 1, f(Yes, false, "デ")}, + {0x30c8, 0, 0, 0, f(Yes, true, "")}, + {0x30c9, 0, 0, 1, f(Yes, false, "ド")}, + {0x30ca, 0, 0, 0, f(Yes, false, "")}, + {0x30cf, 0, 0, 0, f(Yes, true, "")}, + {0x30d0, 0, 0, 1, f(Yes, false, "バ")}, + {0x30d1, 0, 0, 1, f(Yes, false, "パ")}, + {0x30d2, 0, 0, 0, f(Yes, true, "")}, + {0x30d3, 0, 0, 1, f(Yes, false, "ビ")}, + {0x30d4, 0, 0, 1, f(Yes, false, "ピ")}, + {0x30d5, 0, 0, 0, f(Yes, true, "")}, + {0x30d6, 0, 0, 1, f(Yes, false, "ブ")}, + {0x30d7, 0, 0, 1, f(Yes, false, "プ")}, + {0x30d8, 0, 0, 0, f(Yes, true, "")}, + {0x30d9, 0, 0, 1, f(Yes, false, "ベ")}, + {0x30da, 0, 0, 1, f(Yes, false, "ペ")}, + {0x30db, 0, 0, 0, f(Yes, true, "")}, + {0x30dc, 0, 0, 1, f(Yes, false, "ボ")}, + {0x30dd, 0, 0, 1, f(Yes, false, "ポ")}, + {0x30de, 0, 0, 0, f(Yes, false, "")}, + {0x30ef, 0, 0, 0, f(Yes, true, "")}, + {0x30f3, 0, 0, 0, f(Yes, false, "")}, + {0x30f4, 0, 0, 1, f(Yes, false, "ヴ")}, + {0x30f5, 0, 0, 0, f(Yes, false, "")}, + {0x30f7, 0, 0, 1, f(Yes, false, "ヷ")}, + {0x30f8, 0, 0, 1, f(Yes, false, "ヸ")}, + {0x30f9, 0, 0, 1, f(Yes, false, "ヹ")}, + {0x30fa, 0, 0, 1, f(Yes, false, "ヺ")}, + {0x30fb, 0, 0, 0, f(Yes, false, "")}, + {0x30fd, 0, 0, 0, f(Yes, true, "")}, + {0x30fe, 0, 0, 1, f(Yes, false, "ヾ")}, + {0x30ff, 0, 0, 0, g(Yes, No, false, false, "", "コト")}, + {0x3100, 0, 0, 0, f(Yes, false, "")}, + {0x3131, 0, 0, 0, g(Yes, No, false, false, "", "ᄀ")}, + {0x3132, 0, 0, 0, g(Yes, No, false, false, "", "ᄁ")}, + {0x3133, 0, 1, 1, g(Yes, No, false, false, "", "ᆪ")}, + {0x3134, 0, 0, 0, g(Yes, No, false, false, "", "ᄂ")}, + {0x3135, 0, 1, 1, g(Yes, No, false, false, "", "ᆬ")}, + {0x3136, 0, 1, 1, g(Yes, No, false, false, "", "ᆭ")}, + {0x3137, 0, 0, 0, g(Yes, No, false, false, "", "ᄃ")}, + {0x3138, 0, 0, 0, g(Yes, No, false, false, "", "ᄄ")}, + {0x3139, 0, 0, 0, g(Yes, No, false, false, "", "ᄅ")}, + {0x313a, 0, 1, 1, g(Yes, No, false, false, "", "ᆰ")}, + {0x313b, 0, 1, 1, g(Yes, No, false, false, "", "ᆱ")}, + {0x313c, 0, 1, 1, g(Yes, No, false, false, "", "ᆲ")}, + {0x313d, 0, 1, 1, g(Yes, No, false, false, "", "ᆳ")}, + {0x313e, 0, 1, 1, g(Yes, No, false, false, "", "ᆴ")}, + {0x313f, 0, 1, 1, g(Yes, No, false, false, "", "ᆵ")}, + {0x3140, 0, 0, 0, g(Yes, No, false, false, "", "ᄚ")}, + {0x3141, 0, 0, 0, g(Yes, No, false, false, "", "ᄆ")}, + {0x3142, 0, 0, 0, g(Yes, No, false, false, "", "ᄇ")}, + {0x3143, 0, 0, 0, g(Yes, No, false, false, "", "ᄈ")}, + {0x3144, 0, 0, 0, g(Yes, No, false, false, "", "ᄡ")}, + {0x3145, 0, 0, 0, g(Yes, No, false, false, "", "ᄉ")}, + {0x3146, 0, 0, 0, g(Yes, No, false, false, "", "ᄊ")}, + {0x3147, 0, 0, 0, g(Yes, No, false, false, "", "ᄋ")}, + {0x3148, 0, 0, 0, g(Yes, No, false, false, "", "ᄌ")}, + {0x3149, 0, 0, 0, g(Yes, No, false, false, "", "ᄍ")}, + {0x314a, 0, 0, 0, g(Yes, No, false, false, "", "ᄎ")}, + {0x314b, 0, 0, 0, g(Yes, No, false, false, "", "ᄏ")}, + {0x314c, 0, 0, 0, g(Yes, No, false, false, "", "ᄐ")}, + {0x314d, 0, 0, 0, g(Yes, No, false, false, "", "ᄑ")}, + {0x314e, 0, 0, 0, g(Yes, No, false, false, "", "ᄒ")}, + {0x314f, 0, 1, 1, g(Yes, No, false, false, "", "ᅡ")}, + {0x3150, 0, 1, 1, g(Yes, No, false, false, "", "ᅢ")}, + {0x3151, 0, 1, 1, g(Yes, No, false, false, "", "ᅣ")}, + {0x3152, 0, 1, 1, g(Yes, No, false, false, "", "ᅤ")}, + {0x3153, 0, 1, 1, g(Yes, No, false, false, "", "ᅥ")}, + {0x3154, 0, 1, 1, g(Yes, No, false, false, "", "ᅦ")}, + {0x3155, 0, 1, 1, g(Yes, No, false, false, "", "ᅧ")}, + {0x3156, 0, 1, 1, g(Yes, No, false, false, "", "ᅨ")}, + {0x3157, 0, 1, 1, g(Yes, No, false, false, "", "ᅩ")}, + {0x3158, 0, 1, 1, g(Yes, No, false, false, "", "ᅪ")}, + {0x3159, 0, 1, 1, g(Yes, No, false, false, "", "ᅫ")}, + {0x315a, 0, 1, 1, g(Yes, No, false, false, "", "ᅬ")}, + {0x315b, 0, 1, 1, g(Yes, No, false, false, "", "ᅭ")}, + {0x315c, 0, 1, 1, g(Yes, No, false, false, "", "ᅮ")}, + {0x315d, 0, 1, 1, g(Yes, No, false, false, "", "ᅯ")}, + {0x315e, 0, 1, 1, g(Yes, No, false, false, "", "ᅰ")}, + {0x315f, 0, 1, 1, g(Yes, No, false, false, "", "ᅱ")}, + {0x3160, 0, 1, 1, g(Yes, No, false, false, "", "ᅲ")}, + {0x3161, 0, 1, 1, g(Yes, No, false, false, "", "ᅳ")}, + {0x3162, 0, 1, 1, g(Yes, No, false, false, "", "ᅴ")}, + {0x3163, 0, 1, 1, g(Yes, No, false, false, "", "ᅵ")}, + {0x3164, 0, 0, 0, g(Yes, No, false, false, "", "ᅠ")}, + {0x3165, 0, 0, 0, g(Yes, No, false, false, "", "ᄔ")}, + {0x3166, 0, 0, 0, g(Yes, No, false, false, "", "ᄕ")}, + {0x3167, 0, 0, 0, g(Yes, No, false, false, "", "ᇇ")}, + {0x3168, 0, 0, 0, g(Yes, No, false, false, "", "ᇈ")}, + {0x3169, 0, 0, 0, g(Yes, No, false, false, "", "ᇌ")}, + {0x316a, 0, 0, 0, g(Yes, No, false, false, "", "ᇎ")}, + {0x316b, 0, 0, 0, g(Yes, No, false, false, "", "ᇓ")}, + {0x316c, 0, 0, 0, g(Yes, No, false, false, "", "ᇗ")}, + {0x316d, 0, 0, 0, g(Yes, No, false, false, "", "ᇙ")}, + {0x316e, 0, 0, 0, g(Yes, No, false, false, "", "ᄜ")}, + {0x316f, 0, 0, 0, g(Yes, No, false, false, "", "ᇝ")}, + {0x3170, 0, 0, 0, g(Yes, No, false, false, "", "ᇟ")}, + {0x3171, 0, 0, 0, g(Yes, No, false, false, "", "ᄝ")}, + {0x3172, 0, 0, 0, g(Yes, No, false, false, "", "ᄞ")}, + {0x3173, 0, 0, 0, g(Yes, No, false, false, "", "ᄠ")}, + {0x3174, 0, 0, 0, g(Yes, No, false, false, "", "ᄢ")}, + {0x3175, 0, 0, 0, g(Yes, No, false, false, "", "ᄣ")}, + {0x3176, 0, 0, 0, g(Yes, No, false, false, "", "ᄧ")}, + {0x3177, 0, 0, 0, g(Yes, No, false, false, "", "ᄩ")}, + {0x3178, 0, 0, 0, g(Yes, No, false, false, "", "ᄫ")}, + {0x3179, 0, 0, 0, g(Yes, No, false, false, "", "ᄬ")}, + {0x317a, 0, 0, 0, g(Yes, No, false, false, "", "ᄭ")}, + {0x317b, 0, 0, 0, g(Yes, No, false, false, "", "ᄮ")}, + {0x317c, 0, 0, 0, g(Yes, No, false, false, "", "ᄯ")}, + {0x317d, 0, 0, 0, g(Yes, No, false, false, "", "ᄲ")}, + {0x317e, 0, 0, 0, g(Yes, No, false, false, "", "ᄶ")}, + {0x317f, 0, 0, 0, g(Yes, No, false, false, "", "ᅀ")}, + {0x3180, 0, 0, 0, g(Yes, No, false, false, "", "ᅇ")}, + {0x3181, 0, 0, 0, g(Yes, No, false, false, "", "ᅌ")}, + {0x3182, 0, 0, 0, g(Yes, No, false, false, "", "ᇱ")}, + {0x3183, 0, 0, 0, g(Yes, No, false, false, "", "ᇲ")}, + {0x3184, 0, 0, 0, g(Yes, No, false, false, "", "ᅗ")}, + {0x3185, 0, 0, 0, g(Yes, No, false, false, "", "ᅘ")}, + {0x3186, 0, 0, 0, g(Yes, No, false, false, "", "ᅙ")}, + {0x3187, 0, 0, 0, g(Yes, No, false, false, "", "ᆄ")}, + {0x3188, 0, 0, 0, g(Yes, No, false, false, "", "ᆅ")}, + {0x3189, 0, 0, 0, g(Yes, No, false, false, "", "ᆈ")}, + {0x318a, 0, 0, 0, g(Yes, No, false, false, "", "ᆑ")}, + {0x318b, 0, 0, 0, g(Yes, No, false, false, "", "ᆒ")}, + {0x318c, 0, 0, 0, g(Yes, No, false, false, "", "ᆔ")}, + {0x318d, 0, 0, 0, g(Yes, No, false, false, "", "ᆞ")}, + {0x318e, 0, 0, 0, g(Yes, No, false, false, "", "ᆡ")}, + {0x318f, 0, 0, 0, f(Yes, false, "")}, + {0x3192, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x3193, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x3194, 0, 0, 0, g(Yes, No, false, false, "", "三")}, + {0x3195, 0, 0, 0, g(Yes, No, false, false, "", "四")}, + {0x3196, 0, 0, 0, g(Yes, No, false, false, "", "上")}, + {0x3197, 0, 0, 0, g(Yes, No, false, false, "", "中")}, + {0x3198, 0, 0, 0, g(Yes, No, false, false, "", "下")}, + {0x3199, 0, 0, 0, g(Yes, No, false, false, "", "甲")}, + {0x319a, 0, 0, 0, g(Yes, No, false, false, "", "乙")}, + {0x319b, 0, 0, 0, g(Yes, No, false, false, "", "丙")}, + {0x319c, 0, 0, 0, g(Yes, No, false, false, "", "丁")}, + {0x319d, 0, 0, 0, g(Yes, No, false, false, "", "天")}, + {0x319e, 0, 0, 0, g(Yes, No, false, false, "", "地")}, + {0x319f, 0, 0, 0, g(Yes, No, false, false, "", "人")}, + {0x31a0, 0, 0, 0, f(Yes, false, "")}, + {0x3200, 0, 0, 0, g(Yes, No, false, false, "", "(ᄀ)")}, + {0x3201, 0, 0, 0, g(Yes, No, false, false, "", "(ᄂ)")}, + {0x3202, 0, 0, 0, g(Yes, No, false, false, "", "(ᄃ)")}, + {0x3203, 0, 0, 0, g(Yes, No, false, false, "", "(ᄅ)")}, + {0x3204, 0, 0, 0, g(Yes, No, false, false, "", "(ᄆ)")}, + {0x3205, 0, 0, 0, g(Yes, No, false, false, "", "(ᄇ)")}, + {0x3206, 0, 0, 0, g(Yes, No, false, false, "", "(ᄉ)")}, + {0x3207, 0, 0, 0, g(Yes, No, false, false, "", "(ᄋ)")}, + {0x3208, 0, 0, 0, g(Yes, No, false, false, "", "(ᄌ)")}, + {0x3209, 0, 0, 0, g(Yes, No, false, false, "", "(ᄎ)")}, + {0x320a, 0, 0, 0, g(Yes, No, false, false, "", "(ᄏ)")}, + {0x320b, 0, 0, 0, g(Yes, No, false, false, "", "(ᄐ)")}, + {0x320c, 0, 0, 0, g(Yes, No, false, false, "", "(ᄑ)")}, + {0x320d, 0, 0, 0, g(Yes, No, false, false, "", "(ᄒ)")}, + {0x320e, 0, 0, 0, g(Yes, No, false, false, "", "(가)")}, + {0x320f, 0, 0, 0, g(Yes, No, false, false, "", "(나)")}, + {0x3210, 0, 0, 0, g(Yes, No, false, false, "", "(다)")}, + {0x3211, 0, 0, 0, g(Yes, No, false, false, "", "(라)")}, + {0x3212, 0, 0, 0, g(Yes, No, false, false, "", "(마)")}, + {0x3213, 0, 0, 0, g(Yes, No, false, false, "", "(바)")}, + {0x3214, 0, 0, 0, g(Yes, No, false, false, "", "(사)")}, + {0x3215, 0, 0, 0, g(Yes, No, false, false, "", "(아)")}, + {0x3216, 0, 0, 0, g(Yes, No, false, false, "", "(자)")}, + {0x3217, 0, 0, 0, g(Yes, No, false, false, "", "(차)")}, + {0x3218, 0, 0, 0, g(Yes, No, false, false, "", "(카)")}, + {0x3219, 0, 0, 0, g(Yes, No, false, false, "", "(타)")}, + {0x321a, 0, 0, 0, g(Yes, No, false, false, "", "(파)")}, + {0x321b, 0, 0, 0, g(Yes, No, false, false, "", "(하)")}, + {0x321c, 0, 0, 0, g(Yes, No, false, false, "", "(주)")}, + {0x321d, 0, 0, 0, g(Yes, No, false, false, "", "(오전)")}, + {0x321e, 0, 0, 0, g(Yes, No, false, false, "", "(오후)")}, + {0x321f, 0, 0, 0, f(Yes, false, "")}, + {0x3220, 0, 0, 0, g(Yes, No, false, false, "", "(一)")}, + {0x3221, 0, 0, 0, g(Yes, No, false, false, "", "(二)")}, + {0x3222, 0, 0, 0, g(Yes, No, false, false, "", "(三)")}, + {0x3223, 0, 0, 0, g(Yes, No, false, false, "", "(四)")}, + {0x3224, 0, 0, 0, g(Yes, No, false, false, "", "(五)")}, + {0x3225, 0, 0, 0, g(Yes, No, false, false, "", "(六)")}, + {0x3226, 0, 0, 0, g(Yes, No, false, false, "", "(七)")}, + {0x3227, 0, 0, 0, g(Yes, No, false, false, "", "(八)")}, + {0x3228, 0, 0, 0, g(Yes, No, false, false, "", "(九)")}, + {0x3229, 0, 0, 0, g(Yes, No, false, false, "", "(十)")}, + {0x322a, 0, 0, 0, g(Yes, No, false, false, "", "(月)")}, + {0x322b, 0, 0, 0, g(Yes, No, false, false, "", "(火)")}, + {0x322c, 0, 0, 0, g(Yes, No, false, false, "", "(水)")}, + {0x322d, 0, 0, 0, g(Yes, No, false, false, "", "(木)")}, + {0x322e, 0, 0, 0, g(Yes, No, false, false, "", "(金)")}, + {0x322f, 0, 0, 0, g(Yes, No, false, false, "", "(土)")}, + {0x3230, 0, 0, 0, g(Yes, No, false, false, "", "(日)")}, + {0x3231, 0, 0, 0, g(Yes, No, false, false, "", "(株)")}, + {0x3232, 0, 0, 0, g(Yes, No, false, false, "", "(有)")}, + {0x3233, 0, 0, 0, g(Yes, No, false, false, "", "(社)")}, + {0x3234, 0, 0, 0, g(Yes, No, false, false, "", "(名)")}, + {0x3235, 0, 0, 0, g(Yes, No, false, false, "", "(特)")}, + {0x3236, 0, 0, 0, g(Yes, No, false, false, "", "(財)")}, + {0x3237, 0, 0, 0, g(Yes, No, false, false, "", "(祝)")}, + {0x3238, 0, 0, 0, g(Yes, No, false, false, "", "(労)")}, + {0x3239, 0, 0, 0, g(Yes, No, false, false, "", "(代)")}, + {0x323a, 0, 0, 0, g(Yes, No, false, false, "", "(呼)")}, + {0x323b, 0, 0, 0, g(Yes, No, false, false, "", "(学)")}, + {0x323c, 0, 0, 0, g(Yes, No, false, false, "", "(監)")}, + {0x323d, 0, 0, 0, g(Yes, No, false, false, "", "(企)")}, + {0x323e, 0, 0, 0, g(Yes, No, false, false, "", "(資)")}, + {0x323f, 0, 0, 0, g(Yes, No, false, false, "", "(協)")}, + {0x3240, 0, 0, 0, g(Yes, No, false, false, "", "(祭)")}, + {0x3241, 0, 0, 0, g(Yes, No, false, false, "", "(休)")}, + {0x3242, 0, 0, 0, g(Yes, No, false, false, "", "(自)")}, + {0x3243, 0, 0, 0, g(Yes, No, false, false, "", "(至)")}, + {0x3244, 0, 0, 0, g(Yes, No, false, false, "", "問")}, + {0x3245, 0, 0, 0, g(Yes, No, false, false, "", "幼")}, + {0x3246, 0, 0, 0, g(Yes, No, false, false, "", "文")}, + {0x3247, 0, 0, 0, g(Yes, No, false, false, "", "箏")}, + {0x3248, 0, 0, 0, f(Yes, false, "")}, + {0x3250, 0, 0, 0, g(Yes, No, false, false, "", "PTE")}, + {0x3251, 0, 0, 0, g(Yes, No, false, false, "", "21")}, + {0x3252, 0, 0, 0, g(Yes, No, false, false, "", "22")}, + {0x3253, 0, 0, 0, g(Yes, No, false, false, "", "23")}, + {0x3254, 0, 0, 0, g(Yes, No, false, false, "", "24")}, + {0x3255, 0, 0, 0, g(Yes, No, false, false, "", "25")}, + {0x3256, 0, 0, 0, g(Yes, No, false, false, "", "26")}, + {0x3257, 0, 0, 0, g(Yes, No, false, false, "", "27")}, + {0x3258, 0, 0, 0, g(Yes, No, false, false, "", "28")}, + {0x3259, 0, 0, 0, g(Yes, No, false, false, "", "29")}, + {0x325a, 0, 0, 0, g(Yes, No, false, false, "", "30")}, + {0x325b, 0, 0, 0, g(Yes, No, false, false, "", "31")}, + {0x325c, 0, 0, 0, g(Yes, No, false, false, "", "32")}, + {0x325d, 0, 0, 0, g(Yes, No, false, false, "", "33")}, + {0x325e, 0, 0, 0, g(Yes, No, false, false, "", "34")}, + {0x325f, 0, 0, 0, g(Yes, No, false, false, "", "35")}, + {0x3260, 0, 0, 0, g(Yes, No, false, false, "", "ᄀ")}, + {0x3261, 0, 0, 0, g(Yes, No, false, false, "", "ᄂ")}, + {0x3262, 0, 0, 0, g(Yes, No, false, false, "", "ᄃ")}, + {0x3263, 0, 0, 0, g(Yes, No, false, false, "", "ᄅ")}, + {0x3264, 0, 0, 0, g(Yes, No, false, false, "", "ᄆ")}, + {0x3265, 0, 0, 0, g(Yes, No, false, false, "", "ᄇ")}, + {0x3266, 0, 0, 0, g(Yes, No, false, false, "", "ᄉ")}, + {0x3267, 0, 0, 0, g(Yes, No, false, false, "", "ᄋ")}, + {0x3268, 0, 0, 0, g(Yes, No, false, false, "", "ᄌ")}, + {0x3269, 0, 0, 0, g(Yes, No, false, false, "", "ᄎ")}, + {0x326a, 0, 0, 0, g(Yes, No, false, false, "", "ᄏ")}, + {0x326b, 0, 0, 0, g(Yes, No, false, false, "", "ᄐ")}, + {0x326c, 0, 0, 0, g(Yes, No, false, false, "", "ᄑ")}, + {0x326d, 0, 0, 0, g(Yes, No, false, false, "", "ᄒ")}, + {0x326e, 0, 0, 1, g(Yes, No, false, false, "", "가")}, + {0x326f, 0, 0, 1, g(Yes, No, false, false, "", "나")}, + {0x3270, 0, 0, 1, g(Yes, No, false, false, "", "다")}, + {0x3271, 0, 0, 1, g(Yes, No, false, false, "", "라")}, + {0x3272, 0, 0, 1, g(Yes, No, false, false, "", "마")}, + {0x3273, 0, 0, 1, g(Yes, No, false, false, "", "바")}, + {0x3274, 0, 0, 1, g(Yes, No, false, false, "", "사")}, + {0x3275, 0, 0, 1, g(Yes, No, false, false, "", "아")}, + {0x3276, 0, 0, 1, g(Yes, No, false, false, "", "자")}, + {0x3277, 0, 0, 1, g(Yes, No, false, false, "", "차")}, + {0x3278, 0, 0, 1, g(Yes, No, false, false, "", "카")}, + {0x3279, 0, 0, 1, g(Yes, No, false, false, "", "타")}, + {0x327a, 0, 0, 1, g(Yes, No, false, false, "", "파")}, + {0x327b, 0, 0, 1, g(Yes, No, false, false, "", "하")}, + {0x327c, 0, 0, 1, g(Yes, No, false, false, "", "참고")}, + {0x327d, 0, 0, 1, g(Yes, No, false, false, "", "주의")}, + {0x327e, 0, 0, 1, g(Yes, No, false, false, "", "우")}, + {0x327f, 0, 0, 0, f(Yes, false, "")}, + {0x3280, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x3281, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x3282, 0, 0, 0, g(Yes, No, false, false, "", "三")}, + {0x3283, 0, 0, 0, g(Yes, No, false, false, "", "四")}, + {0x3284, 0, 0, 0, g(Yes, No, false, false, "", "五")}, + {0x3285, 0, 0, 0, g(Yes, No, false, false, "", "六")}, + {0x3286, 0, 0, 0, g(Yes, No, false, false, "", "七")}, + {0x3287, 0, 0, 0, g(Yes, No, false, false, "", "八")}, + {0x3288, 0, 0, 0, g(Yes, No, false, false, "", "九")}, + {0x3289, 0, 0, 0, g(Yes, No, false, false, "", "十")}, + {0x328a, 0, 0, 0, g(Yes, No, false, false, "", "月")}, + {0x328b, 0, 0, 0, g(Yes, No, false, false, "", "火")}, + {0x328c, 0, 0, 0, g(Yes, No, false, false, "", "水")}, + {0x328d, 0, 0, 0, g(Yes, No, false, false, "", "木")}, + {0x328e, 0, 0, 0, g(Yes, No, false, false, "", "金")}, + {0x328f, 0, 0, 0, g(Yes, No, false, false, "", "土")}, + {0x3290, 0, 0, 0, g(Yes, No, false, false, "", "日")}, + {0x3291, 0, 0, 0, g(Yes, No, false, false, "", "株")}, + {0x3292, 0, 0, 0, g(Yes, No, false, false, "", "有")}, + {0x3293, 0, 0, 0, g(Yes, No, false, false, "", "社")}, + {0x3294, 0, 0, 0, g(Yes, No, false, false, "", "名")}, + {0x3295, 0, 0, 0, g(Yes, No, false, false, "", "特")}, + {0x3296, 0, 0, 0, g(Yes, No, false, false, "", "財")}, + {0x3297, 0, 0, 0, g(Yes, No, false, false, "", "祝")}, + {0x3298, 0, 0, 0, g(Yes, No, false, false, "", "労")}, + {0x3299, 0, 0, 0, g(Yes, No, false, false, "", "秘")}, + {0x329a, 0, 0, 0, g(Yes, No, false, false, "", "男")}, + {0x329b, 0, 0, 0, g(Yes, No, false, false, "", "女")}, + {0x329c, 0, 0, 0, g(Yes, No, false, false, "", "適")}, + {0x329d, 0, 0, 0, g(Yes, No, false, false, "", "優")}, + {0x329e, 0, 0, 0, g(Yes, No, false, false, "", "印")}, + {0x329f, 0, 0, 0, g(Yes, No, false, false, "", "注")}, + {0x32a0, 0, 0, 0, g(Yes, No, false, false, "", "項")}, + {0x32a1, 0, 0, 0, g(Yes, No, false, false, "", "休")}, + {0x32a2, 0, 0, 0, g(Yes, No, false, false, "", "写")}, + {0x32a3, 0, 0, 0, g(Yes, No, false, false, "", "正")}, + {0x32a4, 0, 0, 0, g(Yes, No, false, false, "", "上")}, + {0x32a5, 0, 0, 0, g(Yes, No, false, false, "", "中")}, + {0x32a6, 0, 0, 0, g(Yes, No, false, false, "", "下")}, + {0x32a7, 0, 0, 0, g(Yes, No, false, false, "", "左")}, + {0x32a8, 0, 0, 0, g(Yes, No, false, false, "", "右")}, + {0x32a9, 0, 0, 0, g(Yes, No, false, false, "", "医")}, + {0x32aa, 0, 0, 0, g(Yes, No, false, false, "", "宗")}, + {0x32ab, 0, 0, 0, g(Yes, No, false, false, "", "学")}, + {0x32ac, 0, 0, 0, g(Yes, No, false, false, "", "監")}, + {0x32ad, 0, 0, 0, g(Yes, No, false, false, "", "企")}, + {0x32ae, 0, 0, 0, g(Yes, No, false, false, "", "資")}, + {0x32af, 0, 0, 0, g(Yes, No, false, false, "", "協")}, + {0x32b0, 0, 0, 0, g(Yes, No, false, false, "", "夜")}, + {0x32b1, 0, 0, 0, g(Yes, No, false, false, "", "36")}, + {0x32b2, 0, 0, 0, g(Yes, No, false, false, "", "37")}, + {0x32b3, 0, 0, 0, g(Yes, No, false, false, "", "38")}, + {0x32b4, 0, 0, 0, g(Yes, No, false, false, "", "39")}, + {0x32b5, 0, 0, 0, g(Yes, No, false, false, "", "40")}, + {0x32b6, 0, 0, 0, g(Yes, No, false, false, "", "41")}, + {0x32b7, 0, 0, 0, g(Yes, No, false, false, "", "42")}, + {0x32b8, 0, 0, 0, g(Yes, No, false, false, "", "43")}, + {0x32b9, 0, 0, 0, g(Yes, No, false, false, "", "44")}, + {0x32ba, 0, 0, 0, g(Yes, No, false, false, "", "45")}, + {0x32bb, 0, 0, 0, g(Yes, No, false, false, "", "46")}, + {0x32bc, 0, 0, 0, g(Yes, No, false, false, "", "47")}, + {0x32bd, 0, 0, 0, g(Yes, No, false, false, "", "48")}, + {0x32be, 0, 0, 0, g(Yes, No, false, false, "", "49")}, + {0x32bf, 0, 0, 0, g(Yes, No, false, false, "", "50")}, + {0x32c0, 0, 0, 0, g(Yes, No, false, false, "", "1月")}, + {0x32c1, 0, 0, 0, g(Yes, No, false, false, "", "2月")}, + {0x32c2, 0, 0, 0, g(Yes, No, false, false, "", "3月")}, + {0x32c3, 0, 0, 0, g(Yes, No, false, false, "", "4月")}, + {0x32c4, 0, 0, 0, g(Yes, No, false, false, "", "5月")}, + {0x32c5, 0, 0, 0, g(Yes, No, false, false, "", "6月")}, + {0x32c6, 0, 0, 0, g(Yes, No, false, false, "", "7月")}, + {0x32c7, 0, 0, 0, g(Yes, No, false, false, "", "8月")}, + {0x32c8, 0, 0, 0, g(Yes, No, false, false, "", "9月")}, + {0x32c9, 0, 0, 0, g(Yes, No, false, false, "", "10月")}, + {0x32ca, 0, 0, 0, g(Yes, No, false, false, "", "11月")}, + {0x32cb, 0, 0, 0, g(Yes, No, false, false, "", "12月")}, + {0x32cc, 0, 0, 0, g(Yes, No, false, false, "", "Hg")}, + {0x32cd, 0, 0, 0, g(Yes, No, false, false, "", "erg")}, + {0x32ce, 0, 0, 0, g(Yes, No, false, false, "", "eV")}, + {0x32cf, 0, 0, 0, g(Yes, No, false, false, "", "LTD")}, + {0x32d0, 0, 0, 0, g(Yes, No, false, false, "", "ア")}, + {0x32d1, 0, 0, 0, g(Yes, No, false, false, "", "イ")}, + {0x32d2, 0, 0, 0, g(Yes, No, false, false, "", "ウ")}, + {0x32d3, 0, 0, 0, g(Yes, No, false, false, "", "エ")}, + {0x32d4, 0, 0, 0, g(Yes, No, false, false, "", "オ")}, + {0x32d5, 0, 0, 0, g(Yes, No, false, false, "", "カ")}, + {0x32d6, 0, 0, 0, g(Yes, No, false, false, "", "キ")}, + {0x32d7, 0, 0, 0, g(Yes, No, false, false, "", "ク")}, + {0x32d8, 0, 0, 0, g(Yes, No, false, false, "", "ケ")}, + {0x32d9, 0, 0, 0, g(Yes, No, false, false, "", "コ")}, + {0x32da, 0, 0, 0, g(Yes, No, false, false, "", "サ")}, + {0x32db, 0, 0, 0, g(Yes, No, false, false, "", "シ")}, + {0x32dc, 0, 0, 0, g(Yes, No, false, false, "", "ス")}, + {0x32dd, 0, 0, 0, g(Yes, No, false, false, "", "セ")}, + {0x32de, 0, 0, 0, g(Yes, No, false, false, "", "ソ")}, + {0x32df, 0, 0, 0, g(Yes, No, false, false, "", "タ")}, + {0x32e0, 0, 0, 0, g(Yes, No, false, false, "", "チ")}, + {0x32e1, 0, 0, 0, g(Yes, No, false, false, "", "ツ")}, + {0x32e2, 0, 0, 0, g(Yes, No, false, false, "", "テ")}, + {0x32e3, 0, 0, 0, g(Yes, No, false, false, "", "ト")}, + {0x32e4, 0, 0, 0, g(Yes, No, false, false, "", "ナ")}, + {0x32e5, 0, 0, 0, g(Yes, No, false, false, "", "ニ")}, + {0x32e6, 0, 0, 0, g(Yes, No, false, false, "", "ヌ")}, + {0x32e7, 0, 0, 0, g(Yes, No, false, false, "", "ネ")}, + {0x32e8, 0, 0, 0, g(Yes, No, false, false, "", "ノ")}, + {0x32e9, 0, 0, 0, g(Yes, No, false, false, "", "ハ")}, + {0x32ea, 0, 0, 0, g(Yes, No, false, false, "", "ヒ")}, + {0x32eb, 0, 0, 0, g(Yes, No, false, false, "", "フ")}, + {0x32ec, 0, 0, 0, g(Yes, No, false, false, "", "ヘ")}, + {0x32ed, 0, 0, 0, g(Yes, No, false, false, "", "ホ")}, + {0x32ee, 0, 0, 0, g(Yes, No, false, false, "", "マ")}, + {0x32ef, 0, 0, 0, g(Yes, No, false, false, "", "ミ")}, + {0x32f0, 0, 0, 0, g(Yes, No, false, false, "", "ム")}, + {0x32f1, 0, 0, 0, g(Yes, No, false, false, "", "メ")}, + {0x32f2, 0, 0, 0, g(Yes, No, false, false, "", "モ")}, + {0x32f3, 0, 0, 0, g(Yes, No, false, false, "", "ヤ")}, + {0x32f4, 0, 0, 0, g(Yes, No, false, false, "", "ユ")}, + {0x32f5, 0, 0, 0, g(Yes, No, false, false, "", "ヨ")}, + {0x32f6, 0, 0, 0, g(Yes, No, false, false, "", "ラ")}, + {0x32f7, 0, 0, 0, g(Yes, No, false, false, "", "リ")}, + {0x32f8, 0, 0, 0, g(Yes, No, false, false, "", "ル")}, + {0x32f9, 0, 0, 0, g(Yes, No, false, false, "", "レ")}, + {0x32fa, 0, 0, 0, g(Yes, No, false, false, "", "ロ")}, + {0x32fb, 0, 0, 0, g(Yes, No, false, false, "", "ワ")}, + {0x32fc, 0, 0, 0, g(Yes, No, false, false, "", "ヰ")}, + {0x32fd, 0, 0, 0, g(Yes, No, false, false, "", "ヱ")}, + {0x32fe, 0, 0, 0, g(Yes, No, false, false, "", "ヲ")}, + {0x32ff, 0, 0, 0, f(Yes, false, "")}, + {0x3300, 0, 0, 0, g(Yes, No, false, false, "", "アパート")}, + {0x3301, 0, 0, 0, g(Yes, No, false, false, "", "アルファ")}, + {0x3302, 0, 0, 0, g(Yes, No, false, false, "", "アンペア")}, + {0x3303, 0, 0, 0, g(Yes, No, false, false, "", "アール")}, + {0x3304, 0, 0, 1, g(Yes, No, false, false, "", "イニング")}, + {0x3305, 0, 0, 0, g(Yes, No, false, false, "", "インチ")}, + {0x3306, 0, 0, 0, g(Yes, No, false, false, "", "ウォン")}, + {0x3307, 0, 0, 1, g(Yes, No, false, false, "", "エスクード")}, + {0x3308, 0, 0, 0, g(Yes, No, false, false, "", "エーカー")}, + {0x3309, 0, 0, 0, g(Yes, No, false, false, "", "オンス")}, + {0x330a, 0, 0, 0, g(Yes, No, false, false, "", "オーム")}, + {0x330b, 0, 0, 0, g(Yes, No, false, false, "", "カイリ")}, + {0x330c, 0, 0, 0, g(Yes, No, false, false, "", "カラット")}, + {0x330d, 0, 0, 0, g(Yes, No, false, false, "", "カロリー")}, + {0x330e, 0, 0, 0, g(Yes, No, false, false, "", "ガロン")}, + {0x330f, 0, 0, 0, g(Yes, No, false, false, "", "ガンマ")}, + {0x3310, 0, 0, 1, g(Yes, No, false, false, "", "ギガ")}, + {0x3311, 0, 0, 0, g(Yes, No, false, false, "", "ギニー")}, + {0x3312, 0, 0, 0, g(Yes, No, false, false, "", "キュリー")}, + {0x3313, 0, 0, 0, g(Yes, No, false, false, "", "ギルダー")}, + {0x3314, 0, 0, 0, g(Yes, No, false, false, "", "キロ")}, + {0x3315, 0, 0, 0, g(Yes, No, false, false, "", "キログラム")}, + {0x3316, 0, 0, 0, g(Yes, No, false, false, "", "キロメートル")}, + {0x3317, 0, 0, 0, g(Yes, No, false, false, "", "キロワット")}, + {0x3318, 0, 0, 0, g(Yes, No, false, false, "", "グラム")}, + {0x3319, 0, 0, 0, g(Yes, No, false, false, "", "グラムトン")}, + {0x331a, 0, 0, 0, g(Yes, No, false, false, "", "クルゼイロ")}, + {0x331b, 0, 0, 0, g(Yes, No, false, false, "", "クローネ")}, + {0x331c, 0, 0, 0, g(Yes, No, false, false, "", "ケース")}, + {0x331d, 0, 0, 0, g(Yes, No, false, false, "", "コルナ")}, + {0x331e, 0, 0, 1, g(Yes, No, false, false, "", "コーポ")}, + {0x331f, 0, 0, 0, g(Yes, No, false, false, "", "サイクル")}, + {0x3320, 0, 0, 0, g(Yes, No, false, false, "", "サンチーム")}, + {0x3321, 0, 0, 1, g(Yes, No, false, false, "", "シリング")}, + {0x3322, 0, 0, 0, g(Yes, No, false, false, "", "センチ")}, + {0x3323, 0, 0, 0, g(Yes, No, false, false, "", "セント")}, + {0x3324, 0, 0, 0, g(Yes, No, false, false, "", "ダース")}, + {0x3325, 0, 0, 0, g(Yes, No, false, false, "", "デシ")}, + {0x3326, 0, 0, 0, g(Yes, No, false, false, "", "ドル")}, + {0x3327, 0, 0, 0, g(Yes, No, false, false, "", "トン")}, + {0x3328, 0, 0, 0, g(Yes, No, false, false, "", "ナノ")}, + {0x3329, 0, 0, 0, g(Yes, No, false, false, "", "ノット")}, + {0x332a, 0, 0, 0, g(Yes, No, false, false, "", "ハイツ")}, + {0x332b, 0, 0, 0, g(Yes, No, false, false, "", "パーセント")}, + {0x332c, 0, 0, 0, g(Yes, No, false, false, "", "パーツ")}, + {0x332d, 0, 0, 0, g(Yes, No, false, false, "", "バーレル")}, + {0x332e, 0, 0, 0, g(Yes, No, false, false, "", "ピアストル")}, + {0x332f, 0, 0, 0, g(Yes, No, false, false, "", "ピクル")}, + {0x3330, 0, 0, 0, g(Yes, No, false, false, "", "ピコ")}, + {0x3331, 0, 0, 0, g(Yes, No, false, false, "", "ビル")}, + {0x3332, 0, 0, 1, g(Yes, No, false, false, "", "ファラッド")}, + {0x3333, 0, 0, 0, g(Yes, No, false, false, "", "フィート")}, + {0x3334, 0, 0, 0, g(Yes, No, false, false, "", "ブッシェル")}, + {0x3335, 0, 0, 0, g(Yes, No, false, false, "", "フラン")}, + {0x3336, 0, 0, 0, g(Yes, No, false, false, "", "ヘクタール")}, + {0x3337, 0, 0, 0, g(Yes, No, false, false, "", "ペソ")}, + {0x3338, 0, 0, 0, g(Yes, No, false, false, "", "ペニヒ")}, + {0x3339, 0, 0, 0, g(Yes, No, false, false, "", "ヘルツ")}, + {0x333a, 0, 0, 0, g(Yes, No, false, false, "", "ペンス")}, + {0x333b, 0, 0, 1, g(Yes, No, false, false, "", "ページ")}, + {0x333c, 0, 0, 0, g(Yes, No, false, false, "", "ベータ")}, + {0x333d, 0, 0, 0, g(Yes, No, false, false, "", "ポイント")}, + {0x333e, 0, 0, 0, g(Yes, No, false, false, "", "ボルト")}, + {0x333f, 0, 0, 0, g(Yes, No, false, false, "", "ホン")}, + {0x3340, 0, 0, 1, g(Yes, No, false, false, "", "ポンド")}, + {0x3341, 0, 0, 0, g(Yes, No, false, false, "", "ホール")}, + {0x3342, 0, 0, 0, g(Yes, No, false, false, "", "ホーン")}, + {0x3343, 0, 0, 0, g(Yes, No, false, false, "", "マイクロ")}, + {0x3344, 0, 0, 0, g(Yes, No, false, false, "", "マイル")}, + {0x3345, 0, 0, 0, g(Yes, No, false, false, "", "マッハ")}, + {0x3346, 0, 0, 0, g(Yes, No, false, false, "", "マルク")}, + {0x3347, 0, 0, 0, g(Yes, No, false, false, "", "マンション")}, + {0x3348, 0, 0, 0, g(Yes, No, false, false, "", "ミクロン")}, + {0x3349, 0, 0, 0, g(Yes, No, false, false, "", "ミリ")}, + {0x334a, 0, 0, 0, g(Yes, No, false, false, "", "ミリバール")}, + {0x334b, 0, 0, 1, g(Yes, No, false, false, "", "メガ")}, + {0x334c, 0, 0, 0, g(Yes, No, false, false, "", "メガトン")}, + {0x334d, 0, 0, 0, g(Yes, No, false, false, "", "メートル")}, + {0x334e, 0, 0, 1, g(Yes, No, false, false, "", "ヤード")}, + {0x334f, 0, 0, 0, g(Yes, No, false, false, "", "ヤール")}, + {0x3350, 0, 0, 0, g(Yes, No, false, false, "", "ユアン")}, + {0x3351, 0, 0, 0, g(Yes, No, false, false, "", "リットル")}, + {0x3352, 0, 0, 0, g(Yes, No, false, false, "", "リラ")}, + {0x3353, 0, 0, 0, g(Yes, No, false, false, "", "ルピー")}, + {0x3354, 0, 0, 0, g(Yes, No, false, false, "", "ルーブル")}, + {0x3355, 0, 0, 0, g(Yes, No, false, false, "", "レム")}, + {0x3356, 0, 0, 0, g(Yes, No, false, false, "", "レントゲン")}, + {0x3357, 0, 0, 0, g(Yes, No, false, false, "", "ワット")}, + {0x3358, 0, 0, 0, g(Yes, No, false, false, "", "0点")}, + {0x3359, 0, 0, 0, g(Yes, No, false, false, "", "1点")}, + {0x335a, 0, 0, 0, g(Yes, No, false, false, "", "2点")}, + {0x335b, 0, 0, 0, g(Yes, No, false, false, "", "3点")}, + {0x335c, 0, 0, 0, g(Yes, No, false, false, "", "4点")}, + {0x335d, 0, 0, 0, g(Yes, No, false, false, "", "5点")}, + {0x335e, 0, 0, 0, g(Yes, No, false, false, "", "6点")}, + {0x335f, 0, 0, 0, g(Yes, No, false, false, "", "7点")}, + {0x3360, 0, 0, 0, g(Yes, No, false, false, "", "8点")}, + {0x3361, 0, 0, 0, g(Yes, No, false, false, "", "9点")}, + {0x3362, 0, 0, 0, g(Yes, No, false, false, "", "10点")}, + {0x3363, 0, 0, 0, g(Yes, No, false, false, "", "11点")}, + {0x3364, 0, 0, 0, g(Yes, No, false, false, "", "12点")}, + {0x3365, 0, 0, 0, g(Yes, No, false, false, "", "13点")}, + {0x3366, 0, 0, 0, g(Yes, No, false, false, "", "14点")}, + {0x3367, 0, 0, 0, g(Yes, No, false, false, "", "15点")}, + {0x3368, 0, 0, 0, g(Yes, No, false, false, "", "16点")}, + {0x3369, 0, 0, 0, g(Yes, No, false, false, "", "17点")}, + {0x336a, 0, 0, 0, g(Yes, No, false, false, "", "18点")}, + {0x336b, 0, 0, 0, g(Yes, No, false, false, "", "19点")}, + {0x336c, 0, 0, 0, g(Yes, No, false, false, "", "20点")}, + {0x336d, 0, 0, 0, g(Yes, No, false, false, "", "21点")}, + {0x336e, 0, 0, 0, g(Yes, No, false, false, "", "22点")}, + {0x336f, 0, 0, 0, g(Yes, No, false, false, "", "23点")}, + {0x3370, 0, 0, 0, g(Yes, No, false, false, "", "24点")}, + {0x3371, 0, 0, 0, g(Yes, No, false, false, "", "hPa")}, + {0x3372, 0, 0, 0, g(Yes, No, false, false, "", "da")}, + {0x3373, 0, 0, 0, g(Yes, No, false, false, "", "AU")}, + {0x3374, 0, 0, 0, g(Yes, No, false, false, "", "bar")}, + {0x3375, 0, 0, 0, g(Yes, No, false, false, "", "oV")}, + {0x3376, 0, 0, 0, g(Yes, No, false, false, "", "pc")}, + {0x3377, 0, 0, 0, g(Yes, No, false, false, "", "dm")}, + {0x3378, 0, 0, 0, g(Yes, No, false, false, "", "dm2")}, + {0x3379, 0, 0, 0, g(Yes, No, false, false, "", "dm3")}, + {0x337a, 0, 0, 0, g(Yes, No, false, false, "", "IU")}, + {0x337b, 0, 0, 0, g(Yes, No, false, false, "", "平成")}, + {0x337c, 0, 0, 0, g(Yes, No, false, false, "", "昭和")}, + {0x337d, 0, 0, 0, g(Yes, No, false, false, "", "大正")}, + {0x337e, 0, 0, 0, g(Yes, No, false, false, "", "明治")}, + {0x337f, 0, 0, 0, g(Yes, No, false, false, "", "株式会社")}, + {0x3380, 0, 0, 0, g(Yes, No, false, false, "", "pA")}, + {0x3381, 0, 0, 0, g(Yes, No, false, false, "", "nA")}, + {0x3382, 0, 0, 0, g(Yes, No, false, false, "", "μA")}, + {0x3383, 0, 0, 0, g(Yes, No, false, false, "", "mA")}, + {0x3384, 0, 0, 0, g(Yes, No, false, false, "", "kA")}, + {0x3385, 0, 0, 0, g(Yes, No, false, false, "", "KB")}, + {0x3386, 0, 0, 0, g(Yes, No, false, false, "", "MB")}, + {0x3387, 0, 0, 0, g(Yes, No, false, false, "", "GB")}, + {0x3388, 0, 0, 0, g(Yes, No, false, false, "", "cal")}, + {0x3389, 0, 0, 0, g(Yes, No, false, false, "", "kcal")}, + {0x338a, 0, 0, 0, g(Yes, No, false, false, "", "pF")}, + {0x338b, 0, 0, 0, g(Yes, No, false, false, "", "nF")}, + {0x338c, 0, 0, 0, g(Yes, No, false, false, "", "μF")}, + {0x338d, 0, 0, 0, g(Yes, No, false, false, "", "μg")}, + {0x338e, 0, 0, 0, g(Yes, No, false, false, "", "mg")}, + {0x338f, 0, 0, 0, g(Yes, No, false, false, "", "kg")}, + {0x3390, 0, 0, 0, g(Yes, No, false, false, "", "Hz")}, + {0x3391, 0, 0, 0, g(Yes, No, false, false, "", "kHz")}, + {0x3392, 0, 0, 0, g(Yes, No, false, false, "", "MHz")}, + {0x3393, 0, 0, 0, g(Yes, No, false, false, "", "GHz")}, + {0x3394, 0, 0, 0, g(Yes, No, false, false, "", "THz")}, + {0x3395, 0, 0, 0, g(Yes, No, false, false, "", "μl")}, + {0x3396, 0, 0, 0, g(Yes, No, false, false, "", "ml")}, + {0x3397, 0, 0, 0, g(Yes, No, false, false, "", "dl")}, + {0x3398, 0, 0, 0, g(Yes, No, false, false, "", "kl")}, + {0x3399, 0, 0, 0, g(Yes, No, false, false, "", "fm")}, + {0x339a, 0, 0, 0, g(Yes, No, false, false, "", "nm")}, + {0x339b, 0, 0, 0, g(Yes, No, false, false, "", "μm")}, + {0x339c, 0, 0, 0, g(Yes, No, false, false, "", "mm")}, + {0x339d, 0, 0, 0, g(Yes, No, false, false, "", "cm")}, + {0x339e, 0, 0, 0, g(Yes, No, false, false, "", "km")}, + {0x339f, 0, 0, 0, g(Yes, No, false, false, "", "mm2")}, + {0x33a0, 0, 0, 0, g(Yes, No, false, false, "", "cm2")}, + {0x33a1, 0, 0, 0, g(Yes, No, false, false, "", "m2")}, + {0x33a2, 0, 0, 0, g(Yes, No, false, false, "", "km2")}, + {0x33a3, 0, 0, 0, g(Yes, No, false, false, "", "mm3")}, + {0x33a4, 0, 0, 0, g(Yes, No, false, false, "", "cm3")}, + {0x33a5, 0, 0, 0, g(Yes, No, false, false, "", "m3")}, + {0x33a6, 0, 0, 0, g(Yes, No, false, false, "", "km3")}, + {0x33a7, 0, 0, 0, g(Yes, No, false, false, "", "m∕s")}, + {0x33a8, 0, 0, 0, g(Yes, No, false, false, "", "m∕s2")}, + {0x33a9, 0, 0, 0, g(Yes, No, false, false, "", "Pa")}, + {0x33aa, 0, 0, 0, g(Yes, No, false, false, "", "kPa")}, + {0x33ab, 0, 0, 0, g(Yes, No, false, false, "", "MPa")}, + {0x33ac, 0, 0, 0, g(Yes, No, false, false, "", "GPa")}, + {0x33ad, 0, 0, 0, g(Yes, No, false, false, "", "rad")}, + {0x33ae, 0, 0, 0, g(Yes, No, false, false, "", "rad∕s")}, + {0x33af, 0, 0, 0, g(Yes, No, false, false, "", "rad∕s2")}, + {0x33b0, 0, 0, 0, g(Yes, No, false, false, "", "ps")}, + {0x33b1, 0, 0, 0, g(Yes, No, false, false, "", "ns")}, + {0x33b2, 0, 0, 0, g(Yes, No, false, false, "", "μs")}, + {0x33b3, 0, 0, 0, g(Yes, No, false, false, "", "ms")}, + {0x33b4, 0, 0, 0, g(Yes, No, false, false, "", "pV")}, + {0x33b5, 0, 0, 0, g(Yes, No, false, false, "", "nV")}, + {0x33b6, 0, 0, 0, g(Yes, No, false, false, "", "μV")}, + {0x33b7, 0, 0, 0, g(Yes, No, false, false, "", "mV")}, + {0x33b8, 0, 0, 0, g(Yes, No, false, false, "", "kV")}, + {0x33b9, 0, 0, 0, g(Yes, No, false, false, "", "MV")}, + {0x33ba, 0, 0, 0, g(Yes, No, false, false, "", "pW")}, + {0x33bb, 0, 0, 0, g(Yes, No, false, false, "", "nW")}, + {0x33bc, 0, 0, 0, g(Yes, No, false, false, "", "μW")}, + {0x33bd, 0, 0, 0, g(Yes, No, false, false, "", "mW")}, + {0x33be, 0, 0, 0, g(Yes, No, false, false, "", "kW")}, + {0x33bf, 0, 0, 0, g(Yes, No, false, false, "", "MW")}, + {0x33c0, 0, 0, 0, g(Yes, No, false, false, "", "kΩ")}, + {0x33c1, 0, 0, 0, g(Yes, No, false, false, "", "MΩ")}, + {0x33c2, 0, 0, 0, g(Yes, No, false, false, "", "a.m.")}, + {0x33c3, 0, 0, 0, g(Yes, No, false, false, "", "Bq")}, + {0x33c4, 0, 0, 0, g(Yes, No, false, false, "", "cc")}, + {0x33c5, 0, 0, 0, g(Yes, No, false, false, "", "cd")}, + {0x33c6, 0, 0, 0, g(Yes, No, false, false, "", "C∕kg")}, + {0x33c7, 0, 0, 0, g(Yes, No, false, false, "", "Co.")}, + {0x33c8, 0, 0, 0, g(Yes, No, false, false, "", "dB")}, + {0x33c9, 0, 0, 0, g(Yes, No, false, false, "", "Gy")}, + {0x33ca, 0, 0, 0, g(Yes, No, false, false, "", "ha")}, + {0x33cb, 0, 0, 0, g(Yes, No, false, false, "", "HP")}, + {0x33cc, 0, 0, 0, g(Yes, No, false, false, "", "in")}, + {0x33cd, 0, 0, 0, g(Yes, No, false, false, "", "KK")}, + {0x33ce, 0, 0, 0, g(Yes, No, false, false, "", "KM")}, + {0x33cf, 0, 0, 0, g(Yes, No, false, false, "", "kt")}, + {0x33d0, 0, 0, 0, g(Yes, No, false, false, "", "lm")}, + {0x33d1, 0, 0, 0, g(Yes, No, false, false, "", "ln")}, + {0x33d2, 0, 0, 0, g(Yes, No, false, false, "", "log")}, + {0x33d3, 0, 0, 0, g(Yes, No, false, false, "", "lx")}, + {0x33d4, 0, 0, 0, g(Yes, No, false, false, "", "mb")}, + {0x33d5, 0, 0, 0, g(Yes, No, false, false, "", "mil")}, + {0x33d6, 0, 0, 0, g(Yes, No, false, false, "", "mol")}, + {0x33d7, 0, 0, 0, g(Yes, No, false, false, "", "PH")}, + {0x33d8, 0, 0, 0, g(Yes, No, false, false, "", "p.m.")}, + {0x33d9, 0, 0, 0, g(Yes, No, false, false, "", "PPM")}, + {0x33da, 0, 0, 0, g(Yes, No, false, false, "", "PR")}, + {0x33db, 0, 0, 0, g(Yes, No, false, false, "", "sr")}, + {0x33dc, 0, 0, 0, g(Yes, No, false, false, "", "Sv")}, + {0x33dd, 0, 0, 0, g(Yes, No, false, false, "", "Wb")}, + {0x33de, 0, 0, 0, g(Yes, No, false, false, "", "V∕m")}, + {0x33df, 0, 0, 0, g(Yes, No, false, false, "", "A∕m")}, + {0x33e0, 0, 0, 0, g(Yes, No, false, false, "", "1日")}, + {0x33e1, 0, 0, 0, g(Yes, No, false, false, "", "2日")}, + {0x33e2, 0, 0, 0, g(Yes, No, false, false, "", "3日")}, + {0x33e3, 0, 0, 0, g(Yes, No, false, false, "", "4日")}, + {0x33e4, 0, 0, 0, g(Yes, No, false, false, "", "5日")}, + {0x33e5, 0, 0, 0, g(Yes, No, false, false, "", "6日")}, + {0x33e6, 0, 0, 0, g(Yes, No, false, false, "", "7日")}, + {0x33e7, 0, 0, 0, g(Yes, No, false, false, "", "8日")}, + {0x33e8, 0, 0, 0, g(Yes, No, false, false, "", "9日")}, + {0x33e9, 0, 0, 0, g(Yes, No, false, false, "", "10日")}, + {0x33ea, 0, 0, 0, g(Yes, No, false, false, "", "11日")}, + {0x33eb, 0, 0, 0, g(Yes, No, false, false, "", "12日")}, + {0x33ec, 0, 0, 0, g(Yes, No, false, false, "", "13日")}, + {0x33ed, 0, 0, 0, g(Yes, No, false, false, "", "14日")}, + {0x33ee, 0, 0, 0, g(Yes, No, false, false, "", "15日")}, + {0x33ef, 0, 0, 0, g(Yes, No, false, false, "", "16日")}, + {0x33f0, 0, 0, 0, g(Yes, No, false, false, "", "17日")}, + {0x33f1, 0, 0, 0, g(Yes, No, false, false, "", "18日")}, + {0x33f2, 0, 0, 0, g(Yes, No, false, false, "", "19日")}, + {0x33f3, 0, 0, 0, g(Yes, No, false, false, "", "20日")}, + {0x33f4, 0, 0, 0, g(Yes, No, false, false, "", "21日")}, + {0x33f5, 0, 0, 0, g(Yes, No, false, false, "", "22日")}, + {0x33f6, 0, 0, 0, g(Yes, No, false, false, "", "23日")}, + {0x33f7, 0, 0, 0, g(Yes, No, false, false, "", "24日")}, + {0x33f8, 0, 0, 0, g(Yes, No, false, false, "", "25日")}, + {0x33f9, 0, 0, 0, g(Yes, No, false, false, "", "26日")}, + {0x33fa, 0, 0, 0, g(Yes, No, false, false, "", "27日")}, + {0x33fb, 0, 0, 0, g(Yes, No, false, false, "", "28日")}, + {0x33fc, 0, 0, 0, g(Yes, No, false, false, "", "29日")}, + {0x33fd, 0, 0, 0, g(Yes, No, false, false, "", "30日")}, + {0x33fe, 0, 0, 0, g(Yes, No, false, false, "", "31日")}, + {0x33ff, 0, 0, 0, g(Yes, No, false, false, "", "gal")}, + {0x3400, 0, 0, 0, f(Yes, false, "")}, + {0xa66f, 230, 1, 1, f(Yes, false, "")}, + {0xa670, 0, 0, 0, f(Yes, false, "")}, + {0xa674, 230, 1, 1, f(Yes, false, "")}, + {0xa67e, 0, 0, 0, f(Yes, false, "")}, + {0xa69c, 0, 0, 0, g(Yes, No, false, false, "", "ъ")}, + {0xa69d, 0, 0, 0, g(Yes, No, false, false, "", "ь")}, + {0xa69e, 230, 1, 1, f(Yes, false, "")}, + {0xa6a0, 0, 0, 0, f(Yes, false, "")}, + {0xa6f0, 230, 1, 1, f(Yes, false, "")}, + {0xa6f2, 0, 0, 0, f(Yes, false, "")}, + {0xa770, 0, 0, 0, g(Yes, No, false, false, "", "ꝯ")}, + {0xa771, 0, 0, 0, f(Yes, false, "")}, + {0xa7f8, 0, 0, 0, g(Yes, No, false, false, "", "Ħ")}, + {0xa7f9, 0, 0, 0, g(Yes, No, false, false, "", "œ")}, + {0xa7fa, 0, 0, 0, f(Yes, false, "")}, + {0xa806, 9, 1, 1, f(Yes, false, "")}, + {0xa807, 0, 0, 0, f(Yes, false, "")}, + {0xa8c4, 9, 1, 1, f(Yes, false, "")}, + {0xa8c5, 0, 0, 0, f(Yes, false, "")}, + {0xa8e0, 230, 1, 1, f(Yes, false, "")}, + {0xa8f2, 0, 0, 0, f(Yes, false, "")}, + {0xa92b, 220, 1, 1, f(Yes, false, "")}, + {0xa92e, 0, 0, 0, f(Yes, false, "")}, + {0xa953, 9, 1, 1, f(Yes, false, "")}, + {0xa954, 0, 0, 0, f(Yes, false, "")}, + {0xa9b3, 7, 1, 1, f(Yes, false, "")}, + {0xa9b4, 0, 0, 0, f(Yes, false, "")}, + {0xa9c0, 9, 1, 1, f(Yes, false, "")}, + {0xa9c1, 0, 0, 0, f(Yes, false, "")}, + {0xaab0, 230, 1, 1, f(Yes, false, "")}, + {0xaab1, 0, 0, 0, f(Yes, false, "")}, + {0xaab2, 230, 1, 1, f(Yes, false, "")}, + {0xaab4, 220, 1, 1, f(Yes, false, "")}, + {0xaab5, 0, 0, 0, f(Yes, false, "")}, + {0xaab7, 230, 1, 1, f(Yes, false, "")}, + {0xaab9, 0, 0, 0, f(Yes, false, "")}, + {0xaabe, 230, 1, 1, f(Yes, false, "")}, + {0xaac0, 0, 0, 0, f(Yes, false, "")}, + {0xaac1, 230, 1, 1, f(Yes, false, "")}, + {0xaac2, 0, 0, 0, f(Yes, false, "")}, + {0xaaf6, 9, 1, 1, f(Yes, false, "")}, + {0xaaf7, 0, 0, 0, f(Yes, false, "")}, + {0xab5c, 0, 0, 0, g(Yes, No, false, false, "", "ꜧ")}, + {0xab5d, 0, 0, 0, g(Yes, No, false, false, "", "ꬷ")}, + {0xab5e, 0, 0, 0, g(Yes, No, false, false, "", "ɫ")}, + {0xab5f, 0, 0, 0, g(Yes, No, false, false, "", "ꭒ")}, + {0xab60, 0, 0, 0, f(Yes, false, "")}, + {0xabed, 9, 1, 1, f(Yes, false, "")}, + {0xabee, 0, 0, 0, f(Yes, false, "")}, + {0xac00, 0, 0, 1, f(Yes, true, "")}, + {0xac01, 0, 0, 2, f(Yes, false, "")}, + {0xac1c, 0, 0, 1, f(Yes, true, "")}, + {0xac1d, 0, 0, 2, f(Yes, false, "")}, + {0xac38, 0, 0, 1, f(Yes, true, "")}, + {0xac39, 0, 0, 2, f(Yes, false, "")}, + {0xac54, 0, 0, 1, f(Yes, true, "")}, + {0xac55, 0, 0, 2, f(Yes, false, "")}, + {0xac70, 0, 0, 1, f(Yes, true, "")}, + {0xac71, 0, 0, 2, f(Yes, false, "")}, + {0xac8c, 0, 0, 1, f(Yes, true, "")}, + {0xac8d, 0, 0, 2, f(Yes, false, "")}, + {0xaca8, 0, 0, 1, f(Yes, true, "")}, + {0xaca9, 0, 0, 2, f(Yes, false, "")}, + {0xacc4, 0, 0, 1, f(Yes, true, "")}, + {0xacc5, 0, 0, 2, f(Yes, false, "")}, + {0xace0, 0, 0, 1, f(Yes, true, "")}, + {0xace1, 0, 0, 2, f(Yes, false, "")}, + {0xacfc, 0, 0, 1, f(Yes, true, "")}, + {0xacfd, 0, 0, 2, f(Yes, false, "")}, + {0xad18, 0, 0, 1, f(Yes, true, "")}, + {0xad19, 0, 0, 2, f(Yes, false, "")}, + {0xad34, 0, 0, 1, f(Yes, true, "")}, + {0xad35, 0, 0, 2, f(Yes, false, "")}, + {0xad50, 0, 0, 1, f(Yes, true, "")}, + {0xad51, 0, 0, 2, f(Yes, false, "")}, + {0xad6c, 0, 0, 1, f(Yes, true, "")}, + {0xad6d, 0, 0, 2, f(Yes, false, "")}, + {0xad88, 0, 0, 1, f(Yes, true, "")}, + {0xad89, 0, 0, 2, f(Yes, false, "")}, + {0xada4, 0, 0, 1, f(Yes, true, "")}, + {0xada5, 0, 0, 2, f(Yes, false, "")}, + {0xadc0, 0, 0, 1, f(Yes, true, "")}, + {0xadc1, 0, 0, 2, f(Yes, false, "")}, + {0xaddc, 0, 0, 1, f(Yes, true, "")}, + {0xaddd, 0, 0, 2, f(Yes, false, "")}, + {0xadf8, 0, 0, 1, f(Yes, true, "")}, + {0xadf9, 0, 0, 2, f(Yes, false, "")}, + {0xae14, 0, 0, 1, f(Yes, true, "")}, + {0xae15, 0, 0, 2, f(Yes, false, "")}, + {0xae30, 0, 0, 1, f(Yes, true, "")}, + {0xae31, 0, 0, 2, f(Yes, false, "")}, + {0xae4c, 0, 0, 1, f(Yes, true, "")}, + {0xae4d, 0, 0, 2, f(Yes, false, "")}, + {0xae68, 0, 0, 1, f(Yes, true, "")}, + {0xae69, 0, 0, 2, f(Yes, false, "")}, + {0xae84, 0, 0, 1, f(Yes, true, "")}, + {0xae85, 0, 0, 2, f(Yes, false, "")}, + {0xaea0, 0, 0, 1, f(Yes, true, "")}, + {0xaea1, 0, 0, 2, f(Yes, false, "")}, + {0xaebc, 0, 0, 1, f(Yes, true, "")}, + {0xaebd, 0, 0, 2, f(Yes, false, "")}, + {0xaed8, 0, 0, 1, f(Yes, true, "")}, + {0xaed9, 0, 0, 2, f(Yes, false, "")}, + {0xaef4, 0, 0, 1, f(Yes, true, "")}, + {0xaef5, 0, 0, 2, f(Yes, false, "")}, + {0xaf10, 0, 0, 1, f(Yes, true, "")}, + {0xaf11, 0, 0, 2, f(Yes, false, "")}, + {0xaf2c, 0, 0, 1, f(Yes, true, "")}, + {0xaf2d, 0, 0, 2, f(Yes, false, "")}, + {0xaf48, 0, 0, 1, f(Yes, true, "")}, + {0xaf49, 0, 0, 2, f(Yes, false, "")}, + {0xaf64, 0, 0, 1, f(Yes, true, "")}, + {0xaf65, 0, 0, 2, f(Yes, false, "")}, + {0xaf80, 0, 0, 1, f(Yes, true, "")}, + {0xaf81, 0, 0, 2, f(Yes, false, "")}, + {0xaf9c, 0, 0, 1, f(Yes, true, "")}, + {0xaf9d, 0, 0, 2, f(Yes, false, "")}, + {0xafb8, 0, 0, 1, f(Yes, true, "")}, + {0xafb9, 0, 0, 2, f(Yes, false, "")}, + {0xafd4, 0, 0, 1, f(Yes, true, "")}, + {0xafd5, 0, 0, 2, f(Yes, false, "")}, + {0xaff0, 0, 0, 1, f(Yes, true, "")}, + {0xaff1, 0, 0, 2, f(Yes, false, "")}, + {0xb00c, 0, 0, 1, f(Yes, true, "")}, + {0xb00d, 0, 0, 2, f(Yes, false, "")}, + {0xb028, 0, 0, 1, f(Yes, true, "")}, + {0xb029, 0, 0, 2, f(Yes, false, "")}, + {0xb044, 0, 0, 1, f(Yes, true, "")}, + {0xb045, 0, 0, 2, f(Yes, false, "")}, + {0xb060, 0, 0, 1, f(Yes, true, "")}, + {0xb061, 0, 0, 2, f(Yes, false, "")}, + {0xb07c, 0, 0, 1, f(Yes, true, "")}, + {0xb07d, 0, 0, 2, f(Yes, false, "")}, + {0xb098, 0, 0, 1, f(Yes, true, "")}, + {0xb099, 0, 0, 2, f(Yes, false, "")}, + {0xb0b4, 0, 0, 1, f(Yes, true, "")}, + {0xb0b5, 0, 0, 2, f(Yes, false, "")}, + {0xb0d0, 0, 0, 1, f(Yes, true, "")}, + {0xb0d1, 0, 0, 2, f(Yes, false, "")}, + {0xb0ec, 0, 0, 1, f(Yes, true, "")}, + {0xb0ed, 0, 0, 2, f(Yes, false, "")}, + {0xb108, 0, 0, 1, f(Yes, true, "")}, + {0xb109, 0, 0, 2, f(Yes, false, "")}, + {0xb124, 0, 0, 1, f(Yes, true, "")}, + {0xb125, 0, 0, 2, f(Yes, false, "")}, + {0xb140, 0, 0, 1, f(Yes, true, "")}, + {0xb141, 0, 0, 2, f(Yes, false, "")}, + {0xb15c, 0, 0, 1, f(Yes, true, "")}, + {0xb15d, 0, 0, 2, f(Yes, false, "")}, + {0xb178, 0, 0, 1, f(Yes, true, "")}, + {0xb179, 0, 0, 2, f(Yes, false, "")}, + {0xb194, 0, 0, 1, f(Yes, true, "")}, + {0xb195, 0, 0, 2, f(Yes, false, "")}, + {0xb1b0, 0, 0, 1, f(Yes, true, "")}, + {0xb1b1, 0, 0, 2, f(Yes, false, "")}, + {0xb1cc, 0, 0, 1, f(Yes, true, "")}, + {0xb1cd, 0, 0, 2, f(Yes, false, "")}, + {0xb1e8, 0, 0, 1, f(Yes, true, "")}, + {0xb1e9, 0, 0, 2, f(Yes, false, "")}, + {0xb204, 0, 0, 1, f(Yes, true, "")}, + {0xb205, 0, 0, 2, f(Yes, false, "")}, + {0xb220, 0, 0, 1, f(Yes, true, "")}, + {0xb221, 0, 0, 2, f(Yes, false, "")}, + {0xb23c, 0, 0, 1, f(Yes, true, "")}, + {0xb23d, 0, 0, 2, f(Yes, false, "")}, + {0xb258, 0, 0, 1, f(Yes, true, "")}, + {0xb259, 0, 0, 2, f(Yes, false, "")}, + {0xb274, 0, 0, 1, f(Yes, true, "")}, + {0xb275, 0, 0, 2, f(Yes, false, "")}, + {0xb290, 0, 0, 1, f(Yes, true, "")}, + {0xb291, 0, 0, 2, f(Yes, false, "")}, + {0xb2ac, 0, 0, 1, f(Yes, true, "")}, + {0xb2ad, 0, 0, 2, f(Yes, false, "")}, + {0xb2c8, 0, 0, 1, f(Yes, true, "")}, + {0xb2c9, 0, 0, 2, f(Yes, false, "")}, + {0xb2e4, 0, 0, 1, f(Yes, true, "")}, + {0xb2e5, 0, 0, 2, f(Yes, false, "")}, + {0xb300, 0, 0, 1, f(Yes, true, "")}, + {0xb301, 0, 0, 2, f(Yes, false, "")}, + {0xb31c, 0, 0, 1, f(Yes, true, "")}, + {0xb31d, 0, 0, 2, f(Yes, false, "")}, + {0xb338, 0, 0, 1, f(Yes, true, "")}, + {0xb339, 0, 0, 2, f(Yes, false, "")}, + {0xb354, 0, 0, 1, f(Yes, true, "")}, + {0xb355, 0, 0, 2, f(Yes, false, "")}, + {0xb370, 0, 0, 1, f(Yes, true, "")}, + {0xb371, 0, 0, 2, f(Yes, false, "")}, + {0xb38c, 0, 0, 1, f(Yes, true, "")}, + {0xb38d, 0, 0, 2, f(Yes, false, "")}, + {0xb3a8, 0, 0, 1, f(Yes, true, "")}, + {0xb3a9, 0, 0, 2, f(Yes, false, "")}, + {0xb3c4, 0, 0, 1, f(Yes, true, "")}, + {0xb3c5, 0, 0, 2, f(Yes, false, "")}, + {0xb3e0, 0, 0, 1, f(Yes, true, "")}, + {0xb3e1, 0, 0, 2, f(Yes, false, "")}, + {0xb3fc, 0, 0, 1, f(Yes, true, "")}, + {0xb3fd, 0, 0, 2, f(Yes, false, "")}, + {0xb418, 0, 0, 1, f(Yes, true, "")}, + {0xb419, 0, 0, 2, f(Yes, false, "")}, + {0xb434, 0, 0, 1, f(Yes, true, "")}, + {0xb435, 0, 0, 2, f(Yes, false, "")}, + {0xb450, 0, 0, 1, f(Yes, true, "")}, + {0xb451, 0, 0, 2, f(Yes, false, "")}, + {0xb46c, 0, 0, 1, f(Yes, true, "")}, + {0xb46d, 0, 0, 2, f(Yes, false, "")}, + {0xb488, 0, 0, 1, f(Yes, true, "")}, + {0xb489, 0, 0, 2, f(Yes, false, "")}, + {0xb4a4, 0, 0, 1, f(Yes, true, "")}, + {0xb4a5, 0, 0, 2, f(Yes, false, "")}, + {0xb4c0, 0, 0, 1, f(Yes, true, "")}, + {0xb4c1, 0, 0, 2, f(Yes, false, "")}, + {0xb4dc, 0, 0, 1, f(Yes, true, "")}, + {0xb4dd, 0, 0, 2, f(Yes, false, "")}, + {0xb4f8, 0, 0, 1, f(Yes, true, "")}, + {0xb4f9, 0, 0, 2, f(Yes, false, "")}, + {0xb514, 0, 0, 1, f(Yes, true, "")}, + {0xb515, 0, 0, 2, f(Yes, false, "")}, + {0xb530, 0, 0, 1, f(Yes, true, "")}, + {0xb531, 0, 0, 2, f(Yes, false, "")}, + {0xb54c, 0, 0, 1, f(Yes, true, "")}, + {0xb54d, 0, 0, 2, f(Yes, false, "")}, + {0xb568, 0, 0, 1, f(Yes, true, "")}, + {0xb569, 0, 0, 2, f(Yes, false, "")}, + {0xb584, 0, 0, 1, f(Yes, true, "")}, + {0xb585, 0, 0, 2, f(Yes, false, "")}, + {0xb5a0, 0, 0, 1, f(Yes, true, "")}, + {0xb5a1, 0, 0, 2, f(Yes, false, "")}, + {0xb5bc, 0, 0, 1, f(Yes, true, "")}, + {0xb5bd, 0, 0, 2, f(Yes, false, "")}, + {0xb5d8, 0, 0, 1, f(Yes, true, "")}, + {0xb5d9, 0, 0, 2, f(Yes, false, "")}, + {0xb5f4, 0, 0, 1, f(Yes, true, "")}, + {0xb5f5, 0, 0, 2, f(Yes, false, "")}, + {0xb610, 0, 0, 1, f(Yes, true, "")}, + {0xb611, 0, 0, 2, f(Yes, false, "")}, + {0xb62c, 0, 0, 1, f(Yes, true, "")}, + {0xb62d, 0, 0, 2, f(Yes, false, "")}, + {0xb648, 0, 0, 1, f(Yes, true, "")}, + {0xb649, 0, 0, 2, f(Yes, false, "")}, + {0xb664, 0, 0, 1, f(Yes, true, "")}, + {0xb665, 0, 0, 2, f(Yes, false, "")}, + {0xb680, 0, 0, 1, f(Yes, true, "")}, + {0xb681, 0, 0, 2, f(Yes, false, "")}, + {0xb69c, 0, 0, 1, f(Yes, true, "")}, + {0xb69d, 0, 0, 2, f(Yes, false, "")}, + {0xb6b8, 0, 0, 1, f(Yes, true, "")}, + {0xb6b9, 0, 0, 2, f(Yes, false, "")}, + {0xb6d4, 0, 0, 1, f(Yes, true, "")}, + {0xb6d5, 0, 0, 2, f(Yes, false, "")}, + {0xb6f0, 0, 0, 1, f(Yes, true, "")}, + {0xb6f1, 0, 0, 2, f(Yes, false, "")}, + {0xb70c, 0, 0, 1, f(Yes, true, "")}, + {0xb70d, 0, 0, 2, f(Yes, false, "")}, + {0xb728, 0, 0, 1, f(Yes, true, "")}, + {0xb729, 0, 0, 2, f(Yes, false, "")}, + {0xb744, 0, 0, 1, f(Yes, true, "")}, + {0xb745, 0, 0, 2, f(Yes, false, "")}, + {0xb760, 0, 0, 1, f(Yes, true, "")}, + {0xb761, 0, 0, 2, f(Yes, false, "")}, + {0xb77c, 0, 0, 1, f(Yes, true, "")}, + {0xb77d, 0, 0, 2, f(Yes, false, "")}, + {0xb798, 0, 0, 1, f(Yes, true, "")}, + {0xb799, 0, 0, 2, f(Yes, false, "")}, + {0xb7b4, 0, 0, 1, f(Yes, true, "")}, + {0xb7b5, 0, 0, 2, f(Yes, false, "")}, + {0xb7d0, 0, 0, 1, f(Yes, true, "")}, + {0xb7d1, 0, 0, 2, f(Yes, false, "")}, + {0xb7ec, 0, 0, 1, f(Yes, true, "")}, + {0xb7ed, 0, 0, 2, f(Yes, false, "")}, + {0xb808, 0, 0, 1, f(Yes, true, "")}, + {0xb809, 0, 0, 2, f(Yes, false, "")}, + {0xb824, 0, 0, 1, f(Yes, true, "")}, + {0xb825, 0, 0, 2, f(Yes, false, "")}, + {0xb840, 0, 0, 1, f(Yes, true, "")}, + {0xb841, 0, 0, 2, f(Yes, false, "")}, + {0xb85c, 0, 0, 1, f(Yes, true, "")}, + {0xb85d, 0, 0, 2, f(Yes, false, "")}, + {0xb878, 0, 0, 1, f(Yes, true, "")}, + {0xb879, 0, 0, 2, f(Yes, false, "")}, + {0xb894, 0, 0, 1, f(Yes, true, "")}, + {0xb895, 0, 0, 2, f(Yes, false, "")}, + {0xb8b0, 0, 0, 1, f(Yes, true, "")}, + {0xb8b1, 0, 0, 2, f(Yes, false, "")}, + {0xb8cc, 0, 0, 1, f(Yes, true, "")}, + {0xb8cd, 0, 0, 2, f(Yes, false, "")}, + {0xb8e8, 0, 0, 1, f(Yes, true, "")}, + {0xb8e9, 0, 0, 2, f(Yes, false, "")}, + {0xb904, 0, 0, 1, f(Yes, true, "")}, + {0xb905, 0, 0, 2, f(Yes, false, "")}, + {0xb920, 0, 0, 1, f(Yes, true, "")}, + {0xb921, 0, 0, 2, f(Yes, false, "")}, + {0xb93c, 0, 0, 1, f(Yes, true, "")}, + {0xb93d, 0, 0, 2, f(Yes, false, "")}, + {0xb958, 0, 0, 1, f(Yes, true, "")}, + {0xb959, 0, 0, 2, f(Yes, false, "")}, + {0xb974, 0, 0, 1, f(Yes, true, "")}, + {0xb975, 0, 0, 2, f(Yes, false, "")}, + {0xb990, 0, 0, 1, f(Yes, true, "")}, + {0xb991, 0, 0, 2, f(Yes, false, "")}, + {0xb9ac, 0, 0, 1, f(Yes, true, "")}, + {0xb9ad, 0, 0, 2, f(Yes, false, "")}, + {0xb9c8, 0, 0, 1, f(Yes, true, "")}, + {0xb9c9, 0, 0, 2, f(Yes, false, "")}, + {0xb9e4, 0, 0, 1, f(Yes, true, "")}, + {0xb9e5, 0, 0, 2, f(Yes, false, "")}, + {0xba00, 0, 0, 1, f(Yes, true, "")}, + {0xba01, 0, 0, 2, f(Yes, false, "")}, + {0xba1c, 0, 0, 1, f(Yes, true, "")}, + {0xba1d, 0, 0, 2, f(Yes, false, "")}, + {0xba38, 0, 0, 1, f(Yes, true, "")}, + {0xba39, 0, 0, 2, f(Yes, false, "")}, + {0xba54, 0, 0, 1, f(Yes, true, "")}, + {0xba55, 0, 0, 2, f(Yes, false, "")}, + {0xba70, 0, 0, 1, f(Yes, true, "")}, + {0xba71, 0, 0, 2, f(Yes, false, "")}, + {0xba8c, 0, 0, 1, f(Yes, true, "")}, + {0xba8d, 0, 0, 2, f(Yes, false, "")}, + {0xbaa8, 0, 0, 1, f(Yes, true, "")}, + {0xbaa9, 0, 0, 2, f(Yes, false, "")}, + {0xbac4, 0, 0, 1, f(Yes, true, "")}, + {0xbac5, 0, 0, 2, f(Yes, false, "")}, + {0xbae0, 0, 0, 1, f(Yes, true, "")}, + {0xbae1, 0, 0, 2, f(Yes, false, "")}, + {0xbafc, 0, 0, 1, f(Yes, true, "")}, + {0xbafd, 0, 0, 2, f(Yes, false, "")}, + {0xbb18, 0, 0, 1, f(Yes, true, "")}, + {0xbb19, 0, 0, 2, f(Yes, false, "")}, + {0xbb34, 0, 0, 1, f(Yes, true, "")}, + {0xbb35, 0, 0, 2, f(Yes, false, "")}, + {0xbb50, 0, 0, 1, f(Yes, true, "")}, + {0xbb51, 0, 0, 2, f(Yes, false, "")}, + {0xbb6c, 0, 0, 1, f(Yes, true, "")}, + {0xbb6d, 0, 0, 2, f(Yes, false, "")}, + {0xbb88, 0, 0, 1, f(Yes, true, "")}, + {0xbb89, 0, 0, 2, f(Yes, false, "")}, + {0xbba4, 0, 0, 1, f(Yes, true, "")}, + {0xbba5, 0, 0, 2, f(Yes, false, "")}, + {0xbbc0, 0, 0, 1, f(Yes, true, "")}, + {0xbbc1, 0, 0, 2, f(Yes, false, "")}, + {0xbbdc, 0, 0, 1, f(Yes, true, "")}, + {0xbbdd, 0, 0, 2, f(Yes, false, "")}, + {0xbbf8, 0, 0, 1, f(Yes, true, "")}, + {0xbbf9, 0, 0, 2, f(Yes, false, "")}, + {0xbc14, 0, 0, 1, f(Yes, true, "")}, + {0xbc15, 0, 0, 2, f(Yes, false, "")}, + {0xbc30, 0, 0, 1, f(Yes, true, "")}, + {0xbc31, 0, 0, 2, f(Yes, false, "")}, + {0xbc4c, 0, 0, 1, f(Yes, true, "")}, + {0xbc4d, 0, 0, 2, f(Yes, false, "")}, + {0xbc68, 0, 0, 1, f(Yes, true, "")}, + {0xbc69, 0, 0, 2, f(Yes, false, "")}, + {0xbc84, 0, 0, 1, f(Yes, true, "")}, + {0xbc85, 0, 0, 2, f(Yes, false, "")}, + {0xbca0, 0, 0, 1, f(Yes, true, "")}, + {0xbca1, 0, 0, 2, f(Yes, false, "")}, + {0xbcbc, 0, 0, 1, f(Yes, true, "")}, + {0xbcbd, 0, 0, 2, f(Yes, false, "")}, + {0xbcd8, 0, 0, 1, f(Yes, true, "")}, + {0xbcd9, 0, 0, 2, f(Yes, false, "")}, + {0xbcf4, 0, 0, 1, f(Yes, true, "")}, + {0xbcf5, 0, 0, 2, f(Yes, false, "")}, + {0xbd10, 0, 0, 1, f(Yes, true, "")}, + {0xbd11, 0, 0, 2, f(Yes, false, "")}, + {0xbd2c, 0, 0, 1, f(Yes, true, "")}, + {0xbd2d, 0, 0, 2, f(Yes, false, "")}, + {0xbd48, 0, 0, 1, f(Yes, true, "")}, + {0xbd49, 0, 0, 2, f(Yes, false, "")}, + {0xbd64, 0, 0, 1, f(Yes, true, "")}, + {0xbd65, 0, 0, 2, f(Yes, false, "")}, + {0xbd80, 0, 0, 1, f(Yes, true, "")}, + {0xbd81, 0, 0, 2, f(Yes, false, "")}, + {0xbd9c, 0, 0, 1, f(Yes, true, "")}, + {0xbd9d, 0, 0, 2, f(Yes, false, "")}, + {0xbdb8, 0, 0, 1, f(Yes, true, "")}, + {0xbdb9, 0, 0, 2, f(Yes, false, "")}, + {0xbdd4, 0, 0, 1, f(Yes, true, "")}, + {0xbdd5, 0, 0, 2, f(Yes, false, "")}, + {0xbdf0, 0, 0, 1, f(Yes, true, "")}, + {0xbdf1, 0, 0, 2, f(Yes, false, "")}, + {0xbe0c, 0, 0, 1, f(Yes, true, "")}, + {0xbe0d, 0, 0, 2, f(Yes, false, "")}, + {0xbe28, 0, 0, 1, f(Yes, true, "")}, + {0xbe29, 0, 0, 2, f(Yes, false, "")}, + {0xbe44, 0, 0, 1, f(Yes, true, "")}, + {0xbe45, 0, 0, 2, f(Yes, false, "")}, + {0xbe60, 0, 0, 1, f(Yes, true, "")}, + {0xbe61, 0, 0, 2, f(Yes, false, "")}, + {0xbe7c, 0, 0, 1, f(Yes, true, "")}, + {0xbe7d, 0, 0, 2, f(Yes, false, "")}, + {0xbe98, 0, 0, 1, f(Yes, true, "")}, + {0xbe99, 0, 0, 2, f(Yes, false, "")}, + {0xbeb4, 0, 0, 1, f(Yes, true, "")}, + {0xbeb5, 0, 0, 2, f(Yes, false, "")}, + {0xbed0, 0, 0, 1, f(Yes, true, "")}, + {0xbed1, 0, 0, 2, f(Yes, false, "")}, + {0xbeec, 0, 0, 1, f(Yes, true, "")}, + {0xbeed, 0, 0, 2, f(Yes, false, "")}, + {0xbf08, 0, 0, 1, f(Yes, true, "")}, + {0xbf09, 0, 0, 2, f(Yes, false, "")}, + {0xbf24, 0, 0, 1, f(Yes, true, "")}, + {0xbf25, 0, 0, 2, f(Yes, false, "")}, + {0xbf40, 0, 0, 1, f(Yes, true, "")}, + {0xbf41, 0, 0, 2, f(Yes, false, "")}, + {0xbf5c, 0, 0, 1, f(Yes, true, "")}, + {0xbf5d, 0, 0, 2, f(Yes, false, "")}, + {0xbf78, 0, 0, 1, f(Yes, true, "")}, + {0xbf79, 0, 0, 2, f(Yes, false, "")}, + {0xbf94, 0, 0, 1, f(Yes, true, "")}, + {0xbf95, 0, 0, 2, f(Yes, false, "")}, + {0xbfb0, 0, 0, 1, f(Yes, true, "")}, + {0xbfb1, 0, 0, 2, f(Yes, false, "")}, + {0xbfcc, 0, 0, 1, f(Yes, true, "")}, + {0xbfcd, 0, 0, 2, f(Yes, false, "")}, + {0xbfe8, 0, 0, 1, f(Yes, true, "")}, + {0xbfe9, 0, 0, 2, f(Yes, false, "")}, + {0xc004, 0, 0, 1, f(Yes, true, "")}, + {0xc005, 0, 0, 2, f(Yes, false, "")}, + {0xc020, 0, 0, 1, f(Yes, true, "")}, + {0xc021, 0, 0, 2, f(Yes, false, "")}, + {0xc03c, 0, 0, 1, f(Yes, true, "")}, + {0xc03d, 0, 0, 2, f(Yes, false, "")}, + {0xc058, 0, 0, 1, f(Yes, true, "")}, + {0xc059, 0, 0, 2, f(Yes, false, "")}, + {0xc074, 0, 0, 1, f(Yes, true, "")}, + {0xc075, 0, 0, 2, f(Yes, false, "")}, + {0xc090, 0, 0, 1, f(Yes, true, "")}, + {0xc091, 0, 0, 2, f(Yes, false, "")}, + {0xc0ac, 0, 0, 1, f(Yes, true, "")}, + {0xc0ad, 0, 0, 2, f(Yes, false, "")}, + {0xc0c8, 0, 0, 1, f(Yes, true, "")}, + {0xc0c9, 0, 0, 2, f(Yes, false, "")}, + {0xc0e4, 0, 0, 1, f(Yes, true, "")}, + {0xc0e5, 0, 0, 2, f(Yes, false, "")}, + {0xc100, 0, 0, 1, f(Yes, true, "")}, + {0xc101, 0, 0, 2, f(Yes, false, "")}, + {0xc11c, 0, 0, 1, f(Yes, true, "")}, + {0xc11d, 0, 0, 2, f(Yes, false, "")}, + {0xc138, 0, 0, 1, f(Yes, true, "")}, + {0xc139, 0, 0, 2, f(Yes, false, "")}, + {0xc154, 0, 0, 1, f(Yes, true, "")}, + {0xc155, 0, 0, 2, f(Yes, false, "")}, + {0xc170, 0, 0, 1, f(Yes, true, "")}, + {0xc171, 0, 0, 2, f(Yes, false, "")}, + {0xc18c, 0, 0, 1, f(Yes, true, "")}, + {0xc18d, 0, 0, 2, f(Yes, false, "")}, + {0xc1a8, 0, 0, 1, f(Yes, true, "")}, + {0xc1a9, 0, 0, 2, f(Yes, false, "")}, + {0xc1c4, 0, 0, 1, f(Yes, true, "")}, + {0xc1c5, 0, 0, 2, f(Yes, false, "")}, + {0xc1e0, 0, 0, 1, f(Yes, true, "")}, + {0xc1e1, 0, 0, 2, f(Yes, false, "")}, + {0xc1fc, 0, 0, 1, f(Yes, true, "")}, + {0xc1fd, 0, 0, 2, f(Yes, false, "")}, + {0xc218, 0, 0, 1, f(Yes, true, "")}, + {0xc219, 0, 0, 2, f(Yes, false, "")}, + {0xc234, 0, 0, 1, f(Yes, true, "")}, + {0xc235, 0, 0, 2, f(Yes, false, "")}, + {0xc250, 0, 0, 1, f(Yes, true, "")}, + {0xc251, 0, 0, 2, f(Yes, false, "")}, + {0xc26c, 0, 0, 1, f(Yes, true, "")}, + {0xc26d, 0, 0, 2, f(Yes, false, "")}, + {0xc288, 0, 0, 1, f(Yes, true, "")}, + {0xc289, 0, 0, 2, f(Yes, false, "")}, + {0xc2a4, 0, 0, 1, f(Yes, true, "")}, + {0xc2a5, 0, 0, 2, f(Yes, false, "")}, + {0xc2c0, 0, 0, 1, f(Yes, true, "")}, + {0xc2c1, 0, 0, 2, f(Yes, false, "")}, + {0xc2dc, 0, 0, 1, f(Yes, true, "")}, + {0xc2dd, 0, 0, 2, f(Yes, false, "")}, + {0xc2f8, 0, 0, 1, f(Yes, true, "")}, + {0xc2f9, 0, 0, 2, f(Yes, false, "")}, + {0xc314, 0, 0, 1, f(Yes, true, "")}, + {0xc315, 0, 0, 2, f(Yes, false, "")}, + {0xc330, 0, 0, 1, f(Yes, true, "")}, + {0xc331, 0, 0, 2, f(Yes, false, "")}, + {0xc34c, 0, 0, 1, f(Yes, true, "")}, + {0xc34d, 0, 0, 2, f(Yes, false, "")}, + {0xc368, 0, 0, 1, f(Yes, true, "")}, + {0xc369, 0, 0, 2, f(Yes, false, "")}, + {0xc384, 0, 0, 1, f(Yes, true, "")}, + {0xc385, 0, 0, 2, f(Yes, false, "")}, + {0xc3a0, 0, 0, 1, f(Yes, true, "")}, + {0xc3a1, 0, 0, 2, f(Yes, false, "")}, + {0xc3bc, 0, 0, 1, f(Yes, true, "")}, + {0xc3bd, 0, 0, 2, f(Yes, false, "")}, + {0xc3d8, 0, 0, 1, f(Yes, true, "")}, + {0xc3d9, 0, 0, 2, f(Yes, false, "")}, + {0xc3f4, 0, 0, 1, f(Yes, true, "")}, + {0xc3f5, 0, 0, 2, f(Yes, false, "")}, + {0xc410, 0, 0, 1, f(Yes, true, "")}, + {0xc411, 0, 0, 2, f(Yes, false, "")}, + {0xc42c, 0, 0, 1, f(Yes, true, "")}, + {0xc42d, 0, 0, 2, f(Yes, false, "")}, + {0xc448, 0, 0, 1, f(Yes, true, "")}, + {0xc449, 0, 0, 2, f(Yes, false, "")}, + {0xc464, 0, 0, 1, f(Yes, true, "")}, + {0xc465, 0, 0, 2, f(Yes, false, "")}, + {0xc480, 0, 0, 1, f(Yes, true, "")}, + {0xc481, 0, 0, 2, f(Yes, false, "")}, + {0xc49c, 0, 0, 1, f(Yes, true, "")}, + {0xc49d, 0, 0, 2, f(Yes, false, "")}, + {0xc4b8, 0, 0, 1, f(Yes, true, "")}, + {0xc4b9, 0, 0, 2, f(Yes, false, "")}, + {0xc4d4, 0, 0, 1, f(Yes, true, "")}, + {0xc4d5, 0, 0, 2, f(Yes, false, "")}, + {0xc4f0, 0, 0, 1, f(Yes, true, "")}, + {0xc4f1, 0, 0, 2, f(Yes, false, "")}, + {0xc50c, 0, 0, 1, f(Yes, true, "")}, + {0xc50d, 0, 0, 2, f(Yes, false, "")}, + {0xc528, 0, 0, 1, f(Yes, true, "")}, + {0xc529, 0, 0, 2, f(Yes, false, "")}, + {0xc544, 0, 0, 1, f(Yes, true, "")}, + {0xc545, 0, 0, 2, f(Yes, false, "")}, + {0xc560, 0, 0, 1, f(Yes, true, "")}, + {0xc561, 0, 0, 2, f(Yes, false, "")}, + {0xc57c, 0, 0, 1, f(Yes, true, "")}, + {0xc57d, 0, 0, 2, f(Yes, false, "")}, + {0xc598, 0, 0, 1, f(Yes, true, "")}, + {0xc599, 0, 0, 2, f(Yes, false, "")}, + {0xc5b4, 0, 0, 1, f(Yes, true, "")}, + {0xc5b5, 0, 0, 2, f(Yes, false, "")}, + {0xc5d0, 0, 0, 1, f(Yes, true, "")}, + {0xc5d1, 0, 0, 2, f(Yes, false, "")}, + {0xc5ec, 0, 0, 1, f(Yes, true, "")}, + {0xc5ed, 0, 0, 2, f(Yes, false, "")}, + {0xc608, 0, 0, 1, f(Yes, true, "")}, + {0xc609, 0, 0, 2, f(Yes, false, "")}, + {0xc624, 0, 0, 1, f(Yes, true, "")}, + {0xc625, 0, 0, 2, f(Yes, false, "")}, + {0xc640, 0, 0, 1, f(Yes, true, "")}, + {0xc641, 0, 0, 2, f(Yes, false, "")}, + {0xc65c, 0, 0, 1, f(Yes, true, "")}, + {0xc65d, 0, 0, 2, f(Yes, false, "")}, + {0xc678, 0, 0, 1, f(Yes, true, "")}, + {0xc679, 0, 0, 2, f(Yes, false, "")}, + {0xc694, 0, 0, 1, f(Yes, true, "")}, + {0xc695, 0, 0, 2, f(Yes, false, "")}, + {0xc6b0, 0, 0, 1, f(Yes, true, "")}, + {0xc6b1, 0, 0, 2, f(Yes, false, "")}, + {0xc6cc, 0, 0, 1, f(Yes, true, "")}, + {0xc6cd, 0, 0, 2, f(Yes, false, "")}, + {0xc6e8, 0, 0, 1, f(Yes, true, "")}, + {0xc6e9, 0, 0, 2, f(Yes, false, "")}, + {0xc704, 0, 0, 1, f(Yes, true, "")}, + {0xc705, 0, 0, 2, f(Yes, false, "")}, + {0xc720, 0, 0, 1, f(Yes, true, "")}, + {0xc721, 0, 0, 2, f(Yes, false, "")}, + {0xc73c, 0, 0, 1, f(Yes, true, "")}, + {0xc73d, 0, 0, 2, f(Yes, false, "")}, + {0xc758, 0, 0, 1, f(Yes, true, "")}, + {0xc759, 0, 0, 2, f(Yes, false, "")}, + {0xc774, 0, 0, 1, f(Yes, true, "")}, + {0xc775, 0, 0, 2, f(Yes, false, "")}, + {0xc790, 0, 0, 1, f(Yes, true, "")}, + {0xc791, 0, 0, 2, f(Yes, false, "")}, + {0xc7ac, 0, 0, 1, f(Yes, true, "")}, + {0xc7ad, 0, 0, 2, f(Yes, false, "")}, + {0xc7c8, 0, 0, 1, f(Yes, true, "")}, + {0xc7c9, 0, 0, 2, f(Yes, false, "")}, + {0xc7e4, 0, 0, 1, f(Yes, true, "")}, + {0xc7e5, 0, 0, 2, f(Yes, false, "")}, + {0xc800, 0, 0, 1, f(Yes, true, "")}, + {0xc801, 0, 0, 2, f(Yes, false, "")}, + {0xc81c, 0, 0, 1, f(Yes, true, "")}, + {0xc81d, 0, 0, 2, f(Yes, false, "")}, + {0xc838, 0, 0, 1, f(Yes, true, "")}, + {0xc839, 0, 0, 2, f(Yes, false, "")}, + {0xc854, 0, 0, 1, f(Yes, true, "")}, + {0xc855, 0, 0, 2, f(Yes, false, "")}, + {0xc870, 0, 0, 1, f(Yes, true, "")}, + {0xc871, 0, 0, 2, f(Yes, false, "")}, + {0xc88c, 0, 0, 1, f(Yes, true, "")}, + {0xc88d, 0, 0, 2, f(Yes, false, "")}, + {0xc8a8, 0, 0, 1, f(Yes, true, "")}, + {0xc8a9, 0, 0, 2, f(Yes, false, "")}, + {0xc8c4, 0, 0, 1, f(Yes, true, "")}, + {0xc8c5, 0, 0, 2, f(Yes, false, "")}, + {0xc8e0, 0, 0, 1, f(Yes, true, "")}, + {0xc8e1, 0, 0, 2, f(Yes, false, "")}, + {0xc8fc, 0, 0, 1, f(Yes, true, "")}, + {0xc8fd, 0, 0, 2, f(Yes, false, "")}, + {0xc918, 0, 0, 1, f(Yes, true, "")}, + {0xc919, 0, 0, 2, f(Yes, false, "")}, + {0xc934, 0, 0, 1, f(Yes, true, "")}, + {0xc935, 0, 0, 2, f(Yes, false, "")}, + {0xc950, 0, 0, 1, f(Yes, true, "")}, + {0xc951, 0, 0, 2, f(Yes, false, "")}, + {0xc96c, 0, 0, 1, f(Yes, true, "")}, + {0xc96d, 0, 0, 2, f(Yes, false, "")}, + {0xc988, 0, 0, 1, f(Yes, true, "")}, + {0xc989, 0, 0, 2, f(Yes, false, "")}, + {0xc9a4, 0, 0, 1, f(Yes, true, "")}, + {0xc9a5, 0, 0, 2, f(Yes, false, "")}, + {0xc9c0, 0, 0, 1, f(Yes, true, "")}, + {0xc9c1, 0, 0, 2, f(Yes, false, "")}, + {0xc9dc, 0, 0, 1, f(Yes, true, "")}, + {0xc9dd, 0, 0, 2, f(Yes, false, "")}, + {0xc9f8, 0, 0, 1, f(Yes, true, "")}, + {0xc9f9, 0, 0, 2, f(Yes, false, "")}, + {0xca14, 0, 0, 1, f(Yes, true, "")}, + {0xca15, 0, 0, 2, f(Yes, false, "")}, + {0xca30, 0, 0, 1, f(Yes, true, "")}, + {0xca31, 0, 0, 2, f(Yes, false, "")}, + {0xca4c, 0, 0, 1, f(Yes, true, "")}, + {0xca4d, 0, 0, 2, f(Yes, false, "")}, + {0xca68, 0, 0, 1, f(Yes, true, "")}, + {0xca69, 0, 0, 2, f(Yes, false, "")}, + {0xca84, 0, 0, 1, f(Yes, true, "")}, + {0xca85, 0, 0, 2, f(Yes, false, "")}, + {0xcaa0, 0, 0, 1, f(Yes, true, "")}, + {0xcaa1, 0, 0, 2, f(Yes, false, "")}, + {0xcabc, 0, 0, 1, f(Yes, true, "")}, + {0xcabd, 0, 0, 2, f(Yes, false, "")}, + {0xcad8, 0, 0, 1, f(Yes, true, "")}, + {0xcad9, 0, 0, 2, f(Yes, false, "")}, + {0xcaf4, 0, 0, 1, f(Yes, true, "")}, + {0xcaf5, 0, 0, 2, f(Yes, false, "")}, + {0xcb10, 0, 0, 1, f(Yes, true, "")}, + {0xcb11, 0, 0, 2, f(Yes, false, "")}, + {0xcb2c, 0, 0, 1, f(Yes, true, "")}, + {0xcb2d, 0, 0, 2, f(Yes, false, "")}, + {0xcb48, 0, 0, 1, f(Yes, true, "")}, + {0xcb49, 0, 0, 2, f(Yes, false, "")}, + {0xcb64, 0, 0, 1, f(Yes, true, "")}, + {0xcb65, 0, 0, 2, f(Yes, false, "")}, + {0xcb80, 0, 0, 1, f(Yes, true, "")}, + {0xcb81, 0, 0, 2, f(Yes, false, "")}, + {0xcb9c, 0, 0, 1, f(Yes, true, "")}, + {0xcb9d, 0, 0, 2, f(Yes, false, "")}, + {0xcbb8, 0, 0, 1, f(Yes, true, "")}, + {0xcbb9, 0, 0, 2, f(Yes, false, "")}, + {0xcbd4, 0, 0, 1, f(Yes, true, "")}, + {0xcbd5, 0, 0, 2, f(Yes, false, "")}, + {0xcbf0, 0, 0, 1, f(Yes, true, "")}, + {0xcbf1, 0, 0, 2, f(Yes, false, "")}, + {0xcc0c, 0, 0, 1, f(Yes, true, "")}, + {0xcc0d, 0, 0, 2, f(Yes, false, "")}, + {0xcc28, 0, 0, 1, f(Yes, true, "")}, + {0xcc29, 0, 0, 2, f(Yes, false, "")}, + {0xcc44, 0, 0, 1, f(Yes, true, "")}, + {0xcc45, 0, 0, 2, f(Yes, false, "")}, + {0xcc60, 0, 0, 1, f(Yes, true, "")}, + {0xcc61, 0, 0, 2, f(Yes, false, "")}, + {0xcc7c, 0, 0, 1, f(Yes, true, "")}, + {0xcc7d, 0, 0, 2, f(Yes, false, "")}, + {0xcc98, 0, 0, 1, f(Yes, true, "")}, + {0xcc99, 0, 0, 2, f(Yes, false, "")}, + {0xccb4, 0, 0, 1, f(Yes, true, "")}, + {0xccb5, 0, 0, 2, f(Yes, false, "")}, + {0xccd0, 0, 0, 1, f(Yes, true, "")}, + {0xccd1, 0, 0, 2, f(Yes, false, "")}, + {0xccec, 0, 0, 1, f(Yes, true, "")}, + {0xcced, 0, 0, 2, f(Yes, false, "")}, + {0xcd08, 0, 0, 1, f(Yes, true, "")}, + {0xcd09, 0, 0, 2, f(Yes, false, "")}, + {0xcd24, 0, 0, 1, f(Yes, true, "")}, + {0xcd25, 0, 0, 2, f(Yes, false, "")}, + {0xcd40, 0, 0, 1, f(Yes, true, "")}, + {0xcd41, 0, 0, 2, f(Yes, false, "")}, + {0xcd5c, 0, 0, 1, f(Yes, true, "")}, + {0xcd5d, 0, 0, 2, f(Yes, false, "")}, + {0xcd78, 0, 0, 1, f(Yes, true, "")}, + {0xcd79, 0, 0, 2, f(Yes, false, "")}, + {0xcd94, 0, 0, 1, f(Yes, true, "")}, + {0xcd95, 0, 0, 2, f(Yes, false, "")}, + {0xcdb0, 0, 0, 1, f(Yes, true, "")}, + {0xcdb1, 0, 0, 2, f(Yes, false, "")}, + {0xcdcc, 0, 0, 1, f(Yes, true, "")}, + {0xcdcd, 0, 0, 2, f(Yes, false, "")}, + {0xcde8, 0, 0, 1, f(Yes, true, "")}, + {0xcde9, 0, 0, 2, f(Yes, false, "")}, + {0xce04, 0, 0, 1, f(Yes, true, "")}, + {0xce05, 0, 0, 2, f(Yes, false, "")}, + {0xce20, 0, 0, 1, f(Yes, true, "")}, + {0xce21, 0, 0, 2, f(Yes, false, "")}, + {0xce3c, 0, 0, 1, f(Yes, true, "")}, + {0xce3d, 0, 0, 2, f(Yes, false, "")}, + {0xce58, 0, 0, 1, f(Yes, true, "")}, + {0xce59, 0, 0, 2, f(Yes, false, "")}, + {0xce74, 0, 0, 1, f(Yes, true, "")}, + {0xce75, 0, 0, 2, f(Yes, false, "")}, + {0xce90, 0, 0, 1, f(Yes, true, "")}, + {0xce91, 0, 0, 2, f(Yes, false, "")}, + {0xceac, 0, 0, 1, f(Yes, true, "")}, + {0xcead, 0, 0, 2, f(Yes, false, "")}, + {0xcec8, 0, 0, 1, f(Yes, true, "")}, + {0xcec9, 0, 0, 2, f(Yes, false, "")}, + {0xcee4, 0, 0, 1, f(Yes, true, "")}, + {0xcee5, 0, 0, 2, f(Yes, false, "")}, + {0xcf00, 0, 0, 1, f(Yes, true, "")}, + {0xcf01, 0, 0, 2, f(Yes, false, "")}, + {0xcf1c, 0, 0, 1, f(Yes, true, "")}, + {0xcf1d, 0, 0, 2, f(Yes, false, "")}, + {0xcf38, 0, 0, 1, f(Yes, true, "")}, + {0xcf39, 0, 0, 2, f(Yes, false, "")}, + {0xcf54, 0, 0, 1, f(Yes, true, "")}, + {0xcf55, 0, 0, 2, f(Yes, false, "")}, + {0xcf70, 0, 0, 1, f(Yes, true, "")}, + {0xcf71, 0, 0, 2, f(Yes, false, "")}, + {0xcf8c, 0, 0, 1, f(Yes, true, "")}, + {0xcf8d, 0, 0, 2, f(Yes, false, "")}, + {0xcfa8, 0, 0, 1, f(Yes, true, "")}, + {0xcfa9, 0, 0, 2, f(Yes, false, "")}, + {0xcfc4, 0, 0, 1, f(Yes, true, "")}, + {0xcfc5, 0, 0, 2, f(Yes, false, "")}, + {0xcfe0, 0, 0, 1, f(Yes, true, "")}, + {0xcfe1, 0, 0, 2, f(Yes, false, "")}, + {0xcffc, 0, 0, 1, f(Yes, true, "")}, + {0xcffd, 0, 0, 2, f(Yes, false, "")}, + {0xd018, 0, 0, 1, f(Yes, true, "")}, + {0xd019, 0, 0, 2, f(Yes, false, "")}, + {0xd034, 0, 0, 1, f(Yes, true, "")}, + {0xd035, 0, 0, 2, f(Yes, false, "")}, + {0xd050, 0, 0, 1, f(Yes, true, "")}, + {0xd051, 0, 0, 2, f(Yes, false, "")}, + {0xd06c, 0, 0, 1, f(Yes, true, "")}, + {0xd06d, 0, 0, 2, f(Yes, false, "")}, + {0xd088, 0, 0, 1, f(Yes, true, "")}, + {0xd089, 0, 0, 2, f(Yes, false, "")}, + {0xd0a4, 0, 0, 1, f(Yes, true, "")}, + {0xd0a5, 0, 0, 2, f(Yes, false, "")}, + {0xd0c0, 0, 0, 1, f(Yes, true, "")}, + {0xd0c1, 0, 0, 2, f(Yes, false, "")}, + {0xd0dc, 0, 0, 1, f(Yes, true, "")}, + {0xd0dd, 0, 0, 2, f(Yes, false, "")}, + {0xd0f8, 0, 0, 1, f(Yes, true, "")}, + {0xd0f9, 0, 0, 2, f(Yes, false, "")}, + {0xd114, 0, 0, 1, f(Yes, true, "")}, + {0xd115, 0, 0, 2, f(Yes, false, "")}, + {0xd130, 0, 0, 1, f(Yes, true, "")}, + {0xd131, 0, 0, 2, f(Yes, false, "")}, + {0xd14c, 0, 0, 1, f(Yes, true, "")}, + {0xd14d, 0, 0, 2, f(Yes, false, "")}, + {0xd168, 0, 0, 1, f(Yes, true, "")}, + {0xd169, 0, 0, 2, f(Yes, false, "")}, + {0xd184, 0, 0, 1, f(Yes, true, "")}, + {0xd185, 0, 0, 2, f(Yes, false, "")}, + {0xd1a0, 0, 0, 1, f(Yes, true, "")}, + {0xd1a1, 0, 0, 2, f(Yes, false, "")}, + {0xd1bc, 0, 0, 1, f(Yes, true, "")}, + {0xd1bd, 0, 0, 2, f(Yes, false, "")}, + {0xd1d8, 0, 0, 1, f(Yes, true, "")}, + {0xd1d9, 0, 0, 2, f(Yes, false, "")}, + {0xd1f4, 0, 0, 1, f(Yes, true, "")}, + {0xd1f5, 0, 0, 2, f(Yes, false, "")}, + {0xd210, 0, 0, 1, f(Yes, true, "")}, + {0xd211, 0, 0, 2, f(Yes, false, "")}, + {0xd22c, 0, 0, 1, f(Yes, true, "")}, + {0xd22d, 0, 0, 2, f(Yes, false, "")}, + {0xd248, 0, 0, 1, f(Yes, true, "")}, + {0xd249, 0, 0, 2, f(Yes, false, "")}, + {0xd264, 0, 0, 1, f(Yes, true, "")}, + {0xd265, 0, 0, 2, f(Yes, false, "")}, + {0xd280, 0, 0, 1, f(Yes, true, "")}, + {0xd281, 0, 0, 2, f(Yes, false, "")}, + {0xd29c, 0, 0, 1, f(Yes, true, "")}, + {0xd29d, 0, 0, 2, f(Yes, false, "")}, + {0xd2b8, 0, 0, 1, f(Yes, true, "")}, + {0xd2b9, 0, 0, 2, f(Yes, false, "")}, + {0xd2d4, 0, 0, 1, f(Yes, true, "")}, + {0xd2d5, 0, 0, 2, f(Yes, false, "")}, + {0xd2f0, 0, 0, 1, f(Yes, true, "")}, + {0xd2f1, 0, 0, 2, f(Yes, false, "")}, + {0xd30c, 0, 0, 1, f(Yes, true, "")}, + {0xd30d, 0, 0, 2, f(Yes, false, "")}, + {0xd328, 0, 0, 1, f(Yes, true, "")}, + {0xd329, 0, 0, 2, f(Yes, false, "")}, + {0xd344, 0, 0, 1, f(Yes, true, "")}, + {0xd345, 0, 0, 2, f(Yes, false, "")}, + {0xd360, 0, 0, 1, f(Yes, true, "")}, + {0xd361, 0, 0, 2, f(Yes, false, "")}, + {0xd37c, 0, 0, 1, f(Yes, true, "")}, + {0xd37d, 0, 0, 2, f(Yes, false, "")}, + {0xd398, 0, 0, 1, f(Yes, true, "")}, + {0xd399, 0, 0, 2, f(Yes, false, "")}, + {0xd3b4, 0, 0, 1, f(Yes, true, "")}, + {0xd3b5, 0, 0, 2, f(Yes, false, "")}, + {0xd3d0, 0, 0, 1, f(Yes, true, "")}, + {0xd3d1, 0, 0, 2, f(Yes, false, "")}, + {0xd3ec, 0, 0, 1, f(Yes, true, "")}, + {0xd3ed, 0, 0, 2, f(Yes, false, "")}, + {0xd408, 0, 0, 1, f(Yes, true, "")}, + {0xd409, 0, 0, 2, f(Yes, false, "")}, + {0xd424, 0, 0, 1, f(Yes, true, "")}, + {0xd425, 0, 0, 2, f(Yes, false, "")}, + {0xd440, 0, 0, 1, f(Yes, true, "")}, + {0xd441, 0, 0, 2, f(Yes, false, "")}, + {0xd45c, 0, 0, 1, f(Yes, true, "")}, + {0xd45d, 0, 0, 2, f(Yes, false, "")}, + {0xd478, 0, 0, 1, f(Yes, true, "")}, + {0xd479, 0, 0, 2, f(Yes, false, "")}, + {0xd494, 0, 0, 1, f(Yes, true, "")}, + {0xd495, 0, 0, 2, f(Yes, false, "")}, + {0xd4b0, 0, 0, 1, f(Yes, true, "")}, + {0xd4b1, 0, 0, 2, f(Yes, false, "")}, + {0xd4cc, 0, 0, 1, f(Yes, true, "")}, + {0xd4cd, 0, 0, 2, f(Yes, false, "")}, + {0xd4e8, 0, 0, 1, f(Yes, true, "")}, + {0xd4e9, 0, 0, 2, f(Yes, false, "")}, + {0xd504, 0, 0, 1, f(Yes, true, "")}, + {0xd505, 0, 0, 2, f(Yes, false, "")}, + {0xd520, 0, 0, 1, f(Yes, true, "")}, + {0xd521, 0, 0, 2, f(Yes, false, "")}, + {0xd53c, 0, 0, 1, f(Yes, true, "")}, + {0xd53d, 0, 0, 2, f(Yes, false, "")}, + {0xd558, 0, 0, 1, f(Yes, true, "")}, + {0xd559, 0, 0, 2, f(Yes, false, "")}, + {0xd574, 0, 0, 1, f(Yes, true, "")}, + {0xd575, 0, 0, 2, f(Yes, false, "")}, + {0xd590, 0, 0, 1, f(Yes, true, "")}, + {0xd591, 0, 0, 2, f(Yes, false, "")}, + {0xd5ac, 0, 0, 1, f(Yes, true, "")}, + {0xd5ad, 0, 0, 2, f(Yes, false, "")}, + {0xd5c8, 0, 0, 1, f(Yes, true, "")}, + {0xd5c9, 0, 0, 2, f(Yes, false, "")}, + {0xd5e4, 0, 0, 1, f(Yes, true, "")}, + {0xd5e5, 0, 0, 2, f(Yes, false, "")}, + {0xd600, 0, 0, 1, f(Yes, true, "")}, + {0xd601, 0, 0, 2, f(Yes, false, "")}, + {0xd61c, 0, 0, 1, f(Yes, true, "")}, + {0xd61d, 0, 0, 2, f(Yes, false, "")}, + {0xd638, 0, 0, 1, f(Yes, true, "")}, + {0xd639, 0, 0, 2, f(Yes, false, "")}, + {0xd654, 0, 0, 1, f(Yes, true, "")}, + {0xd655, 0, 0, 2, f(Yes, false, "")}, + {0xd670, 0, 0, 1, f(Yes, true, "")}, + {0xd671, 0, 0, 2, f(Yes, false, "")}, + {0xd68c, 0, 0, 1, f(Yes, true, "")}, + {0xd68d, 0, 0, 2, f(Yes, false, "")}, + {0xd6a8, 0, 0, 1, f(Yes, true, "")}, + {0xd6a9, 0, 0, 2, f(Yes, false, "")}, + {0xd6c4, 0, 0, 1, f(Yes, true, "")}, + {0xd6c5, 0, 0, 2, f(Yes, false, "")}, + {0xd6e0, 0, 0, 1, f(Yes, true, "")}, + {0xd6e1, 0, 0, 2, f(Yes, false, "")}, + {0xd6fc, 0, 0, 1, f(Yes, true, "")}, + {0xd6fd, 0, 0, 2, f(Yes, false, "")}, + {0xd718, 0, 0, 1, f(Yes, true, "")}, + {0xd719, 0, 0, 2, f(Yes, false, "")}, + {0xd734, 0, 0, 1, f(Yes, true, "")}, + {0xd735, 0, 0, 2, f(Yes, false, "")}, + {0xd750, 0, 0, 1, f(Yes, true, "")}, + {0xd751, 0, 0, 2, f(Yes, false, "")}, + {0xd76c, 0, 0, 1, f(Yes, true, "")}, + {0xd76d, 0, 0, 2, f(Yes, false, "")}, + {0xd788, 0, 0, 1, f(Yes, true, "")}, + {0xd789, 0, 0, 2, f(Yes, false, "")}, + {0xd7a4, 0, 0, 0, f(Yes, false, "")}, + {0xf900, 0, 0, 0, f(No, false, "豈")}, + {0xf901, 0, 0, 0, f(No, false, "更")}, + {0xf902, 0, 0, 0, f(No, false, "車")}, + {0xf903, 0, 0, 0, f(No, false, "賈")}, + {0xf904, 0, 0, 0, f(No, false, "滑")}, + {0xf905, 0, 0, 0, f(No, false, "串")}, + {0xf906, 0, 0, 0, f(No, false, "句")}, + {0xf907, 0, 0, 0, f(No, false, "龜")}, + {0xf909, 0, 0, 0, f(No, false, "契")}, + {0xf90a, 0, 0, 0, f(No, false, "金")}, + {0xf90b, 0, 0, 0, f(No, false, "喇")}, + {0xf90c, 0, 0, 0, f(No, false, "奈")}, + {0xf90d, 0, 0, 0, f(No, false, "懶")}, + {0xf90e, 0, 0, 0, f(No, false, "癩")}, + {0xf90f, 0, 0, 0, f(No, false, "羅")}, + {0xf910, 0, 0, 0, f(No, false, "蘿")}, + {0xf911, 0, 0, 0, f(No, false, "螺")}, + {0xf912, 0, 0, 0, f(No, false, "裸")}, + {0xf913, 0, 0, 0, f(No, false, "邏")}, + {0xf914, 0, 0, 0, f(No, false, "樂")}, + {0xf915, 0, 0, 0, f(No, false, "洛")}, + {0xf916, 0, 0, 0, f(No, false, "烙")}, + {0xf917, 0, 0, 0, f(No, false, "珞")}, + {0xf918, 0, 0, 0, f(No, false, "落")}, + {0xf919, 0, 0, 0, f(No, false, "酪")}, + {0xf91a, 0, 0, 0, f(No, false, "駱")}, + {0xf91b, 0, 0, 0, f(No, false, "亂")}, + {0xf91c, 0, 0, 0, f(No, false, "卵")}, + {0xf91d, 0, 0, 0, f(No, false, "欄")}, + {0xf91e, 0, 0, 0, f(No, false, "爛")}, + {0xf91f, 0, 0, 0, f(No, false, "蘭")}, + {0xf920, 0, 0, 0, f(No, false, "鸞")}, + {0xf921, 0, 0, 0, f(No, false, "嵐")}, + {0xf922, 0, 0, 0, f(No, false, "濫")}, + {0xf923, 0, 0, 0, f(No, false, "藍")}, + {0xf924, 0, 0, 0, f(No, false, "襤")}, + {0xf925, 0, 0, 0, f(No, false, "拉")}, + {0xf926, 0, 0, 0, f(No, false, "臘")}, + {0xf927, 0, 0, 0, f(No, false, "蠟")}, + {0xf928, 0, 0, 0, f(No, false, "廊")}, + {0xf929, 0, 0, 0, f(No, false, "朗")}, + {0xf92a, 0, 0, 0, f(No, false, "浪")}, + {0xf92b, 0, 0, 0, f(No, false, "狼")}, + {0xf92c, 0, 0, 0, f(No, false, "郎")}, + {0xf92d, 0, 0, 0, f(No, false, "來")}, + {0xf92e, 0, 0, 0, f(No, false, "冷")}, + {0xf92f, 0, 0, 0, f(No, false, "勞")}, + {0xf930, 0, 0, 0, f(No, false, "擄")}, + {0xf931, 0, 0, 0, f(No, false, "櫓")}, + {0xf932, 0, 0, 0, f(No, false, "爐")}, + {0xf933, 0, 0, 0, f(No, false, "盧")}, + {0xf934, 0, 0, 0, f(No, false, "老")}, + {0xf935, 0, 0, 0, f(No, false, "蘆")}, + {0xf936, 0, 0, 0, f(No, false, "虜")}, + {0xf937, 0, 0, 0, f(No, false, "路")}, + {0xf938, 0, 0, 0, f(No, false, "露")}, + {0xf939, 0, 0, 0, f(No, false, "魯")}, + {0xf93a, 0, 0, 0, f(No, false, "鷺")}, + {0xf93b, 0, 0, 0, f(No, false, "碌")}, + {0xf93c, 0, 0, 0, f(No, false, "祿")}, + {0xf93d, 0, 0, 0, f(No, false, "綠")}, + {0xf93e, 0, 0, 0, f(No, false, "菉")}, + {0xf93f, 0, 0, 0, f(No, false, "錄")}, + {0xf940, 0, 0, 0, f(No, false, "鹿")}, + {0xf941, 0, 0, 0, f(No, false, "論")}, + {0xf942, 0, 0, 0, f(No, false, "壟")}, + {0xf943, 0, 0, 0, f(No, false, "弄")}, + {0xf944, 0, 0, 0, f(No, false, "籠")}, + {0xf945, 0, 0, 0, f(No, false, "聾")}, + {0xf946, 0, 0, 0, f(No, false, "牢")}, + {0xf947, 0, 0, 0, f(No, false, "磊")}, + {0xf948, 0, 0, 0, f(No, false, "賂")}, + {0xf949, 0, 0, 0, f(No, false, "雷")}, + {0xf94a, 0, 0, 0, f(No, false, "壘")}, + {0xf94b, 0, 0, 0, f(No, false, "屢")}, + {0xf94c, 0, 0, 0, f(No, false, "樓")}, + {0xf94d, 0, 0, 0, f(No, false, "淚")}, + {0xf94e, 0, 0, 0, f(No, false, "漏")}, + {0xf94f, 0, 0, 0, f(No, false, "累")}, + {0xf950, 0, 0, 0, f(No, false, "縷")}, + {0xf951, 0, 0, 0, f(No, false, "陋")}, + {0xf952, 0, 0, 0, f(No, false, "勒")}, + {0xf953, 0, 0, 0, f(No, false, "肋")}, + {0xf954, 0, 0, 0, f(No, false, "凜")}, + {0xf955, 0, 0, 0, f(No, false, "凌")}, + {0xf956, 0, 0, 0, f(No, false, "稜")}, + {0xf957, 0, 0, 0, f(No, false, "綾")}, + {0xf958, 0, 0, 0, f(No, false, "菱")}, + {0xf959, 0, 0, 0, f(No, false, "陵")}, + {0xf95a, 0, 0, 0, f(No, false, "讀")}, + {0xf95b, 0, 0, 0, f(No, false, "拏")}, + {0xf95c, 0, 0, 0, f(No, false, "樂")}, + {0xf95d, 0, 0, 0, f(No, false, "諾")}, + {0xf95e, 0, 0, 0, f(No, false, "丹")}, + {0xf95f, 0, 0, 0, f(No, false, "寧")}, + {0xf960, 0, 0, 0, f(No, false, "怒")}, + {0xf961, 0, 0, 0, f(No, false, "率")}, + {0xf962, 0, 0, 0, f(No, false, "異")}, + {0xf963, 0, 0, 0, f(No, false, "北")}, + {0xf964, 0, 0, 0, f(No, false, "磻")}, + {0xf965, 0, 0, 0, f(No, false, "便")}, + {0xf966, 0, 0, 0, f(No, false, "復")}, + {0xf967, 0, 0, 0, f(No, false, "不")}, + {0xf968, 0, 0, 0, f(No, false, "泌")}, + {0xf969, 0, 0, 0, f(No, false, "數")}, + {0xf96a, 0, 0, 0, f(No, false, "索")}, + {0xf96b, 0, 0, 0, f(No, false, "參")}, + {0xf96c, 0, 0, 0, f(No, false, "塞")}, + {0xf96d, 0, 0, 0, f(No, false, "省")}, + {0xf96e, 0, 0, 0, f(No, false, "葉")}, + {0xf96f, 0, 0, 0, f(No, false, "說")}, + {0xf970, 0, 0, 0, f(No, false, "殺")}, + {0xf971, 0, 0, 0, f(No, false, "辰")}, + {0xf972, 0, 0, 0, f(No, false, "沈")}, + {0xf973, 0, 0, 0, f(No, false, "拾")}, + {0xf974, 0, 0, 0, f(No, false, "若")}, + {0xf975, 0, 0, 0, f(No, false, "掠")}, + {0xf976, 0, 0, 0, f(No, false, "略")}, + {0xf977, 0, 0, 0, f(No, false, "亮")}, + {0xf978, 0, 0, 0, f(No, false, "兩")}, + {0xf979, 0, 0, 0, f(No, false, "凉")}, + {0xf97a, 0, 0, 0, f(No, false, "梁")}, + {0xf97b, 0, 0, 0, f(No, false, "糧")}, + {0xf97c, 0, 0, 0, f(No, false, "良")}, + {0xf97d, 0, 0, 0, f(No, false, "諒")}, + {0xf97e, 0, 0, 0, f(No, false, "量")}, + {0xf97f, 0, 0, 0, f(No, false, "勵")}, + {0xf980, 0, 0, 0, f(No, false, "呂")}, + {0xf981, 0, 0, 0, f(No, false, "女")}, + {0xf982, 0, 0, 0, f(No, false, "廬")}, + {0xf983, 0, 0, 0, f(No, false, "旅")}, + {0xf984, 0, 0, 0, f(No, false, "濾")}, + {0xf985, 0, 0, 0, f(No, false, "礪")}, + {0xf986, 0, 0, 0, f(No, false, "閭")}, + {0xf987, 0, 0, 0, f(No, false, "驪")}, + {0xf988, 0, 0, 0, f(No, false, "麗")}, + {0xf989, 0, 0, 0, f(No, false, "黎")}, + {0xf98a, 0, 0, 0, f(No, false, "力")}, + {0xf98b, 0, 0, 0, f(No, false, "曆")}, + {0xf98c, 0, 0, 0, f(No, false, "歷")}, + {0xf98d, 0, 0, 0, f(No, false, "轢")}, + {0xf98e, 0, 0, 0, f(No, false, "年")}, + {0xf98f, 0, 0, 0, f(No, false, "憐")}, + {0xf990, 0, 0, 0, f(No, false, "戀")}, + {0xf991, 0, 0, 0, f(No, false, "撚")}, + {0xf992, 0, 0, 0, f(No, false, "漣")}, + {0xf993, 0, 0, 0, f(No, false, "煉")}, + {0xf994, 0, 0, 0, f(No, false, "璉")}, + {0xf995, 0, 0, 0, f(No, false, "秊")}, + {0xf996, 0, 0, 0, f(No, false, "練")}, + {0xf997, 0, 0, 0, f(No, false, "聯")}, + {0xf998, 0, 0, 0, f(No, false, "輦")}, + {0xf999, 0, 0, 0, f(No, false, "蓮")}, + {0xf99a, 0, 0, 0, f(No, false, "連")}, + {0xf99b, 0, 0, 0, f(No, false, "鍊")}, + {0xf99c, 0, 0, 0, f(No, false, "列")}, + {0xf99d, 0, 0, 0, f(No, false, "劣")}, + {0xf99e, 0, 0, 0, f(No, false, "咽")}, + {0xf99f, 0, 0, 0, f(No, false, "烈")}, + {0xf9a0, 0, 0, 0, f(No, false, "裂")}, + {0xf9a1, 0, 0, 0, f(No, false, "說")}, + {0xf9a2, 0, 0, 0, f(No, false, "廉")}, + {0xf9a3, 0, 0, 0, f(No, false, "念")}, + {0xf9a4, 0, 0, 0, f(No, false, "捻")}, + {0xf9a5, 0, 0, 0, f(No, false, "殮")}, + {0xf9a6, 0, 0, 0, f(No, false, "簾")}, + {0xf9a7, 0, 0, 0, f(No, false, "獵")}, + {0xf9a8, 0, 0, 0, f(No, false, "令")}, + {0xf9a9, 0, 0, 0, f(No, false, "囹")}, + {0xf9aa, 0, 0, 0, f(No, false, "寧")}, + {0xf9ab, 0, 0, 0, f(No, false, "嶺")}, + {0xf9ac, 0, 0, 0, f(No, false, "怜")}, + {0xf9ad, 0, 0, 0, f(No, false, "玲")}, + {0xf9ae, 0, 0, 0, f(No, false, "瑩")}, + {0xf9af, 0, 0, 0, f(No, false, "羚")}, + {0xf9b0, 0, 0, 0, f(No, false, "聆")}, + {0xf9b1, 0, 0, 0, f(No, false, "鈴")}, + {0xf9b2, 0, 0, 0, f(No, false, "零")}, + {0xf9b3, 0, 0, 0, f(No, false, "靈")}, + {0xf9b4, 0, 0, 0, f(No, false, "領")}, + {0xf9b5, 0, 0, 0, f(No, false, "例")}, + {0xf9b6, 0, 0, 0, f(No, false, "禮")}, + {0xf9b7, 0, 0, 0, f(No, false, "醴")}, + {0xf9b8, 0, 0, 0, f(No, false, "隸")}, + {0xf9b9, 0, 0, 0, f(No, false, "惡")}, + {0xf9ba, 0, 0, 0, f(No, false, "了")}, + {0xf9bb, 0, 0, 0, f(No, false, "僚")}, + {0xf9bc, 0, 0, 0, f(No, false, "寮")}, + {0xf9bd, 0, 0, 0, f(No, false, "尿")}, + {0xf9be, 0, 0, 0, f(No, false, "料")}, + {0xf9bf, 0, 0, 0, f(No, false, "樂")}, + {0xf9c0, 0, 0, 0, f(No, false, "燎")}, + {0xf9c1, 0, 0, 0, f(No, false, "療")}, + {0xf9c2, 0, 0, 0, f(No, false, "蓼")}, + {0xf9c3, 0, 0, 0, f(No, false, "遼")}, + {0xf9c4, 0, 0, 0, f(No, false, "龍")}, + {0xf9c5, 0, 0, 0, f(No, false, "暈")}, + {0xf9c6, 0, 0, 0, f(No, false, "阮")}, + {0xf9c7, 0, 0, 0, f(No, false, "劉")}, + {0xf9c8, 0, 0, 0, f(No, false, "杻")}, + {0xf9c9, 0, 0, 0, f(No, false, "柳")}, + {0xf9ca, 0, 0, 0, f(No, false, "流")}, + {0xf9cb, 0, 0, 0, f(No, false, "溜")}, + {0xf9cc, 0, 0, 0, f(No, false, "琉")}, + {0xf9cd, 0, 0, 0, f(No, false, "留")}, + {0xf9ce, 0, 0, 0, f(No, false, "硫")}, + {0xf9cf, 0, 0, 0, f(No, false, "紐")}, + {0xf9d0, 0, 0, 0, f(No, false, "類")}, + {0xf9d1, 0, 0, 0, f(No, false, "六")}, + {0xf9d2, 0, 0, 0, f(No, false, "戮")}, + {0xf9d3, 0, 0, 0, f(No, false, "陸")}, + {0xf9d4, 0, 0, 0, f(No, false, "倫")}, + {0xf9d5, 0, 0, 0, f(No, false, "崙")}, + {0xf9d6, 0, 0, 0, f(No, false, "淪")}, + {0xf9d7, 0, 0, 0, f(No, false, "輪")}, + {0xf9d8, 0, 0, 0, f(No, false, "律")}, + {0xf9d9, 0, 0, 0, f(No, false, "慄")}, + {0xf9da, 0, 0, 0, f(No, false, "栗")}, + {0xf9db, 0, 0, 0, f(No, false, "率")}, + {0xf9dc, 0, 0, 0, f(No, false, "隆")}, + {0xf9dd, 0, 0, 0, f(No, false, "利")}, + {0xf9de, 0, 0, 0, f(No, false, "吏")}, + {0xf9df, 0, 0, 0, f(No, false, "履")}, + {0xf9e0, 0, 0, 0, f(No, false, "易")}, + {0xf9e1, 0, 0, 0, f(No, false, "李")}, + {0xf9e2, 0, 0, 0, f(No, false, "梨")}, + {0xf9e3, 0, 0, 0, f(No, false, "泥")}, + {0xf9e4, 0, 0, 0, f(No, false, "理")}, + {0xf9e5, 0, 0, 0, f(No, false, "痢")}, + {0xf9e6, 0, 0, 0, f(No, false, "罹")}, + {0xf9e7, 0, 0, 0, f(No, false, "裏")}, + {0xf9e8, 0, 0, 0, f(No, false, "裡")}, + {0xf9e9, 0, 0, 0, f(No, false, "里")}, + {0xf9ea, 0, 0, 0, f(No, false, "離")}, + {0xf9eb, 0, 0, 0, f(No, false, "匿")}, + {0xf9ec, 0, 0, 0, f(No, false, "溺")}, + {0xf9ed, 0, 0, 0, f(No, false, "吝")}, + {0xf9ee, 0, 0, 0, f(No, false, "燐")}, + {0xf9ef, 0, 0, 0, f(No, false, "璘")}, + {0xf9f0, 0, 0, 0, f(No, false, "藺")}, + {0xf9f1, 0, 0, 0, f(No, false, "隣")}, + {0xf9f2, 0, 0, 0, f(No, false, "鱗")}, + {0xf9f3, 0, 0, 0, f(No, false, "麟")}, + {0xf9f4, 0, 0, 0, f(No, false, "林")}, + {0xf9f5, 0, 0, 0, f(No, false, "淋")}, + {0xf9f6, 0, 0, 0, f(No, false, "臨")}, + {0xf9f7, 0, 0, 0, f(No, false, "立")}, + {0xf9f8, 0, 0, 0, f(No, false, "笠")}, + {0xf9f9, 0, 0, 0, f(No, false, "粒")}, + {0xf9fa, 0, 0, 0, f(No, false, "狀")}, + {0xf9fb, 0, 0, 0, f(No, false, "炙")}, + {0xf9fc, 0, 0, 0, f(No, false, "識")}, + {0xf9fd, 0, 0, 0, f(No, false, "什")}, + {0xf9fe, 0, 0, 0, f(No, false, "茶")}, + {0xf9ff, 0, 0, 0, f(No, false, "刺")}, + {0xfa00, 0, 0, 0, f(No, false, "切")}, + {0xfa01, 0, 0, 0, f(No, false, "度")}, + {0xfa02, 0, 0, 0, f(No, false, "拓")}, + {0xfa03, 0, 0, 0, f(No, false, "糖")}, + {0xfa04, 0, 0, 0, f(No, false, "宅")}, + {0xfa05, 0, 0, 0, f(No, false, "洞")}, + {0xfa06, 0, 0, 0, f(No, false, "暴")}, + {0xfa07, 0, 0, 0, f(No, false, "輻")}, + {0xfa08, 0, 0, 0, f(No, false, "行")}, + {0xfa09, 0, 0, 0, f(No, false, "降")}, + {0xfa0a, 0, 0, 0, f(No, false, "見")}, + {0xfa0b, 0, 0, 0, f(No, false, "廓")}, + {0xfa0c, 0, 0, 0, f(No, false, "兀")}, + {0xfa0d, 0, 0, 0, f(No, false, "嗀")}, + {0xfa0e, 0, 0, 0, f(Yes, false, "")}, + {0xfa10, 0, 0, 0, f(No, false, "塚")}, + {0xfa11, 0, 0, 0, f(Yes, false, "")}, + {0xfa12, 0, 0, 0, f(No, false, "晴")}, + {0xfa13, 0, 0, 0, f(Yes, false, "")}, + {0xfa15, 0, 0, 0, f(No, false, "凞")}, + {0xfa16, 0, 0, 0, f(No, false, "猪")}, + {0xfa17, 0, 0, 0, f(No, false, "益")}, + {0xfa18, 0, 0, 0, f(No, false, "礼")}, + {0xfa19, 0, 0, 0, f(No, false, "神")}, + {0xfa1a, 0, 0, 0, f(No, false, "祥")}, + {0xfa1b, 0, 0, 0, f(No, false, "福")}, + {0xfa1c, 0, 0, 0, f(No, false, "靖")}, + {0xfa1d, 0, 0, 0, f(No, false, "精")}, + {0xfa1e, 0, 0, 0, f(No, false, "羽")}, + {0xfa1f, 0, 0, 0, f(Yes, false, "")}, + {0xfa20, 0, 0, 0, f(No, false, "蘒")}, + {0xfa21, 0, 0, 0, f(Yes, false, "")}, + {0xfa22, 0, 0, 0, f(No, false, "諸")}, + {0xfa23, 0, 0, 0, f(Yes, false, "")}, + {0xfa25, 0, 0, 0, f(No, false, "逸")}, + {0xfa26, 0, 0, 0, f(No, false, "都")}, + {0xfa27, 0, 0, 0, f(Yes, false, "")}, + {0xfa2a, 0, 0, 0, f(No, false, "飯")}, + {0xfa2b, 0, 0, 0, f(No, false, "飼")}, + {0xfa2c, 0, 0, 0, f(No, false, "館")}, + {0xfa2d, 0, 0, 0, f(No, false, "鶴")}, + {0xfa2e, 0, 0, 0, f(No, false, "郞")}, + {0xfa2f, 0, 0, 0, f(No, false, "隷")}, + {0xfa30, 0, 0, 0, f(No, false, "侮")}, + {0xfa31, 0, 0, 0, f(No, false, "僧")}, + {0xfa32, 0, 0, 0, f(No, false, "免")}, + {0xfa33, 0, 0, 0, f(No, false, "勉")}, + {0xfa34, 0, 0, 0, f(No, false, "勤")}, + {0xfa35, 0, 0, 0, f(No, false, "卑")}, + {0xfa36, 0, 0, 0, f(No, false, "喝")}, + {0xfa37, 0, 0, 0, f(No, false, "嘆")}, + {0xfa38, 0, 0, 0, f(No, false, "器")}, + {0xfa39, 0, 0, 0, f(No, false, "塀")}, + {0xfa3a, 0, 0, 0, f(No, false, "墨")}, + {0xfa3b, 0, 0, 0, f(No, false, "層")}, + {0xfa3c, 0, 0, 0, f(No, false, "屮")}, + {0xfa3d, 0, 0, 0, f(No, false, "悔")}, + {0xfa3e, 0, 0, 0, f(No, false, "慨")}, + {0xfa3f, 0, 0, 0, f(No, false, "憎")}, + {0xfa40, 0, 0, 0, f(No, false, "懲")}, + {0xfa41, 0, 0, 0, f(No, false, "敏")}, + {0xfa42, 0, 0, 0, f(No, false, "既")}, + {0xfa43, 0, 0, 0, f(No, false, "暑")}, + {0xfa44, 0, 0, 0, f(No, false, "梅")}, + {0xfa45, 0, 0, 0, f(No, false, "海")}, + {0xfa46, 0, 0, 0, f(No, false, "渚")}, + {0xfa47, 0, 0, 0, f(No, false, "漢")}, + {0xfa48, 0, 0, 0, f(No, false, "煮")}, + {0xfa49, 0, 0, 0, f(No, false, "爫")}, + {0xfa4a, 0, 0, 0, f(No, false, "琢")}, + {0xfa4b, 0, 0, 0, f(No, false, "碑")}, + {0xfa4c, 0, 0, 0, f(No, false, "社")}, + {0xfa4d, 0, 0, 0, f(No, false, "祉")}, + {0xfa4e, 0, 0, 0, f(No, false, "祈")}, + {0xfa4f, 0, 0, 0, f(No, false, "祐")}, + {0xfa50, 0, 0, 0, f(No, false, "祖")}, + {0xfa51, 0, 0, 0, f(No, false, "祝")}, + {0xfa52, 0, 0, 0, f(No, false, "禍")}, + {0xfa53, 0, 0, 0, f(No, false, "禎")}, + {0xfa54, 0, 0, 0, f(No, false, "穀")}, + {0xfa55, 0, 0, 0, f(No, false, "突")}, + {0xfa56, 0, 0, 0, f(No, false, "節")}, + {0xfa57, 0, 0, 0, f(No, false, "練")}, + {0xfa58, 0, 0, 0, f(No, false, "縉")}, + {0xfa59, 0, 0, 0, f(No, false, "繁")}, + {0xfa5a, 0, 0, 0, f(No, false, "署")}, + {0xfa5b, 0, 0, 0, f(No, false, "者")}, + {0xfa5c, 0, 0, 0, f(No, false, "臭")}, + {0xfa5d, 0, 0, 0, f(No, false, "艹")}, + {0xfa5f, 0, 0, 0, f(No, false, "著")}, + {0xfa60, 0, 0, 0, f(No, false, "褐")}, + {0xfa61, 0, 0, 0, f(No, false, "視")}, + {0xfa62, 0, 0, 0, f(No, false, "謁")}, + {0xfa63, 0, 0, 0, f(No, false, "謹")}, + {0xfa64, 0, 0, 0, f(No, false, "賓")}, + {0xfa65, 0, 0, 0, f(No, false, "贈")}, + {0xfa66, 0, 0, 0, f(No, false, "辶")}, + {0xfa67, 0, 0, 0, f(No, false, "逸")}, + {0xfa68, 0, 0, 0, f(No, false, "難")}, + {0xfa69, 0, 0, 0, f(No, false, "響")}, + {0xfa6a, 0, 0, 0, f(No, false, "頻")}, + {0xfa6b, 0, 0, 0, f(No, false, "恵")}, + {0xfa6c, 0, 0, 0, f(No, false, "𤋮")}, + {0xfa6d, 0, 0, 0, f(No, false, "舘")}, + {0xfa6e, 0, 0, 0, f(Yes, false, "")}, + {0xfa70, 0, 0, 0, f(No, false, "並")}, + {0xfa71, 0, 0, 0, f(No, false, "况")}, + {0xfa72, 0, 0, 0, f(No, false, "全")}, + {0xfa73, 0, 0, 0, f(No, false, "侀")}, + {0xfa74, 0, 0, 0, f(No, false, "充")}, + {0xfa75, 0, 0, 0, f(No, false, "冀")}, + {0xfa76, 0, 0, 0, f(No, false, "勇")}, + {0xfa77, 0, 0, 0, f(No, false, "勺")}, + {0xfa78, 0, 0, 0, f(No, false, "喝")}, + {0xfa79, 0, 0, 0, f(No, false, "啕")}, + {0xfa7a, 0, 0, 0, f(No, false, "喙")}, + {0xfa7b, 0, 0, 0, f(No, false, "嗢")}, + {0xfa7c, 0, 0, 0, f(No, false, "塚")}, + {0xfa7d, 0, 0, 0, f(No, false, "墳")}, + {0xfa7e, 0, 0, 0, f(No, false, "奄")}, + {0xfa7f, 0, 0, 0, f(No, false, "奔")}, + {0xfa80, 0, 0, 0, f(No, false, "婢")}, + {0xfa81, 0, 0, 0, f(No, false, "嬨")}, + {0xfa82, 0, 0, 0, f(No, false, "廒")}, + {0xfa83, 0, 0, 0, f(No, false, "廙")}, + {0xfa84, 0, 0, 0, f(No, false, "彩")}, + {0xfa85, 0, 0, 0, f(No, false, "徭")}, + {0xfa86, 0, 0, 0, f(No, false, "惘")}, + {0xfa87, 0, 0, 0, f(No, false, "慎")}, + {0xfa88, 0, 0, 0, f(No, false, "愈")}, + {0xfa89, 0, 0, 0, f(No, false, "憎")}, + {0xfa8a, 0, 0, 0, f(No, false, "慠")}, + {0xfa8b, 0, 0, 0, f(No, false, "懲")}, + {0xfa8c, 0, 0, 0, f(No, false, "戴")}, + {0xfa8d, 0, 0, 0, f(No, false, "揄")}, + {0xfa8e, 0, 0, 0, f(No, false, "搜")}, + {0xfa8f, 0, 0, 0, f(No, false, "摒")}, + {0xfa90, 0, 0, 0, f(No, false, "敖")}, + {0xfa91, 0, 0, 0, f(No, false, "晴")}, + {0xfa92, 0, 0, 0, f(No, false, "朗")}, + {0xfa93, 0, 0, 0, f(No, false, "望")}, + {0xfa94, 0, 0, 0, f(No, false, "杖")}, + {0xfa95, 0, 0, 0, f(No, false, "歹")}, + {0xfa96, 0, 0, 0, f(No, false, "殺")}, + {0xfa97, 0, 0, 0, f(No, false, "流")}, + {0xfa98, 0, 0, 0, f(No, false, "滛")}, + {0xfa99, 0, 0, 0, f(No, false, "滋")}, + {0xfa9a, 0, 0, 0, f(No, false, "漢")}, + {0xfa9b, 0, 0, 0, f(No, false, "瀞")}, + {0xfa9c, 0, 0, 0, f(No, false, "煮")}, + {0xfa9d, 0, 0, 0, f(No, false, "瞧")}, + {0xfa9e, 0, 0, 0, f(No, false, "爵")}, + {0xfa9f, 0, 0, 0, f(No, false, "犯")}, + {0xfaa0, 0, 0, 0, f(No, false, "猪")}, + {0xfaa1, 0, 0, 0, f(No, false, "瑱")}, + {0xfaa2, 0, 0, 0, f(No, false, "甆")}, + {0xfaa3, 0, 0, 0, f(No, false, "画")}, + {0xfaa4, 0, 0, 0, f(No, false, "瘝")}, + {0xfaa5, 0, 0, 0, f(No, false, "瘟")}, + {0xfaa6, 0, 0, 0, f(No, false, "益")}, + {0xfaa7, 0, 0, 0, f(No, false, "盛")}, + {0xfaa8, 0, 0, 0, f(No, false, "直")}, + {0xfaa9, 0, 0, 0, f(No, false, "睊")}, + {0xfaaa, 0, 0, 0, f(No, false, "着")}, + {0xfaab, 0, 0, 0, f(No, false, "磌")}, + {0xfaac, 0, 0, 0, f(No, false, "窱")}, + {0xfaad, 0, 0, 0, f(No, false, "節")}, + {0xfaae, 0, 0, 0, f(No, false, "类")}, + {0xfaaf, 0, 0, 0, f(No, false, "絛")}, + {0xfab0, 0, 0, 0, f(No, false, "練")}, + {0xfab1, 0, 0, 0, f(No, false, "缾")}, + {0xfab2, 0, 0, 0, f(No, false, "者")}, + {0xfab3, 0, 0, 0, f(No, false, "荒")}, + {0xfab4, 0, 0, 0, f(No, false, "華")}, + {0xfab5, 0, 0, 0, f(No, false, "蝹")}, + {0xfab6, 0, 0, 0, f(No, false, "襁")}, + {0xfab7, 0, 0, 0, f(No, false, "覆")}, + {0xfab8, 0, 0, 0, f(No, false, "視")}, + {0xfab9, 0, 0, 0, f(No, false, "調")}, + {0xfaba, 0, 0, 0, f(No, false, "諸")}, + {0xfabb, 0, 0, 0, f(No, false, "請")}, + {0xfabc, 0, 0, 0, f(No, false, "謁")}, + {0xfabd, 0, 0, 0, f(No, false, "諾")}, + {0xfabe, 0, 0, 0, f(No, false, "諭")}, + {0xfabf, 0, 0, 0, f(No, false, "謹")}, + {0xfac0, 0, 0, 0, f(No, false, "變")}, + {0xfac1, 0, 0, 0, f(No, false, "贈")}, + {0xfac2, 0, 0, 0, f(No, false, "輸")}, + {0xfac3, 0, 0, 0, f(No, false, "遲")}, + {0xfac4, 0, 0, 0, f(No, false, "醙")}, + {0xfac5, 0, 0, 0, f(No, false, "鉶")}, + {0xfac6, 0, 0, 0, f(No, false, "陼")}, + {0xfac7, 0, 0, 0, f(No, false, "難")}, + {0xfac8, 0, 0, 0, f(No, false, "靖")}, + {0xfac9, 0, 0, 0, f(No, false, "韛")}, + {0xfaca, 0, 0, 0, f(No, false, "響")}, + {0xfacb, 0, 0, 0, f(No, false, "頋")}, + {0xfacc, 0, 0, 0, f(No, false, "頻")}, + {0xfacd, 0, 0, 0, f(No, false, "鬒")}, + {0xface, 0, 0, 0, f(No, false, "龜")}, + {0xfacf, 0, 0, 0, f(No, false, "𢡊")}, + {0xfad0, 0, 0, 0, f(No, false, "𢡄")}, + {0xfad1, 0, 0, 0, f(No, false, "𣏕")}, + {0xfad2, 0, 0, 0, f(No, false, "㮝")}, + {0xfad3, 0, 0, 0, f(No, false, "䀘")}, + {0xfad4, 0, 0, 0, f(No, false, "䀹")}, + {0xfad5, 0, 0, 0, f(No, false, "𥉉")}, + {0xfad6, 0, 0, 0, f(No, false, "𥳐")}, + {0xfad7, 0, 0, 0, f(No, false, "𧻓")}, + {0xfad8, 0, 0, 0, f(No, false, "齃")}, + {0xfad9, 0, 0, 0, f(No, false, "龎")}, + {0xfada, 0, 0, 0, f(Yes, false, "")}, + {0xfb00, 0, 0, 0, g(Yes, No, false, false, "", "ff")}, + {0xfb01, 0, 0, 0, g(Yes, No, false, false, "", "fi")}, + {0xfb02, 0, 0, 0, g(Yes, No, false, false, "", "fl")}, + {0xfb03, 0, 0, 0, g(Yes, No, false, false, "", "ffi")}, + {0xfb04, 0, 0, 0, g(Yes, No, false, false, "", "ffl")}, + {0xfb05, 0, 0, 0, g(Yes, No, false, false, "", "st")}, + {0xfb07, 0, 0, 0, f(Yes, false, "")}, + {0xfb13, 0, 0, 0, g(Yes, No, false, false, "", "մն")}, + {0xfb14, 0, 0, 0, g(Yes, No, false, false, "", "մե")}, + {0xfb15, 0, 0, 0, g(Yes, No, false, false, "", "մի")}, + {0xfb16, 0, 0, 0, g(Yes, No, false, false, "", "վն")}, + {0xfb17, 0, 0, 0, g(Yes, No, false, false, "", "մխ")}, + {0xfb18, 0, 0, 0, f(Yes, false, "")}, + {0xfb1d, 0, 0, 1, f(No, false, "יִ")}, + {0xfb1e, 26, 1, 1, f(Yes, false, "")}, + {0xfb1f, 0, 0, 1, f(No, false, "ײַ")}, + {0xfb20, 0, 0, 0, g(Yes, No, false, false, "", "ע")}, + {0xfb21, 0, 0, 0, g(Yes, No, false, false, "", "א")}, + {0xfb22, 0, 0, 0, g(Yes, No, false, false, "", "ד")}, + {0xfb23, 0, 0, 0, g(Yes, No, false, false, "", "ה")}, + {0xfb24, 0, 0, 0, g(Yes, No, false, false, "", "כ")}, + {0xfb25, 0, 0, 0, g(Yes, No, false, false, "", "ל")}, + {0xfb26, 0, 0, 0, g(Yes, No, false, false, "", "ם")}, + {0xfb27, 0, 0, 0, g(Yes, No, false, false, "", "ר")}, + {0xfb28, 0, 0, 0, g(Yes, No, false, false, "", "ת")}, + {0xfb29, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0xfb2a, 0, 0, 1, f(No, false, "שׁ")}, + {0xfb2b, 0, 0, 1, f(No, false, "שׂ")}, + {0xfb2c, 0, 0, 2, f(No, false, "שּׁ")}, + {0xfb2d, 0, 0, 2, f(No, false, "שּׂ")}, + {0xfb2e, 0, 0, 1, f(No, false, "אַ")}, + {0xfb2f, 0, 0, 1, f(No, false, "אָ")}, + {0xfb30, 0, 0, 1, f(No, false, "אּ")}, + {0xfb31, 0, 0, 1, f(No, false, "בּ")}, + {0xfb32, 0, 0, 1, f(No, false, "גּ")}, + {0xfb33, 0, 0, 1, f(No, false, "דּ")}, + {0xfb34, 0, 0, 1, f(No, false, "הּ")}, + {0xfb35, 0, 0, 1, f(No, false, "וּ")}, + {0xfb36, 0, 0, 1, f(No, false, "זּ")}, + {0xfb37, 0, 0, 0, f(Yes, false, "")}, + {0xfb38, 0, 0, 1, f(No, false, "טּ")}, + {0xfb39, 0, 0, 1, f(No, false, "יּ")}, + {0xfb3a, 0, 0, 1, f(No, false, "ךּ")}, + {0xfb3b, 0, 0, 1, f(No, false, "כּ")}, + {0xfb3c, 0, 0, 1, f(No, false, "לּ")}, + {0xfb3d, 0, 0, 0, f(Yes, false, "")}, + {0xfb3e, 0, 0, 1, f(No, false, "מּ")}, + {0xfb3f, 0, 0, 0, f(Yes, false, "")}, + {0xfb40, 0, 0, 1, f(No, false, "נּ")}, + {0xfb41, 0, 0, 1, f(No, false, "סּ")}, + {0xfb42, 0, 0, 0, f(Yes, false, "")}, + {0xfb43, 0, 0, 1, f(No, false, "ףּ")}, + {0xfb44, 0, 0, 1, f(No, false, "פּ")}, + {0xfb45, 0, 0, 0, f(Yes, false, "")}, + {0xfb46, 0, 0, 1, f(No, false, "צּ")}, + {0xfb47, 0, 0, 1, f(No, false, "קּ")}, + {0xfb48, 0, 0, 1, f(No, false, "רּ")}, + {0xfb49, 0, 0, 1, f(No, false, "שּ")}, + {0xfb4a, 0, 0, 1, f(No, false, "תּ")}, + {0xfb4b, 0, 0, 1, f(No, false, "וֹ")}, + {0xfb4c, 0, 0, 1, f(No, false, "בֿ")}, + {0xfb4d, 0, 0, 1, f(No, false, "כֿ")}, + {0xfb4e, 0, 0, 1, f(No, false, "פֿ")}, + {0xfb4f, 0, 0, 0, g(Yes, No, false, false, "", "אל")}, + {0xfb50, 0, 0, 0, g(Yes, No, false, false, "", "ٱ")}, + {0xfb52, 0, 0, 0, g(Yes, No, false, false, "", "ٻ")}, + {0xfb56, 0, 0, 0, g(Yes, No, false, false, "", "پ")}, + {0xfb5a, 0, 0, 0, g(Yes, No, false, false, "", "ڀ")}, + {0xfb5e, 0, 0, 0, g(Yes, No, false, false, "", "ٺ")}, + {0xfb62, 0, 0, 0, g(Yes, No, false, false, "", "ٿ")}, + {0xfb66, 0, 0, 0, g(Yes, No, false, false, "", "ٹ")}, + {0xfb6a, 0, 0, 0, g(Yes, No, false, false, "", "ڤ")}, + {0xfb6e, 0, 0, 0, g(Yes, No, false, false, "", "ڦ")}, + {0xfb72, 0, 0, 0, g(Yes, No, false, false, "", "ڄ")}, + {0xfb76, 0, 0, 0, g(Yes, No, false, false, "", "ڃ")}, + {0xfb7a, 0, 0, 0, g(Yes, No, false, false, "", "چ")}, + {0xfb7e, 0, 0, 0, g(Yes, No, false, false, "", "ڇ")}, + {0xfb82, 0, 0, 0, g(Yes, No, false, false, "", "ڍ")}, + {0xfb84, 0, 0, 0, g(Yes, No, false, false, "", "ڌ")}, + {0xfb86, 0, 0, 0, g(Yes, No, false, false, "", "ڎ")}, + {0xfb88, 0, 0, 0, g(Yes, No, false, false, "", "ڈ")}, + {0xfb8a, 0, 0, 0, g(Yes, No, false, false, "", "ژ")}, + {0xfb8c, 0, 0, 0, g(Yes, No, false, false, "", "ڑ")}, + {0xfb8e, 0, 0, 0, g(Yes, No, false, false, "", "ک")}, + {0xfb92, 0, 0, 0, g(Yes, No, false, false, "", "گ")}, + {0xfb96, 0, 0, 0, g(Yes, No, false, false, "", "ڳ")}, + {0xfb9a, 0, 0, 0, g(Yes, No, false, false, "", "ڱ")}, + {0xfb9e, 0, 0, 0, g(Yes, No, false, false, "", "ں")}, + {0xfba0, 0, 0, 0, g(Yes, No, false, false, "", "ڻ")}, + {0xfba4, 0, 0, 1, g(Yes, No, false, false, "", "ۀ")}, + {0xfba6, 0, 0, 0, g(Yes, No, false, false, "", "ہ")}, + {0xfbaa, 0, 0, 0, g(Yes, No, false, false, "", "ھ")}, + {0xfbae, 0, 0, 0, g(Yes, No, false, false, "", "ے")}, + {0xfbb0, 0, 0, 1, g(Yes, No, false, false, "", "ۓ")}, + {0xfbb2, 0, 0, 0, f(Yes, false, "")}, + {0xfbd3, 0, 0, 0, g(Yes, No, false, false, "", "ڭ")}, + {0xfbd7, 0, 0, 0, g(Yes, No, false, false, "", "ۇ")}, + {0xfbd9, 0, 0, 0, g(Yes, No, false, false, "", "ۆ")}, + {0xfbdb, 0, 0, 0, g(Yes, No, false, false, "", "ۈ")}, + {0xfbdd, 0, 0, 0, g(Yes, No, false, false, "", "ۇٴ")}, + {0xfbde, 0, 0, 0, g(Yes, No, false, false, "", "ۋ")}, + {0xfbe0, 0, 0, 0, g(Yes, No, false, false, "", "ۅ")}, + {0xfbe2, 0, 0, 0, g(Yes, No, false, false, "", "ۉ")}, + {0xfbe4, 0, 0, 0, g(Yes, No, false, false, "", "ې")}, + {0xfbe8, 0, 0, 0, g(Yes, No, false, false, "", "ى")}, + {0xfbea, 0, 0, 0, g(Yes, No, false, false, "", "ئا")}, + {0xfbec, 0, 0, 0, g(Yes, No, false, false, "", "ئە")}, + {0xfbee, 0, 0, 0, g(Yes, No, false, false, "", "ئو")}, + {0xfbf0, 0, 0, 0, g(Yes, No, false, false, "", "ئۇ")}, + {0xfbf2, 0, 0, 0, g(Yes, No, false, false, "", "ئۆ")}, + {0xfbf4, 0, 0, 0, g(Yes, No, false, false, "", "ئۈ")}, + {0xfbf6, 0, 0, 0, g(Yes, No, false, false, "", "ئې")}, + {0xfbf9, 0, 0, 0, g(Yes, No, false, false, "", "ئى")}, + {0xfbfc, 0, 0, 0, g(Yes, No, false, false, "", "ی")}, + {0xfc00, 0, 0, 0, g(Yes, No, false, false, "", "ئج")}, + {0xfc01, 0, 0, 0, g(Yes, No, false, false, "", "ئح")}, + {0xfc02, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfc03, 0, 0, 0, g(Yes, No, false, false, "", "ئى")}, + {0xfc04, 0, 0, 0, g(Yes, No, false, false, "", "ئي")}, + {0xfc05, 0, 0, 0, g(Yes, No, false, false, "", "بج")}, + {0xfc06, 0, 0, 0, g(Yes, No, false, false, "", "بح")}, + {0xfc07, 0, 0, 0, g(Yes, No, false, false, "", "بخ")}, + {0xfc08, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfc09, 0, 0, 0, g(Yes, No, false, false, "", "بى")}, + {0xfc0a, 0, 0, 0, g(Yes, No, false, false, "", "بي")}, + {0xfc0b, 0, 0, 0, g(Yes, No, false, false, "", "تج")}, + {0xfc0c, 0, 0, 0, g(Yes, No, false, false, "", "تح")}, + {0xfc0d, 0, 0, 0, g(Yes, No, false, false, "", "تخ")}, + {0xfc0e, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfc0f, 0, 0, 0, g(Yes, No, false, false, "", "تى")}, + {0xfc10, 0, 0, 0, g(Yes, No, false, false, "", "تي")}, + {0xfc11, 0, 0, 0, g(Yes, No, false, false, "", "ثج")}, + {0xfc12, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfc13, 0, 0, 0, g(Yes, No, false, false, "", "ثى")}, + {0xfc14, 0, 0, 0, g(Yes, No, false, false, "", "ثي")}, + {0xfc15, 0, 0, 0, g(Yes, No, false, false, "", "جح")}, + {0xfc16, 0, 0, 0, g(Yes, No, false, false, "", "جم")}, + {0xfc17, 0, 0, 0, g(Yes, No, false, false, "", "حج")}, + {0xfc18, 0, 0, 0, g(Yes, No, false, false, "", "حم")}, + {0xfc19, 0, 0, 0, g(Yes, No, false, false, "", "خج")}, + {0xfc1a, 0, 0, 0, g(Yes, No, false, false, "", "خح")}, + {0xfc1b, 0, 0, 0, g(Yes, No, false, false, "", "خم")}, + {0xfc1c, 0, 0, 0, g(Yes, No, false, false, "", "سج")}, + {0xfc1d, 0, 0, 0, g(Yes, No, false, false, "", "سح")}, + {0xfc1e, 0, 0, 0, g(Yes, No, false, false, "", "سخ")}, + {0xfc1f, 0, 0, 0, g(Yes, No, false, false, "", "سم")}, + {0xfc20, 0, 0, 0, g(Yes, No, false, false, "", "صح")}, + {0xfc21, 0, 0, 0, g(Yes, No, false, false, "", "صم")}, + {0xfc22, 0, 0, 0, g(Yes, No, false, false, "", "ضج")}, + {0xfc23, 0, 0, 0, g(Yes, No, false, false, "", "ضح")}, + {0xfc24, 0, 0, 0, g(Yes, No, false, false, "", "ضخ")}, + {0xfc25, 0, 0, 0, g(Yes, No, false, false, "", "ضم")}, + {0xfc26, 0, 0, 0, g(Yes, No, false, false, "", "طح")}, + {0xfc27, 0, 0, 0, g(Yes, No, false, false, "", "طم")}, + {0xfc28, 0, 0, 0, g(Yes, No, false, false, "", "ظم")}, + {0xfc29, 0, 0, 0, g(Yes, No, false, false, "", "عج")}, + {0xfc2a, 0, 0, 0, g(Yes, No, false, false, "", "عم")}, + {0xfc2b, 0, 0, 0, g(Yes, No, false, false, "", "غج")}, + {0xfc2c, 0, 0, 0, g(Yes, No, false, false, "", "غم")}, + {0xfc2d, 0, 0, 0, g(Yes, No, false, false, "", "فج")}, + {0xfc2e, 0, 0, 0, g(Yes, No, false, false, "", "فح")}, + {0xfc2f, 0, 0, 0, g(Yes, No, false, false, "", "فخ")}, + {0xfc30, 0, 0, 0, g(Yes, No, false, false, "", "فم")}, + {0xfc31, 0, 0, 0, g(Yes, No, false, false, "", "فى")}, + {0xfc32, 0, 0, 0, g(Yes, No, false, false, "", "في")}, + {0xfc33, 0, 0, 0, g(Yes, No, false, false, "", "قح")}, + {0xfc34, 0, 0, 0, g(Yes, No, false, false, "", "قم")}, + {0xfc35, 0, 0, 0, g(Yes, No, false, false, "", "قى")}, + {0xfc36, 0, 0, 0, g(Yes, No, false, false, "", "قي")}, + {0xfc37, 0, 0, 0, g(Yes, No, false, false, "", "كا")}, + {0xfc38, 0, 0, 0, g(Yes, No, false, false, "", "كج")}, + {0xfc39, 0, 0, 0, g(Yes, No, false, false, "", "كح")}, + {0xfc3a, 0, 0, 0, g(Yes, No, false, false, "", "كخ")}, + {0xfc3b, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfc3c, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfc3d, 0, 0, 0, g(Yes, No, false, false, "", "كى")}, + {0xfc3e, 0, 0, 0, g(Yes, No, false, false, "", "كي")}, + {0xfc3f, 0, 0, 0, g(Yes, No, false, false, "", "لج")}, + {0xfc40, 0, 0, 0, g(Yes, No, false, false, "", "لح")}, + {0xfc41, 0, 0, 0, g(Yes, No, false, false, "", "لخ")}, + {0xfc42, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfc43, 0, 0, 0, g(Yes, No, false, false, "", "لى")}, + {0xfc44, 0, 0, 0, g(Yes, No, false, false, "", "لي")}, + {0xfc45, 0, 0, 0, g(Yes, No, false, false, "", "مج")}, + {0xfc46, 0, 0, 0, g(Yes, No, false, false, "", "مح")}, + {0xfc47, 0, 0, 0, g(Yes, No, false, false, "", "مخ")}, + {0xfc48, 0, 0, 0, g(Yes, No, false, false, "", "مم")}, + {0xfc49, 0, 0, 0, g(Yes, No, false, false, "", "مى")}, + {0xfc4a, 0, 0, 0, g(Yes, No, false, false, "", "مي")}, + {0xfc4b, 0, 0, 0, g(Yes, No, false, false, "", "نج")}, + {0xfc4c, 0, 0, 0, g(Yes, No, false, false, "", "نح")}, + {0xfc4d, 0, 0, 0, g(Yes, No, false, false, "", "نخ")}, + {0xfc4e, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfc4f, 0, 0, 0, g(Yes, No, false, false, "", "نى")}, + {0xfc50, 0, 0, 0, g(Yes, No, false, false, "", "ني")}, + {0xfc51, 0, 0, 0, g(Yes, No, false, false, "", "هج")}, + {0xfc52, 0, 0, 0, g(Yes, No, false, false, "", "هم")}, + {0xfc53, 0, 0, 0, g(Yes, No, false, false, "", "هى")}, + {0xfc54, 0, 0, 0, g(Yes, No, false, false, "", "هي")}, + {0xfc55, 0, 0, 0, g(Yes, No, false, false, "", "يج")}, + {0xfc56, 0, 0, 0, g(Yes, No, false, false, "", "يح")}, + {0xfc57, 0, 0, 0, g(Yes, No, false, false, "", "يخ")}, + {0xfc58, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfc59, 0, 0, 0, g(Yes, No, false, false, "", "يى")}, + {0xfc5a, 0, 0, 0, g(Yes, No, false, false, "", "يي")}, + {0xfc5b, 0, 0, 1, g(Yes, No, false, false, "", "ذٰ")}, + {0xfc5c, 0, 0, 1, g(Yes, No, false, false, "", "رٰ")}, + {0xfc5d, 0, 0, 1, g(Yes, No, false, false, "", "ىٰ")}, + {0xfc5e, 0, 0, 2, g(Yes, No, false, false, "", " ٌّ")}, + {0xfc5f, 0, 0, 2, g(Yes, No, false, false, "", " ٍّ")}, + {0xfc60, 0, 0, 2, g(Yes, No, false, false, "", " َّ")}, + {0xfc61, 0, 0, 2, g(Yes, No, false, false, "", " ُّ")}, + {0xfc62, 0, 0, 2, g(Yes, No, false, false, "", " ِّ")}, + {0xfc63, 0, 0, 2, g(Yes, No, false, false, "", " ّٰ")}, + {0xfc64, 0, 0, 0, g(Yes, No, false, false, "", "ئر")}, + {0xfc65, 0, 0, 0, g(Yes, No, false, false, "", "ئز")}, + {0xfc66, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfc67, 0, 0, 0, g(Yes, No, false, false, "", "ئن")}, + {0xfc68, 0, 0, 0, g(Yes, No, false, false, "", "ئى")}, + {0xfc69, 0, 0, 0, g(Yes, No, false, false, "", "ئي")}, + {0xfc6a, 0, 0, 0, g(Yes, No, false, false, "", "بر")}, + {0xfc6b, 0, 0, 0, g(Yes, No, false, false, "", "بز")}, + {0xfc6c, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfc6d, 0, 0, 0, g(Yes, No, false, false, "", "بن")}, + {0xfc6e, 0, 0, 0, g(Yes, No, false, false, "", "بى")}, + {0xfc6f, 0, 0, 0, g(Yes, No, false, false, "", "بي")}, + {0xfc70, 0, 0, 0, g(Yes, No, false, false, "", "تر")}, + {0xfc71, 0, 0, 0, g(Yes, No, false, false, "", "تز")}, + {0xfc72, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfc73, 0, 0, 0, g(Yes, No, false, false, "", "تن")}, + {0xfc74, 0, 0, 0, g(Yes, No, false, false, "", "تى")}, + {0xfc75, 0, 0, 0, g(Yes, No, false, false, "", "تي")}, + {0xfc76, 0, 0, 0, g(Yes, No, false, false, "", "ثر")}, + {0xfc77, 0, 0, 0, g(Yes, No, false, false, "", "ثز")}, + {0xfc78, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfc79, 0, 0, 0, g(Yes, No, false, false, "", "ثن")}, + {0xfc7a, 0, 0, 0, g(Yes, No, false, false, "", "ثى")}, + {0xfc7b, 0, 0, 0, g(Yes, No, false, false, "", "ثي")}, + {0xfc7c, 0, 0, 0, g(Yes, No, false, false, "", "فى")}, + {0xfc7d, 0, 0, 0, g(Yes, No, false, false, "", "في")}, + {0xfc7e, 0, 0, 0, g(Yes, No, false, false, "", "قى")}, + {0xfc7f, 0, 0, 0, g(Yes, No, false, false, "", "قي")}, + {0xfc80, 0, 0, 0, g(Yes, No, false, false, "", "كا")}, + {0xfc81, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfc82, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfc83, 0, 0, 0, g(Yes, No, false, false, "", "كى")}, + {0xfc84, 0, 0, 0, g(Yes, No, false, false, "", "كي")}, + {0xfc85, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfc86, 0, 0, 0, g(Yes, No, false, false, "", "لى")}, + {0xfc87, 0, 0, 0, g(Yes, No, false, false, "", "لي")}, + {0xfc88, 0, 0, 0, g(Yes, No, false, false, "", "ما")}, + {0xfc89, 0, 0, 0, g(Yes, No, false, false, "", "مم")}, + {0xfc8a, 0, 0, 0, g(Yes, No, false, false, "", "نر")}, + {0xfc8b, 0, 0, 0, g(Yes, No, false, false, "", "نز")}, + {0xfc8c, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfc8d, 0, 0, 0, g(Yes, No, false, false, "", "نن")}, + {0xfc8e, 0, 0, 0, g(Yes, No, false, false, "", "نى")}, + {0xfc8f, 0, 0, 0, g(Yes, No, false, false, "", "ني")}, + {0xfc90, 0, 0, 1, g(Yes, No, false, false, "", "ىٰ")}, + {0xfc91, 0, 0, 0, g(Yes, No, false, false, "", "ير")}, + {0xfc92, 0, 0, 0, g(Yes, No, false, false, "", "يز")}, + {0xfc93, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfc94, 0, 0, 0, g(Yes, No, false, false, "", "ين")}, + {0xfc95, 0, 0, 0, g(Yes, No, false, false, "", "يى")}, + {0xfc96, 0, 0, 0, g(Yes, No, false, false, "", "يي")}, + {0xfc97, 0, 0, 0, g(Yes, No, false, false, "", "ئج")}, + {0xfc98, 0, 0, 0, g(Yes, No, false, false, "", "ئح")}, + {0xfc99, 0, 0, 0, g(Yes, No, false, false, "", "ئخ")}, + {0xfc9a, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfc9b, 0, 0, 0, g(Yes, No, false, false, "", "ئه")}, + {0xfc9c, 0, 0, 0, g(Yes, No, false, false, "", "بج")}, + {0xfc9d, 0, 0, 0, g(Yes, No, false, false, "", "بح")}, + {0xfc9e, 0, 0, 0, g(Yes, No, false, false, "", "بخ")}, + {0xfc9f, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfca0, 0, 0, 0, g(Yes, No, false, false, "", "به")}, + {0xfca1, 0, 0, 0, g(Yes, No, false, false, "", "تج")}, + {0xfca2, 0, 0, 0, g(Yes, No, false, false, "", "تح")}, + {0xfca3, 0, 0, 0, g(Yes, No, false, false, "", "تخ")}, + {0xfca4, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfca5, 0, 0, 0, g(Yes, No, false, false, "", "ته")}, + {0xfca6, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfca7, 0, 0, 0, g(Yes, No, false, false, "", "جح")}, + {0xfca8, 0, 0, 0, g(Yes, No, false, false, "", "جم")}, + {0xfca9, 0, 0, 0, g(Yes, No, false, false, "", "حج")}, + {0xfcaa, 0, 0, 0, g(Yes, No, false, false, "", "حم")}, + {0xfcab, 0, 0, 0, g(Yes, No, false, false, "", "خج")}, + {0xfcac, 0, 0, 0, g(Yes, No, false, false, "", "خم")}, + {0xfcad, 0, 0, 0, g(Yes, No, false, false, "", "سج")}, + {0xfcae, 0, 0, 0, g(Yes, No, false, false, "", "سح")}, + {0xfcaf, 0, 0, 0, g(Yes, No, false, false, "", "سخ")}, + {0xfcb0, 0, 0, 0, g(Yes, No, false, false, "", "سم")}, + {0xfcb1, 0, 0, 0, g(Yes, No, false, false, "", "صح")}, + {0xfcb2, 0, 0, 0, g(Yes, No, false, false, "", "صخ")}, + {0xfcb3, 0, 0, 0, g(Yes, No, false, false, "", "صم")}, + {0xfcb4, 0, 0, 0, g(Yes, No, false, false, "", "ضج")}, + {0xfcb5, 0, 0, 0, g(Yes, No, false, false, "", "ضح")}, + {0xfcb6, 0, 0, 0, g(Yes, No, false, false, "", "ضخ")}, + {0xfcb7, 0, 0, 0, g(Yes, No, false, false, "", "ضم")}, + {0xfcb8, 0, 0, 0, g(Yes, No, false, false, "", "طح")}, + {0xfcb9, 0, 0, 0, g(Yes, No, false, false, "", "ظم")}, + {0xfcba, 0, 0, 0, g(Yes, No, false, false, "", "عج")}, + {0xfcbb, 0, 0, 0, g(Yes, No, false, false, "", "عم")}, + {0xfcbc, 0, 0, 0, g(Yes, No, false, false, "", "غج")}, + {0xfcbd, 0, 0, 0, g(Yes, No, false, false, "", "غم")}, + {0xfcbe, 0, 0, 0, g(Yes, No, false, false, "", "فج")}, + {0xfcbf, 0, 0, 0, g(Yes, No, false, false, "", "فح")}, + {0xfcc0, 0, 0, 0, g(Yes, No, false, false, "", "فخ")}, + {0xfcc1, 0, 0, 0, g(Yes, No, false, false, "", "فم")}, + {0xfcc2, 0, 0, 0, g(Yes, No, false, false, "", "قح")}, + {0xfcc3, 0, 0, 0, g(Yes, No, false, false, "", "قم")}, + {0xfcc4, 0, 0, 0, g(Yes, No, false, false, "", "كج")}, + {0xfcc5, 0, 0, 0, g(Yes, No, false, false, "", "كح")}, + {0xfcc6, 0, 0, 0, g(Yes, No, false, false, "", "كخ")}, + {0xfcc7, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfcc8, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfcc9, 0, 0, 0, g(Yes, No, false, false, "", "لج")}, + {0xfcca, 0, 0, 0, g(Yes, No, false, false, "", "لح")}, + {0xfccb, 0, 0, 0, g(Yes, No, false, false, "", "لخ")}, + {0xfccc, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfccd, 0, 0, 0, g(Yes, No, false, false, "", "له")}, + {0xfcce, 0, 0, 0, g(Yes, No, false, false, "", "مج")}, + {0xfccf, 0, 0, 0, g(Yes, No, false, false, "", "مح")}, + {0xfcd0, 0, 0, 0, g(Yes, No, false, false, "", "مخ")}, + {0xfcd1, 0, 0, 0, g(Yes, No, false, false, "", "مم")}, + {0xfcd2, 0, 0, 0, g(Yes, No, false, false, "", "نج")}, + {0xfcd3, 0, 0, 0, g(Yes, No, false, false, "", "نح")}, + {0xfcd4, 0, 0, 0, g(Yes, No, false, false, "", "نخ")}, + {0xfcd5, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfcd6, 0, 0, 0, g(Yes, No, false, false, "", "نه")}, + {0xfcd7, 0, 0, 0, g(Yes, No, false, false, "", "هج")}, + {0xfcd8, 0, 0, 0, g(Yes, No, false, false, "", "هم")}, + {0xfcd9, 0, 0, 1, g(Yes, No, false, false, "", "هٰ")}, + {0xfcda, 0, 0, 0, g(Yes, No, false, false, "", "يج")}, + {0xfcdb, 0, 0, 0, g(Yes, No, false, false, "", "يح")}, + {0xfcdc, 0, 0, 0, g(Yes, No, false, false, "", "يخ")}, + {0xfcdd, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfcde, 0, 0, 0, g(Yes, No, false, false, "", "يه")}, + {0xfcdf, 0, 0, 0, g(Yes, No, false, false, "", "ئم")}, + {0xfce0, 0, 0, 0, g(Yes, No, false, false, "", "ئه")}, + {0xfce1, 0, 0, 0, g(Yes, No, false, false, "", "بم")}, + {0xfce2, 0, 0, 0, g(Yes, No, false, false, "", "به")}, + {0xfce3, 0, 0, 0, g(Yes, No, false, false, "", "تم")}, + {0xfce4, 0, 0, 0, g(Yes, No, false, false, "", "ته")}, + {0xfce5, 0, 0, 0, g(Yes, No, false, false, "", "ثم")}, + {0xfce6, 0, 0, 0, g(Yes, No, false, false, "", "ثه")}, + {0xfce7, 0, 0, 0, g(Yes, No, false, false, "", "سم")}, + {0xfce8, 0, 0, 0, g(Yes, No, false, false, "", "سه")}, + {0xfce9, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfcea, 0, 0, 0, g(Yes, No, false, false, "", "شه")}, + {0xfceb, 0, 0, 0, g(Yes, No, false, false, "", "كل")}, + {0xfcec, 0, 0, 0, g(Yes, No, false, false, "", "كم")}, + {0xfced, 0, 0, 0, g(Yes, No, false, false, "", "لم")}, + {0xfcee, 0, 0, 0, g(Yes, No, false, false, "", "نم")}, + {0xfcef, 0, 0, 0, g(Yes, No, false, false, "", "نه")}, + {0xfcf0, 0, 0, 0, g(Yes, No, false, false, "", "يم")}, + {0xfcf1, 0, 0, 0, g(Yes, No, false, false, "", "يه")}, + {0xfcf2, 0, 0, 2, g(Yes, No, false, false, "", "ـَّ")}, + {0xfcf3, 0, 0, 2, g(Yes, No, false, false, "", "ـُّ")}, + {0xfcf4, 0, 0, 2, g(Yes, No, false, false, "", "ـِّ")}, + {0xfcf5, 0, 0, 0, g(Yes, No, false, false, "", "طى")}, + {0xfcf6, 0, 0, 0, g(Yes, No, false, false, "", "طي")}, + {0xfcf7, 0, 0, 0, g(Yes, No, false, false, "", "عى")}, + {0xfcf8, 0, 0, 0, g(Yes, No, false, false, "", "عي")}, + {0xfcf9, 0, 0, 0, g(Yes, No, false, false, "", "غى")}, + {0xfcfa, 0, 0, 0, g(Yes, No, false, false, "", "غي")}, + {0xfcfb, 0, 0, 0, g(Yes, No, false, false, "", "سى")}, + {0xfcfc, 0, 0, 0, g(Yes, No, false, false, "", "سي")}, + {0xfcfd, 0, 0, 0, g(Yes, No, false, false, "", "شى")}, + {0xfcfe, 0, 0, 0, g(Yes, No, false, false, "", "شي")}, + {0xfcff, 0, 0, 0, g(Yes, No, false, false, "", "حى")}, + {0xfd00, 0, 0, 0, g(Yes, No, false, false, "", "حي")}, + {0xfd01, 0, 0, 0, g(Yes, No, false, false, "", "جى")}, + {0xfd02, 0, 0, 0, g(Yes, No, false, false, "", "جي")}, + {0xfd03, 0, 0, 0, g(Yes, No, false, false, "", "خى")}, + {0xfd04, 0, 0, 0, g(Yes, No, false, false, "", "خي")}, + {0xfd05, 0, 0, 0, g(Yes, No, false, false, "", "صى")}, + {0xfd06, 0, 0, 0, g(Yes, No, false, false, "", "صي")}, + {0xfd07, 0, 0, 0, g(Yes, No, false, false, "", "ضى")}, + {0xfd08, 0, 0, 0, g(Yes, No, false, false, "", "ضي")}, + {0xfd09, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd0a, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd0b, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd0c, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfd0d, 0, 0, 0, g(Yes, No, false, false, "", "شر")}, + {0xfd0e, 0, 0, 0, g(Yes, No, false, false, "", "سر")}, + {0xfd0f, 0, 0, 0, g(Yes, No, false, false, "", "صر")}, + {0xfd10, 0, 0, 0, g(Yes, No, false, false, "", "ضر")}, + {0xfd11, 0, 0, 0, g(Yes, No, false, false, "", "طى")}, + {0xfd12, 0, 0, 0, g(Yes, No, false, false, "", "طي")}, + {0xfd13, 0, 0, 0, g(Yes, No, false, false, "", "عى")}, + {0xfd14, 0, 0, 0, g(Yes, No, false, false, "", "عي")}, + {0xfd15, 0, 0, 0, g(Yes, No, false, false, "", "غى")}, + {0xfd16, 0, 0, 0, g(Yes, No, false, false, "", "غي")}, + {0xfd17, 0, 0, 0, g(Yes, No, false, false, "", "سى")}, + {0xfd18, 0, 0, 0, g(Yes, No, false, false, "", "سي")}, + {0xfd19, 0, 0, 0, g(Yes, No, false, false, "", "شى")}, + {0xfd1a, 0, 0, 0, g(Yes, No, false, false, "", "شي")}, + {0xfd1b, 0, 0, 0, g(Yes, No, false, false, "", "حى")}, + {0xfd1c, 0, 0, 0, g(Yes, No, false, false, "", "حي")}, + {0xfd1d, 0, 0, 0, g(Yes, No, false, false, "", "جى")}, + {0xfd1e, 0, 0, 0, g(Yes, No, false, false, "", "جي")}, + {0xfd1f, 0, 0, 0, g(Yes, No, false, false, "", "خى")}, + {0xfd20, 0, 0, 0, g(Yes, No, false, false, "", "خي")}, + {0xfd21, 0, 0, 0, g(Yes, No, false, false, "", "صى")}, + {0xfd22, 0, 0, 0, g(Yes, No, false, false, "", "صي")}, + {0xfd23, 0, 0, 0, g(Yes, No, false, false, "", "ضى")}, + {0xfd24, 0, 0, 0, g(Yes, No, false, false, "", "ضي")}, + {0xfd25, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd26, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd27, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd28, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfd29, 0, 0, 0, g(Yes, No, false, false, "", "شر")}, + {0xfd2a, 0, 0, 0, g(Yes, No, false, false, "", "سر")}, + {0xfd2b, 0, 0, 0, g(Yes, No, false, false, "", "صر")}, + {0xfd2c, 0, 0, 0, g(Yes, No, false, false, "", "ضر")}, + {0xfd2d, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd2e, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd2f, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd30, 0, 0, 0, g(Yes, No, false, false, "", "شم")}, + {0xfd31, 0, 0, 0, g(Yes, No, false, false, "", "سه")}, + {0xfd32, 0, 0, 0, g(Yes, No, false, false, "", "شه")}, + {0xfd33, 0, 0, 0, g(Yes, No, false, false, "", "طم")}, + {0xfd34, 0, 0, 0, g(Yes, No, false, false, "", "سج")}, + {0xfd35, 0, 0, 0, g(Yes, No, false, false, "", "سح")}, + {0xfd36, 0, 0, 0, g(Yes, No, false, false, "", "سخ")}, + {0xfd37, 0, 0, 0, g(Yes, No, false, false, "", "شج")}, + {0xfd38, 0, 0, 0, g(Yes, No, false, false, "", "شح")}, + {0xfd39, 0, 0, 0, g(Yes, No, false, false, "", "شخ")}, + {0xfd3a, 0, 0, 0, g(Yes, No, false, false, "", "طم")}, + {0xfd3b, 0, 0, 0, g(Yes, No, false, false, "", "ظم")}, + {0xfd3c, 0, 0, 1, g(Yes, No, false, false, "", "اً")}, + {0xfd3e, 0, 0, 0, f(Yes, false, "")}, + {0xfd50, 0, 0, 0, g(Yes, No, false, false, "", "تجم")}, + {0xfd51, 0, 0, 0, g(Yes, No, false, false, "", "تحج")}, + {0xfd53, 0, 0, 0, g(Yes, No, false, false, "", "تحم")}, + {0xfd54, 0, 0, 0, g(Yes, No, false, false, "", "تخم")}, + {0xfd55, 0, 0, 0, g(Yes, No, false, false, "", "تمج")}, + {0xfd56, 0, 0, 0, g(Yes, No, false, false, "", "تمح")}, + {0xfd57, 0, 0, 0, g(Yes, No, false, false, "", "تمخ")}, + {0xfd58, 0, 0, 0, g(Yes, No, false, false, "", "جمح")}, + {0xfd5a, 0, 0, 0, g(Yes, No, false, false, "", "حمي")}, + {0xfd5b, 0, 0, 0, g(Yes, No, false, false, "", "حمى")}, + {0xfd5c, 0, 0, 0, g(Yes, No, false, false, "", "سحج")}, + {0xfd5d, 0, 0, 0, g(Yes, No, false, false, "", "سجح")}, + {0xfd5e, 0, 0, 0, g(Yes, No, false, false, "", "سجى")}, + {0xfd5f, 0, 0, 0, g(Yes, No, false, false, "", "سمح")}, + {0xfd61, 0, 0, 0, g(Yes, No, false, false, "", "سمج")}, + {0xfd62, 0, 0, 0, g(Yes, No, false, false, "", "سمم")}, + {0xfd64, 0, 0, 0, g(Yes, No, false, false, "", "صحح")}, + {0xfd66, 0, 0, 0, g(Yes, No, false, false, "", "صمم")}, + {0xfd67, 0, 0, 0, g(Yes, No, false, false, "", "شحم")}, + {0xfd69, 0, 0, 0, g(Yes, No, false, false, "", "شجي")}, + {0xfd6a, 0, 0, 0, g(Yes, No, false, false, "", "شمخ")}, + {0xfd6c, 0, 0, 0, g(Yes, No, false, false, "", "شمم")}, + {0xfd6e, 0, 0, 0, g(Yes, No, false, false, "", "ضحى")}, + {0xfd6f, 0, 0, 0, g(Yes, No, false, false, "", "ضخم")}, + {0xfd71, 0, 0, 0, g(Yes, No, false, false, "", "طمح")}, + {0xfd73, 0, 0, 0, g(Yes, No, false, false, "", "طمم")}, + {0xfd74, 0, 0, 0, g(Yes, No, false, false, "", "طمي")}, + {0xfd75, 0, 0, 0, g(Yes, No, false, false, "", "عجم")}, + {0xfd76, 0, 0, 0, g(Yes, No, false, false, "", "عمم")}, + {0xfd78, 0, 0, 0, g(Yes, No, false, false, "", "عمى")}, + {0xfd79, 0, 0, 0, g(Yes, No, false, false, "", "غمم")}, + {0xfd7a, 0, 0, 0, g(Yes, No, false, false, "", "غمي")}, + {0xfd7b, 0, 0, 0, g(Yes, No, false, false, "", "غمى")}, + {0xfd7c, 0, 0, 0, g(Yes, No, false, false, "", "فخم")}, + {0xfd7e, 0, 0, 0, g(Yes, No, false, false, "", "قمح")}, + {0xfd7f, 0, 0, 0, g(Yes, No, false, false, "", "قمم")}, + {0xfd80, 0, 0, 0, g(Yes, No, false, false, "", "لحم")}, + {0xfd81, 0, 0, 0, g(Yes, No, false, false, "", "لحي")}, + {0xfd82, 0, 0, 0, g(Yes, No, false, false, "", "لحى")}, + {0xfd83, 0, 0, 0, g(Yes, No, false, false, "", "لجج")}, + {0xfd85, 0, 0, 0, g(Yes, No, false, false, "", "لخم")}, + {0xfd87, 0, 0, 0, g(Yes, No, false, false, "", "لمح")}, + {0xfd89, 0, 0, 0, g(Yes, No, false, false, "", "محج")}, + {0xfd8a, 0, 0, 0, g(Yes, No, false, false, "", "محم")}, + {0xfd8b, 0, 0, 0, g(Yes, No, false, false, "", "محي")}, + {0xfd8c, 0, 0, 0, g(Yes, No, false, false, "", "مجح")}, + {0xfd8d, 0, 0, 0, g(Yes, No, false, false, "", "مجم")}, + {0xfd8e, 0, 0, 0, g(Yes, No, false, false, "", "مخج")}, + {0xfd8f, 0, 0, 0, g(Yes, No, false, false, "", "مخم")}, + {0xfd90, 0, 0, 0, f(Yes, false, "")}, + {0xfd92, 0, 0, 0, g(Yes, No, false, false, "", "مجخ")}, + {0xfd93, 0, 0, 0, g(Yes, No, false, false, "", "همج")}, + {0xfd94, 0, 0, 0, g(Yes, No, false, false, "", "همم")}, + {0xfd95, 0, 0, 0, g(Yes, No, false, false, "", "نحم")}, + {0xfd96, 0, 0, 0, g(Yes, No, false, false, "", "نحى")}, + {0xfd97, 0, 0, 0, g(Yes, No, false, false, "", "نجم")}, + {0xfd99, 0, 0, 0, g(Yes, No, false, false, "", "نجى")}, + {0xfd9a, 0, 0, 0, g(Yes, No, false, false, "", "نمي")}, + {0xfd9b, 0, 0, 0, g(Yes, No, false, false, "", "نمى")}, + {0xfd9c, 0, 0, 0, g(Yes, No, false, false, "", "يمم")}, + {0xfd9e, 0, 0, 0, g(Yes, No, false, false, "", "بخي")}, + {0xfd9f, 0, 0, 0, g(Yes, No, false, false, "", "تجي")}, + {0xfda0, 0, 0, 0, g(Yes, No, false, false, "", "تجى")}, + {0xfda1, 0, 0, 0, g(Yes, No, false, false, "", "تخي")}, + {0xfda2, 0, 0, 0, g(Yes, No, false, false, "", "تخى")}, + {0xfda3, 0, 0, 0, g(Yes, No, false, false, "", "تمي")}, + {0xfda4, 0, 0, 0, g(Yes, No, false, false, "", "تمى")}, + {0xfda5, 0, 0, 0, g(Yes, No, false, false, "", "جمي")}, + {0xfda6, 0, 0, 0, g(Yes, No, false, false, "", "جحى")}, + {0xfda7, 0, 0, 0, g(Yes, No, false, false, "", "جمى")}, + {0xfda8, 0, 0, 0, g(Yes, No, false, false, "", "سخى")}, + {0xfda9, 0, 0, 0, g(Yes, No, false, false, "", "صحي")}, + {0xfdaa, 0, 0, 0, g(Yes, No, false, false, "", "شحي")}, + {0xfdab, 0, 0, 0, g(Yes, No, false, false, "", "ضحي")}, + {0xfdac, 0, 0, 0, g(Yes, No, false, false, "", "لجي")}, + {0xfdad, 0, 0, 0, g(Yes, No, false, false, "", "لمي")}, + {0xfdae, 0, 0, 0, g(Yes, No, false, false, "", "يحي")}, + {0xfdaf, 0, 0, 0, g(Yes, No, false, false, "", "يجي")}, + {0xfdb0, 0, 0, 0, g(Yes, No, false, false, "", "يمي")}, + {0xfdb1, 0, 0, 0, g(Yes, No, false, false, "", "ممي")}, + {0xfdb2, 0, 0, 0, g(Yes, No, false, false, "", "قمي")}, + {0xfdb3, 0, 0, 0, g(Yes, No, false, false, "", "نحي")}, + {0xfdb4, 0, 0, 0, g(Yes, No, false, false, "", "قمح")}, + {0xfdb5, 0, 0, 0, g(Yes, No, false, false, "", "لحم")}, + {0xfdb6, 0, 0, 0, g(Yes, No, false, false, "", "عمي")}, + {0xfdb7, 0, 0, 0, g(Yes, No, false, false, "", "كمي")}, + {0xfdb8, 0, 0, 0, g(Yes, No, false, false, "", "نجح")}, + {0xfdb9, 0, 0, 0, g(Yes, No, false, false, "", "مخي")}, + {0xfdba, 0, 0, 0, g(Yes, No, false, false, "", "لجم")}, + {0xfdbb, 0, 0, 0, g(Yes, No, false, false, "", "كمم")}, + {0xfdbc, 0, 0, 0, g(Yes, No, false, false, "", "لجم")}, + {0xfdbd, 0, 0, 0, g(Yes, No, false, false, "", "نجح")}, + {0xfdbe, 0, 0, 0, g(Yes, No, false, false, "", "جحي")}, + {0xfdbf, 0, 0, 0, g(Yes, No, false, false, "", "حجي")}, + {0xfdc0, 0, 0, 0, g(Yes, No, false, false, "", "مجي")}, + {0xfdc1, 0, 0, 0, g(Yes, No, false, false, "", "فمي")}, + {0xfdc2, 0, 0, 0, g(Yes, No, false, false, "", "بحي")}, + {0xfdc3, 0, 0, 0, g(Yes, No, false, false, "", "كمم")}, + {0xfdc4, 0, 0, 0, g(Yes, No, false, false, "", "عجم")}, + {0xfdc5, 0, 0, 0, g(Yes, No, false, false, "", "صمم")}, + {0xfdc6, 0, 0, 0, g(Yes, No, false, false, "", "سخي")}, + {0xfdc7, 0, 0, 0, g(Yes, No, false, false, "", "نجي")}, + {0xfdc8, 0, 0, 0, f(Yes, false, "")}, + {0xfdf0, 0, 0, 0, g(Yes, No, false, false, "", "صلے")}, + {0xfdf1, 0, 0, 0, g(Yes, No, false, false, "", "قلے")}, + {0xfdf2, 0, 0, 0, g(Yes, No, false, false, "", "الله")}, + {0xfdf3, 0, 0, 0, g(Yes, No, false, false, "", "اكبر")}, + {0xfdf4, 0, 0, 0, g(Yes, No, false, false, "", "محمد")}, + {0xfdf5, 0, 0, 0, g(Yes, No, false, false, "", "صلعم")}, + {0xfdf6, 0, 0, 0, g(Yes, No, false, false, "", "رسول")}, + {0xfdf7, 0, 0, 0, g(Yes, No, false, false, "", "عليه")}, + {0xfdf8, 0, 0, 0, g(Yes, No, false, false, "", "وسلم")}, + {0xfdf9, 0, 0, 0, g(Yes, No, false, false, "", "صلى")}, + {0xfdfa, 0, 0, 0, g(Yes, No, false, false, "", "صلى الله عليه وسلم")}, + {0xfdfb, 0, 0, 0, g(Yes, No, false, false, "", "جل جلاله")}, + {0xfdfc, 0, 0, 0, g(Yes, No, false, false, "", "ریال")}, + {0xfdfd, 0, 0, 0, f(Yes, false, "")}, + {0xfe10, 0, 0, 0, g(Yes, No, false, false, "", ",")}, + {0xfe11, 0, 0, 0, g(Yes, No, false, false, "", "、")}, + {0xfe12, 0, 0, 0, g(Yes, No, false, false, "", "。")}, + {0xfe13, 0, 0, 0, g(Yes, No, false, false, "", ":")}, + {0xfe14, 0, 0, 0, g(Yes, No, false, false, "", ";")}, + {0xfe15, 0, 0, 0, g(Yes, No, false, false, "", "!")}, + {0xfe16, 0, 0, 0, g(Yes, No, false, false, "", "?")}, + {0xfe17, 0, 0, 0, g(Yes, No, false, false, "", "〖")}, + {0xfe18, 0, 0, 0, g(Yes, No, false, false, "", "〗")}, + {0xfe19, 0, 0, 0, g(Yes, No, false, false, "", "...")}, + {0xfe1a, 0, 0, 0, f(Yes, false, "")}, + {0xfe20, 230, 1, 1, f(Yes, false, "")}, + {0xfe27, 220, 1, 1, f(Yes, false, "")}, + {0xfe2e, 230, 1, 1, f(Yes, false, "")}, + {0xfe30, 0, 0, 0, g(Yes, No, false, false, "", "..")}, + {0xfe31, 0, 0, 0, g(Yes, No, false, false, "", "—")}, + {0xfe32, 0, 0, 0, g(Yes, No, false, false, "", "–")}, + {0xfe33, 0, 0, 0, g(Yes, No, false, false, "", "_")}, + {0xfe35, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0xfe36, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0xfe37, 0, 0, 0, g(Yes, No, false, false, "", "{")}, + {0xfe38, 0, 0, 0, g(Yes, No, false, false, "", "}")}, + {0xfe39, 0, 0, 0, g(Yes, No, false, false, "", "〔")}, + {0xfe3a, 0, 0, 0, g(Yes, No, false, false, "", "〕")}, + {0xfe3b, 0, 0, 0, g(Yes, No, false, false, "", "【")}, + {0xfe3c, 0, 0, 0, g(Yes, No, false, false, "", "】")}, + {0xfe3d, 0, 0, 0, g(Yes, No, false, false, "", "《")}, + {0xfe3e, 0, 0, 0, g(Yes, No, false, false, "", "》")}, + {0xfe3f, 0, 0, 0, g(Yes, No, false, false, "", "〈")}, + {0xfe40, 0, 0, 0, g(Yes, No, false, false, "", "〉")}, + {0xfe41, 0, 0, 0, g(Yes, No, false, false, "", "「")}, + {0xfe42, 0, 0, 0, g(Yes, No, false, false, "", "」")}, + {0xfe43, 0, 0, 0, g(Yes, No, false, false, "", "『")}, + {0xfe44, 0, 0, 0, g(Yes, No, false, false, "", "』")}, + {0xfe45, 0, 0, 0, f(Yes, false, "")}, + {0xfe47, 0, 0, 0, g(Yes, No, false, false, "", "[")}, + {0xfe48, 0, 0, 0, g(Yes, No, false, false, "", "]")}, + {0xfe49, 0, 0, 1, g(Yes, No, false, false, "", " ̅")}, + {0xfe4d, 0, 0, 0, g(Yes, No, false, false, "", "_")}, + {0xfe50, 0, 0, 0, g(Yes, No, false, false, "", ",")}, + {0xfe51, 0, 0, 0, g(Yes, No, false, false, "", "、")}, + {0xfe52, 0, 0, 0, g(Yes, No, false, false, "", ".")}, + {0xfe53, 0, 0, 0, f(Yes, false, "")}, + {0xfe54, 0, 0, 0, g(Yes, No, false, false, "", ";")}, + {0xfe55, 0, 0, 0, g(Yes, No, false, false, "", ":")}, + {0xfe56, 0, 0, 0, g(Yes, No, false, false, "", "?")}, + {0xfe57, 0, 0, 0, g(Yes, No, false, false, "", "!")}, + {0xfe58, 0, 0, 0, g(Yes, No, false, false, "", "—")}, + {0xfe59, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0xfe5a, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0xfe5b, 0, 0, 0, g(Yes, No, false, false, "", "{")}, + {0xfe5c, 0, 0, 0, g(Yes, No, false, false, "", "}")}, + {0xfe5d, 0, 0, 0, g(Yes, No, false, false, "", "〔")}, + {0xfe5e, 0, 0, 0, g(Yes, No, false, false, "", "〕")}, + {0xfe5f, 0, 0, 0, g(Yes, No, false, false, "", "#")}, + {0xfe60, 0, 0, 0, g(Yes, No, false, false, "", "&")}, + {0xfe61, 0, 0, 0, g(Yes, No, false, false, "", "*")}, + {0xfe62, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0xfe63, 0, 0, 0, g(Yes, No, false, false, "", "-")}, + {0xfe64, 0, 0, 0, g(Yes, No, false, false, "", "<")}, + {0xfe65, 0, 0, 0, g(Yes, No, false, false, "", ">")}, + {0xfe66, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0xfe67, 0, 0, 0, f(Yes, false, "")}, + {0xfe68, 0, 0, 0, g(Yes, No, false, false, "", "\\")}, + {0xfe69, 0, 0, 0, g(Yes, No, false, false, "", "$")}, + {0xfe6a, 0, 0, 0, g(Yes, No, false, false, "", "%")}, + {0xfe6b, 0, 0, 0, g(Yes, No, false, false, "", "@")}, + {0xfe6c, 0, 0, 0, f(Yes, false, "")}, + {0xfe70, 0, 0, 1, g(Yes, No, false, false, "", " ً")}, + {0xfe71, 0, 0, 1, g(Yes, No, false, false, "", "ـً")}, + {0xfe72, 0, 0, 1, g(Yes, No, false, false, "", " ٌ")}, + {0xfe73, 0, 0, 0, f(Yes, false, "")}, + {0xfe74, 0, 0, 1, g(Yes, No, false, false, "", " ٍ")}, + {0xfe75, 0, 0, 0, f(Yes, false, "")}, + {0xfe76, 0, 0, 1, g(Yes, No, false, false, "", " َ")}, + {0xfe77, 0, 0, 1, g(Yes, No, false, false, "", "ـَ")}, + {0xfe78, 0, 0, 1, g(Yes, No, false, false, "", " ُ")}, + {0xfe79, 0, 0, 1, g(Yes, No, false, false, "", "ـُ")}, + {0xfe7a, 0, 0, 1, g(Yes, No, false, false, "", " ِ")}, + {0xfe7b, 0, 0, 1, g(Yes, No, false, false, "", "ـِ")}, + {0xfe7c, 0, 0, 1, g(Yes, No, false, false, "", " ّ")}, + {0xfe7d, 0, 0, 1, g(Yes, No, false, false, "", "ـّ")}, + {0xfe7e, 0, 0, 1, g(Yes, No, false, false, "", " ْ")}, + {0xfe7f, 0, 0, 1, g(Yes, No, false, false, "", "ـْ")}, + {0xfe80, 0, 0, 0, g(Yes, No, false, false, "", "ء")}, + {0xfe81, 0, 0, 1, g(Yes, No, false, false, "", "آ")}, + {0xfe83, 0, 0, 1, g(Yes, No, false, false, "", "أ")}, + {0xfe85, 0, 0, 1, g(Yes, No, false, false, "", "ؤ")}, + {0xfe87, 0, 0, 1, g(Yes, No, false, false, "", "إ")}, + {0xfe89, 0, 0, 1, g(Yes, No, false, false, "", "ئ")}, + {0xfe8d, 0, 0, 0, g(Yes, No, false, false, "", "ا")}, + {0xfe8f, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0xfe93, 0, 0, 0, g(Yes, No, false, false, "", "ة")}, + {0xfe95, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0xfe99, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0xfe9d, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0xfea1, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0xfea5, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0xfea9, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0xfeab, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0xfead, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0xfeaf, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0xfeb1, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0xfeb5, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0xfeb9, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0xfebd, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0xfec1, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0xfec5, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0xfec9, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0xfecd, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0xfed1, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0xfed5, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0xfed9, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0xfedd, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0xfee1, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0xfee5, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0xfee9, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0xfeed, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0xfeef, 0, 0, 0, g(Yes, No, false, false, "", "ى")}, + {0xfef1, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0xfef5, 0, 0, 1, g(Yes, No, false, false, "", "لآ")}, + {0xfef7, 0, 0, 1, g(Yes, No, false, false, "", "لأ")}, + {0xfef9, 0, 0, 1, g(Yes, No, false, false, "", "لإ")}, + {0xfefb, 0, 0, 0, g(Yes, No, false, false, "", "لا")}, + {0xfefd, 0, 0, 0, f(Yes, false, "")}, + {0xff01, 0, 0, 0, g(Yes, No, false, false, "", "!")}, + {0xff02, 0, 0, 0, g(Yes, No, false, false, "", "\"")}, + {0xff03, 0, 0, 0, g(Yes, No, false, false, "", "#")}, + {0xff04, 0, 0, 0, g(Yes, No, false, false, "", "$")}, + {0xff05, 0, 0, 0, g(Yes, No, false, false, "", "%")}, + {0xff06, 0, 0, 0, g(Yes, No, false, false, "", "&")}, + {0xff07, 0, 0, 0, g(Yes, No, false, false, "", "'")}, + {0xff08, 0, 0, 0, g(Yes, No, false, false, "", "(")}, + {0xff09, 0, 0, 0, g(Yes, No, false, false, "", ")")}, + {0xff0a, 0, 0, 0, g(Yes, No, false, false, "", "*")}, + {0xff0b, 0, 0, 0, g(Yes, No, false, false, "", "+")}, + {0xff0c, 0, 0, 0, g(Yes, No, false, false, "", ",")}, + {0xff0d, 0, 0, 0, g(Yes, No, false, false, "", "-")}, + {0xff0e, 0, 0, 0, g(Yes, No, false, false, "", ".")}, + {0xff0f, 0, 0, 0, g(Yes, No, false, false, "", "/")}, + {0xff10, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0xff11, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0xff12, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0xff13, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0xff14, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0xff15, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0xff16, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0xff17, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0xff18, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0xff19, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0xff1a, 0, 0, 0, g(Yes, No, false, false, "", ":")}, + {0xff1b, 0, 0, 0, g(Yes, No, false, false, "", ";")}, + {0xff1c, 0, 0, 0, g(Yes, No, false, false, "", "<")}, + {0xff1d, 0, 0, 0, g(Yes, No, false, false, "", "=")}, + {0xff1e, 0, 0, 0, g(Yes, No, false, false, "", ">")}, + {0xff1f, 0, 0, 0, g(Yes, No, false, false, "", "?")}, + {0xff20, 0, 0, 0, g(Yes, No, false, false, "", "@")}, + {0xff21, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0xff22, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0xff23, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0xff24, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0xff25, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0xff26, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0xff27, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0xff28, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0xff29, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0xff2a, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0xff2b, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0xff2c, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0xff2d, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0xff2e, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0xff2f, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0xff30, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0xff31, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0xff32, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0xff33, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0xff34, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0xff35, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0xff36, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0xff37, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0xff38, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0xff39, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0xff3a, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0xff3b, 0, 0, 0, g(Yes, No, false, false, "", "[")}, + {0xff3c, 0, 0, 0, g(Yes, No, false, false, "", "\\")}, + {0xff3d, 0, 0, 0, g(Yes, No, false, false, "", "]")}, + {0xff3e, 0, 0, 0, g(Yes, No, false, false, "", "^")}, + {0xff3f, 0, 0, 0, g(Yes, No, false, false, "", "_")}, + {0xff40, 0, 0, 0, g(Yes, No, false, false, "", "`")}, + {0xff41, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0xff42, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0xff43, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0xff44, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0xff45, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0xff46, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0xff47, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0xff48, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0xff49, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0xff4a, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0xff4b, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0xff4c, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0xff4d, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0xff4e, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0xff4f, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0xff50, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0xff51, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0xff52, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0xff53, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0xff54, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0xff55, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0xff56, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0xff57, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0xff58, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0xff59, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0xff5a, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0xff5b, 0, 0, 0, g(Yes, No, false, false, "", "{")}, + {0xff5c, 0, 0, 0, g(Yes, No, false, false, "", "|")}, + {0xff5d, 0, 0, 0, g(Yes, No, false, false, "", "}")}, + {0xff5e, 0, 0, 0, g(Yes, No, false, false, "", "~")}, + {0xff5f, 0, 0, 0, g(Yes, No, false, false, "", "⦅")}, + {0xff60, 0, 0, 0, g(Yes, No, false, false, "", "⦆")}, + {0xff61, 0, 0, 0, g(Yes, No, false, false, "", "。")}, + {0xff62, 0, 0, 0, g(Yes, No, false, false, "", "「")}, + {0xff63, 0, 0, 0, g(Yes, No, false, false, "", "」")}, + {0xff64, 0, 0, 0, g(Yes, No, false, false, "", "、")}, + {0xff65, 0, 0, 0, g(Yes, No, false, false, "", "・")}, + {0xff66, 0, 0, 0, g(Yes, No, false, false, "", "ヲ")}, + {0xff67, 0, 0, 0, g(Yes, No, false, false, "", "ァ")}, + {0xff68, 0, 0, 0, g(Yes, No, false, false, "", "ィ")}, + {0xff69, 0, 0, 0, g(Yes, No, false, false, "", "ゥ")}, + {0xff6a, 0, 0, 0, g(Yes, No, false, false, "", "ェ")}, + {0xff6b, 0, 0, 0, g(Yes, No, false, false, "", "ォ")}, + {0xff6c, 0, 0, 0, g(Yes, No, false, false, "", "ャ")}, + {0xff6d, 0, 0, 0, g(Yes, No, false, false, "", "ュ")}, + {0xff6e, 0, 0, 0, g(Yes, No, false, false, "", "ョ")}, + {0xff6f, 0, 0, 0, g(Yes, No, false, false, "", "ッ")}, + {0xff70, 0, 0, 0, g(Yes, No, false, false, "", "ー")}, + {0xff71, 0, 0, 0, g(Yes, No, false, false, "", "ア")}, + {0xff72, 0, 0, 0, g(Yes, No, false, false, "", "イ")}, + {0xff73, 0, 0, 0, g(Yes, No, false, false, "", "ウ")}, + {0xff74, 0, 0, 0, g(Yes, No, false, false, "", "エ")}, + {0xff75, 0, 0, 0, g(Yes, No, false, false, "", "オ")}, + {0xff76, 0, 0, 0, g(Yes, No, false, false, "", "カ")}, + {0xff77, 0, 0, 0, g(Yes, No, false, false, "", "キ")}, + {0xff78, 0, 0, 0, g(Yes, No, false, false, "", "ク")}, + {0xff79, 0, 0, 0, g(Yes, No, false, false, "", "ケ")}, + {0xff7a, 0, 0, 0, g(Yes, No, false, false, "", "コ")}, + {0xff7b, 0, 0, 0, g(Yes, No, false, false, "", "サ")}, + {0xff7c, 0, 0, 0, g(Yes, No, false, false, "", "シ")}, + {0xff7d, 0, 0, 0, g(Yes, No, false, false, "", "ス")}, + {0xff7e, 0, 0, 0, g(Yes, No, false, false, "", "セ")}, + {0xff7f, 0, 0, 0, g(Yes, No, false, false, "", "ソ")}, + {0xff80, 0, 0, 0, g(Yes, No, false, false, "", "タ")}, + {0xff81, 0, 0, 0, g(Yes, No, false, false, "", "チ")}, + {0xff82, 0, 0, 0, g(Yes, No, false, false, "", "ツ")}, + {0xff83, 0, 0, 0, g(Yes, No, false, false, "", "テ")}, + {0xff84, 0, 0, 0, g(Yes, No, false, false, "", "ト")}, + {0xff85, 0, 0, 0, g(Yes, No, false, false, "", "ナ")}, + {0xff86, 0, 0, 0, g(Yes, No, false, false, "", "ニ")}, + {0xff87, 0, 0, 0, g(Yes, No, false, false, "", "ヌ")}, + {0xff88, 0, 0, 0, g(Yes, No, false, false, "", "ネ")}, + {0xff89, 0, 0, 0, g(Yes, No, false, false, "", "ノ")}, + {0xff8a, 0, 0, 0, g(Yes, No, false, false, "", "ハ")}, + {0xff8b, 0, 0, 0, g(Yes, No, false, false, "", "ヒ")}, + {0xff8c, 0, 0, 0, g(Yes, No, false, false, "", "フ")}, + {0xff8d, 0, 0, 0, g(Yes, No, false, false, "", "ヘ")}, + {0xff8e, 0, 0, 0, g(Yes, No, false, false, "", "ホ")}, + {0xff8f, 0, 0, 0, g(Yes, No, false, false, "", "マ")}, + {0xff90, 0, 0, 0, g(Yes, No, false, false, "", "ミ")}, + {0xff91, 0, 0, 0, g(Yes, No, false, false, "", "ム")}, + {0xff92, 0, 0, 0, g(Yes, No, false, false, "", "メ")}, + {0xff93, 0, 0, 0, g(Yes, No, false, false, "", "モ")}, + {0xff94, 0, 0, 0, g(Yes, No, false, false, "", "ヤ")}, + {0xff95, 0, 0, 0, g(Yes, No, false, false, "", "ユ")}, + {0xff96, 0, 0, 0, g(Yes, No, false, false, "", "ヨ")}, + {0xff97, 0, 0, 0, g(Yes, No, false, false, "", "ラ")}, + {0xff98, 0, 0, 0, g(Yes, No, false, false, "", "リ")}, + {0xff99, 0, 0, 0, g(Yes, No, false, false, "", "ル")}, + {0xff9a, 0, 0, 0, g(Yes, No, false, false, "", "レ")}, + {0xff9b, 0, 0, 0, g(Yes, No, false, false, "", "ロ")}, + {0xff9c, 0, 0, 0, g(Yes, No, false, false, "", "ワ")}, + {0xff9d, 0, 0, 0, g(Yes, No, false, false, "", "ン")}, + {0xff9e, 0, 1, 1, g(Yes, No, false, false, "", "゙")}, + {0xff9f, 0, 1, 1, g(Yes, No, false, false, "", "゚")}, + {0xffa0, 0, 0, 0, g(Yes, No, false, false, "", "ᅠ")}, + {0xffa1, 0, 0, 0, g(Yes, No, false, false, "", "ᄀ")}, + {0xffa2, 0, 0, 0, g(Yes, No, false, false, "", "ᄁ")}, + {0xffa3, 0, 1, 1, g(Yes, No, false, false, "", "ᆪ")}, + {0xffa4, 0, 0, 0, g(Yes, No, false, false, "", "ᄂ")}, + {0xffa5, 0, 1, 1, g(Yes, No, false, false, "", "ᆬ")}, + {0xffa6, 0, 1, 1, g(Yes, No, false, false, "", "ᆭ")}, + {0xffa7, 0, 0, 0, g(Yes, No, false, false, "", "ᄃ")}, + {0xffa8, 0, 0, 0, g(Yes, No, false, false, "", "ᄄ")}, + {0xffa9, 0, 0, 0, g(Yes, No, false, false, "", "ᄅ")}, + {0xffaa, 0, 1, 1, g(Yes, No, false, false, "", "ᆰ")}, + {0xffab, 0, 1, 1, g(Yes, No, false, false, "", "ᆱ")}, + {0xffac, 0, 1, 1, g(Yes, No, false, false, "", "ᆲ")}, + {0xffad, 0, 1, 1, g(Yes, No, false, false, "", "ᆳ")}, + {0xffae, 0, 1, 1, g(Yes, No, false, false, "", "ᆴ")}, + {0xffaf, 0, 1, 1, g(Yes, No, false, false, "", "ᆵ")}, + {0xffb0, 0, 0, 0, g(Yes, No, false, false, "", "ᄚ")}, + {0xffb1, 0, 0, 0, g(Yes, No, false, false, "", "ᄆ")}, + {0xffb2, 0, 0, 0, g(Yes, No, false, false, "", "ᄇ")}, + {0xffb3, 0, 0, 0, g(Yes, No, false, false, "", "ᄈ")}, + {0xffb4, 0, 0, 0, g(Yes, No, false, false, "", "ᄡ")}, + {0xffb5, 0, 0, 0, g(Yes, No, false, false, "", "ᄉ")}, + {0xffb6, 0, 0, 0, g(Yes, No, false, false, "", "ᄊ")}, + {0xffb7, 0, 0, 0, g(Yes, No, false, false, "", "ᄋ")}, + {0xffb8, 0, 0, 0, g(Yes, No, false, false, "", "ᄌ")}, + {0xffb9, 0, 0, 0, g(Yes, No, false, false, "", "ᄍ")}, + {0xffba, 0, 0, 0, g(Yes, No, false, false, "", "ᄎ")}, + {0xffbb, 0, 0, 0, g(Yes, No, false, false, "", "ᄏ")}, + {0xffbc, 0, 0, 0, g(Yes, No, false, false, "", "ᄐ")}, + {0xffbd, 0, 0, 0, g(Yes, No, false, false, "", "ᄑ")}, + {0xffbe, 0, 0, 0, g(Yes, No, false, false, "", "ᄒ")}, + {0xffbf, 0, 0, 0, f(Yes, false, "")}, + {0xffc2, 0, 1, 1, g(Yes, No, false, false, "", "ᅡ")}, + {0xffc3, 0, 1, 1, g(Yes, No, false, false, "", "ᅢ")}, + {0xffc4, 0, 1, 1, g(Yes, No, false, false, "", "ᅣ")}, + {0xffc5, 0, 1, 1, g(Yes, No, false, false, "", "ᅤ")}, + {0xffc6, 0, 1, 1, g(Yes, No, false, false, "", "ᅥ")}, + {0xffc7, 0, 1, 1, g(Yes, No, false, false, "", "ᅦ")}, + {0xffc8, 0, 0, 0, f(Yes, false, "")}, + {0xffca, 0, 1, 1, g(Yes, No, false, false, "", "ᅧ")}, + {0xffcb, 0, 1, 1, g(Yes, No, false, false, "", "ᅨ")}, + {0xffcc, 0, 1, 1, g(Yes, No, false, false, "", "ᅩ")}, + {0xffcd, 0, 1, 1, g(Yes, No, false, false, "", "ᅪ")}, + {0xffce, 0, 1, 1, g(Yes, No, false, false, "", "ᅫ")}, + {0xffcf, 0, 1, 1, g(Yes, No, false, false, "", "ᅬ")}, + {0xffd0, 0, 0, 0, f(Yes, false, "")}, + {0xffd2, 0, 1, 1, g(Yes, No, false, false, "", "ᅭ")}, + {0xffd3, 0, 1, 1, g(Yes, No, false, false, "", "ᅮ")}, + {0xffd4, 0, 1, 1, g(Yes, No, false, false, "", "ᅯ")}, + {0xffd5, 0, 1, 1, g(Yes, No, false, false, "", "ᅰ")}, + {0xffd6, 0, 1, 1, g(Yes, No, false, false, "", "ᅱ")}, + {0xffd7, 0, 1, 1, g(Yes, No, false, false, "", "ᅲ")}, + {0xffd8, 0, 0, 0, f(Yes, false, "")}, + {0xffda, 0, 1, 1, g(Yes, No, false, false, "", "ᅳ")}, + {0xffdb, 0, 1, 1, g(Yes, No, false, false, "", "ᅴ")}, + {0xffdc, 0, 1, 1, g(Yes, No, false, false, "", "ᅵ")}, + {0xffdd, 0, 0, 0, f(Yes, false, "")}, + {0xffe0, 0, 0, 0, g(Yes, No, false, false, "", "¢")}, + {0xffe1, 0, 0, 0, g(Yes, No, false, false, "", "£")}, + {0xffe2, 0, 0, 0, g(Yes, No, false, false, "", "¬")}, + {0xffe3, 0, 0, 1, g(Yes, No, false, false, "", " ̄")}, + {0xffe4, 0, 0, 0, g(Yes, No, false, false, "", "¦")}, + {0xffe5, 0, 0, 0, g(Yes, No, false, false, "", "¥")}, + {0xffe6, 0, 0, 0, g(Yes, No, false, false, "", "₩")}, + {0xffe7, 0, 0, 0, f(Yes, false, "")}, + {0xffe8, 0, 0, 0, g(Yes, No, false, false, "", "│")}, + {0xffe9, 0, 0, 0, g(Yes, No, false, false, "", "←")}, + {0xffea, 0, 0, 0, g(Yes, No, false, false, "", "↑")}, + {0xffeb, 0, 0, 0, g(Yes, No, false, false, "", "→")}, + {0xffec, 0, 0, 0, g(Yes, No, false, false, "", "↓")}, + {0xffed, 0, 0, 0, g(Yes, No, false, false, "", "■")}, + {0xffee, 0, 0, 0, g(Yes, No, false, false, "", "○")}, + {0xffef, 0, 0, 0, f(Yes, false, "")}, + {0x101fd, 220, 1, 1, f(Yes, false, "")}, + {0x101fe, 0, 0, 0, f(Yes, false, "")}, + {0x102e0, 220, 1, 1, f(Yes, false, "")}, + {0x102e1, 0, 0, 0, f(Yes, false, "")}, + {0x10376, 230, 1, 1, f(Yes, false, "")}, + {0x1037b, 0, 0, 0, f(Yes, false, "")}, + {0x10a0d, 220, 1, 1, f(Yes, false, "")}, + {0x10a0e, 0, 0, 0, f(Yes, false, "")}, + {0x10a0f, 230, 1, 1, f(Yes, false, "")}, + {0x10a10, 0, 0, 0, f(Yes, false, "")}, + {0x10a38, 230, 1, 1, f(Yes, false, "")}, + {0x10a39, 1, 1, 1, f(Yes, false, "")}, + {0x10a3a, 220, 1, 1, f(Yes, false, "")}, + {0x10a3b, 0, 0, 0, f(Yes, false, "")}, + {0x10a3f, 9, 1, 1, f(Yes, false, "")}, + {0x10a40, 0, 0, 0, f(Yes, false, "")}, + {0x10ae5, 230, 1, 1, f(Yes, false, "")}, + {0x10ae6, 220, 1, 1, f(Yes, false, "")}, + {0x10ae7, 0, 0, 0, f(Yes, false, "")}, + {0x11046, 9, 1, 1, f(Yes, false, "")}, + {0x11047, 0, 0, 0, f(Yes, false, "")}, + {0x1107f, 9, 1, 1, f(Yes, false, "")}, + {0x11080, 0, 0, 0, f(Yes, false, "")}, + {0x11099, 0, 0, 0, f(Yes, true, "")}, + {0x1109a, 0, 0, 1, f(Yes, false, "𑂚")}, + {0x1109b, 0, 0, 0, f(Yes, true, "")}, + {0x1109c, 0, 0, 1, f(Yes, false, "𑂜")}, + {0x1109d, 0, 0, 0, f(Yes, false, "")}, + {0x110a5, 0, 0, 0, f(Yes, true, "")}, + {0x110a6, 0, 0, 0, f(Yes, false, "")}, + {0x110ab, 0, 0, 1, f(Yes, false, "𑂫")}, + {0x110ac, 0, 0, 0, f(Yes, false, "")}, + {0x110b9, 9, 1, 1, f(Yes, false, "")}, + {0x110ba, 7, 1, 1, f(Maybe, false, "")}, + {0x110bb, 0, 0, 0, f(Yes, false, "")}, + {0x11100, 230, 1, 1, f(Yes, false, "")}, + {0x11103, 0, 0, 0, f(Yes, false, "")}, + {0x11127, 0, 1, 1, f(Maybe, false, "")}, + {0x11128, 0, 0, 0, f(Yes, false, "")}, + {0x1112e, 0, 0, 1, f(Yes, false, "𑄮")}, + {0x1112f, 0, 0, 1, f(Yes, false, "𑄯")}, + {0x11130, 0, 0, 0, f(Yes, false, "")}, + {0x11131, 0, 0, 0, f(Yes, true, "")}, + {0x11133, 9, 1, 1, f(Yes, false, "")}, + {0x11135, 0, 0, 0, f(Yes, false, "")}, + {0x11173, 7, 1, 1, f(Yes, false, "")}, + {0x11174, 0, 0, 0, f(Yes, false, "")}, + {0x111c0, 9, 1, 1, f(Yes, false, "")}, + {0x111c1, 0, 0, 0, f(Yes, false, "")}, + {0x111ca, 7, 1, 1, f(Yes, false, "")}, + {0x111cb, 0, 0, 0, f(Yes, false, "")}, + {0x11235, 9, 1, 1, f(Yes, false, "")}, + {0x11236, 7, 1, 1, f(Yes, false, "")}, + {0x11237, 0, 0, 0, f(Yes, false, "")}, + {0x112e9, 7, 1, 1, f(Yes, false, "")}, + {0x112ea, 9, 1, 1, f(Yes, false, "")}, + {0x112eb, 0, 0, 0, f(Yes, false, "")}, + {0x1133c, 7, 1, 1, f(Yes, false, "")}, + {0x1133d, 0, 0, 0, f(Yes, false, "")}, + {0x1133e, 0, 1, 1, f(Maybe, false, "")}, + {0x1133f, 0, 0, 0, f(Yes, false, "")}, + {0x11347, 0, 0, 0, f(Yes, true, "")}, + {0x11348, 0, 0, 0, f(Yes, false, "")}, + {0x1134b, 0, 0, 1, f(Yes, false, "𑍋")}, + {0x1134c, 0, 0, 1, f(Yes, false, "𑍌")}, + {0x1134d, 9, 1, 1, f(Yes, false, "")}, + {0x1134e, 0, 0, 0, f(Yes, false, "")}, + {0x11357, 0, 1, 1, f(Maybe, false, "")}, + {0x11358, 0, 0, 0, f(Yes, false, "")}, + {0x11366, 230, 1, 1, f(Yes, false, "")}, + {0x1136d, 0, 0, 0, f(Yes, false, "")}, + {0x11370, 230, 1, 1, f(Yes, false, "")}, + {0x11375, 0, 0, 0, f(Yes, false, "")}, + {0x11442, 9, 1, 1, f(Yes, false, "")}, + {0x11443, 0, 0, 0, f(Yes, false, "")}, + {0x11446, 7, 1, 1, f(Yes, false, "")}, + {0x11447, 0, 0, 0, f(Yes, false, "")}, + {0x114b0, 0, 1, 1, f(Maybe, false, "")}, + {0x114b1, 0, 0, 0, f(Yes, false, "")}, + {0x114b9, 0, 0, 0, f(Yes, true, "")}, + {0x114ba, 0, 1, 1, f(Maybe, false, "")}, + {0x114bb, 0, 0, 1, f(Yes, false, "𑒻")}, + {0x114bc, 0, 0, 1, f(Yes, false, "𑒼")}, + {0x114bd, 0, 1, 1, f(Maybe, false, "")}, + {0x114be, 0, 0, 1, f(Yes, false, "𑒾")}, + {0x114bf, 0, 0, 0, f(Yes, false, "")}, + {0x114c2, 9, 1, 1, f(Yes, false, "")}, + {0x114c3, 7, 1, 1, f(Yes, false, "")}, + {0x114c4, 0, 0, 0, f(Yes, false, "")}, + {0x115af, 0, 1, 1, f(Maybe, false, "")}, + {0x115b0, 0, 0, 0, f(Yes, false, "")}, + {0x115b8, 0, 0, 0, f(Yes, true, "")}, + {0x115ba, 0, 0, 1, f(Yes, false, "𑖺")}, + {0x115bb, 0, 0, 1, f(Yes, false, "𑖻")}, + {0x115bc, 0, 0, 0, f(Yes, false, "")}, + {0x115bf, 9, 1, 1, f(Yes, false, "")}, + {0x115c0, 7, 1, 1, f(Yes, false, "")}, + {0x115c1, 0, 0, 0, f(Yes, false, "")}, + {0x1163f, 9, 1, 1, f(Yes, false, "")}, + {0x11640, 0, 0, 0, f(Yes, false, "")}, + {0x116b6, 9, 1, 1, f(Yes, false, "")}, + {0x116b7, 7, 1, 1, f(Yes, false, "")}, + {0x116b8, 0, 0, 0, f(Yes, false, "")}, + {0x1172b, 9, 1, 1, f(Yes, false, "")}, + {0x1172c, 0, 0, 0, f(Yes, false, "")}, + {0x11c3f, 9, 1, 1, f(Yes, false, "")}, + {0x11c40, 0, 0, 0, f(Yes, false, "")}, + {0x16af0, 1, 1, 1, f(Yes, false, "")}, + {0x16af5, 0, 0, 0, f(Yes, false, "")}, + {0x16b30, 230, 1, 1, f(Yes, false, "")}, + {0x16b37, 0, 0, 0, f(Yes, false, "")}, + {0x1bc9e, 1, 1, 1, f(Yes, false, "")}, + {0x1bc9f, 0, 0, 0, f(Yes, false, "")}, + {0x1d15e, 0, 0, 1, f(No, false, "𝅗𝅥")}, + {0x1d15f, 0, 0, 1, f(No, false, "𝅘𝅥")}, + {0x1d160, 0, 0, 2, f(No, false, "𝅘𝅥𝅮")}, + {0x1d161, 0, 0, 2, f(No, false, "𝅘𝅥𝅯")}, + {0x1d162, 0, 0, 2, f(No, false, "𝅘𝅥𝅰")}, + {0x1d163, 0, 0, 2, f(No, false, "𝅘𝅥𝅱")}, + {0x1d164, 0, 0, 2, f(No, false, "𝅘𝅥𝅲")}, + {0x1d165, 216, 1, 1, f(Yes, false, "")}, + {0x1d167, 1, 1, 1, f(Yes, false, "")}, + {0x1d16a, 0, 0, 0, f(Yes, false, "")}, + {0x1d16d, 226, 1, 1, f(Yes, false, "")}, + {0x1d16e, 216, 1, 1, f(Yes, false, "")}, + {0x1d173, 0, 0, 0, f(Yes, false, "")}, + {0x1d17b, 220, 1, 1, f(Yes, false, "")}, + {0x1d183, 0, 0, 0, f(Yes, false, "")}, + {0x1d185, 230, 1, 1, f(Yes, false, "")}, + {0x1d18a, 220, 1, 1, f(Yes, false, "")}, + {0x1d18c, 0, 0, 0, f(Yes, false, "")}, + {0x1d1aa, 230, 1, 1, f(Yes, false, "")}, + {0x1d1ae, 0, 0, 0, f(Yes, false, "")}, + {0x1d1bb, 0, 0, 1, f(No, false, "𝆹𝅥")}, + {0x1d1bc, 0, 0, 1, f(No, false, "𝆺𝅥")}, + {0x1d1bd, 0, 0, 2, f(No, false, "𝆹𝅥𝅮")}, + {0x1d1be, 0, 0, 2, f(No, false, "𝆺𝅥𝅮")}, + {0x1d1bf, 0, 0, 2, f(No, false, "𝆹𝅥𝅯")}, + {0x1d1c0, 0, 0, 2, f(No, false, "𝆺𝅥𝅯")}, + {0x1d1c1, 0, 0, 0, f(Yes, false, "")}, + {0x1d242, 230, 1, 1, f(Yes, false, "")}, + {0x1d245, 0, 0, 0, f(Yes, false, "")}, + {0x1d400, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d401, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d402, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d403, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d404, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d405, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d406, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d407, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d408, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d409, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d40a, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d40b, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d40c, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d40d, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d40e, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d40f, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d410, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d411, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d412, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d413, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d414, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d415, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d416, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d417, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d418, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d419, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d41a, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d41b, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d41c, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d41d, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d41e, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d41f, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d420, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d421, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d422, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d423, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d424, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d425, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d426, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d427, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d428, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d429, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d42a, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d42b, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d42c, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d42d, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d42e, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d42f, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d430, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d431, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d432, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d433, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d434, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d435, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d436, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d437, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d438, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d439, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d43a, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d43b, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d43c, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d43d, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d43e, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d43f, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d440, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d441, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d442, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d443, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d444, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d445, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d446, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d447, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d448, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d449, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d44a, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d44b, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d44c, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d44d, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d44e, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d44f, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d450, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d451, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d452, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d453, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d454, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d455, 0, 0, 0, f(Yes, false, "")}, + {0x1d456, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d457, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d458, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d459, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d45a, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d45b, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d45c, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d45d, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d45e, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d45f, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d460, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d461, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d462, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d463, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d464, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d465, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d466, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d467, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d468, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d469, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d46a, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d46b, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d46c, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d46d, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d46e, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d46f, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d470, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d471, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d472, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d473, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d474, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d475, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d476, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d477, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d478, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d479, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d47a, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d47b, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d47c, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d47d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d47e, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d47f, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d480, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d481, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d482, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d483, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d484, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d485, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d486, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d487, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d488, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d489, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d48a, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d48b, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d48c, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d48d, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d48e, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d48f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d490, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d491, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d492, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d493, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d494, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d495, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d496, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d497, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d498, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d499, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d49a, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d49b, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d49c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d49d, 0, 0, 0, f(Yes, false, "")}, + {0x1d49e, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d49f, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d4a0, 0, 0, 0, f(Yes, false, "")}, + {0x1d4a2, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d4a3, 0, 0, 0, f(Yes, false, "")}, + {0x1d4a5, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d4a6, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d4a7, 0, 0, 0, f(Yes, false, "")}, + {0x1d4a9, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d4aa, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d4ab, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d4ac, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d4ad, 0, 0, 0, f(Yes, false, "")}, + {0x1d4ae, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d4af, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d4b0, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d4b1, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d4b2, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d4b3, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d4b4, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d4b5, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d4b6, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d4b7, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d4b8, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d4b9, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d4ba, 0, 0, 0, f(Yes, false, "")}, + {0x1d4bb, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d4bc, 0, 0, 0, f(Yes, false, "")}, + {0x1d4bd, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d4be, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d4bf, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d4c0, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d4c1, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d4c2, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d4c3, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d4c4, 0, 0, 0, f(Yes, false, "")}, + {0x1d4c5, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d4c6, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d4c7, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d4c8, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d4c9, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d4ca, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d4cb, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d4cc, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d4cd, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d4ce, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d4cf, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d4d0, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d4d1, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d4d2, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d4d3, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d4d4, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d4d5, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d4d6, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d4d7, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d4d8, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d4d9, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d4da, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d4db, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d4dc, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d4dd, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d4de, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d4df, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d4e0, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d4e1, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d4e2, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d4e3, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d4e4, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d4e5, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d4e6, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d4e7, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d4e8, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d4e9, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d4ea, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d4eb, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d4ec, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d4ed, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d4ee, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d4ef, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d4f0, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d4f1, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d4f2, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d4f3, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d4f4, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d4f5, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d4f6, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d4f7, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d4f8, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d4f9, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d4fa, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d4fb, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d4fc, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d4fd, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d4fe, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d4ff, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d500, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d501, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d502, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d503, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d504, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d505, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d506, 0, 0, 0, f(Yes, false, "")}, + {0x1d507, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d508, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d509, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d50a, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d50b, 0, 0, 0, f(Yes, false, "")}, + {0x1d50d, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d50e, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d50f, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d510, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d511, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d512, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d513, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d514, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d515, 0, 0, 0, f(Yes, false, "")}, + {0x1d516, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d517, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d518, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d519, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d51a, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d51b, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d51c, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d51d, 0, 0, 0, f(Yes, false, "")}, + {0x1d51e, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d51f, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d520, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d521, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d522, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d523, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d524, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d525, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d526, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d527, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d528, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d529, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d52a, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d52b, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d52c, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d52d, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d52e, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d52f, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d530, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d531, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d532, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d533, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d534, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d535, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d536, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d537, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d538, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d539, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d53a, 0, 0, 0, f(Yes, false, "")}, + {0x1d53b, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d53c, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d53d, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d53e, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d53f, 0, 0, 0, f(Yes, false, "")}, + {0x1d540, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d541, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d542, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d543, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d544, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d545, 0, 0, 0, f(Yes, false, "")}, + {0x1d546, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d547, 0, 0, 0, f(Yes, false, "")}, + {0x1d54a, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d54b, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d54c, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d54d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d54e, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d54f, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d550, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d551, 0, 0, 0, f(Yes, false, "")}, + {0x1d552, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d553, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d554, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d555, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d556, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d557, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d558, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d559, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d55a, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d55b, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d55c, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d55d, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d55e, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d55f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d560, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d561, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d562, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d563, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d564, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d565, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d566, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d567, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d568, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d569, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d56a, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d56b, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d56c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d56d, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d56e, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d56f, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d570, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d571, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d572, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d573, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d574, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d575, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d576, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d577, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d578, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d579, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d57a, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d57b, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d57c, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d57d, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d57e, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d57f, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d580, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d581, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d582, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d583, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d584, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d585, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d586, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d587, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d588, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d589, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d58a, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d58b, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d58c, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d58d, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d58e, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d58f, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d590, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d591, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d592, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d593, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d594, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d595, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d596, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d597, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d598, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d599, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d59a, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d59b, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d59c, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d59d, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d59e, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d59f, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d5a0, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d5a1, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d5a2, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d5a3, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d5a4, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d5a5, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d5a6, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d5a7, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d5a8, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d5a9, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d5aa, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d5ab, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d5ac, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d5ad, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d5ae, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d5af, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d5b0, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d5b1, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d5b2, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d5b3, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d5b4, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d5b5, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d5b6, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d5b7, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d5b8, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d5b9, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d5ba, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d5bb, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d5bc, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d5bd, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d5be, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d5bf, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d5c0, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d5c1, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d5c2, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d5c3, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d5c4, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d5c5, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d5c6, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d5c7, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d5c8, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d5c9, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d5ca, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d5cb, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d5cc, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d5cd, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d5ce, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d5cf, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d5d0, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d5d1, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d5d2, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d5d3, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d5d4, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d5d5, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d5d6, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d5d7, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d5d8, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d5d9, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d5da, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d5db, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d5dc, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d5dd, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d5de, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d5df, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d5e0, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d5e1, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d5e2, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d5e3, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d5e4, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d5e5, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d5e6, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d5e7, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d5e8, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d5e9, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d5ea, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d5eb, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d5ec, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d5ed, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d5ee, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d5ef, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d5f0, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d5f1, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d5f2, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d5f3, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d5f4, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d5f5, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d5f6, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d5f7, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d5f8, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d5f9, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d5fa, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d5fb, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d5fc, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d5fd, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d5fe, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d5ff, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d600, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d601, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d602, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d603, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d604, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d605, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d606, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d607, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d608, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d609, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d60a, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d60b, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d60c, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d60d, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d60e, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d60f, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d610, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d611, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d612, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d613, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d614, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d615, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d616, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d617, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d618, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d619, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d61a, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d61b, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d61c, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d61d, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d61e, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d61f, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d620, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d621, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d622, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d623, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d624, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d625, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d626, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d627, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d628, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d629, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d62a, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d62b, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d62c, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d62d, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d62e, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d62f, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d630, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d631, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d632, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d633, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d634, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d635, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d636, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d637, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d638, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d639, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d63a, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d63b, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d63c, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d63d, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d63e, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d63f, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d640, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d641, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d642, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d643, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d644, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d645, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d646, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d647, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d648, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d649, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d64a, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d64b, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d64c, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d64d, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d64e, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d64f, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d650, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d651, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d652, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d653, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d654, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d655, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d656, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d657, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d658, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d659, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d65a, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d65b, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d65c, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d65d, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d65e, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d65f, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d660, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d661, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d662, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d663, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d664, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d665, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d666, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d667, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d668, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d669, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d66a, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d66b, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d66c, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d66d, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d66e, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d66f, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d670, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1d671, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1d672, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1d673, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1d674, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1d675, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1d676, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1d677, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1d678, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1d679, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1d67a, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1d67b, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1d67c, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1d67d, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1d67e, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1d67f, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1d680, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1d681, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1d682, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1d683, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1d684, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1d685, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1d686, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1d687, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1d688, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1d689, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1d68a, 0, 0, 0, g(Yes, No, false, false, "", "a")}, + {0x1d68b, 0, 0, 0, g(Yes, No, false, false, "", "b")}, + {0x1d68c, 0, 0, 0, g(Yes, No, false, false, "", "c")}, + {0x1d68d, 0, 0, 0, g(Yes, No, false, false, "", "d")}, + {0x1d68e, 0, 0, 0, g(Yes, No, false, false, "", "e")}, + {0x1d68f, 0, 0, 0, g(Yes, No, false, false, "", "f")}, + {0x1d690, 0, 0, 0, g(Yes, No, false, false, "", "g")}, + {0x1d691, 0, 0, 0, g(Yes, No, false, false, "", "h")}, + {0x1d692, 0, 0, 0, g(Yes, No, false, false, "", "i")}, + {0x1d693, 0, 0, 0, g(Yes, No, false, false, "", "j")}, + {0x1d694, 0, 0, 0, g(Yes, No, false, false, "", "k")}, + {0x1d695, 0, 0, 0, g(Yes, No, false, false, "", "l")}, + {0x1d696, 0, 0, 0, g(Yes, No, false, false, "", "m")}, + {0x1d697, 0, 0, 0, g(Yes, No, false, false, "", "n")}, + {0x1d698, 0, 0, 0, g(Yes, No, false, false, "", "o")}, + {0x1d699, 0, 0, 0, g(Yes, No, false, false, "", "p")}, + {0x1d69a, 0, 0, 0, g(Yes, No, false, false, "", "q")}, + {0x1d69b, 0, 0, 0, g(Yes, No, false, false, "", "r")}, + {0x1d69c, 0, 0, 0, g(Yes, No, false, false, "", "s")}, + {0x1d69d, 0, 0, 0, g(Yes, No, false, false, "", "t")}, + {0x1d69e, 0, 0, 0, g(Yes, No, false, false, "", "u")}, + {0x1d69f, 0, 0, 0, g(Yes, No, false, false, "", "v")}, + {0x1d6a0, 0, 0, 0, g(Yes, No, false, false, "", "w")}, + {0x1d6a1, 0, 0, 0, g(Yes, No, false, false, "", "x")}, + {0x1d6a2, 0, 0, 0, g(Yes, No, false, false, "", "y")}, + {0x1d6a3, 0, 0, 0, g(Yes, No, false, false, "", "z")}, + {0x1d6a4, 0, 0, 0, g(Yes, No, false, false, "", "ı")}, + {0x1d6a5, 0, 0, 0, g(Yes, No, false, false, "", "ȷ")}, + {0x1d6a6, 0, 0, 0, f(Yes, false, "")}, + {0x1d6a8, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d6a9, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d6aa, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d6ab, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d6ac, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d6ad, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d6ae, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d6af, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6b0, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d6b1, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d6b2, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d6b3, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d6b4, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d6b5, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d6b6, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d6b7, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d6b8, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d6b9, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6ba, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d6bb, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d6bc, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d6bd, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d6be, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d6bf, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d6c0, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d6c1, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d6c2, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d6c3, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d6c4, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d6c5, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d6c6, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d6c7, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d6c8, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d6c9, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d6ca, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d6cb, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d6cc, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d6cd, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d6ce, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d6cf, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d6d0, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d6d1, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d6d2, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d6d3, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d6d4, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d6d5, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d6d6, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d6d7, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d6d8, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d6d9, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d6da, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d6db, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d6dc, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d6dd, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d6de, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d6df, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d6e0, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d6e1, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d6e2, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d6e3, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d6e4, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d6e5, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d6e6, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d6e7, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d6e8, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d6e9, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6ea, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d6eb, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d6ec, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d6ed, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d6ee, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d6ef, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d6f0, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d6f1, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d6f2, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d6f3, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d6f4, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d6f5, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d6f6, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d6f7, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d6f8, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d6f9, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d6fa, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d6fb, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d6fc, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d6fd, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d6fe, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d6ff, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d700, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d701, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d702, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d703, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d704, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d705, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d706, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d707, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d708, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d709, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d70a, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d70b, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d70c, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d70d, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d70e, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d70f, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d710, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d711, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d712, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d713, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d714, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d715, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d716, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d717, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d718, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d719, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d71a, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d71b, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d71c, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d71d, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d71e, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d71f, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d720, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d721, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d722, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d723, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d724, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d725, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d726, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d727, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d728, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d729, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d72a, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d72b, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d72c, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d72d, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d72e, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d72f, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d730, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d731, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d732, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d733, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d734, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d735, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d736, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d737, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d738, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d739, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d73a, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d73b, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d73c, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d73d, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d73e, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d73f, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d740, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d741, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d742, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d743, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d744, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d745, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d746, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d747, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d748, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d749, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d74a, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d74b, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d74c, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d74d, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d74e, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d74f, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d750, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d751, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d752, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d753, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d754, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d755, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d756, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d757, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d758, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d759, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d75a, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d75b, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d75c, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d75d, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d75e, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d75f, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d760, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d761, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d762, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d763, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d764, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d765, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d766, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d767, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d768, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d769, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d76a, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d76b, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d76c, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d76d, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d76e, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d76f, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d770, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d771, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d772, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d773, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d774, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d775, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d776, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d777, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d778, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d779, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d77a, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d77b, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d77c, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d77d, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d77e, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d77f, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d780, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d781, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d782, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d783, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d784, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d785, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d786, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d787, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d788, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d789, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d78a, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d78b, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d78c, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d78d, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d78e, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d78f, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d790, 0, 0, 0, g(Yes, No, false, false, "", "Α")}, + {0x1d791, 0, 0, 0, g(Yes, No, false, false, "", "Β")}, + {0x1d792, 0, 0, 0, g(Yes, No, false, false, "", "Γ")}, + {0x1d793, 0, 0, 0, g(Yes, No, false, false, "", "Δ")}, + {0x1d794, 0, 0, 0, g(Yes, No, false, false, "", "Ε")}, + {0x1d795, 0, 0, 0, g(Yes, No, false, false, "", "Ζ")}, + {0x1d796, 0, 0, 0, g(Yes, No, false, false, "", "Η")}, + {0x1d797, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d798, 0, 0, 0, g(Yes, No, false, false, "", "Ι")}, + {0x1d799, 0, 0, 0, g(Yes, No, false, false, "", "Κ")}, + {0x1d79a, 0, 0, 0, g(Yes, No, false, false, "", "Λ")}, + {0x1d79b, 0, 0, 0, g(Yes, No, false, false, "", "Μ")}, + {0x1d79c, 0, 0, 0, g(Yes, No, false, false, "", "Ν")}, + {0x1d79d, 0, 0, 0, g(Yes, No, false, false, "", "Ξ")}, + {0x1d79e, 0, 0, 0, g(Yes, No, false, false, "", "Ο")}, + {0x1d79f, 0, 0, 0, g(Yes, No, false, false, "", "Π")}, + {0x1d7a0, 0, 0, 0, g(Yes, No, false, false, "", "Ρ")}, + {0x1d7a1, 0, 0, 0, g(Yes, No, false, false, "", "Θ")}, + {0x1d7a2, 0, 0, 0, g(Yes, No, false, false, "", "Σ")}, + {0x1d7a3, 0, 0, 0, g(Yes, No, false, false, "", "Τ")}, + {0x1d7a4, 0, 0, 0, g(Yes, No, false, false, "", "Υ")}, + {0x1d7a5, 0, 0, 0, g(Yes, No, false, false, "", "Φ")}, + {0x1d7a6, 0, 0, 0, g(Yes, No, false, false, "", "Χ")}, + {0x1d7a7, 0, 0, 0, g(Yes, No, false, false, "", "Ψ")}, + {0x1d7a8, 0, 0, 0, g(Yes, No, false, false, "", "Ω")}, + {0x1d7a9, 0, 0, 0, g(Yes, No, false, false, "", "∇")}, + {0x1d7aa, 0, 0, 0, g(Yes, No, false, false, "", "α")}, + {0x1d7ab, 0, 0, 0, g(Yes, No, false, false, "", "β")}, + {0x1d7ac, 0, 0, 0, g(Yes, No, false, false, "", "γ")}, + {0x1d7ad, 0, 0, 0, g(Yes, No, false, false, "", "δ")}, + {0x1d7ae, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d7af, 0, 0, 0, g(Yes, No, false, false, "", "ζ")}, + {0x1d7b0, 0, 0, 0, g(Yes, No, false, false, "", "η")}, + {0x1d7b1, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d7b2, 0, 0, 0, g(Yes, No, false, false, "", "ι")}, + {0x1d7b3, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d7b4, 0, 0, 0, g(Yes, No, false, false, "", "λ")}, + {0x1d7b5, 0, 0, 0, g(Yes, No, false, false, "", "μ")}, + {0x1d7b6, 0, 0, 0, g(Yes, No, false, false, "", "ν")}, + {0x1d7b7, 0, 0, 0, g(Yes, No, false, false, "", "ξ")}, + {0x1d7b8, 0, 0, 0, g(Yes, No, false, false, "", "ο")}, + {0x1d7b9, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d7ba, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d7bb, 0, 0, 0, g(Yes, No, false, false, "", "ς")}, + {0x1d7bc, 0, 0, 0, g(Yes, No, false, false, "", "σ")}, + {0x1d7bd, 0, 0, 0, g(Yes, No, false, false, "", "τ")}, + {0x1d7be, 0, 0, 0, g(Yes, No, false, false, "", "υ")}, + {0x1d7bf, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d7c0, 0, 0, 0, g(Yes, No, false, false, "", "χ")}, + {0x1d7c1, 0, 0, 0, g(Yes, No, false, false, "", "ψ")}, + {0x1d7c2, 0, 0, 0, g(Yes, No, false, false, "", "ω")}, + {0x1d7c3, 0, 0, 0, g(Yes, No, false, false, "", "∂")}, + {0x1d7c4, 0, 0, 0, g(Yes, No, false, false, "", "ε")}, + {0x1d7c5, 0, 0, 0, g(Yes, No, false, false, "", "θ")}, + {0x1d7c6, 0, 0, 0, g(Yes, No, false, false, "", "κ")}, + {0x1d7c7, 0, 0, 0, g(Yes, No, false, false, "", "φ")}, + {0x1d7c8, 0, 0, 0, g(Yes, No, false, false, "", "ρ")}, + {0x1d7c9, 0, 0, 0, g(Yes, No, false, false, "", "π")}, + {0x1d7ca, 0, 0, 0, g(Yes, No, false, false, "", "Ϝ")}, + {0x1d7cb, 0, 0, 0, g(Yes, No, false, false, "", "ϝ")}, + {0x1d7cc, 0, 0, 0, f(Yes, false, "")}, + {0x1d7ce, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7cf, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7d0, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7d1, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7d2, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7d3, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7d4, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7d5, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7d6, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7d7, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7d8, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7d9, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7da, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7db, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7dc, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7dd, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7de, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7df, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7e0, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7e1, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7e2, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7e3, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7e4, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7e5, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7e6, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7e7, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7e8, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7e9, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7ea, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7eb, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7ec, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7ed, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7ee, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7ef, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7f0, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7f1, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7f2, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7f3, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7f4, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7f5, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d7f6, 0, 0, 0, g(Yes, No, false, false, "", "0")}, + {0x1d7f7, 0, 0, 0, g(Yes, No, false, false, "", "1")}, + {0x1d7f8, 0, 0, 0, g(Yes, No, false, false, "", "2")}, + {0x1d7f9, 0, 0, 0, g(Yes, No, false, false, "", "3")}, + {0x1d7fa, 0, 0, 0, g(Yes, No, false, false, "", "4")}, + {0x1d7fb, 0, 0, 0, g(Yes, No, false, false, "", "5")}, + {0x1d7fc, 0, 0, 0, g(Yes, No, false, false, "", "6")}, + {0x1d7fd, 0, 0, 0, g(Yes, No, false, false, "", "7")}, + {0x1d7fe, 0, 0, 0, g(Yes, No, false, false, "", "8")}, + {0x1d7ff, 0, 0, 0, g(Yes, No, false, false, "", "9")}, + {0x1d800, 0, 0, 0, f(Yes, false, "")}, + {0x1e000, 230, 1, 1, f(Yes, false, "")}, + {0x1e007, 0, 0, 0, f(Yes, false, "")}, + {0x1e008, 230, 1, 1, f(Yes, false, "")}, + {0x1e019, 0, 0, 0, f(Yes, false, "")}, + {0x1e01b, 230, 1, 1, f(Yes, false, "")}, + {0x1e022, 0, 0, 0, f(Yes, false, "")}, + {0x1e023, 230, 1, 1, f(Yes, false, "")}, + {0x1e025, 0, 0, 0, f(Yes, false, "")}, + {0x1e026, 230, 1, 1, f(Yes, false, "")}, + {0x1e02b, 0, 0, 0, f(Yes, false, "")}, + {0x1e8d0, 220, 1, 1, f(Yes, false, "")}, + {0x1e8d7, 0, 0, 0, f(Yes, false, "")}, + {0x1e944, 230, 1, 1, f(Yes, false, "")}, + {0x1e94a, 7, 1, 1, f(Yes, false, "")}, + {0x1e94b, 0, 0, 0, f(Yes, false, "")}, + {0x1ee00, 0, 0, 0, g(Yes, No, false, false, "", "ا")}, + {0x1ee01, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee02, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee03, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0x1ee04, 0, 0, 0, f(Yes, false, "")}, + {0x1ee05, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0x1ee06, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0x1ee07, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee08, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1ee09, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee0a, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0x1ee0b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee0c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee0d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee0e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee0f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee10, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee11, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee12, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee13, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0x1ee14, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee15, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee16, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee17, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee18, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0x1ee19, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee1a, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1ee1b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee1c, 0, 0, 0, g(Yes, No, false, false, "", "ٮ")}, + {0x1ee1d, 0, 0, 0, g(Yes, No, false, false, "", "ں")}, + {0x1ee1e, 0, 0, 0, g(Yes, No, false, false, "", "ڡ")}, + {0x1ee1f, 0, 0, 0, g(Yes, No, false, false, "", "ٯ")}, + {0x1ee20, 0, 0, 0, f(Yes, false, "")}, + {0x1ee21, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee22, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee23, 0, 0, 0, f(Yes, false, "")}, + {0x1ee24, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0x1ee25, 0, 0, 0, f(Yes, false, "")}, + {0x1ee27, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee28, 0, 0, 0, f(Yes, false, "")}, + {0x1ee29, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee2a, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0x1ee2b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee2c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee2d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee2e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee2f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee30, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee31, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee32, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee33, 0, 0, 0, f(Yes, false, "")}, + {0x1ee34, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee35, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee36, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee37, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee38, 0, 0, 0, f(Yes, false, "")}, + {0x1ee39, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee3a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee3b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee3c, 0, 0, 0, f(Yes, false, "")}, + {0x1ee42, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee43, 0, 0, 0, f(Yes, false, "")}, + {0x1ee47, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee48, 0, 0, 0, f(Yes, false, "")}, + {0x1ee49, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee4a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee4b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee4c, 0, 0, 0, f(Yes, false, "")}, + {0x1ee4d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee4e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee4f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee50, 0, 0, 0, f(Yes, false, "")}, + {0x1ee51, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee52, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee53, 0, 0, 0, f(Yes, false, "")}, + {0x1ee54, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee55, 0, 0, 0, f(Yes, false, "")}, + {0x1ee57, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee58, 0, 0, 0, f(Yes, false, "")}, + {0x1ee59, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee5a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee5b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee5c, 0, 0, 0, f(Yes, false, "")}, + {0x1ee5d, 0, 0, 0, g(Yes, No, false, false, "", "ں")}, + {0x1ee5e, 0, 0, 0, f(Yes, false, "")}, + {0x1ee5f, 0, 0, 0, g(Yes, No, false, false, "", "ٯ")}, + {0x1ee60, 0, 0, 0, f(Yes, false, "")}, + {0x1ee61, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee62, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee63, 0, 0, 0, f(Yes, false, "")}, + {0x1ee64, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0x1ee65, 0, 0, 0, f(Yes, false, "")}, + {0x1ee67, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee68, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1ee69, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee6a, 0, 0, 0, g(Yes, No, false, false, "", "ك")}, + {0x1ee6b, 0, 0, 0, f(Yes, false, "")}, + {0x1ee6c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee6d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee6e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee6f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee70, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee71, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee72, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee73, 0, 0, 0, f(Yes, false, "")}, + {0x1ee74, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee75, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee76, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee77, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee78, 0, 0, 0, f(Yes, false, "")}, + {0x1ee79, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee7a, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1ee7b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee7c, 0, 0, 0, g(Yes, No, false, false, "", "ٮ")}, + {0x1ee7d, 0, 0, 0, f(Yes, false, "")}, + {0x1ee7e, 0, 0, 0, g(Yes, No, false, false, "", "ڡ")}, + {0x1ee7f, 0, 0, 0, f(Yes, false, "")}, + {0x1ee80, 0, 0, 0, g(Yes, No, false, false, "", "ا")}, + {0x1ee81, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1ee82, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1ee83, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0x1ee84, 0, 0, 0, g(Yes, No, false, false, "", "ه")}, + {0x1ee85, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0x1ee86, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0x1ee87, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1ee88, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1ee89, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1ee8a, 0, 0, 0, f(Yes, false, "")}, + {0x1ee8b, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1ee8c, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1ee8d, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1ee8e, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1ee8f, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1ee90, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1ee91, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1ee92, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1ee93, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0x1ee94, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1ee95, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1ee96, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1ee97, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1ee98, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0x1ee99, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1ee9a, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1ee9b, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1ee9c, 0, 0, 0, f(Yes, false, "")}, + {0x1eea1, 0, 0, 0, g(Yes, No, false, false, "", "ب")}, + {0x1eea2, 0, 0, 0, g(Yes, No, false, false, "", "ج")}, + {0x1eea3, 0, 0, 0, g(Yes, No, false, false, "", "د")}, + {0x1eea4, 0, 0, 0, f(Yes, false, "")}, + {0x1eea5, 0, 0, 0, g(Yes, No, false, false, "", "و")}, + {0x1eea6, 0, 0, 0, g(Yes, No, false, false, "", "ز")}, + {0x1eea7, 0, 0, 0, g(Yes, No, false, false, "", "ح")}, + {0x1eea8, 0, 0, 0, g(Yes, No, false, false, "", "ط")}, + {0x1eea9, 0, 0, 0, g(Yes, No, false, false, "", "ي")}, + {0x1eeaa, 0, 0, 0, f(Yes, false, "")}, + {0x1eeab, 0, 0, 0, g(Yes, No, false, false, "", "ل")}, + {0x1eeac, 0, 0, 0, g(Yes, No, false, false, "", "م")}, + {0x1eead, 0, 0, 0, g(Yes, No, false, false, "", "ن")}, + {0x1eeae, 0, 0, 0, g(Yes, No, false, false, "", "س")}, + {0x1eeaf, 0, 0, 0, g(Yes, No, false, false, "", "ع")}, + {0x1eeb0, 0, 0, 0, g(Yes, No, false, false, "", "ف")}, + {0x1eeb1, 0, 0, 0, g(Yes, No, false, false, "", "ص")}, + {0x1eeb2, 0, 0, 0, g(Yes, No, false, false, "", "ق")}, + {0x1eeb3, 0, 0, 0, g(Yes, No, false, false, "", "ر")}, + {0x1eeb4, 0, 0, 0, g(Yes, No, false, false, "", "ش")}, + {0x1eeb5, 0, 0, 0, g(Yes, No, false, false, "", "ت")}, + {0x1eeb6, 0, 0, 0, g(Yes, No, false, false, "", "ث")}, + {0x1eeb7, 0, 0, 0, g(Yes, No, false, false, "", "خ")}, + {0x1eeb8, 0, 0, 0, g(Yes, No, false, false, "", "ذ")}, + {0x1eeb9, 0, 0, 0, g(Yes, No, false, false, "", "ض")}, + {0x1eeba, 0, 0, 0, g(Yes, No, false, false, "", "ظ")}, + {0x1eebb, 0, 0, 0, g(Yes, No, false, false, "", "غ")}, + {0x1eebc, 0, 0, 0, f(Yes, false, "")}, + {0x1f100, 0, 0, 0, g(Yes, No, false, false, "", "0.")}, + {0x1f101, 0, 0, 0, g(Yes, No, false, false, "", "0,")}, + {0x1f102, 0, 0, 0, g(Yes, No, false, false, "", "1,")}, + {0x1f103, 0, 0, 0, g(Yes, No, false, false, "", "2,")}, + {0x1f104, 0, 0, 0, g(Yes, No, false, false, "", "3,")}, + {0x1f105, 0, 0, 0, g(Yes, No, false, false, "", "4,")}, + {0x1f106, 0, 0, 0, g(Yes, No, false, false, "", "5,")}, + {0x1f107, 0, 0, 0, g(Yes, No, false, false, "", "6,")}, + {0x1f108, 0, 0, 0, g(Yes, No, false, false, "", "7,")}, + {0x1f109, 0, 0, 0, g(Yes, No, false, false, "", "8,")}, + {0x1f10a, 0, 0, 0, g(Yes, No, false, false, "", "9,")}, + {0x1f10b, 0, 0, 0, f(Yes, false, "")}, + {0x1f110, 0, 0, 0, g(Yes, No, false, false, "", "(A)")}, + {0x1f111, 0, 0, 0, g(Yes, No, false, false, "", "(B)")}, + {0x1f112, 0, 0, 0, g(Yes, No, false, false, "", "(C)")}, + {0x1f113, 0, 0, 0, g(Yes, No, false, false, "", "(D)")}, + {0x1f114, 0, 0, 0, g(Yes, No, false, false, "", "(E)")}, + {0x1f115, 0, 0, 0, g(Yes, No, false, false, "", "(F)")}, + {0x1f116, 0, 0, 0, g(Yes, No, false, false, "", "(G)")}, + {0x1f117, 0, 0, 0, g(Yes, No, false, false, "", "(H)")}, + {0x1f118, 0, 0, 0, g(Yes, No, false, false, "", "(I)")}, + {0x1f119, 0, 0, 0, g(Yes, No, false, false, "", "(J)")}, + {0x1f11a, 0, 0, 0, g(Yes, No, false, false, "", "(K)")}, + {0x1f11b, 0, 0, 0, g(Yes, No, false, false, "", "(L)")}, + {0x1f11c, 0, 0, 0, g(Yes, No, false, false, "", "(M)")}, + {0x1f11d, 0, 0, 0, g(Yes, No, false, false, "", "(N)")}, + {0x1f11e, 0, 0, 0, g(Yes, No, false, false, "", "(O)")}, + {0x1f11f, 0, 0, 0, g(Yes, No, false, false, "", "(P)")}, + {0x1f120, 0, 0, 0, g(Yes, No, false, false, "", "(Q)")}, + {0x1f121, 0, 0, 0, g(Yes, No, false, false, "", "(R)")}, + {0x1f122, 0, 0, 0, g(Yes, No, false, false, "", "(S)")}, + {0x1f123, 0, 0, 0, g(Yes, No, false, false, "", "(T)")}, + {0x1f124, 0, 0, 0, g(Yes, No, false, false, "", "(U)")}, + {0x1f125, 0, 0, 0, g(Yes, No, false, false, "", "(V)")}, + {0x1f126, 0, 0, 0, g(Yes, No, false, false, "", "(W)")}, + {0x1f127, 0, 0, 0, g(Yes, No, false, false, "", "(X)")}, + {0x1f128, 0, 0, 0, g(Yes, No, false, false, "", "(Y)")}, + {0x1f129, 0, 0, 0, g(Yes, No, false, false, "", "(Z)")}, + {0x1f12a, 0, 0, 0, g(Yes, No, false, false, "", "〔S〕")}, + {0x1f12b, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1f12c, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1f12d, 0, 0, 0, g(Yes, No, false, false, "", "CD")}, + {0x1f12e, 0, 0, 0, g(Yes, No, false, false, "", "WZ")}, + {0x1f12f, 0, 0, 0, f(Yes, false, "")}, + {0x1f130, 0, 0, 0, g(Yes, No, false, false, "", "A")}, + {0x1f131, 0, 0, 0, g(Yes, No, false, false, "", "B")}, + {0x1f132, 0, 0, 0, g(Yes, No, false, false, "", "C")}, + {0x1f133, 0, 0, 0, g(Yes, No, false, false, "", "D")}, + {0x1f134, 0, 0, 0, g(Yes, No, false, false, "", "E")}, + {0x1f135, 0, 0, 0, g(Yes, No, false, false, "", "F")}, + {0x1f136, 0, 0, 0, g(Yes, No, false, false, "", "G")}, + {0x1f137, 0, 0, 0, g(Yes, No, false, false, "", "H")}, + {0x1f138, 0, 0, 0, g(Yes, No, false, false, "", "I")}, + {0x1f139, 0, 0, 0, g(Yes, No, false, false, "", "J")}, + {0x1f13a, 0, 0, 0, g(Yes, No, false, false, "", "K")}, + {0x1f13b, 0, 0, 0, g(Yes, No, false, false, "", "L")}, + {0x1f13c, 0, 0, 0, g(Yes, No, false, false, "", "M")}, + {0x1f13d, 0, 0, 0, g(Yes, No, false, false, "", "N")}, + {0x1f13e, 0, 0, 0, g(Yes, No, false, false, "", "O")}, + {0x1f13f, 0, 0, 0, g(Yes, No, false, false, "", "P")}, + {0x1f140, 0, 0, 0, g(Yes, No, false, false, "", "Q")}, + {0x1f141, 0, 0, 0, g(Yes, No, false, false, "", "R")}, + {0x1f142, 0, 0, 0, g(Yes, No, false, false, "", "S")}, + {0x1f143, 0, 0, 0, g(Yes, No, false, false, "", "T")}, + {0x1f144, 0, 0, 0, g(Yes, No, false, false, "", "U")}, + {0x1f145, 0, 0, 0, g(Yes, No, false, false, "", "V")}, + {0x1f146, 0, 0, 0, g(Yes, No, false, false, "", "W")}, + {0x1f147, 0, 0, 0, g(Yes, No, false, false, "", "X")}, + {0x1f148, 0, 0, 0, g(Yes, No, false, false, "", "Y")}, + {0x1f149, 0, 0, 0, g(Yes, No, false, false, "", "Z")}, + {0x1f14a, 0, 0, 0, g(Yes, No, false, false, "", "HV")}, + {0x1f14b, 0, 0, 0, g(Yes, No, false, false, "", "MV")}, + {0x1f14c, 0, 0, 0, g(Yes, No, false, false, "", "SD")}, + {0x1f14d, 0, 0, 0, g(Yes, No, false, false, "", "SS")}, + {0x1f14e, 0, 0, 0, g(Yes, No, false, false, "", "PPV")}, + {0x1f14f, 0, 0, 0, g(Yes, No, false, false, "", "WC")}, + {0x1f150, 0, 0, 0, f(Yes, false, "")}, + {0x1f16a, 0, 0, 0, g(Yes, No, false, false, "", "MC")}, + {0x1f16b, 0, 0, 0, g(Yes, No, false, false, "", "MD")}, + {0x1f16c, 0, 0, 0, f(Yes, false, "")}, + {0x1f190, 0, 0, 0, g(Yes, No, false, false, "", "DJ")}, + {0x1f191, 0, 0, 0, f(Yes, false, "")}, + {0x1f200, 0, 0, 0, g(Yes, No, false, false, "", "ほか")}, + {0x1f201, 0, 0, 0, g(Yes, No, false, false, "", "ココ")}, + {0x1f202, 0, 0, 0, g(Yes, No, false, false, "", "サ")}, + {0x1f203, 0, 0, 0, f(Yes, false, "")}, + {0x1f210, 0, 0, 0, g(Yes, No, false, false, "", "手")}, + {0x1f211, 0, 0, 0, g(Yes, No, false, false, "", "字")}, + {0x1f212, 0, 0, 0, g(Yes, No, false, false, "", "双")}, + {0x1f213, 0, 0, 1, g(Yes, No, false, false, "", "デ")}, + {0x1f214, 0, 0, 0, g(Yes, No, false, false, "", "二")}, + {0x1f215, 0, 0, 0, g(Yes, No, false, false, "", "多")}, + {0x1f216, 0, 0, 0, g(Yes, No, false, false, "", "解")}, + {0x1f217, 0, 0, 0, g(Yes, No, false, false, "", "天")}, + {0x1f218, 0, 0, 0, g(Yes, No, false, false, "", "交")}, + {0x1f219, 0, 0, 0, g(Yes, No, false, false, "", "映")}, + {0x1f21a, 0, 0, 0, g(Yes, No, false, false, "", "無")}, + {0x1f21b, 0, 0, 0, g(Yes, No, false, false, "", "料")}, + {0x1f21c, 0, 0, 0, g(Yes, No, false, false, "", "前")}, + {0x1f21d, 0, 0, 0, g(Yes, No, false, false, "", "後")}, + {0x1f21e, 0, 0, 0, g(Yes, No, false, false, "", "再")}, + {0x1f21f, 0, 0, 0, g(Yes, No, false, false, "", "新")}, + {0x1f220, 0, 0, 0, g(Yes, No, false, false, "", "初")}, + {0x1f221, 0, 0, 0, g(Yes, No, false, false, "", "終")}, + {0x1f222, 0, 0, 0, g(Yes, No, false, false, "", "生")}, + {0x1f223, 0, 0, 0, g(Yes, No, false, false, "", "販")}, + {0x1f224, 0, 0, 0, g(Yes, No, false, false, "", "声")}, + {0x1f225, 0, 0, 0, g(Yes, No, false, false, "", "吹")}, + {0x1f226, 0, 0, 0, g(Yes, No, false, false, "", "演")}, + {0x1f227, 0, 0, 0, g(Yes, No, false, false, "", "投")}, + {0x1f228, 0, 0, 0, g(Yes, No, false, false, "", "捕")}, + {0x1f229, 0, 0, 0, g(Yes, No, false, false, "", "一")}, + {0x1f22a, 0, 0, 0, g(Yes, No, false, false, "", "三")}, + {0x1f22b, 0, 0, 0, g(Yes, No, false, false, "", "遊")}, + {0x1f22c, 0, 0, 0, g(Yes, No, false, false, "", "左")}, + {0x1f22d, 0, 0, 0, g(Yes, No, false, false, "", "中")}, + {0x1f22e, 0, 0, 0, g(Yes, No, false, false, "", "右")}, + {0x1f22f, 0, 0, 0, g(Yes, No, false, false, "", "指")}, + {0x1f230, 0, 0, 0, g(Yes, No, false, false, "", "走")}, + {0x1f231, 0, 0, 0, g(Yes, No, false, false, "", "打")}, + {0x1f232, 0, 0, 0, g(Yes, No, false, false, "", "禁")}, + {0x1f233, 0, 0, 0, g(Yes, No, false, false, "", "空")}, + {0x1f234, 0, 0, 0, g(Yes, No, false, false, "", "合")}, + {0x1f235, 0, 0, 0, g(Yes, No, false, false, "", "満")}, + {0x1f236, 0, 0, 0, g(Yes, No, false, false, "", "有")}, + {0x1f237, 0, 0, 0, g(Yes, No, false, false, "", "月")}, + {0x1f238, 0, 0, 0, g(Yes, No, false, false, "", "申")}, + {0x1f239, 0, 0, 0, g(Yes, No, false, false, "", "割")}, + {0x1f23a, 0, 0, 0, g(Yes, No, false, false, "", "営")}, + {0x1f23b, 0, 0, 0, g(Yes, No, false, false, "", "配")}, + {0x1f23c, 0, 0, 0, f(Yes, false, "")}, + {0x1f240, 0, 0, 0, g(Yes, No, false, false, "", "〔本〕")}, + {0x1f241, 0, 0, 0, g(Yes, No, false, false, "", "〔三〕")}, + {0x1f242, 0, 0, 0, g(Yes, No, false, false, "", "〔二〕")}, + {0x1f243, 0, 0, 0, g(Yes, No, false, false, "", "〔安〕")}, + {0x1f244, 0, 0, 0, g(Yes, No, false, false, "", "〔点〕")}, + {0x1f245, 0, 0, 0, g(Yes, No, false, false, "", "〔打〕")}, + {0x1f246, 0, 0, 0, g(Yes, No, false, false, "", "〔盗〕")}, + {0x1f247, 0, 0, 0, g(Yes, No, false, false, "", "〔勝〕")}, + {0x1f248, 0, 0, 0, g(Yes, No, false, false, "", "〔敗〕")}, + {0x1f249, 0, 0, 0, f(Yes, false, "")}, + {0x1f250, 0, 0, 0, g(Yes, No, false, false, "", "得")}, + {0x1f251, 0, 0, 0, g(Yes, No, false, false, "", "可")}, + {0x1f252, 0, 0, 0, f(Yes, false, "")}, + {0x2f800, 0, 0, 0, f(No, false, "丽")}, + {0x2f801, 0, 0, 0, f(No, false, "丸")}, + {0x2f802, 0, 0, 0, f(No, false, "乁")}, + {0x2f803, 0, 0, 0, f(No, false, "𠄢")}, + {0x2f804, 0, 0, 0, f(No, false, "你")}, + {0x2f805, 0, 0, 0, f(No, false, "侮")}, + {0x2f806, 0, 0, 0, f(No, false, "侻")}, + {0x2f807, 0, 0, 0, f(No, false, "倂")}, + {0x2f808, 0, 0, 0, f(No, false, "偺")}, + {0x2f809, 0, 0, 0, f(No, false, "備")}, + {0x2f80a, 0, 0, 0, f(No, false, "僧")}, + {0x2f80b, 0, 0, 0, f(No, false, "像")}, + {0x2f80c, 0, 0, 0, f(No, false, "㒞")}, + {0x2f80d, 0, 0, 0, f(No, false, "𠘺")}, + {0x2f80e, 0, 0, 0, f(No, false, "免")}, + {0x2f80f, 0, 0, 0, f(No, false, "兔")}, + {0x2f810, 0, 0, 0, f(No, false, "兤")}, + {0x2f811, 0, 0, 0, f(No, false, "具")}, + {0x2f812, 0, 0, 0, f(No, false, "𠔜")}, + {0x2f813, 0, 0, 0, f(No, false, "㒹")}, + {0x2f814, 0, 0, 0, f(No, false, "內")}, + {0x2f815, 0, 0, 0, f(No, false, "再")}, + {0x2f816, 0, 0, 0, f(No, false, "𠕋")}, + {0x2f817, 0, 0, 0, f(No, false, "冗")}, + {0x2f818, 0, 0, 0, f(No, false, "冤")}, + {0x2f819, 0, 0, 0, f(No, false, "仌")}, + {0x2f81a, 0, 0, 0, f(No, false, "冬")}, + {0x2f81b, 0, 0, 0, f(No, false, "况")}, + {0x2f81c, 0, 0, 0, f(No, false, "𩇟")}, + {0x2f81d, 0, 0, 0, f(No, false, "凵")}, + {0x2f81e, 0, 0, 0, f(No, false, "刃")}, + {0x2f81f, 0, 0, 0, f(No, false, "㓟")}, + {0x2f820, 0, 0, 0, f(No, false, "刻")}, + {0x2f821, 0, 0, 0, f(No, false, "剆")}, + {0x2f822, 0, 0, 0, f(No, false, "割")}, + {0x2f823, 0, 0, 0, f(No, false, "剷")}, + {0x2f824, 0, 0, 0, f(No, false, "㔕")}, + {0x2f825, 0, 0, 0, f(No, false, "勇")}, + {0x2f826, 0, 0, 0, f(No, false, "勉")}, + {0x2f827, 0, 0, 0, f(No, false, "勤")}, + {0x2f828, 0, 0, 0, f(No, false, "勺")}, + {0x2f829, 0, 0, 0, f(No, false, "包")}, + {0x2f82a, 0, 0, 0, f(No, false, "匆")}, + {0x2f82b, 0, 0, 0, f(No, false, "北")}, + {0x2f82c, 0, 0, 0, f(No, false, "卉")}, + {0x2f82d, 0, 0, 0, f(No, false, "卑")}, + {0x2f82e, 0, 0, 0, f(No, false, "博")}, + {0x2f82f, 0, 0, 0, f(No, false, "即")}, + {0x2f830, 0, 0, 0, f(No, false, "卽")}, + {0x2f831, 0, 0, 0, f(No, false, "卿")}, + {0x2f834, 0, 0, 0, f(No, false, "𠨬")}, + {0x2f835, 0, 0, 0, f(No, false, "灰")}, + {0x2f836, 0, 0, 0, f(No, false, "及")}, + {0x2f837, 0, 0, 0, f(No, false, "叟")}, + {0x2f838, 0, 0, 0, f(No, false, "𠭣")}, + {0x2f839, 0, 0, 0, f(No, false, "叫")}, + {0x2f83a, 0, 0, 0, f(No, false, "叱")}, + {0x2f83b, 0, 0, 0, f(No, false, "吆")}, + {0x2f83c, 0, 0, 0, f(No, false, "咞")}, + {0x2f83d, 0, 0, 0, f(No, false, "吸")}, + {0x2f83e, 0, 0, 0, f(No, false, "呈")}, + {0x2f83f, 0, 0, 0, f(No, false, "周")}, + {0x2f840, 0, 0, 0, f(No, false, "咢")}, + {0x2f841, 0, 0, 0, f(No, false, "哶")}, + {0x2f842, 0, 0, 0, f(No, false, "唐")}, + {0x2f843, 0, 0, 0, f(No, false, "啓")}, + {0x2f844, 0, 0, 0, f(No, false, "啣")}, + {0x2f845, 0, 0, 0, f(No, false, "善")}, + {0x2f847, 0, 0, 0, f(No, false, "喙")}, + {0x2f848, 0, 0, 0, f(No, false, "喫")}, + {0x2f849, 0, 0, 0, f(No, false, "喳")}, + {0x2f84a, 0, 0, 0, f(No, false, "嗂")}, + {0x2f84b, 0, 0, 0, f(No, false, "圖")}, + {0x2f84c, 0, 0, 0, f(No, false, "嘆")}, + {0x2f84d, 0, 0, 0, f(No, false, "圗")}, + {0x2f84e, 0, 0, 0, f(No, false, "噑")}, + {0x2f84f, 0, 0, 0, f(No, false, "噴")}, + {0x2f850, 0, 0, 0, f(No, false, "切")}, + {0x2f851, 0, 0, 0, f(No, false, "壮")}, + {0x2f852, 0, 0, 0, f(No, false, "城")}, + {0x2f853, 0, 0, 0, f(No, false, "埴")}, + {0x2f854, 0, 0, 0, f(No, false, "堍")}, + {0x2f855, 0, 0, 0, f(No, false, "型")}, + {0x2f856, 0, 0, 0, f(No, false, "堲")}, + {0x2f857, 0, 0, 0, f(No, false, "報")}, + {0x2f858, 0, 0, 0, f(No, false, "墬")}, + {0x2f859, 0, 0, 0, f(No, false, "𡓤")}, + {0x2f85a, 0, 0, 0, f(No, false, "売")}, + {0x2f85b, 0, 0, 0, f(No, false, "壷")}, + {0x2f85c, 0, 0, 0, f(No, false, "夆")}, + {0x2f85d, 0, 0, 0, f(No, false, "多")}, + {0x2f85e, 0, 0, 0, f(No, false, "夢")}, + {0x2f85f, 0, 0, 0, f(No, false, "奢")}, + {0x2f860, 0, 0, 0, f(No, false, "𡚨")}, + {0x2f861, 0, 0, 0, f(No, false, "𡛪")}, + {0x2f862, 0, 0, 0, f(No, false, "姬")}, + {0x2f863, 0, 0, 0, f(No, false, "娛")}, + {0x2f864, 0, 0, 0, f(No, false, "娧")}, + {0x2f865, 0, 0, 0, f(No, false, "姘")}, + {0x2f866, 0, 0, 0, f(No, false, "婦")}, + {0x2f867, 0, 0, 0, f(No, false, "㛮")}, + {0x2f868, 0, 0, 0, f(No, false, "㛼")}, + {0x2f869, 0, 0, 0, f(No, false, "嬈")}, + {0x2f86a, 0, 0, 0, f(No, false, "嬾")}, + {0x2f86c, 0, 0, 0, f(No, false, "𡧈")}, + {0x2f86d, 0, 0, 0, f(No, false, "寃")}, + {0x2f86e, 0, 0, 0, f(No, false, "寘")}, + {0x2f86f, 0, 0, 0, f(No, false, "寧")}, + {0x2f870, 0, 0, 0, f(No, false, "寳")}, + {0x2f871, 0, 0, 0, f(No, false, "𡬘")}, + {0x2f872, 0, 0, 0, f(No, false, "寿")}, + {0x2f873, 0, 0, 0, f(No, false, "将")}, + {0x2f874, 0, 0, 0, f(No, false, "当")}, + {0x2f875, 0, 0, 0, f(No, false, "尢")}, + {0x2f876, 0, 0, 0, f(No, false, "㞁")}, + {0x2f877, 0, 0, 0, f(No, false, "屠")}, + {0x2f878, 0, 0, 0, f(No, false, "屮")}, + {0x2f879, 0, 0, 0, f(No, false, "峀")}, + {0x2f87a, 0, 0, 0, f(No, false, "岍")}, + {0x2f87b, 0, 0, 0, f(No, false, "𡷤")}, + {0x2f87c, 0, 0, 0, f(No, false, "嵃")}, + {0x2f87d, 0, 0, 0, f(No, false, "𡷦")}, + {0x2f87e, 0, 0, 0, f(No, false, "嵮")}, + {0x2f87f, 0, 0, 0, f(No, false, "嵫")}, + {0x2f880, 0, 0, 0, f(No, false, "嵼")}, + {0x2f881, 0, 0, 0, f(No, false, "巡")}, + {0x2f882, 0, 0, 0, f(No, false, "巢")}, + {0x2f883, 0, 0, 0, f(No, false, "㠯")}, + {0x2f884, 0, 0, 0, f(No, false, "巽")}, + {0x2f885, 0, 0, 0, f(No, false, "帨")}, + {0x2f886, 0, 0, 0, f(No, false, "帽")}, + {0x2f887, 0, 0, 0, f(No, false, "幩")}, + {0x2f888, 0, 0, 0, f(No, false, "㡢")}, + {0x2f889, 0, 0, 0, f(No, false, "𢆃")}, + {0x2f88a, 0, 0, 0, f(No, false, "㡼")}, + {0x2f88b, 0, 0, 0, f(No, false, "庰")}, + {0x2f88c, 0, 0, 0, f(No, false, "庳")}, + {0x2f88d, 0, 0, 0, f(No, false, "庶")}, + {0x2f88e, 0, 0, 0, f(No, false, "廊")}, + {0x2f88f, 0, 0, 0, f(No, false, "𪎒")}, + {0x2f890, 0, 0, 0, f(No, false, "廾")}, + {0x2f891, 0, 0, 0, f(No, false, "𢌱")}, + {0x2f893, 0, 0, 0, f(No, false, "舁")}, + {0x2f894, 0, 0, 0, f(No, false, "弢")}, + {0x2f896, 0, 0, 0, f(No, false, "㣇")}, + {0x2f897, 0, 0, 0, f(No, false, "𣊸")}, + {0x2f898, 0, 0, 0, f(No, false, "𦇚")}, + {0x2f899, 0, 0, 0, f(No, false, "形")}, + {0x2f89a, 0, 0, 0, f(No, false, "彫")}, + {0x2f89b, 0, 0, 0, f(No, false, "㣣")}, + {0x2f89c, 0, 0, 0, f(No, false, "徚")}, + {0x2f89d, 0, 0, 0, f(No, false, "忍")}, + {0x2f89e, 0, 0, 0, f(No, false, "志")}, + {0x2f89f, 0, 0, 0, f(No, false, "忹")}, + {0x2f8a0, 0, 0, 0, f(No, false, "悁")}, + {0x2f8a1, 0, 0, 0, f(No, false, "㤺")}, + {0x2f8a2, 0, 0, 0, f(No, false, "㤜")}, + {0x2f8a3, 0, 0, 0, f(No, false, "悔")}, + {0x2f8a4, 0, 0, 0, f(No, false, "𢛔")}, + {0x2f8a5, 0, 0, 0, f(No, false, "惇")}, + {0x2f8a6, 0, 0, 0, f(No, false, "慈")}, + {0x2f8a7, 0, 0, 0, f(No, false, "慌")}, + {0x2f8a8, 0, 0, 0, f(No, false, "慎")}, + {0x2f8a9, 0, 0, 0, f(No, false, "慌")}, + {0x2f8aa, 0, 0, 0, f(No, false, "慺")}, + {0x2f8ab, 0, 0, 0, f(No, false, "憎")}, + {0x2f8ac, 0, 0, 0, f(No, false, "憲")}, + {0x2f8ad, 0, 0, 0, f(No, false, "憤")}, + {0x2f8ae, 0, 0, 0, f(No, false, "憯")}, + {0x2f8af, 0, 0, 0, f(No, false, "懞")}, + {0x2f8b0, 0, 0, 0, f(No, false, "懲")}, + {0x2f8b1, 0, 0, 0, f(No, false, "懶")}, + {0x2f8b2, 0, 0, 0, f(No, false, "成")}, + {0x2f8b3, 0, 0, 0, f(No, false, "戛")}, + {0x2f8b4, 0, 0, 0, f(No, false, "扝")}, + {0x2f8b5, 0, 0, 0, f(No, false, "抱")}, + {0x2f8b6, 0, 0, 0, f(No, false, "拔")}, + {0x2f8b7, 0, 0, 0, f(No, false, "捐")}, + {0x2f8b8, 0, 0, 0, f(No, false, "𢬌")}, + {0x2f8b9, 0, 0, 0, f(No, false, "挽")}, + {0x2f8ba, 0, 0, 0, f(No, false, "拼")}, + {0x2f8bb, 0, 0, 0, f(No, false, "捨")}, + {0x2f8bc, 0, 0, 0, f(No, false, "掃")}, + {0x2f8bd, 0, 0, 0, f(No, false, "揤")}, + {0x2f8be, 0, 0, 0, f(No, false, "𢯱")}, + {0x2f8bf, 0, 0, 0, f(No, false, "搢")}, + {0x2f8c0, 0, 0, 0, f(No, false, "揅")}, + {0x2f8c1, 0, 0, 0, f(No, false, "掩")}, + {0x2f8c2, 0, 0, 0, f(No, false, "㨮")}, + {0x2f8c3, 0, 0, 0, f(No, false, "摩")}, + {0x2f8c4, 0, 0, 0, f(No, false, "摾")}, + {0x2f8c5, 0, 0, 0, f(No, false, "撝")}, + {0x2f8c6, 0, 0, 0, f(No, false, "摷")}, + {0x2f8c7, 0, 0, 0, f(No, false, "㩬")}, + {0x2f8c8, 0, 0, 0, f(No, false, "敏")}, + {0x2f8c9, 0, 0, 0, f(No, false, "敬")}, + {0x2f8ca, 0, 0, 0, f(No, false, "𣀊")}, + {0x2f8cb, 0, 0, 0, f(No, false, "旣")}, + {0x2f8cc, 0, 0, 0, f(No, false, "書")}, + {0x2f8cd, 0, 0, 0, f(No, false, "晉")}, + {0x2f8ce, 0, 0, 0, f(No, false, "㬙")}, + {0x2f8cf, 0, 0, 0, f(No, false, "暑")}, + {0x2f8d0, 0, 0, 0, f(No, false, "㬈")}, + {0x2f8d1, 0, 0, 0, f(No, false, "㫤")}, + {0x2f8d2, 0, 0, 0, f(No, false, "冒")}, + {0x2f8d3, 0, 0, 0, f(No, false, "冕")}, + {0x2f8d4, 0, 0, 0, f(No, false, "最")}, + {0x2f8d5, 0, 0, 0, f(No, false, "暜")}, + {0x2f8d6, 0, 0, 0, f(No, false, "肭")}, + {0x2f8d7, 0, 0, 0, f(No, false, "䏙")}, + {0x2f8d8, 0, 0, 0, f(No, false, "朗")}, + {0x2f8d9, 0, 0, 0, f(No, false, "望")}, + {0x2f8da, 0, 0, 0, f(No, false, "朡")}, + {0x2f8db, 0, 0, 0, f(No, false, "杞")}, + {0x2f8dc, 0, 0, 0, f(No, false, "杓")}, + {0x2f8dd, 0, 0, 0, f(No, false, "𣏃")}, + {0x2f8de, 0, 0, 0, f(No, false, "㭉")}, + {0x2f8df, 0, 0, 0, f(No, false, "柺")}, + {0x2f8e0, 0, 0, 0, f(No, false, "枅")}, + {0x2f8e1, 0, 0, 0, f(No, false, "桒")}, + {0x2f8e2, 0, 0, 0, f(No, false, "梅")}, + {0x2f8e3, 0, 0, 0, f(No, false, "𣑭")}, + {0x2f8e4, 0, 0, 0, f(No, false, "梎")}, + {0x2f8e5, 0, 0, 0, f(No, false, "栟")}, + {0x2f8e6, 0, 0, 0, f(No, false, "椔")}, + {0x2f8e7, 0, 0, 0, f(No, false, "㮝")}, + {0x2f8e8, 0, 0, 0, f(No, false, "楂")}, + {0x2f8e9, 0, 0, 0, f(No, false, "榣")}, + {0x2f8ea, 0, 0, 0, f(No, false, "槪")}, + {0x2f8eb, 0, 0, 0, f(No, false, "檨")}, + {0x2f8ec, 0, 0, 0, f(No, false, "𣚣")}, + {0x2f8ed, 0, 0, 0, f(No, false, "櫛")}, + {0x2f8ee, 0, 0, 0, f(No, false, "㰘")}, + {0x2f8ef, 0, 0, 0, f(No, false, "次")}, + {0x2f8f0, 0, 0, 0, f(No, false, "𣢧")}, + {0x2f8f1, 0, 0, 0, f(No, false, "歔")}, + {0x2f8f2, 0, 0, 0, f(No, false, "㱎")}, + {0x2f8f3, 0, 0, 0, f(No, false, "歲")}, + {0x2f8f4, 0, 0, 0, f(No, false, "殟")}, + {0x2f8f5, 0, 0, 0, f(No, false, "殺")}, + {0x2f8f6, 0, 0, 0, f(No, false, "殻")}, + {0x2f8f7, 0, 0, 0, f(No, false, "𣪍")}, + {0x2f8f8, 0, 0, 0, f(No, false, "𡴋")}, + {0x2f8f9, 0, 0, 0, f(No, false, "𣫺")}, + {0x2f8fa, 0, 0, 0, f(No, false, "汎")}, + {0x2f8fb, 0, 0, 0, f(No, false, "𣲼")}, + {0x2f8fc, 0, 0, 0, f(No, false, "沿")}, + {0x2f8fd, 0, 0, 0, f(No, false, "泍")}, + {0x2f8fe, 0, 0, 0, f(No, false, "汧")}, + {0x2f8ff, 0, 0, 0, f(No, false, "洖")}, + {0x2f900, 0, 0, 0, f(No, false, "派")}, + {0x2f901, 0, 0, 0, f(No, false, "海")}, + {0x2f902, 0, 0, 0, f(No, false, "流")}, + {0x2f903, 0, 0, 0, f(No, false, "浩")}, + {0x2f904, 0, 0, 0, f(No, false, "浸")}, + {0x2f905, 0, 0, 0, f(No, false, "涅")}, + {0x2f906, 0, 0, 0, f(No, false, "𣴞")}, + {0x2f907, 0, 0, 0, f(No, false, "洴")}, + {0x2f908, 0, 0, 0, f(No, false, "港")}, + {0x2f909, 0, 0, 0, f(No, false, "湮")}, + {0x2f90a, 0, 0, 0, f(No, false, "㴳")}, + {0x2f90b, 0, 0, 0, f(No, false, "滋")}, + {0x2f90c, 0, 0, 0, f(No, false, "滇")}, + {0x2f90d, 0, 0, 0, f(No, false, "𣻑")}, + {0x2f90e, 0, 0, 0, f(No, false, "淹")}, + {0x2f90f, 0, 0, 0, f(No, false, "潮")}, + {0x2f910, 0, 0, 0, f(No, false, "𣽞")}, + {0x2f911, 0, 0, 0, f(No, false, "𣾎")}, + {0x2f912, 0, 0, 0, f(No, false, "濆")}, + {0x2f913, 0, 0, 0, f(No, false, "瀹")}, + {0x2f914, 0, 0, 0, f(No, false, "瀞")}, + {0x2f915, 0, 0, 0, f(No, false, "瀛")}, + {0x2f916, 0, 0, 0, f(No, false, "㶖")}, + {0x2f917, 0, 0, 0, f(No, false, "灊")}, + {0x2f918, 0, 0, 0, f(No, false, "災")}, + {0x2f919, 0, 0, 0, f(No, false, "灷")}, + {0x2f91a, 0, 0, 0, f(No, false, "炭")}, + {0x2f91b, 0, 0, 0, f(No, false, "𠔥")}, + {0x2f91c, 0, 0, 0, f(No, false, "煅")}, + {0x2f91d, 0, 0, 0, f(No, false, "𤉣")}, + {0x2f91e, 0, 0, 0, f(No, false, "熜")}, + {0x2f91f, 0, 0, 0, f(No, false, "𤎫")}, + {0x2f920, 0, 0, 0, f(No, false, "爨")}, + {0x2f921, 0, 0, 0, f(No, false, "爵")}, + {0x2f922, 0, 0, 0, f(No, false, "牐")}, + {0x2f923, 0, 0, 0, f(No, false, "𤘈")}, + {0x2f924, 0, 0, 0, f(No, false, "犀")}, + {0x2f925, 0, 0, 0, f(No, false, "犕")}, + {0x2f926, 0, 0, 0, f(No, false, "𤜵")}, + {0x2f927, 0, 0, 0, f(No, false, "𤠔")}, + {0x2f928, 0, 0, 0, f(No, false, "獺")}, + {0x2f929, 0, 0, 0, f(No, false, "王")}, + {0x2f92a, 0, 0, 0, f(No, false, "㺬")}, + {0x2f92b, 0, 0, 0, f(No, false, "玥")}, + {0x2f92c, 0, 0, 0, f(No, false, "㺸")}, + {0x2f92e, 0, 0, 0, f(No, false, "瑇")}, + {0x2f92f, 0, 0, 0, f(No, false, "瑜")}, + {0x2f930, 0, 0, 0, f(No, false, "瑱")}, + {0x2f931, 0, 0, 0, f(No, false, "璅")}, + {0x2f932, 0, 0, 0, f(No, false, "瓊")}, + {0x2f933, 0, 0, 0, f(No, false, "㼛")}, + {0x2f934, 0, 0, 0, f(No, false, "甤")}, + {0x2f935, 0, 0, 0, f(No, false, "𤰶")}, + {0x2f936, 0, 0, 0, f(No, false, "甾")}, + {0x2f937, 0, 0, 0, f(No, false, "𤲒")}, + {0x2f938, 0, 0, 0, f(No, false, "異")}, + {0x2f939, 0, 0, 0, f(No, false, "𢆟")}, + {0x2f93a, 0, 0, 0, f(No, false, "瘐")}, + {0x2f93b, 0, 0, 0, f(No, false, "𤾡")}, + {0x2f93c, 0, 0, 0, f(No, false, "𤾸")}, + {0x2f93d, 0, 0, 0, f(No, false, "𥁄")}, + {0x2f93e, 0, 0, 0, f(No, false, "㿼")}, + {0x2f93f, 0, 0, 0, f(No, false, "䀈")}, + {0x2f940, 0, 0, 0, f(No, false, "直")}, + {0x2f941, 0, 0, 0, f(No, false, "𥃳")}, + {0x2f942, 0, 0, 0, f(No, false, "𥃲")}, + {0x2f943, 0, 0, 0, f(No, false, "𥄙")}, + {0x2f944, 0, 0, 0, f(No, false, "𥄳")}, + {0x2f945, 0, 0, 0, f(No, false, "眞")}, + {0x2f946, 0, 0, 0, f(No, false, "真")}, + {0x2f948, 0, 0, 0, f(No, false, "睊")}, + {0x2f949, 0, 0, 0, f(No, false, "䀹")}, + {0x2f94a, 0, 0, 0, f(No, false, "瞋")}, + {0x2f94b, 0, 0, 0, f(No, false, "䁆")}, + {0x2f94c, 0, 0, 0, f(No, false, "䂖")}, + {0x2f94d, 0, 0, 0, f(No, false, "𥐝")}, + {0x2f94e, 0, 0, 0, f(No, false, "硎")}, + {0x2f94f, 0, 0, 0, f(No, false, "碌")}, + {0x2f950, 0, 0, 0, f(No, false, "磌")}, + {0x2f951, 0, 0, 0, f(No, false, "䃣")}, + {0x2f952, 0, 0, 0, f(No, false, "𥘦")}, + {0x2f953, 0, 0, 0, f(No, false, "祖")}, + {0x2f954, 0, 0, 0, f(No, false, "𥚚")}, + {0x2f955, 0, 0, 0, f(No, false, "𥛅")}, + {0x2f956, 0, 0, 0, f(No, false, "福")}, + {0x2f957, 0, 0, 0, f(No, false, "秫")}, + {0x2f958, 0, 0, 0, f(No, false, "䄯")}, + {0x2f959, 0, 0, 0, f(No, false, "穀")}, + {0x2f95a, 0, 0, 0, f(No, false, "穊")}, + {0x2f95b, 0, 0, 0, f(No, false, "穏")}, + {0x2f95c, 0, 0, 0, f(No, false, "𥥼")}, + {0x2f95d, 0, 0, 0, f(No, false, "𥪧")}, + {0x2f95f, 0, 0, 0, f(No, false, "竮")}, + {0x2f960, 0, 0, 0, f(No, false, "䈂")}, + {0x2f961, 0, 0, 0, f(No, false, "𥮫")}, + {0x2f962, 0, 0, 0, f(No, false, "篆")}, + {0x2f963, 0, 0, 0, f(No, false, "築")}, + {0x2f964, 0, 0, 0, f(No, false, "䈧")}, + {0x2f965, 0, 0, 0, f(No, false, "𥲀")}, + {0x2f966, 0, 0, 0, f(No, false, "糒")}, + {0x2f967, 0, 0, 0, f(No, false, "䊠")}, + {0x2f968, 0, 0, 0, f(No, false, "糨")}, + {0x2f969, 0, 0, 0, f(No, false, "糣")}, + {0x2f96a, 0, 0, 0, f(No, false, "紀")}, + {0x2f96b, 0, 0, 0, f(No, false, "𥾆")}, + {0x2f96c, 0, 0, 0, f(No, false, "絣")}, + {0x2f96d, 0, 0, 0, f(No, false, "䌁")}, + {0x2f96e, 0, 0, 0, f(No, false, "緇")}, + {0x2f96f, 0, 0, 0, f(No, false, "縂")}, + {0x2f970, 0, 0, 0, f(No, false, "繅")}, + {0x2f971, 0, 0, 0, f(No, false, "䌴")}, + {0x2f972, 0, 0, 0, f(No, false, "𦈨")}, + {0x2f973, 0, 0, 0, f(No, false, "𦉇")}, + {0x2f974, 0, 0, 0, f(No, false, "䍙")}, + {0x2f975, 0, 0, 0, f(No, false, "𦋙")}, + {0x2f976, 0, 0, 0, f(No, false, "罺")}, + {0x2f977, 0, 0, 0, f(No, false, "𦌾")}, + {0x2f978, 0, 0, 0, f(No, false, "羕")}, + {0x2f979, 0, 0, 0, f(No, false, "翺")}, + {0x2f97a, 0, 0, 0, f(No, false, "者")}, + {0x2f97b, 0, 0, 0, f(No, false, "𦓚")}, + {0x2f97c, 0, 0, 0, f(No, false, "𦔣")}, + {0x2f97d, 0, 0, 0, f(No, false, "聠")}, + {0x2f97e, 0, 0, 0, f(No, false, "𦖨")}, + {0x2f97f, 0, 0, 0, f(No, false, "聰")}, + {0x2f980, 0, 0, 0, f(No, false, "𣍟")}, + {0x2f981, 0, 0, 0, f(No, false, "䏕")}, + {0x2f982, 0, 0, 0, f(No, false, "育")}, + {0x2f983, 0, 0, 0, f(No, false, "脃")}, + {0x2f984, 0, 0, 0, f(No, false, "䐋")}, + {0x2f985, 0, 0, 0, f(No, false, "脾")}, + {0x2f986, 0, 0, 0, f(No, false, "媵")}, + {0x2f987, 0, 0, 0, f(No, false, "𦞧")}, + {0x2f988, 0, 0, 0, f(No, false, "𦞵")}, + {0x2f989, 0, 0, 0, f(No, false, "𣎓")}, + {0x2f98a, 0, 0, 0, f(No, false, "𣎜")}, + {0x2f98b, 0, 0, 0, f(No, false, "舁")}, + {0x2f98c, 0, 0, 0, f(No, false, "舄")}, + {0x2f98d, 0, 0, 0, f(No, false, "辞")}, + {0x2f98e, 0, 0, 0, f(No, false, "䑫")}, + {0x2f98f, 0, 0, 0, f(No, false, "芑")}, + {0x2f990, 0, 0, 0, f(No, false, "芋")}, + {0x2f991, 0, 0, 0, f(No, false, "芝")}, + {0x2f992, 0, 0, 0, f(No, false, "劳")}, + {0x2f993, 0, 0, 0, f(No, false, "花")}, + {0x2f994, 0, 0, 0, f(No, false, "芳")}, + {0x2f995, 0, 0, 0, f(No, false, "芽")}, + {0x2f996, 0, 0, 0, f(No, false, "苦")}, + {0x2f997, 0, 0, 0, f(No, false, "𦬼")}, + {0x2f998, 0, 0, 0, f(No, false, "若")}, + {0x2f999, 0, 0, 0, f(No, false, "茝")}, + {0x2f99a, 0, 0, 0, f(No, false, "荣")}, + {0x2f99b, 0, 0, 0, f(No, false, "莭")}, + {0x2f99c, 0, 0, 0, f(No, false, "茣")}, + {0x2f99d, 0, 0, 0, f(No, false, "莽")}, + {0x2f99e, 0, 0, 0, f(No, false, "菧")}, + {0x2f99f, 0, 0, 0, f(No, false, "著")}, + {0x2f9a0, 0, 0, 0, f(No, false, "荓")}, + {0x2f9a1, 0, 0, 0, f(No, false, "菊")}, + {0x2f9a2, 0, 0, 0, f(No, false, "菌")}, + {0x2f9a3, 0, 0, 0, f(No, false, "菜")}, + {0x2f9a4, 0, 0, 0, f(No, false, "𦰶")}, + {0x2f9a5, 0, 0, 0, f(No, false, "𦵫")}, + {0x2f9a6, 0, 0, 0, f(No, false, "𦳕")}, + {0x2f9a7, 0, 0, 0, f(No, false, "䔫")}, + {0x2f9a8, 0, 0, 0, f(No, false, "蓱")}, + {0x2f9a9, 0, 0, 0, f(No, false, "蓳")}, + {0x2f9aa, 0, 0, 0, f(No, false, "蔖")}, + {0x2f9ab, 0, 0, 0, f(No, false, "𧏊")}, + {0x2f9ac, 0, 0, 0, f(No, false, "蕤")}, + {0x2f9ad, 0, 0, 0, f(No, false, "𦼬")}, + {0x2f9ae, 0, 0, 0, f(No, false, "䕝")}, + {0x2f9af, 0, 0, 0, f(No, false, "䕡")}, + {0x2f9b0, 0, 0, 0, f(No, false, "𦾱")}, + {0x2f9b1, 0, 0, 0, f(No, false, "𧃒")}, + {0x2f9b2, 0, 0, 0, f(No, false, "䕫")}, + {0x2f9b3, 0, 0, 0, f(No, false, "虐")}, + {0x2f9b4, 0, 0, 0, f(No, false, "虜")}, + {0x2f9b5, 0, 0, 0, f(No, false, "虧")}, + {0x2f9b6, 0, 0, 0, f(No, false, "虩")}, + {0x2f9b7, 0, 0, 0, f(No, false, "蚩")}, + {0x2f9b8, 0, 0, 0, f(No, false, "蚈")}, + {0x2f9b9, 0, 0, 0, f(No, false, "蜎")}, + {0x2f9ba, 0, 0, 0, f(No, false, "蛢")}, + {0x2f9bb, 0, 0, 0, f(No, false, "蝹")}, + {0x2f9bc, 0, 0, 0, f(No, false, "蜨")}, + {0x2f9bd, 0, 0, 0, f(No, false, "蝫")}, + {0x2f9be, 0, 0, 0, f(No, false, "螆")}, + {0x2f9bf, 0, 0, 0, f(No, false, "䗗")}, + {0x2f9c0, 0, 0, 0, f(No, false, "蟡")}, + {0x2f9c1, 0, 0, 0, f(No, false, "蠁")}, + {0x2f9c2, 0, 0, 0, f(No, false, "䗹")}, + {0x2f9c3, 0, 0, 0, f(No, false, "衠")}, + {0x2f9c4, 0, 0, 0, f(No, false, "衣")}, + {0x2f9c5, 0, 0, 0, f(No, false, "𧙧")}, + {0x2f9c6, 0, 0, 0, f(No, false, "裗")}, + {0x2f9c7, 0, 0, 0, f(No, false, "裞")}, + {0x2f9c8, 0, 0, 0, f(No, false, "䘵")}, + {0x2f9c9, 0, 0, 0, f(No, false, "裺")}, + {0x2f9ca, 0, 0, 0, f(No, false, "㒻")}, + {0x2f9cb, 0, 0, 0, f(No, false, "𧢮")}, + {0x2f9cc, 0, 0, 0, f(No, false, "𧥦")}, + {0x2f9cd, 0, 0, 0, f(No, false, "䚾")}, + {0x2f9ce, 0, 0, 0, f(No, false, "䛇")}, + {0x2f9cf, 0, 0, 0, f(No, false, "誠")}, + {0x2f9d0, 0, 0, 0, f(No, false, "諭")}, + {0x2f9d1, 0, 0, 0, f(No, false, "變")}, + {0x2f9d2, 0, 0, 0, f(No, false, "豕")}, + {0x2f9d3, 0, 0, 0, f(No, false, "𧲨")}, + {0x2f9d4, 0, 0, 0, f(No, false, "貫")}, + {0x2f9d5, 0, 0, 0, f(No, false, "賁")}, + {0x2f9d6, 0, 0, 0, f(No, false, "贛")}, + {0x2f9d7, 0, 0, 0, f(No, false, "起")}, + {0x2f9d8, 0, 0, 0, f(No, false, "𧼯")}, + {0x2f9d9, 0, 0, 0, f(No, false, "𠠄")}, + {0x2f9da, 0, 0, 0, f(No, false, "跋")}, + {0x2f9db, 0, 0, 0, f(No, false, "趼")}, + {0x2f9dc, 0, 0, 0, f(No, false, "跰")}, + {0x2f9dd, 0, 0, 0, f(No, false, "𠣞")}, + {0x2f9de, 0, 0, 0, f(No, false, "軔")}, + {0x2f9df, 0, 0, 0, f(No, false, "輸")}, + {0x2f9e0, 0, 0, 0, f(No, false, "𨗒")}, + {0x2f9e1, 0, 0, 0, f(No, false, "𨗭")}, + {0x2f9e2, 0, 0, 0, f(No, false, "邔")}, + {0x2f9e3, 0, 0, 0, f(No, false, "郱")}, + {0x2f9e4, 0, 0, 0, f(No, false, "鄑")}, + {0x2f9e5, 0, 0, 0, f(No, false, "𨜮")}, + {0x2f9e6, 0, 0, 0, f(No, false, "鄛")}, + {0x2f9e7, 0, 0, 0, f(No, false, "鈸")}, + {0x2f9e8, 0, 0, 0, f(No, false, "鋗")}, + {0x2f9e9, 0, 0, 0, f(No, false, "鋘")}, + {0x2f9ea, 0, 0, 0, f(No, false, "鉼")}, + {0x2f9eb, 0, 0, 0, f(No, false, "鏹")}, + {0x2f9ec, 0, 0, 0, f(No, false, "鐕")}, + {0x2f9ed, 0, 0, 0, f(No, false, "𨯺")}, + {0x2f9ee, 0, 0, 0, f(No, false, "開")}, + {0x2f9ef, 0, 0, 0, f(No, false, "䦕")}, + {0x2f9f0, 0, 0, 0, f(No, false, "閷")}, + {0x2f9f1, 0, 0, 0, f(No, false, "𨵷")}, + {0x2f9f2, 0, 0, 0, f(No, false, "䧦")}, + {0x2f9f3, 0, 0, 0, f(No, false, "雃")}, + {0x2f9f4, 0, 0, 0, f(No, false, "嶲")}, + {0x2f9f5, 0, 0, 0, f(No, false, "霣")}, + {0x2f9f6, 0, 0, 0, f(No, false, "𩅅")}, + {0x2f9f7, 0, 0, 0, f(No, false, "𩈚")}, + {0x2f9f8, 0, 0, 0, f(No, false, "䩮")}, + {0x2f9f9, 0, 0, 0, f(No, false, "䩶")}, + {0x2f9fa, 0, 0, 0, f(No, false, "韠")}, + {0x2f9fb, 0, 0, 0, f(No, false, "𩐊")}, + {0x2f9fc, 0, 0, 0, f(No, false, "䪲")}, + {0x2f9fd, 0, 0, 0, f(No, false, "𩒖")}, + {0x2f9fe, 0, 0, 0, f(No, false, "頋")}, + {0x2fa00, 0, 0, 0, f(No, false, "頩")}, + {0x2fa01, 0, 0, 0, f(No, false, "𩖶")}, + {0x2fa02, 0, 0, 0, f(No, false, "飢")}, + {0x2fa03, 0, 0, 0, f(No, false, "䬳")}, + {0x2fa04, 0, 0, 0, f(No, false, "餩")}, + {0x2fa05, 0, 0, 0, f(No, false, "馧")}, + {0x2fa06, 0, 0, 0, f(No, false, "駂")}, + {0x2fa07, 0, 0, 0, f(No, false, "駾")}, + {0x2fa08, 0, 0, 0, f(No, false, "䯎")}, + {0x2fa09, 0, 0, 0, f(No, false, "𩬰")}, + {0x2fa0a, 0, 0, 0, f(No, false, "鬒")}, + {0x2fa0b, 0, 0, 0, f(No, false, "鱀")}, + {0x2fa0c, 0, 0, 0, f(No, false, "鳽")}, + {0x2fa0d, 0, 0, 0, f(No, false, "䳎")}, + {0x2fa0e, 0, 0, 0, f(No, false, "䳭")}, + {0x2fa0f, 0, 0, 0, f(No, false, "鵧")}, + {0x2fa10, 0, 0, 0, f(No, false, "𪃎")}, + {0x2fa11, 0, 0, 0, f(No, false, "䳸")}, + {0x2fa12, 0, 0, 0, f(No, false, "𪄅")}, + {0x2fa13, 0, 0, 0, f(No, false, "𪈎")}, + {0x2fa14, 0, 0, 0, f(No, false, "𪊑")}, + {0x2fa15, 0, 0, 0, f(No, false, "麻")}, + {0x2fa16, 0, 0, 0, f(No, false, "䵖")}, + {0x2fa17, 0, 0, 0, f(No, false, "黹")}, + {0x2fa18, 0, 0, 0, f(No, false, "黾")}, + {0x2fa19, 0, 0, 0, f(No, false, "鼅")}, + {0x2fa1a, 0, 0, 0, f(No, false, "鼏")}, + {0x2fa1b, 0, 0, 0, f(No, false, "鼖")}, + {0x2fa1c, 0, 0, 0, f(No, false, "鼻")}, + {0x2fa1d, 0, 0, 0, f(No, false, "𪘀")}, + {0x2fa1e, 0, 0, 0, f(Yes, false, "")}, +} diff --git a/vendor/golang.org/x/text/unicode/norm/example_iter_test.go b/vendor/golang.org/x/text/unicode/norm/example_iter_test.go new file mode 100644 index 000000000..82df89c7b --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/example_iter_test.go @@ -0,0 +1,82 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm_test + +import ( + "bytes" + "fmt" + "unicode/utf8" + + "golang.org/x/text/unicode/norm" +) + +// EqualSimple uses a norm.Iter to compare two non-normalized +// strings for equivalence. +func EqualSimple(a, b string) bool { + var ia, ib norm.Iter + ia.InitString(norm.NFKD, a) + ib.InitString(norm.NFKD, b) + for !ia.Done() && !ib.Done() { + if !bytes.Equal(ia.Next(), ib.Next()) { + return false + } + } + return ia.Done() && ib.Done() +} + +// FindPrefix finds the longest common prefix of ASCII characters +// of a and b. +func FindPrefix(a, b string) int { + i := 0 + for ; i < len(a) && i < len(b) && a[i] < utf8.RuneSelf && a[i] == b[i]; i++ { + } + return i +} + +// EqualOpt is like EqualSimple, but optimizes the special +// case for ASCII characters. +func EqualOpt(a, b string) bool { + n := FindPrefix(a, b) + a, b = a[n:], b[n:] + var ia, ib norm.Iter + ia.InitString(norm.NFKD, a) + ib.InitString(norm.NFKD, b) + for !ia.Done() && !ib.Done() { + if !bytes.Equal(ia.Next(), ib.Next()) { + return false + } + if n := int64(FindPrefix(a[ia.Pos():], b[ib.Pos():])); n != 0 { + ia.Seek(n, 1) + ib.Seek(n, 1) + } + } + return ia.Done() && ib.Done() +} + +var compareTests = []struct{ a, b string }{ + {"aaa", "aaa"}, + {"aaa", "aab"}, + {"a\u0300a", "\u00E0a"}, + {"a\u0300\u0320b", "a\u0320\u0300b"}, + {"\u1E0A\u0323", "\x44\u0323\u0307"}, + // A character that decomposes into multiple segments + // spans several iterations. + {"\u3304", "\u30A4\u30CB\u30F3\u30AF\u3099"}, +} + +func ExampleIter() { + for i, t := range compareTests { + r0 := EqualSimple(t.a, t.b) + r1 := EqualOpt(t.a, t.b) + fmt.Printf("%d: %v %v\n", i, r0, r1) + } + // Output: + // 0: true true + // 1: false false + // 2: true true + // 3: true true + // 4: true true + // 5: true true +} diff --git a/vendor/golang.org/x/text/unicode/norm/example_test.go b/vendor/golang.org/x/text/unicode/norm/example_test.go new file mode 100644 index 000000000..8f3b15653 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/example_test.go @@ -0,0 +1,27 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm_test + +import ( + "fmt" + + "golang.org/x/text/unicode/norm" +) + +func ExampleForm_NextBoundary() { + s := norm.NFD.String("Mêlée") + + for i := 0; i < len(s); { + d := norm.NFC.NextBoundaryInString(s[i:], true) + fmt.Printf("%[1]s: %+[1]q\n", s[i:i+d]) + i += d + } + // Output: + // M: "M" + // ê: "e\u0302" + // l: "l" + // é: "e\u0301" + // e: "e" +} diff --git a/vendor/golang.org/x/text/unicode/norm/forminfo_test.go b/vendor/golang.org/x/text/unicode/norm/forminfo_test.go new file mode 100644 index 000000000..e15ba9bee --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/forminfo_test.go @@ -0,0 +1,54 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build test + +package norm + +import "testing" + +func TestProperties(t *testing.T) { + var d runeData + CK := [2]string{"C", "K"} + for k, r := 1, rune(0); r < 0x2ffff; r++ { + if k < len(testData) && r == testData[k].r { + d = testData[k] + k++ + } + s := string(r) + for j, p := range []Properties{NFC.PropertiesString(s), NFKC.PropertiesString(s)} { + f := d.f[j] + if p.CCC() != d.ccc { + t.Errorf("%U: ccc(%s): was %d; want %d %X", r, CK[j], p.CCC(), d.ccc, p.index) + } + if p.isYesC() != (f.qc == Yes) { + t.Errorf("%U: YesC(%s): was %v; want %v", r, CK[j], p.isYesC(), f.qc == Yes) + } + if p.combinesBackward() != (f.qc == Maybe) { + t.Errorf("%U: combines backwards(%s): was %v; want %v", r, CK[j], p.combinesBackward(), f.qc == Maybe) + } + if p.nLeadingNonStarters() != d.nLead { + t.Errorf("%U: nLead(%s): was %d; want %d %#v %#v", r, CK[j], p.nLeadingNonStarters(), d.nLead, p, d) + } + if p.nTrailingNonStarters() != d.nTrail { + t.Errorf("%U: nTrail(%s): was %d; want %d %#v %#v", r, CK[j], p.nTrailingNonStarters(), d.nTrail, p, d) + } + if p.combinesForward() != f.combinesForward { + t.Errorf("%U: combines forward(%s): was %v; want %v %#v", r, CK[j], p.combinesForward(), f.combinesForward, p) + } + // Skip Hangul as it is algorithmically computed. + if r >= hangulBase && r < hangulEnd { + continue + } + if p.hasDecomposition() { + if has := f.decomposition != ""; !has { + t.Errorf("%U: hasDecomposition(%s): was %v; want %v", r, CK[j], p.hasDecomposition(), has) + } + if string(p.Decomposition()) != f.decomposition { + t.Errorf("%U: decomp(%s): was %+q; want %+q", r, CK[j], p.Decomposition(), f.decomposition) + } + } + } + } +} diff --git a/vendor/golang.org/x/text/unicode/norm/iter_test.go b/vendor/golang.org/x/text/unicode/norm/iter_test.go new file mode 100644 index 000000000..d95aa304d --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/iter_test.go @@ -0,0 +1,98 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "strings" + "testing" +) + +func doIterNorm(f Form, s string) []byte { + acc := []byte{} + i := Iter{} + i.InitString(f, s) + for !i.Done() { + acc = append(acc, i.Next()...) + } + return acc +} + +func TestIterNext(t *testing.T) { + runNormTests(t, "IterNext", func(f Form, out []byte, s string) []byte { + return doIterNorm(f, string(append(out, s...))) + }) +} + +type SegmentTest struct { + in string + out []string +} + +var segmentTests = []SegmentTest{ + {"\u1E0A\u0323a", []string{"\x44\u0323\u0307", "a", ""}}, + {rep('a', segSize), append(strings.Split(rep('a', segSize), ""), "")}, + {rep('a', segSize+2), append(strings.Split(rep('a', segSize+2), ""), "")}, + {rep('a', segSize) + "\u0300aa", + append(strings.Split(rep('a', segSize-1), ""), "a\u0300", "a", "a", "")}, + + // U+0f73 is NOT treated as a starter as it is a modifier + {"a" + grave(29) + "\u0f73", []string{"a" + grave(29), cgj + "\u0f73"}}, + {"a\u0f73", []string{"a\u0f73"}}, + + // U+ff9e is treated as a non-starter. + // TODO: should we? Note that this will only affect iteration, as whether + // or not we do so does not affect the normalization output and will either + // way result in consistent iteration output. + {"a" + grave(30) + "\uff9e", []string{"a" + grave(30), cgj + "\uff9e"}}, + {"a\uff9e", []string{"a\uff9e"}}, +} + +var segmentTestsK = []SegmentTest{ + {"\u3332", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u3099", ""}}, + // last segment of multi-segment decomposition needs normalization + {"\u3332\u093C", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u093C\u3099", ""}}, + {"\u320E", []string{"\x28", "\uAC00", "\x29"}}, + + // last segment should be copied to start of buffer. + {"\ufdfa", []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645", ""}}, + {"\ufdfa" + grave(30), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), ""}}, + {"\uFDFA" + grave(64), []string{"\u0635", "\u0644", "\u0649", " ", "\u0627", "\u0644", "\u0644", "\u0647", " ", "\u0639", "\u0644", "\u064a", "\u0647", " ", "\u0648", "\u0633", "\u0644", "\u0645" + grave(30), cgj + grave(30), cgj + grave(4), ""}}, + + // Hangul and Jamo are grouped together. + {"\uAC00", []string{"\u1100\u1161", ""}}, + {"\uAC01", []string{"\u1100\u1161\u11A8", ""}}, + {"\u1100\u1161", []string{"\u1100\u1161", ""}}, +} + +// Note that, by design, segmentation is equal for composing and decomposing forms. +func TestIterSegmentation(t *testing.T) { + segmentTest(t, "SegmentTestD", NFD, segmentTests) + segmentTest(t, "SegmentTestC", NFC, segmentTests) + segmentTest(t, "SegmentTestKD", NFKD, segmentTestsK) + segmentTest(t, "SegmentTestKC", NFKC, segmentTestsK) +} + +func segmentTest(t *testing.T, name string, f Form, tests []SegmentTest) { + iter := Iter{} + for i, tt := range tests { + iter.InitString(f, tt.in) + for j, seg := range tt.out { + if seg == "" { + if !iter.Done() { + res := string(iter.Next()) + t.Errorf(`%s:%d:%d: expected Done()==true, found segment %+q`, name, i, j, res) + } + continue + } + if iter.Done() { + t.Errorf("%s:%d:%d: Done()==true, want false", name, i, j) + } + seg = f.String(seg) + if res := string(iter.Next()); res != seg { + t.Errorf(`%s:%d:%d" segment was %+q (%d); want %+q (%d)`, name, i, j, pc(res), len(res), pc(seg), len(seg)) + } + } + } +} diff --git a/vendor/golang.org/x/text/unicode/norm/normalize_test.go b/vendor/golang.org/x/text/unicode/norm/normalize_test.go new file mode 100644 index 000000000..e3c0ac73a --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/normalize_test.go @@ -0,0 +1,1287 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bytes" + "flag" + "fmt" + "io" + "log" + "strings" + "testing" + "unicode/utf8" + + "golang.org/x/text/internal/testtext" + "golang.org/x/text/transform" +) + +var ( + testn = flag.Int("testn", -1, "specific test number to run or -1 for all") +) + +// pc replaces any rune r that is repeated n times, for n > 1, with r{n}. +func pc(s string) []byte { + b := bytes.NewBuffer(make([]byte, 0, len(s))) + for i := 0; i < len(s); { + r, sz := utf8.DecodeRuneInString(s[i:]) + n := 0 + if sz == 1 { + // Special-case one-byte case to handle repetition for invalid UTF-8. + for c := s[i]; i+n < len(s) && s[i+n] == c; n++ { + } + } else { + for _, r2 := range s[i:] { + if r2 != r { + break + } + n++ + } + } + b.WriteString(s[i : i+sz]) + if n > 1 { + fmt.Fprintf(b, "{%d}", n) + } + i += sz * n + } + return b.Bytes() +} + +// pidx finds the index from which two strings start to differ, plus context. +// It returns the index and ellipsis if the index is greater than 0. +func pidx(a, b string) (i int, prefix string) { + for ; i < len(a) && i < len(b) && a[i] == b[i]; i++ { + } + if i < 8 { + return 0, "" + } + i -= 3 // ensure taking at least one full rune before the difference. + for k := i - 7; i > k && !utf8.RuneStart(a[i]); i-- { + } + return i, "..." +} + +type PositionTest struct { + input string + pos int + buffer string // expected contents of reorderBuffer, if applicable +} + +type positionFunc func(rb *reorderBuffer, s string) (int, []byte) + +func runPosTests(t *testing.T, name string, f Form, fn positionFunc, tests []PositionTest) { + rb := reorderBuffer{} + rb.init(f, nil) + for i, test := range tests { + rb.reset() + rb.src = inputString(test.input) + rb.nsrc = len(test.input) + pos, out := fn(&rb, test.input) + if pos != test.pos { + t.Errorf("%s:%d: position is %d; want %d", name, i, pos, test.pos) + } + if outs := string(out); outs != test.buffer { + k, pfx := pidx(outs, test.buffer) + t.Errorf("%s:%d: buffer \nwas %s%+q; \nwant %s%+q", name, i, pfx, pc(outs[k:]), pfx, pc(test.buffer[k:])) + } + } +} + +func grave(n int) string { + return rep(0x0300, n) +} + +func rep(r rune, n int) string { + return strings.Repeat(string(r), n) +} + +const segSize = maxByteBufferSize + +var cgj = GraphemeJoiner + +var decomposeSegmentTests = []PositionTest{ + // illegal runes + {"\xC2", 0, ""}, + {"\xC0", 1, "\xC0"}, + {"\u00E0\x80", 2, "\u0061\u0300"}, + // starter + {"a", 1, "a"}, + {"ab", 1, "a"}, + // starter + composing + {"a\u0300", 3, "a\u0300"}, + {"a\u0300b", 3, "a\u0300"}, + // with decomposition + {"\u00C0", 2, "A\u0300"}, + {"\u00C0b", 2, "A\u0300"}, + // long + {grave(31), 60, grave(30) + cgj}, + {"a" + grave(31), 61, "a" + grave(30) + cgj}, + + // Stability tests: see http://www.unicode.org/review/pr-29.html. + // U+0300 COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;;;; + // U+0B47 ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; + // U+0B3E ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; + // U+1100 HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;; + // U+1161 HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;; + {"\u0B47\u0300\u0B3E", 8, "\u0B47\u0300\u0B3E"}, + {"\u1100\u0300\u1161", 8, "\u1100\u0300\u1161"}, + {"\u0B47\u0B3E", 6, "\u0B47\u0B3E"}, + {"\u1100\u1161", 6, "\u1100\u1161"}, + + // U+04DA MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; + // Sequence of decomposing characters that are starters and modifiers. + {"\u0d4a" + strings.Repeat("\u0d3e", 31), 90, "\u0d46" + strings.Repeat("\u0d3e", 30) + cgj}, + + {grave(30), 60, grave(30)}, + // U+FF9E is a starter, but decomposes to U+3099, which is not. + {grave(30) + "\uff9e", 60, grave(30) + cgj}, + // ends with incomplete UTF-8 encoding + {"\xCC", 0, ""}, + {"\u0300\xCC", 2, "\u0300"}, +} + +func decomposeSegmentF(rb *reorderBuffer, s string) (int, []byte) { + rb.initString(NFD, s) + rb.setFlusher(nil, appendFlush) + p := decomposeSegment(rb, 0, true) + return p, rb.out +} + +func TestDecomposeSegment(t *testing.T) { + runPosTests(t, "TestDecomposeSegment", NFC, decomposeSegmentF, decomposeSegmentTests) +} + +var firstBoundaryTests = []PositionTest{ + // no boundary + {"", -1, ""}, + {"\u0300", -1, ""}, + {"\x80\x80", -1, ""}, + // illegal runes + {"\xff", 0, ""}, + {"\u0300\xff", 2, ""}, + {"\u0300\xc0\x80\x80", 2, ""}, + // boundaries + {"a", 0, ""}, + {"\u0300a", 2, ""}, + // Hangul + {"\u1103\u1161", 0, ""}, + {"\u110B\u1173\u11B7", 0, ""}, + {"\u1161\u110B\u1173\u11B7", 3, ""}, + {"\u1173\u11B7\u1103\u1161", 6, ""}, + // too many combining characters. + {grave(maxNonStarters - 1), -1, ""}, + {grave(maxNonStarters), 60, ""}, + {grave(maxNonStarters + 1), 60, ""}, +} + +func firstBoundaryF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.FirstBoundary([]byte(s)), nil +} + +func firstBoundaryStringF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.FirstBoundaryInString(s), nil +} + +func TestFirstBoundary(t *testing.T) { + runPosTests(t, "TestFirstBoundary", NFC, firstBoundaryF, firstBoundaryTests) + runPosTests(t, "TestFirstBoundaryInString", NFC, firstBoundaryStringF, firstBoundaryTests) +} + +func TestNextBoundary(t *testing.T) { + testCases := []struct { + input string + atEOF bool + want int + }{ + // no boundary + {"", true, 0}, + {"", false, -1}, + {"\u0300", true, 2}, + {"\u0300", false, -1}, + {"\x80\x80", true, 1}, + {"\x80\x80", false, 1}, + // illegal runes + {"\xff", false, 1}, + {"\u0300\xff", false, 2}, + {"\u0300\xc0\x80\x80", false, 2}, + {"\xc2\x80\x80", false, 2}, + {"\xc2", false, -1}, + {"\xc2", true, 1}, + {"a\u0300\xc2", false, -1}, + {"a\u0300\xc2", true, 3}, + // boundaries + {"a", true, 1}, + {"a", false, -1}, + {"aa", false, 1}, + {"\u0300", true, 2}, + {"\u0300", false, -1}, + {"\u0300a", false, 2}, + // Hangul + {"\u1103\u1161", true, 6}, + {"\u1103\u1161", false, -1}, + {"\u110B\u1173\u11B7", false, -1}, + {"\u110B\u1173\u11B7\u110B\u1173\u11B7", false, 9}, + {"\u1161\u110B\u1173\u11B7", false, 3}, + {"\u1173\u11B7\u1103\u1161", false, 6}, + // too many combining characters. + {grave(maxNonStarters - 1), false, -1}, + {grave(maxNonStarters), false, 60}, + {grave(maxNonStarters + 1), false, 60}, + } + + for _, tc := range testCases { + if got := NFC.NextBoundary([]byte(tc.input), tc.atEOF); got != tc.want { + t.Errorf("NextBoundary(%+q, %v) = %d; want %d", tc.input, tc.atEOF, got, tc.want) + } + if got := NFC.NextBoundaryInString(tc.input, tc.atEOF); got != tc.want { + t.Errorf("NextBoundaryInString(%+q, %v) = %d; want %d", tc.input, tc.atEOF, got, tc.want) + } + } +} + +var decomposeToLastTests = []PositionTest{ + // ends with inert character + {"Hello!", 6, ""}, + {"\u0632", 2, ""}, + {"a\u0301\u0635", 5, ""}, + // ends with non-inert starter + {"a", 0, "a"}, + {"a\u0301a", 3, "a"}, + {"a\u0301\u03B9", 3, "\u03B9"}, + {"a\u0327", 0, "a\u0327"}, + // illegal runes + {"\xFF", 1, ""}, + {"aa\xFF", 3, ""}, + {"\xC0\x80\x80", 3, ""}, + {"\xCC\x80\x80", 3, ""}, + // ends with incomplete UTF-8 encoding + {"a\xCC", 2, ""}, + // ends with combining characters + {"\u0300\u0301", 0, "\u0300\u0301"}, + {"a\u0300\u0301", 0, "a\u0300\u0301"}, + {"a\u0301\u0308", 0, "a\u0301\u0308"}, + {"a\u0308\u0301", 0, "a\u0308\u0301"}, + {"aaaa\u0300\u0301", 3, "a\u0300\u0301"}, + {"\u0300a\u0300\u0301", 2, "a\u0300\u0301"}, + {"\u00C0", 0, "A\u0300"}, + {"a\u00C0", 1, "A\u0300"}, + // decomposing + {"a\u0300\u00E0", 3, "a\u0300"}, + // multisegment decompositions (flushes leading segments) + {"a\u0300\uFDC0", 7, "\u064A"}, + {"\uFDC0" + grave(29), 4, "\u064A" + grave(29)}, + {"\uFDC0" + grave(30), 4, "\u064A" + grave(30)}, + {"\uFDC0" + grave(31), 5, grave(30)}, + {"\uFDFA" + grave(14), 31, "\u0645" + grave(14)}, + // Overflow + {"\u00E0" + grave(29), 0, "a" + grave(30)}, + {"\u00E0" + grave(30), 2, grave(30)}, + // Hangul + {"a\u1103", 1, "\u1103"}, + {"a\u110B", 1, "\u110B"}, + {"a\u110B\u1173", 1, "\u110B\u1173"}, + // See comment in composition.go:compBoundaryAfter. + {"a\u110B\u1173\u11B7", 1, "\u110B\u1173\u11B7"}, + {"a\uC73C", 1, "\u110B\u1173"}, + {"다음", 3, "\u110B\u1173\u11B7"}, + {"다", 0, "\u1103\u1161"}, + {"\u1103\u1161\u110B\u1173\u11B7", 6, "\u110B\u1173\u11B7"}, + {"\u110B\u1173\u11B7\u1103\u1161", 9, "\u1103\u1161"}, + {"다음음", 6, "\u110B\u1173\u11B7"}, + {"음다다", 6, "\u1103\u1161"}, + // maximized buffer + {"a" + grave(30), 0, "a" + grave(30)}, + // Buffer overflow + {"a" + grave(31), 3, grave(30)}, + // weird UTF-8 + {"a\u0300\u11B7", 0, "a\u0300\u11B7"}, +} + +func decomposeToLast(rb *reorderBuffer, s string) (int, []byte) { + rb.setFlusher([]byte(s), appendFlush) + decomposeToLastBoundary(rb) + buf := rb.flush(nil) + return len(rb.out), buf +} + +func TestDecomposeToLastBoundary(t *testing.T) { + runPosTests(t, "TestDecomposeToLastBoundary", NFKC, decomposeToLast, decomposeToLastTests) +} + +var lastBoundaryTests = []PositionTest{ + // ends with inert character + {"Hello!", 6, ""}, + {"\u0632", 2, ""}, + // ends with non-inert starter + {"a", 0, ""}, + // illegal runes + {"\xff", 1, ""}, + {"aa\xff", 3, ""}, + {"a\xff\u0300", 1, ""}, // TODO: should probably be 2. + {"\xc0\x80\x80", 3, ""}, + {"\xc0\x80\x80\u0300", 3, ""}, + // ends with incomplete UTF-8 encoding + {"\xCC", -1, ""}, + {"\xE0\x80", -1, ""}, + {"\xF0\x80\x80", -1, ""}, + {"a\xCC", 0, ""}, + {"\x80\xCC", 1, ""}, + {"\xCC\xCC", 1, ""}, + // ends with combining characters + {"a\u0300\u0301", 0, ""}, + {"aaaa\u0300\u0301", 3, ""}, + {"\u0300a\u0300\u0301", 2, ""}, + {"\u00C2", 0, ""}, + {"a\u00C2", 1, ""}, + // decomposition may recombine + {"\u0226", 0, ""}, + // no boundary + {"", -1, ""}, + {"\u0300\u0301", -1, ""}, + {"\u0300", -1, ""}, + {"\x80\x80", -1, ""}, + {"\x80\x80\u0301", -1, ""}, + // Hangul + {"다음", 3, ""}, + {"다", 0, ""}, + {"\u1103\u1161\u110B\u1173\u11B7", 6, ""}, + {"\u110B\u1173\u11B7\u1103\u1161", 9, ""}, + // too many combining characters. + {grave(maxNonStarters - 1), -1, ""}, + // May still be preceded with a non-starter. + {grave(maxNonStarters), -1, ""}, + // May still need to insert a cgj after the last combiner. + {grave(maxNonStarters + 1), 2, ""}, + {grave(maxNonStarters + 2), 4, ""}, + + {"a" + grave(maxNonStarters-1), 0, ""}, + {"a" + grave(maxNonStarters), 0, ""}, + // May still need to insert a cgj after the last combiner. + {"a" + grave(maxNonStarters+1), 3, ""}, + {"a" + grave(maxNonStarters+2), 5, ""}, +} + +func lastBoundaryF(rb *reorderBuffer, s string) (int, []byte) { + return rb.f.form.LastBoundary([]byte(s)), nil +} + +func TestLastBoundary(t *testing.T) { + runPosTests(t, "TestLastBoundary", NFC, lastBoundaryF, lastBoundaryTests) +} + +type spanTest struct { + input string + atEOF bool + n int + err error +} + +var quickSpanTests = []spanTest{ + {"", true, 0, nil}, + // starters + {"a", true, 1, nil}, + {"abc", true, 3, nil}, + {"\u043Eb", true, 3, nil}, + // incomplete last rune. + {"\xCC", true, 1, nil}, + {"\xCC", false, 0, transform.ErrShortSrc}, + {"a\xCC", true, 2, nil}, + {"a\xCC", false, 0, transform.ErrShortSrc}, // TODO: could be 1 for NFD + // incorrectly ordered combining characters + {"\u0300\u0316", true, 0, transform.ErrEndOfSpan}, + {"\u0300\u0316", false, 0, transform.ErrEndOfSpan}, + {"\u0300\u0316cd", true, 0, transform.ErrEndOfSpan}, + {"\u0300\u0316cd", false, 0, transform.ErrEndOfSpan}, + // have a maximum number of combining characters. + {rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan}, + {"a" + rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan}, + {"Ɵ" + rep(0x035D, 30) + "\u035B", true, 0, transform.ErrEndOfSpan}, + {"aa" + rep(0x035D, 30) + "\u035B", true, 1, transform.ErrEndOfSpan}, + {rep(0x035D, 30) + cgj + "\u035B", true, 64, nil}, + {"a" + rep(0x035D, 30) + cgj + "\u035B", true, 65, nil}, + {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", true, 66, nil}, + {"aa" + rep(0x035D, 30) + cgj + "\u035B", true, 66, nil}, + + {"a" + rep(0x035D, 30) + cgj + "\u035B", false, 61, transform.ErrShortSrc}, + {"Ɵ" + rep(0x035D, 30) + cgj + "\u035B", false, 62, transform.ErrShortSrc}, + {"aa" + rep(0x035D, 30) + cgj + "\u035B", false, 62, transform.ErrShortSrc}, +} + +var quickSpanNFDTests = []spanTest{ + // needs decomposing + {"\u00C0", true, 0, transform.ErrEndOfSpan}, + {"abc\u00C0", true, 3, transform.ErrEndOfSpan}, + // correctly ordered combining characters + {"\u0300", true, 2, nil}, + {"ab\u0300", true, 4, nil}, + {"ab\u0300cd", true, 6, nil}, + {"\u0300cd", true, 4, nil}, + {"\u0316\u0300", true, 4, nil}, + {"ab\u0316\u0300", true, 6, nil}, + {"ab\u0316\u0300cd", true, 8, nil}, + {"ab\u0316\u0300\u00C0", true, 6, transform.ErrEndOfSpan}, + {"\u0316\u0300cd", true, 6, nil}, + {"\u043E\u0308b", true, 5, nil}, + // incorrectly ordered combining characters + {"ab\u0300\u0316", true, 1, transform.ErrEndOfSpan}, // TODO: we could skip 'b' as well. + {"ab\u0300\u0316cd", true, 1, transform.ErrEndOfSpan}, + // Hangul + {"같은", true, 0, transform.ErrEndOfSpan}, +} + +var quickSpanNFCTests = []spanTest{ + // okay composed + {"\u00C0", true, 2, nil}, + {"abc\u00C0", true, 5, nil}, + // correctly ordered combining characters + // TODO: b may combine with modifiers, which is why this fails. We could + // make a more precise test that that actually checks whether last + // characters combines. Probably not worth it. + {"ab\u0300", true, 1, transform.ErrEndOfSpan}, + {"ab\u0300cd", true, 1, transform.ErrEndOfSpan}, + {"ab\u0316\u0300", true, 1, transform.ErrEndOfSpan}, + {"ab\u0316\u0300cd", true, 1, transform.ErrEndOfSpan}, + {"\u00C0\u035D", true, 4, nil}, + // we do not special case leading combining characters + {"\u0300cd", true, 0, transform.ErrEndOfSpan}, + {"\u0300", true, 0, transform.ErrEndOfSpan}, + {"\u0316\u0300", true, 0, transform.ErrEndOfSpan}, + {"\u0316\u0300cd", true, 0, transform.ErrEndOfSpan}, + // incorrectly ordered combining characters + {"ab\u0300\u0316", true, 1, transform.ErrEndOfSpan}, + {"ab\u0300\u0316cd", true, 1, transform.ErrEndOfSpan}, + // Hangul + {"같은", true, 6, nil}, + {"같은", false, 3, transform.ErrShortSrc}, + // We return the start of the violating segment in case of overflow. + {grave(30) + "\uff9e", true, 0, transform.ErrEndOfSpan}, + {grave(30), true, 0, transform.ErrEndOfSpan}, +} + +func runSpanTests(t *testing.T, name string, f Form, testCases []spanTest) { + for i, tc := range testCases { + s := fmt.Sprintf("Bytes/%s/%d=%+q/atEOF=%v", name, i, pc(tc.input), tc.atEOF) + ok := testtext.Run(t, s, func(t *testing.T) { + n, err := f.Span([]byte(tc.input), tc.atEOF) + if n != tc.n || err != tc.err { + t.Errorf("\n got %d, %v;\nwant %d, %v", n, err, tc.n, tc.err) + } + }) + if !ok { + continue // Don't do the String variant if the Bytes variant failed. + } + s = fmt.Sprintf("String/%s/%d=%+q/atEOF=%v", name, i, pc(tc.input), tc.atEOF) + testtext.Run(t, s, func(t *testing.T) { + n, err := f.SpanString(tc.input, tc.atEOF) + if n != tc.n || err != tc.err { + t.Errorf("\n got %d, %v;\nwant %d, %v", n, err, tc.n, tc.err) + } + }) + } +} + +func TestSpan(t *testing.T) { + runSpanTests(t, "NFD", NFD, quickSpanTests) + runSpanTests(t, "NFD", NFD, quickSpanNFDTests) + runSpanTests(t, "NFC", NFC, quickSpanTests) + runSpanTests(t, "NFC", NFC, quickSpanNFCTests) +} + +var isNormalTests = []PositionTest{ + {"", 1, ""}, + // illegal runes + {"\xff", 1, ""}, + // starters + {"a", 1, ""}, + {"abc", 1, ""}, + {"\u043Eb", 1, ""}, + // incorrectly ordered combining characters + {"\u0300\u0316", 0, ""}, + {"ab\u0300\u0316", 0, ""}, + {"ab\u0300\u0316cd", 0, ""}, + {"\u0300\u0316cd", 0, ""}, +} +var isNormalNFDTests = []PositionTest{ + // needs decomposing + {"\u00C0", 0, ""}, + {"abc\u00C0", 0, ""}, + // correctly ordered combining characters + {"\u0300", 1, ""}, + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"\u0300cd", 1, ""}, + {"\u0316\u0300", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u0316\u0300cd", 1, ""}, + {"\u043E\u0308b", 1, ""}, + // Hangul + {"같은", 0, ""}, +} +var isNormalNFCTests = []PositionTest{ + // okay composed + {"\u00C0", 1, ""}, + {"abc\u00C0", 1, ""}, + // need reordering + {"a\u0300", 0, ""}, + {"a\u0300cd", 0, ""}, + {"a\u0316\u0300", 0, ""}, + {"a\u0316\u0300cd", 0, ""}, + // correctly ordered combining characters + {"ab\u0300", 1, ""}, + {"ab\u0300cd", 1, ""}, + {"ab\u0316\u0300", 1, ""}, + {"ab\u0316\u0300cd", 1, ""}, + {"\u00C0\u035D", 1, ""}, + {"\u0300", 1, ""}, + {"\u0316\u0300cd", 1, ""}, + // Hangul + {"같은", 1, ""}, +} + +var isNormalNFKXTests = []PositionTest{ + // Special case. + {"\u00BC", 0, ""}, +} + +func isNormalF(rb *reorderBuffer, s string) (int, []byte) { + if rb.f.form.IsNormal([]byte(s)) { + return 1, nil + } + return 0, nil +} + +func isNormalStringF(rb *reorderBuffer, s string) (int, []byte) { + if rb.f.form.IsNormalString(s) { + return 1, nil + } + return 0, nil +} + +func TestIsNormal(t *testing.T) { + runPosTests(t, "TestIsNormalNFD1", NFD, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFD2", NFD, isNormalF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFC1", NFC, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFC2", NFC, isNormalF, isNormalNFCTests) + runPosTests(t, "TestIsNormalNFKD1", NFKD, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFKD2", NFKD, isNormalF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFKD3", NFKD, isNormalF, isNormalNFKXTests) + runPosTests(t, "TestIsNormalNFKC1", NFKC, isNormalF, isNormalTests) + runPosTests(t, "TestIsNormalNFKC2", NFKC, isNormalF, isNormalNFCTests) + runPosTests(t, "TestIsNormalNFKC3", NFKC, isNormalF, isNormalNFKXTests) +} + +func TestIsNormalString(t *testing.T) { + runPosTests(t, "TestIsNormalNFD1", NFD, isNormalStringF, isNormalTests) + runPosTests(t, "TestIsNormalNFD2", NFD, isNormalStringF, isNormalNFDTests) + runPosTests(t, "TestIsNormalNFC1", NFC, isNormalStringF, isNormalTests) + runPosTests(t, "TestIsNormalNFC2", NFC, isNormalStringF, isNormalNFCTests) +} + +type AppendTest struct { + left string + right string + out string +} + +type appendFunc func(f Form, out []byte, s string) []byte + +var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"} + +func runNormTests(t *testing.T, name string, fn appendFunc) { + for f := NFC; f <= NFKD; f++ { + runAppendTests(t, name, f, fn, normTests[f]) + } +} + +func runAppendTests(t *testing.T, name string, f Form, fn appendFunc, tests []AppendTest) { + for i, test := range tests { + t.Run(fmt.Sprintf("%s/%d", fstr[f], i), func(t *testing.T) { + id := pc(test.left + test.right) + if *testn >= 0 && i != *testn { + return + } + t.Run("fn", func(t *testing.T) { + out := []byte(test.left) + have := string(fn(f, out, test.right)) + if len(have) != len(test.out) { + t.Errorf("%+q: length is %d; want %d (%+q vs %+q)", id, len(have), len(test.out), pc(have), pc(test.out)) + } + if have != test.out { + k, pf := pidx(have, test.out) + t.Errorf("%+q:\nwas %s%+q; \nwant %s%+q", id, pf, pc(have[k:]), pf, pc(test.out[k:])) + } + }) + + // Bootstrap by normalizing input. Ensures that the various variants + // behave the same. + for g := NFC; g <= NFKD; g++ { + if f == g { + continue + } + t.Run(fstr[g], func(t *testing.T) { + want := g.String(test.left + test.right) + have := string(fn(g, g.AppendString(nil, test.left), test.right)) + if len(have) != len(want) { + t.Errorf("%+q: length is %d; want %d (%+q vs %+q)", id, len(have), len(want), pc(have), pc(want)) + } + if have != want { + k, pf := pidx(have, want) + t.Errorf("%+q:\nwas %s%+q; \nwant %s%+q", id, pf, pc(have[k:]), pf, pc(want[k:])) + } + }) + } + }) + } +} + +var normTests = [][]AppendTest{ + appendTestsNFC, + appendTestsNFD, + appendTestsNFKC, + appendTestsNFKD, +} + +var appendTestsNFC = []AppendTest{ + {"", ascii, ascii}, + {"", txt_all, txt_all}, + {"\uff9e", grave(30), "\uff9e" + grave(29) + cgj + grave(1)}, + {grave(30), "\uff9e", grave(30) + cgj + "\uff9e"}, + + // Tests designed for Iter. + { // ordering of non-composing combining characters + "", + "\u0305\u0316", + "\u0316\u0305", + }, + { // segment overflow + "", + "a" + rep(0x0305, maxNonStarters+4) + "\u0316", + "a" + rep(0x0305, maxNonStarters) + cgj + "\u0316" + rep(0x305, 4), + }, + + { // Combine across non-blocking non-starters. + // U+0327 COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;; + // U+0325 COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;; + "", "a\u0327\u0325", "\u1e01\u0327", + }, + + { // Jamo V+T does not combine. + "", + "\u1161\u11a8", + "\u1161\u11a8", + }, + + // Stability tests: see http://www.unicode.org/review/pr-29.html. + {"", "\u0b47\u0300\u0b3e", "\u0b47\u0300\u0b3e"}, + {"", "\u1100\u0300\u1161", "\u1100\u0300\u1161"}, + {"", "\u0b47\u0b3e", "\u0b4b"}, + {"", "\u1100\u1161", "\uac00"}, + + // U+04DA MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; + { // 0d4a starts a new segment. + "", + "\u0d4a" + strings.Repeat("\u0d3e", 15) + "\u0d4a" + strings.Repeat("\u0d3e", 15), + "\u0d4a" + strings.Repeat("\u0d3e", 15) + "\u0d4a" + strings.Repeat("\u0d3e", 15), + }, + + { // Split combining characters. + // TODO: don't insert CGJ before starters. + "", + "\u0d46" + strings.Repeat("\u0d3e", 31), + "\u0d4a" + strings.Repeat("\u0d3e", 29) + cgj + "\u0d3e", + }, + + { // Split combining characters. + "", + "\u0d4a" + strings.Repeat("\u0d3e", 30), + "\u0d4a" + strings.Repeat("\u0d3e", 29) + cgj + "\u0d3e", + }, + + { // https://golang.org/issues/20079 + "", + "\xeb\u0344", + "\xeb\u0308\u0301", + }, + + { // https://golang.org/issues/20079 + "", + "\uac00" + strings.Repeat("\u0300", 30), + "\uac00" + strings.Repeat("\u0300", 29) + "\u034f\u0300", + }, + + { // https://golang.org/issues/20079 + "", + "\xeb" + strings.Repeat("\u0300", 31), + "\xeb" + strings.Repeat("\u0300", 30) + "\u034f\u0300", + }, +} + +var appendTestsNFD = []AppendTest{ + // TODO: Move some of the tests here. +} + +var appendTestsNFKC = []AppendTest{ + // empty buffers + {"", "", ""}, + {"a", "", "a"}, + {"", "a", "a"}, + {"", "\u0041\u0307\u0304", "\u01E0"}, + // segment split across buffers + {"", "a\u0300b", "\u00E0b"}, + {"a", "\u0300b", "\u00E0b"}, + {"a", "\u0300\u0316", "\u00E0\u0316"}, + {"a", "\u0316\u0300", "\u00E0\u0316"}, + {"a", "\u0300a\u0300", "\u00E0\u00E0"}, + {"a", "\u0300a\u0300a\u0300", "\u00E0\u00E0\u00E0"}, + {"a", "\u0300aaa\u0300aaa\u0300", "\u00E0aa\u00E0aa\u00E0"}, + {"a\u0300", "\u0327", "\u00E0\u0327"}, + {"a\u0327", "\u0300", "\u00E0\u0327"}, + {"a\u0316", "\u0300", "\u00E0\u0316"}, + {"\u0041\u0307", "\u0304", "\u01E0"}, + // Hangul + {"", "\u110B\u1173", "\uC73C"}, + {"", "\u1103\u1161", "\uB2E4"}, + {"", "\u110B\u1173\u11B7", "\uC74C"}, + {"", "\u320E", "\x28\uAC00\x29"}, + {"", "\x28\u1100\u1161\x29", "\x28\uAC00\x29"}, + {"\u1103", "\u1161", "\uB2E4"}, + {"\u110B", "\u1173\u11B7", "\uC74C"}, + {"\u110B\u1173", "\u11B7", "\uC74C"}, + {"\uC73C", "\u11B7", "\uC74C"}, + // UTF-8 encoding split across buffers + {"a\xCC", "\x80", "\u00E0"}, + {"a\xCC", "\x80b", "\u00E0b"}, + {"a\xCC", "\x80a\u0300", "\u00E0\u00E0"}, + {"a\xCC", "\x80\x80", "\u00E0\x80"}, + {"a\xCC", "\x80\xCC", "\u00E0\xCC"}, + {"a\u0316\xCC", "\x80a\u0316\u0300", "\u00E0\u0316\u00E0\u0316"}, + // ending in incomplete UTF-8 encoding + {"", "\xCC", "\xCC"}, + {"a", "\xCC", "a\xCC"}, + {"a", "b\xCC", "ab\xCC"}, + {"\u0226", "\xCC", "\u0226\xCC"}, + // illegal runes + {"", "\x80", "\x80"}, + {"", "\x80\x80\x80", "\x80\x80\x80"}, + {"", "\xCC\x80\x80\x80", "\xCC\x80\x80\x80"}, + {"", "a\x80", "a\x80"}, + {"", "a\x80\x80\x80", "a\x80\x80\x80"}, + {"", "a\x80\x80\x80\x80\x80\x80", "a\x80\x80\x80\x80\x80\x80"}, + {"a", "\x80\x80\x80", "a\x80\x80\x80"}, + // overflow + {"", strings.Repeat("\x80", 33), strings.Repeat("\x80", 33)}, + {strings.Repeat("\x80", 33), "", strings.Repeat("\x80", 33)}, + {strings.Repeat("\x80", 33), strings.Repeat("\x80", 33), strings.Repeat("\x80", 66)}, + // overflow of combining characters + {"", grave(34), grave(30) + cgj + grave(4)}, + {"", grave(36), grave(30) + cgj + grave(6)}, + {grave(29), grave(5), grave(30) + cgj + grave(4)}, + {grave(30), grave(4), grave(30) + cgj + grave(4)}, + {grave(30), grave(3), grave(30) + cgj + grave(3)}, + {grave(30) + "\xCC", "\x80", grave(30) + cgj + grave(1)}, + {"", "\uFDFA" + grave(14), "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645" + grave(14)}, + {"", "\uFDFA" + grave(28) + "\u0316", "\u0635\u0644\u0649 \u0627\u0644\u0644\u0647 \u0639\u0644\u064a\u0647 \u0648\u0633\u0644\u0645\u0316" + grave(28)}, + // - First rune has a trailing non-starter. + {"\u00d5", grave(30), "\u00d5" + grave(29) + cgj + grave(1)}, + // - U+FF9E decomposes into a non-starter in compatibility mode. A CGJ must be + // inserted even when FF9E starts a new segment. + {"\uff9e", grave(30), "\u3099" + grave(29) + cgj + grave(1)}, + {grave(30), "\uff9e", grave(30) + cgj + "\u3099"}, + // - Many non-starter decompositions in a row causing overflow. + {"", rep(0x340, 31), rep(0x300, 30) + cgj + "\u0300"}, + {"", rep(0xFF9E, 31), rep(0x3099, 30) + cgj + "\u3099"}, + + {"", "\u0644\u0625" + rep(0x300, 31), "\u0644\u0625" + rep(0x300, 29) + cgj + "\u0300\u0300"}, + {"", "\ufef9" + rep(0x300, 31), "\u0644\u0625" + rep(0x300, 29) + cgj + rep(0x0300, 2)}, + {"", "\ufef9" + rep(0x300, 31), "\u0644\u0625" + rep(0x300, 29) + cgj + rep(0x0300, 2)}, + + // U+0F81 TIBETAN VOWEL SIGN REVERSED II splits into two modifiers. + {"", "\u0f7f" + rep(0xf71, 29) + "\u0f81", "\u0f7f" + rep(0xf71, 29) + cgj + "\u0f71\u0f80"}, + {"", "\u0f7f" + rep(0xf71, 28) + "\u0f81", "\u0f7f" + rep(0xf71, 29) + "\u0f80"}, + {"", "\u0f7f" + rep(0xf81, 16), "\u0f7f" + rep(0xf71, 15) + rep(0xf80, 15) + cgj + "\u0f71\u0f80"}, + + // weird UTF-8 + {"\u00E0\xE1", "\x86", "\u00E0\xE1\x86"}, + {"a\u0300\u11B7", "\u0300", "\u00E0\u11B7\u0300"}, + {"a\u0300\u11B7\u0300", "\u0300", "\u00E0\u11B7\u0300\u0300"}, + {"\u0300", "\xF8\x80\x80\x80\x80\u0300", "\u0300\xF8\x80\x80\x80\x80\u0300"}, + {"\u0300", "\xFC\x80\x80\x80\x80\x80\u0300", "\u0300\xFC\x80\x80\x80\x80\x80\u0300"}, + {"\xF8\x80\x80\x80\x80\u0300", "\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"}, + {"\xFC\x80\x80\x80\x80\x80\u0300", "\u0300", "\xFC\x80\x80\x80\x80\x80\u0300\u0300"}, + {"\xF8\x80\x80\x80", "\x80\u0300\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"}, + + {"", strings.Repeat("a\u0316\u0300", 6), strings.Repeat("\u00E0\u0316", 6)}, + // large input. + {"", strings.Repeat("a\u0300\u0316", 31), strings.Repeat("\u00E0\u0316", 31)}, + {"", strings.Repeat("a\u0300\u0316", 4000), strings.Repeat("\u00E0\u0316", 4000)}, + {"", strings.Repeat("\x80\x80", 4000), strings.Repeat("\x80\x80", 4000)}, + {"", "\u0041\u0307\u0304", "\u01E0"}, +} + +var appendTestsNFKD = []AppendTest{ + {"", "a" + grave(64), "a" + grave(30) + cgj + grave(30) + cgj + grave(4)}, + + { // segment overflow on unchanged character + "", + "a" + grave(64) + "\u0316", + "a" + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(4), + }, + { // segment overflow on unchanged character + start value + "", + "a" + grave(98) + "\u0316", + "a" + grave(30) + cgj + grave(30) + cgj + grave(30) + cgj + "\u0316" + grave(8), + }, + { // segment overflow on decomposition. (U+0340 decomposes to U+0300.) + "", + "a" + grave(59) + "\u0340", + "a" + grave(30) + cgj + grave(30), + }, + { // segment overflow on non-starter decomposition + "", + "a" + grave(33) + "\u0340" + grave(30) + "\u0320", + "a" + grave(30) + cgj + grave(30) + cgj + "\u0320" + grave(4), + }, + { // start value after ASCII overflow + "", + rep('a', segSize) + grave(32) + "\u0320", + rep('a', segSize) + grave(30) + cgj + "\u0320" + grave(2), + }, + { // Jamo overflow + "", + "\u1100\u1161" + grave(30) + "\u0320" + grave(2), + "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul + "", + "\uac00", + "\u1100\u1161", + }, + { // Hangul overflow + "", + "\uac00" + grave(32) + "\u0320", + "\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul overflow in Hangul mode. + "", + "\uac00\uac00" + grave(32) + "\u0320", + "\u1100\u1161\u1100\u1161" + grave(29) + cgj + "\u0320" + grave(3), + }, + { // Hangul overflow in Hangul mode. + "", + strings.Repeat("\uac00", 3) + grave(32) + "\u0320", + strings.Repeat("\u1100\u1161", 3) + grave(29) + cgj + "\u0320" + grave(3), + }, + { // start value after cc=0 + "", + "您您" + grave(34) + "\u0320", + "您您" + grave(30) + cgj + "\u0320" + grave(4), + }, + { // start value after normalization + "", + "\u0300\u0320a" + grave(34) + "\u0320", + "\u0320\u0300a" + grave(30) + cgj + "\u0320" + grave(4), + }, + { + // U+0F81 TIBETAN VOWEL SIGN REVERSED II splits into two modifiers. + "", + "a\u0f7f" + rep(0xf71, 29) + "\u0f81", + "a\u0f7f" + rep(0xf71, 29) + cgj + "\u0f71\u0f80", + }, +} + +func TestAppend(t *testing.T) { + runNormTests(t, "Append", func(f Form, out []byte, s string) []byte { + return f.Append(out, []byte(s)...) + }) +} + +func TestAppendString(t *testing.T) { + runNormTests(t, "AppendString", func(f Form, out []byte, s string) []byte { + return f.AppendString(out, s) + }) +} + +func TestBytes(t *testing.T) { + runNormTests(t, "Bytes", func(f Form, out []byte, s string) []byte { + buf := []byte{} + buf = append(buf, out...) + buf = append(buf, s...) + return f.Bytes(buf) + }) +} + +func TestString(t *testing.T) { + runNormTests(t, "String", func(f Form, out []byte, s string) []byte { + outs := string(out) + s + return []byte(f.String(outs)) + }) +} + +func TestLinking(t *testing.T) { + const prog = ` + package main + import "fmt" + import "golang.org/x/text/unicode/norm" + func main() { fmt.Println(norm.%s) } + ` + baseline, errB := testtext.CodeSize(fmt.Sprintf(prog, "MaxSegmentSize")) + withTables, errT := testtext.CodeSize(fmt.Sprintf(prog, `NFC.String("")`)) + if errB != nil || errT != nil { + t.Skipf("code size failed: %v and %v", errB, errT) + } + // Tables are at least 50K + if d := withTables - baseline; d < 50*1024 { + t.Errorf("tables appear not to be dropped: %d - %d = %d", + withTables, baseline, d) + } +} + +func appendBench(f Form, in []byte) func() { + buf := make([]byte, 0, 4*len(in)) + return func() { + f.Append(buf, in...) + } +} + +func bytesBench(f Form, in []byte) func() { + return func() { + f.Bytes(in) + } +} + +func iterBench(f Form, in []byte) func() { + iter := Iter{} + return func() { + iter.Init(f, in) + for !iter.Done() { + iter.Next() + } + } +} + +func transformBench(f Form, in []byte) func() { + buf := make([]byte, 4*len(in)) + return func() { + if _, n, err := f.Transform(buf, in, true); err != nil || len(in) != n { + log.Panic(n, len(in), err) + } + } +} + +func readerBench(f Form, in []byte) func() { + buf := make([]byte, 4*len(in)) + return func() { + r := f.Reader(bytes.NewReader(in)) + var err error + for err == nil { + _, err = r.Read(buf) + } + if err != io.EOF { + panic("") + } + } +} + +func writerBench(f Form, in []byte) func() { + buf := make([]byte, 0, 4*len(in)) + return func() { + r := f.Writer(bytes.NewBuffer(buf)) + if _, err := r.Write(in); err != nil { + panic("") + } + } +} + +func appendBenchmarks(bm []func(), f Form, in []byte) []func() { + bm = append(bm, appendBench(f, in)) + bm = append(bm, iterBench(f, in)) + bm = append(bm, transformBench(f, in)) + bm = append(bm, readerBench(f, in)) + bm = append(bm, writerBench(f, in)) + return bm +} + +func doFormBenchmark(b *testing.B, inf, f Form, s string) { + b.StopTimer() + in := inf.Bytes([]byte(s)) + bm := appendBenchmarks(nil, f, in) + b.SetBytes(int64(len(in) * len(bm))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for _, fn := range bm { + fn() + } + } +} + +func doSingle(b *testing.B, f func(Form, []byte) func(), s []byte) { + b.StopTimer() + fn := f(NFC, s) + b.SetBytes(int64(len(s))) + b.StartTimer() + for i := 0; i < b.N; i++ { + fn() + } +} + +var ( + smallNoChange = []byte("nörmalization") + smallChange = []byte("No\u0308rmalization") + ascii = strings.Repeat("There is nothing to change here! ", 500) +) + +func lowerBench(f Form, in []byte) func() { + // Use package strings instead of bytes as it doesn't allocate memory + // if there aren't any changes. + s := string(in) + return func() { + strings.ToLower(s) + } +} + +func BenchmarkLowerCaseNoChange(b *testing.B) { + doSingle(b, lowerBench, smallNoChange) +} +func BenchmarkLowerCaseChange(b *testing.B) { + doSingle(b, lowerBench, smallChange) +} + +func quickSpanBench(f Form, in []byte) func() { + return func() { + f.QuickSpan(in) + } +} + +func BenchmarkQuickSpanChangeNFC(b *testing.B) { + doSingle(b, quickSpanBench, smallNoChange) +} + +func BenchmarkBytesNoChangeNFC(b *testing.B) { + doSingle(b, bytesBench, smallNoChange) +} +func BenchmarkBytesChangeNFC(b *testing.B) { + doSingle(b, bytesBench, smallChange) +} + +func BenchmarkAppendNoChangeNFC(b *testing.B) { + doSingle(b, appendBench, smallNoChange) +} +func BenchmarkAppendChangeNFC(b *testing.B) { + doSingle(b, appendBench, smallChange) +} +func BenchmarkAppendLargeNFC(b *testing.B) { + doSingle(b, appendBench, txt_all_bytes) +} + +func BenchmarkIterNoChangeNFC(b *testing.B) { + doSingle(b, iterBench, smallNoChange) +} +func BenchmarkIterChangeNFC(b *testing.B) { + doSingle(b, iterBench, smallChange) +} +func BenchmarkIterLargeNFC(b *testing.B) { + doSingle(b, iterBench, txt_all_bytes) +} + +func BenchmarkTransformNoChangeNFC(b *testing.B) { + doSingle(b, transformBench, smallNoChange) +} +func BenchmarkTransformChangeNFC(b *testing.B) { + doSingle(b, transformBench, smallChange) +} +func BenchmarkTransformLargeNFC(b *testing.B) { + doSingle(b, transformBench, txt_all_bytes) +} + +func BenchmarkNormalizeAsciiNFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, ascii) +} +func BenchmarkNormalizeAsciiNFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, ascii) +} +func BenchmarkNormalizeAsciiNFKC(b *testing.B) { + doFormBenchmark(b, NFC, NFKC, ascii) +} +func BenchmarkNormalizeAsciiNFKD(b *testing.B) { + doFormBenchmark(b, NFC, NFKD, ascii) +} + +func BenchmarkNormalizeNFC2NFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, txt_all) +} +func BenchmarkNormalizeNFC2NFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, txt_all) +} +func BenchmarkNormalizeNFD2NFC(b *testing.B) { + doFormBenchmark(b, NFD, NFC, txt_all) +} +func BenchmarkNormalizeNFD2NFD(b *testing.B) { + doFormBenchmark(b, NFD, NFD, txt_all) +} + +// Hangul is often special-cased, so we test it separately. +func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) { + doFormBenchmark(b, NFC, NFC, txt_kr) +} +func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) { + doFormBenchmark(b, NFC, NFD, txt_kr) +} +func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) { + doFormBenchmark(b, NFD, NFC, txt_kr) +} +func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) { + doFormBenchmark(b, NFD, NFD, txt_kr) +} + +var forms = []Form{NFC, NFD, NFKC, NFKD} + +func doTextBenchmark(b *testing.B, s string) { + b.StopTimer() + in := []byte(s) + bm := []func(){} + for _, f := range forms { + bm = appendBenchmarks(bm, f, in) + } + b.SetBytes(int64(len(s) * len(bm))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for _, f := range bm { + f() + } + } +} + +func BenchmarkCanonicalOrdering(b *testing.B) { + doTextBenchmark(b, txt_canon) +} +func BenchmarkExtendedLatin(b *testing.B) { + doTextBenchmark(b, txt_vn) +} +func BenchmarkMiscTwoByteUtf8(b *testing.B) { + doTextBenchmark(b, twoByteUtf8) +} +func BenchmarkMiscThreeByteUtf8(b *testing.B) { + doTextBenchmark(b, threeByteUtf8) +} +func BenchmarkHangul(b *testing.B) { + doTextBenchmark(b, txt_kr) +} +func BenchmarkJapanese(b *testing.B) { + doTextBenchmark(b, txt_jp) +} +func BenchmarkChinese(b *testing.B) { + doTextBenchmark(b, txt_cn) +} +func BenchmarkOverflow(b *testing.B) { + doTextBenchmark(b, overflow) +} + +var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B" + +// Tests sampled from the Canonical ordering tests (Part 2) of +// http://unicode.org/Public/UNIDATA/NormalizationTest.txt +const txt_canon = `\u0061\u0315\u0300\u05AE\u0300\u0062 \u0061\u0300\u0315\u0300\u05AE\u0062 +\u0061\u0302\u0315\u0300\u05AE\u0062 \u0061\u0307\u0315\u0300\u05AE\u0062 +\u0061\u0315\u0300\u05AE\u030A\u0062 \u0061\u059A\u0316\u302A\u031C\u0062 +\u0061\u032E\u059A\u0316\u302A\u0062 \u0061\u0338\u093C\u0334\u0062 +\u0061\u059A\u0316\u302A\u0339 \u0061\u0341\u0315\u0300\u05AE\u0062 +\u0061\u0348\u059A\u0316\u302A\u0062 \u0061\u0361\u0345\u035D\u035C\u0062 +\u0061\u0366\u0315\u0300\u05AE\u0062 \u0061\u0315\u0300\u05AE\u0486\u0062 +\u0061\u05A4\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0613\u0062 +\u0061\u0315\u0300\u05AE\u0615\u0062 \u0061\u0617\u0315\u0300\u05AE\u0062 +\u0061\u0619\u0618\u064D\u064E\u0062 \u0061\u0315\u0300\u05AE\u0654\u0062 +\u0061\u0315\u0300\u05AE\u06DC\u0062 \u0061\u0733\u0315\u0300\u05AE\u0062 +\u0061\u0744\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0745\u0062 +\u0061\u09CD\u05B0\u094D\u3099\u0062 \u0061\u0E38\u0E48\u0E38\u0C56\u0062 +\u0061\u0EB8\u0E48\u0E38\u0E49\u0062 \u0061\u0F72\u0F71\u0EC8\u0F71\u0062 +\u0061\u1039\u05B0\u094D\u3099\u0062 \u0061\u05B0\u094D\u3099\u1A60\u0062 +\u0061\u3099\u093C\u0334\u1BE6\u0062 \u0061\u3099\u093C\u0334\u1C37\u0062 +\u0061\u1CD9\u059A\u0316\u302A\u0062 \u0061\u2DED\u0315\u0300\u05AE\u0062 +\u0061\u2DEF\u0315\u0300\u05AE\u0062 \u0061\u302D\u302E\u059A\u0316\u0062` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/ +const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả. +Nếu bạn sử dụng, chuyển đổi, hoặc xây dựng dự án từ +nội dung được chia sẻ này, bạn phải áp dụng giấy phép này hoặc +một giấy phép khác có các điều khoản tương tự như giấy phép này +cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào +trên đây cũng có thể được miễn bỏ nếu bạn được sự cho phép của +người sở hữu bản quyền. Phạm vi công chúng — Khi tác phẩm hoặc +bất kỳ chương nào của tác phẩm đã trong vùng dành cho công +chúng theo quy định của pháp luật thì tình trạng của nó không +bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.` + +// Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru +const txt_ru = `При обязательном соблюдении следующих условий: +Attribution — Вы должны атрибутировать произведение (указывать +автора и источник) в порядке, предусмотренном автором или +лицензиаром (но только так, чтобы никоим образом не подразумевалось, +что они поддерживают вас или использование вами данного произведения). +Υπό τις ακόλουθες προϋποθέσεις:` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/ +const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με τον +τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια +(χωρίς όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή +τη χρήση του έργου από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε, +τροποποιήσετε ή δημιουργήσετε περαιτέρω βασισμένοι στο έργο θα +μπορείτε να διανέμετε το έργο που θα προκύψει μόνο με την ίδια ή +παρόμοια άδεια.` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/deed.ar +const txt_ar = `بموجب الشروط التالية نسب المصنف — يجب عليك أن +تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من +الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل). +المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة +من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد +لهذا الترخيص.` + +// Taken from http://creativecommons.org/licenses/by-sa/1.0/il/ +const txt_il = `בכפוף לתנאים הבאים: ייחוס — עליך לייחס את היצירה (לתת קרדיט) באופן +המצויין על-ידי היוצר או מעניק הרישיון (אך לא בשום אופן המרמז על כך +שהם תומכים בך או בשימוש שלך ביצירה). שיתוף זהה — אם תחליט/י לשנות, +לעבד או ליצור יצירה נגזרת בהסתמך על יצירה זו, תוכל/י להפיץ את יצירתך +החדשה רק תחת אותו הרישיון או רישיון דומה לרישיון זה.` + +const twoByteUtf8 = txt_ru + txt_gr + txt_ar + txt_il + +// Taken from http://creativecommons.org/licenses/by-sa/2.0/kr/ +const txt_kr = `다음과 같은 조건을 따라야 합니다: 저작자표시 +(Attribution) — 저작자나 이용허락자가 정한 방법으로 저작물의 +원저작자를 표시하여야 합니다(그러나 원저작자가 이용자나 이용자의 +이용을 보증하거나 추천한다는 의미로 표시해서는 안됩니다). +동일조건변경허락 — 이 저작물을 이용하여 만든 이차적 저작물에는 본 +라이선스와 동일한 라이선스를 적용해야 합니다.` + +// Taken from http://creativecommons.org/licenses/by-sa/3.0/th/ +const txt_th = `ภายใต้เงื่อนไข ดังต่อไปนี้ : แสดงที่มา — คุณต้องแสดงที่ +มาของงานดังกล่าว ตามรูปแบบที่ผู้สร้างสรรค์หรือผู้อนุญาตกำหนด (แต่ +ไม่ใช่ในลักษณะที่ว่า พวกเขาสนับสนุนคุณหรือสนับสนุนการที่ +คุณนำงานไปใช้) อนุญาตแบบเดียวกัน — หากคุณดัดแปลง เปลี่ยนรูป หรื +อต่อเติมงานนี้ คุณต้องใช้สัญญาอนุญาตแบบเดียวกันหรือแบบที่เหมื +อนกับสัญญาอนุญาตที่ใช้กับงานนี้เท่านั้น` + +const threeByteUtf8 = txt_th + +// Taken from http://creativecommons.org/licenses/by-sa/2.0/jp/ +const txt_jp = `あなたの従うべき条件は以下の通りです。 +表示 — あなたは原著作者のクレジットを表示しなければなりません。 +継承 — もしあなたがこの作品を改変、変形または加工した場合、 +あなたはその結果生じた作品をこの作品と同一の許諾条件の下でのみ +頒布することができます。` + +// http://creativecommons.org/licenses/by-sa/2.5/cn/ +const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、 +广播或通过信息网络传播本作品 创作演绎作品 +对本作品进行商业性使用 惟须遵守下列条件: +署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。 +相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作, +您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。` + +const txt_cjk = txt_cn + txt_jp + txt_kr +const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk + +var txt_all_bytes = []byte(txt_all) diff --git a/vendor/golang.org/x/text/unicode/norm/readwriter_test.go b/vendor/golang.org/x/text/unicode/norm/readwriter_test.go new file mode 100644 index 000000000..b7756ba24 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/readwriter_test.go @@ -0,0 +1,56 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bytes" + "fmt" + "testing" +) + +var bufSizes = []int{1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 102, 103, 4000, 4001, 4002, 4003} + +func readFunc(size int) appendFunc { + return func(f Form, out []byte, s string) []byte { + out = append(out, s...) + r := f.Reader(bytes.NewBuffer(out)) + buf := make([]byte, size) + result := []byte{} + for n, err := 0, error(nil); err == nil; { + n, err = r.Read(buf) + result = append(result, buf[:n]...) + } + return result + } +} + +func TestReader(t *testing.T) { + for _, s := range bufSizes { + name := fmt.Sprintf("TestReader%d", s) + runNormTests(t, name, readFunc(s)) + } +} + +func writeFunc(size int) appendFunc { + return func(f Form, out []byte, s string) []byte { + in := append(out, s...) + result := new(bytes.Buffer) + w := f.Writer(result) + buf := make([]byte, size) + for n := 0; len(in) > 0; in = in[n:] { + n = copy(buf, in) + _, _ = w.Write(buf[:n]) + } + w.Close() + return result.Bytes() + } +} + +func TestWriter(t *testing.T) { + for _, s := range bufSizes { + name := fmt.Sprintf("TestWriter%d", s) + runNormTests(t, name, writeFunc(s)) + } +} diff --git a/vendor/golang.org/x/text/unicode/norm/transform_test.go b/vendor/golang.org/x/text/unicode/norm/transform_test.go new file mode 100644 index 000000000..d596ff3d8 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/transform_test.go @@ -0,0 +1,101 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "fmt" + "testing" + + "golang.org/x/text/transform" +) + +func TestTransform(t *testing.T) { + tests := []struct { + f Form + in, out string + eof bool + dstSize int + err error + }{ + {NFC, "ab", "ab", true, 2, nil}, + {NFC, "qx", "qx", true, 2, nil}, + {NFD, "qx", "qx", true, 2, nil}, + {NFC, "", "", true, 1, nil}, + {NFD, "", "", true, 1, nil}, + {NFC, "", "", false, 1, nil}, + {NFD, "", "", false, 1, nil}, + + // Normalized segment does not fit in destination. + {NFD, "ö", "", true, 1, transform.ErrShortDst}, + {NFD, "ö", "", true, 2, transform.ErrShortDst}, + + // As an artifact of the algorithm, only full segments are written. + // This is not strictly required, and some bytes could be written. + // In practice, for Transform to not block, the destination buffer + // should be at least MaxSegmentSize to work anyway and these edge + // conditions will be relatively rare. + {NFC, "ab", "", true, 1, transform.ErrShortDst}, + // This is even true for inert runes. + {NFC, "qx", "", true, 1, transform.ErrShortDst}, + {NFC, "a\u0300abc", "\u00e0a", true, 4, transform.ErrShortDst}, + + // We cannot write a segment if successive runes could still change the result. + {NFD, "ö", "", false, 3, transform.ErrShortSrc}, + {NFC, "a\u0300", "", false, 4, transform.ErrShortSrc}, + {NFD, "a\u0300", "", false, 4, transform.ErrShortSrc}, + {NFC, "ö", "", false, 3, transform.ErrShortSrc}, + + {NFC, "a\u0300", "", true, 1, transform.ErrShortDst}, + // Theoretically could fit, but won't due to simplified checks. + {NFC, "a\u0300", "", true, 2, transform.ErrShortDst}, + {NFC, "a\u0300", "", true, 3, transform.ErrShortDst}, + {NFC, "a\u0300", "\u00e0", true, 4, nil}, + + {NFD, "öa\u0300", "o\u0308", false, 8, transform.ErrShortSrc}, + {NFD, "öa\u0300ö", "o\u0308a\u0300", true, 8, transform.ErrShortDst}, + {NFD, "öa\u0300ö", "o\u0308a\u0300", false, 12, transform.ErrShortSrc}, + + // Illegal input is copied verbatim. + {NFD, "\xbd\xb2=\xbc ", "\xbd\xb2=\xbc ", true, 8, nil}, + } + b := make([]byte, 100) + for i, tt := range tests { + nDst, _, err := tt.f.Transform(b[:tt.dstSize], []byte(tt.in), tt.eof) + out := string(b[:nDst]) + if out != tt.out || err != tt.err { + t.Errorf("%d: was %+q (%v); want %+q (%v)", i, out, err, tt.out, tt.err) + } + if want := tt.f.String(tt.in)[:nDst]; want != out { + t.Errorf("%d: incorrect normalization: was %+q; want %+q", i, out, want) + } + } +} + +var transBufSizes = []int{ + MaxTransformChunkSize, + 3 * MaxTransformChunkSize / 2, + 2 * MaxTransformChunkSize, + 3 * MaxTransformChunkSize, + 100 * MaxTransformChunkSize, +} + +func doTransNorm(f Form, buf []byte, b []byte) []byte { + acc := []byte{} + for p := 0; p < len(b); { + nd, ns, _ := f.Transform(buf[:], b[p:], true) + p += ns + acc = append(acc, buf[:nd]...) + } + return acc +} + +func TestTransformNorm(t *testing.T) { + for _, sz := range transBufSizes { + buf := make([]byte, sz) + runNormTests(t, fmt.Sprintf("Transform:%d", sz), func(f Form, out []byte, s string) []byte { + return doTransNorm(f, buf, append(out, s...)) + }) + } +} diff --git a/vendor/golang.org/x/text/unicode/norm/ucd_test.go b/vendor/golang.org/x/text/unicode/norm/ucd_test.go new file mode 100644 index 000000000..29205a6aa --- /dev/null +++ b/vendor/golang.org/x/text/unicode/norm/ucd_test.go @@ -0,0 +1,275 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package norm + +import ( + "bufio" + "bytes" + "fmt" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + "testing" + "time" + "unicode/utf8" + + "golang.org/x/text/internal/gen" + "golang.org/x/text/internal/testtext" +) + +var once sync.Once + +func skipShort(t *testing.T) { + testtext.SkipIfNotLong(t) + + once.Do(func() { loadTestData(t) }) +} + +// This regression test runs the test set in NormalizationTest.txt +// (taken from http://www.unicode.org/Public/<unicode.Version>/ucd/). +// +// NormalizationTest.txt has form: +// @Part0 # Specific cases +// # +// 1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE +// 1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW +// +// Each test has 5 columns (c1, c2, c3, c4, c5), where +// (c1, c2, c3, c4, c5) == (c1, NFC(c1), NFD(c1), NFKC(c1), NFKD(c1)) +// +// CONFORMANCE: +// 1. The following invariants must be true for all conformant implementations +// +// NFC +// c2 == NFC(c1) == NFC(c2) == NFC(c3) +// c4 == NFC(c4) == NFC(c5) +// +// NFD +// c3 == NFD(c1) == NFD(c2) == NFD(c3) +// c5 == NFD(c4) == NFD(c5) +// +// NFKC +// c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5) +// +// NFKD +// c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5) +// +// 2. For every code point X assigned in this version of Unicode that is not +// specifically listed in Part 1, the following invariants must be true +// for all conformant implementations: +// +// X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X) +// + +// Column types. +const ( + cRaw = iota + cNFC + cNFD + cNFKC + cNFKD + cMaxColumns +) + +// Holds data from NormalizationTest.txt +var part []Part + +type Part struct { + name string + number int + tests []Test +} + +type Test struct { + name string + partnr int + number int + r rune // used for character by character test + cols [cMaxColumns]string // Each has 5 entries, see below. +} + +func (t Test) Name() string { + if t.number < 0 { + return part[t.partnr].name + } + return fmt.Sprintf("%s:%d", part[t.partnr].name, t.number) +} + +var partRe = regexp.MustCompile(`@Part(\d) # (.*)$`) +var testRe = regexp.MustCompile(`^` + strings.Repeat(`([\dA-F ]+);`, 5) + ` # (.*)$`) + +var counter int + +// Load the data form NormalizationTest.txt +func loadTestData(t *testing.T) { + f := gen.OpenUCDFile("NormalizationTest.txt") + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + m := partRe.FindStringSubmatch(line) + if m != nil { + if len(m) < 3 { + t.Fatal("Failed to parse Part: ", line) + } + i, err := strconv.Atoi(m[1]) + if err != nil { + t.Fatal(err) + } + name := m[2] + part = append(part, Part{name: name[:len(name)-1], number: i}) + continue + } + m = testRe.FindStringSubmatch(line) + if m == nil || len(m) < 7 { + t.Fatalf(`Failed to parse: "%s" result: %#v`, line, m) + } + test := Test{name: m[6], partnr: len(part) - 1, number: counter} + counter++ + for j := 1; j < len(m)-1; j++ { + for _, split := range strings.Split(m[j], " ") { + r, err := strconv.ParseUint(split, 16, 64) + if err != nil { + t.Fatal(err) + } + if test.r == 0 { + // save for CharacterByCharacterTests + test.r = rune(r) + } + var buf [utf8.UTFMax]byte + sz := utf8.EncodeRune(buf[:], rune(r)) + test.cols[j-1] += string(buf[:sz]) + } + } + part := &part[len(part)-1] + part.tests = append(part.tests, test) + } + if scanner.Err() != nil { + t.Fatal(scanner.Err()) + } +} + +func cmpResult(t *testing.T, tc *Test, name string, f Form, gold, test, result string) { + if gold != result { + t.Errorf("%s:%s: %s(%+q)=%+q; want %+q: %s", + tc.Name(), name, fstr[f], test, result, gold, tc.name) + } +} + +func cmpIsNormal(t *testing.T, tc *Test, name string, f Form, test string, result, want bool) { + if result != want { + t.Errorf("%s:%s: %s(%+q)=%v; want %v", tc.Name(), name, fstr[f], test, result, want) + } +} + +func doTest(t *testing.T, tc *Test, f Form, gold, test string) { + testb := []byte(test) + result := f.Bytes(testb) + cmpResult(t, tc, "Bytes", f, gold, test, string(result)) + + sresult := f.String(test) + cmpResult(t, tc, "String", f, gold, test, sresult) + + acc := []byte{} + i := Iter{} + i.InitString(f, test) + for !i.Done() { + acc = append(acc, i.Next()...) + } + cmpResult(t, tc, "Iter.Next", f, gold, test, string(acc)) + + buf := make([]byte, 128) + acc = nil + for p := 0; p < len(testb); { + nDst, nSrc, _ := f.Transform(buf, testb[p:], true) + acc = append(acc, buf[:nDst]...) + p += nSrc + } + cmpResult(t, tc, "Transform", f, gold, test, string(acc)) + + for i := range test { + out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...) + cmpResult(t, tc, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out)) + } + cmpIsNormal(t, tc, "IsNormal", f, test, f.IsNormal([]byte(test)), test == gold) + cmpIsNormal(t, tc, "IsNormalString", f, test, f.IsNormalString(test), test == gold) +} + +func doConformanceTests(t *testing.T, tc *Test, partn int) { + for i := 0; i <= 2; i++ { + doTest(t, tc, NFC, tc.cols[1], tc.cols[i]) + doTest(t, tc, NFD, tc.cols[2], tc.cols[i]) + doTest(t, tc, NFKC, tc.cols[3], tc.cols[i]) + doTest(t, tc, NFKD, tc.cols[4], tc.cols[i]) + } + for i := 3; i <= 4; i++ { + doTest(t, tc, NFC, tc.cols[3], tc.cols[i]) + doTest(t, tc, NFD, tc.cols[4], tc.cols[i]) + doTest(t, tc, NFKC, tc.cols[3], tc.cols[i]) + doTest(t, tc, NFKD, tc.cols[4], tc.cols[i]) + } +} + +func TestCharacterByCharacter(t *testing.T) { + skipShort(t) + tests := part[1].tests + var last rune = 0 + for i := 0; i <= len(tests); i++ { // last one is special case + var r rune + if i == len(tests) { + r = 0x2FA1E // Don't have to go to 0x10FFFF + } else { + r = tests[i].r + } + for last++; last < r; last++ { + // Check all characters that were not explicitly listed in the test. + tc := &Test{partnr: 1, number: -1} + char := string(last) + doTest(t, tc, NFC, char, char) + doTest(t, tc, NFD, char, char) + doTest(t, tc, NFKC, char, char) + doTest(t, tc, NFKD, char, char) + } + if i < len(tests) { + doConformanceTests(t, &tests[i], 1) + } + } +} + +func TestStandardTests(t *testing.T) { + skipShort(t) + for _, j := range []int{0, 2, 3} { + for _, test := range part[j].tests { + doConformanceTests(t, &test, j) + } + } +} + +// TestPerformance verifies that normalization is O(n). If any of the +// code does not properly check for maxCombiningChars, normalization +// may exhibit O(n**2) behavior. +func TestPerformance(t *testing.T) { + skipShort(t) + runtime.GOMAXPROCS(2) + success := make(chan bool, 1) + go func() { + buf := bytes.Repeat([]byte("\u035D"), 1024*1024) + buf = append(buf, "\u035B"...) + NFC.Append(nil, buf...) + success <- true + }() + timeout := time.After(1 * time.Second) + select { + case <-success: + // test completed before the timeout + case <-timeout: + t.Errorf(`unexpectedly long time to complete PerformanceTest`) + } +} diff --git a/vendor/golang.org/x/text/unicode/rangetable/merge_test.go b/vendor/golang.org/x/text/unicode/rangetable/merge_test.go new file mode 100644 index 000000000..93ed0fcad --- /dev/null +++ b/vendor/golang.org/x/text/unicode/rangetable/merge_test.go @@ -0,0 +1,184 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rangetable + +import ( + "testing" + "unicode" +) + +var ( + maxRuneTable = &unicode.RangeTable{ + R32: []unicode.Range32{ + {unicode.MaxRune, unicode.MaxRune, 1}, + }, + } + + overlap1 = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x100, 0xfffc, 4}, + }, + R32: []unicode.Range32{ + {0x100000, 0x10fffc, 4}, + }, + } + + overlap2 = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x101, 0xfffd, 4}, + }, + R32: []unicode.Range32{ + {0x100001, 0x10fffd, 3}, + }, + } + + // The following table should be compacted into two entries for R16 and R32. + optimize = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x1, 0x1, 1}, + {0x2, 0x2, 1}, + {0x3, 0x3, 1}, + {0x5, 0x5, 1}, + {0x7, 0x7, 1}, + {0x9, 0x9, 1}, + {0xb, 0xf, 2}, + }, + R32: []unicode.Range32{ + {0x10001, 0x10001, 1}, + {0x10002, 0x10002, 1}, + {0x10003, 0x10003, 1}, + {0x10005, 0x10005, 1}, + {0x10007, 0x10007, 1}, + {0x10009, 0x10009, 1}, + {0x1000b, 0x1000f, 2}, + }, + } +) + +func TestMerge(t *testing.T) { + for i, tt := range [][]*unicode.RangeTable{ + {unicode.Cc, unicode.Cf}, + {unicode.L, unicode.Ll}, + {unicode.L, unicode.Ll, unicode.Lu}, + {unicode.Ll, unicode.Lu}, + {unicode.M}, + unicode.GraphicRanges, + cased, + + // Merge R16 only and R32 only and vice versa. + {unicode.Khmer, unicode.Khudawadi}, + {unicode.Imperial_Aramaic, unicode.Radical}, + + // Merge with empty. + {&unicode.RangeTable{}}, + {&unicode.RangeTable{}, &unicode.RangeTable{}}, + {&unicode.RangeTable{}, &unicode.RangeTable{}, &unicode.RangeTable{}}, + {&unicode.RangeTable{}, unicode.Hiragana}, + {unicode.Inherited, &unicode.RangeTable{}}, + {&unicode.RangeTable{}, unicode.Hanunoo, &unicode.RangeTable{}}, + + // Hypothetical tables. + {maxRuneTable}, + {overlap1, overlap2}, + + // Optimization + {optimize}, + } { + rt := Merge(tt...) + for r := rune(0); r <= unicode.MaxRune; r++ { + if got, want := unicode.Is(rt, r), unicode.In(r, tt...); got != want { + t.Fatalf("%d:%U: got %v; want %v", i, r, got, want) + } + } + // Test optimization and correctness for R16. + for k := 0; k < len(rt.R16)-1; k++ { + if lo, hi := rt.R16[k].Lo, rt.R16[k].Hi; lo > hi { + t.Errorf("%d: Lo (%x) > Hi (%x)", i, lo, hi) + } + if hi, lo := rt.R16[k].Hi, rt.R16[k+1].Lo; hi >= lo { + t.Errorf("%d: Hi (%x) >= next Lo (%x)", i, hi, lo) + } + if rt.R16[k].Hi+rt.R16[k].Stride == rt.R16[k+1].Lo { + t.Errorf("%d: missed optimization for R16 at %d between %X and %x", + i, k, rt.R16[k], rt.R16[k+1]) + } + } + // Test optimization and correctness for R32. + for k := 0; k < len(rt.R32)-1; k++ { + if lo, hi := rt.R32[k].Lo, rt.R32[k].Hi; lo > hi { + t.Errorf("%d: Lo (%x) > Hi (%x)", i, lo, hi) + } + if hi, lo := rt.R32[k].Hi, rt.R32[k+1].Lo; hi >= lo { + t.Errorf("%d: Hi (%x) >= next Lo (%x)", i, hi, lo) + } + if rt.R32[k].Hi+rt.R32[k].Stride == rt.R32[k+1].Lo { + t.Errorf("%d: missed optimization for R32 at %d between %X and %X", + i, k, rt.R32[k], rt.R32[k+1]) + } + } + } +} + +const runes = "Hello World in 2015!,\U0010fffd" + +func BenchmarkNotMerged(t *testing.B) { + for i := 0; i < t.N; i++ { + for _, r := range runes { + unicode.In(r, unicode.GraphicRanges...) + } + } +} + +func BenchmarkMerged(t *testing.B) { + rt := Merge(unicode.GraphicRanges...) + + for i := 0; i < t.N; i++ { + for _, r := range runes { + unicode.Is(rt, r) + } + } +} + +var cased = []*unicode.RangeTable{ + unicode.Lower, + unicode.Upper, + unicode.Title, + unicode.Other_Lowercase, + unicode.Other_Uppercase, +} + +func BenchmarkNotMergedCased(t *testing.B) { + for i := 0; i < t.N; i++ { + for _, r := range runes { + unicode.In(r, cased...) + } + } +} + +func BenchmarkMergedCased(t *testing.B) { + // This reduces len(R16) from 243 to 82 and len(R32) from 65 to 35 for + // Unicode 7.0.0. + rt := Merge(cased...) + + for i := 0; i < t.N; i++ { + for _, r := range runes { + unicode.Is(rt, r) + } + } +} + +func BenchmarkInit(t *testing.B) { + for i := 0; i < t.N; i++ { + Merge(cased...) + Merge(unicode.GraphicRanges...) + } +} + +func BenchmarkInit2(t *testing.B) { + // Hypothetical near-worst-case performance. + for i := 0; i < t.N; i++ { + Merge(overlap1, overlap2) + } +} diff --git a/vendor/golang.org/x/text/unicode/rangetable/rangetable_test.go b/vendor/golang.org/x/text/unicode/rangetable/rangetable_test.go new file mode 100644 index 000000000..5a355aa35 --- /dev/null +++ b/vendor/golang.org/x/text/unicode/rangetable/rangetable_test.go @@ -0,0 +1,55 @@ +package rangetable + +import ( + "reflect" + "testing" + "unicode" +) + +var ( + empty = &unicode.RangeTable{} + many = &unicode.RangeTable{ + R16: []unicode.Range16{{0, 0xffff, 5}}, + R32: []unicode.Range32{{0x10004, 0x10009, 5}}, + LatinOffset: 0, + } +) + +func TestVisit(t *testing.T) { + Visit(empty, func(got rune) { + t.Error("call from empty RangeTable") + }) + + var want rune + Visit(many, func(got rune) { + if got != want { + t.Errorf("got %U; want %U", got, want) + } + want += 5 + }) + if want -= 5; want != 0x10009 { + t.Errorf("last run was %U; want U+10009", want) + } +} + +func TestNew(t *testing.T) { + for i, rt := range []*unicode.RangeTable{ + empty, + unicode.Co, + unicode.Letter, + unicode.ASCII_Hex_Digit, + many, + maxRuneTable, + } { + var got, want []rune + Visit(rt, func(r rune) { + want = append(want, r) + }) + Visit(New(want...), func(r rune) { + got = append(got, r) + }) + if !reflect.DeepEqual(got, want) { + t.Errorf("%d:\ngot %v;\nwant %v", i, got, want) + } + } +} diff --git a/vendor/golang.org/x/text/width/common_test.go b/vendor/golang.org/x/text/width/common_test.go new file mode 100644 index 000000000..9ebb782c0 --- /dev/null +++ b/vendor/golang.org/x/text/width/common_test.go @@ -0,0 +1,92 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package width + +// This code is shared between the main code generator and the test code. + +import ( + "flag" + "log" + "strconv" + "strings" + + "golang.org/x/text/internal/gen" + "golang.org/x/text/internal/ucd" +) + +var ( + outputFile = flag.String("out", "tables.go", "output file") +) + +var typeMap = map[string]elem{ + "A": tagAmbiguous, + "N": tagNeutral, + "Na": tagNarrow, + "W": tagWide, + "F": tagFullwidth, + "H": tagHalfwidth, +} + +// getWidthData calls f for every entry for which it is defined. +// +// f may be called multiple times for the same rune. The last call to f is the +// correct value. f is not called for all runes. The default tag type is +// Neutral. +func getWidthData(f func(r rune, tag elem, alt rune)) { + // Set the default values for Unified Ideographs. In line with Annex 11, + // we encode full ranges instead of the defined runes in Unified_Ideograph. + for _, b := range []struct{ lo, hi rune }{ + {0x4E00, 0x9FFF}, // the CJK Unified Ideographs block, + {0x3400, 0x4DBF}, // the CJK Unified Ideographs Externsion A block, + {0xF900, 0xFAFF}, // the CJK Compatibility Ideographs block, + {0x20000, 0x2FFFF}, // the Supplementary Ideographic Plane, + {0x30000, 0x3FFFF}, // the Tertiary Ideographic Plane, + } { + for r := b.lo; r <= b.hi; r++ { + f(r, tagWide, 0) + } + } + + inverse := map[rune]rune{} + maps := map[string]bool{ + "<wide>": true, + "<narrow>": true, + } + + // We cannot reuse package norm's decomposition, as we need an unexpanded + // decomposition. We make use of the opportunity to verify that the + // decomposition type is as expected. + ucd.Parse(gen.OpenUCDFile("UnicodeData.txt"), func(p *ucd.Parser) { + r := p.Rune(0) + s := strings.SplitN(p.String(ucd.DecompMapping), " ", 2) + if !maps[s[0]] { + return + } + x, err := strconv.ParseUint(s[1], 16, 32) + if err != nil { + log.Fatalf("Error parsing rune %q", s[1]) + } + if inverse[r] != 0 || inverse[rune(x)] != 0 { + log.Fatalf("Circular dependency in mapping between %U and %U", r, x) + } + inverse[r] = rune(x) + inverse[rune(x)] = r + }) + + // <rune range>;<type> + ucd.Parse(gen.OpenUCDFile("EastAsianWidth.txt"), func(p *ucd.Parser) { + tag, ok := typeMap[p.String(1)] + if !ok { + log.Fatalf("Unknown width type %q", p.String(1)) + } + r := p.Rune(0) + alt, ok := inverse[r] + if tag == tagFullwidth || tag == tagHalfwidth && r != wonSign { + tag |= tagNeedsFold + if !ok { + log.Fatalf("Narrow or wide rune %U has no decomposition", r) + } + } + f(r, tag, alt) + }) +} diff --git a/vendor/golang.org/x/text/width/example_test.go b/vendor/golang.org/x/text/width/example_test.go new file mode 100644 index 000000000..62adba660 --- /dev/null +++ b/vendor/golang.org/x/text/width/example_test.go @@ -0,0 +1,52 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package width_test + +import ( + "fmt" + + "golang.org/x/text/width" +) + +func ExampleTransformer_fold() { + s := "abヲ₩○¥A" + f := width.Fold.String(s) + fmt.Printf("%U: %s\n", []rune(s), s) + fmt.Printf("%U: %s\n", []rune(f), f) + + // Output: + // [U+0061 U+0062 U+FF66 U+FFE6 U+FFEE U+FFE5 U+FF21]: abヲ₩○¥A + // [U+0061 U+0062 U+30F2 U+20A9 U+25CB U+00A5 U+0041]: abヲ₩○¥A +} + +func ExampleTransformer_widen() { + s := "ab¥ヲ₩○" + w := width.Widen.String(s) + fmt.Printf("%U: %s\n", []rune(s), s) + fmt.Printf("%U: %s\n", []rune(w), w) + + // Output: + // [U+0061 U+0062 U+00A5 U+FF66 U+20A9 U+FFEE]: ab¥ヲ₩○ + // [U+FF41 U+FF42 U+FFE5 U+30F2 U+FFE6 U+25CB]: ab¥ヲ₩○ +} + +func ExampleTransformer_narrow() { + s := "abヲ₩○¥A" + n := width.Narrow.String(s) + fmt.Printf("%U: %s\n", []rune(s), s) + fmt.Printf("%U: %s\n", []rune(n), n) + + // Ambiguous characters with a halfwidth equivalent get mapped as well. + s = "←" + n = width.Narrow.String(s) + fmt.Printf("%U: %s\n", []rune(s), s) + fmt.Printf("%U: %s\n", []rune(n), n) + + // Output: + // [U+0061 U+0062 U+30F2 U+FFE6 U+25CB U+FFE5 U+FF21]: abヲ₩○¥A + // [U+0061 U+0062 U+FF66 U+20A9 U+FFEE U+00A5 U+0041]: abヲ₩○¥A + // [U+2190]: ← + // [U+FFE9]: ← +} diff --git a/vendor/golang.org/x/text/width/runes_test.go b/vendor/golang.org/x/text/width/runes_test.go new file mode 100644 index 000000000..587dab4ed --- /dev/null +++ b/vendor/golang.org/x/text/width/runes_test.go @@ -0,0 +1,461 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package width + +var mapRunes = map[rune]struct { + r rune + e elem +}{ + 0x20: {0x3000, 0x6000}, + 0x21: {0xFF01, 0x6000}, + 0x22: {0xFF02, 0x6000}, + 0x23: {0xFF03, 0x6000}, + 0x24: {0xFF04, 0x6000}, + 0x25: {0xFF05, 0x6000}, + 0x26: {0xFF06, 0x6000}, + 0x27: {0xFF07, 0x6000}, + 0x28: {0xFF08, 0x6000}, + 0x29: {0xFF09, 0x6000}, + 0x2A: {0xFF0A, 0x6000}, + 0x2B: {0xFF0B, 0x6000}, + 0x2C: {0xFF0C, 0x6000}, + 0x2D: {0xFF0D, 0x6000}, + 0x2E: {0xFF0E, 0x6000}, + 0x2F: {0xFF0F, 0x6000}, + 0x30: {0xFF10, 0x6000}, + 0x31: {0xFF11, 0x6000}, + 0x32: {0xFF12, 0x6000}, + 0x33: {0xFF13, 0x6000}, + 0x34: {0xFF14, 0x6000}, + 0x35: {0xFF15, 0x6000}, + 0x36: {0xFF16, 0x6000}, + 0x37: {0xFF17, 0x6000}, + 0x38: {0xFF18, 0x6000}, + 0x39: {0xFF19, 0x6000}, + 0x3A: {0xFF1A, 0x6000}, + 0x3B: {0xFF1B, 0x6000}, + 0x3C: {0xFF1C, 0x6000}, + 0x3D: {0xFF1D, 0x6000}, + 0x3E: {0xFF1E, 0x6000}, + 0x3F: {0xFF1F, 0x6000}, + 0x40: {0xFF20, 0x6000}, + 0x41: {0xFF21, 0x6000}, + 0x42: {0xFF22, 0x6000}, + 0x43: {0xFF23, 0x6000}, + 0x44: {0xFF24, 0x6000}, + 0x45: {0xFF25, 0x6000}, + 0x46: {0xFF26, 0x6000}, + 0x47: {0xFF27, 0x6000}, + 0x48: {0xFF28, 0x6000}, + 0x49: {0xFF29, 0x6000}, + 0x4A: {0xFF2A, 0x6000}, + 0x4B: {0xFF2B, 0x6000}, + 0x4C: {0xFF2C, 0x6000}, + 0x4D: {0xFF2D, 0x6000}, + 0x4E: {0xFF2E, 0x6000}, + 0x4F: {0xFF2F, 0x6000}, + 0x50: {0xFF30, 0x6000}, + 0x51: {0xFF31, 0x6000}, + 0x52: {0xFF32, 0x6000}, + 0x53: {0xFF33, 0x6000}, + 0x54: {0xFF34, 0x6000}, + 0x55: {0xFF35, 0x6000}, + 0x56: {0xFF36, 0x6000}, + 0x57: {0xFF37, 0x6000}, + 0x58: {0xFF38, 0x6000}, + 0x59: {0xFF39, 0x6000}, + 0x5A: {0xFF3A, 0x6000}, + 0x5B: {0xFF3B, 0x6000}, + 0x5C: {0xFF3C, 0x6000}, + 0x5D: {0xFF3D, 0x6000}, + 0x5E: {0xFF3E, 0x6000}, + 0x5F: {0xFF3F, 0x6000}, + 0x60: {0xFF40, 0x6000}, + 0x61: {0xFF41, 0x6000}, + 0x62: {0xFF42, 0x6000}, + 0x63: {0xFF43, 0x6000}, + 0x64: {0xFF44, 0x6000}, + 0x65: {0xFF45, 0x6000}, + 0x66: {0xFF46, 0x6000}, + 0x67: {0xFF47, 0x6000}, + 0x68: {0xFF48, 0x6000}, + 0x69: {0xFF49, 0x6000}, + 0x6A: {0xFF4A, 0x6000}, + 0x6B: {0xFF4B, 0x6000}, + 0x6C: {0xFF4C, 0x6000}, + 0x6D: {0xFF4D, 0x6000}, + 0x6E: {0xFF4E, 0x6000}, + 0x6F: {0xFF4F, 0x6000}, + 0x70: {0xFF50, 0x6000}, + 0x71: {0xFF51, 0x6000}, + 0x72: {0xFF52, 0x6000}, + 0x73: {0xFF53, 0x6000}, + 0x74: {0xFF54, 0x6000}, + 0x75: {0xFF55, 0x6000}, + 0x76: {0xFF56, 0x6000}, + 0x77: {0xFF57, 0x6000}, + 0x78: {0xFF58, 0x6000}, + 0x79: {0xFF59, 0x6000}, + 0x7A: {0xFF5A, 0x6000}, + 0x7B: {0xFF5B, 0x6000}, + 0x7C: {0xFF5C, 0x6000}, + 0x7D: {0xFF5D, 0x6000}, + 0x7E: {0xFF5E, 0x6000}, + 0xA2: {0xFFE0, 0x6000}, + 0xA3: {0xFFE1, 0x6000}, + 0xA5: {0xFFE5, 0x6000}, + 0xA6: {0xFFE4, 0x6000}, + 0xAC: {0xFFE2, 0x6000}, + 0xAF: {0xFFE3, 0x6000}, + 0x20A9: {0xFFE6, 0xA000}, + 0x2190: {0xFFE9, 0x2000}, + 0x2191: {0xFFEA, 0x2000}, + 0x2192: {0xFFEB, 0x2000}, + 0x2193: {0xFFEC, 0x2000}, + 0x2502: {0xFFE8, 0x2000}, + 0x25A0: {0xFFED, 0x2000}, + 0x25CB: {0xFFEE, 0x2000}, + 0x2985: {0xFF5F, 0x6000}, + 0x2986: {0xFF60, 0x6000}, + 0x3000: {0x20, 0x9000}, + 0x3001: {0xFF64, 0x4000}, + 0x3002: {0xFF61, 0x4000}, + 0x300C: {0xFF62, 0x4000}, + 0x300D: {0xFF63, 0x4000}, + 0x3099: {0xFF9E, 0x4000}, + 0x309A: {0xFF9F, 0x4000}, + 0x30A1: {0xFF67, 0x4000}, + 0x30A2: {0xFF71, 0x4000}, + 0x30A3: {0xFF68, 0x4000}, + 0x30A4: {0xFF72, 0x4000}, + 0x30A5: {0xFF69, 0x4000}, + 0x30A6: {0xFF73, 0x4000}, + 0x30A7: {0xFF6A, 0x4000}, + 0x30A8: {0xFF74, 0x4000}, + 0x30A9: {0xFF6B, 0x4000}, + 0x30AA: {0xFF75, 0x4000}, + 0x30AB: {0xFF76, 0x4000}, + 0x30AD: {0xFF77, 0x4000}, + 0x30AF: {0xFF78, 0x4000}, + 0x30B1: {0xFF79, 0x4000}, + 0x30B3: {0xFF7A, 0x4000}, + 0x30B5: {0xFF7B, 0x4000}, + 0x30B7: {0xFF7C, 0x4000}, + 0x30B9: {0xFF7D, 0x4000}, + 0x30BB: {0xFF7E, 0x4000}, + 0x30BD: {0xFF7F, 0x4000}, + 0x30BF: {0xFF80, 0x4000}, + 0x30C1: {0xFF81, 0x4000}, + 0x30C3: {0xFF6F, 0x4000}, + 0x30C4: {0xFF82, 0x4000}, + 0x30C6: {0xFF83, 0x4000}, + 0x30C8: {0xFF84, 0x4000}, + 0x30CA: {0xFF85, 0x4000}, + 0x30CB: {0xFF86, 0x4000}, + 0x30CC: {0xFF87, 0x4000}, + 0x30CD: {0xFF88, 0x4000}, + 0x30CE: {0xFF89, 0x4000}, + 0x30CF: {0xFF8A, 0x4000}, + 0x30D2: {0xFF8B, 0x4000}, + 0x30D5: {0xFF8C, 0x4000}, + 0x30D8: {0xFF8D, 0x4000}, + 0x30DB: {0xFF8E, 0x4000}, + 0x30DE: {0xFF8F, 0x4000}, + 0x30DF: {0xFF90, 0x4000}, + 0x30E0: {0xFF91, 0x4000}, + 0x30E1: {0xFF92, 0x4000}, + 0x30E2: {0xFF93, 0x4000}, + 0x30E3: {0xFF6C, 0x4000}, + 0x30E4: {0xFF94, 0x4000}, + 0x30E5: {0xFF6D, 0x4000}, + 0x30E6: {0xFF95, 0x4000}, + 0x30E7: {0xFF6E, 0x4000}, + 0x30E8: {0xFF96, 0x4000}, + 0x30E9: {0xFF97, 0x4000}, + 0x30EA: {0xFF98, 0x4000}, + 0x30EB: {0xFF99, 0x4000}, + 0x30EC: {0xFF9A, 0x4000}, + 0x30ED: {0xFF9B, 0x4000}, + 0x30EF: {0xFF9C, 0x4000}, + 0x30F2: {0xFF66, 0x4000}, + 0x30F3: {0xFF9D, 0x4000}, + 0x30FB: {0xFF65, 0x4000}, + 0x30FC: {0xFF70, 0x4000}, + 0x3131: {0xFFA1, 0x4000}, + 0x3132: {0xFFA2, 0x4000}, + 0x3133: {0xFFA3, 0x4000}, + 0x3134: {0xFFA4, 0x4000}, + 0x3135: {0xFFA5, 0x4000}, + 0x3136: {0xFFA6, 0x4000}, + 0x3137: {0xFFA7, 0x4000}, + 0x3138: {0xFFA8, 0x4000}, + 0x3139: {0xFFA9, 0x4000}, + 0x313A: {0xFFAA, 0x4000}, + 0x313B: {0xFFAB, 0x4000}, + 0x313C: {0xFFAC, 0x4000}, + 0x313D: {0xFFAD, 0x4000}, + 0x313E: {0xFFAE, 0x4000}, + 0x313F: {0xFFAF, 0x4000}, + 0x3140: {0xFFB0, 0x4000}, + 0x3141: {0xFFB1, 0x4000}, + 0x3142: {0xFFB2, 0x4000}, + 0x3143: {0xFFB3, 0x4000}, + 0x3144: {0xFFB4, 0x4000}, + 0x3145: {0xFFB5, 0x4000}, + 0x3146: {0xFFB6, 0x4000}, + 0x3147: {0xFFB7, 0x4000}, + 0x3148: {0xFFB8, 0x4000}, + 0x3149: {0xFFB9, 0x4000}, + 0x314A: {0xFFBA, 0x4000}, + 0x314B: {0xFFBB, 0x4000}, + 0x314C: {0xFFBC, 0x4000}, + 0x314D: {0xFFBD, 0x4000}, + 0x314E: {0xFFBE, 0x4000}, + 0x314F: {0xFFC2, 0x4000}, + 0x3150: {0xFFC3, 0x4000}, + 0x3151: {0xFFC4, 0x4000}, + 0x3152: {0xFFC5, 0x4000}, + 0x3153: {0xFFC6, 0x4000}, + 0x3154: {0xFFC7, 0x4000}, + 0x3155: {0xFFCA, 0x4000}, + 0x3156: {0xFFCB, 0x4000}, + 0x3157: {0xFFCC, 0x4000}, + 0x3158: {0xFFCD, 0x4000}, + 0x3159: {0xFFCE, 0x4000}, + 0x315A: {0xFFCF, 0x4000}, + 0x315B: {0xFFD2, 0x4000}, + 0x315C: {0xFFD3, 0x4000}, + 0x315D: {0xFFD4, 0x4000}, + 0x315E: {0xFFD5, 0x4000}, + 0x315F: {0xFFD6, 0x4000}, + 0x3160: {0xFFD7, 0x4000}, + 0x3161: {0xFFDA, 0x4000}, + 0x3162: {0xFFDB, 0x4000}, + 0x3163: {0xFFDC, 0x4000}, + 0x3164: {0xFFA0, 0x4000}, + 0xFF01: {0x21, 0x9000}, + 0xFF02: {0x22, 0x9000}, + 0xFF03: {0x23, 0x9000}, + 0xFF04: {0x24, 0x9000}, + 0xFF05: {0x25, 0x9000}, + 0xFF06: {0x26, 0x9000}, + 0xFF07: {0x27, 0x9000}, + 0xFF08: {0x28, 0x9000}, + 0xFF09: {0x29, 0x9000}, + 0xFF0A: {0x2A, 0x9000}, + 0xFF0B: {0x2B, 0x9000}, + 0xFF0C: {0x2C, 0x9000}, + 0xFF0D: {0x2D, 0x9000}, + 0xFF0E: {0x2E, 0x9000}, + 0xFF0F: {0x2F, 0x9000}, + 0xFF10: {0x30, 0x9000}, + 0xFF11: {0x31, 0x9000}, + 0xFF12: {0x32, 0x9000}, + 0xFF13: {0x33, 0x9000}, + 0xFF14: {0x34, 0x9000}, + 0xFF15: {0x35, 0x9000}, + 0xFF16: {0x36, 0x9000}, + 0xFF17: {0x37, 0x9000}, + 0xFF18: {0x38, 0x9000}, + 0xFF19: {0x39, 0x9000}, + 0xFF1A: {0x3A, 0x9000}, + 0xFF1B: {0x3B, 0x9000}, + 0xFF1C: {0x3C, 0x9000}, + 0xFF1D: {0x3D, 0x9000}, + 0xFF1E: {0x3E, 0x9000}, + 0xFF1F: {0x3F, 0x9000}, + 0xFF20: {0x40, 0x9000}, + 0xFF21: {0x41, 0x9000}, + 0xFF22: {0x42, 0x9000}, + 0xFF23: {0x43, 0x9000}, + 0xFF24: {0x44, 0x9000}, + 0xFF25: {0x45, 0x9000}, + 0xFF26: {0x46, 0x9000}, + 0xFF27: {0x47, 0x9000}, + 0xFF28: {0x48, 0x9000}, + 0xFF29: {0x49, 0x9000}, + 0xFF2A: {0x4A, 0x9000}, + 0xFF2B: {0x4B, 0x9000}, + 0xFF2C: {0x4C, 0x9000}, + 0xFF2D: {0x4D, 0x9000}, + 0xFF2E: {0x4E, 0x9000}, + 0xFF2F: {0x4F, 0x9000}, + 0xFF30: {0x50, 0x9000}, + 0xFF31: {0x51, 0x9000}, + 0xFF32: {0x52, 0x9000}, + 0xFF33: {0x53, 0x9000}, + 0xFF34: {0x54, 0x9000}, + 0xFF35: {0x55, 0x9000}, + 0xFF36: {0x56, 0x9000}, + 0xFF37: {0x57, 0x9000}, + 0xFF38: {0x58, 0x9000}, + 0xFF39: {0x59, 0x9000}, + 0xFF3A: {0x5A, 0x9000}, + 0xFF3B: {0x5B, 0x9000}, + 0xFF3C: {0x5C, 0x9000}, + 0xFF3D: {0x5D, 0x9000}, + 0xFF3E: {0x5E, 0x9000}, + 0xFF3F: {0x5F, 0x9000}, + 0xFF40: {0x60, 0x9000}, + 0xFF41: {0x61, 0x9000}, + 0xFF42: {0x62, 0x9000}, + 0xFF43: {0x63, 0x9000}, + 0xFF44: {0x64, 0x9000}, + 0xFF45: {0x65, 0x9000}, + 0xFF46: {0x66, 0x9000}, + 0xFF47: {0x67, 0x9000}, + 0xFF48: {0x68, 0x9000}, + 0xFF49: {0x69, 0x9000}, + 0xFF4A: {0x6A, 0x9000}, + 0xFF4B: {0x6B, 0x9000}, + 0xFF4C: {0x6C, 0x9000}, + 0xFF4D: {0x6D, 0x9000}, + 0xFF4E: {0x6E, 0x9000}, + 0xFF4F: {0x6F, 0x9000}, + 0xFF50: {0x70, 0x9000}, + 0xFF51: {0x71, 0x9000}, + 0xFF52: {0x72, 0x9000}, + 0xFF53: {0x73, 0x9000}, + 0xFF54: {0x74, 0x9000}, + 0xFF55: {0x75, 0x9000}, + 0xFF56: {0x76, 0x9000}, + 0xFF57: {0x77, 0x9000}, + 0xFF58: {0x78, 0x9000}, + 0xFF59: {0x79, 0x9000}, + 0xFF5A: {0x7A, 0x9000}, + 0xFF5B: {0x7B, 0x9000}, + 0xFF5C: {0x7C, 0x9000}, + 0xFF5D: {0x7D, 0x9000}, + 0xFF5E: {0x7E, 0x9000}, + 0xFF5F: {0x2985, 0x9000}, + 0xFF60: {0x2986, 0x9000}, + 0xFF61: {0x3002, 0xB000}, + 0xFF62: {0x300C, 0xB000}, + 0xFF63: {0x300D, 0xB000}, + 0xFF64: {0x3001, 0xB000}, + 0xFF65: {0x30FB, 0xB000}, + 0xFF66: {0x30F2, 0xB000}, + 0xFF67: {0x30A1, 0xB000}, + 0xFF68: {0x30A3, 0xB000}, + 0xFF69: {0x30A5, 0xB000}, + 0xFF6A: {0x30A7, 0xB000}, + 0xFF6B: {0x30A9, 0xB000}, + 0xFF6C: {0x30E3, 0xB000}, + 0xFF6D: {0x30E5, 0xB000}, + 0xFF6E: {0x30E7, 0xB000}, + 0xFF6F: {0x30C3, 0xB000}, + 0xFF70: {0x30FC, 0xB000}, + 0xFF71: {0x30A2, 0xB000}, + 0xFF72: {0x30A4, 0xB000}, + 0xFF73: {0x30A6, 0xB000}, + 0xFF74: {0x30A8, 0xB000}, + 0xFF75: {0x30AA, 0xB000}, + 0xFF76: {0x30AB, 0xB000}, + 0xFF77: {0x30AD, 0xB000}, + 0xFF78: {0x30AF, 0xB000}, + 0xFF79: {0x30B1, 0xB000}, + 0xFF7A: {0x30B3, 0xB000}, + 0xFF7B: {0x30B5, 0xB000}, + 0xFF7C: {0x30B7, 0xB000}, + 0xFF7D: {0x30B9, 0xB000}, + 0xFF7E: {0x30BB, 0xB000}, + 0xFF7F: {0x30BD, 0xB000}, + 0xFF80: {0x30BF, 0xB000}, + 0xFF81: {0x30C1, 0xB000}, + 0xFF82: {0x30C4, 0xB000}, + 0xFF83: {0x30C6, 0xB000}, + 0xFF84: {0x30C8, 0xB000}, + 0xFF85: {0x30CA, 0xB000}, + 0xFF86: {0x30CB, 0xB000}, + 0xFF87: {0x30CC, 0xB000}, + 0xFF88: {0x30CD, 0xB000}, + 0xFF89: {0x30CE, 0xB000}, + 0xFF8A: {0x30CF, 0xB000}, + 0xFF8B: {0x30D2, 0xB000}, + 0xFF8C: {0x30D5, 0xB000}, + 0xFF8D: {0x30D8, 0xB000}, + 0xFF8E: {0x30DB, 0xB000}, + 0xFF8F: {0x30DE, 0xB000}, + 0xFF90: {0x30DF, 0xB000}, + 0xFF91: {0x30E0, 0xB000}, + 0xFF92: {0x30E1, 0xB000}, + 0xFF93: {0x30E2, 0xB000}, + 0xFF94: {0x30E4, 0xB000}, + 0xFF95: {0x30E6, 0xB000}, + 0xFF96: {0x30E8, 0xB000}, + 0xFF97: {0x30E9, 0xB000}, + 0xFF98: {0x30EA, 0xB000}, + 0xFF99: {0x30EB, 0xB000}, + 0xFF9A: {0x30EC, 0xB000}, + 0xFF9B: {0x30ED, 0xB000}, + 0xFF9C: {0x30EF, 0xB000}, + 0xFF9D: {0x30F3, 0xB000}, + 0xFF9E: {0x3099, 0xB000}, + 0xFF9F: {0x309A, 0xB000}, + 0xFFA0: {0x3164, 0xB000}, + 0xFFA1: {0x3131, 0xB000}, + 0xFFA2: {0x3132, 0xB000}, + 0xFFA3: {0x3133, 0xB000}, + 0xFFA4: {0x3134, 0xB000}, + 0xFFA5: {0x3135, 0xB000}, + 0xFFA6: {0x3136, 0xB000}, + 0xFFA7: {0x3137, 0xB000}, + 0xFFA8: {0x3138, 0xB000}, + 0xFFA9: {0x3139, 0xB000}, + 0xFFAA: {0x313A, 0xB000}, + 0xFFAB: {0x313B, 0xB000}, + 0xFFAC: {0x313C, 0xB000}, + 0xFFAD: {0x313D, 0xB000}, + 0xFFAE: {0x313E, 0xB000}, + 0xFFAF: {0x313F, 0xB000}, + 0xFFB0: {0x3140, 0xB000}, + 0xFFB1: {0x3141, 0xB000}, + 0xFFB2: {0x3142, 0xB000}, + 0xFFB3: {0x3143, 0xB000}, + 0xFFB4: {0x3144, 0xB000}, + 0xFFB5: {0x3145, 0xB000}, + 0xFFB6: {0x3146, 0xB000}, + 0xFFB7: {0x3147, 0xB000}, + 0xFFB8: {0x3148, 0xB000}, + 0xFFB9: {0x3149, 0xB000}, + 0xFFBA: {0x314A, 0xB000}, + 0xFFBB: {0x314B, 0xB000}, + 0xFFBC: {0x314C, 0xB000}, + 0xFFBD: {0x314D, 0xB000}, + 0xFFBE: {0x314E, 0xB000}, + 0xFFC2: {0x314F, 0xB000}, + 0xFFC3: {0x3150, 0xB000}, + 0xFFC4: {0x3151, 0xB000}, + 0xFFC5: {0x3152, 0xB000}, + 0xFFC6: {0x3153, 0xB000}, + 0xFFC7: {0x3154, 0xB000}, + 0xFFCA: {0x3155, 0xB000}, + 0xFFCB: {0x3156, 0xB000}, + 0xFFCC: {0x3157, 0xB000}, + 0xFFCD: {0x3158, 0xB000}, + 0xFFCE: {0x3159, 0xB000}, + 0xFFCF: {0x315A, 0xB000}, + 0xFFD2: {0x315B, 0xB000}, + 0xFFD3: {0x315C, 0xB000}, + 0xFFD4: {0x315D, 0xB000}, + 0xFFD5: {0x315E, 0xB000}, + 0xFFD6: {0x315F, 0xB000}, + 0xFFD7: {0x3160, 0xB000}, + 0xFFDA: {0x3161, 0xB000}, + 0xFFDB: {0x3162, 0xB000}, + 0xFFDC: {0x3163, 0xB000}, + 0xFFE0: {0xA2, 0x9000}, + 0xFFE1: {0xA3, 0x9000}, + 0xFFE2: {0xAC, 0x9000}, + 0xFFE3: {0xAF, 0x9000}, + 0xFFE4: {0xA6, 0x9000}, + 0xFFE5: {0xA5, 0x9000}, + 0xFFE6: {0x20A9, 0x9000}, + 0xFFE8: {0x2502, 0xB000}, + 0xFFE9: {0x2190, 0xB000}, + 0xFFEA: {0x2191, 0xB000}, + 0xFFEB: {0x2192, 0xB000}, + 0xFFEC: {0x2193, 0xB000}, + 0xFFED: {0x25A0, 0xB000}, + 0xFFEE: {0x25CB, 0xB000}, +} diff --git a/vendor/golang.org/x/text/width/tables_test.go b/vendor/golang.org/x/text/width/tables_test.go new file mode 100644 index 000000000..189febd3c --- /dev/null +++ b/vendor/golang.org/x/text/width/tables_test.go @@ -0,0 +1,59 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package width + +import ( + "testing" + + "golang.org/x/text/internal/testtext" +) + +const ( + loSurrogate = 0xD800 + hiSurrogate = 0xDFFF +) + +func TestTables(t *testing.T) { + testtext.SkipIfNotLong(t) + + runes := map[rune]Kind{} + getWidthData(func(r rune, tag elem, _ rune) { + runes[r] = tag.kind() + }) + for r := rune(0); r < 0x10FFFF; r++ { + if loSurrogate <= r && r <= hiSurrogate { + continue + } + p := LookupRune(r) + if got, want := p.Kind(), runes[r]; got != want { + t.Errorf("Kind of %U was %s; want %s.", r, got, want) + } + want, mapped := foldRune(r) + if got := p.Folded(); (got == 0) == mapped || got != 0 && got != want { + t.Errorf("Folded(%U) = %U; want %U", r, got, want) + } + want, mapped = widenRune(r) + if got := p.Wide(); (got == 0) == mapped || got != 0 && got != want { + t.Errorf("Wide(%U) = %U; want %U", r, got, want) + } + want, mapped = narrowRune(r) + if got := p.Narrow(); (got == 0) == mapped || got != 0 && got != want { + t.Errorf("Narrow(%U) = %U; want %U", r, got, want) + } + } +} + +// TestAmbiguous verifies that that ambiguous runes with a mapping always map to +// a halfwidth rune. +func TestAmbiguous(t *testing.T) { + for r, m := range mapRunes { + if m.e != tagAmbiguous { + continue + } + if k := mapRunes[m.r].e.kind(); k != EastAsianHalfwidth { + t.Errorf("Rune %U is ambiguous and maps to a rune of type %v", r, k) + } + } +} diff --git a/vendor/golang.org/x/text/width/transform_test.go b/vendor/golang.org/x/text/width/transform_test.go new file mode 100644 index 000000000..f9122d6db --- /dev/null +++ b/vendor/golang.org/x/text/width/transform_test.go @@ -0,0 +1,701 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package width + +import ( + "bytes" + "strings" + "testing" + + "golang.org/x/text/internal/testtext" + "golang.org/x/text/transform" +) + +func foldRune(r rune) (folded rune, ok bool) { + alt, ok := mapRunes[r] + if ok && alt.e&tagNeedsFold != 0 { + return alt.r, true + } + return r, false +} + +func widenRune(r rune) (wide rune, ok bool) { + alt, ok := mapRunes[r] + if k := alt.e.kind(); k == EastAsianHalfwidth || k == EastAsianNarrow { + return alt.r, true + } + return r, false +} + +func narrowRune(r rune) (narrow rune, ok bool) { + alt, ok := mapRunes[r] + if k := alt.e.kind(); k == EastAsianFullwidth || k == EastAsianWide || k == EastAsianAmbiguous { + return alt.r, true + } + return r, false +} + +func TestFoldSingleRunes(t *testing.T) { + for r := rune(0); r < 0x1FFFF; r++ { + if loSurrogate <= r && r <= hiSurrogate { + continue + } + x, _ := foldRune(r) + want := string(x) + got := Fold.String(string(r)) + if got != want { + t.Errorf("Fold().String(%U) = %+q; want %+q", r, got, want) + } + } +} + +type transformTest struct { + desc string + src string + nBuf int + nDst int + atEOF bool + dst string + nSrc int + err error + nSpan int + errSpan error +} + +func (tc *transformTest) doTest(t *testing.T, tr Transformer) { + testtext.Run(t, tc.desc, func(t *testing.T) { + b := make([]byte, tc.nBuf) + nDst, nSrc, err := tr.Transform(b, []byte(tc.src), tc.atEOF) + if got := string(b[:nDst]); got != tc.dst[:nDst] { + t.Errorf("dst was %+q; want %+q", got, tc.dst) + } + if nDst != tc.nDst { + t.Errorf("nDst was %d; want %d", nDst, tc.nDst) + } + if nSrc != tc.nSrc { + t.Errorf("nSrc was %d; want %d", nSrc, tc.nSrc) + } + if err != tc.err { + t.Errorf("error was %v; want %v", err, tc.err) + } + if got := tr.String(tc.src); got != tc.dst { + t.Errorf("String(%q) = %q; want %q", tc.src, got, tc.dst) + } + n, err := tr.Span([]byte(tc.src), tc.atEOF) + if n != tc.nSpan || err != tc.errSpan { + t.Errorf("Span: got %d, %v; want %d, %v", n, err, tc.nSpan, tc.errSpan) + } + }) +} + +func TestFold(t *testing.T) { + for _, tc := range []transformTest{{ + desc: "empty", + src: "", + nBuf: 10, + dst: "", + nDst: 0, + nSrc: 0, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: nil, + }, { + desc: "short source 1", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 1, + nSrc: 1, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 1, + errSpan: transform.ErrShortSrc, + }, { + desc: "short source 2", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 1, + nSrc: 1, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 1, + errSpan: transform.ErrShortSrc, + }, { + desc: "incomplete but terminated source 1", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 2, + nSrc: 2, + atEOF: true, + err: nil, + nSpan: 2, + errSpan: nil, + }, { + desc: "incomplete but terminated source 2", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 3, + nSrc: 3, + atEOF: true, + err: nil, + nSpan: 3, + errSpan: nil, + }, { + desc: "exact fit dst", + src: "a\uff01", + nBuf: 2, + dst: "a!", + nDst: 2, + nSrc: 4, + atEOF: false, + err: nil, + nSpan: 1, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "exact fit dst and src ascii", + src: "ab", + nBuf: 2, + dst: "ab", + nDst: 2, + nSrc: 2, + atEOF: true, + err: nil, + nSpan: 2, + errSpan: nil, + }, { + desc: "empty dst", + src: "\u0300", + nBuf: 0, + dst: "\u0300", + nDst: 0, + nSrc: 0, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 2, + errSpan: nil, + }, { + desc: "empty dst ascii", + src: "a", + nBuf: 0, + dst: "a", + nDst: 0, + nSrc: 0, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 1, + errSpan: nil, + }, { + desc: "short dst 1", + src: "a\uffe0", // ¢ + nBuf: 2, + dst: "a\u00a2", // ¢ + nDst: 1, + nSrc: 1, + atEOF: false, + err: transform.ErrShortDst, + nSpan: 1, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short dst 2", + src: "不夠", + nBuf: 3, + dst: "不夠", + nDst: 3, + nSrc: 3, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 6, + errSpan: nil, + }, { + desc: "short dst fast path", + src: "fast", + nDst: 3, + dst: "fast", + nBuf: 3, + nSrc: 3, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 4, + errSpan: nil, + }, { + desc: "short dst larger buffer", + src: "\uff21" + strings.Repeat("0", 127) + "B", + nBuf: 128, + dst: "A" + strings.Repeat("0", 127) + "B", + nDst: 128, + nSrc: 130, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "fast path alternation", + src: "fast路徑fast路徑", + nBuf: 20, + dst: "fast路徑fast路徑", + nDst: 20, + nSrc: 20, + atEOF: true, + err: nil, + nSpan: 20, + errSpan: nil, + }} { + tc.doTest(t, Fold) + } +} + +func TestWidenSingleRunes(t *testing.T) { + for r := rune(0); r < 0x1FFFF; r++ { + if loSurrogate <= r && r <= hiSurrogate { + continue + } + alt, _ := widenRune(r) + want := string(alt) + got := Widen.String(string(r)) + if got != want { + t.Errorf("Widen().String(%U) = %+q; want %+q", r, got, want) + } + } +} + +func TestWiden(t *testing.T) { + for _, tc := range []transformTest{{ + desc: "empty", + src: "", + nBuf: 10, + dst: "", + nDst: 0, + nSrc: 0, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: nil, + }, { + desc: "short source 1", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 3, + nSrc: 1, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short source 2", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 3, + nSrc: 1, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "incomplete but terminated source 1", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 4, + nSrc: 2, + atEOF: true, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "incomplete but terminated source 2", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 5, + nSrc: 3, + atEOF: true, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short source 1 some span", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 3, + nSrc: 3, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 3, + errSpan: transform.ErrShortSrc, + }, { + desc: "short source 2 some span", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 3, + nSrc: 3, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 3, + errSpan: transform.ErrShortSrc, + }, { + desc: "incomplete but terminated source 1 some span", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 4, + nSrc: 4, + atEOF: true, + err: nil, + nSpan: 4, + errSpan: nil, + }, { + desc: "incomplete but terminated source 2 some span", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 5, + nSrc: 5, + atEOF: true, + err: nil, + nSpan: 5, + errSpan: nil, + }, { + desc: "exact fit dst", + src: "a!", + nBuf: 6, + dst: "a\uff01", + nDst: 6, + nSrc: 2, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "empty dst", + src: "\u0300", + nBuf: 0, + dst: "\u0300", + nDst: 0, + nSrc: 0, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 2, + errSpan: nil, + }, { + desc: "empty dst ascii", + src: "a", + nBuf: 0, + dst: "a", + nDst: 0, + nSrc: 0, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short dst 1", + src: "a\uffe0", + nBuf: 4, + dst: "a\uffe0", + nDst: 3, + nSrc: 1, + atEOF: false, + err: transform.ErrShortDst, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short dst 2", + src: "不夠", + nBuf: 3, + dst: "不夠", + nDst: 3, + nSrc: 3, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 6, + errSpan: nil, + }, { + desc: "short dst ascii", + src: "ascii", + nBuf: 3, + dst: "ascii", // U+ff41, ... + nDst: 3, + nSrc: 1, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "ambiguous", + src: "\uffe9", + nBuf: 4, + dst: "\u2190", + nDst: 3, + nSrc: 3, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }} { + tc.doTest(t, Widen) + } +} + +func TestNarrowSingleRunes(t *testing.T) { + for r := rune(0); r < 0x1FFFF; r++ { + if loSurrogate <= r && r <= hiSurrogate { + continue + } + alt, _ := narrowRune(r) + want := string(alt) + got := Narrow.String(string(r)) + if got != want { + t.Errorf("Narrow().String(%U) = %+q; want %+q", r, got, want) + } + } +} + +func TestNarrow(t *testing.T) { + for _, tc := range []transformTest{{ + desc: "empty", + src: "", + nBuf: 10, + dst: "", + nDst: 0, + nSrc: 0, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: nil, + }, { + desc: "short source 1", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 1, + nSrc: 1, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 1, + errSpan: transform.ErrShortSrc, + }, { + desc: "short source 2", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 1, + nSrc: 3, + atEOF: false, + err: transform.ErrShortSrc, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "incomplete but terminated source 1", + src: "a\xc2", + nBuf: 10, + dst: "a\xc2", + nDst: 2, + nSrc: 4, + atEOF: true, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "incomplete but terminated source 2", + src: "a\xe0\x80", + nBuf: 10, + dst: "a\xe0\x80", + nDst: 3, + nSrc: 5, + atEOF: true, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "exact fit dst", + src: "a\uff01", + nBuf: 2, + dst: "a!", + nDst: 2, + nSrc: 6, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "exact fit dst some span", + src: "a\uff01", + nBuf: 2, + dst: "a!", + nDst: 2, + nSrc: 4, + atEOF: false, + err: nil, + nSpan: 1, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "empty dst", + src: "\u0300", + nBuf: 0, + dst: "\u0300", + nDst: 0, + nSrc: 0, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 2, + errSpan: nil, + }, { + desc: "empty dst ascii", + src: "a", + nBuf: 0, + dst: "a", + nDst: 0, + nSrc: 0, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 1, + errSpan: nil, + }, { + desc: "short dst 1", + src: "a\uffe0", // ¢ + nBuf: 2, + dst: "a\u00a2", // ¢ + nDst: 1, + nSrc: 3, + atEOF: false, + err: transform.ErrShortDst, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short dst 2", + src: "不夠", + nBuf: 3, + dst: "不夠", + nDst: 3, + nSrc: 3, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 6, + errSpan: nil, + }, { + // Create a narrow variant of ambiguous runes, if they exist. + desc: "ambiguous", + src: "\u2190", + nBuf: 4, + dst: "\uffe9", + nDst: 3, + nSrc: 3, + atEOF: false, + err: nil, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "short dst fast path", + src: "fast", + nBuf: 3, + dst: "fast", + nDst: 3, + nSrc: 3, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 4, + errSpan: nil, + }, { + desc: "short dst larger buffer", + src: "\uff21" + strings.Repeat("0", 127) + "B", + nBuf: 128, + dst: "A" + strings.Repeat("0", 127) + "B", + nDst: 128, + nSrc: 130, + atEOF: true, + err: transform.ErrShortDst, + nSpan: 0, + errSpan: transform.ErrEndOfSpan, + }, { + desc: "fast path alternation", + src: "fast路徑fast路徑", + nBuf: 20, + dst: "fast路徑fast路徑", + nDst: 20, + nSrc: 20, + atEOF: true, + err: nil, + nSpan: 20, + errSpan: nil, + }} { + tc.doTest(t, Narrow) + } +} + +func bench(b *testing.B, t Transformer, s string) { + dst := make([]byte, 1024) + src := []byte(s) + b.SetBytes(int64(len(src))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + t.Transform(dst, src, true) + } +} + +func changingRunes(f func(r rune) (rune, bool)) string { + buf := &bytes.Buffer{} + for r := rune(0); r <= 0xFFFF; r++ { + if _, ok := foldRune(r); ok { + buf.WriteRune(r) + } + } + return buf.String() +} + +func BenchmarkFoldASCII(b *testing.B) { + bench(b, Fold, testtext.ASCII) +} + +func BenchmarkFoldCJK(b *testing.B) { + bench(b, Fold, testtext.CJK) +} + +func BenchmarkFoldNonCanonical(b *testing.B) { + bench(b, Fold, changingRunes(foldRune)) +} + +func BenchmarkFoldOther(b *testing.B) { + bench(b, Fold, testtext.TwoByteUTF8+testtext.ThreeByteUTF8) +} + +func BenchmarkWideASCII(b *testing.B) { + bench(b, Widen, testtext.ASCII) +} + +func BenchmarkWideCJK(b *testing.B) { + bench(b, Widen, testtext.CJK) +} + +func BenchmarkWideNonCanonical(b *testing.B) { + bench(b, Widen, changingRunes(widenRune)) +} + +func BenchmarkWideOther(b *testing.B) { + bench(b, Widen, testtext.TwoByteUTF8+testtext.ThreeByteUTF8) +} + +func BenchmarkNarrowASCII(b *testing.B) { + bench(b, Narrow, testtext.ASCII) +} + +func BenchmarkNarrowCJK(b *testing.B) { + bench(b, Narrow, testtext.CJK) +} + +func BenchmarkNarrowNonCanonical(b *testing.B) { + bench(b, Narrow, changingRunes(narrowRune)) +} + +func BenchmarkNarrowOther(b *testing.B) { + bench(b, Narrow, testtext.TwoByteUTF8+testtext.ThreeByteUTF8) +} diff --git a/vendor/golang.org/x/time/CONTRIBUTING.md b/vendor/golang.org/x/time/CONTRIBUTING.md new file mode 100644 index 000000000..d0485e887 --- /dev/null +++ b/vendor/golang.org/x/time/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/time/README.md b/vendor/golang.org/x/time/README.md new file mode 100644 index 000000000..ce9becdde --- /dev/null +++ b/vendor/golang.org/x/time/README.md @@ -0,0 +1,17 @@ +# Go Time + +This repository provides supplementary Go time packages. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/time`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/time`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the time repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/time:" in the +subject line, so it is easy to find. diff --git a/vendor/golang.org/x/time/rate/rate_test.go b/vendor/golang.org/x/time/rate/rate_test.go new file mode 100644 index 000000000..ec8c66ddf --- /dev/null +++ b/vendor/golang.org/x/time/rate/rate_test.go @@ -0,0 +1,459 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7 + +package rate + +import ( + "context" + "math" + "runtime" + "sync" + "sync/atomic" + "testing" + "time" +) + +func TestLimit(t *testing.T) { + if Limit(10) == Inf { + t.Errorf("Limit(10) == Inf should be false") + } +} + +func closeEnough(a, b Limit) bool { + return (math.Abs(float64(a)/float64(b)) - 1.0) < 1e-9 +} + +func TestEvery(t *testing.T) { + cases := []struct { + interval time.Duration + lim Limit + }{ + {0, Inf}, + {-1, Inf}, + {1 * time.Nanosecond, Limit(1e9)}, + {1 * time.Microsecond, Limit(1e6)}, + {1 * time.Millisecond, Limit(1e3)}, + {10 * time.Millisecond, Limit(100)}, + {100 * time.Millisecond, Limit(10)}, + {1 * time.Second, Limit(1)}, + {2 * time.Second, Limit(0.5)}, + {time.Duration(2.5 * float64(time.Second)), Limit(0.4)}, + {4 * time.Second, Limit(0.25)}, + {10 * time.Second, Limit(0.1)}, + {time.Duration(math.MaxInt64), Limit(1e9 / float64(math.MaxInt64))}, + } + for _, tc := range cases { + lim := Every(tc.interval) + if !closeEnough(lim, tc.lim) { + t.Errorf("Every(%v) = %v want %v", tc.interval, lim, tc.lim) + } + } +} + +const ( + d = 100 * time.Millisecond +) + +var ( + t0 = time.Now() + t1 = t0.Add(time.Duration(1) * d) + t2 = t0.Add(time.Duration(2) * d) + t3 = t0.Add(time.Duration(3) * d) + t4 = t0.Add(time.Duration(4) * d) + t5 = t0.Add(time.Duration(5) * d) + t9 = t0.Add(time.Duration(9) * d) +) + +type allow struct { + t time.Time + n int + ok bool +} + +func run(t *testing.T, lim *Limiter, allows []allow) { + for i, allow := range allows { + ok := lim.AllowN(allow.t, allow.n) + if ok != allow.ok { + t.Errorf("step %d: lim.AllowN(%v, %v) = %v want %v", + i, allow.t, allow.n, ok, allow.ok) + } + } +} + +func TestLimiterBurst1(t *testing.T) { + run(t, NewLimiter(10, 1), []allow{ + {t0, 1, true}, + {t0, 1, false}, + {t0, 1, false}, + {t1, 1, true}, + {t1, 1, false}, + {t1, 1, false}, + {t2, 2, false}, // burst size is 1, so n=2 always fails + {t2, 1, true}, + {t2, 1, false}, + }) +} + +func TestLimiterBurst3(t *testing.T) { + run(t, NewLimiter(10, 3), []allow{ + {t0, 2, true}, + {t0, 2, false}, + {t0, 1, true}, + {t0, 1, false}, + {t1, 4, false}, + {t2, 1, true}, + {t3, 1, true}, + {t4, 1, true}, + {t4, 1, true}, + {t4, 1, false}, + {t4, 1, false}, + {t9, 3, true}, + {t9, 0, true}, + }) +} + +func TestLimiterJumpBackwards(t *testing.T) { + run(t, NewLimiter(10, 3), []allow{ + {t1, 1, true}, // start at t1 + {t0, 1, true}, // jump back to t0, two tokens remain + {t0, 1, true}, + {t0, 1, false}, + {t0, 1, false}, + {t1, 1, true}, // got a token + {t1, 1, false}, + {t1, 1, false}, + {t2, 1, true}, // got another token + {t2, 1, false}, + {t2, 1, false}, + }) +} + +func TestSimultaneousRequests(t *testing.T) { + const ( + limit = 1 + burst = 5 + numRequests = 15 + ) + var ( + wg sync.WaitGroup + numOK = uint32(0) + ) + + // Very slow replenishing bucket. + lim := NewLimiter(limit, burst) + + // Tries to take a token, atomically updates the counter and decreases the wait + // group counter. + f := func() { + defer wg.Done() + if ok := lim.Allow(); ok { + atomic.AddUint32(&numOK, 1) + } + } + + wg.Add(numRequests) + for i := 0; i < numRequests; i++ { + go f() + } + wg.Wait() + if numOK != burst { + t.Errorf("numOK = %d, want %d", numOK, burst) + } +} + +func TestLongRunningQPS(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + if runtime.GOOS == "openbsd" { + t.Skip("low resolution time.Sleep invalidates test (golang.org/issue/14183)") + return + } + + // The test runs for a few seconds executing many requests and then checks + // that overall number of requests is reasonable. + const ( + limit = 100 + burst = 100 + ) + var numOK = int32(0) + + lim := NewLimiter(limit, burst) + + var wg sync.WaitGroup + f := func() { + if ok := lim.Allow(); ok { + atomic.AddInt32(&numOK, 1) + } + wg.Done() + } + + start := time.Now() + end := start.Add(5 * time.Second) + for time.Now().Before(end) { + wg.Add(1) + go f() + + // This will still offer ~500 requests per second, but won't consume + // outrageous amount of CPU. + time.Sleep(2 * time.Millisecond) + } + wg.Wait() + elapsed := time.Since(start) + ideal := burst + (limit * float64(elapsed) / float64(time.Second)) + + // We should never get more requests than allowed. + if want := int32(ideal + 1); numOK > want { + t.Errorf("numOK = %d, want %d (ideal %f)", numOK, want, ideal) + } + // We should get very close to the number of requests allowed. + if want := int32(0.999 * ideal); numOK < want { + t.Errorf("numOK = %d, want %d (ideal %f)", numOK, want, ideal) + } +} + +type request struct { + t time.Time + n int + act time.Time + ok bool +} + +// dFromDuration converts a duration to a multiple of the global constant d +func dFromDuration(dur time.Duration) int { + // Adding a millisecond to be swallowed by the integer division + // because we don't care about small inaccuracies + return int((dur + time.Millisecond) / d) +} + +// dSince returns multiples of d since t0 +func dSince(t time.Time) int { + return dFromDuration(t.Sub(t0)) +} + +func runReserve(t *testing.T, lim *Limiter, req request) *Reservation { + return runReserveMax(t, lim, req, InfDuration) +} + +func runReserveMax(t *testing.T, lim *Limiter, req request, maxReserve time.Duration) *Reservation { + r := lim.reserveN(req.t, req.n, maxReserve) + if r.ok && (dSince(r.timeToAct) != dSince(req.act)) || r.ok != req.ok { + t.Errorf("lim.reserveN(t%d, %v, %v) = (t%d, %v) want (t%d, %v)", + dSince(req.t), req.n, maxReserve, dSince(r.timeToAct), r.ok, dSince(req.act), req.ok) + } + return &r +} + +func TestSimpleReserve(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + runReserve(t, lim, request{t0, 2, t2, true}) + runReserve(t, lim, request{t3, 2, t4, true}) +} + +func TestMix(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 3, t1, false}) // should return false because n > Burst + runReserve(t, lim, request{t0, 2, t0, true}) + run(t, lim, []allow{{t1, 2, false}}) // not enought tokens - don't allow + runReserve(t, lim, request{t1, 2, t2, true}) + run(t, lim, []allow{{t1, 1, false}}) // negative tokens - don't allow + run(t, lim, []allow{{t3, 1, true}}) +} + +func TestCancelInvalid(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + r := runReserve(t, lim, request{t0, 3, t3, false}) + r.CancelAt(t0) // should have no effect + runReserve(t, lim, request{t0, 2, t2, true}) // did not get extra tokens +} + +func TestCancelLast(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + r := runReserve(t, lim, request{t0, 2, t2, true}) + r.CancelAt(t1) // got 2 tokens back + runReserve(t, lim, request{t1, 2, t2, true}) +} + +func TestCancelTooLate(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + r := runReserve(t, lim, request{t0, 2, t2, true}) + r.CancelAt(t3) // too late to cancel - should have no effect + runReserve(t, lim, request{t3, 2, t4, true}) +} + +func TestCancel0Tokens(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + r := runReserve(t, lim, request{t0, 1, t1, true}) + runReserve(t, lim, request{t0, 1, t2, true}) + r.CancelAt(t0) // got 0 tokens back + runReserve(t, lim, request{t0, 1, t3, true}) +} + +func TestCancel1Token(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + r := runReserve(t, lim, request{t0, 2, t2, true}) + runReserve(t, lim, request{t0, 1, t3, true}) + r.CancelAt(t2) // got 1 token back + runReserve(t, lim, request{t2, 2, t4, true}) +} + +func TestCancelMulti(t *testing.T) { + lim := NewLimiter(10, 4) + + runReserve(t, lim, request{t0, 4, t0, true}) + rA := runReserve(t, lim, request{t0, 3, t3, true}) + runReserve(t, lim, request{t0, 1, t4, true}) + rC := runReserve(t, lim, request{t0, 1, t5, true}) + rC.CancelAt(t1) // get 1 token back + rA.CancelAt(t1) // get 2 tokens back, as if C was never reserved + runReserve(t, lim, request{t1, 3, t5, true}) +} + +func TestReserveJumpBack(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t1, 2, t1, true}) // start at t1 + runReserve(t, lim, request{t0, 1, t1, true}) // should violate Limit,Burst + runReserve(t, lim, request{t2, 2, t3, true}) +} + +func TestReserveJumpBackCancel(t *testing.T) { + lim := NewLimiter(10, 2) + + runReserve(t, lim, request{t1, 2, t1, true}) // start at t1 + r := runReserve(t, lim, request{t1, 2, t3, true}) + runReserve(t, lim, request{t1, 1, t4, true}) + r.CancelAt(t0) // cancel at t0, get 1 token back + runReserve(t, lim, request{t1, 2, t4, true}) // should violate Limit,Burst +} + +func TestReserveSetLimit(t *testing.T) { + lim := NewLimiter(5, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + runReserve(t, lim, request{t0, 2, t4, true}) + lim.SetLimitAt(t2, 10) + runReserve(t, lim, request{t2, 1, t4, true}) // violates Limit and Burst +} + +func TestReserveSetLimitCancel(t *testing.T) { + lim := NewLimiter(5, 2) + + runReserve(t, lim, request{t0, 2, t0, true}) + r := runReserve(t, lim, request{t0, 2, t4, true}) + lim.SetLimitAt(t2, 10) + r.CancelAt(t2) // 2 tokens back + runReserve(t, lim, request{t2, 2, t3, true}) +} + +func TestReserveMax(t *testing.T) { + lim := NewLimiter(10, 2) + maxT := d + + runReserveMax(t, lim, request{t0, 2, t0, true}, maxT) + runReserveMax(t, lim, request{t0, 1, t1, true}, maxT) // reserve for close future + runReserveMax(t, lim, request{t0, 1, t2, false}, maxT) // time to act too far in the future +} + +type wait struct { + name string + ctx context.Context + n int + delay int // in multiples of d + nilErr bool +} + +func runWait(t *testing.T, lim *Limiter, w wait) { + start := time.Now() + err := lim.WaitN(w.ctx, w.n) + delay := time.Now().Sub(start) + if (w.nilErr && err != nil) || (!w.nilErr && err == nil) || w.delay != dFromDuration(delay) { + errString := "<nil>" + if !w.nilErr { + errString = "<non-nil error>" + } + t.Errorf("lim.WaitN(%v, lim, %v) = %v with delay %v ; want %v with delay %v", + w.name, w.n, err, delay, errString, d*time.Duration(w.delay)) + } +} + +func TestWaitSimple(t *testing.T) { + lim := NewLimiter(10, 3) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + runWait(t, lim, wait{"already-cancelled", ctx, 1, 0, false}) + + runWait(t, lim, wait{"exceed-burst-error", context.Background(), 4, 0, false}) + + runWait(t, lim, wait{"act-now", context.Background(), 2, 0, true}) + runWait(t, lim, wait{"act-later", context.Background(), 3, 2, true}) +} + +func TestWaitCancel(t *testing.T) { + lim := NewLimiter(10, 3) + + ctx, cancel := context.WithCancel(context.Background()) + runWait(t, lim, wait{"act-now", ctx, 2, 0, true}) // after this lim.tokens = 1 + go func() { + time.Sleep(d) + cancel() + }() + runWait(t, lim, wait{"will-cancel", ctx, 3, 1, false}) + // should get 3 tokens back, and have lim.tokens = 2 + t.Logf("tokens:%v last:%v lastEvent:%v", lim.tokens, lim.last, lim.lastEvent) + runWait(t, lim, wait{"act-now-after-cancel", context.Background(), 2, 0, true}) +} + +func TestWaitTimeout(t *testing.T) { + lim := NewLimiter(10, 3) + + ctx, cancel := context.WithTimeout(context.Background(), d) + defer cancel() + runWait(t, lim, wait{"act-now", ctx, 2, 0, true}) + runWait(t, lim, wait{"w-timeout-err", ctx, 3, 0, false}) +} + +func TestWaitInf(t *testing.T) { + lim := NewLimiter(Inf, 0) + + runWait(t, lim, wait{"exceed-burst-no-error", context.Background(), 3, 0, true}) +} + +func BenchmarkAllowN(b *testing.B) { + lim := NewLimiter(Every(1*time.Second), 1) + now := time.Now() + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + lim.AllowN(now, 1) + } + }) +} + +func BenchmarkWaitNNoDelay(b *testing.B) { + lim := NewLimiter(Limit(b.N), b.N) + ctx := context.Background() + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + lim.WaitN(ctx, 1) + } +} diff --git a/vendor/golang.org/x/tools/.gitattributes b/vendor/golang.org/x/tools/.gitattributes new file mode 100644 index 000000000..d2f212e5d --- /dev/null +++ b/vendor/golang.org/x/tools/.gitattributes @@ -0,0 +1,10 @@ +# Treat all files in this repo as binary, with no git magic updating +# line endings. Windows users contributing to Go will need to use a +# modern version of git and editors capable of LF line endings. +# +# We'll prevent accidental CRLF line endings from entering the repo +# via the git-review gofmt checks. +# +# See golang.org/issue/9281 + +* -text diff --git a/vendor/golang.org/x/tools/.gitignore b/vendor/golang.org/x/tools/.gitignore new file mode 100644 index 000000000..5a9d62efd --- /dev/null +++ b/vendor/golang.org/x/tools/.gitignore @@ -0,0 +1,2 @@ +# Add no patterns to .gitignore except for files generated by the build. +last-change diff --git a/vendor/golang.org/x/tools/CONTRIBUTING.md b/vendor/golang.org/x/tools/CONTRIBUTING.md new file mode 100644 index 000000000..d0485e887 --- /dev/null +++ b/vendor/golang.org/x/tools/CONTRIBUTING.md @@ -0,0 +1,26 @@ +# Contributing to Go + +Go is an open source project. + +It is the work of hundreds of contributors. We appreciate your help! + +## Filing issues + +When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: + +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. +The gophers there will answer or ask you to file an issue if you've tripped over a bug. + +## Contributing code + +Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) +before sending patches. + +Unless otherwise noted, the Go source files are distributed under +the BSD-style license found in the LICENSE file. diff --git a/vendor/golang.org/x/tools/README.md b/vendor/golang.org/x/tools/README.md new file mode 100644 index 000000000..20be9e1ab --- /dev/null +++ b/vendor/golang.org/x/tools/README.md @@ -0,0 +1,27 @@ +# Go Tools + +This subrepository holds the source for various packages and tools that support +the Go programming language. + +Some of the tools, `godoc` and `vet` for example, are included in binary Go +distributions. + +Others, including the Go `guru` and the test coverage tool, can be fetched with +`go get`. + +Packages include a type-checker for Go and an implementation of the +Static Single Assignment form (SSA) representation for Go programs. + +## Download/Install + +The easiest way to install is to run `go get -u golang.org/x/tools/...`. You can +also manually git clone the repository to `$GOPATH/src/golang.org/x/tools`. + +## Report Issues / Send Patches + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. + +The main issue tracker for the tools repository is located at +https://github.com/golang/go/issues. Prefix your issue with "x/tools/(your +subdir):" in the subject line, so it is easy to find. diff --git a/vendor/golang.org/x/tools/cmd/getgo/LICENSE b/vendor/golang.org/x/tools/cmd/getgo/LICENSE deleted file mode 100644 index 32017f8fa..000000000 --- a/vendor/golang.org/x/tools/cmd/getgo/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2017 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/tools/codereview.cfg b/vendor/golang.org/x/tools/codereview.cfg new file mode 100644 index 000000000..3f8b14b64 --- /dev/null +++ b/vendor/golang.org/x/tools/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/tools/go/ast/astutil/enclosing_test.go b/vendor/golang.org/x/tools/go/ast/astutil/enclosing_test.go new file mode 100644 index 000000000..107f87c55 --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/enclosing_test.go @@ -0,0 +1,195 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutil_test + +// This file defines tests of PathEnclosingInterval. + +// TODO(adonovan): exhaustive tests that run over the whole input +// tree, not just handcrafted examples. + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/token" + "strings" + "testing" + + "golang.org/x/tools/go/ast/astutil" +) + +// pathToString returns a string containing the concrete types of the +// nodes in path. +func pathToString(path []ast.Node) string { + var buf bytes.Buffer + fmt.Fprint(&buf, "[") + for i, n := range path { + if i > 0 { + fmt.Fprint(&buf, " ") + } + fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast.")) + } + fmt.Fprint(&buf, "]") + return buf.String() +} + +// findInterval parses input and returns the [start, end) positions of +// the first occurrence of substr in input. f==nil indicates failure; +// an error has already been reported in that case. +// +func findInterval(t *testing.T, fset *token.FileSet, input, substr string) (f *ast.File, start, end token.Pos) { + f, err := parser.ParseFile(fset, "<input>", input, 0) + if err != nil { + t.Errorf("parse error: %s", err) + return + } + + i := strings.Index(input, substr) + if i < 0 { + t.Errorf("%q is not a substring of input", substr) + f = nil + return + } + + filePos := fset.File(f.Package) + return f, filePos.Pos(i), filePos.Pos(i + len(substr)) +} + +// Common input for following tests. +const input = ` +// Hello. +package main +import "fmt" +func f() {} +func main() { + z := (x + y) // add them + f() // NB: ExprStmt and its CallExpr have same Pos/End +} +` + +func TestPathEnclosingInterval_Exact(t *testing.T) { + // For the exact tests, we check that a substring is mapped to + // the canonical string for the node it denotes. + tests := []struct { + substr string // first occurrence of this string indicates interval + node string // complete text of expected containing node + }{ + {"package", + input[11 : len(input)-1]}, + {"\npack", + input[11 : len(input)-1]}, + {"main", + "main"}, + {"import", + "import \"fmt\""}, + {"\"fmt\"", + "\"fmt\""}, + {"\nfunc f() {}\n", + "func f() {}"}, + {"x ", + "x"}, + {" y", + "y"}, + {"z", + "z"}, + {" + ", + "x + y"}, + {" :=", + "z := (x + y)"}, + {"x + y", + "x + y"}, + {"(x + y)", + "(x + y)"}, + {" (x + y) ", + "(x + y)"}, + {" (x + y) // add", + "(x + y)"}, + {"func", + "func f() {}"}, + {"func f() {}", + "func f() {}"}, + {"\nfun", + "func f() {}"}, + {" f", + "f"}, + } + for _, test := range tests { + f, start, end := findInterval(t, new(token.FileSet), input, test.substr) + if f == nil { + continue + } + + path, exact := astutil.PathEnclosingInterval(f, start, end) + if !exact { + t.Errorf("PathEnclosingInterval(%q) not exact", test.substr) + continue + } + + if len(path) == 0 { + if test.node != "" { + t.Errorf("PathEnclosingInterval(%q).path: got [], want %q", + test.substr, test.node) + } + continue + } + + if got := input[path[0].Pos():path[0].End()]; got != test.node { + t.Errorf("PathEnclosingInterval(%q): got %q, want %q (path was %s)", + test.substr, got, test.node, pathToString(path)) + continue + } + } +} + +func TestPathEnclosingInterval_Paths(t *testing.T) { + // For these tests, we check only the path of the enclosing + // node, but not its complete text because it's often quite + // large when !exact. + tests := []struct { + substr string // first occurrence of this string indicates interval + path string // the pathToString(),exact of the expected path + }{ + {"// add", + "[BlockStmt FuncDecl File],false"}, + {"(x + y", + "[ParenExpr AssignStmt BlockStmt FuncDecl File],false"}, + {"x +", + "[BinaryExpr ParenExpr AssignStmt BlockStmt FuncDecl File],false"}, + {"z := (x", + "[AssignStmt BlockStmt FuncDecl File],false"}, + {"func f", + "[FuncDecl File],false"}, + {"func f()", + "[FuncDecl File],false"}, + {" f()", + "[FuncDecl File],false"}, + {"() {}", + "[FuncDecl File],false"}, + {"// Hello", + "[File],false"}, + {" f", + "[Ident FuncDecl File],true"}, + {"func ", + "[FuncDecl File],true"}, + {"mai", + "[Ident File],true"}, + {"f() // NB", + "[CallExpr ExprStmt BlockStmt FuncDecl File],true"}, + } + for _, test := range tests { + f, start, end := findInterval(t, new(token.FileSet), input, test.substr) + if f == nil { + continue + } + + path, exact := astutil.PathEnclosingInterval(f, start, end) + if got := fmt.Sprintf("%s,%v", pathToString(path), exact); got != test.path { + t.Errorf("PathEnclosingInterval(%q): got %q, want %q", + test.substr, got, test.path) + continue + } + } +} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/imports_test.go b/vendor/golang.org/x/tools/go/ast/astutil/imports_test.go new file mode 100644 index 000000000..8bc348087 --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/imports_test.go @@ -0,0 +1,1818 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutil + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "reflect" + "strconv" + "testing" +) + +var fset = token.NewFileSet() + +func parse(t *testing.T, name, in string) *ast.File { + file, err := parser.ParseFile(fset, name, in, parser.ParseComments) + if err != nil { + t.Fatalf("%s parse: %v", name, err) + } + return file +} + +func print(t *testing.T, name string, f *ast.File) string { + var buf bytes.Buffer + if err := format.Node(&buf, fset, f); err != nil { + t.Fatalf("%s gofmt: %v", name, err) + } + return string(buf.Bytes()) +} + +type test struct { + name string + renamedPkg string + pkg string + in string + out string + broken bool // known broken +} + +var addTests = []test{ + { + name: "leave os alone", + pkg: "os", + in: `package main + +import ( + "os" +) +`, + out: `package main + +import ( + "os" +) +`, + }, + { + name: "import.1", + pkg: "os", + in: `package main +`, + out: `package main + +import "os" +`, + }, + { + name: "import.2", + pkg: "os", + in: `package main + +// Comment +import "C" +`, + out: `package main + +// Comment +import "C" +import "os" +`, + }, + { + name: "import.3", + pkg: "os", + in: `package main + +// Comment +import "C" + +import ( + "io" + "utf8" +) +`, + out: `package main + +// Comment +import "C" + +import ( + "io" + "os" + "utf8" +) +`, + }, + { + name: "import.17", + pkg: "x/y/z", + in: `package main + +// Comment +import "C" + +import ( + "a" + "b" + + "x/w" + + "d/f" +) +`, + out: `package main + +// Comment +import "C" + +import ( + "a" + "b" + + "x/w" + "x/y/z" + + "d/f" +) +`, + }, + { + name: "issue #19190", + pkg: "x.org/y/z", + in: `package main + +// Comment +import "C" + +import ( + "bytes" + "os" + + "d.com/f" +) +`, + out: `package main + +// Comment +import "C" + +import ( + "bytes" + "os" + + "d.com/f" + "x.org/y/z" +) +`, + }, + { + name: "issue #19190 with existing grouped import packages", + pkg: "x.org/y/z", + in: `package main + +// Comment +import "C" + +import ( + "bytes" + "os" + + "c.com/f" + "d.com/f" + + "y.com/a" + "y.com/b" + "y.com/c" +) +`, + out: `package main + +// Comment +import "C" + +import ( + "bytes" + "os" + + "c.com/f" + "d.com/f" + "x.org/y/z" + + "y.com/a" + "y.com/b" + "y.com/c" +) +`, + }, + { + name: "issue #19190 - match score is still respected", + pkg: "y.org/c", + in: `package main + +import ( + "x.org/a" + + "y.org/b" +) +`, + out: `package main + +import ( + "x.org/a" + + "y.org/b" + "y.org/c" +) +`, + }, + { + name: "import into singular group", + pkg: "bytes", + in: `package main + +import "os" + +`, + out: `package main + +import ( + "bytes" + "os" +) +`, + }, + { + name: "import into singular group with comment", + pkg: "bytes", + in: `package main + +import /* why */ /* comment here? */ "os" + +`, + out: `package main + +import /* why */ /* comment here? */ ( + "bytes" + "os" +) +`, + }, + { + name: "import into group with leading comment", + pkg: "strings", + in: `package main + +import ( + // comment before bytes + "bytes" + "os" +) + +`, + out: `package main + +import ( + // comment before bytes + "bytes" + "os" + "strings" +) +`, + }, + { + name: "", + renamedPkg: "fmtpkg", + pkg: "fmt", + in: `package main + +import "os" + +`, + out: `package main + +import ( + fmtpkg "fmt" + "os" +) +`, + }, + { + name: "struct comment", + pkg: "time", + in: `package main + +// This is a comment before a struct. +type T struct { + t time.Time +} +`, + out: `package main + +import "time" + +// This is a comment before a struct. +type T struct { + t time.Time +} +`, + }, + { + name: "issue 8729 import C", + pkg: "time", + in: `package main + +import "C" + +// comment +type T time.Time +`, + out: `package main + +import "C" +import "time" + +// comment +type T time.Time +`, + }, + { + name: "issue 8729 empty import", + pkg: "time", + in: `package main + +import () + +// comment +type T time.Time +`, + out: `package main + +import "time" + +// comment +type T time.Time +`, + }, + { + name: "issue 8729 comment on package line", + pkg: "time", + in: `package main // comment + +type T time.Time +`, + out: `package main // comment +import "time" + +type T time.Time +`, + }, + { + name: "issue 8729 comment after package", + pkg: "time", + in: `package main +// comment + +type T time.Time +`, + out: `package main + +import "time" + +// comment + +type T time.Time +`, + }, + { + name: "issue 8729 comment before and on package line", + pkg: "time", + in: `// comment before +package main // comment on + +type T time.Time +`, + out: `// comment before +package main // comment on +import "time" + +type T time.Time +`, + }, + + // Issue 9961: Match prefixes using path segments rather than bytes + { + name: "issue 9961", + pkg: "regexp", + in: `package main + +import ( + "flag" + "testing" + + "rsc.io/p" +) +`, + out: `package main + +import ( + "flag" + "regexp" + "testing" + + "rsc.io/p" +) +`, + }, + // Issue 10337: Preserve comment position + { + name: "issue 10337", + pkg: "fmt", + in: `package main + +import ( + "bytes" // a + "log" // c +) +`, + out: `package main + +import ( + "bytes" // a + "fmt" + "log" // c +) +`, + }, + { + name: "issue 10337 new import at the start", + pkg: "bytes", + in: `package main + +import ( + "fmt" // b + "log" // c +) +`, + out: `package main + +import ( + "bytes" + "fmt" // b + "log" // c +) +`, + }, + { + name: "issue 10337 new import at the end", + pkg: "log", + in: `package main + +import ( + "bytes" // a + "fmt" // b +) +`, + out: `package main + +import ( + "bytes" // a + "fmt" // b + "log" +) +`, + }, + // Issue 14075: Merge import declarations + { + name: "issue 14075", + pkg: "bufio", + in: `package main + +import "bytes" +import "fmt" +`, + out: `package main + +import ( + "bufio" + "bytes" + "fmt" +) +`, + }, + { + name: "issue 14075 update position", + pkg: "bufio", + in: `package main + +import "bytes" +import ( + "fmt" +) +`, + out: `package main + +import ( + "bufio" + "bytes" + "fmt" +) +`, + }, + { + name: `issue 14075 ignore import "C"`, + pkg: "bufio", + in: `package main + +// Comment +import "C" + +import "bytes" +import "fmt" +`, + out: `package main + +// Comment +import "C" + +import ( + "bufio" + "bytes" + "fmt" +) +`, + }, + { + name: `issue 14075 ignore adjacent import "C"`, + pkg: "bufio", + in: `package main + +// Comment +import "C" +import "fmt" +`, + out: `package main + +// Comment +import "C" +import ( + "bufio" + "fmt" +) +`, + }, + { + name: `issue 14075 ignore adjacent import "C" (without factored import)`, + pkg: "bufio", + in: `package main + +// Comment +import "C" +import "fmt" +`, + out: `package main + +// Comment +import "C" +import ( + "bufio" + "fmt" +) +`, + }, + { + name: `issue 14075 ignore single import "C"`, + pkg: "bufio", + in: `package main + +// Comment +import "C" +`, + out: `package main + +// Comment +import "C" +import "bufio" +`, + }, + { + name: `issue 17212 several single-import lines with shared prefix ending in a slash`, + pkg: "net/http", + in: `package main + +import "bufio" +import "net/url" +`, + out: `package main + +import ( + "bufio" + "net/http" + "net/url" +) +`, + }, + { + name: `issue 17212 block imports lines with shared prefix ending in a slash`, + pkg: "net/http", + in: `package main + +import ( + "bufio" + "net/url" +) +`, + out: `package main + +import ( + "bufio" + "net/http" + "net/url" +) +`, + }, + { + name: `issue 17213 many single-import lines`, + pkg: "fmt", + in: `package main + +import "bufio" +import "bytes" +import "errors" +`, + out: `package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" +) +`, + }, +} + +func TestAddImport(t *testing.T) { + for _, test := range addTests { + file := parse(t, test.name, test.in) + var before bytes.Buffer + ast.Fprint(&before, fset, file, nil) + AddNamedImport(fset, file, test.renamedPkg, test.pkg) + if got := print(t, test.name, file); got != test.out { + if test.broken { + t.Logf("%s is known broken:\ngot: %s\nwant: %s", test.name, got, test.out) + } else { + t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out) + } + var after bytes.Buffer + ast.Fprint(&after, fset, file, nil) + + t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String()) + } + } +} + +func TestDoubleAddImport(t *testing.T) { + file := parse(t, "doubleimport", "package main\n") + AddImport(fset, file, "os") + AddImport(fset, file, "bytes") + want := `package main + +import ( + "bytes" + "os" +) +` + if got := print(t, "doubleimport", file); got != want { + t.Errorf("got: %s\nwant: %s", got, want) + } +} + +func TestDoubleAddNamedImport(t *testing.T) { + file := parse(t, "doublenamedimport", "package main\n") + AddNamedImport(fset, file, "o", "os") + AddNamedImport(fset, file, "i", "io") + want := `package main + +import ( + i "io" + o "os" +) +` + if got := print(t, "doublenamedimport", file); got != want { + t.Errorf("got: %s\nwant: %s", got, want) + } +} + +// Part of issue 8729. +func TestDoubleAddImportWithDeclComment(t *testing.T) { + file := parse(t, "doubleimport", `package main + +import ( +) + +// comment +type I int +`) + // The AddImport order here matters. + AddImport(fset, file, "golang.org/x/tools/go/ast/astutil") + AddImport(fset, file, "os") + want := `package main + +import ( + "golang.org/x/tools/go/ast/astutil" + "os" +) + +// comment +type I int +` + if got := print(t, "doubleimport_with_decl_comment", file); got != want { + t.Errorf("got: %s\nwant: %s", got, want) + } +} + +var deleteTests = []test{ + { + name: "import.4", + pkg: "os", + in: `package main + +import ( + "os" +) +`, + out: `package main +`, + }, + { + name: "import.5", + pkg: "os", + in: `package main + +// Comment +import "C" +import "os" +`, + out: `package main + +// Comment +import "C" +`, + }, + { + name: "import.6", + pkg: "os", + in: `package main + +// Comment +import "C" + +import ( + "io" + "os" + "utf8" +) +`, + out: `package main + +// Comment +import "C" + +import ( + "io" + "utf8" +) +`, + }, + { + name: "import.7", + pkg: "io", + in: `package main + +import ( + "io" // a + "os" // b + "utf8" // c +) +`, + out: `package main + +import ( + // a + "os" // b + "utf8" // c +) +`, + }, + { + name: "import.8", + pkg: "os", + in: `package main + +import ( + "io" // a + "os" // b + "utf8" // c +) +`, + out: `package main + +import ( + "io" // a + // b + "utf8" // c +) +`, + }, + { + name: "import.9", + pkg: "utf8", + in: `package main + +import ( + "io" // a + "os" // b + "utf8" // c +) +`, + out: `package main + +import ( + "io" // a + "os" // b + // c +) +`, + }, + { + name: "import.10", + pkg: "io", + in: `package main + +import ( + "io" + "os" + "utf8" +) +`, + out: `package main + +import ( + "os" + "utf8" +) +`, + }, + { + name: "import.11", + pkg: "os", + in: `package main + +import ( + "io" + "os" + "utf8" +) +`, + out: `package main + +import ( + "io" + "utf8" +) +`, + }, + { + name: "import.12", + pkg: "utf8", + in: `package main + +import ( + "io" + "os" + "utf8" +) +`, + out: `package main + +import ( + "io" + "os" +) +`, + }, + { + name: "handle.raw.quote.imports", + pkg: "os", + in: "package main\n\nimport `os`", + out: `package main +`, + }, + { + name: "import.13", + pkg: "io", + in: `package main + +import ( + "fmt" + + "io" + "os" + "utf8" + + "go/format" +) +`, + out: `package main + +import ( + "fmt" + + "os" + "utf8" + + "go/format" +) +`, + }, + { + name: "import.14", + pkg: "io", + in: `package main + +import ( + "fmt" // a + + "io" // b + "os" // c + "utf8" // d + + "go/format" // e +) +`, + out: `package main + +import ( + "fmt" // a + + // b + "os" // c + "utf8" // d + + "go/format" // e +) +`, + }, + { + name: "import.15", + pkg: "double", + in: `package main + +import ( + "double" + "double" +) +`, + out: `package main +`, + }, + { + name: "import.16", + pkg: "bubble", + in: `package main + +import ( + "toil" + "bubble" + "bubble" + "trouble" +) +`, + out: `package main + +import ( + "toil" + "trouble" +) +`, + }, + { + name: "import.17", + pkg: "quad", + in: `package main + +import ( + "quad" + "quad" +) + +import ( + "quad" + "quad" +) +`, + out: `package main +`, + }, + { + name: "import.18", + renamedPkg: "x", + pkg: "fmt", + in: `package main + +import ( + "fmt" + x "fmt" +) +`, + out: `package main + +import ( + "fmt" +) +`, + }, + { + name: "import.18", + renamedPkg: "x", + pkg: "fmt", + in: `package main + +import x "fmt" +import y "fmt" +`, + out: `package main + +import y "fmt" +`, + }, + // Issue #15432, #18051 + { + name: "import.19", + pkg: "fmt", + in: `package main + +import ( + "fmt" + + // Some comment. + "io" +)`, + out: `package main + +import ( + // Some comment. + "io" +) +`, + }, + { + name: "import.20", + pkg: "fmt", + in: `package main + +import ( + "fmt" + + // Some + // comment. + "io" +)`, + out: `package main + +import ( + // Some + // comment. + "io" +) +`, + }, + { + name: "import.21", + pkg: "fmt", + in: `package main + +import ( + "fmt" + + /* + Some + comment. + */ + "io" +)`, + out: `package main + +import ( + /* + Some + comment. + */ + "io" +) +`, + }, + { + name: "import.22", + pkg: "fmt", + in: `package main + +import ( + /* Some */ + // comment. + "io" + "fmt" +)`, + out: `package main + +import ( + /* Some */ + // comment. + "io" +) +`, + }, + { + name: "import.23", + pkg: "fmt", + in: `package main + +import ( + // comment 1 + "fmt" + // comment 2 + "io" +)`, + out: `package main + +import ( + // comment 2 + "io" +) +`, + }, + { + name: "import.24", + pkg: "fmt", + in: `package main + +import ( + "fmt" // comment 1 + "io" // comment 2 +)`, + out: `package main + +import ( + "io" // comment 2 +) +`, + }, + { + name: "import.25", + pkg: "fmt", + in: `package main + +import ( + "fmt" + /* comment */ "io" +)`, + out: `package main + +import ( + /* comment */ "io" +) +`, + }, + { + name: "import.26", + pkg: "fmt", + in: `package main + +import ( + "fmt" + "io" /* comment */ +)`, + out: `package main + +import ( + "io" /* comment */ +) +`, + }, + { + name: "import.27", + pkg: "fmt", + in: `package main + +import ( + "fmt" /* comment */ + "io" +)`, + out: `package main + +import ( + "io" +) +`, + }, + { + name: "import.28", + pkg: "fmt", + in: `package main + +import ( + /* comment */ "fmt" + "io" +)`, + out: `package main + +import ( + "io" +) +`, + }, + { + name: "import.29", + pkg: "fmt", + in: `package main + +// comment 1 +import ( + "fmt" + "io" // comment 2 +)`, + out: `package main + +// comment 1 +import ( + "io" // comment 2 +) +`, + }, + { + name: "import.30", + pkg: "fmt", + in: `package main + +// comment 1 +import ( + "fmt" // comment 2 + "io" +)`, + out: `package main + +// comment 1 +import ( + "io" +) +`, + }, + { + name: "import.31", + pkg: "fmt", + in: `package main + +// comment 1 +import ( + "fmt" + /* comment 2 */ "io" +)`, + out: `package main + +// comment 1 +import ( + /* comment 2 */ "io" +) +`, + }, + { + name: "import.32", + pkg: "fmt", + renamedPkg: "f", + in: `package main + +// comment 1 +import ( + f "fmt" + /* comment 2 */ i "io" +)`, + out: `package main + +// comment 1 +import ( + /* comment 2 */ i "io" +) +`, + }, + { + name: "import.33", + pkg: "fmt", + renamedPkg: "f", + in: `package main + +// comment 1 +import ( + /* comment 2 */ f "fmt" + i "io" +)`, + out: `package main + +// comment 1 +import ( + i "io" +) +`, + }, + { + name: "import.34", + pkg: "fmt", + renamedPkg: "f", + in: `package main + +// comment 1 +import ( + f "fmt" /* comment 2 */ + i "io" +)`, + out: `package main + +// comment 1 +import ( + i "io" +) +`, + }, + { + name: "import.35", + pkg: "fmt", + in: `package main + +// comment 1 +import ( + "fmt" + // comment 2 + "io" +)`, + out: `package main + +// comment 1 +import ( + // comment 2 + "io" +) +`, + }, + { + name: "import.36", + pkg: "fmt", + in: `package main + +/* comment 1 */ +import ( + "fmt" + /* comment 2 */ + "io" +)`, + out: `package main + +/* comment 1 */ +import ( + /* comment 2 */ + "io" +) +`, + }, + + // Issue 20229: MergeLine panic on weird input + { + name: "import.37", + pkg: "io", + in: `package main +import("_" +"io")`, + out: `package main + +import ( + "_" +) +`, + }, +} + +func TestDeleteImport(t *testing.T) { + for _, test := range deleteTests { + file := parse(t, test.name, test.in) + DeleteNamedImport(fset, file, test.renamedPkg, test.pkg) + if got := print(t, test.name, file); got != test.out { + t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out) + } + } +} + +type rewriteTest struct { + name string + srcPkg string + dstPkg string + in string + out string +} + +var rewriteTests = []rewriteTest{ + { + name: "import.13", + srcPkg: "utf8", + dstPkg: "encoding/utf8", + in: `package main + +import ( + "io" + "os" + "utf8" // thanks ken +) +`, + out: `package main + +import ( + "encoding/utf8" // thanks ken + "io" + "os" +) +`, + }, + { + name: "import.14", + srcPkg: "asn1", + dstPkg: "encoding/asn1", + in: `package main + +import ( + "asn1" + "crypto" + "crypto/rsa" + _ "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "time" +) + +var x = 1 +`, + out: `package main + +import ( + "crypto" + "crypto/rsa" + _ "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "time" +) + +var x = 1 +`, + }, + { + name: "import.15", + srcPkg: "url", + dstPkg: "net/url", + in: `package main + +import ( + "bufio" + "net" + "path" + "url" +) + +var x = 1 // comment on x, not on url +`, + out: `package main + +import ( + "bufio" + "net" + "net/url" + "path" +) + +var x = 1 // comment on x, not on url +`, + }, + { + name: "import.16", + srcPkg: "http", + dstPkg: "net/http", + in: `package main + +import ( + "flag" + "http" + "log" + "text/template" +) + +var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 +`, + out: `package main + +import ( + "flag" + "log" + "net/http" + "text/template" +) + +var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 +`, + }, +} + +func TestRewriteImport(t *testing.T) { + for _, test := range rewriteTests { + file := parse(t, test.name, test.in) + RewriteImport(fset, file, test.srcPkg, test.dstPkg) + if got := print(t, test.name, file); got != test.out { + t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out) + } + } +} + +var importsTests = []struct { + name string + in string + want [][]string +}{ + { + name: "no packages", + in: `package foo +`, + want: nil, + }, + { + name: "one group", + in: `package foo + +import ( + "fmt" + "testing" +) +`, + want: [][]string{{"fmt", "testing"}}, + }, + { + name: "four groups", + in: `package foo + +import "C" +import ( + "fmt" + "testing" + + "appengine" + + "myproject/mylib1" + "myproject/mylib2" +) +`, + want: [][]string{ + {"C"}, + {"fmt", "testing"}, + {"appengine"}, + {"myproject/mylib1", "myproject/mylib2"}, + }, + }, + { + name: "multiple factored groups", + in: `package foo + +import ( + "fmt" + "testing" + + "appengine" +) +import ( + "reflect" + + "bytes" +) +`, + want: [][]string{ + {"fmt", "testing"}, + {"appengine"}, + {"reflect"}, + {"bytes"}, + }, + }, +} + +func unquote(s string) string { + res, err := strconv.Unquote(s) + if err != nil { + return "could_not_unquote" + } + return res +} + +func TestImports(t *testing.T) { + fset := token.NewFileSet() + for _, test := range importsTests { + f, err := parser.ParseFile(fset, "test.go", test.in, 0) + if err != nil { + t.Errorf("%s: %v", test.name, err) + continue + } + var got [][]string + for _, group := range Imports(fset, f) { + var b []string + for _, spec := range group { + b = append(b, unquote(spec.Path.Value)) + } + got = append(got, b) + } + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Imports(%s)=%v, want %v", test.name, got, test.want) + } + } +} + +var usesImportTests = []struct { + name string + path string + in string + want bool +}{ + { + name: "no packages", + path: "io", + in: `package foo +`, + want: false, + }, + { + name: "import.1", + path: "io", + in: `package foo + +import "io" + +var _ io.Writer +`, + want: true, + }, + { + name: "import.2", + path: "io", + in: `package foo + +import "io" +`, + want: false, + }, + { + name: "import.3", + path: "io", + in: `package foo + +import "io" + +var io = 42 +`, + want: false, + }, + { + name: "import.4", + path: "io", + in: `package foo + +import i "io" + +var _ i.Writer +`, + want: true, + }, + { + name: "import.5", + path: "io", + in: `package foo + +import i "io" +`, + want: false, + }, + { + name: "import.6", + path: "io", + in: `package foo + +import i "io" + +var i = 42 +var io = 42 +`, + want: false, + }, + { + name: "import.7", + path: "encoding/json", + in: `package foo + +import "encoding/json" + +var _ json.Encoder +`, + want: true, + }, + { + name: "import.8", + path: "encoding/json", + in: `package foo + +import "encoding/json" +`, + want: false, + }, + { + name: "import.9", + path: "encoding/json", + in: `package foo + +import "encoding/json" + +var json = 42 +`, + want: false, + }, + { + name: "import.10", + path: "encoding/json", + in: `package foo + +import j "encoding/json" + +var _ j.Encoder +`, + want: true, + }, + { + name: "import.11", + path: "encoding/json", + in: `package foo + +import j "encoding/json" +`, + want: false, + }, + { + name: "import.12", + path: "encoding/json", + in: `package foo + +import j "encoding/json" + +var j = 42 +var json = 42 +`, + want: false, + }, + { + name: "import.13", + path: "io", + in: `package foo + +import _ "io" +`, + want: true, + }, + { + name: "import.14", + path: "io", + in: `package foo + +import . "io" +`, + want: true, + }, +} + +func TestUsesImport(t *testing.T) { + fset := token.NewFileSet() + for _, test := range usesImportTests { + f, err := parser.ParseFile(fset, "test.go", test.in, 0) + if err != nil { + t.Errorf("%s: %v", test.name, err) + continue + } + got := UsesImport(f, test.path) + if got != test.want { + t.Errorf("UsesImport(%s)=%v, want %v", test.name, got, test.want) + } + } +} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/rewrite_test.go b/vendor/golang.org/x/tools/go/ast/astutil/rewrite_test.go new file mode 100644 index 000000000..1c86970ff --- /dev/null +++ b/vendor/golang.org/x/tools/go/ast/astutil/rewrite_test.go @@ -0,0 +1,248 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package astutil_test + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "testing" + + "golang.org/x/tools/go/ast/astutil" +) + +var rewriteTests = [...]struct { + name string + orig, want string + pre, post astutil.ApplyFunc +}{ + {name: "nop", orig: "package p\n", want: "package p\n"}, + + {name: "replace", + orig: `package p + +var x int +`, + want: `package p + +var t T +`, + post: func(c *astutil.Cursor) bool { + if _, ok := c.Node().(*ast.ValueSpec); ok { + c.Replace(valspec("t", "T")) + return false + } + return true + }, + }, + + {name: "set doc strings", + orig: `package p + +const z = 0 + +type T struct{} + +var x int +`, + want: `package p +// a foo is a foo +const z = 0 +// a foo is a foo +type T struct{} +// a foo is a foo +var x int +`, + post: func(c *astutil.Cursor) bool { + if _, ok := c.Parent().(*ast.GenDecl); ok && c.Name() == "Doc" && c.Node() == nil { + c.Replace(&ast.CommentGroup{List: []*ast.Comment{{Text: "// a foo is a foo"}}}) + } + return true + }, + }, + + {name: "insert names", + orig: `package p + +const a = 1 +`, + want: `package p + +const a, b, c = 1, 2, 3 +`, + pre: func(c *astutil.Cursor) bool { + if _, ok := c.Parent().(*ast.ValueSpec); ok { + switch c.Name() { + case "Names": + c.InsertAfter(ast.NewIdent("c")) + c.InsertAfter(ast.NewIdent("b")) + case "Values": + c.InsertAfter(&ast.BasicLit{Kind: token.INT, Value: "3"}) + c.InsertAfter(&ast.BasicLit{Kind: token.INT, Value: "2"}) + } + } + return true + }, + }, + + {name: "insert", + orig: `package p + +var ( + x int + y int +) +`, + want: `package p + +var before1 int +var before2 int + +var ( + x int + y int +) +var after2 int +var after1 int +`, + pre: func(c *astutil.Cursor) bool { + if _, ok := c.Node().(*ast.GenDecl); ok { + c.InsertBefore(vardecl("before1", "int")) + c.InsertAfter(vardecl("after1", "int")) + c.InsertAfter(vardecl("after2", "int")) + c.InsertBefore(vardecl("before2", "int")) + } + return true + }, + }, + + {name: "delete", + orig: `package p + +var x int +var y int +var z int +`, + want: `package p + +var y int +var z int +`, + pre: func(c *astutil.Cursor) bool { + n := c.Node() + if d, ok := n.(*ast.GenDecl); ok && d.Specs[0].(*ast.ValueSpec).Names[0].Name == "x" { + c.Delete() + } + return true + }, + }, + + {name: "insertafter-delete", + orig: `package p + +var x int +var y int +var z int +`, + want: `package p + +var x1 int + +var y int +var z int +`, + pre: func(c *astutil.Cursor) bool { + n := c.Node() + if d, ok := n.(*ast.GenDecl); ok && d.Specs[0].(*ast.ValueSpec).Names[0].Name == "x" { + c.InsertAfter(vardecl("x1", "int")) + c.Delete() + } + return true + }, + }, + + {name: "delete-insertafter", + orig: `package p + +var x int +var y int +var z int +`, + want: `package p + +var y int +var x1 int +var z int +`, + pre: func(c *astutil.Cursor) bool { + n := c.Node() + if d, ok := n.(*ast.GenDecl); ok && d.Specs[0].(*ast.ValueSpec).Names[0].Name == "x" { + c.Delete() + // The cursor is now effectively atop the 'var y int' node. + c.InsertAfter(vardecl("x1", "int")) + } + return true + }, + }, +} + +func valspec(name, typ string) *ast.ValueSpec { + return &ast.ValueSpec{Names: []*ast.Ident{ast.NewIdent(name)}, + Type: ast.NewIdent(typ), + } +} + +func vardecl(name, typ string) *ast.GenDecl { + return &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{valspec(name, typ)}, + } +} + +func TestRewrite(t *testing.T) { + t.Run("*", func(t *testing.T) { + for _, test := range rewriteTests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, test.name, test.orig, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + n := astutil.Apply(f, test.pre, test.post) + var buf bytes.Buffer + if err := format.Node(&buf, fset, n); err != nil { + t.Fatal(err) + } + got := buf.String() + if got != test.want { + t.Errorf("got:\n\n%s\nwant:\n\n%s\n", got, test.want) + } + }) + } + }) +} + +var sink ast.Node + +func BenchmarkRewrite(b *testing.B) { + for _, test := range rewriteTests { + b.Run(test.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + b.StopTimer() + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, test.name, test.orig, parser.ParseComments) + if err != nil { + b.Fatal(err) + } + b.StartTimer() + sink = astutil.Apply(f, test.pre, test.post) + } + }) + } +} diff --git a/vendor/golang.org/x/tools/imports/fix_test.go b/vendor/golang.org/x/tools/imports/fix_test.go new file mode 100644 index 000000000..62c6f3c32 --- /dev/null +++ b/vendor/golang.org/x/tools/imports/fix_test.go @@ -0,0 +1,2175 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package imports + +import ( + "bytes" + "context" + "flag" + "go/build" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + "testing" +) + +var only = flag.String("only", "", "If non-empty, the fix test to run") + +var tests = []struct { + name string + formatOnly bool + in, out string +}{ + // Adding an import to an existing parenthesized import + { + name: "factored_imports_add", + in: `package foo +import ( + "fmt" +) +func bar() { +var b bytes.Buffer +fmt.Println(b.String()) +} +`, + out: `package foo + +import ( + "bytes" + "fmt" +) + +func bar() { + var b bytes.Buffer + fmt.Println(b.String()) +} +`, + }, + + // Adding an import to an existing parenthesized import, + // verifying it goes into the first section. + { + name: "factored_imports_add_first_sec", + in: `package foo +import ( + "fmt" + + "appengine" +) +func bar() { +var b bytes.Buffer +_ = appengine.IsDevServer +fmt.Println(b.String()) +} +`, + out: `package foo + +import ( + "bytes" + "fmt" + + "appengine" +) + +func bar() { + var b bytes.Buffer + _ = appengine.IsDevServer + fmt.Println(b.String()) +} +`, + }, + + // Adding an import to an existing parenthesized import, + // verifying it goes into the first section. (test 2) + { + name: "factored_imports_add_first_sec_2", + in: `package foo +import ( + "fmt" + + "appengine" +) +func bar() { +_ = math.NaN +_ = fmt.Sprintf +_ = appengine.IsDevServer +} +`, + out: `package foo + +import ( + "fmt" + "math" + + "appengine" +) + +func bar() { + _ = math.NaN + _ = fmt.Sprintf + _ = appengine.IsDevServer +} +`, + }, + + // Adding a new import line, without parens + { + name: "add_import_section", + in: `package foo +func bar() { +var b bytes.Buffer +} +`, + out: `package foo + +import "bytes" + +func bar() { + var b bytes.Buffer +} +`, + }, + + // Adding two new imports, which should make a parenthesized import decl. + { + name: "add_import_paren_section", + in: `package foo +func bar() { +_, _ := bytes.Buffer, zip.NewReader +} +`, + out: `package foo + +import ( + "archive/zip" + "bytes" +) + +func bar() { + _, _ := bytes.Buffer, zip.NewReader +} +`, + }, + + // Make sure we don't add things twice + { + name: "no_double_add", + in: `package foo +func bar() { +_, _ := bytes.Buffer, bytes.NewReader +} +`, + out: `package foo + +import "bytes" + +func bar() { + _, _ := bytes.Buffer, bytes.NewReader +} +`, + }, + + // Remove unused imports, 1 of a factored block + { + name: "remove_unused_1_of_2", + in: `package foo +import ( +"bytes" +"fmt" +) + +func bar() { +_, _ := bytes.Buffer, bytes.NewReader +} +`, + out: `package foo + +import ( + "bytes" +) + +func bar() { + _, _ := bytes.Buffer, bytes.NewReader +} +`, + }, + + // Remove unused imports, 2 of 2 + { + name: "remove_unused_2_of_2", + in: `package foo +import ( +"bytes" +"fmt" +) + +func bar() { +} +`, + out: `package foo + +func bar() { +} +`, + }, + + // Remove unused imports, 1 of 1 + { + name: "remove_unused_1_of_1", + in: `package foo + +import "fmt" + +func bar() { +} +`, + out: `package foo + +func bar() { +} +`, + }, + + // Don't remove empty imports. + { + name: "dont_remove_empty_imports", + in: `package foo +import ( +_ "image/png" +_ "image/jpeg" +) +`, + out: `package foo + +import ( + _ "image/jpeg" + _ "image/png" +) +`, + }, + + // Don't remove dot imports. + { + name: "dont_remove_dot_imports", + in: `package foo +import ( +. "foo" +. "bar" +) +`, + out: `package foo + +import ( + . "bar" + . "foo" +) +`, + }, + + // Skip refs the parser can resolve. + { + name: "skip_resolved_refs", + in: `package foo + +func f() { + type t struct{ Println func(string) } + fmt := t{Println: func(string) {}} + fmt.Println("foo") +} +`, + out: `package foo + +func f() { + type t struct{ Println func(string) } + fmt := t{Println: func(string) {}} + fmt.Println("foo") +} +`, + }, + + // Do not add a package we already have a resolution for. + { + name: "skip_template", + in: `package foo + +import "html/template" + +func f() { t = template.New("sometemplate") } +`, + out: `package foo + +import "html/template" + +func f() { t = template.New("sometemplate") } +`, + }, + + // Don't touch cgo + { + name: "cgo", + in: `package foo + +/* +#include <foo.h> +*/ +import "C" +`, + out: `package foo + +/* +#include <foo.h> +*/ +import "C" +`, + }, + + // Put some things in their own section + { + name: "make_sections", + in: `package foo + +import ( +"os" +) + +func foo () { +_, _ = os.Args, fmt.Println +_, _ = appengine.FooSomething, user.Current +} +`, + out: `package foo + +import ( + "fmt" + "os" + + "appengine" + "appengine/user" +) + +func foo() { + _, _ = os.Args, fmt.Println + _, _ = appengine.FooSomething, user.Current +} +`, + }, + + // Delete existing empty import block + { + name: "delete_empty_import_block", + in: `package foo + +import () +`, + out: `package foo +`, + }, + + // Use existing empty import block + { + name: "use_empty_import_block", + in: `package foo + +import () + +func f() { + _ = fmt.Println +} +`, + out: `package foo + +import "fmt" + +func f() { + _ = fmt.Println +} +`, + }, + + // Blank line before adding new section. + { + name: "blank_line_before_new_group", + in: `package foo + +import ( + "fmt" + "net" +) + +func f() { + _ = net.Dial + _ = fmt.Printf + _ = snappy.Foo +} +`, + out: `package foo + +import ( + "fmt" + "net" + + "code.google.com/p/snappy-go/snappy" +) + +func f() { + _ = net.Dial + _ = fmt.Printf + _ = snappy.Foo +} +`, + }, + + // Blank line between standard library and third-party stuff. + { + name: "blank_line_separating_std_and_third_party", + in: `package foo + +import ( + "code.google.com/p/snappy-go/snappy" + "fmt" + "net" +) + +func f() { + _ = net.Dial + _ = fmt.Printf + _ = snappy.Foo +} +`, + out: `package foo + +import ( + "fmt" + "net" + + "code.google.com/p/snappy-go/snappy" +) + +func f() { + _ = net.Dial + _ = fmt.Printf + _ = snappy.Foo +} +`, + }, + + // golang.org/issue/6884 + { + name: "issue 6884", + in: `package main + +// A comment +func main() { + fmt.Println("Hello, world") +} +`, + out: `package main + +import "fmt" + +// A comment +func main() { + fmt.Println("Hello, world") +} +`, + }, + + // golang.org/issue/7132 + { + name: "issue 7132", + in: `package main + +import ( +"fmt" + +"gu" +"github.com/foo/bar" +) + +var ( +a = bar.a +b = gu.a +c = fmt.Printf +) +`, + out: `package main + +import ( + "fmt" + + "gu" + + "github.com/foo/bar" +) + +var ( + a = bar.a + b = gu.a + c = fmt.Printf +) +`, + }, + + { + name: "renamed package", + in: `package main + +var _ = str.HasPrefix +`, + out: `package main + +import str "strings" + +var _ = str.HasPrefix +`, + }, + + { + name: "fragment with main", + in: `func main(){fmt.Println("Hello, world")}`, + out: `package main + +import "fmt" + +func main() { fmt.Println("Hello, world") } +`, + }, + + { + name: "fragment without main", + in: `func notmain(){fmt.Println("Hello, world")}`, + out: `import "fmt" + +func notmain() { fmt.Println("Hello, world") }`, + }, + + // Remove first import within in a 2nd/3rd/4th/etc. section. + // golang.org/issue/7679 + { + name: "issue 7679", + in: `package main + +import ( + "fmt" + + "github.com/foo/bar" + "github.com/foo/qux" +) + +func main() { + var _ = fmt.Println + //var _ = bar.A + var _ = qux.B +} +`, + out: `package main + +import ( + "fmt" + + "github.com/foo/qux" +) + +func main() { + var _ = fmt.Println + //var _ = bar.A + var _ = qux.B +} +`, + }, + + // Blank line can be added before all types of import declarations. + // golang.org/issue/7866 + { + name: "issue 7866", + in: `package main + +import ( + "fmt" + renamed_bar "github.com/foo/bar" + + . "github.com/foo/baz" + "io" + + _ "github.com/foo/qux" + "strings" +) + +func main() { + _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B +} +`, + out: `package main + +import ( + "fmt" + + renamed_bar "github.com/foo/bar" + + "io" + + . "github.com/foo/baz" + + "strings" + + _ "github.com/foo/qux" +) + +func main() { + _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_bar.A, B +} +`, + }, + + // Non-idempotent comment formatting + // golang.org/issue/8035 + { + name: "issue 8035", + in: `package main + +import ( + "fmt" // A + "go/ast" // B + _ "launchpad.net/gocheck" // C +) + +func main() { _, _ = fmt.Print, ast.Walk } +`, + out: `package main + +import ( + "fmt" // A + "go/ast" // B + + _ "launchpad.net/gocheck" // C +) + +func main() { _, _ = fmt.Print, ast.Walk } +`, + }, + + // Failure to delete all duplicate imports + // golang.org/issue/8459 + { + name: "issue 8459", + in: `package main + +import ( + "fmt" + "log" + "log" + "math" +) + +func main() { fmt.Println("pi:", math.Pi) } +`, + out: `package main + +import ( + "fmt" + "math" +) + +func main() { fmt.Println("pi:", math.Pi) } +`, + }, + + // Too aggressive prefix matching + // golang.org/issue/9961 + { + name: "issue 9961", + in: `package p + +import ( + "zip" + + "rsc.io/p" +) + +var ( + _ = fmt.Print + _ = zip.Store + _ p.P + _ = regexp.Compile +) +`, + out: `package p + +import ( + "fmt" + "regexp" + "zip" + + "rsc.io/p" +) + +var ( + _ = fmt.Print + _ = zip.Store + _ p.P + _ = regexp.Compile +) +`, + }, + + // Unused named import is mistaken for unnamed import + // golang.org/issue/8149 + { + name: "issue 8149", + in: `package main + +import foo "fmt" + +func main() { fmt.Println() } +`, + out: `package main + +import "fmt" + +func main() { fmt.Println() } +`, + }, + + // Unused named import is mistaken for unnamed import + // golang.org/issue/8149 + { + name: "issue 8149", + in: `package main + +import ( + "fmt" + x "fmt" +) + +func main() { fmt.Println() } +`, + out: `package main + +import ( + "fmt" +) + +func main() { fmt.Println() } +`, + }, + + // FormatOnly + { + name: "format only", + formatOnly: true, + in: `package main + +import ( +"fmt" +"golang.org/x/foo" +) + +func main() {} +`, + out: `package main + +import ( + "fmt" + + "golang.org/x/foo" +) + +func main() {} +`, + }, + + { + name: "do not make grouped imports non-grouped", + in: `package p + +import ( + "bytes" + "fmt" +) + +var _ = fmt.Sprintf +`, + out: `package p + +import ( + "fmt" +) + +var _ = fmt.Sprintf +`, + }, + + { + name: "issue #19190 1", + in: `package main + +import ( + "time" +) + +func main() { + _ = snappy.Encode + _ = p.P + _ = time.Parse +} +`, + out: `package main + +import ( + "time" + + "code.google.com/p/snappy-go/snappy" + "rsc.io/p" +) + +func main() { + _ = snappy.Encode + _ = p.P + _ = time.Parse +} +`, + }, + + { + name: "issue #19190 2", + in: `package main + +import ( + "time" + + "code.google.com/p/snappy-go/snappy" +) + +func main() { + _ = snappy.Encode + _ = p.P + _ = time.Parse +} +`, + out: `package main + +import ( + "time" + + "code.google.com/p/snappy-go/snappy" + "rsc.io/p" +) + +func main() { + _ = snappy.Encode + _ = p.P + _ = time.Parse +} +`, + }, + + { + name: "issue #12097", + in: `// a +// b +// c + +func main() { + _ = fmt.Println +}`, + out: `package main + +import "fmt" + +// a +// b +// c + +func main() { + _ = fmt.Println +} +`, + }, +} + +func TestFixImports(t *testing.T) { + simplePkgs := map[string]string{ + "appengine": "appengine", + "bytes": "bytes", + "fmt": "fmt", + "math": "math", + "os": "os", + "p": "rsc.io/p", + "regexp": "regexp", + "snappy": "code.google.com/p/snappy-go/snappy", + "str": "strings", + "user": "appengine/user", + "zip": "archive/zip", + } + old := findImport + defer func() { + findImport = old + }() + findImport = func(_ context.Context, pkgName string, symbols map[string]bool, filename string) (string, bool, error) { + return simplePkgs[pkgName], pkgName == "str", nil + } + + options := &Options{ + TabWidth: 8, + TabIndent: true, + Comments: true, + Fragment: true, + } + + for _, tt := range tests { + options.FormatOnly = tt.formatOnly + if *only != "" && tt.name != *only { + continue + } + buf, err := Process(tt.name+".go", []byte(tt.in), options) + if err != nil { + t.Errorf("error on %q: %v", tt.name, err) + continue + } + if got := string(buf); got != tt.out { + t.Errorf("results diff on %q\nGOT:\n%s\nWANT:\n%s\n", tt.name, got, tt.out) + } + } +} + +func TestProcess_nil_src(t *testing.T) { + dir, err := ioutil.TempDir("", "goimports-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + tests := []struct { + name string + in, out string + }{ + { + name: "nil-src", + in: `package foo +func bar() { +fmt.Println("hi") +} +`, + out: `package foo + +import "fmt" + +func bar() { + fmt.Println("hi") +} +`, + }, + { + name: "missing package", + in: ` +func bar() { +fmt.Println("hi") +} +`, + out: ` +import "fmt" + +func bar() { + fmt.Println("hi") +} +`, + }, + } + + options := &Options{ + TabWidth: 8, + TabIndent: true, + Comments: true, + Fragment: true, + } + + for _, tt := range tests { + filename := filepath.Join(dir, tt.name+".go") + if err := ioutil.WriteFile(filename, []byte(tt.in), 0666); err != nil { + t.Fatal(err) + } + buf, err := Process(filename, nil, options) + if err != nil { + t.Errorf("error on %q: %v", tt.name, err) + continue + } + if got := string(buf); got != tt.out { + t.Errorf("results diff on %q\nGOT:\n%s\nWANT:\n%s\n", tt.name, got, tt.out) + } + } +} + +// Test support for packages in GOPATH that are actually symlinks. +// Also test that a symlink loop does not block the process. +func TestImportSymlinks(t *testing.T) { + switch runtime.GOOS { + case "windows", "plan9": + t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS) + } + + newGoPath, err := ioutil.TempDir("", "symlinktest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(newGoPath) + + // Create: + // $GOPATH/target/ + // $GOPATH/target/f.go // package mypkg\nvar Foo = 123\n + // $GOPATH/src/x/ + // $GOPATH/src/x/mypkg => $GOPATH/target // symlink + // $GOPATH/src/x/apkg => $GOPATH/src/x // symlink loop + // Test: + // $GOPATH/src/myotherpkg/toformat.go referencing mypkg.Foo + + targetPath := newGoPath + "/target" + if err := os.MkdirAll(targetPath, 0755); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(targetPath+"/f.go", []byte("package mypkg\nvar Foo = 123\n"), 0666); err != nil { + t.Fatal(err) + } + + symlinkPath := newGoPath + "/src/x/mypkg" + if err := os.MkdirAll(filepath.Dir(symlinkPath), 0755); err != nil { + t.Fatal(err) + } + if err := os.Symlink(targetPath, symlinkPath); err != nil { + t.Fatal(err) + } + + // Add a symlink loop. + if err := os.Symlink(newGoPath+"/src/x", newGoPath+"/src/x/apkg"); err != nil { + t.Fatal(err) + } + + withEmptyGoPath(func() { + build.Default.GOPATH = newGoPath + + input := `package p + +var ( + _ = fmt.Print + _ = mypkg.Foo +) +` + output := `package p + +import ( + "fmt" + "x/mypkg" +) + +var ( + _ = fmt.Print + _ = mypkg.Foo +) +` + buf, err := Process(newGoPath+"/src/myotherpkg/toformat.go", []byte(input), &Options{}) + if err != nil { + t.Fatal(err) + } + if got := string(buf); got != output { + t.Fatalf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, output) + } + }) + + // Add a .goimportsignore and ensure it is respected. + if err := ioutil.WriteFile(newGoPath+"/src/.goimportsignore", []byte("x/mypkg\n"), 0666); err != nil { + t.Fatal(err) + } + + withEmptyGoPath(func() { + build.Default.GOPATH = newGoPath + + input := `package p + +var ( + _ = fmt.Print + _ = mypkg.Foo +) +` + output := `package p + +import "fmt" + +var ( + _ = fmt.Print + _ = mypkg.Foo +) +` + buf, err := Process(newGoPath+"/src/myotherpkg/toformat.go", []byte(input), &Options{}) + if err != nil { + t.Fatal(err) + } + if got := string(buf); got != output { + t.Fatalf("ignored results differ\nGOT:\n%s\nWANT:\n%s\n", got, output) + } + }) + +} + +// Test for correctly identifying the name of a vendored package when it +// differs from its directory name. In this test, the import line +// "mypkg.com/mypkg.v1" would be removed if goimports wasn't able to detect +// that the package name is "mypkg". +func TestFixImportsVendorPackage(t *testing.T) { + // Skip this test on go versions with no vendor support. + if _, err := os.Stat(filepath.Join(runtime.GOROOT(), "src/vendor")); err != nil { + t.Skip(err) + } + testConfig{ + gopathFiles: map[string]string{ + "mypkg.com/outpkg/vendor/mypkg.com/mypkg.v1/f.go": "package mypkg\nvar Foo = 123\n", + }, + }.test(t, func(t *goimportTest) { + input := `package p + +import ( + "fmt" + + "mypkg.com/mypkg.v1" +) + +var ( + _ = fmt.Print + _ = mypkg.Foo +) +` + buf, err := Process(filepath.Join(t.gopath, "src/mypkg.com/outpkg/toformat.go"), []byte(input), &Options{}) + if err != nil { + t.Fatal(err) + } + if got := string(buf); got != input { + t.Fatalf("results differ\nGOT:\n%s\nWANT:\n%s\n", got, input) + } + }) +} + +func TestFindImportGoPath(t *testing.T) { + goroot, err := ioutil.TempDir("", "goimports-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(goroot) + + origStdlib := stdlib + defer func() { + stdlib = origStdlib + }() + stdlib = nil + + withEmptyGoPath(func() { + // Test against imaginary bits/bytes package in std lib + bytesDir := filepath.Join(goroot, "src", "pkg", "bits", "bytes") + for _, tag := range build.Default.ReleaseTags { + // Go 1.4 rearranged the GOROOT tree to remove the "pkg" path component. + if tag == "go1.4" { + bytesDir = filepath.Join(goroot, "src", "bits", "bytes") + } + } + if err := os.MkdirAll(bytesDir, 0755); err != nil { + t.Fatal(err) + } + bytesSrcPath := filepath.Join(bytesDir, "bytes.go") + bytesPkgPath := "bits/bytes" + bytesSrc := []byte(`package bytes + +type Buffer2 struct {} +`) + if err := ioutil.WriteFile(bytesSrcPath, bytesSrc, 0775); err != nil { + t.Fatal(err) + } + build.Default.GOROOT = goroot + + got, rename, err := findImportGoPath(context.Background(), "bytes", map[string]bool{"Buffer2": true}, "x.go") + if err != nil { + t.Fatal(err) + } + if got != bytesPkgPath || rename { + t.Errorf(`findImportGoPath("bytes", Buffer2 ...)=%q, %t, want "%s", false`, got, rename, bytesPkgPath) + } + + got, rename, err = findImportGoPath(context.Background(), "bytes", map[string]bool{"Missing": true}, "x.go") + if err != nil { + t.Fatal(err) + } + if got != "" || rename { + t.Errorf(`findImportGoPath("bytes", Missing ...)=%q, %t, want "", false`, got, rename) + } + }) +} + +func withEmptyGoPath(fn func()) { + populateIgnoreOnce = sync.Once{} + scanGoRootOnce = sync.Once{} + scanGoPathOnce = sync.Once{} + dirScan = nil + ignoredDirs = nil + scanGoRootDone = make(chan struct{}) + + oldGOPATH := build.Default.GOPATH + oldGOROOT := build.Default.GOROOT + build.Default.GOPATH = "" + testHookScanDir = func(string) {} + + defer func() { + testHookScanDir = func(string) {} + build.Default.GOPATH = oldGOPATH + build.Default.GOROOT = oldGOROOT + }() + + fn() +} + +func TestFindImportInternal(t *testing.T) { + withEmptyGoPath(func() { + // Check for src/internal/race, not just src/internal, + // so that we can run this test also against go1.5 + // (which doesn't contain that file). + _, err := os.Stat(filepath.Join(runtime.GOROOT(), "src/internal/race")) + if err != nil { + t.Skip(err) + } + + got, rename, err := findImportGoPath(context.Background(), "race", map[string]bool{"Acquire": true}, filepath.Join(runtime.GOROOT(), "src/math/x.go")) + if err != nil { + t.Fatal(err) + } + if got != "internal/race" || rename { + t.Errorf(`findImportGoPath("race", Acquire ...) = %q, %t; want "internal/race", false`, got, rename) + } + + // should not be able to use internal from outside that tree + got, rename, err = findImportGoPath(context.Background(), "race", map[string]bool{"Acquire": true}, filepath.Join(runtime.GOROOT(), "x.go")) + if err != nil { + t.Fatal(err) + } + if got != "" || rename { + t.Errorf(`findImportGoPath("race", Acquire ...)=%q, %t, want "", false`, got, rename) + } + }) +} + +// rand.Read should prefer crypto/rand.Read, not math/rand.Read. +func TestFindImportRandRead(t *testing.T) { + withEmptyGoPath(func() { + file := filepath.Join(runtime.GOROOT(), "src/foo/x.go") // dummy + tests := []struct { + syms []string + want string + }{ + { + syms: []string{"Read"}, + want: "crypto/rand", + }, + { + syms: []string{"Read", "NewZipf"}, + want: "math/rand", + }, + { + syms: []string{"NewZipf"}, + want: "math/rand", + }, + { + syms: []string{"Read", "Prime"}, + want: "crypto/rand", + }, + } + for _, tt := range tests { + m := map[string]bool{} + for _, sym := range tt.syms { + m[sym] = true + } + got, _, err := findImportGoPath(context.Background(), "rand", m, file) + if err != nil { + t.Errorf("for %q: %v", tt.syms, err) + continue + } + if got != tt.want { + t.Errorf("for %q, findImportGoPath = %q; want %q", tt.syms, got, tt.want) + } + } + }) +} + +func TestFindImportVendor(t *testing.T) { + testConfig{ + gorootFiles: map[string]string{ + "vendor/golang.org/x/net/http2/hpack/huffman.go": "package hpack\nfunc HuffmanDecode() { }\n", + }, + }.test(t, func(t *goimportTest) { + got, rename, err := findImportGoPath(context.Background(), "hpack", map[string]bool{"HuffmanDecode": true}, filepath.Join(t.goroot, "src/math/x.go")) + if err != nil { + t.Fatal(err) + } + want := "golang.org/x/net/http2/hpack" + if got != want || rename { + t.Errorf(`findImportGoPath("hpack", HuffmanDecode ...) = %q, %t; want %q, false`, got, rename, want) + } + }) +} + +func TestProcessVendor(t *testing.T) { + withEmptyGoPath(func() { + _, err := os.Stat(filepath.Join(runtime.GOROOT(), "src/vendor")) + if err != nil { + t.Skip(err) + } + + target := filepath.Join(runtime.GOROOT(), "src/math/x.go") + out, err := Process(target, []byte("package http\nimport \"bytes\"\nfunc f() { strings.NewReader(); hpack.HuffmanDecode() }\n"), nil) + + if err != nil { + t.Fatal(err) + } + + want := "golang_org/x/net/http2/hpack" + if _, err := os.Stat(filepath.Join(runtime.GOROOT(), "src/vendor", want)); os.IsNotExist(err) { + want = "golang.org/x/net/http2/hpack" + } + + if !bytes.Contains(out, []byte(want)) { + t.Fatalf("Process(%q) did not add expected hpack import %q; got:\n%s", target, want, out) + } + }) +} + +func TestFindImportStdlib(t *testing.T) { + tests := []struct { + pkg string + symbols []string + want string + }{ + {"http", []string{"Get"}, "net/http"}, + {"http", []string{"Get", "Post"}, "net/http"}, + {"http", []string{"Get", "Foo"}, ""}, + {"bytes", []string{"Buffer"}, "bytes"}, + {"ioutil", []string{"Discard"}, "io/ioutil"}, + } + for _, tt := range tests { + got, ok := findImportStdlib(tt.pkg, strSet(tt.symbols)) + if (got != "") != ok { + t.Error("findImportStdlib return value inconsistent") + } + if got != tt.want { + t.Errorf("findImportStdlib(%q, %q) = %q, want %q", tt.pkg, tt.symbols, got, tt.want) + } + } +} + +type testConfig struct { + // goroot and gopath optionally specifies the path on disk + // to use for the GOROOT and GOPATH. If empty, a temp directory + // is made if needed. + goroot, gopath string + + // gorootFiles optionally specifies the complete contents of GOROOT to use, + // If nil, the normal current $GOROOT is used. + gorootFiles map[string]string // paths relative to $GOROOT/src to contents + + // gopathFiles is like gorootFiles, but for $GOPATH. + // If nil, there is no GOPATH, though. + gopathFiles map[string]string // paths relative to $GOPATH/src to contents +} + +func mustTempDir(t *testing.T, prefix string) string { + dir, err := ioutil.TempDir("", prefix) + if err != nil { + t.Fatal(err) + } + return dir +} + +func mapToDir(destDir string, files map[string]string) error { + for path, contents := range files { + file := filepath.Join(destDir, "src", path) + if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil { + return err + } + var err error + if strings.HasPrefix(contents, "LINK:") { + err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file) + } else { + err = ioutil.WriteFile(file, []byte(contents), 0644) + } + if err != nil { + return err + } + } + return nil +} + +func (c testConfig) test(t *testing.T, fn func(*goimportTest)) { + goroot := c.goroot + gopath := c.gopath + + if c.gorootFiles != nil && goroot == "" { + goroot = mustTempDir(t, "goroot-") + defer os.RemoveAll(goroot) + } + if err := mapToDir(goroot, c.gorootFiles); err != nil { + t.Fatal(err) + } + + if c.gopathFiles != nil && gopath == "" { + gopath = mustTempDir(t, "gopath-") + defer os.RemoveAll(gopath) + } + if err := mapToDir(gopath, c.gopathFiles); err != nil { + t.Fatal(err) + } + + withEmptyGoPath(func() { + if goroot != "" { + build.Default.GOROOT = goroot + } + build.Default.GOPATH = gopath + + it := &goimportTest{ + T: t, + goroot: build.Default.GOROOT, + gopath: gopath, + ctx: &build.Default, + } + fn(it) + }) +} + +type goimportTest struct { + *testing.T + ctx *build.Context + goroot string + gopath string +} + +// Tests that added imports are renamed when the import path's base doesn't +// match its package name. For example, we want to generate: +// +// import cloudbilling "google.golang.org/api/cloudbilling/v1" +func TestRenameWhenPackageNameMismatch(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "foo/bar/v1/x.go": "package bar \n const X = 1", + }, + }.test(t, func(t *goimportTest) { + buf, err := Process(t.gopath+"/src/test/t.go", []byte("package main \n const Y = bar.X"), &Options{}) + if err != nil { + t.Fatal(err) + } + const want = `package main + +import bar "foo/bar/v1" + +const Y = bar.X +` + if string(buf) != want { + t.Errorf("Got:\n%s\nWant:\n%s", buf, want) + } + }) +} + +// Tests that the LocalPrefix option causes imports +// to be added into a later group (num=3). +func TestLocalPrefix(t *testing.T) { + tests := []struct { + config testConfig + localPrefix string + src string + want string + }{ + { + config: testConfig{ + gopathFiles: map[string]string{ + "foo/bar/bar.go": "package bar \n const X = 1", + }, + }, + localPrefix: "foo/", + src: "package main \n const Y = bar.X \n const _ = runtime.GOOS", + want: `package main + +import ( + "runtime" + + "foo/bar" +) + +const Y = bar.X +const _ = runtime.GOOS +`, + }, + { + config: testConfig{ + gopathFiles: map[string]string{ + "foo/foo.go": "package foo \n const X = 1", + "foo/bar/bar.go": "package bar \n const X = 1", + }, + }, + localPrefix: "foo/", + src: "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS", + want: `package main + +import ( + "runtime" + + "foo" + "foo/bar" +) + +const Y = bar.X +const Z = foo.X +const _ = runtime.GOOS +`, + }, + { + config: testConfig{ + gopathFiles: map[string]string{ + "example.org/pkg/pkg.go": "package pkg \n const A = 1", + "foo/bar/bar.go": "package bar \n const B = 1", + "code.org/r/p/expproj/expproj.go": "package expproj \n const C = 1", + }, + }, + localPrefix: "example.org/pkg,foo/,code.org", + src: "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS", + want: `package main + +import ( + "runtime" + + "code.org/r/p/expproj" + "example.org/pkg" + "foo/bar" +) + +const X = pkg.A +const Y = bar.B +const Z = expproj.C +const _ = runtime.GOOS +`, + }, + } + + for _, tt := range tests { + tt.config.test(t, func(t *goimportTest) { + defer func(s string) { LocalPrefix = s }(LocalPrefix) + LocalPrefix = tt.localPrefix + buf, err := Process(t.gopath+"/src/test/t.go", []byte(tt.src), &Options{}) + if err != nil { + t.Fatal(err) + } + if string(buf) != tt.want { + t.Errorf("Got:\n%s\nWant:\n%s", buf, tt.want) + } + }) + } +} + +// Tests that running goimport on files in GOROOT (for people hacking +// on Go itself) don't cause the GOPATH to be scanned (which might be +// much bigger). +func TestOptimizationWhenInGoroot(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "foo/foo.go": "package foo\nconst X = 1\n", + }, + }.test(t, func(t *goimportTest) { + testHookScanDir = func(dir string) { + if dir != filepath.Join(build.Default.GOROOT, "src") { + t.Errorf("unexpected dir scan of %s", dir) + } + } + const in = "package foo\n\nconst Y = bar.X\n" + buf, err := Process(t.goroot+"/src/foo/foo.go", []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != in { + t.Errorf("got:\n%q\nwant unchanged:\n%q\n", in, buf) + } + }) +} + +// Tests that "package documentation" files are ignored. +func TestIgnoreDocumentationPackage(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "foo/foo.go": "package foo\nconst X = 1\n", + "foo/doc.go": "package documentation \n // just to confuse things\n", + }, + }.test(t, func(t *goimportTest) { + const in = "package x\n\nconst Y = foo.X\n" + const want = "package x\n\nimport \"foo\"\n\nconst Y = foo.X\n" + buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != want { + t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", in, want) + } + }) +} + +// Tests importPathToNameGoPathParse and in particular that it stops +// after finding the first non-documentation package name, not +// reporting an error on inconsistent package names (since it should +// never make it that far). +func TestImportPathToNameGoPathParse(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "example.net/pkg/doc.go": "package documentation\n", // ignored + "example.net/pkg/gen.go": "package main\n", // also ignored + "example.net/pkg/pkg.go": "package the_pkg_name_to_find\n and this syntax error is ignored because of parser.PackageClauseOnly", + "example.net/pkg/z.go": "package inconsistent\n", // inconsistent but ignored + }, + }.test(t, func(t *goimportTest) { + got, err := importPathToNameGoPathParse("example.net/pkg", filepath.Join(t.gopath, "src", "other.net")) + if err != nil { + t.Fatal(err) + } + const want = "the_pkg_name_to_find" + if got != want { + t.Errorf("importPathToNameGoPathParse(..) = %q; want %q", got, want) + } + }) +} + +func TestIgnoreConfiguration(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + ".goimportsignore": "# comment line\n\n example.net", // tests comment, blank line, whitespace trimming + "example.net/pkg/pkg.go": "package pkg\nconst X = 1", + "otherwise-longer-so-worse.example.net/foo/pkg/pkg.go": "package pkg\nconst X = 1", + }, + }.test(t, func(t *goimportTest) { + const in = "package x\n\nconst _ = pkg.X\n" + const want = "package x\n\nimport \"otherwise-longer-so-worse.example.net/foo/pkg\"\n\nconst _ = pkg.X\n" + buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != want { + t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want) + } + }) +} + +// Skip "node_modules" directory. +func TestSkipNodeModules(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "example.net/node_modules/pkg/a.go": "package pkg\nconst X = 1", + "otherwise-longer.net/not_modules/pkg/a.go": "package pkg\nconst X = 1", + }, + }.test(t, func(t *goimportTest) { + const in = "package x\n\nconst _ = pkg.X\n" + const want = "package x\n\nimport \"otherwise-longer.net/not_modules/pkg\"\n\nconst _ = pkg.X\n" + buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != want { + t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want) + } + }) +} + +// golang.org/issue/16458 -- if GOROOT is a prefix of GOPATH, GOPATH is ignored. +func TestGoRootPrefixOfGoPath(t *testing.T) { + dir := mustTempDir(t, "importstest") + defer os.RemoveAll(dir) + testConfig{ + goroot: filepath.Join(dir, "go"), + gopath: filepath.Join(dir, "gopath"), + gopathFiles: map[string]string{ + "example.com/foo/pkg.go": "package foo\nconst X = 1", + }, + }.test(t, func(t *goimportTest) { + const in = "package x\n\nconst _ = foo.X\n" + const want = "package x\n\nimport \"example.com/foo\"\n\nconst _ = foo.X\n" + buf, err := Process(t.gopath+"/src/x/x.go", []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != want { + t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want) + } + }) + +} + +const testGlobalImportsUsesGlobal = `package globalimporttest + +func doSomething() { + t := time.Now() +} +` + +const testGlobalImportsGlobalDecl = `package globalimporttest + +type Time struct{} + +func (t Time) Now() Time { + return Time{} +} + +var time Time +` + +// Tests that package global variables with the same name and function name as +// a function in a separate package do not result in an import which masks +// the global variable +func TestGlobalImports(t *testing.T) { + const pkg = "globalimporttest" + const usesGlobalFile = pkg + "/uses_global.go" + testConfig{ + gopathFiles: map[string]string{ + usesGlobalFile: testGlobalImportsUsesGlobal, + pkg + "/global.go": testGlobalImportsGlobalDecl, + }, + }.test(t, func(t *goimportTest) { + buf, err := Process( + t.gopath+"/src/"+usesGlobalFile, []byte(testGlobalImportsUsesGlobal), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != testGlobalImportsUsesGlobal { + t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, testGlobalImportsUsesGlobal) + } + }) +} + +// Tests that sibling files - other files in the same package - can provide an +// import that may not be the default one otherwise. +func TestSiblingImports(t *testing.T) { + + // provide is the sibling file that provides the desired import. + const provide = `package siblingimporttest + +import "local/log" +import "my/bytes" + +func LogSomething() { + log.Print("Something") + bytes.SomeFunc() +} +` + + // need is the file being tested that needs the import. + const need = `package siblingimporttest + +var _ = bytes.Buffer{} + +func LogSomethingElse() { + log.Print("Something else") +} +` + + // want is the expected result file + const want = `package siblingimporttest + +import ( + "bytes" + "local/log" +) + +var _ = bytes.Buffer{} + +func LogSomethingElse() { + log.Print("Something else") +} +` + + const pkg = "siblingimporttest" + const siblingFile = pkg + "/needs_import.go" + testConfig{ + gopathFiles: map[string]string{ + siblingFile: need, + pkg + "/provides_import.go": provide, + }, + }.test(t, func(t *goimportTest) { + buf, err := Process( + t.gopath+"/src/"+siblingFile, []byte(need), nil) + if err != nil { + t.Fatal(err) + } + if string(buf) != want { + t.Errorf("wrong output.\ngot:\n%q\nwant:\n%q\n", buf, want) + } + }) +} + +func strSet(ss []string) map[string]bool { + m := make(map[string]bool) + for _, s := range ss { + m[s] = true + } + return m +} + +func TestPkgIsCandidate(t *testing.T) { + tests := [...]struct { + filename string + pkgIdent string + pkg *pkg + want bool + }{ + // normal match + 0: { + filename: "/gopath/src/my/pkg/pkg.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/client", + importPath: "client", + importPathShort: "client", + }, + want: true, + }, + // not a match + 1: { + filename: "/gopath/src/my/pkg/pkg.go", + pkgIdent: "zzz", + pkg: &pkg{ + dir: "/gopath/src/client", + importPath: "client", + importPathShort: "client", + }, + want: false, + }, + // would be a match, but "client" appears too deep. + 2: { + filename: "/gopath/src/my/pkg/pkg.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/client/foo/foo/foo", + importPath: "client/foo/foo", + importPathShort: "client/foo/foo", + }, + want: false, + }, + // not an exact match, but substring is good enough. + 3: { + filename: "/gopath/src/my/pkg/pkg.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/foo/go-client", + importPath: "foo/go-client", + importPathShort: "foo/go-client", + }, + want: true, + }, + // "internal" package, and not visible + 4: { + filename: "/gopath/src/my/pkg/pkg.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/foo/internal/client", + importPath: "foo/internal/client", + importPathShort: "foo/internal/client", + }, + want: false, + }, + // "internal" package but visible + 5: { + filename: "/gopath/src/foo/bar.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/foo/internal/client", + importPath: "foo/internal/client", + importPathShort: "foo/internal/client", + }, + want: true, + }, + // "vendor" package not visible + 6: { + filename: "/gopath/src/foo/bar.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/other/vendor/client", + importPath: "other/vendor/client", + importPathShort: "client", + }, + want: false, + }, + // "vendor" package, visible + 7: { + filename: "/gopath/src/foo/bar.go", + pkgIdent: "client", + pkg: &pkg{ + dir: "/gopath/src/foo/vendor/client", + importPath: "other/foo/client", + importPathShort: "client", + }, + want: true, + }, + // Ignore hyphens. + 8: { + filename: "/gopath/src/foo/bar.go", + pkgIdent: "socketio", + pkg: &pkg{ + dir: "/gopath/src/foo/socket-io", + importPath: "foo/socket-io", + importPathShort: "foo/socket-io", + }, + want: true, + }, + // Ignore case. + 9: { + filename: "/gopath/src/foo/bar.go", + pkgIdent: "fooprod", + pkg: &pkg{ + dir: "/gopath/src/foo/FooPROD", + importPath: "foo/FooPROD", + importPathShort: "foo/FooPROD", + }, + want: true, + }, + // Ignoring both hyphens and case together. + 10: { + filename: "/gopath/src/foo/bar.go", + pkgIdent: "fooprod", + pkg: &pkg{ + dir: "/gopath/src/foo/Foo-PROD", + importPath: "foo/Foo-PROD", + importPathShort: "foo/Foo-PROD", + }, + want: true, + }, + } + for i, tt := range tests { + got := pkgIsCandidate(tt.filename, tt.pkgIdent, tt.pkg) + if got != tt.want { + t.Errorf("test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v", + i, tt.filename, tt.pkgIdent, *tt.pkg, got, tt.want) + } + } +} + +func TestShouldTraverse(t *testing.T) { + switch runtime.GOOS { + case "windows", "plan9": + t.Skipf("skipping symlink-requiring test on %s", runtime.GOOS) + } + + dir, err := ioutil.TempDir("", "goimports-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // Note: mapToDir prepends "src" to each element, since + // mapToDir was made for creating GOPATHs. + if err := mapToDir(dir, map[string]string{ + "foo/foo2/file.txt": "", + "foo/foo2/link-to-src": "LINK:" + dir + "/src", + "foo/foo2/link-to-src-foo": "LINK:" + dir + "/src/foo", + "foo/foo2/link-to-dot": "LINK:.", + "bar/bar2/file.txt": "", + "bar/bar2/link-to-src-foo": "LINK:" + dir + "/src/foo", + + "a/b/c": "LINK:" + dir + "/src/a/d", + "a/d/e": "LINK:" + dir + "/src/a/b", + }); err != nil { + t.Fatal(err) + } + tests := []struct { + dir string + file string + want bool + }{ + { + dir: dir + "/src/foo/foo2", + file: "link-to-src-foo", + want: false, // loop + }, + { + dir: dir + "/src/foo/foo2", + file: "link-to-src", + want: false, // loop + }, + { + dir: dir + "/src/foo/foo2", + file: "link-to-dot", + want: false, // loop + }, + { + dir: dir + "/src/bar/bar2", + file: "link-to-src-foo", + want: true, // not a loop + }, + { + dir: dir + "/src/a/b/c", + file: "e", + want: false, // loop: "e" is the same as "b". + }, + } + for i, tt := range tests { + fi, err := os.Stat(filepath.Join(tt.dir, tt.file)) + if err != nil { + t.Errorf("%d. Stat = %v", i, err) + continue + } + got := shouldTraverse(tt.dir, fi) + if got != tt.want { + t.Errorf("%d. shouldTraverse(%q, %q) = %v; want %v", i, tt.dir, tt.file, got, tt.want) + } + } +} + +// Issue 20941: this used to panic on Windows. +func TestProcessStdin(t *testing.T) { + got, err := Process("<standard input>", []byte("package main\nfunc main() {\n\tfmt.Println(123)\n}\n"), nil) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(got), `"fmt"`) { + t.Errorf("expected fmt import; got: %s", got) + } +} + +// Tests LocalPackagePromotion when there is a local package that matches, it +// should be the closest match. +// https://golang.org/issues/17557 +func TestLocalPackagePromotion(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "config.net/config/config.go": "package config\n type SystemConfig struct {}", // Will match but should not be first choice + "mycompany.net/config/config.go": "package config\n type SystemConfig struct {}", // Will match but should not be first choice + "mycompany.net/tool/config/config.go": "package config\n type SystemConfig struct {}", // Local package should be promoted over shorter package + }, + }.test(t, func(t *goimportTest) { + const in = "package main\n var c = &config.SystemConfig{}" + const want = `package main + +import "mycompany.net/tool/config" + +var c = &config.SystemConfig{} +` + got, err := Process(filepath.Join(t.gopath, "src", "mycompany.net/tool/main.go"), []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(got) != want { + t.Errorf("Process = %q; want %q", got, want) + } + }) +} + +// Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the +// local directory, since the user is likely to import the same packages in the current +// Go file. If an import is found that satisfies the need, it should be used over the +// standard library. +// https://golang.org/issues/17557 +func TestFindImportInLocalGoFiles(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{ + "bytes.net/bytes/bytes.go": "package bytes\n type Buffer struct {}", // Should be selected over standard library + "mycompany.net/tool/io.go": "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored + "mycompany.net/tool/err.go": "package main\n import \"bogus.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains import which is not resolved, so it is ignored + }, + }.test(t, func(t *goimportTest) { + const in = "package main\n var _ = &bytes.Buffer{}" + const want = `package main + +import "bytes.net/bytes" + +var _ = &bytes.Buffer{} +` + got, err := Process(filepath.Join(t.gopath, "src", "mycompany.net/tool/main.go"), []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(got) != want { + t.Errorf("Process = got %q; want %q", got, want) + } + }) +} + +func TestImportNoGoFiles(t *testing.T) { + testConfig{ + gopathFiles: map[string]string{}, + }.test(t, func(t *goimportTest) { + const in = "package main\n var _ = &bytes.Buffer{}" + const want = `package main + +import "bytes" + +var _ = &bytes.Buffer{} +` + got, err := Process(filepath.Join(t.gopath, "src", "mycompany.net/tool/main.go"), []byte(in), nil) + if err != nil { + t.Fatal(err) + } + if string(got) != want { + t.Errorf("Process = got %q; want %q", got, want) + } + }) +} + +// A happy path test for Process +func TestProcess(t *testing.T) { + in := `package testimports + + var s = fmt.Sprintf("%s", "value") +` + out, err := Process("foo", []byte(in), nil) + + if err != nil { + t.Errorf("Process returned error.\n got:\n%v\nwant:\nnil", err) + } + + want := `package testimports + +import "fmt" + +var s = fmt.Sprintf("%s", "value") +` + if got := string(out); got != want { + t.Errorf("Process returned unexpected result.\ngot:\n%v\nwant:\n%v", got, want) + } +} + +// Ensures a token as large as 500000 bytes can be handled +// https://golang.org/issues/18201 +func TestProcessLargeToken(t *testing.T) { + largeString := strings.Repeat("x", 500000) + + in := `package testimports + +import ( + "fmt" + "mydomain.mystuff/mypkg" +) + +const s = fmt.Sprintf("%s", "` + largeString + `") +const x = mypkg.Sprintf("%s", "my package") + +// end +` + + out, err := Process("foo", []byte(in), nil) + + if err != nil { + t.Errorf("Process returned error.\n got:\n%v\nwant:\nnil", err) + } + + want := `package testimports + +import ( + "fmt" + + "mydomain.mystuff/mypkg" +) + +const s = fmt.Sprintf("%s", "` + largeString + `") +const x = mypkg.Sprintf("%s", "my package") + +// end +` + if got := string(out); got != want { + t.Errorf("Process returned unexpected result.\ngot:\n%.100v\nwant:\n%.100v", got, want) + } +} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_test.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_test.go new file mode 100644 index 000000000..e9ab0d59f --- /dev/null +++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_test.go @@ -0,0 +1,190 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fastwalk_test + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "runtime" + "sort" + "strings" + "sync" + "testing" + + "golang.org/x/tools/internal/fastwalk" +) + +func formatFileModes(m map[string]os.FileMode) string { + var keys []string + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + var buf bytes.Buffer + for _, k := range keys { + fmt.Fprintf(&buf, "%-20s: %v\n", k, m[k]) + } + return buf.String() +} + +func testFastWalk(t *testing.T, files map[string]string, callback func(path string, typ os.FileMode) error, want map[string]os.FileMode) { + tempdir, err := ioutil.TempDir("", "test-fast-walk") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempdir) + for path, contents := range files { + file := filepath.Join(tempdir, "/src", path) + if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil { + t.Fatal(err) + } + var err error + if strings.HasPrefix(contents, "LINK:") { + err = os.Symlink(strings.TrimPrefix(contents, "LINK:"), file) + } else { + err = ioutil.WriteFile(file, []byte(contents), 0644) + } + if err != nil { + t.Fatal(err) + } + } + got := map[string]os.FileMode{} + var mu sync.Mutex + if err := fastwalk.Walk(tempdir, func(path string, typ os.FileMode) error { + mu.Lock() + defer mu.Unlock() + if !strings.HasPrefix(path, tempdir) { + t.Fatalf("bogus prefix on %q, expect %q", path, tempdir) + } + key := filepath.ToSlash(strings.TrimPrefix(path, tempdir)) + if old, dup := got[key]; dup { + t.Fatalf("callback called twice for key %q: %v -> %v", key, old, typ) + } + got[key] = typ + return callback(path, typ) + }); err != nil { + t.Fatalf("callback returned: %v", err) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("walk mismatch.\n got:\n%v\nwant:\n%v", formatFileModes(got), formatFileModes(want)) + } +} + +func TestFastWalk_Basic(t *testing.T) { + testFastWalk(t, map[string]string{ + "foo/foo.go": "one", + "bar/bar.go": "two", + "skip/skip.go": "skip", + }, + func(path string, typ os.FileMode) error { + return nil + }, + map[string]os.FileMode{ + "": os.ModeDir, + "/src": os.ModeDir, + "/src/bar": os.ModeDir, + "/src/bar/bar.go": 0, + "/src/foo": os.ModeDir, + "/src/foo/foo.go": 0, + "/src/skip": os.ModeDir, + "/src/skip/skip.go": 0, + }) +} + +func TestFastWalk_Symlink(t *testing.T) { + switch runtime.GOOS { + case "windows", "plan9": + t.Skipf("skipping on %s", runtime.GOOS) + } + testFastWalk(t, map[string]string{ + "foo/foo.go": "one", + "bar/bar.go": "LINK:../foo.go", + "symdir": "LINK:foo", + }, + func(path string, typ os.FileMode) error { + return nil + }, + map[string]os.FileMode{ + "": os.ModeDir, + "/src": os.ModeDir, + "/src/bar": os.ModeDir, + "/src/bar/bar.go": os.ModeSymlink, + "/src/foo": os.ModeDir, + "/src/foo/foo.go": 0, + "/src/symdir": os.ModeSymlink, + }) +} + +func TestFastWalk_SkipDir(t *testing.T) { + testFastWalk(t, map[string]string{ + "foo/foo.go": "one", + "bar/bar.go": "two", + "skip/skip.go": "skip", + }, + func(path string, typ os.FileMode) error { + if typ == os.ModeDir && strings.HasSuffix(path, "skip") { + return filepath.SkipDir + } + return nil + }, + map[string]os.FileMode{ + "": os.ModeDir, + "/src": os.ModeDir, + "/src/bar": os.ModeDir, + "/src/bar/bar.go": 0, + "/src/foo": os.ModeDir, + "/src/foo/foo.go": 0, + "/src/skip": os.ModeDir, + }) +} + +func TestFastWalk_TraverseSymlink(t *testing.T) { + switch runtime.GOOS { + case "windows", "plan9": + t.Skipf("skipping on %s", runtime.GOOS) + } + + testFastWalk(t, map[string]string{ + "foo/foo.go": "one", + "bar/bar.go": "two", + "skip/skip.go": "skip", + "symdir": "LINK:foo", + }, + func(path string, typ os.FileMode) error { + if typ == os.ModeSymlink { + return fastwalk.TraverseLink + } + return nil + }, + map[string]os.FileMode{ + "": os.ModeDir, + "/src": os.ModeDir, + "/src/bar": os.ModeDir, + "/src/bar/bar.go": 0, + "/src/foo": os.ModeDir, + "/src/foo/foo.go": 0, + "/src/skip": os.ModeDir, + "/src/skip/skip.go": 0, + "/src/symdir": os.ModeSymlink, + "/src/symdir/foo.go": 0, + }) +} + +var benchDir = flag.String("benchdir", runtime.GOROOT(), "The directory to scan for BenchmarkFastWalk") + +func BenchmarkFastWalk(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + err := fastwalk.Walk(*benchDir, func(path string, typ os.FileMode) error { return nil }) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/golang.org/x/tools/third_party/moduleloader/LICENSE b/vendor/golang.org/x/tools/third_party/moduleloader/LICENSE deleted file mode 100644 index 1723a2247..000000000 --- a/vendor/golang.org/x/tools/third_party/moduleloader/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013-2016 Guy Bedford, Luke Hoban, Addy Osmani - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/golang.org/x/tools/third_party/typescript/LICENSE b/vendor/golang.org/x/tools/third_party/typescript/LICENSE deleted file mode 100644 index e7259f843..000000000 --- a/vendor/golang.org/x/tools/third_party/typescript/LICENSE +++ /dev/null @@ -1,55 +0,0 @@ -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: - -You must give any other recipients of the Work or Derivative Works a copy of this License; and - -You must cause any modified files to carry prominent notices stating that You changed the files; and - -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 - -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 \ No newline at end of file diff --git a/vendor/golang.org/x/tools/third_party/webcomponents/LICENSE b/vendor/golang.org/x/tools/third_party/webcomponents/LICENSE deleted file mode 100644 index e648283b4..000000000 --- a/vendor/golang.org/x/tools/third_party/webcomponents/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015 The Polymer Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/google.golang.org/api/.gitignore b/vendor/google.golang.org/api/.gitignore new file mode 100644 index 000000000..50d2a9bd6 --- /dev/null +++ b/vendor/google.golang.org/api/.gitignore @@ -0,0 +1,12 @@ +_obj/ +*_testmain.go +clientid.dat +clientsecret.dat +/google-api-go-generator/google-api-go-generator + +*.6 +*.8 +*~ +*.out +*.test +*.exe diff --git a/vendor/google.golang.org/api/.hgtags b/vendor/google.golang.org/api/.hgtags new file mode 100644 index 000000000..f1a735783 --- /dev/null +++ b/vendor/google.golang.org/api/.hgtags @@ -0,0 +1 @@ +b571b553f8c057cb6952ce817dfb09b6e34a8c0b release diff --git a/vendor/google.golang.org/api/.travis.yml b/vendor/google.golang.org/api/.travis.yml new file mode 100644 index 000000000..ef68b4b95 --- /dev/null +++ b/vendor/google.golang.org/api/.travis.yml @@ -0,0 +1,18 @@ +sudo: false + +language: go + +go: + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + +before_install: + - openssl aes-256-cbc -K $encrypted_6c6ebd86ce52_key -iv $encrypted_6c6ebd86ce52_iv -in key.json.enc -out key.json -d + +install: + - go get -v -t -p 1 google.golang.org/api/... + +script: + - GCLOUD_TESTS_GOLANG_PROJECT_ID="dulcet-port-762" GCLOUD_TESTS_GOLANG_DESTRUCTIVE_TEST_BUCKET_NAME="dulcet-port-762-api-go-client-storage-integration-test" GCLOUD_TESTS_GOLANG_KEY="$(pwd)/key.json" go test -v -tags=integration google.golang.org/api/... diff --git a/vendor/google.golang.org/api/CONTRIBUTING.md b/vendor/google.golang.org/api/CONTRIBUTING.md new file mode 100644 index 000000000..e4d36da35 --- /dev/null +++ b/vendor/google.golang.org/api/CONTRIBUTING.md @@ -0,0 +1,484 @@ +# Contributing to the Google API Go Client + +## Master git repo + +Our master git repo is https://code.googlesource.com/google-api-go-client + +## Pull Requests + +We do **NOT** use Github pull requests. We use Gerrit instead +with the same workflow as Go. See below. + +## The source tree + +Most of this project is auto-generated. + +The notable directories which are not auto-generated: + +``` + google-api-go-generator/ -- the generator itself + googleapi/ -- shared common code, used by auto-generated code + examples/ -- sample code +``` + +# Contribution Guidelines + +## Introduction + +This document explains how to contribute changes to the google-api-go-client project. + +## Testing redux + +You've written and tested your code, but +before sending code out for review, run all the tests for the whole +tree to make sure the changes don't break other packages or programs: + +``` +$ make cached +$ go test ./... +... +ok google.golang.org/api/google-api-go-generator 0.226s +ok google.golang.org/api/googleapi 0.015s +... +``` + +Ideally, you will add unit tests to one of the above directories to +demonstrate the changes you are making and include the tests with your +code review. + +## Code review + +Changes to google-api-go-client must be reviewed before they are submitted, +no matter who makes the change. +A custom git command called `git-codereview`, +discussed below, helps manage the code review process through a Google-hosted +[instance](https://code-review.googlesource.com/) of the code review +system called [Gerrit](https://code.google.com/p/gerrit/). + +### Set up authentication for code review + +The Git code hosting server and Gerrit code review server both use a Google +Account to authenticate. You therefore need a Google Account to proceed. +(If you can use the account to +[sign in at google.com](https://www.google.com/accounts/Login), +you can use it to sign in to the code review server.) +The email address you use with the code review system +needs to be added to the [`CONTRIBUTORS`](/CONTRIBUTORS) file +with your first code review. +You can [create a Google Account](https://www.google.com/accounts/NewAccount) +associated with any address where you receive email. + +Visit the site [code.googlesource.com](https://code.googlesource.com) +and log in using your Google Account. +Click on the "Generate Password" link that appears at the top of the page. + +Click the radio button that says "Only `code.googlesource.com`" +to use this authentication token only for the google-api-go-client project. + +Further down the page is a box containing commands to install +the authentication cookie in file called `.gitcookies` in your home +directory. +Copy the text for the commands into a Unix shell window to execute it. +That will install the authentication token. + +(If you are on a Windows computer, you should instead follow the instructions +in the yellow box to run the command.) + +### Register with Gerrit + +Now that you have a Google account and the authentication token, +you need to register your account with Gerrit, the code review system. +To do this, visit [golang.org/cl](https://golang.org/cl) +and log in using the same Google Account you used above. +That is all that is required. + +### Install the git-codereview command + +Now install the `git-codereview` command by running, + +``` +go get -u golang.org/x/review/git-codereview +``` + +Make sure `git-codereview` is installed in your shell path, so that the +`git` command can find it. Check that + +``` +$ git codereview help +``` + +prints help text, not an error. + +Note to Git aficionados: The `git-codereview` command is not required to +upload and manage Gerrit code reviews. For those who prefer plain Git, the text +below gives the Git equivalent of each git-codereview command. If you do use plain +Git, note that you still need the commit hooks that the git-codereview command +configures; those hooks add a Gerrit `Change-Id` line to the commit +message and check that all Go source files have been formatted with gofmt. Even +if you intend to use plain Git for daily work, install the hooks in a new Git +checkout by running `git-codereview hooks`. + +### Set up git aliases + +The `git-codereview` command can be run directly from the shell +by typing, for instance, + +``` +$ git codereview sync +``` + +but it is more convenient to set up aliases for `git-codereview`'s own +subcommands, so that the above becomes, + +``` +$ git sync +``` + +The `git-codereview` subcommands have been chosen to be distinct from +Git's own, so it's safe to do so. + +The aliases are optional, but in the rest of this document we will assume +they are installed. +To install them, copy this text into your Git configuration file +(usually `.gitconfig` in your home directory): + +``` +[alias] + change = codereview change + gofmt = codereview gofmt + mail = codereview mail + pending = codereview pending + submit = codereview submit + sync = codereview sync +``` + +### Understanding the git-codereview command + +After installing the `git-codereview` command, you can run + +``` +$ git codereview help +``` + +to learn more about its commands. +You can also read the [command documentation](https://godoc.org/golang.org/x/review/git-codereview). + +### Switch to the master branch + +New changes should +only be made based on the master branch. +Before making a change, make sure you start on the master branch: + +``` +$ git checkout master +$ git sync +```` + +(In Git terms, `git sync` runs +`git pull -r`.) + +### Make a change + +The entire checked-out tree is writable. +Once you have edited files, you must tell Git that they have been modified. +You must also tell Git about any files that are added, removed, or renamed files. +These operations are done with the usual Git commands, +`git add`, +`git rm`, +and +`git mv`. + +If you wish to checkpoint your work, or are ready to send the code out for review, run + +``` +$ git change <branch> +``` + +from any directory in your google-api-go-client repository to commit the changes so far. +The name `<branch>` is an arbitrary one you choose to identify the +local branch containing your changes. + +(In Git terms, `git change <branch>` +runs `git checkout -b branch`, +then `git branch --set-upstream-to origin/master`, +then `git commit`.) + +Git will open a change description file in your editor. +(It uses the editor named by the `$EDITOR` environment variable, +`vi` by default.) +The file will look like: + +``` +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch foo +# Changes not staged for commit: +# modified: editedfile.go +# +``` + +At the beginning of this file is a blank line; replace it +with a thorough description of your change. +The first line of the change description is conventionally a one-line +summary of the change, prefixed by `google-api-go-client:`, +and is used as the subject for code review mail. +The rest of the +description elaborates and should provide context for the +change and explain what it does. +If there is a helpful reference, mention it here. + +After editing, the template might now read: + +``` +math: improved Sin, Cos and Tan precision for very large arguments + +The existing implementation has poor numerical properties for +large arguments, so use the McGillicutty algorithm to improve +accuracy above 1e10. + +The algorithm is described at http://wikipedia.org/wiki/McGillicutty_Algorithm + +Fixes #54 + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch foo +# Changes not staged for commit: +# modified: editedfile.go +# +``` + +The commented section of the file lists all the modified files in your client. +It is best to keep unrelated changes in different change lists, +so if you see a file listed that should not be included, abort +the command and move that file to a different branch. + +The special notation "Fixes #54" associates the change with issue 54 in the +[google-api-go-client issue tracker](https://github.com/google/google-api-go-client/issues/54). +When this change is eventually submitted, the issue +tracker will automatically mark the issue as fixed. +(There are several such conventions, described in detail in the +[GitHub Issue Tracker documentation](https://help.github.com/articles/closing-issues-via-commit-messages/).) + +Once you have finished writing the commit message, +save the file and exit the editor. + +If you wish to do more editing, re-stage your changes using +`git add`, and then run + +``` +$ git change +``` + +to update the change description and incorporate the staged changes. The +change description contains a `Change-Id` line near the bottom, +added by a Git commit hook during the initial +`git change`. +That line is used by Gerrit to match successive uploads of the same change. +Do not edit or delete it. + +(In Git terms, `git change` with no branch name +runs `git commit --amend`.) + +### Mail the change for review + +Once the change is ready, mail it out for review: + +``` +$ git mail +``` + +You can specify a reviewer or CC interested parties +using the `-r` or `-cc` options. +Both accept a comma-separated list of email addresses: + +``` +$ git mail -r joe@golang.org -cc mabel@example.com,math-nuts@swtch.com +``` + +Unless explicitly told otherwise, such as in the discussion leading +up to sending in the change list, please specify +`bradfitz@golang.org`, `gmlewis@google.com`, or +`mcgreevy@golang.org` as a reviewer. + +(In Git terms, `git mail` pushes the local committed +changes to Gerrit using `git push origin HEAD:refs/for/master`.) + +If your change relates to an open issue, please add a comment to the issue +announcing your proposed fix, including a link to your CL. + +The code review server assigns your change an issue number and URL, +which `git mail` will print, something like: + +``` +remote: New Changes: +remote: https://code-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments +``` + +### Reviewing code + +Running `git mail` will send an email to you and the +reviewers asking them to visit the issue's URL and make comments on the change. +When done, the reviewer adds comments through the Gerrit user interface +and clicks "Reply" to send comments back. +You will receive a mail notification when this happens. +You must reply through the web interface. + +### Revise and upload + +You must respond to review comments through the web interface. + +When you have revised the code and are ready for another round of review, +stage those changes and use `git change` to update the +commit. +To send the update change list for another round of review, +run `git mail` again. + +The reviewer can comment on the new copy, and the process repeats. +The reviewer approves the change by giving it a positive score +(+1 or +2) and replying `LGTM`: looks good to me. + +You can see a list of your pending changes by running +`git pending`, and switch between change branches with +`git change <branch>`. + +### Synchronize your client + +While you were working, others might have submitted changes to the repository. +To update your local branch, run + +``` +$ git sync +``` + +(In git terms, `git sync` runs +`git pull -r`.) + +If files you were editing have changed, Git does its best to merge the +remote changes into your local changes. +It may leave some files to merge by hand. + +For example, suppose you have edited `sin.go` but +someone else has committed an independent change. +When you run `git sync`, +you will get the (scary-looking) output: + +``` +$ git sync +Failed to merge in the changes. +Patch failed at 0023 math: improved Sin, Cos and Tan precision for very large arguments +The copy of the patch that failed is found in: + /home/you/repo/.git/rebase-apply/patch + +When you have resolved this problem, run "git rebase --continue". +If you prefer to skip this patch, run "git rebase --skip" instead. +To check out the original branch and stop rebasing, run "git rebase --abort". +``` + + +If this happens, run + +``` +$ git status +``` + +to see which files failed to merge. +The output will look something like this: + +``` +rebase in progress; onto a24c3eb +You are currently rebasing branch 'mcgillicutty' on 'a24c3eb'. + (fix conflicts and then run "git rebase --continue") + (use "git rebase --skip" to skip this patch) + (use "git rebase --abort" to check out the original branch) + +Unmerged paths: + (use "git reset HEAD <file>..." to unstage) + (use "git add <file>..." to mark resolution) + + _both modified: sin.go_ +``` + + +The only important part in that transcript is the italicized "both modified" +line: Git failed to merge your changes with the conflicting change. +When this happens, Git leaves both sets of edits in the file, +with conflicts marked by `<<<<<<<` and +`>>>>>>>`. +It is now your job to edit the file to combine them. +Continuing the example, searching for those strings in `sin.go` +might turn up: + +``` + arg = scale(arg) +<<<<<<< HEAD + if arg > 1e9 { +======= + if arg > 1e10 { +>>>>>>> mcgillicutty + largeReduce(arg) +``` + +Git doesn't show it, but suppose the original text that both edits +started with was 1e8; you changed it to 1e10 and the other change to 1e9, +so the correct answer might now be 1e10. First, edit the section +to remove the markers and leave the correct code: + +``` + arg = scale(arg) + if arg > 1e10 { + largeReduce(arg) +``` + +Then tell Git that the conflict is resolved by running + +``` +$ git add sin.go +``` + +If you had been editing the file, say for debugging, but do not +care to preserve your changes, you can run +`git reset HEAD sin.go` +to abandon your changes. +Then run `git rebase --continue` to +restore the change commit. + +### Reviewing code by others + +You can import a change proposed by someone else into your local Git repository. +On the Gerrit review page, click the "Download ▼" link in the upper right +corner, copy the "Checkout" command and run it from your local Git repo. +It should look something like this: + +``` +$ git fetch https://code.googlesource.com/review refs/changes/21/1221/1 && git checkout FETCH_HEAD +``` + +To revert, change back to the branch you were working in. + +### Submit the change after the review + +After the code has been `LGTM`'ed, an approver may +submit it to the master branch using the Gerrit UI. +There is a "Submit" button on the web page for the change +that appears once the change is approved (marked +2). + +This checks the change into the repository. +The change description will include a link to the code review, +and the code review will be updated with a link to the change +in the repository. +Since the method used to integrate the changes is "Cherry Pick", +the commit hashes in the repository will be changed by +the submit operation. + +### More information + +In addition to the information here, the Go community maintains a [CodeReview](https://golang.org/wiki/CodeReview) wiki page. +Feel free to contribute to this page as you learn the review process. + +## Contributors + +Files in the google-api-go-client repository don't list author names, +both to avoid clutter and to avoid having to keep the lists up to date. +Instead, please add your name to the [`CONTRIBUTORS`](/CONTRIBUTORS) +file as your first code review, keeping the names in sorted order. diff --git a/vendor/google.golang.org/api/GettingStarted.md b/vendor/google.golang.org/api/GettingStarted.md new file mode 100644 index 000000000..08641d9c5 --- /dev/null +++ b/vendor/google.golang.org/api/GettingStarted.md @@ -0,0 +1,130 @@ +# Getting Started with the Google APIs for Go + +## Getting Started + +This is a quick walk-through of how to get started with the Google APIs for Go. + +## Background + +The first thing to understand is that the Google API libraries are auto-generated for +each language, including Go, so they may not feel like 100% natural for any language. +The Go versions are pretty natural, but please forgive any small non-idiomatic things. +(Suggestions welcome, though!) + +## Installing + +Pick an API and a version of that API to install. +You can find the complete list by looking at the +[directories here](https://github.com/google/google-api-go-client/tree/master/). + +For example, let's install the +[urlshortener's version 1 API](https://godoc.org/google.golang.org/api/urlshortener/v1): + +``` +$ go get -u google.golang.org/api/urlshortener/v1 +``` + +Now it's ready for use in your code. + +## Using + +Once you've installed a library, you import it like this: + +```go +package main + +import ( + "golang.org/x/net/context" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + "google.golang.org/api/urlshortener/v1" +) +``` + +The package name, if you don't override it on your import line, is the name of the +API without the version number. In the case above, just `urlshortener`. + +## Instantiating + +Each API has a `New` function taking an `*http.Client` and returning an API-specific `*Service`. + +You create the service like: + +```go + svc, err := urlshortener.New(httpClient) +``` + +## OAuth HTTP Client + +The HTTP client you pass in to the service must be one that automatically adds +Google-supported Authorization information to the requests. + +There are several ways to do authentication. They will all involve the package +[golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2) in some way. + +### 3-legged OAuth + +For 3-legged OAuth (your application redirecting a user through a website to get a +token giving your application access to that user's resources), you will need to +create an oauth2.Config, + + +```go + var config = &oauth2.Config{ + ClientID: "", // from https://console.developers.google.com/project/<your-project-id>/apiui/credential + ClientSecret: "", // from https://console.developers.google.com/project/<your-project-id>/apiui/credential + Endpoint: google.Endpoint, + Scopes: []string{urlshortener.UrlshortenerScope}, + } +``` + +... and then use the AuthCodeURL, Exchange, and Client methods on it. +For an example, see: https://godoc.org/golang.org/x/oauth2#example-Config + +For the redirect URL, see +https://developers.google.com/identity/protocols/OAuth2InstalledApp#choosingredirecturi + +### Service Accounts + +To use a Google service account, or the GCE metadata service, see +the [golang.org/x/oauth2/google](https://godoc.org/golang.org/x/oauth2/google) package. +In particular, see [google.DefaultClient](https://godoc.org/golang.org/x/oauth2/google#DefaultClient). + +### Using API Keys + +Some APIs require passing API keys from your application. +To do this, you can use +[transport.APIKey](https://godoc.org/google.golang.org/api/googleapi/transport#APIKey): + +```go + ctx := context.WithValue(context.Background(), oauth2.HTTPClient, &http.Client{ + Transport: &transport.APIKey{Key: developerKey}, + }) + oauthConfig := &oauth2.Config{ .... } + var token *oauth2.Token = .... // via cache, or oauthConfig.Exchange + httpClient := oauthConfig.Client(ctx, token) + svc, err := urlshortener.New(httpClient) + ... +``` + +## Using the Service + +Each service contains zero or more methods and zero or more sub-services. +The sub-services related to a specific type of "Resource". + +Those sub-services then contain their own methods. + +For instance, the urlshortener API has just the "Url" sub-service: + +```go + url, err := svc.Url.Get(shortURL).Do() + if err != nil { + ... + } + fmt.Printf("The URL %s goes to %s\n", shortURL, url.LongUrl) +``` + +For a more complete example, see +[urlshortener.go](https://github.com/google/google-api-go-client/tree/master/examples/urlshortener.go) +in the [examples directory](https://github.com/google/google-api-go-client/tree/master/examples/). +(the examples use some functions in `main.go` in the same directory) diff --git a/vendor/google.golang.org/api/NOTES b/vendor/google.golang.org/api/NOTES new file mode 100644 index 000000000..571f6ec79 --- /dev/null +++ b/vendor/google.golang.org/api/NOTES @@ -0,0 +1,13 @@ +Discovery Service: +https://developers.google.com/discovery/ +https://developers.google.com/discovery/v1/reference/ + +The "type" key: +http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 + +The "format" key: +http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.23 +https://developers.google.com/discovery/v1/type-format + +Google JSON format docs: +http://google-styleguide.googlecode.com/svn/trunk/jsoncstyleguide.xml diff --git a/vendor/google.golang.org/api/README.md b/vendor/google.golang.org/api/README.md new file mode 100644 index 000000000..9df50a7ab --- /dev/null +++ b/vendor/google.golang.org/api/README.md @@ -0,0 +1,104 @@ +# Google APIs Client Library for Go + +## Getting Started + +``` +$ go get google.golang.org/api/tasks/v1 +$ go get google.golang.org/api/moderator/v1 +$ go get google.golang.org/api/urlshortener/v1 +... etc ... +``` + +and using: + +```go +package main + +import ( + "net/http" + + "google.golang.org/api/urlshortener/v1" +) + +func main() { + svc, err := urlshortener.New(http.DefaultClient) + // ... +} +``` + +* For a longer tutorial, see the [Getting Started guide](https://github.com/google/google-api-go-client/blob/master/GettingStarted.md). +* For examples, see the [examples directory](https://github.com/google/google-api-go-client/tree/master/examples). +* For support, use the [golang-nuts](https://groups.google.com/group/golang-nuts) mailing list. + +## Status +[![Build Status](https://travis-ci.org/google/google-api-go-client.png)](https://travis-ci.org/google/google-api-go-client) +[![GoDoc](https://godoc.org/google.golang.org/api?status.svg)](https://godoc.org/google.golang.org/api) + +These are auto-generated Go libraries from the Google Discovery Service's JSON description files of the available "new style" Google APIs. + +Due to the auto-generated nature of this collection of libraries, complete APIs or specific versions can appear or go away without notice. +As a result, you should always locally vendor any API(s) that your code relies upon. + +These client libraries are officially supported by Google. However, the libraries are considered complete and are in maintenance mode. This means that we will address critical bugs and security issues but will not add any new features. + +If you're working with Google Cloud Platform APIs such as Datastore or Pub/Sub, +consider using the +[Cloud Client Libraries for Go](https://github.com/GoogleCloudPlatform/google-cloud-go) +instead. These are the new and +idiomatic Go libraries targeted specifically at Google Cloud Platform Services. + +The generator itself and the code it produces are beta. Some APIs are +alpha/beta, and indicated as such in the import path (e.g., +"google.golang.org/api/someapi/v1alpha"). + +## Application Default Credentials Example + +Application Default Credentials provide a simplified way to obtain credentials +for authenticating with Google APIs. + +The Application Default Credentials authenticate as the application itself, +which make them great for working with Google Cloud APIs like Storage or +Datastore. They are the recommended form of authentication when building +applications that run on Google Compute Engine or Google App Engine. + +Default credentials are provided by the `golang.org/x/oauth2/google` package. To use them, add the following import: + +```go +import "golang.org/x/oauth2/google" +``` + +Some credentials types require you to specify scopes, and service entry points may not inject them. If you encounter this situation you may need to specify scopes as follows: + +```go +import ( + "golang.org/x/net/context" + "golang.org/x/oauth2/google" + "google.golang.org/api/compute/v1" +) + +func main() { + // Use oauth2.NoContext if there isn't a good context to pass in. + ctx := context.Background() + + client, err := google.DefaultClient(ctx, compute.ComputeScope) + if err != nil { + //... + } + computeService, err := compute.New(client) + if err != nil { + //... + } +} +``` + +If you need a `oauth2.TokenSource`, use the `DefaultTokenSource` function: + +```go +ts, err := google.DefaultTokenSource(ctx, scope1, scope2, ...) +if err != nil { + //... +} +client := oauth2.NewClient(ctx, ts) +``` + +See also: [golang.org/x/oauth2/google](https://godoc.org/golang.org/x/oauth2/google) package documentation. diff --git a/vendor/google.golang.org/api/TODO b/vendor/google.golang.org/api/TODO new file mode 100644 index 000000000..de2467c39 --- /dev/null +++ b/vendor/google.golang.org/api/TODO @@ -0,0 +1,2 @@ +Moved to: +https://github.com/google/google-api-go-client/issues diff --git a/vendor/google.golang.org/api/api-list.json b/vendor/google.golang.org/api/api-list.json new file mode 100644 index 000000000..dcb7bd4ed --- /dev/null +++ b/vendor/google.golang.org/api/api-list.json @@ -0,0 +1,3140 @@ +{ + "kind": "discovery#directoryList", + "discoveryVersion": "v1", + "items": [ + { + "kind": "discovery#directoryItem", + "id": "abusiveexperiencereport:v1", + "name": "abusiveexperiencereport", + "version": "v1", + "title": "Abusive Experience Report API", + "description": "View Abusive Experience Report data, and get a list of sites that have a significant number of abusive experiences.", + "discoveryRestUrl": "https://abusiveexperiencereport.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/abusive-experience-report/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "acceleratedmobilepageurl:v1", + "name": "acceleratedmobilepageurl", + "version": "v1", + "title": "Accelerated Mobile Pages (AMP) URL API", + "description": "This API contains a single method, batchGet. Call this method to retrieve the AMP URL (and equivalent AMP Cache URL) for given public URL(s).", + "discoveryRestUrl": "https://acceleratedmobilepageurl.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/amp/cache/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangebuyer:v1.2", + "name": "adexchangebuyer", + "version": "v1.2", + "title": "Ad Exchange Buyer API", + "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.2/rest", + "discoveryLink": "./apis/adexchangebuyer/v1.2/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangebuyer:v1.3", + "name": "adexchangebuyer", + "version": "v1.3", + "title": "Ad Exchange Buyer API", + "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.3/rest", + "discoveryLink": "./apis/adexchangebuyer/v1.3/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangebuyer:v1.4", + "name": "adexchangebuyer", + "version": "v1.4", + "title": "Ad Exchange Buyer API", + "description": "Accesses your bidding-account information, submits creatives for validation, finds available direct deals, and retrieves performance reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangebuyer/v1.4/rest", + "discoveryLink": "./apis/adexchangebuyer/v1.4/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangebuyer2:v2beta1", + "name": "adexchangebuyer2", + "version": "v2beta1", + "title": "Ad Exchange Buyer API II", + "description": "Accesses the latest features for managing Ad Exchange accounts, Real-Time Bidding configurations and auction metrics, and Marketplace programmatic deals.", + "discoveryRestUrl": "https://adexchangebuyer.googleapis.com/$discovery/rest?version=v2beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/ad-exchange/buyer-rest/reference/rest/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangeseller:v1", + "name": "adexchangeseller", + "version": "v1", + "title": "Ad Exchange Seller API", + "description": "Accesses the inventory of Ad Exchange seller users and generates reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangeseller/v1/rest", + "discoveryLink": "./apis/adexchangeseller/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/ad-exchange/seller-rest/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangeseller:v1.1", + "name": "adexchangeseller", + "version": "v1.1", + "title": "Ad Exchange Seller API", + "description": "Accesses the inventory of Ad Exchange seller users and generates reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangeseller/v1.1/rest", + "discoveryLink": "./apis/adexchangeseller/v1.1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/ad-exchange/seller-rest/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "adexchangeseller:v2.0", + "name": "adexchangeseller", + "version": "v2.0", + "title": "Ad Exchange Seller API", + "description": "Accesses the inventory of Ad Exchange seller users and generates reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adexchangeseller/v2.0/rest", + "discoveryLink": "./apis/adexchangeseller/v2.0/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/ad-exchange/seller-rest/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "adexperiencereport:v1", + "name": "adexperiencereport", + "version": "v1", + "title": "Ad Experience Report API", + "description": "View Ad Experience Report data, and get a list of sites that have a significant number of annoying ads.", + "discoveryRestUrl": "https://adexperiencereport.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/ad-experience-report/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "admin:datatransfer_v1", + "name": "admin", + "version": "datatransfer_v1", + "title": "Admin Data Transfer API", + "description": "Transfers user data from one user to another.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/datatransfer_v1/rest", + "discoveryLink": "./apis/admin/datatransfer_v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/admin-sdk/data-transfer/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "admin:directory_v1", + "name": "admin", + "version": "directory_v1", + "title": "Admin Directory API", + "description": "Manages enterprise resources such as users and groups, administrative notifications, security features, and more.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/directory_v1/rest", + "discoveryLink": "./apis/admin/directory_v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/admin-sdk/directory/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "admin:reports_v1", + "name": "admin", + "version": "reports_v1", + "title": "Admin Reports API", + "description": "Fetches reports for the administrators of G Suite customers about the usage, collaboration, security, and risk for their users.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/admin/reports_v1/rest", + "discoveryLink": "./apis/admin/reports_v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/admin-sdk/reports/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "adsense:v1.4", + "name": "adsense", + "version": "v1.4", + "title": "AdSense Management API", + "description": "Accesses AdSense publishers' inventory and generates performance reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adsense/v1.4/rest", + "discoveryLink": "./apis/adsense/v1.4/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/adsense-16.png", + "x32": "https://www.google.com/images/icons/product/adsense-32.png" + }, + "documentationLink": "https://developers.google.com/adsense/management/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "adsensehost:v4.1", + "name": "adsensehost", + "version": "v4.1", + "title": "AdSense Host API", + "description": "Generates performance reports, generates ad codes, and provides publisher management capabilities for AdSense Hosts.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/adsensehost/v4.1/rest", + "discoveryLink": "./apis/adsensehost/v4.1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/adsense-16.png", + "x32": "https://www.google.com/images/icons/product/adsense-32.png" + }, + "documentationLink": "https://developers.google.com/adsense/host/", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "analytics:v2.4", + "name": "analytics", + "version": "v2.4", + "title": "Google Analytics API", + "description": "Views and manages your Google Analytics data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/analytics/v2.4/rest", + "discoveryLink": "./apis/analytics/v2.4/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/analytics-16.png", + "x32": "https://www.google.com/images/icons/product/analytics-32.png" + }, + "documentationLink": "https://developers.google.com/analytics/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "analytics:v3", + "name": "analytics", + "version": "v3", + "title": "Google Analytics API", + "description": "Views and manages your Google Analytics data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/analytics/v3/rest", + "discoveryLink": "./apis/analytics/v3/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/analytics-16.png", + "x32": "https://www.google.com/images/icons/product/analytics-32.png" + }, + "documentationLink": "https://developers.google.com/analytics/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "analyticsreporting:v4", + "name": "analyticsreporting", + "version": "v4", + "title": "Google Analytics Reporting API", + "description": "Accesses Analytics report data.", + "discoveryRestUrl": "https://analyticsreporting.googleapis.com/$discovery/rest?version=v4", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/analytics/devguides/reporting/core/v4/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "androiddeviceprovisioning:v1", + "name": "androiddeviceprovisioning", + "version": "v1", + "title": "Android Device Provisioning Partner API", + "description": "Automates reseller integration into zero-touch enrollment by assigning devices to customers and creating device reports.", + "discoveryRestUrl": "https://androiddeviceprovisioning.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/zero-touch/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "androidenterprise:v1", + "name": "androidenterprise", + "version": "v1", + "title": "Google Play EMM API", + "description": "Manages the deployment of apps to Android for Work users.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidenterprise/v1/rest", + "discoveryLink": "./apis/androidenterprise/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/android-16.png", + "x32": "https://www.google.com/images/icons/product/android-32.png" + }, + "documentationLink": "https://developers.google.com/android/work/play/emm-api", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "androidmanagement:v1", + "name": "androidmanagement", + "version": "v1", + "title": "Android Management API", + "description": "The Android Management API provides remote enterprise management of Android devices and apps.", + "discoveryRestUrl": "https://androidmanagement.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/android/management", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "androidpublisher:v1", + "name": "androidpublisher", + "version": "v1", + "title": "Google Play Developer API", + "description": "Lets Android application developers access their Google Play accounts.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v1/rest", + "discoveryLink": "./apis/androidpublisher/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/android-16.png", + "x32": "https://www.google.com/images/icons/product/android-32.png" + }, + "documentationLink": "https://developers.google.com/android-publisher", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "androidpublisher:v1.1", + "name": "androidpublisher", + "version": "v1.1", + "title": "Google Play Developer API", + "description": "Lets Android application developers access their Google Play accounts.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v1.1/rest", + "discoveryLink": "./apis/androidpublisher/v1.1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/android-16.png", + "x32": "https://www.google.com/images/icons/product/android-32.png" + }, + "documentationLink": "https://developers.google.com/android-publisher", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "androidpublisher:v2", + "name": "androidpublisher", + "version": "v2", + "title": "Google Play Developer API", + "description": "Lets Android application developers access their Google Play accounts.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v2/rest", + "discoveryLink": "./apis/androidpublisher/v2/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/android-16.png", + "x32": "https://www.google.com/images/icons/product/android-32.png" + }, + "documentationLink": "https://developers.google.com/android-publisher", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "androidpublisher:v3", + "name": "androidpublisher", + "version": "v3", + "title": "Google Play Developer API", + "description": "Lets Android application developers access their Google Play accounts.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/androidpublisher/v3/rest", + "discoveryLink": "./apis/androidpublisher/v3/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/android-16.png", + "x32": "https://www.google.com/images/icons/product/android-32.png" + }, + "documentationLink": "https://developers.google.com/android-publisher", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "appengine:v1alpha", + "name": "appengine", + "version": "v1alpha", + "title": "Google App Engine Admin API", + "description": "The App Engine Admin API enables developers to provision and manage their App Engine applications.", + "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1alpha", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "appengine:v1beta", + "name": "appengine", + "version": "v1beta", + "title": "Google App Engine Admin API", + "description": "The App Engine Admin API enables developers to provision and manage their App Engine applications.", + "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1beta", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "appengine:v1", + "name": "appengine", + "version": "v1", + "title": "Google App Engine Admin API", + "description": "The App Engine Admin API enables developers to provision and manage their App Engine applications.", + "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "appengine:v1beta4", + "name": "appengine", + "version": "v1beta4", + "title": "Google App Engine Admin API", + "description": "The App Engine Admin API enables developers to provision and manage their App Engine applications.", + "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1beta4", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "appengine:v1beta5", + "name": "appengine", + "version": "v1beta5", + "title": "Google App Engine Admin API", + "description": "The App Engine Admin API enables developers to provision and manage their App Engine applications.", + "discoveryRestUrl": "https://appengine.googleapis.com/$discovery/rest?version=v1beta5", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/appengine/docs/admin-api/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "appsactivity:v1", + "name": "appsactivity", + "version": "v1", + "title": "G Suite Activity API", + "description": "Provides a historical view of activity.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/appsactivity/v1/rest", + "discoveryLink": "./apis/appsactivity/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/google-apps/activity/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "appstate:v1", + "name": "appstate", + "version": "v1", + "title": "Google App State API", + "description": "The Google App State API.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/appstate/v1/rest", + "discoveryLink": "./apis/appstate/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/games/services/web/api/states", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "bigquery:v2", + "name": "bigquery", + "version": "v2", + "title": "BigQuery API", + "description": "A data platform for customers to create, manage, share and query data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/bigquery/v2/rest", + "discoveryLink": "./apis/bigquery/v2/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/search-16.gif", + "x32": "https://www.google.com/images/icons/product/search-32.gif" + }, + "documentationLink": "https://cloud.google.com/bigquery/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "bigquerydatatransfer:v1", + "name": "bigquerydatatransfer", + "version": "v1", + "title": "BigQuery Data Transfer API", + "description": "Transfers data from partner SaaS applications to Google BigQuery on a scheduled, managed basis.", + "discoveryRestUrl": "https://bigquerydatatransfer.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/bigquery/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "blogger:v2", + "name": "blogger", + "version": "v2", + "title": "Blogger API", + "description": "API for access to the data within Blogger.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/blogger/v2/rest", + "discoveryLink": "./apis/blogger/v2/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/blogger-16.png", + "x32": "https://www.google.com/images/icons/product/blogger-32.png" + }, + "documentationLink": "https://developers.google.com/blogger/docs/2.0/json/getting_started", + "labels": [ + "limited_availability" + ], + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "blogger:v3", + "name": "blogger", + "version": "v3", + "title": "Blogger API", + "description": "API for access to the data within Blogger.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/blogger/v3/rest", + "discoveryLink": "./apis/blogger/v3/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/blogger-16.png", + "x32": "https://www.google.com/images/icons/product/blogger-32.png" + }, + "documentationLink": "https://developers.google.com/blogger/docs/3.0/getting_started", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "books:v1", + "name": "books", + "version": "v1", + "title": "Books API", + "description": "Searches for books and manages your Google Books library.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/books/v1/rest", + "discoveryLink": "./apis/books/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/ebooks-16.png", + "x32": "https://www.google.com/images/icons/product/ebooks-32.png" + }, + "documentationLink": "https://developers.google.com/books/docs/v1/getting_started", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "calendar:v3", + "name": "calendar", + "version": "v3", + "title": "Calendar API", + "description": "Manipulates events and other calendar data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest", + "discoveryLink": "./apis/calendar/v3/rest", + "icons": { + "x16": "http://www.google.com/images/icons/product/calendar-16.png", + "x32": "http://www.google.com/images/icons/product/calendar-32.png" + }, + "documentationLink": "https://developers.google.com/google-apps/calendar/firstapp", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "chat:v1", + "name": "chat", + "version": "v1", + "title": "Hangouts Chat API", + "description": "Create bots and extend the new Hangouts Chat.", + "discoveryRestUrl": "https://chat.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/hangouts/chat", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "civicinfo:v2", + "name": "civicinfo", + "version": "v2", + "title": "Google Civic Information API", + "description": "Provides polling places, early vote locations, contest data, election officials, and government representatives for U.S. residential addresses.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/civicinfo/v2/rest", + "discoveryLink": "./apis/civicinfo/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/civic-information", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "classroom:v1", + "name": "classroom", + "version": "v1", + "title": "Google Classroom API", + "description": "Manages classes, rosters, and invitations in Google Classroom.", + "discoveryRestUrl": "https://classroom.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/classroom", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudbilling:v1", + "name": "cloudbilling", + "version": "v1", + "title": "Cloud Billing API", + "description": "Allows developers to manage billing for their Google Cloud Platform projects programmatically.", + "discoveryRestUrl": "https://cloudbilling.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/billing/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudbuild:v1", + "name": "cloudbuild", + "version": "v1", + "title": "Cloud Container Builder API", + "description": "Builds container images in the cloud.", + "discoveryRestUrl": "https://cloudbuild.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/container-builder/docs/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "clouddebugger:v2", + "name": "clouddebugger", + "version": "v2", + "title": "Stackdriver Debugger API", + "description": "Examines the call stack and variables of a running application without stopping or slowing it down.", + "discoveryRestUrl": "https://clouddebugger.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/debugger", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "clouderrorreporting:v1beta1", + "name": "clouderrorreporting", + "version": "v1beta1", + "title": "Stackdriver Error Reporting API", + "description": "Groups and counts similar errors from cloud services and applications, reports new errors, and provides access to error groups and their associated errors.", + "discoveryRestUrl": "https://clouderrorreporting.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/error-reporting/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudfunctions:v1", + "name": "cloudfunctions", + "version": "v1", + "title": "Cloud Functions API", + "description": "Manages lightweight user-provided functions executed in response to events.", + "discoveryRestUrl": "https://cloudfunctions.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/functions", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudfunctions:v1beta2", + "name": "cloudfunctions", + "version": "v1beta2", + "title": "Cloud Functions API", + "description": "Manages lightweight user-provided functions executed in response to events.", + "discoveryRestUrl": "https://cloudfunctions.googleapis.com/$discovery/rest?version=v1beta2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/functions", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudiot:v1", + "name": "cloudiot", + "version": "v1", + "title": "Cloud IoT API", + "description": "Registers and manages IoT (Internet of Things) devices that connect to the Google Cloud Platform.", + "discoveryRestUrl": "https://cloudiot.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/iot", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudiot:v1beta1", + "name": "cloudiot", + "version": "v1beta1", + "title": "Cloud IoT API", + "description": "Registers and manages IoT (Internet of Things) devices that connect to the Google Cloud Platform.", + "discoveryRestUrl": "https://cloudiot.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/iot", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudkms:v1", + "name": "cloudkms", + "version": "v1", + "title": "Cloud Key Management Service (KMS) API", + "description": "Manages encryption for your cloud services the same way you do on-premises. You can generate, use, rotate, and destroy AES256 encryption keys.", + "discoveryRestUrl": "https://cloudkms.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/kms/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudresourcemanager:v1", + "name": "cloudresourcemanager", + "version": "v1", + "title": "Cloud Resource Manager API", + "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", + "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/resource-manager", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudresourcemanager:v1beta1", + "name": "cloudresourcemanager", + "version": "v1beta1", + "title": "Cloud Resource Manager API", + "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", + "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/resource-manager", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudresourcemanager:v2", + "name": "cloudresourcemanager", + "version": "v2", + "title": "Cloud Resource Manager API", + "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", + "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/resource-manager", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudresourcemanager:v2beta1", + "name": "cloudresourcemanager", + "version": "v2beta1", + "title": "Cloud Resource Manager API", + "description": "The Google Cloud Resource Manager API provides methods for creating, reading, and updating project metadata.", + "discoveryRestUrl": "https://cloudresourcemanager.googleapis.com/$discovery/rest?version=v2beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/resource-manager", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudshell:v1alpha1", + "name": "cloudshell", + "version": "v1alpha1", + "title": "Cloud Shell API", + "description": "Allows users to start, configure, and connect to interactive shell sessions running in the cloud.", + "discoveryRestUrl": "https://cloudshell.googleapis.com/$discovery/rest?version=v1alpha1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/shell/docs/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudshell:v1", + "name": "cloudshell", + "version": "v1", + "title": "Cloud Shell API", + "description": "Allows users to start, configure, and connect to interactive shell sessions running in the cloud.", + "discoveryRestUrl": "https://cloudshell.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/shell/docs/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudtasks:v2beta2", + "name": "cloudtasks", + "version": "v2beta2", + "title": "Cloud Tasks API", + "description": "Manages the execution of large numbers of distributed requests. Cloud Tasks is in Alpha.", + "discoveryRestUrl": "https://cloudtasks.googleapis.com/$discovery/rest?version=v2beta2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/cloud-tasks/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "cloudtrace:v1", + "name": "cloudtrace", + "version": "v1", + "title": "Stackdriver Trace API", + "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API.", + "discoveryRestUrl": "https://cloudtrace.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/trace", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "cloudtrace:v2", + "name": "cloudtrace", + "version": "v2", + "title": "Stackdriver Trace API", + "description": "Sends application trace data to Stackdriver Trace for viewing. Trace data is collected for all App Engine applications by default. Trace data from other applications can be provided using this API.", + "discoveryRestUrl": "https://cloudtrace.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/trace", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "composer:v1beta1", + "name": "composer", + "version": "v1beta1", + "title": "Cloud Composer API", + "description": "Manages Apache Airflow environments on Google Cloud Platform.", + "discoveryRestUrl": "https://composer.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/composer/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "compute:alpha", + "name": "compute", + "version": "alpha", + "title": "Compute Engine API", + "description": "Creates and runs virtual machines on Google Cloud Platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/alpha/rest", + "discoveryLink": "./apis/compute/alpha/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", + "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" + }, + "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "compute:beta", + "name": "compute", + "version": "beta", + "title": "Compute Engine API", + "description": "Creates and runs virtual machines on Google Cloud Platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/beta/rest", + "discoveryLink": "./apis/compute/beta/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", + "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" + }, + "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "compute:v1", + "name": "compute", + "version": "v1", + "title": "Compute Engine API", + "description": "Creates and runs virtual machines on Google Cloud Platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest", + "discoveryLink": "./apis/compute/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", + "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" + }, + "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "container:v1", + "name": "container", + "version": "v1", + "title": "Kubernetes Engine API", + "description": "The Google Kubernetes Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.", + "discoveryRestUrl": "https://container.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/container-engine/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "container:v1beta1", + "name": "container", + "version": "v1beta1", + "title": "Kubernetes Engine API", + "description": "The Google Kubernetes Engine API is used for building and managing container based applications, powered by the open source Kubernetes technology.", + "discoveryRestUrl": "https://container.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/container-engine/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "content:v2sandbox", + "name": "content", + "version": "v2sandbox", + "title": "Content API for Shopping", + "description": "Manages product items, inventory, and Merchant Center accounts for Google Shopping.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/content/v2sandbox/rest", + "discoveryLink": "./apis/content/v2sandbox/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/shopping-content", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "content:v2", + "name": "content", + "version": "v2", + "title": "Content API for Shopping", + "description": "Manages product items, inventory, and Merchant Center accounts for Google Shopping.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/content/v2/rest", + "discoveryLink": "./apis/content/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/shopping-content", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "customsearch:v1", + "name": "customsearch", + "version": "v1", + "title": "CustomSearch API", + "description": "Searches over a website or collection of websites", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/customsearch/v1/rest", + "discoveryLink": "./apis/customsearch/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/custom-search/v1/using_rest", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dataflow:v1b3", + "name": "dataflow", + "version": "v1b3", + "title": "Dataflow API", + "description": "Manages Google Cloud Dataflow projects on Google Cloud Platform.", + "discoveryRestUrl": "https://dataflow.googleapis.com/$discovery/rest?version=v1b3", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/dataflow", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dataproc:v1", + "name": "dataproc", + "version": "v1", + "title": "Cloud Dataproc API", + "description": "Manages Hadoop-based clusters and jobs on Google Cloud Platform.", + "discoveryRestUrl": "https://dataproc.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/dataproc/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dataproc:v1beta2", + "name": "dataproc", + "version": "v1beta2", + "title": "Cloud Dataproc API", + "description": "Manages Hadoop-based clusters and jobs on Google Cloud Platform.", + "discoveryRestUrl": "https://dataproc.googleapis.com/$discovery/rest?version=v1beta2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/dataproc/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "datastore:v1", + "name": "datastore", + "version": "v1", + "title": "Cloud Datastore API", + "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", + "discoveryRestUrl": "https://datastore.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/datastore/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "datastore:v1beta1", + "name": "datastore", + "version": "v1beta1", + "title": "Cloud Datastore API", + "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", + "discoveryRestUrl": "https://datastore.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/datastore/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "datastore:v1beta3", + "name": "datastore", + "version": "v1beta3", + "title": "Cloud Datastore API", + "description": "Accesses the schemaless NoSQL database to provide fully managed, robust, scalable storage for your application.", + "discoveryRestUrl": "https://datastore.googleapis.com/$discovery/rest?version=v1beta3", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/datastore/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "deploymentmanager:alpha", + "name": "deploymentmanager", + "version": "alpha", + "title": "Google Cloud Deployment Manager Alpha API", + "description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/alpha/rest", + "discoveryLink": "./apis/deploymentmanager/alpha/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/deployment-manager/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "deploymentmanager:v2beta", + "name": "deploymentmanager", + "version": "v2beta", + "title": "Google Cloud Deployment Manager API V2Beta Methods", + "description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/v2beta/rest", + "discoveryLink": "./apis/deploymentmanager/v2beta/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/deployment-manager/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "deploymentmanager:v2", + "name": "deploymentmanager", + "version": "v2", + "title": "Google Cloud Deployment Manager API", + "description": "Declares, configures, and deploys complex solutions on Google Cloud Platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/deploymentmanager/v2/rest", + "discoveryLink": "./apis/deploymentmanager/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/deployment-manager/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dfareporting:v2.8", + "name": "dfareporting", + "version": "v2.8", + "title": "DCM/DFA Reporting And Trafficking API", + "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v2.8/rest", + "discoveryLink": "./apis/dfareporting/v2.8/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/doubleclick-advertisers/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "dfareporting:v3.0", + "name": "dfareporting", + "version": "v3.0", + "title": "DCM/DFA Reporting And Trafficking API", + "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.0/rest", + "discoveryLink": "./apis/dfareporting/v3.0/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/doubleclick-advertisers/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "dfareporting:v3.1", + "name": "dfareporting", + "version": "v3.1", + "title": "DCM/DFA Reporting And Trafficking API", + "description": "Manages your DoubleClick Campaign Manager ad campaigns and reports.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dfareporting/v3.1/rest", + "discoveryLink": "./apis/dfareporting/v3.1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/doubleclick-16.gif", + "x32": "https://www.google.com/images/icons/product/doubleclick-32.gif" + }, + "documentationLink": "https://developers.google.com/doubleclick-advertisers/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dialogflow:v2", + "name": "dialogflow", + "version": "v2", + "title": "Dialogflow API", + "description": "An end-to-end development suite for conversational interfaces (e.g., chatbots, voice-powered apps and devices).", + "discoveryRestUrl": "https://dialogflow.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/dialogflow-enterprise/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dialogflow:v2beta1", + "name": "dialogflow", + "version": "v2beta1", + "title": "Dialogflow API", + "description": "An end-to-end development suite for conversational interfaces (e.g., chatbots, voice-powered apps and devices).", + "discoveryRestUrl": "https://dialogflow.googleapis.com/$discovery/rest?version=v2beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/dialogflow-enterprise/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "digitalassetlinks:v1", + "name": "digitalassetlinks", + "version": "v1", + "title": "Digital Asset Links API", + "description": "API for discovering relationships between online assets such as web sites or mobile apps.", + "discoveryRestUrl": "https://digitalassetlinks.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/digital-asset-links/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "discovery:v1", + "name": "discovery", + "version": "v1", + "title": "APIs Discovery Service", + "description": "Provides information about other Google APIs, such as what APIs are available, the resource, and method details for each API.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/discovery/v1/rest", + "discoveryLink": "./apis/discovery/v1/rest", + "icons": { + "x16": "http://www.google.com/images/icons/feature/filing_cabinet_search-g16.png", + "x32": "http://www.google.com/images/icons/feature/filing_cabinet_search-g32.png" + }, + "documentationLink": "https://developers.google.com/discovery/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dlp:v2", + "name": "dlp", + "version": "v2", + "title": "Cloud Data Loss Prevention (DLP) API", + "description": "Provides methods for detection, risk analysis, and de-identification of privacy-sensitive fragments in text, images, and Google Cloud Platform storage repositories.", + "discoveryRestUrl": "https://dlp.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/dlp/docs/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dns:v1", + "name": "dns", + "version": "v1", + "title": "Google Cloud DNS API", + "description": "Configures and serves authoritative DNS records.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v1/rest", + "discoveryLink": "./apis/dns/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/cloud-dns", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "dns:v1beta2", + "name": "dns", + "version": "v1beta2", + "title": "Google Cloud DNS API", + "description": "Configures and serves authoritative DNS records.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v1beta2/rest", + "discoveryLink": "./apis/dns/v1beta2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/cloud-dns", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "dns:v2beta1", + "name": "dns", + "version": "v2beta1", + "title": "Google Cloud DNS API", + "description": "Configures and serves authoritative DNS records.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/dns/v2beta1/rest", + "discoveryLink": "./apis/dns/v2beta1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/cloud-dns", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "doubleclickbidmanager:v1", + "name": "doubleclickbidmanager", + "version": "v1", + "title": "DoubleClick Bid Manager API", + "description": "API for viewing and managing your reports in DoubleClick Bid Manager.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/doubleclickbidmanager/v1/rest", + "discoveryLink": "./apis/doubleclickbidmanager/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/bid-manager/", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "doubleclicksearch:v2", + "name": "doubleclicksearch", + "version": "v2", + "title": "DoubleClick Search API", + "description": "Reports and modifies your advertising data in DoubleClick Search (for example, campaigns, ad groups, keywords, and conversions).", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/doubleclicksearch/v2/rest", + "discoveryLink": "./apis/doubleclicksearch/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/doubleclick-search/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "drive:v2", + "name": "drive", + "version": "v2", + "title": "Drive API", + "description": "Manages files in Drive including uploading, downloading, searching, detecting changes, and updating sharing permissions.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v2/rest", + "discoveryLink": "./apis/drive/v2/rest", + "icons": { + "x16": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_16.png", + "x32": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_32.png" + }, + "documentationLink": "https://developers.google.com/drive/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "drive:v3", + "name": "drive", + "version": "v3", + "title": "Drive API", + "description": "Manages files in Drive including uploading, downloading, searching, detecting changes, and updating sharing permissions.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest", + "discoveryLink": "./apis/drive/v3/rest", + "icons": { + "x16": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_16.png", + "x32": "https://ssl.gstatic.com/docs/doclist/images/drive_icon_32.png" + }, + "documentationLink": "https://developers.google.com/drive/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "firebasedynamiclinks:v1", + "name": "firebasedynamiclinks", + "version": "v1", + "title": "Firebase Dynamic Links API", + "description": "Programmatically creates and manages Firebase Dynamic Links.", + "discoveryRestUrl": "https://firebasedynamiclinks.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://firebase.google.com/docs/dynamic-links/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "firebaserules:v1", + "name": "firebaserules", + "version": "v1", + "title": "Firebase Rules API", + "description": "Creates and manages rules that determine when a Firebase Rules-enabled service should permit a request.", + "discoveryRestUrl": "https://firebaserules.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://firebase.google.com/docs/storage/security", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "firestore:v1beta1", + "name": "firestore", + "version": "v1beta1", + "title": "Cloud Firestore API", + "description": "", + "discoveryRestUrl": "https://firestore.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/firestore", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "fitness:v1", + "name": "fitness", + "version": "v1", + "title": "Fitness", + "description": "Stores and accesses user data in the fitness store from apps on any platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fitness/v1/rest", + "discoveryLink": "./apis/fitness/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/fit/rest/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "fusiontables:v1", + "name": "fusiontables", + "version": "v1", + "title": "Fusion Tables API", + "description": "API for working with Fusion Tables data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fusiontables/v1/rest", + "discoveryLink": "./apis/fusiontables/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/fusiontables", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "fusiontables:v2", + "name": "fusiontables", + "version": "v2", + "title": "Fusion Tables API", + "description": "API for working with Fusion Tables data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/fusiontables/v2/rest", + "discoveryLink": "./apis/fusiontables/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/fusiontables", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "games:v1", + "name": "games", + "version": "v1", + "title": "Google Play Game Services API", + "description": "The API for Google Play Game Services.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/games/v1/rest", + "discoveryLink": "./apis/games/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/games/services/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "gamesConfiguration:v1configuration", + "name": "gamesConfiguration", + "version": "v1configuration", + "title": "Google Play Game Services Publishing API", + "description": "The Publishing API for Google Play Game Services.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gamesConfiguration/v1configuration/rest", + "discoveryLink": "./apis/gamesConfiguration/v1configuration/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/games/services", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "gamesManagement:v1management", + "name": "gamesManagement", + "version": "v1management", + "title": "Google Play Game Services Management API", + "description": "The Management API for Google Play Game Services.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gamesManagement/v1management/rest", + "discoveryLink": "./apis/gamesManagement/v1management/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/games/services", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "genomics:v1alpha2", + "name": "genomics", + "version": "v1alpha2", + "title": "Genomics API", + "description": "Upload, process, query, and search Genomics data in the cloud.", + "discoveryRestUrl": "https://genomics.googleapis.com/$discovery/rest?version=v1alpha2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/genomics", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "genomics:v2alpha1", + "name": "genomics", + "version": "v2alpha1", + "title": "Genomics API", + "description": "Upload, process, query, and search Genomics data in the cloud.", + "discoveryRestUrl": "https://genomics.googleapis.com/$discovery/rest?version=v2alpha1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/genomics", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "genomics:v1", + "name": "genomics", + "version": "v1", + "title": "Genomics API", + "description": "Upload, process, query, and search Genomics data in the cloud.", + "discoveryRestUrl": "https://genomics.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/genomics", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "gmail:v1", + "name": "gmail", + "version": "v1", + "title": "Gmail API", + "description": "Access Gmail mailboxes including sending user email.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest", + "discoveryLink": "./apis/gmail/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/googlemail-16.png", + "x32": "https://www.google.com/images/icons/product/googlemail-32.png" + }, + "documentationLink": "https://developers.google.com/gmail/api/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "groupsmigration:v1", + "name": "groupsmigration", + "version": "v1", + "title": "Groups Migration API", + "description": "Groups Migration Api.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/groupsmigration/v1/rest", + "discoveryLink": "./apis/groupsmigration/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/discussions-16.gif", + "x32": "https://www.google.com/images/icons/product/discussions-32.gif" + }, + "documentationLink": "https://developers.google.com/google-apps/groups-migration/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "groupssettings:v1", + "name": "groupssettings", + "version": "v1", + "title": "Groups Settings API", + "description": "Lets you manage permission levels and related settings of a group.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/groupssettings/v1/rest", + "discoveryLink": "./apis/groupssettings/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/google-apps/groups-settings/get_started", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "iam:v1", + "name": "iam", + "version": "v1", + "title": "Identity and Access Management (IAM) API", + "description": "Manages identity and access control for Google Cloud Platform resources, including the creation of service accounts, which you can use to authenticate to Google and make API calls.", + "discoveryRestUrl": "https://iam.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/iam/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "identitytoolkit:v3", + "name": "identitytoolkit", + "version": "v3", + "title": "Google Identity Toolkit API", + "description": "Help the third party sites to implement federated login.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/identitytoolkit/v3/rest", + "discoveryLink": "./apis/identitytoolkit/v3/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/identity-toolkit/v3/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "jobs:v2", + "name": "jobs", + "version": "v2", + "title": "Cloud Job Discovery", + "description": "Cloud Job Discovery provides the capability to create, read, update, and delete job postings, as well as search jobs based on keywords and filters.", + "discoveryRestUrl": "https://jobs.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/job-discovery/docs", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "kgsearch:v1", + "name": "kgsearch", + "version": "v1", + "title": "Knowledge Graph Search API", + "description": "Searches the Google Knowledge Graph for entities.", + "discoveryRestUrl": "https://kgsearch.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/knowledge-graph/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "language:v1", + "name": "language", + "version": "v1", + "title": "Cloud Natural Language API", + "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", + "discoveryRestUrl": "https://language.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/natural-language/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "language:v1beta1", + "name": "language", + "version": "v1beta1", + "title": "Cloud Natural Language API", + "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", + "discoveryRestUrl": "https://language.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/natural-language/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "language:v1beta2", + "name": "language", + "version": "v1beta2", + "title": "Cloud Natural Language API", + "description": "Provides natural language understanding technologies to developers. Examples include sentiment analysis, entity recognition, entity sentiment analysis, and text annotations.", + "discoveryRestUrl": "https://language.googleapis.com/$discovery/rest?version=v1beta2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/natural-language/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "licensing:v1", + "name": "licensing", + "version": "v1", + "title": "Enterprise License Manager API", + "description": "Views and manages licenses for your domain.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/licensing/v1/rest", + "discoveryLink": "./apis/licensing/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/google-apps/licensing/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "logging:v2", + "name": "logging", + "version": "v2", + "title": "Stackdriver Logging API", + "description": "Writes log entries and manages your Stackdriver Logging configuration.", + "discoveryRestUrl": "https://logging.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/logging/docs/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "logging:v2beta1", + "name": "logging", + "version": "v2beta1", + "title": "Stackdriver Logging API", + "description": "Writes log entries and manages your Stackdriver Logging configuration.", + "discoveryRestUrl": "https://logging.googleapis.com/$discovery/rest?version=v2beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/logging/docs/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "manufacturers:v1", + "name": "manufacturers", + "version": "v1", + "title": "Manufacturer Center API", + "description": "Public API for managing Manufacturer Center related data.", + "discoveryRestUrl": "https://manufacturers.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/manufacturers/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "mirror:v1", + "name": "mirror", + "version": "v1", + "title": "Google Mirror API", + "description": "Interacts with Glass users via the timeline.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/mirror/v1/rest", + "discoveryLink": "./apis/mirror/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/glass", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "ml:v1", + "name": "ml", + "version": "v1", + "title": "Cloud Machine Learning Engine", + "description": "An API to enable creating and using machine learning models.", + "discoveryRestUrl": "https://ml.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/ml/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "monitoring:v3", + "name": "monitoring", + "version": "v3", + "title": "Stackdriver Monitoring API", + "description": "Manages your Stackdriver Monitoring data and configurations. Most projects must be associated with a Stackdriver account, with a few exceptions as noted on the individual method pages.", + "discoveryRestUrl": "https://monitoring.googleapis.com/$discovery/rest?version=v3", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/monitoring/api/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "oauth2:v1", + "name": "oauth2", + "version": "v1", + "title": "Google OAuth2 API", + "description": "Obtains end-user authorization grants for use with other Google APIs.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/oauth2/v1/rest", + "discoveryLink": "./apis/oauth2/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/accounts/docs/OAuth2", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "oauth2:v2", + "name": "oauth2", + "version": "v2", + "title": "Google OAuth2 API", + "description": "Obtains end-user authorization grants for use with other Google APIs.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/oauth2/v2/rest", + "discoveryLink": "./apis/oauth2/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/accounts/docs/OAuth2", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "oslogin:v1alpha", + "name": "oslogin", + "version": "v1alpha", + "title": "Cloud OS Login API", + "description": "Manages OS login configuration for Google account users.", + "discoveryRestUrl": "https://oslogin.googleapis.com/$discovery/rest?version=v1alpha", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "oslogin:v1beta", + "name": "oslogin", + "version": "v1beta", + "title": "Cloud OS Login API", + "description": "Manages OS login configuration for Google account users.", + "discoveryRestUrl": "https://oslogin.googleapis.com/$discovery/rest?version=v1beta", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "oslogin:v1", + "name": "oslogin", + "version": "v1", + "title": "Cloud OS Login API", + "description": "Manages OS login configuration for Google account users.", + "discoveryRestUrl": "https://oslogin.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/compute/docs/oslogin/rest/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "pagespeedonline:v1", + "name": "pagespeedonline", + "version": "v1", + "title": "PageSpeed Insights API", + "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v1/rest", + "discoveryLink": "./apis/pagespeedonline/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", + "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" + }, + "documentationLink": "https://developers.google.com/speed/docs/insights/v1/getting_started", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "pagespeedonline:v2", + "name": "pagespeedonline", + "version": "v2", + "title": "PageSpeed Insights API", + "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v2/rest", + "discoveryLink": "./apis/pagespeedonline/v2/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", + "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" + }, + "documentationLink": "https://developers.google.com/speed/docs/insights/v2/getting-started", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "pagespeedonline:v4", + "name": "pagespeedonline", + "version": "v4", + "title": "PageSpeed Insights API", + "description": "Analyzes the performance of a web page and provides tailored suggestions to make that page faster.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/pagespeedonline/v4/rest", + "discoveryLink": "./apis/pagespeedonline/v4/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/pagespeed-16.png", + "x32": "https://www.google.com/images/icons/product/pagespeed-32.png" + }, + "documentationLink": "https://developers.google.com/speed/docs/insights/v4/getting-started", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "partners:v2", + "name": "partners", + "version": "v2", + "title": "Google Partners API", + "description": "Searches certified companies and creates contact leads with them, and also audits the usage of clients.", + "discoveryRestUrl": "https://partners.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/partners/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "people:v1", + "name": "people", + "version": "v1", + "title": "People API", + "description": "Provides access to information about profiles and contacts.", + "discoveryRestUrl": "https://people.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/people/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "photoslibrary:v1", + "name": "photoslibrary", + "version": "v1", + "title": "Photos Library API", + "description": "Manage photos, videos, and albums in Google Photos", + "discoveryRestUrl": "https://photoslibrary.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/photos/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "playcustomapp:v1", + "name": "playcustomapp", + "version": "v1", + "title": "Google Play Custom App Publishing API", + "description": "An API to publish custom Android apps.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/playcustomapp/v1/rest", + "discoveryLink": "./apis/playcustomapp/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/android/work/play/custom-app-api", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "plus:v1", + "name": "plus", + "version": "v1", + "title": "Google+ API", + "description": "Builds on top of the Google+ platform.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/plus/v1/rest", + "discoveryLink": "./apis/plus/v1/rest", + "icons": { + "x16": "http://www.google.com/images/icons/product/gplus-16.png", + "x32": "http://www.google.com/images/icons/product/gplus-32.png" + }, + "documentationLink": "https://developers.google.com/+/api/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "plusDomains:v1", + "name": "plusDomains", + "version": "v1", + "title": "Google+ Domains API", + "description": "Builds on top of the Google+ platform for Google Apps Domains.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/plusDomains/v1/rest", + "discoveryLink": "./apis/plusDomains/v1/rest", + "icons": { + "x16": "http://www.google.com/images/icons/product/gplus-16.png", + "x32": "http://www.google.com/images/icons/product/gplus-32.png" + }, + "documentationLink": "https://developers.google.com/+/domains/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "poly:v1", + "name": "poly", + "version": "v1", + "title": "Poly API", + "description": "The Poly API provides read-only access to assets hosted on poly.google.com.", + "discoveryRestUrl": "https://poly.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/poly/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "proximitybeacon:v1beta1", + "name": "proximitybeacon", + "version": "v1beta1", + "title": "Google Proximity Beacon API", + "description": "Registers, manages, indexes, and searches beacons.", + "discoveryRestUrl": "https://proximitybeacon.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/beacons/proximity/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "pubsub:v1beta1a", + "name": "pubsub", + "version": "v1beta1a", + "title": "Cloud Pub/Sub API", + "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", + "discoveryRestUrl": "https://pubsub.googleapis.com/$discovery/rest?version=v1beta1a", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/pubsub/docs", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "pubsub:v1", + "name": "pubsub", + "version": "v1", + "title": "Cloud Pub/Sub API", + "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", + "discoveryRestUrl": "https://pubsub.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/pubsub/docs", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "pubsub:v1beta2", + "name": "pubsub", + "version": "v1beta2", + "title": "Cloud Pub/Sub API", + "description": "Provides reliable, many-to-many, asynchronous messaging between applications.", + "discoveryRestUrl": "https://pubsub.googleapis.com/$discovery/rest?version=v1beta2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/pubsub/docs", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "redis:v1beta1", + "name": "redis", + "version": "v1beta1", + "title": "Cloud Memorystore for Redis API", + "description": "The Google Cloud Memorystore for Redis API is used for creating and managing Redis instances on the Google Cloud Platform.", + "discoveryRestUrl": "https://redis.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/memorystore/docs/redis/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "replicapool:v1beta1", + "name": "replicapool", + "version": "v1beta1", + "title": "Replica Pool API", + "description": "The Replica Pool API allows users to declaratively provision and manage groups of Google Compute Engine instances based on a common template.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapool/v1beta1/rest", + "discoveryLink": "./apis/replicapool/v1beta1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/compute/docs/replica-pool/", + "labels": [ + "limited_availability" + ], + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "replicapool:v1beta2", + "name": "replicapool", + "version": "v1beta2", + "title": "Google Compute Engine Instance Group Manager API", + "description": "[Deprecated. Please use Instance Group Manager in Compute API] Provides groups of homogenous Compute Engine instances.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapool/v1beta2/rest", + "discoveryLink": "./apis/replicapool/v1beta2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/compute/docs/instance-groups/manager/v1beta2", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "replicapoolupdater:v1beta1", + "name": "replicapoolupdater", + "version": "v1beta1", + "title": "Google Compute Engine Instance Group Updater API", + "description": "[Deprecated. Please use compute.instanceGroupManagers.update method. replicapoolupdater API will be disabled after December 30th, 2016] Updates groups of Compute Engine instances.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/replicapoolupdater/v1beta1/rest", + "discoveryLink": "./apis/replicapoolupdater/v1beta1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/compute/docs/instance-groups/manager/#applying_rolling_updates_using_the_updater_service", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "reseller:v1", + "name": "reseller", + "version": "v1", + "title": "Enterprise Apps Reseller API", + "description": "Creates and manages your customers and their subscriptions.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/reseller/v1/rest", + "discoveryLink": "./apis/reseller/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/google-apps/reseller/", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "resourceviews:v1beta1", + "name": "resourceviews", + "version": "v1beta1", + "title": "Resource Views API", + "description": "The Resource View API allows users to create and manage logical sets of Google Compute Engine instances.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/resourceviews/v1beta1/rest", + "discoveryLink": "./apis/resourceviews/v1beta1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/compute/", + "labels": [ + "limited_availability" + ], + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "resourceviews:v1beta2", + "name": "resourceviews", + "version": "v1beta2", + "title": "Google Compute Engine Instance Groups API", + "description": "The Resource View API allows users to create and manage logical sets of Google Compute Engine instances.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/resourceviews/v1beta2/rest", + "discoveryLink": "./apis/resourceviews/v1beta2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/compute/", + "labels": [ + "limited_availability" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "runtimeconfig:v1", + "name": "runtimeconfig", + "version": "v1", + "title": "Google Cloud Runtime Configuration API", + "description": "The Runtime Configurator allows you to dynamically configure and expose variables through Google Cloud Platform. In addition, you can also set Watchers and Waiters that will watch for changes to your data and return based on certain conditions.", + "discoveryRestUrl": "https://runtimeconfig.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/deployment-manager/runtime-configurator/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "runtimeconfig:v1beta1", + "name": "runtimeconfig", + "version": "v1beta1", + "title": "Google Cloud Runtime Configuration API", + "description": "The Runtime Configurator allows you to dynamically configure and expose variables through Google Cloud Platform. In addition, you can also set Watchers and Waiters that will watch for changes to your data and return based on certain conditions.", + "discoveryRestUrl": "https://runtimeconfig.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/deployment-manager/runtime-configurator/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "safebrowsing:v4", + "name": "safebrowsing", + "version": "v4", + "title": "Safe Browsing API", + "description": "Enables client applications to check web resources (most commonly URLs) against Google-generated lists of unsafe web resources.", + "discoveryRestUrl": "https://safebrowsing.googleapis.com/$discovery/rest?version=v4", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/safe-browsing/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "script:v1", + "name": "script", + "version": "v1", + "title": "Apps Script API", + "description": "An API for managing and executing Google Apps Script projects. Note: In order to use this API in your apps, you must enable it for use. To allow other apps to manage your scripts, you must grant them access.", + "discoveryRestUrl": "https://script.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/apps-script/api/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "searchconsole:v1", + "name": "searchconsole", + "version": "v1", + "title": "Google Search Console URL Testing Tools API", + "description": "Provides tools for running validation tests against single URLs", + "discoveryRestUrl": "https://searchconsole.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/webmaster-tools/search-console-api/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "servicebroker:v1alpha1", + "name": "servicebroker", + "version": "v1alpha1", + "title": "Service Broker API", + "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", + "discoveryRestUrl": "https://servicebroker.googleapis.com/$discovery/rest?version=v1alpha1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "servicebroker:v1", + "name": "servicebroker", + "version": "v1", + "title": "Service Broker API", + "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", + "discoveryRestUrl": "https://servicebroker.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "servicebroker:v1beta1", + "name": "servicebroker", + "version": "v1beta1", + "title": "Service Broker API", + "description": "The Google Cloud Platform Service Broker API provides Google hosted implementation of the Open Service Broker API (https://www.openservicebrokerapi.org/).", + "discoveryRestUrl": "https://servicebroker.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/kubernetes-engine/docs/concepts/add-on/service-broker", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "serviceconsumermanagement:v1", + "name": "serviceconsumermanagement", + "version": "v1", + "title": "Service Consumer Management API", + "description": "Provides management methods for configuring service producer resources on Google Cloud.", + "discoveryRestUrl": "https://serviceconsumermanagement.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/service-consumer-management/docs/overview", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "servicecontrol:v1", + "name": "servicecontrol", + "version": "v1", + "title": "Service Control API", + "description": "Google Service Control provides control plane functionality to managed services, such as logging, monitoring, and status checks.", + "discoveryRestUrl": "https://servicecontrol.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/service-control/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "servicemanagement:v1", + "name": "servicemanagement", + "version": "v1", + "title": "Service Management API", + "description": "Google Service Management allows service producers to publish their services on Google Cloud Platform so that they can be discovered and used by service consumers.", + "discoveryRestUrl": "https://servicemanagement.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/service-management/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "serviceusage:v1beta1", + "name": "serviceusage", + "version": "v1beta1", + "title": "Service Usage API", + "description": "Enables services that service consumers want to use on Google Cloud Platform, lists the available or enabled services, or disables services that service consumers no longer use.", + "discoveryRestUrl": "https://serviceusage.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/service-usage/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "serviceuser:v1", + "name": "serviceuser", + "version": "v1", + "title": "Google Service User API", + "description": "Enables services that service consumers want to use on Google Cloud Platform, lists the available or enabled services, or disables services that service consumers no longer use.", + "discoveryRestUrl": "https://serviceuser.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/service-management/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "sheets:v4", + "name": "sheets", + "version": "v4", + "title": "Google Sheets API", + "description": "Reads and writes Google Sheets.", + "discoveryRestUrl": "https://sheets.googleapis.com/$discovery/rest?version=v4", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/sheets/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "siteVerification:v1", + "name": "siteVerification", + "version": "v1", + "title": "Google Site Verification API", + "description": "Verifies ownership of websites or domains with Google.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/siteVerification/v1/rest", + "discoveryLink": "./apis/siteVerification/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/site-verification/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "slides:v1", + "name": "slides", + "version": "v1", + "title": "Google Slides API", + "description": "An API for creating and editing Google Slides presentations.", + "discoveryRestUrl": "https://slides.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/slides/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "sourcerepo:v1", + "name": "sourcerepo", + "version": "v1", + "title": "Cloud Source Repositories API", + "description": "Access source code repositories hosted by Google.", + "discoveryRestUrl": "https://sourcerepo.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/source-repositories/docs/apis", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "spanner:v1", + "name": "spanner", + "version": "v1", + "title": "Cloud Spanner API", + "description": "Cloud Spanner is a managed, mission-critical, globally consistent and scalable relational database service.", + "discoveryRestUrl": "https://spanner.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/spanner/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "spectrum:v1explorer", + "name": "spectrum", + "version": "v1explorer", + "title": "Google Spectrum Database API", + "description": "API for spectrum-management functions.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/spectrum/v1explorer/rest", + "discoveryLink": "./apis/spectrum/v1explorer/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "http://developers.google.com/spectrum", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "speech:v1", + "name": "speech", + "version": "v1", + "title": "Cloud Speech API", + "description": "Converts audio to text by applying powerful neural network models.", + "discoveryRestUrl": "https://speech.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/speech/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "speech:v1beta1", + "name": "speech", + "version": "v1beta1", + "title": "Cloud Speech API", + "description": "Converts audio to text by applying powerful neural network models.", + "discoveryRestUrl": "https://speech.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/speech/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "sqladmin:v1beta3", + "name": "sqladmin", + "version": "v1beta3", + "title": "Cloud SQL Administration API", + "description": "Creates and configures Cloud SQL instances, which provide fully-managed MySQL databases.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/sqladmin/v1beta3/rest", + "discoveryLink": "./apis/sqladmin/v1beta3/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/sql/docs/reference/latest", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "sqladmin:v1beta4", + "name": "sqladmin", + "version": "v1beta4", + "title": "Cloud SQL Administration API", + "description": "Creates and configures Cloud SQL instances, which provide fully-managed MySQL databases.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/sqladmin/v1beta4/rest", + "discoveryLink": "./apis/sqladmin/v1beta4/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/sql/docs/reference/latest", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "storage:v1", + "name": "storage", + "version": "v1", + "title": "Cloud Storage JSON API", + "description": "Stores and retrieves potentially large, immutable data objects.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1/rest", + "discoveryLink": "./apis/storage/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", + "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" + }, + "documentationLink": "https://developers.google.com/storage/docs/json_api/", + "labels": [ + "labs" + ], + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "storage:v1beta1", + "name": "storage", + "version": "v1beta1", + "title": "Cloud Storage JSON API", + "description": "Lets you store and retrieve potentially-large, immutable data objects.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1beta1/rest", + "discoveryLink": "./apis/storage/v1beta1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", + "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" + }, + "documentationLink": "https://developers.google.com/storage/docs/json_api/", + "labels": [ + "labs" + ], + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "storage:v1beta2", + "name": "storage", + "version": "v1beta2", + "title": "Cloud Storage JSON API", + "description": "Lets you store and retrieve potentially-large, immutable data objects.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/storage/v1beta2/rest", + "discoveryLink": "./apis/storage/v1beta2/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", + "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" + }, + "documentationLink": "https://developers.google.com/storage/docs/json_api/", + "labels": [ + "labs" + ], + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "storagetransfer:v1", + "name": "storagetransfer", + "version": "v1", + "title": "Google Storage Transfer API", + "description": "Transfers data from external data sources to a Google Cloud Storage bucket or between Google Cloud Storage buckets.", + "discoveryRestUrl": "https://storagetransfer.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/storage/transfer", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "streetviewpublish:v1", + "name": "streetviewpublish", + "version": "v1", + "title": "Street View Publish API", + "description": "Publishes 360 photos to Google Maps, along with position, orientation, and connectivity metadata. Apps can offer an interface for positioning, connecting, and uploading user-generated Street View images.", + "discoveryRestUrl": "https://streetviewpublish.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/streetview/publish/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "surveys:v2", + "name": "surveys", + "version": "v2", + "title": "Surveys API", + "description": "Creates and conducts surveys, lists the surveys that an authenticated user owns, and retrieves survey results and information about specified surveys.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/surveys/v2/rest", + "discoveryLink": "./apis/surveys/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "tagmanager:v1", + "name": "tagmanager", + "version": "v1", + "title": "Tag Manager API", + "description": "Accesses Tag Manager accounts and containers.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tagmanager/v1/rest", + "discoveryLink": "./apis/tagmanager/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/tag-manager/api/v1/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "tagmanager:v2", + "name": "tagmanager", + "version": "v2", + "title": "Tag Manager API", + "description": "Accesses Tag Manager accounts and containers.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tagmanager/v2/rest", + "discoveryLink": "./apis/tagmanager/v2/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/tag-manager/api/v2/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "tasks:v1", + "name": "tasks", + "version": "v1", + "title": "Tasks API", + "description": "Lets you manage your tasks and task lists.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest", + "discoveryLink": "./apis/tasks/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/tasks-16.png", + "x32": "https://www.google.com/images/icons/product/tasks-32.png" + }, + "documentationLink": "https://developers.google.com/google-apps/tasks/firstapp", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "testing:v1", + "name": "testing", + "version": "v1", + "title": "Cloud Testing API", + "description": "Allows developers to run automated tests for their mobile applications on Google infrastructure.", + "discoveryRestUrl": "https://testing.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/cloud-test-lab/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "texttospeech:v1beta1", + "name": "texttospeech", + "version": "v1beta1", + "title": "Cloud Text-to-Speech API", + "description": "Synthesizes natural-sounding speech by applying powerful neural network models.", + "discoveryRestUrl": "https://texttospeech.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/text-to-speech/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "toolresults:v1beta3", + "name": "toolresults", + "version": "v1beta3", + "title": "Cloud Tool Results API", + "description": "Reads and publishes results from Firebase Test Lab.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/toolresults/v1beta3/rest", + "discoveryLink": "./apis/toolresults/v1beta3/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://firebase.google.com/docs/test-lab/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "tpu:v1alpha1", + "name": "tpu", + "version": "v1alpha1", + "title": "Cloud TPU API", + "description": "TPU API provides customers with access to Google TPU technology.", + "discoveryRestUrl": "https://tpu.googleapis.com/$discovery/rest?version=v1alpha1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/tpu/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "translate:v2", + "name": "translate", + "version": "v2", + "title": "Cloud Translation API", + "description": "The Google Cloud Translation API lets websites and programs integrate with Google Translate programmatically.", + "discoveryRestUrl": "https://translation.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://code.google.com/apis/language/translate/v2/getting_started.html", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "urlshortener:v1", + "name": "urlshortener", + "version": "v1", + "title": "URL Shortener API", + "description": "Lets you create, inspect, and manage goo.gl short URLs", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/urlshortener/v1/rest", + "discoveryLink": "./apis/urlshortener/v1/rest", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/url-shortener/v1/getting_started", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "vault:v1", + "name": "vault", + "version": "v1", + "title": "G Suite Vault API", + "description": "Archiving and eDiscovery for G Suite.", + "discoveryRestUrl": "https://vault.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/vault", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "videointelligence:v1", + "name": "videointelligence", + "version": "v1", + "title": "Cloud Video Intelligence API", + "description": "Cloud Video Intelligence API.", + "discoveryRestUrl": "https://videointelligence.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/video-intelligence/docs/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "videointelligence:v1beta1", + "name": "videointelligence", + "version": "v1beta1", + "title": "Cloud Video Intelligence API", + "description": "Cloud Video Intelligence API.", + "discoveryRestUrl": "https://videointelligence.googleapis.com/$discovery/rest?version=v1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/video-intelligence/docs/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "videointelligence:v1beta2", + "name": "videointelligence", + "version": "v1beta2", + "title": "Cloud Video Intelligence API", + "description": "Cloud Video Intelligence API.", + "discoveryRestUrl": "https://videointelligence.googleapis.com/$discovery/rest?version=v1beta2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/video-intelligence/docs/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "vision:v1p1beta1", + "name": "vision", + "version": "v1p1beta1", + "title": "Cloud Vision API", + "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", + "discoveryRestUrl": "https://vision.googleapis.com/$discovery/rest?version=v1p1beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/vision/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "vision:v1p2beta1", + "name": "vision", + "version": "v1p2beta1", + "title": "Cloud Vision API", + "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", + "discoveryRestUrl": "https://vision.googleapis.com/$discovery/rest?version=v1p2beta1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/vision/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "vision:v1", + "name": "vision", + "version": "v1", + "title": "Cloud Vision API", + "description": "Integrates Google Vision features, including image labeling, face, logo, and landmark detection, optical character recognition (OCR), and detection of explicit content, into applications.", + "discoveryRestUrl": "https://vision.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/vision/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "webfonts:v1", + "name": "webfonts", + "version": "v1", + "title": "Google Fonts Developer API", + "description": "Accesses the metadata for all families served by Google Fonts, providing a list of families currently available (including available styles and a list of supported script subsets).", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/webfonts/v1/rest", + "discoveryLink": "./apis/webfonts/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/feature/font_api-16.png", + "x32": "https://www.google.com/images/icons/feature/font_api-32.gif" + }, + "documentationLink": "https://developers.google.com/fonts/docs/developer_api", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "webmasters:v3", + "name": "webmasters", + "version": "v3", + "title": "Search Console API", + "description": "View Google Search Console data for your verified sites.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/webmasters/v3/rest", + "discoveryLink": "./apis/webmasters/v3/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/webmaster_tools-16.png", + "x32": "https://www.google.com/images/icons/product/webmaster_tools-32.png" + }, + "documentationLink": "https://developers.google.com/webmaster-tools/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "websecurityscanner:v1alpha", + "name": "websecurityscanner", + "version": "v1alpha", + "title": "Web Security Scanner API", + "description": "Web Security Scanner API (under development).", + "discoveryRestUrl": "https://websecurityscanner.googleapis.com/$discovery/rest?version=v1alpha", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://cloud.google.com/security-scanner/", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "youtube:v3", + "name": "youtube", + "version": "v3", + "title": "YouTube Data API", + "description": "Supports core YouTube features, such as uploading videos, creating and managing playlists, searching for content, and much more.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest", + "discoveryLink": "./apis/youtube/v3/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/youtube-16.png", + "x32": "https://www.google.com/images/icons/product/youtube-32.png" + }, + "documentationLink": "https://developers.google.com/youtube/v3", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "youtubeAnalytics:v1", + "name": "youtubeAnalytics", + "version": "v1", + "title": "YouTube Analytics API", + "description": "Retrieves your YouTube Analytics data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtubeAnalytics/v1/rest", + "discoveryLink": "./apis/youtubeAnalytics/v1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/youtube-16.png", + "x32": "https://www.google.com/images/icons/product/youtube-32.png" + }, + "documentationLink": "http://developers.google.com/youtube/analytics/", + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "youtubeAnalytics:v1beta1", + "name": "youtubeAnalytics", + "version": "v1beta1", + "title": "YouTube Analytics API", + "description": "Retrieves your YouTube Analytics data.", + "discoveryRestUrl": "https://www.googleapis.com/discovery/v1/apis/youtubeAnalytics/v1beta1/rest", + "discoveryLink": "./apis/youtubeAnalytics/v1beta1/rest", + "icons": { + "x16": "https://www.google.com/images/icons/product/youtube-16.png", + "x32": "https://www.google.com/images/icons/product/youtube-32.png" + }, + "documentationLink": "http://developers.google.com/youtube/analytics/", + "labels": [ + "deprecated" + ], + "preferred": false + }, + { + "kind": "discovery#directoryItem", + "id": "youtubeAnalytics:v2", + "name": "youtubeAnalytics", + "version": "v2", + "title": "YouTube Analytics API", + "description": "Retrieves your YouTube Analytics data.", + "discoveryRestUrl": "https://youtubeanalytics.googleapis.com/$discovery/rest?version=v2", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/youtube/analytics", + "preferred": true + }, + { + "kind": "discovery#directoryItem", + "id": "youtubereporting:v1", + "name": "youtubereporting", + "version": "v1", + "title": "YouTube Reporting API", + "description": "Schedules reporting jobs containing your YouTube Analytics data and downloads the resulting bulk data reports in the form of CSV files.", + "discoveryRestUrl": "https://youtubereporting.googleapis.com/$discovery/rest?version=v1", + "icons": { + "x16": "https://www.gstatic.com/images/branding/product/1x/googleg_16dp.png", + "x32": "https://www.gstatic.com/images/branding/product/1x/googleg_32dp.png" + }, + "documentationLink": "https://developers.google.com/youtube/reporting/v1/reports/", + "preferred": true + } + ] +} diff --git a/vendor/google.golang.org/api/compute/v1/compute-api.json b/vendor/google.golang.org/api/compute/v1/compute-api.json new file mode 100644 index 000000000..d9adab6ca --- /dev/null +++ b/vendor/google.golang.org/api/compute/v1/compute-api.json @@ -0,0 +1,31438 @@ +{ + "auth": { + "oauth2": { + "scopes": { + "https://www.googleapis.com/auth/cloud-platform": { + "description": "View and manage your data across Google Cloud Platform services" + }, + "https://www.googleapis.com/auth/compute": { + "description": "View and manage your Google Compute Engine resources" + }, + "https://www.googleapis.com/auth/compute.readonly": { + "description": "View your Google Compute Engine resources" + }, + "https://www.googleapis.com/auth/devstorage.full_control": { + "description": "Manage your data and permissions in Google Cloud Storage" + }, + "https://www.googleapis.com/auth/devstorage.read_only": { + "description": "View your data in Google Cloud Storage" + }, + "https://www.googleapis.com/auth/devstorage.read_write": { + "description": "Manage your data in Google Cloud Storage" + } + } + } + }, + "basePath": "/compute/v1/projects/", + "baseUrl": "https://www.googleapis.com/compute/v1/projects/", + "batchPath": "batch/compute/v1", + "description": "Creates and runs virtual machines on Google Cloud Platform.", + "discoveryVersion": "v1", + "documentationLink": "https://developers.google.com/compute/docs/reference/latest/", + "etag": "\"Zkyw9ACJZUvcYmlFaKGChzhmtnE/2Sihb9fRr0FXDJb4Sf8e4q9OvYg\"", + "icons": { + "x16": "https://www.google.com/images/icons/product/compute_engine-16.png", + "x32": "https://www.google.com/images/icons/product/compute_engine-32.png" + }, + "id": "compute:v1", + "kind": "discovery#restDescription", + "name": "compute", + "ownerDomain": "google.com", + "ownerName": "Google", + "parameters": { + "alt": { + "default": "json", + "description": "Data format for the response.", + "enum": [ + "json" + ], + "enumDescriptions": [ + "Responses with Content-Type of application/json" + ], + "location": "query", + "type": "string" + }, + "fields": { + "description": "Selector specifying which fields to include in a partial response.", + "location": "query", + "type": "string" + }, + "key": { + "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.", + "location": "query", + "type": "string" + }, + "oauth_token": { + "description": "OAuth 2.0 token for the current user.", + "location": "query", + "type": "string" + }, + "prettyPrint": { + "default": "true", + "description": "Returns response with indentations and line breaks.", + "location": "query", + "type": "boolean" + }, + "quotaUser": { + "description": "An opaque string that represents a user for quota purposes. Must not exceed 40 characters.", + "location": "query", + "type": "string" + }, + "userIp": { + "description": "Deprecated. Please use quotaUser instead.", + "location": "query", + "type": "string" + } + }, + "protocol": "rest", + "resources": { + "acceleratorTypes": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of accelerator types.", + "httpMethod": "GET", + "id": "compute.acceleratorTypes.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/acceleratorTypes", + "response": { + "$ref": "AcceleratorTypeAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "get": { + "description": "Returns the specified accelerator type.", + "httpMethod": "GET", + "id": "compute.acceleratorTypes.get", + "parameterOrder": [ + "project", + "zone", + "acceleratorType" + ], + "parameters": { + "acceleratorType": { + "description": "Name of the accelerator type to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/acceleratorTypes/{acceleratorType}", + "response": { + "$ref": "AcceleratorType" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of accelerator types available to the specified project.", + "httpMethod": "GET", + "id": "compute.acceleratorTypes.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/acceleratorTypes", + "response": { + "$ref": "AcceleratorTypeList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "addresses": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of addresses.", + "httpMethod": "GET", + "id": "compute.addresses.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/addresses", + "response": { + "$ref": "AddressAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified address resource.", + "httpMethod": "DELETE", + "id": "compute.addresses.delete", + "parameterOrder": [ + "project", + "region", + "address" + ], + "parameters": { + "address": { + "description": "Name of the address resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/addresses/{address}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified address resource.", + "httpMethod": "GET", + "id": "compute.addresses.get", + "parameterOrder": [ + "project", + "region", + "address" + ], + "parameters": { + "address": { + "description": "Name of the address resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/addresses/{address}", + "response": { + "$ref": "Address" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an address resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.addresses.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/addresses", + "request": { + "$ref": "Address" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of addresses contained within the specified region.", + "httpMethod": "GET", + "id": "compute.addresses.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/addresses", + "response": { + "$ref": "AddressList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "autoscalers": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of autoscalers.", + "httpMethod": "GET", + "id": "compute.autoscalers.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/autoscalers", + "response": { + "$ref": "AutoscalerAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified autoscaler.", + "httpMethod": "DELETE", + "id": "compute.autoscalers.delete", + "parameterOrder": [ + "project", + "zone", + "autoscaler" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/autoscalers/{autoscaler}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified autoscaler resource. Gets a list of available autoscalers by making a list() request.", + "httpMethod": "GET", + "id": "compute.autoscalers.get", + "parameterOrder": [ + "project", + "zone", + "autoscaler" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/autoscalers/{autoscaler}", + "response": { + "$ref": "Autoscaler" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an autoscaler in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.autoscalers.insert", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/autoscalers", + "request": { + "$ref": "Autoscaler" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of autoscalers contained within the specified zone.", + "httpMethod": "GET", + "id": "compute.autoscalers.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/autoscalers", + "response": { + "$ref": "AutoscalerList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates an autoscaler in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.autoscalers.patch", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to patch.", + "location": "query", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/autoscalers", + "request": { + "$ref": "Autoscaler" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates an autoscaler in the specified project using the data included in the request.", + "httpMethod": "PUT", + "id": "compute.autoscalers.update", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to update.", + "location": "query", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/autoscalers", + "request": { + "$ref": "Autoscaler" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "backendBuckets": { + "methods": { + "delete": { + "description": "Deletes the specified BackendBucket resource.", + "httpMethod": "DELETE", + "id": "compute.backendBuckets.delete", + "parameterOrder": [ + "project", + "backendBucket" + ], + "parameters": { + "backendBucket": { + "description": "Name of the BackendBucket resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendBuckets/{backendBucket}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified BackendBucket resource. Gets a list of available backend buckets by making a list() request.", + "httpMethod": "GET", + "id": "compute.backendBuckets.get", + "parameterOrder": [ + "project", + "backendBucket" + ], + "parameters": { + "backendBucket": { + "description": "Name of the BackendBucket resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/backendBuckets/{backendBucket}", + "response": { + "$ref": "BackendBucket" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a BackendBucket resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.backendBuckets.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendBuckets", + "request": { + "$ref": "BackendBucket" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of BackendBucket resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.backendBuckets.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/backendBuckets", + "response": { + "$ref": "BackendBucketList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates the specified BackendBucket resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.backendBuckets.patch", + "parameterOrder": [ + "project", + "backendBucket" + ], + "parameters": { + "backendBucket": { + "description": "Name of the BackendBucket resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendBuckets/{backendBucket}", + "request": { + "$ref": "BackendBucket" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates the specified BackendBucket resource with the data included in the request.", + "httpMethod": "PUT", + "id": "compute.backendBuckets.update", + "parameterOrder": [ + "project", + "backendBucket" + ], + "parameters": { + "backendBucket": { + "description": "Name of the BackendBucket resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendBuckets/{backendBucket}", + "request": { + "$ref": "BackendBucket" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "backendServices": { + "methods": { + "aggregatedList": { + "description": "Retrieves the list of all BackendService resources, regional and global, available to the specified project.", + "httpMethod": "GET", + "id": "compute.backendServices.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Name of the project scoping this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/backendServices", + "response": { + "$ref": "BackendServiceAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified BackendService resource.", + "httpMethod": "DELETE", + "id": "compute.backendServices.delete", + "parameterOrder": [ + "project", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendServices/{backendService}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified BackendService resource. Gets a list of available backend services by making a list() request.", + "httpMethod": "GET", + "id": "compute.backendServices.get", + "parameterOrder": [ + "project", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/backendServices/{backendService}", + "response": { + "$ref": "BackendService" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getHealth": { + "description": "Gets the most recent health check results for this BackendService.", + "httpMethod": "POST", + "id": "compute.backendServices.getHealth", + "parameterOrder": [ + "project", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to which the queried instance belongs.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/backendServices/{backendService}/getHealth", + "request": { + "$ref": "ResourceGroupReference" + }, + "response": { + "$ref": "BackendServiceGroupHealth" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a BackendService resource in the specified project using the data included in the request. There are several restrictions and guidelines to keep in mind when creating a backend service. Read Restrictions and Guidelines for more information.", + "httpMethod": "POST", + "id": "compute.backendServices.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendServices", + "request": { + "$ref": "BackendService" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of BackendService resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.backendServices.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/backendServices", + "response": { + "$ref": "BackendServiceList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Patches the specified BackendService resource with the data included in the request. There are several restrictions and guidelines to keep in mind when updating a backend service. Read Restrictions and Guidelines for more information. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.backendServices.patch", + "parameterOrder": [ + "project", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendServices/{backendService}", + "request": { + "$ref": "BackendService" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates the specified BackendService resource with the data included in the request. There are several restrictions and guidelines to keep in mind when updating a backend service. Read Restrictions and Guidelines for more information.", + "httpMethod": "PUT", + "id": "compute.backendServices.update", + "parameterOrder": [ + "project", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/backendServices/{backendService}", + "request": { + "$ref": "BackendService" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "diskTypes": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of disk types.", + "httpMethod": "GET", + "id": "compute.diskTypes.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/diskTypes", + "response": { + "$ref": "DiskTypeAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "get": { + "description": "Returns the specified disk type. Gets a list of available disk types by making a list() request.", + "httpMethod": "GET", + "id": "compute.diskTypes.get", + "parameterOrder": [ + "project", + "zone", + "diskType" + ], + "parameters": { + "diskType": { + "description": "Name of the disk type to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/diskTypes/{diskType}", + "response": { + "$ref": "DiskType" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of disk types available to the specified project.", + "httpMethod": "GET", + "id": "compute.diskTypes.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/diskTypes", + "response": { + "$ref": "DiskTypeList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "disks": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of persistent disks.", + "httpMethod": "GET", + "id": "compute.disks.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/disks", + "response": { + "$ref": "DiskAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "createSnapshot": { + "description": "Creates a snapshot of a specified persistent disk.", + "httpMethod": "POST", + "id": "compute.disks.createSnapshot", + "parameterOrder": [ + "project", + "zone", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the persistent disk to snapshot.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "guestFlush": { + "location": "query", + "type": "boolean" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks/{disk}/createSnapshot", + "request": { + "$ref": "Snapshot" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "delete": { + "description": "Deletes the specified persistent disk. Deleting a disk removes its data permanently and is irreversible. However, deleting a disk does not delete any snapshots previously made from the disk. You must separately delete snapshots.", + "httpMethod": "DELETE", + "id": "compute.disks.delete", + "parameterOrder": [ + "project", + "zone", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the persistent disk to delete.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks/{disk}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns a specified persistent disk. Gets a list of available persistent disks by making a list() request.", + "httpMethod": "GET", + "id": "compute.disks.get", + "parameterOrder": [ + "project", + "zone", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the persistent disk to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks/{disk}", + "response": { + "$ref": "Disk" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a persistent disk in the specified project using the data in the request. You can create a disk with a sourceImage, a sourceSnapshot, or create an empty 500 GB data disk by omitting all properties. You can also create a disk that is larger than the default size by specifying the sizeGb property.", + "httpMethod": "POST", + "id": "compute.disks.insert", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "sourceImage": { + "description": "Optional. Source image to restore onto a disk.", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks", + "request": { + "$ref": "Disk" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of persistent disks contained within the specified zone.", + "httpMethod": "GET", + "id": "compute.disks.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks", + "response": { + "$ref": "DiskList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "resize": { + "description": "Resizes the specified persistent disk. You can only increase the size of the disk.", + "httpMethod": "POST", + "id": "compute.disks.resize", + "parameterOrder": [ + "project", + "zone", + "disk" + ], + "parameters": { + "disk": { + "description": "The name of the persistent disk.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks/{disk}/resize", + "request": { + "$ref": "DisksResizeRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setLabels": { + "description": "Sets the labels on a disk. To learn more about labels, read the Labeling Resources documentation.", + "httpMethod": "POST", + "id": "compute.disks.setLabels", + "parameterOrder": [ + "project", + "zone", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/disks/{resource}/setLabels", + "request": { + "$ref": "ZoneSetLabelsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "firewalls": { + "methods": { + "delete": { + "description": "Deletes the specified firewall.", + "httpMethod": "DELETE", + "id": "compute.firewalls.delete", + "parameterOrder": [ + "project", + "firewall" + ], + "parameters": { + "firewall": { + "description": "Name of the firewall rule to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/firewalls/{firewall}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified firewall.", + "httpMethod": "GET", + "id": "compute.firewalls.get", + "parameterOrder": [ + "project", + "firewall" + ], + "parameters": { + "firewall": { + "description": "Name of the firewall rule to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/firewalls/{firewall}", + "response": { + "$ref": "Firewall" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a firewall rule in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.firewalls.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/firewalls", + "request": { + "$ref": "Firewall" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of firewall rules available to the specified project.", + "httpMethod": "GET", + "id": "compute.firewalls.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/firewalls", + "response": { + "$ref": "FirewallList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates the specified firewall rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.firewalls.patch", + "parameterOrder": [ + "project", + "firewall" + ], + "parameters": { + "firewall": { + "description": "Name of the firewall rule to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/firewalls/{firewall}", + "request": { + "$ref": "Firewall" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates the specified firewall rule with the data included in the request. The PUT method can only update the following fields of firewall rule: allowed, description, sourceRanges, sourceTags, targetTags.", + "httpMethod": "PUT", + "id": "compute.firewalls.update", + "parameterOrder": [ + "project", + "firewall" + ], + "parameters": { + "firewall": { + "description": "Name of the firewall rule to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/firewalls/{firewall}", + "request": { + "$ref": "Firewall" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "forwardingRules": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of forwarding rules.", + "httpMethod": "GET", + "id": "compute.forwardingRules.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/forwardingRules", + "response": { + "$ref": "ForwardingRuleAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified ForwardingRule resource.", + "httpMethod": "DELETE", + "id": "compute.forwardingRules.delete", + "parameterOrder": [ + "project", + "region", + "forwardingRule" + ], + "parameters": { + "forwardingRule": { + "description": "Name of the ForwardingRule resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/forwardingRules/{forwardingRule}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified ForwardingRule resource.", + "httpMethod": "GET", + "id": "compute.forwardingRules.get", + "parameterOrder": [ + "project", + "region", + "forwardingRule" + ], + "parameters": { + "forwardingRule": { + "description": "Name of the ForwardingRule resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/forwardingRules/{forwardingRule}", + "response": { + "$ref": "ForwardingRule" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a ForwardingRule resource in the specified project and region using the data included in the request.", + "httpMethod": "POST", + "id": "compute.forwardingRules.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/forwardingRules", + "request": { + "$ref": "ForwardingRule" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of ForwardingRule resources available to the specified project and region.", + "httpMethod": "GET", + "id": "compute.forwardingRules.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/forwardingRules", + "response": { + "$ref": "ForwardingRuleList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setTarget": { + "description": "Changes target URL for forwarding rule. The new target should be of the same type as the old target.", + "httpMethod": "POST", + "id": "compute.forwardingRules.setTarget", + "parameterOrder": [ + "project", + "region", + "forwardingRule" + ], + "parameters": { + "forwardingRule": { + "description": "Name of the ForwardingRule resource in which target is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/forwardingRules/{forwardingRule}/setTarget", + "request": { + "$ref": "TargetReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "globalAddresses": { + "methods": { + "delete": { + "description": "Deletes the specified address resource.", + "httpMethod": "DELETE", + "id": "compute.globalAddresses.delete", + "parameterOrder": [ + "project", + "address" + ], + "parameters": { + "address": { + "description": "Name of the address resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/addresses/{address}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified address resource. Gets a list of available addresses by making a list() request.", + "httpMethod": "GET", + "id": "compute.globalAddresses.get", + "parameterOrder": [ + "project", + "address" + ], + "parameters": { + "address": { + "description": "Name of the address resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/addresses/{address}", + "response": { + "$ref": "Address" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an address resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.globalAddresses.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/addresses", + "request": { + "$ref": "Address" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of global addresses.", + "httpMethod": "GET", + "id": "compute.globalAddresses.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/addresses", + "response": { + "$ref": "AddressList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "globalForwardingRules": { + "methods": { + "delete": { + "description": "Deletes the specified GlobalForwardingRule resource.", + "httpMethod": "DELETE", + "id": "compute.globalForwardingRules.delete", + "parameterOrder": [ + "project", + "forwardingRule" + ], + "parameters": { + "forwardingRule": { + "description": "Name of the ForwardingRule resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/forwardingRules/{forwardingRule}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified GlobalForwardingRule resource. Gets a list of available forwarding rules by making a list() request.", + "httpMethod": "GET", + "id": "compute.globalForwardingRules.get", + "parameterOrder": [ + "project", + "forwardingRule" + ], + "parameters": { + "forwardingRule": { + "description": "Name of the ForwardingRule resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/forwardingRules/{forwardingRule}", + "response": { + "$ref": "ForwardingRule" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a GlobalForwardingRule resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.globalForwardingRules.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/forwardingRules", + "request": { + "$ref": "ForwardingRule" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of GlobalForwardingRule resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.globalForwardingRules.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/forwardingRules", + "response": { + "$ref": "ForwardingRuleList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setTarget": { + "description": "Changes target URL for the GlobalForwardingRule resource. The new target should be of the same type as the old target.", + "httpMethod": "POST", + "id": "compute.globalForwardingRules.setTarget", + "parameterOrder": [ + "project", + "forwardingRule" + ], + "parameters": { + "forwardingRule": { + "description": "Name of the ForwardingRule resource in which target is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/forwardingRules/{forwardingRule}/setTarget", + "request": { + "$ref": "TargetReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "globalOperations": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of all operations.", + "httpMethod": "GET", + "id": "compute.globalOperations.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/operations", + "response": { + "$ref": "OperationAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified Operations resource.", + "httpMethod": "DELETE", + "id": "compute.globalOperations.delete", + "parameterOrder": [ + "project", + "operation" + ], + "parameters": { + "operation": { + "description": "Name of the Operations resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/operations/{operation}", + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Retrieves the specified Operations resource. Gets a list of operations by making a list() request.", + "httpMethod": "GET", + "id": "compute.globalOperations.get", + "parameterOrder": [ + "project", + "operation" + ], + "parameters": { + "operation": { + "description": "Name of the Operations resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/operations/{operation}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of Operation resources contained within the specified project.", + "httpMethod": "GET", + "id": "compute.globalOperations.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/operations", + "response": { + "$ref": "OperationList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "healthChecks": { + "methods": { + "delete": { + "description": "Deletes the specified HealthCheck resource.", + "httpMethod": "DELETE", + "id": "compute.healthChecks.delete", + "parameterOrder": [ + "project", + "healthCheck" + ], + "parameters": { + "healthCheck": { + "description": "Name of the HealthCheck resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/healthChecks/{healthCheck}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified HealthCheck resource. Gets a list of available health checks by making a list() request.", + "httpMethod": "GET", + "id": "compute.healthChecks.get", + "parameterOrder": [ + "project", + "healthCheck" + ], + "parameters": { + "healthCheck": { + "description": "Name of the HealthCheck resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/healthChecks/{healthCheck}", + "response": { + "$ref": "HealthCheck" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a HealthCheck resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.healthChecks.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/healthChecks", + "request": { + "$ref": "HealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of HealthCheck resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.healthChecks.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/healthChecks", + "response": { + "$ref": "HealthCheckList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates a HealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.healthChecks.patch", + "parameterOrder": [ + "project", + "healthCheck" + ], + "parameters": { + "healthCheck": { + "description": "Name of the HealthCheck resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/healthChecks/{healthCheck}", + "request": { + "$ref": "HealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates a HealthCheck resource in the specified project using the data included in the request.", + "httpMethod": "PUT", + "id": "compute.healthChecks.update", + "parameterOrder": [ + "project", + "healthCheck" + ], + "parameters": { + "healthCheck": { + "description": "Name of the HealthCheck resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/healthChecks/{healthCheck}", + "request": { + "$ref": "HealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "httpHealthChecks": { + "methods": { + "delete": { + "description": "Deletes the specified HttpHealthCheck resource.", + "httpMethod": "DELETE", + "id": "compute.httpHealthChecks.delete", + "parameterOrder": [ + "project", + "httpHealthCheck" + ], + "parameters": { + "httpHealthCheck": { + "description": "Name of the HttpHealthCheck resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpHealthChecks/{httpHealthCheck}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified HttpHealthCheck resource. Gets a list of available HTTP health checks by making a list() request.", + "httpMethod": "GET", + "id": "compute.httpHealthChecks.get", + "parameterOrder": [ + "project", + "httpHealthCheck" + ], + "parameters": { + "httpHealthCheck": { + "description": "Name of the HttpHealthCheck resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/httpHealthChecks/{httpHealthCheck}", + "response": { + "$ref": "HttpHealthCheck" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a HttpHealthCheck resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.httpHealthChecks.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpHealthChecks", + "request": { + "$ref": "HttpHealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of HttpHealthCheck resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.httpHealthChecks.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/httpHealthChecks", + "response": { + "$ref": "HttpHealthCheckList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates a HttpHealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.httpHealthChecks.patch", + "parameterOrder": [ + "project", + "httpHealthCheck" + ], + "parameters": { + "httpHealthCheck": { + "description": "Name of the HttpHealthCheck resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpHealthChecks/{httpHealthCheck}", + "request": { + "$ref": "HttpHealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates a HttpHealthCheck resource in the specified project using the data included in the request.", + "httpMethod": "PUT", + "id": "compute.httpHealthChecks.update", + "parameterOrder": [ + "project", + "httpHealthCheck" + ], + "parameters": { + "httpHealthCheck": { + "description": "Name of the HttpHealthCheck resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpHealthChecks/{httpHealthCheck}", + "request": { + "$ref": "HttpHealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "httpsHealthChecks": { + "methods": { + "delete": { + "description": "Deletes the specified HttpsHealthCheck resource.", + "httpMethod": "DELETE", + "id": "compute.httpsHealthChecks.delete", + "parameterOrder": [ + "project", + "httpsHealthCheck" + ], + "parameters": { + "httpsHealthCheck": { + "description": "Name of the HttpsHealthCheck resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpsHealthChecks/{httpsHealthCheck}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified HttpsHealthCheck resource. Gets a list of available HTTPS health checks by making a list() request.", + "httpMethod": "GET", + "id": "compute.httpsHealthChecks.get", + "parameterOrder": [ + "project", + "httpsHealthCheck" + ], + "parameters": { + "httpsHealthCheck": { + "description": "Name of the HttpsHealthCheck resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/httpsHealthChecks/{httpsHealthCheck}", + "response": { + "$ref": "HttpsHealthCheck" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a HttpsHealthCheck resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.httpsHealthChecks.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpsHealthChecks", + "request": { + "$ref": "HttpsHealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of HttpsHealthCheck resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.httpsHealthChecks.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/httpsHealthChecks", + "response": { + "$ref": "HttpsHealthCheckList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates a HttpsHealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.httpsHealthChecks.patch", + "parameterOrder": [ + "project", + "httpsHealthCheck" + ], + "parameters": { + "httpsHealthCheck": { + "description": "Name of the HttpsHealthCheck resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpsHealthChecks/{httpsHealthCheck}", + "request": { + "$ref": "HttpsHealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates a HttpsHealthCheck resource in the specified project using the data included in the request.", + "httpMethod": "PUT", + "id": "compute.httpsHealthChecks.update", + "parameterOrder": [ + "project", + "httpsHealthCheck" + ], + "parameters": { + "httpsHealthCheck": { + "description": "Name of the HttpsHealthCheck resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/httpsHealthChecks/{httpsHealthCheck}", + "request": { + "$ref": "HttpsHealthCheck" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "images": { + "methods": { + "delete": { + "description": "Deletes the specified image.", + "httpMethod": "DELETE", + "id": "compute.images.delete", + "parameterOrder": [ + "project", + "image" + ], + "parameters": { + "image": { + "description": "Name of the image resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/images/{image}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "deprecate": { + "description": "Sets the deprecation status of an image.\n\nIf an empty request body is given, clears the deprecation status instead.", + "httpMethod": "POST", + "id": "compute.images.deprecate", + "parameterOrder": [ + "project", + "image" + ], + "parameters": { + "image": { + "description": "Image name.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/images/{image}/deprecate", + "request": { + "$ref": "DeprecationStatus" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified image. Gets a list of available images by making a list() request.", + "httpMethod": "GET", + "id": "compute.images.get", + "parameterOrder": [ + "project", + "image" + ], + "parameters": { + "image": { + "description": "Name of the image resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/images/{image}", + "response": { + "$ref": "Image" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getFromFamily": { + "description": "Returns the latest image that is part of an image family and is not deprecated.", + "httpMethod": "GET", + "id": "compute.images.getFromFamily", + "parameterOrder": [ + "project", + "family" + ], + "parameters": { + "family": { + "description": "Name of the image family to search for.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/images/family/{family}", + "response": { + "$ref": "Image" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an image in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.images.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "forceCreate": { + "description": "Force image creation if true.", + "location": "query", + "type": "boolean" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/images", + "request": { + "$ref": "Image" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/devstorage.read_write" + ] + }, + "list": { + "description": "Retrieves the list of custom images available to the specified project. Custom images are images you create that belong to your project. This method does not get any images that belong to other projects, including publicly-available images, like Debian 8. If you want to get a list of publicly-available images, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud.", + "httpMethod": "GET", + "id": "compute.images.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/images", + "response": { + "$ref": "ImageList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setLabels": { + "description": "Sets the labels on an image. To learn more about labels, read the Labeling Resources documentation.", + "httpMethod": "POST", + "id": "compute.images.setLabels", + "parameterOrder": [ + "project", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9_]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/images/{resource}/setLabels", + "request": { + "$ref": "GlobalSetLabelsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "instanceGroupManagers": { + "methods": { + "abandonInstances": { + "description": "Schedules a group action to remove the specified instances from the managed instance group. Abandoning an instance does not delete the instance, but it does remove the instance from any target pools that are applied by the managed instance group. This method reduces the targetSize of the managed instance group by the number of instances that you abandon. This operation is marked as DONE when the action is scheduled even if the instances have not yet been removed from the group. You must separately verify the status of the abandoning action with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.\n\nYou can specify a maximum of 1000 instances with this method per request.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.abandonInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/abandonInstances", + "request": { + "$ref": "InstanceGroupManagersAbandonInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "aggregatedList": { + "description": "Retrieves the list of managed instance groups and groups them by zone.", + "httpMethod": "GET", + "id": "compute.instanceGroupManagers.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/instanceGroupManagers", + "response": { + "$ref": "InstanceGroupManagerAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified managed instance group and all of the instances in that group. Note that the instance group must not belong to a backend service. Read Deleting an instance group for more information.", + "httpMethod": "DELETE", + "id": "compute.instanceGroupManagers.delete", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group to delete.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "deleteInstances": { + "description": "Schedules a group action to delete the specified instances in the managed instance group. The instances are also removed from any target pools of which they were a member. This method reduces the targetSize of the managed instance group by the number of instances that you delete. This operation is marked as DONE when the action is scheduled even if the instances are still being deleted. You must separately verify the status of the deleting action with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.\n\nYou can specify a maximum of 1000 instances with this method per request.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.deleteInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/deleteInstances", + "request": { + "$ref": "InstanceGroupManagersDeleteInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns all of the details about the specified managed instance group. Gets a list of available managed instance groups by making a list() request.", + "httpMethod": "GET", + "id": "compute.instanceGroupManagers.get", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}", + "response": { + "$ref": "InstanceGroupManager" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a managed instance group using the information that you specify in the request. After the group is created, it schedules an action to create instances in the group using the specified instance template. This operation is marked as DONE when the group is created even if the instances in the group have not yet been created. You must separately verify the status of the individual instances with the listmanagedinstances method.\n\nA managed instance group can have up to 1000 VM instances per group. Please contact Cloud Support if you need an increase in this limit.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.insert", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where you want to create the managed instance group.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers", + "request": { + "$ref": "InstanceGroupManager" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of managed instance groups that are contained within the specified project and zone.", + "httpMethod": "GET", + "id": "compute.instanceGroupManagers.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers", + "response": { + "$ref": "InstanceGroupManagerList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "listManagedInstances": { + "description": "Lists all of the instances in the managed instance group. Each instance in the list has a currentAction, which indicates the action that the managed instance group is performing on the instance. For example, if the group is still creating an instance, the currentAction is CREATING. If a previous action failed, the list displays the errors for that failed action.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.listManagedInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "filter": { + "location": "query", + "type": "string" + }, + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "maxResults": { + "default": "500", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "order_by": { + "location": "query", + "type": "string" + }, + "pageToken": { + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/listManagedInstances", + "response": { + "$ref": "InstanceGroupManagersListManagedInstancesResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "recreateInstances": { + "description": "Schedules a group action to recreate the specified instances in the managed instance group. The instances are deleted and recreated using the current instance template for the managed instance group. This operation is marked as DONE when the action is scheduled even if the instances have not yet been recreated. You must separately verify the status of the recreating action with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.\n\nYou can specify a maximum of 1000 instances with this method per request.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.recreateInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/recreateInstances", + "request": { + "$ref": "InstanceGroupManagersRecreateInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "resize": { + "description": "Resizes the managed instance group. If you increase the size, the group creates new instances using the current instance template. If you decrease the size, the group deletes instances. The resize operation is marked DONE when the resize actions are scheduled even if the group has not yet added or deleted any instances. You must separately verify the status of the creating or deleting actions with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.resize", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager", + "size" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "size": { + "description": "The number of running instances that the managed instance group should maintain at any given time. The group automatically adds or removes instances to maintain the number of instances specified by this parameter.", + "format": "int32", + "location": "query", + "required": true, + "type": "integer" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/resize", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setInstanceTemplate": { + "description": "Specifies the instance template to use when creating new instances in this group. The templates for existing instances in the group do not change unless you recreate them.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.setInstanceTemplate", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/setInstanceTemplate", + "request": { + "$ref": "InstanceGroupManagersSetInstanceTemplateRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setTargetPools": { + "description": "Modifies the target pools to which all instances in this managed instance group are assigned. The target pools automatically apply to all of the instances in the managed instance group. This operation is marked DONE when you make the request even if the instances have not yet been added to their target pools. The change might take some time to apply to all of the instances in the group depending on the size of the group.", + "httpMethod": "POST", + "id": "compute.instanceGroupManagers.setTargetPools", + "parameterOrder": [ + "project", + "zone", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the managed instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroupManagers/{instanceGroupManager}/setTargetPools", + "request": { + "$ref": "InstanceGroupManagersSetTargetPoolsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "instanceGroups": { + "methods": { + "addInstances": { + "description": "Adds a list of instances to the specified instance group. All of the instances in the instance group must be in the same network/subnetwork. Read Adding instances for more information.", + "httpMethod": "POST", + "id": "compute.instanceGroups.addInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "The name of the instance group where you are adding instances.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups/{instanceGroup}/addInstances", + "request": { + "$ref": "InstanceGroupsAddInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "aggregatedList": { + "description": "Retrieves the list of instance groups and sorts them by zone.", + "httpMethod": "GET", + "id": "compute.instanceGroups.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/instanceGroups", + "response": { + "$ref": "InstanceGroupAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified instance group. The instances in the group are not deleted. Note that instance group must not belong to a backend service. Read Deleting an instance group for more information.", + "httpMethod": "DELETE", + "id": "compute.instanceGroups.delete", + "parameterOrder": [ + "project", + "zone", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "The name of the instance group to delete.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups/{instanceGroup}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified instance group. Gets a list of available instance groups by making a list() request.", + "httpMethod": "GET", + "id": "compute.instanceGroups.get", + "parameterOrder": [ + "project", + "zone", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "The name of the instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups/{instanceGroup}", + "response": { + "$ref": "InstanceGroup" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an instance group in the specified project using the parameters that are included in the request.", + "httpMethod": "POST", + "id": "compute.instanceGroups.insert", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where you want to create the instance group.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups", + "request": { + "$ref": "InstanceGroup" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of instance groups that are located in the specified project and zone.", + "httpMethod": "GET", + "id": "compute.instanceGroups.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups", + "response": { + "$ref": "InstanceGroupList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "listInstances": { + "description": "Lists the instances in the specified instance group.", + "httpMethod": "POST", + "id": "compute.instanceGroups.listInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroup" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "instanceGroup": { + "description": "The name of the instance group from which you want to generate a list of included instances.", + "location": "path", + "required": true, + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups/{instanceGroup}/listInstances", + "request": { + "$ref": "InstanceGroupsListInstancesRequest" + }, + "response": { + "$ref": "InstanceGroupsListInstances" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "removeInstances": { + "description": "Removes one or more instances from the specified instance group, but does not delete those instances.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration before the VM instance is removed or deleted.", + "httpMethod": "POST", + "id": "compute.instanceGroups.removeInstances", + "parameterOrder": [ + "project", + "zone", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "The name of the instance group where the specified instances will be removed.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups/{instanceGroup}/removeInstances", + "request": { + "$ref": "InstanceGroupsRemoveInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setNamedPorts": { + "description": "Sets the named ports for the specified instance group.", + "httpMethod": "POST", + "id": "compute.instanceGroups.setNamedPorts", + "parameterOrder": [ + "project", + "zone", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "The name of the instance group where the named ports are updated.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone where the instance group is located.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instanceGroups/{instanceGroup}/setNamedPorts", + "request": { + "$ref": "InstanceGroupsSetNamedPortsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "instanceTemplates": { + "methods": { + "delete": { + "description": "Deletes the specified instance template. Deleting an instance template is permanent and cannot be undone. It's not possible to delete templates which are in use by an instance group.", + "httpMethod": "DELETE", + "id": "compute.instanceTemplates.delete", + "parameterOrder": [ + "project", + "instanceTemplate" + ], + "parameters": { + "instanceTemplate": { + "description": "The name of the instance template to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/instanceTemplates/{instanceTemplate}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified instance template. Gets a list of available instance templates by making a list() request.", + "httpMethod": "GET", + "id": "compute.instanceTemplates.get", + "parameterOrder": [ + "project", + "instanceTemplate" + ], + "parameters": { + "instanceTemplate": { + "description": "The name of the instance template.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/instanceTemplates/{instanceTemplate}", + "response": { + "$ref": "InstanceTemplate" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an instance template in the specified project using the data that is included in the request. If you are creating a new template to update an existing instance group, your new instance template must use the same network or, if applicable, the same subnetwork as the original template.", + "httpMethod": "POST", + "id": "compute.instanceTemplates.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/instanceTemplates", + "request": { + "$ref": "InstanceTemplate" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of instance templates that are contained within the specified project and zone.", + "httpMethod": "GET", + "id": "compute.instanceTemplates.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/instanceTemplates", + "response": { + "$ref": "InstanceTemplateList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "instances": { + "methods": { + "addAccessConfig": { + "description": "Adds an access config to an instance's network interface.", + "httpMethod": "POST", + "id": "compute.instances.addAccessConfig", + "parameterOrder": [ + "project", + "zone", + "instance", + "networkInterface" + ], + "parameters": { + "instance": { + "description": "The instance name for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "networkInterface": { + "description": "The name of the network interface to add to this instance.", + "location": "query", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/addAccessConfig", + "request": { + "$ref": "AccessConfig" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "aggregatedList": { + "description": "Retrieves aggregated list of instances.", + "httpMethod": "GET", + "id": "compute.instances.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/instances", + "response": { + "$ref": "InstanceAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "attachDisk": { + "description": "Attaches an existing Disk resource to an instance. You must first create the disk before you can attach it. It is not possible to create and attach a disk at the same time. For more information, read Adding a persistent disk to your instance.", + "httpMethod": "POST", + "id": "compute.instances.attachDisk", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "forceAttach": { + "description": "Whether to force attach the disk even if it's currently attached to another instance. This is only available for regional disks.", + "location": "query", + "type": "boolean" + }, + "instance": { + "description": "The instance name for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/attachDisk", + "request": { + "$ref": "AttachedDisk" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "delete": { + "description": "Deletes the specified Instance resource. For more information, see Stopping or Deleting an Instance.", + "httpMethod": "DELETE", + "id": "compute.instances.delete", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "deleteAccessConfig": { + "description": "Deletes an access config from an instance's network interface.", + "httpMethod": "POST", + "id": "compute.instances.deleteAccessConfig", + "parameterOrder": [ + "project", + "zone", + "instance", + "accessConfig", + "networkInterface" + ], + "parameters": { + "accessConfig": { + "description": "The name of the access config to delete.", + "location": "query", + "required": true, + "type": "string" + }, + "instance": { + "description": "The instance name for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "networkInterface": { + "description": "The name of the network interface.", + "location": "query", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/deleteAccessConfig", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "detachDisk": { + "description": "Detaches a disk from an instance.", + "httpMethod": "POST", + "id": "compute.instances.detachDisk", + "parameterOrder": [ + "project", + "zone", + "instance", + "deviceName" + ], + "parameters": { + "deviceName": { + "description": "Disk device name to detach.", + "location": "query", + "required": true, + "type": "string" + }, + "instance": { + "description": "Instance name.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/detachDisk", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified Instance resource. Gets a list of available instances by making a list() request.", + "httpMethod": "GET", + "id": "compute.instances.get", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}", + "response": { + "$ref": "Instance" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getSerialPortOutput": { + "description": "Returns the specified instance's serial port output.", + "httpMethod": "GET", + "id": "compute.instances.getSerialPortOutput", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "port": { + "default": "1", + "description": "Specifies which COM or serial port to retrieve data from.", + "format": "int32", + "location": "query", + "maximum": "4", + "minimum": "1", + "type": "integer" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "start": { + "description": "Returns output starting from a specific byte position. Use this to page through output when the output is too large to return in a single request. For the initial request, leave this field unspecified. For subsequent calls, this field should be set to the next value returned in the previous call.", + "format": "int64", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/serialPort", + "response": { + "$ref": "SerialPortOutput" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an instance resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.instances.insert", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "sourceInstanceTemplate": { + "description": "Specifies instance template to create the instance.\n\nThis field is optional. It can be a full or partial URL. For example, the following are all valid URLs to an instance template: \n- https://www.googleapis.com/compute/v1/projects/project/global/global/instanceTemplates/instanceTemplate \n- projects/project/global/global/instanceTemplates/instanceTemplate \n- global/instancesTemplates/instanceTemplate", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances", + "request": { + "$ref": "Instance" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of instances contained within the specified zone.", + "httpMethod": "GET", + "id": "compute.instances.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances", + "response": { + "$ref": "InstanceList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "listReferrers": { + "description": "Retrieves the list of referrers to instances contained within the specified zone.", + "httpMethod": "GET", + "id": "compute.instances.listReferrers", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "instance": { + "description": "Name of the target instance scoping this request, or '-' if the request should span over all instances in the container.", + "location": "path", + "pattern": "-|[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/referrers", + "response": { + "$ref": "InstanceListReferrers" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "reset": { + "description": "Performs a reset on the instance. For more information, see Resetting an instance.", + "httpMethod": "POST", + "id": "compute.instances.reset", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/reset", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setDeletionProtection": { + "description": "Sets deletion protection on the instance.", + "httpMethod": "POST", + "id": "compute.instances.setDeletionProtection", + "parameterOrder": [ + "project", + "zone", + "resource" + ], + "parameters": { + "deletionProtection": { + "default": "true", + "description": "Whether the resource should be protected against deletion.", + "location": "query", + "type": "boolean" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{resource}/setDeletionProtection", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setDiskAutoDelete": { + "description": "Sets the auto-delete flag for a disk attached to an instance.", + "httpMethod": "POST", + "id": "compute.instances.setDiskAutoDelete", + "parameterOrder": [ + "project", + "zone", + "instance", + "autoDelete", + "deviceName" + ], + "parameters": { + "autoDelete": { + "description": "Whether to auto-delete the disk when the instance is deleted.", + "location": "query", + "required": true, + "type": "boolean" + }, + "deviceName": { + "description": "The device name of the disk to modify.", + "location": "query", + "pattern": "\\w[\\w.-]{0,254}", + "required": true, + "type": "string" + }, + "instance": { + "description": "The instance name.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setDiskAutoDelete", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setLabels": { + "description": "Sets labels on an instance. To learn more about labels, read the Labeling Resources documentation.", + "httpMethod": "POST", + "id": "compute.instances.setLabels", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setLabels", + "request": { + "$ref": "InstancesSetLabelsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setMachineResources": { + "description": "Changes the number and/or type of accelerator for a stopped instance to the values specified in the request.", + "httpMethod": "POST", + "id": "compute.instances.setMachineResources", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setMachineResources", + "request": { + "$ref": "InstancesSetMachineResourcesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setMachineType": { + "description": "Changes the machine type for a stopped instance to the machine type specified in the request.", + "httpMethod": "POST", + "id": "compute.instances.setMachineType", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setMachineType", + "request": { + "$ref": "InstancesSetMachineTypeRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setMetadata": { + "description": "Sets metadata for the specified instance to the data included in the request.", + "httpMethod": "POST", + "id": "compute.instances.setMetadata", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setMetadata", + "request": { + "$ref": "Metadata" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setMinCpuPlatform": { + "description": "Changes the minimum CPU platform that this instance should use. This method can only be called on a stopped instance. For more information, read Specifying a Minimum CPU Platform.", + "httpMethod": "POST", + "id": "compute.instances.setMinCpuPlatform", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setMinCpuPlatform", + "request": { + "$ref": "InstancesSetMinCpuPlatformRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setScheduling": { + "description": "Sets an instance's scheduling options.", + "httpMethod": "POST", + "id": "compute.instances.setScheduling", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Instance name.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setScheduling", + "request": { + "$ref": "Scheduling" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setServiceAccount": { + "description": "Sets the service account on the instance. For more information, read Changing the service account and access scopes for an instance.", + "httpMethod": "POST", + "id": "compute.instances.setServiceAccount", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance resource to start.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setServiceAccount", + "request": { + "$ref": "InstancesSetServiceAccountRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setTags": { + "description": "Sets tags for the specified instance to the data included in the request.", + "httpMethod": "POST", + "id": "compute.instances.setTags", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/setTags", + "request": { + "$ref": "Tags" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "start": { + "description": "Starts an instance that was stopped using the instances().stop method. For more information, see Restart an instance.", + "httpMethod": "POST", + "id": "compute.instances.start", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance resource to start.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/start", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "startWithEncryptionKey": { + "description": "Starts an instance that was stopped using the instances().stop method. For more information, see Restart an instance.", + "httpMethod": "POST", + "id": "compute.instances.startWithEncryptionKey", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance resource to start.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/startWithEncryptionKey", + "request": { + "$ref": "InstancesStartWithEncryptionKeyRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "stop": { + "description": "Stops a running instance, shutting it down cleanly, and allows you to restart the instance at a later time. Stopped instances do not incur VM usage charges while they are stopped. However, resources that the VM is using, such as persistent disks and static IP addresses, will continue to be charged until they are deleted. For more information, see Stopping an instance.", + "httpMethod": "POST", + "id": "compute.instances.stop", + "parameterOrder": [ + "project", + "zone", + "instance" + ], + "parameters": { + "instance": { + "description": "Name of the instance resource to stop.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/stop", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "updateAccessConfig": { + "description": "Updates the specified access config from an instance's network interface with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "POST", + "id": "compute.instances.updateAccessConfig", + "parameterOrder": [ + "project", + "zone", + "instance", + "networkInterface" + ], + "parameters": { + "instance": { + "description": "The instance name for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "networkInterface": { + "description": "The name of the network interface where the access config is attached.", + "location": "query", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/updateAccessConfig", + "request": { + "$ref": "AccessConfig" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "updateNetworkInterface": { + "description": "Updates an instance's network interface. This method follows PATCH semantics.", + "httpMethod": "PATCH", + "id": "compute.instances.updateNetworkInterface", + "parameterOrder": [ + "project", + "zone", + "instance", + "networkInterface" + ], + "parameters": { + "instance": { + "description": "The instance name for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "networkInterface": { + "description": "The name of the network interface to update.", + "location": "query", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/instances/{instance}/updateNetworkInterface", + "request": { + "$ref": "NetworkInterface" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "interconnectAttachments": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of interconnect attachments.", + "httpMethod": "GET", + "id": "compute.interconnectAttachments.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/interconnectAttachments", + "response": { + "$ref": "InterconnectAttachmentAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified interconnect attachment.", + "httpMethod": "DELETE", + "id": "compute.interconnectAttachments.delete", + "parameterOrder": [ + "project", + "region", + "interconnectAttachment" + ], + "parameters": { + "interconnectAttachment": { + "description": "Name of the interconnect attachment to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/interconnectAttachments/{interconnectAttachment}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified interconnect attachment.", + "httpMethod": "GET", + "id": "compute.interconnectAttachments.get", + "parameterOrder": [ + "project", + "region", + "interconnectAttachment" + ], + "parameters": { + "interconnectAttachment": { + "description": "Name of the interconnect attachment to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/interconnectAttachments/{interconnectAttachment}", + "response": { + "$ref": "InterconnectAttachment" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an InterconnectAttachment in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.interconnectAttachments.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/interconnectAttachments", + "request": { + "$ref": "InterconnectAttachment" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of interconnect attachments contained within the specified region.", + "httpMethod": "GET", + "id": "compute.interconnectAttachments.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/interconnectAttachments", + "response": { + "$ref": "InterconnectAttachmentList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "interconnectLocations": { + "methods": { + "get": { + "description": "Returns the details for the specified interconnect location. Gets a list of available interconnect locations by making a list() request.", + "httpMethod": "GET", + "id": "compute.interconnectLocations.get", + "parameterOrder": [ + "project", + "interconnectLocation" + ], + "parameters": { + "interconnectLocation": { + "description": "Name of the interconnect location to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/interconnectLocations/{interconnectLocation}", + "response": { + "$ref": "InterconnectLocation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves the list of interconnect locations available to the specified project.", + "httpMethod": "GET", + "id": "compute.interconnectLocations.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/interconnectLocations", + "response": { + "$ref": "InterconnectLocationList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "interconnects": { + "methods": { + "delete": { + "description": "Deletes the specified interconnect.", + "httpMethod": "DELETE", + "id": "compute.interconnects.delete", + "parameterOrder": [ + "project", + "interconnect" + ], + "parameters": { + "interconnect": { + "description": "Name of the interconnect to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/interconnects/{interconnect}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified interconnect. Get a list of available interconnects by making a list() request.", + "httpMethod": "GET", + "id": "compute.interconnects.get", + "parameterOrder": [ + "project", + "interconnect" + ], + "parameters": { + "interconnect": { + "description": "Name of the interconnect to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/interconnects/{interconnect}", + "response": { + "$ref": "Interconnect" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a Interconnect in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.interconnects.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/interconnects", + "request": { + "$ref": "Interconnect" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of interconnect available to the specified project.", + "httpMethod": "GET", + "id": "compute.interconnects.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/interconnects", + "response": { + "$ref": "InterconnectList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates the specified interconnect with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.interconnects.patch", + "parameterOrder": [ + "project", + "interconnect" + ], + "parameters": { + "interconnect": { + "description": "Name of the interconnect to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/interconnects/{interconnect}", + "request": { + "$ref": "Interconnect" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "licenseCodes": { + "methods": { + "get": { + "description": "Return a specified license code. License codes are mirrored across all projects that have permissions to read the License Code.", + "httpMethod": "GET", + "id": "compute.licenseCodes.get", + "parameterOrder": [ + "project", + "licenseCode" + ], + "parameters": { + "licenseCode": { + "description": "Number corresponding to the License code resource to return.", + "location": "path", + "pattern": "[0-9]{0,61}?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/licenseCodes/{licenseCode}", + "response": { + "$ref": "LicenseCode" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "testIamPermissions": { + "description": "Returns permissions that a caller has on the specified resource.", + "httpMethod": "POST", + "id": "compute.licenseCodes.testIamPermissions", + "parameterOrder": [ + "project", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "(?:[-a-z0-9_]{0,62}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/licenseCodes/{resource}/testIamPermissions", + "request": { + "$ref": "TestPermissionsRequest" + }, + "response": { + "$ref": "TestPermissionsResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "licenses": { + "methods": { + "delete": { + "description": "Deletes the specified license.", + "httpMethod": "DELETE", + "id": "compute.licenses.delete", + "parameterOrder": [ + "project", + "license" + ], + "parameters": { + "license": { + "description": "Name of the license resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/licenses/{license}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified License resource.", + "httpMethod": "GET", + "id": "compute.licenses.get", + "parameterOrder": [ + "project", + "license" + ], + "parameters": { + "license": { + "description": "Name of the License resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/licenses/{license}", + "response": { + "$ref": "License" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Create a License resource in the specified project.", + "httpMethod": "POST", + "id": "compute.licenses.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/licenses", + "request": { + "$ref": "License" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/devstorage.read_write" + ] + }, + "list": { + "description": "Retrieves the list of licenses available in the specified project. This method does not get any licenses that belong to other projects, including licenses attached to publicly-available images, like Debian 9. If you want to get a list of publicly-available licenses, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud.", + "httpMethod": "GET", + "id": "compute.licenses.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/licenses", + "response": { + "$ref": "LicensesListResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "testIamPermissions": { + "description": "Returns permissions that a caller has on the specified resource.", + "httpMethod": "POST", + "id": "compute.licenses.testIamPermissions", + "parameterOrder": [ + "project", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "(?:[-a-z0-9_]{0,62}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/licenses/{resource}/testIamPermissions", + "request": { + "$ref": "TestPermissionsRequest" + }, + "response": { + "$ref": "TestPermissionsResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "machineTypes": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of machine types.", + "httpMethod": "GET", + "id": "compute.machineTypes.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/machineTypes", + "response": { + "$ref": "MachineTypeAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "get": { + "description": "Returns the specified machine type. Gets a list of available machine types by making a list() request.", + "httpMethod": "GET", + "id": "compute.machineTypes.get", + "parameterOrder": [ + "project", + "zone", + "machineType" + ], + "parameters": { + "machineType": { + "description": "Name of the machine type to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/machineTypes/{machineType}", + "response": { + "$ref": "MachineType" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of machine types available to the specified project.", + "httpMethod": "GET", + "id": "compute.machineTypes.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "The name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/machineTypes", + "response": { + "$ref": "MachineTypeList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "networks": { + "methods": { + "addPeering": { + "description": "Adds a peering to the specified network.", + "httpMethod": "POST", + "id": "compute.networks.addPeering", + "parameterOrder": [ + "project", + "network" + ], + "parameters": { + "network": { + "description": "Name of the network resource to add peering to.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/networks/{network}/addPeering", + "request": { + "$ref": "NetworksAddPeeringRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "delete": { + "description": "Deletes the specified network.", + "httpMethod": "DELETE", + "id": "compute.networks.delete", + "parameterOrder": [ + "project", + "network" + ], + "parameters": { + "network": { + "description": "Name of the network to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/networks/{network}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified network. Gets a list of available networks by making a list() request.", + "httpMethod": "GET", + "id": "compute.networks.get", + "parameterOrder": [ + "project", + "network" + ], + "parameters": { + "network": { + "description": "Name of the network to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/networks/{network}", + "response": { + "$ref": "Network" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a network in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.networks.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/networks", + "request": { + "$ref": "Network" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of networks available to the specified project.", + "httpMethod": "GET", + "id": "compute.networks.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/networks", + "response": { + "$ref": "NetworkList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Patches the specified network with the data included in the request. Only the following fields can be modified: routingConfig.routingMode.", + "httpMethod": "PATCH", + "id": "compute.networks.patch", + "parameterOrder": [ + "project", + "network" + ], + "parameters": { + "network": { + "description": "Name of the network to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/networks/{network}", + "request": { + "$ref": "Network" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "removePeering": { + "description": "Removes a peering from the specified network.", + "httpMethod": "POST", + "id": "compute.networks.removePeering", + "parameterOrder": [ + "project", + "network" + ], + "parameters": { + "network": { + "description": "Name of the network resource to remove peering from.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/networks/{network}/removePeering", + "request": { + "$ref": "NetworksRemovePeeringRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "switchToCustomMode": { + "description": "Switches the network mode from auto subnet mode to custom subnet mode.", + "httpMethod": "POST", + "id": "compute.networks.switchToCustomMode", + "parameterOrder": [ + "project", + "network" + ], + "parameters": { + "network": { + "description": "Name of the network to be updated.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/networks/{network}/switchToCustomMode", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "projects": { + "methods": { + "disableXpnHost": { + "description": "Disable this project as a shared VPC host project.", + "httpMethod": "POST", + "id": "compute.projects.disableXpnHost", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/disableXpnHost", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "disableXpnResource": { + "description": "Disable a serivce resource (a.k.a service project) associated with this host project.", + "httpMethod": "POST", + "id": "compute.projects.disableXpnResource", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/disableXpnResource", + "request": { + "$ref": "ProjectsDisableXpnResourceRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "enableXpnHost": { + "description": "Enable this project as a shared VPC host project.", + "httpMethod": "POST", + "id": "compute.projects.enableXpnHost", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/enableXpnHost", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "enableXpnResource": { + "description": "Enable service resource (a.k.a service project) for a host project, so that subnets in the host project can be used by instances in the service project.", + "httpMethod": "POST", + "id": "compute.projects.enableXpnResource", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/enableXpnResource", + "request": { + "$ref": "ProjectsEnableXpnResourceRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified Project resource.", + "httpMethod": "GET", + "id": "compute.projects.get", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}", + "response": { + "$ref": "Project" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getXpnHost": { + "description": "Gets the shared VPC host project that this project links to. May be empty if no link exists.", + "httpMethod": "GET", + "id": "compute.projects.getXpnHost", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/getXpnHost", + "response": { + "$ref": "Project" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "getXpnResources": { + "description": "Gets service resources (a.k.a service project) associated with this host project.", + "httpMethod": "GET", + "id": "compute.projects.getXpnResources", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "order_by": { + "location": "query", + "type": "string" + }, + "pageToken": { + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/getXpnResources", + "response": { + "$ref": "ProjectsGetXpnResources" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "listXpnHosts": { + "description": "Lists all shared VPC host projects visible to the user in an organization.", + "httpMethod": "POST", + "id": "compute.projects.listXpnHosts", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "order_by": { + "location": "query", + "type": "string" + }, + "pageToken": { + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/listXpnHosts", + "request": { + "$ref": "ProjectsListXpnHostsRequest" + }, + "response": { + "$ref": "XpnHostList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "moveDisk": { + "description": "Moves a persistent disk from one zone to another.", + "httpMethod": "POST", + "id": "compute.projects.moveDisk", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/moveDisk", + "request": { + "$ref": "DiskMoveRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "moveInstance": { + "description": "Moves an instance and its attached persistent disks from one zone to another.", + "httpMethod": "POST", + "id": "compute.projects.moveInstance", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/moveInstance", + "request": { + "$ref": "InstanceMoveRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setCommonInstanceMetadata": { + "description": "Sets metadata common to all instances within the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.projects.setCommonInstanceMetadata", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/setCommonInstanceMetadata", + "request": { + "$ref": "Metadata" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setUsageExportBucket": { + "description": "Enables the usage export feature and sets the usage export bucket where reports are stored. If you provide an empty request body using this method, the usage export feature will be disabled.", + "httpMethod": "POST", + "id": "compute.projects.setUsageExportBucket", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/setUsageExportBucket", + "request": { + "$ref": "UsageExportLocation" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/devstorage.read_write" + ] + } + } + }, + "regionAutoscalers": { + "methods": { + "delete": { + "description": "Deletes the specified autoscaler.", + "httpMethod": "DELETE", + "id": "compute.regionAutoscalers.delete", + "parameterOrder": [ + "project", + "region", + "autoscaler" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/autoscalers/{autoscaler}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified autoscaler.", + "httpMethod": "GET", + "id": "compute.regionAutoscalers.get", + "parameterOrder": [ + "project", + "region", + "autoscaler" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/autoscalers/{autoscaler}", + "response": { + "$ref": "Autoscaler" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates an autoscaler in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.regionAutoscalers.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/autoscalers", + "request": { + "$ref": "Autoscaler" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of autoscalers contained within the specified region.", + "httpMethod": "GET", + "id": "compute.regionAutoscalers.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/autoscalers", + "response": { + "$ref": "RegionAutoscalerList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates an autoscaler in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.regionAutoscalers.patch", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to patch.", + "location": "query", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/autoscalers", + "request": { + "$ref": "Autoscaler" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates an autoscaler in the specified project using the data included in the request.", + "httpMethod": "PUT", + "id": "compute.regionAutoscalers.update", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "autoscaler": { + "description": "Name of the autoscaler to update.", + "location": "query", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/autoscalers", + "request": { + "$ref": "Autoscaler" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "regionBackendServices": { + "methods": { + "delete": { + "description": "Deletes the specified regional BackendService resource.", + "httpMethod": "DELETE", + "id": "compute.regionBackendServices.delete", + "parameterOrder": [ + "project", + "region", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices/{backendService}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified regional BackendService resource.", + "httpMethod": "GET", + "id": "compute.regionBackendServices.get", + "parameterOrder": [ + "project", + "region", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices/{backendService}", + "response": { + "$ref": "BackendService" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getHealth": { + "description": "Gets the most recent health check results for this regional BackendService.", + "httpMethod": "POST", + "id": "compute.regionBackendServices.getHealth", + "parameterOrder": [ + "project", + "region", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource for which to get health.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices/{backendService}/getHealth", + "request": { + "$ref": "ResourceGroupReference" + }, + "response": { + "$ref": "BackendServiceGroupHealth" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a regional BackendService resource in the specified project using the data included in the request. There are several restrictions and guidelines to keep in mind when creating a regional backend service. Read Restrictions and Guidelines for more information.", + "httpMethod": "POST", + "id": "compute.regionBackendServices.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices", + "request": { + "$ref": "BackendService" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of regional BackendService resources available to the specified project in the given region.", + "httpMethod": "GET", + "id": "compute.regionBackendServices.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices", + "response": { + "$ref": "BackendServiceList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Updates the specified regional BackendService resource with the data included in the request. There are several restrictions and guidelines to keep in mind when updating a backend service. Read Restrictions and Guidelines for more information. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.regionBackendServices.patch", + "parameterOrder": [ + "project", + "region", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices/{backendService}", + "request": { + "$ref": "BackendService" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates the specified regional BackendService resource with the data included in the request. There are several restrictions and guidelines to keep in mind when updating a backend service. Read Restrictions and Guidelines for more information.", + "httpMethod": "PUT", + "id": "compute.regionBackendServices.update", + "parameterOrder": [ + "project", + "region", + "backendService" + ], + "parameters": { + "backendService": { + "description": "Name of the BackendService resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/backendServices/{backendService}", + "request": { + "$ref": "BackendService" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "regionCommitments": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of commitments.", + "httpMethod": "GET", + "id": "compute.regionCommitments.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/commitments", + "response": { + "$ref": "CommitmentAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "get": { + "description": "Returns the specified commitment resource. Gets a list of available commitments by making a list() request.", + "httpMethod": "GET", + "id": "compute.regionCommitments.get", + "parameterOrder": [ + "project", + "region", + "commitment" + ], + "parameters": { + "commitment": { + "description": "Name of the commitment to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/commitments/{commitment}", + "response": { + "$ref": "Commitment" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a commitment in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.regionCommitments.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/commitments", + "request": { + "$ref": "Commitment" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of commitments contained within the specified region.", + "httpMethod": "GET", + "id": "compute.regionCommitments.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/commitments", + "response": { + "$ref": "CommitmentList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "regionDiskTypes": { + "methods": { + "get": { + "description": "Returns the specified regional disk type. Gets a list of available disk types by making a list() request.", + "httpMethod": "GET", + "id": "compute.regionDiskTypes.get", + "parameterOrder": [ + "project", + "region", + "diskType" + ], + "parameters": { + "diskType": { + "description": "Name of the disk type to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "The name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/diskTypes/{diskType}", + "response": { + "$ref": "DiskType" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of regional disk types available to the specified project.", + "httpMethod": "GET", + "id": "compute.regionDiskTypes.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "The name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/diskTypes", + "response": { + "$ref": "RegionDiskTypeList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "regionDisks": { + "methods": { + "createSnapshot": { + "description": "Creates a snapshot of this regional disk.", + "httpMethod": "POST", + "id": "compute.regionDisks.createSnapshot", + "parameterOrder": [ + "project", + "region", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the regional persistent disk to snapshot.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks/{disk}/createSnapshot", + "request": { + "$ref": "Snapshot" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "delete": { + "description": "Deletes the specified regional persistent disk. Deleting a regional disk removes all the replicas of its data permanently and is irreversible. However, deleting a disk does not delete any snapshots previously made from the disk. You must separately delete snapshots.", + "httpMethod": "DELETE", + "id": "compute.regionDisks.delete", + "parameterOrder": [ + "project", + "region", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the regional persistent disk to delete.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks/{disk}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns a specified regional persistent disk.", + "httpMethod": "GET", + "id": "compute.regionDisks.get", + "parameterOrder": [ + "project", + "region", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the regional persistent disk to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks/{disk}", + "response": { + "$ref": "Disk" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a persistent regional disk in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.regionDisks.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "sourceImage": { + "description": "Optional. Source image to restore onto a disk.", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks", + "request": { + "$ref": "Disk" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of persistent disks contained within the specified region.", + "httpMethod": "GET", + "id": "compute.regionDisks.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks", + "response": { + "$ref": "DiskList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "resize": { + "description": "Resizes the specified regional persistent disk.", + "httpMethod": "POST", + "id": "compute.regionDisks.resize", + "parameterOrder": [ + "project", + "region", + "disk" + ], + "parameters": { + "disk": { + "description": "Name of the regional persistent disk.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "The project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks/{disk}/resize", + "request": { + "$ref": "RegionDisksResizeRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setLabels": { + "description": "Sets the labels on the target regional disk.", + "httpMethod": "POST", + "id": "compute.regionDisks.setLabels", + "parameterOrder": [ + "project", + "region", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "The region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks/{resource}/setLabels", + "request": { + "$ref": "RegionSetLabelsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "testIamPermissions": { + "description": "Returns permissions that a caller has on the specified resource.", + "httpMethod": "POST", + "id": "compute.regionDisks.testIamPermissions", + "parameterOrder": [ + "project", + "region", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "The name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/disks/{resource}/testIamPermissions", + "request": { + "$ref": "TestPermissionsRequest" + }, + "response": { + "$ref": "TestPermissionsResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "regionInstanceGroupManagers": { + "methods": { + "abandonInstances": { + "description": "Schedules a group action to remove the specified instances from the managed instance group. Abandoning an instance does not delete the instance, but it does remove the instance from any target pools that are applied by the managed instance group. This method reduces the targetSize of the managed instance group by the number of instances that you abandon. This operation is marked as DONE when the action is scheduled even if the instances have not yet been removed from the group. You must separately verify the status of the abandoning action with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.\n\nYou can specify a maximum of 1000 instances with this method per request.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.abandonInstances", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/abandonInstances", + "request": { + "$ref": "RegionInstanceGroupManagersAbandonInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "delete": { + "description": "Deletes the specified managed instance group and all of the instances in that group.", + "httpMethod": "DELETE", + "id": "compute.regionInstanceGroupManagers.delete", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group to delete.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "deleteInstances": { + "description": "Schedules a group action to delete the specified instances in the managed instance group. The instances are also removed from any target pools of which they were a member. This method reduces the targetSize of the managed instance group by the number of instances that you delete. This operation is marked as DONE when the action is scheduled even if the instances are still being deleted. You must separately verify the status of the deleting action with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.\n\nYou can specify a maximum of 1000 instances with this method per request.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.deleteInstances", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/deleteInstances", + "request": { + "$ref": "RegionInstanceGroupManagersDeleteInstancesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns all of the details about the specified managed instance group.", + "httpMethod": "GET", + "id": "compute.regionInstanceGroupManagers.get", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group to return.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}", + "response": { + "$ref": "InstanceGroupManager" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a managed instance group using the information that you specify in the request. After the group is created, it schedules an action to create instances in the group using the specified instance template. This operation is marked as DONE when the group is created even if the instances in the group have not yet been created. You must separately verify the status of the individual instances with the listmanagedinstances method.\n\nA regional managed instance group can contain up to 2000 instances.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers", + "request": { + "$ref": "InstanceGroupManager" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of managed instance groups that are contained within the specified region.", + "httpMethod": "GET", + "id": "compute.regionInstanceGroupManagers.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers", + "response": { + "$ref": "RegionInstanceGroupManagerList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "listManagedInstances": { + "description": "Lists the instances in the managed instance group and instances that are scheduled to be created. The list includes any current actions that the group has scheduled for its instances.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.listManagedInstances", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "filter": { + "location": "query", + "type": "string" + }, + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "maxResults": { + "default": "500", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "order_by": { + "location": "query", + "type": "string" + }, + "pageToken": { + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/listManagedInstances", + "response": { + "$ref": "RegionInstanceGroupManagersListInstancesResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "recreateInstances": { + "description": "Schedules a group action to recreate the specified instances in the managed instance group. The instances are deleted and recreated using the current instance template for the managed instance group. This operation is marked as DONE when the action is scheduled even if the instances have not yet been recreated. You must separately verify the status of the recreating action with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.\n\nYou can specify a maximum of 1000 instances with this method per request.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.recreateInstances", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/recreateInstances", + "request": { + "$ref": "RegionInstanceGroupManagersRecreateRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "resize": { + "description": "Changes the intended size for the managed instance group. If you increase the size, the group schedules actions to create new instances using the current instance template. If you decrease the size, the group schedules delete actions on one or more instances. The resize operation is marked DONE when the resize actions are scheduled even if the group has not yet added or deleted any instances. You must separately verify the status of the creating or deleting actions with the listmanagedinstances method.\n\nIf the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.resize", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager", + "size" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "size": { + "description": "Number of instances that should exist in this instance group manager.", + "format": "int32", + "location": "query", + "minimum": "0", + "required": true, + "type": "integer" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/resize", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setInstanceTemplate": { + "description": "Sets the instance template to use when creating new instances or recreating instances in this group. Existing instances are not affected.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.setInstanceTemplate", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "The name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/setInstanceTemplate", + "request": { + "$ref": "RegionInstanceGroupManagersSetTemplateRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setTargetPools": { + "description": "Modifies the target pools to which all new instances in this group are assigned. Existing instances in the group are not affected.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroupManagers.setTargetPools", + "parameterOrder": [ + "project", + "region", + "instanceGroupManager" + ], + "parameters": { + "instanceGroupManager": { + "description": "Name of the managed instance group.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroupManagers/{instanceGroupManager}/setTargetPools", + "request": { + "$ref": "RegionInstanceGroupManagersSetTargetPoolsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "regionInstanceGroups": { + "methods": { + "get": { + "description": "Returns the specified instance group resource.", + "httpMethod": "GET", + "id": "compute.regionInstanceGroups.get", + "parameterOrder": [ + "project", + "region", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "Name of the instance group resource to return.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroups/{instanceGroup}", + "response": { + "$ref": "InstanceGroup" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves the list of instance group resources contained within the specified region.", + "httpMethod": "GET", + "id": "compute.regionInstanceGroups.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroups", + "response": { + "$ref": "RegionInstanceGroupList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "listInstances": { + "description": "Lists the instances in the specified instance group and displays information about the named ports. Depending on the specified options, this method can list all instances or only the instances that are running.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroups.listInstances", + "parameterOrder": [ + "project", + "region", + "instanceGroup" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "instanceGroup": { + "description": "Name of the regional instance group for which we want to list the instances.", + "location": "path", + "required": true, + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroups/{instanceGroup}/listInstances", + "request": { + "$ref": "RegionInstanceGroupsListInstancesRequest" + }, + "response": { + "$ref": "RegionInstanceGroupsListInstances" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setNamedPorts": { + "description": "Sets the named ports for the specified regional instance group.", + "httpMethod": "POST", + "id": "compute.regionInstanceGroups.setNamedPorts", + "parameterOrder": [ + "project", + "region", + "instanceGroup" + ], + "parameters": { + "instanceGroup": { + "description": "The name of the regional instance group where the named ports are updated.", + "location": "path", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/instanceGroups/{instanceGroup}/setNamedPorts", + "request": { + "$ref": "RegionInstanceGroupsSetNamedPortsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "regionOperations": { + "methods": { + "delete": { + "description": "Deletes the specified region-specific Operations resource.", + "httpMethod": "DELETE", + "id": "compute.regionOperations.delete", + "parameterOrder": [ + "project", + "region", + "operation" + ], + "parameters": { + "operation": { + "description": "Name of the Operations resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/operations/{operation}", + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Retrieves the specified region-specific Operations resource.", + "httpMethod": "GET", + "id": "compute.regionOperations.get", + "parameterOrder": [ + "project", + "region", + "operation" + ], + "parameters": { + "operation": { + "description": "Name of the Operations resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/operations/{operation}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of Operation resources contained within the specified region.", + "httpMethod": "GET", + "id": "compute.regionOperations.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/operations", + "response": { + "$ref": "OperationList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "regions": { + "methods": { + "get": { + "description": "Returns the specified Region resource. Gets a list of available regions by making a list() request.", + "httpMethod": "GET", + "id": "compute.regions.get", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}", + "response": { + "$ref": "Region" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves the list of region resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.regions.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions", + "response": { + "$ref": "RegionList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "routers": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of routers.", + "httpMethod": "GET", + "id": "compute.routers.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/routers", + "response": { + "$ref": "RouterAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified Router resource.", + "httpMethod": "DELETE", + "id": "compute.routers.delete", + "parameterOrder": [ + "project", + "region", + "router" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "router": { + "description": "Name of the Router resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers/{router}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified Router resource. Gets a list of available routers by making a list() request.", + "httpMethod": "GET", + "id": "compute.routers.get", + "parameterOrder": [ + "project", + "region", + "router" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "router": { + "description": "Name of the Router resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers/{router}", + "response": { + "$ref": "Router" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getRouterStatus": { + "description": "Retrieves runtime information of the specified router.", + "httpMethod": "GET", + "id": "compute.routers.getRouterStatus", + "parameterOrder": [ + "project", + "region", + "router" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "router": { + "description": "Name of the Router resource to query.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers/{router}/getRouterStatus", + "response": { + "$ref": "RouterStatusResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a Router resource in the specified project and region using the data included in the request.", + "httpMethod": "POST", + "id": "compute.routers.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers", + "request": { + "$ref": "Router" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of Router resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.routers.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers", + "response": { + "$ref": "RouterList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Patches the specified Router resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.routers.patch", + "parameterOrder": [ + "project", + "region", + "router" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "router": { + "description": "Name of the Router resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers/{router}", + "request": { + "$ref": "Router" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "preview": { + "description": "Preview fields auto-generated during router create and update operations. Calling this method does NOT create or update the router.", + "httpMethod": "POST", + "id": "compute.routers.preview", + "parameterOrder": [ + "project", + "region", + "router" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "router": { + "description": "Name of the Router resource to query.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers/{router}/preview", + "request": { + "$ref": "Router" + }, + "response": { + "$ref": "RoutersPreviewResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "update": { + "description": "Updates the specified Router resource with the data included in the request.", + "httpMethod": "PUT", + "id": "compute.routers.update", + "parameterOrder": [ + "project", + "region", + "router" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "router": { + "description": "Name of the Router resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/routers/{router}", + "request": { + "$ref": "Router" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "routes": { + "methods": { + "delete": { + "description": "Deletes the specified Route resource.", + "httpMethod": "DELETE", + "id": "compute.routes.delete", + "parameterOrder": [ + "project", + "route" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "route": { + "description": "Name of the Route resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/routes/{route}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified Route resource. Gets a list of available routes by making a list() request.", + "httpMethod": "GET", + "id": "compute.routes.get", + "parameterOrder": [ + "project", + "route" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "route": { + "description": "Name of the Route resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/routes/{route}", + "response": { + "$ref": "Route" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a Route resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.routes.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/routes", + "request": { + "$ref": "Route" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of Route resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.routes.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/routes", + "response": { + "$ref": "RouteList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "snapshots": { + "methods": { + "delete": { + "description": "Deletes the specified Snapshot resource. Keep in mind that deleting a single snapshot might not necessarily delete all the data on that snapshot. If any data on the snapshot that is marked for deletion is needed for subsequent snapshots, the data will be moved to the next corresponding snapshot.\n\nFor more information, see Deleting snaphots.", + "httpMethod": "DELETE", + "id": "compute.snapshots.delete", + "parameterOrder": [ + "project", + "snapshot" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "snapshot": { + "description": "Name of the Snapshot resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/snapshots/{snapshot}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified Snapshot resource. Gets a list of available snapshots by making a list() request.", + "httpMethod": "GET", + "id": "compute.snapshots.get", + "parameterOrder": [ + "project", + "snapshot" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "snapshot": { + "description": "Name of the Snapshot resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/snapshots/{snapshot}", + "response": { + "$ref": "Snapshot" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves the list of Snapshot resources contained within the specified project.", + "httpMethod": "GET", + "id": "compute.snapshots.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/snapshots", + "response": { + "$ref": "SnapshotList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setLabels": { + "description": "Sets the labels on a snapshot. To learn more about labels, read the Labeling Resources documentation.", + "httpMethod": "POST", + "id": "compute.snapshots.setLabels", + "parameterOrder": [ + "project", + "resource" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "resource": { + "description": "Name of the resource for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9_]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/snapshots/{resource}/setLabels", + "request": { + "$ref": "GlobalSetLabelsRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "sslCertificates": { + "methods": { + "delete": { + "description": "Deletes the specified SslCertificate resource.", + "httpMethod": "DELETE", + "id": "compute.sslCertificates.delete", + "parameterOrder": [ + "project", + "sslCertificate" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "sslCertificate": { + "description": "Name of the SslCertificate resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslCertificates/{sslCertificate}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified SslCertificate resource. Gets a list of available SSL certificates by making a list() request.", + "httpMethod": "GET", + "id": "compute.sslCertificates.get", + "parameterOrder": [ + "project", + "sslCertificate" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "sslCertificate": { + "description": "Name of the SslCertificate resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslCertificates/{sslCertificate}", + "response": { + "$ref": "SslCertificate" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a SslCertificate resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.sslCertificates.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/sslCertificates", + "request": { + "$ref": "SslCertificate" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of SslCertificate resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.sslCertificates.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslCertificates", + "response": { + "$ref": "SslCertificateList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "sslPolicies": { + "methods": { + "delete": { + "description": "Deletes the specified SSL policy. The SSL policy resource can be deleted only if it is not in use by any TargetHttpsProxy or TargetSslProxy resources.", + "httpMethod": "DELETE", + "id": "compute.sslPolicies.delete", + "parameterOrder": [ + "project", + "sslPolicy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "sslPolicy": { + "description": "Name of the SSL policy to delete. The name must be 1-63 characters long, and comply with RFC1035.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslPolicies/{sslPolicy}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Lists all of the ordered rules present in a single specified policy.", + "httpMethod": "GET", + "id": "compute.sslPolicies.get", + "parameterOrder": [ + "project", + "sslPolicy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "sslPolicy": { + "description": "Name of the SSL policy to update. The name must be 1-63 characters long, and comply with RFC1035.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslPolicies/{sslPolicy}", + "response": { + "$ref": "SslPolicy" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Returns the specified SSL policy resource. Gets a list of available SSL policies by making a list() request.", + "httpMethod": "POST", + "id": "compute.sslPolicies.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/sslPolicies", + "request": { + "$ref": "SslPolicy" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Lists all the SSL policies that have been configured for the specified project.", + "httpMethod": "GET", + "id": "compute.sslPolicies.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslPolicies", + "response": { + "$ref": "SslPoliciesList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "listAvailableFeatures": { + "description": "Lists all features that can be specified in the SSL policy when using custom profile.", + "httpMethod": "GET", + "id": "compute.sslPolicies.listAvailableFeatures", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslPolicies/listAvailableFeatures", + "response": { + "$ref": "SslPoliciesListAvailableFeaturesResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Patches the specified SSL policy with the data included in the request.", + "httpMethod": "PATCH", + "id": "compute.sslPolicies.patch", + "parameterOrder": [ + "project", + "sslPolicy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "sslPolicy": { + "description": "Name of the SSL policy to update. The name must be 1-63 characters long, and comply with RFC1035.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/sslPolicies/{sslPolicy}", + "request": { + "$ref": "SslPolicy" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "subnetworks": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of subnetworks.", + "httpMethod": "GET", + "id": "compute.subnetworks.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/subnetworks", + "response": { + "$ref": "SubnetworkAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified subnetwork.", + "httpMethod": "DELETE", + "id": "compute.subnetworks.delete", + "parameterOrder": [ + "project", + "region", + "subnetwork" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "subnetwork": { + "description": "Name of the Subnetwork resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks/{subnetwork}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "expandIpCidrRange": { + "description": "Expands the IP CIDR range of the subnetwork to a specified value.", + "httpMethod": "POST", + "id": "compute.subnetworks.expandIpCidrRange", + "parameterOrder": [ + "project", + "region", + "subnetwork" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "subnetwork": { + "description": "Name of the Subnetwork resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks/{subnetwork}/expandIpCidrRange", + "request": { + "$ref": "SubnetworksExpandIpCidrRangeRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified subnetwork. Gets a list of available subnetworks list() request.", + "httpMethod": "GET", + "id": "compute.subnetworks.get", + "parameterOrder": [ + "project", + "region", + "subnetwork" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "subnetwork": { + "description": "Name of the Subnetwork resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks/{subnetwork}", + "response": { + "$ref": "Subnetwork" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a subnetwork in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.subnetworks.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks", + "request": { + "$ref": "Subnetwork" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of subnetworks available to the specified project.", + "httpMethod": "GET", + "id": "compute.subnetworks.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks", + "response": { + "$ref": "SubnetworkList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Patches the specified subnetwork with the data included in the request. Only the following fields within the subnetwork resource can be specified in the request: secondary_ip_range, allow_subnet_cidr_routes_overlap and role. It is also mandatory to specify the current fingeprint of the subnetwork resource being patched.", + "httpMethod": "PATCH", + "id": "compute.subnetworks.patch", + "parameterOrder": [ + "project", + "region", + "subnetwork" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "subnetwork": { + "description": "Name of the Subnetwork resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks/{subnetwork}", + "request": { + "$ref": "Subnetwork" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setPrivateIpGoogleAccess": { + "description": "Set whether VMs in this subnet can access Google services without assigning external IP addresses through Private Google Access.", + "httpMethod": "POST", + "id": "compute.subnetworks.setPrivateIpGoogleAccess", + "parameterOrder": [ + "project", + "region", + "subnetwork" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "subnetwork": { + "description": "Name of the Subnetwork resource.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/subnetworks/{subnetwork}/setPrivateIpGoogleAccess", + "request": { + "$ref": "SubnetworksSetPrivateIpGoogleAccessRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "targetHttpProxies": { + "methods": { + "delete": { + "description": "Deletes the specified TargetHttpProxy resource.", + "httpMethod": "DELETE", + "id": "compute.targetHttpProxies.delete", + "parameterOrder": [ + "project", + "targetHttpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetHttpProxy": { + "description": "Name of the TargetHttpProxy resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpProxies/{targetHttpProxy}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified TargetHttpProxy resource. Gets a list of available target HTTP proxies by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetHttpProxies.get", + "parameterOrder": [ + "project", + "targetHttpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "targetHttpProxy": { + "description": "Name of the TargetHttpProxy resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpProxies/{targetHttpProxy}", + "response": { + "$ref": "TargetHttpProxy" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a TargetHttpProxy resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetHttpProxies.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/targetHttpProxies", + "request": { + "$ref": "TargetHttpProxy" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of TargetHttpProxy resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.targetHttpProxies.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpProxies", + "response": { + "$ref": "TargetHttpProxyList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setUrlMap": { + "description": "Changes the URL map for TargetHttpProxy.", + "httpMethod": "POST", + "id": "compute.targetHttpProxies.setUrlMap", + "parameterOrder": [ + "project", + "targetHttpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetHttpProxy": { + "description": "Name of the TargetHttpProxy to set a URL map for.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/targetHttpProxies/{targetHttpProxy}/setUrlMap", + "request": { + "$ref": "UrlMapReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "targetHttpsProxies": { + "methods": { + "delete": { + "description": "Deletes the specified TargetHttpsProxy resource.", + "httpMethod": "DELETE", + "id": "compute.targetHttpsProxies.delete", + "parameterOrder": [ + "project", + "targetHttpsProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetHttpsProxy": { + "description": "Name of the TargetHttpsProxy resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpsProxies/{targetHttpsProxy}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified TargetHttpsProxy resource. Gets a list of available target HTTPS proxies by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetHttpsProxies.get", + "parameterOrder": [ + "project", + "targetHttpsProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "targetHttpsProxy": { + "description": "Name of the TargetHttpsProxy resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpsProxies/{targetHttpsProxy}", + "response": { + "$ref": "TargetHttpsProxy" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a TargetHttpsProxy resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetHttpsProxies.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/targetHttpsProxies", + "request": { + "$ref": "TargetHttpsProxy" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of TargetHttpsProxy resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.targetHttpsProxies.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpsProxies", + "response": { + "$ref": "TargetHttpsProxyList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setSslCertificates": { + "description": "Replaces SslCertificates for TargetHttpsProxy.", + "httpMethod": "POST", + "id": "compute.targetHttpsProxies.setSslCertificates", + "parameterOrder": [ + "project", + "targetHttpsProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetHttpsProxy": { + "description": "Name of the TargetHttpsProxy resource to set an SslCertificates resource for.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/targetHttpsProxies/{targetHttpsProxy}/setSslCertificates", + "request": { + "$ref": "TargetHttpsProxiesSetSslCertificatesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setSslPolicy": { + "description": "Sets the SSL policy for TargetHttpsProxy. The SSL policy specifies the server-side support for SSL features. This affects connections between clients and the HTTPS proxy load balancer. They do not affect the connection between the load balancer and the backends.", + "httpMethod": "POST", + "id": "compute.targetHttpsProxies.setSslPolicy", + "parameterOrder": [ + "project", + "targetHttpsProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetHttpsProxy": { + "description": "Name of the TargetHttpsProxy resource whose SSL policy is to be set. The name must be 1-63 characters long, and comply with RFC1035.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetHttpsProxies/{targetHttpsProxy}/setSslPolicy", + "request": { + "$ref": "SslPolicyReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setUrlMap": { + "description": "Changes the URL map for TargetHttpsProxy.", + "httpMethod": "POST", + "id": "compute.targetHttpsProxies.setUrlMap", + "parameterOrder": [ + "project", + "targetHttpsProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetHttpsProxy": { + "description": "Name of the TargetHttpsProxy resource whose URL map is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/targetHttpsProxies/{targetHttpsProxy}/setUrlMap", + "request": { + "$ref": "UrlMapReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "targetInstances": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of target instances.", + "httpMethod": "GET", + "id": "compute.targetInstances.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/targetInstances", + "response": { + "$ref": "TargetInstanceAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified TargetInstance resource.", + "httpMethod": "DELETE", + "id": "compute.targetInstances.delete", + "parameterOrder": [ + "project", + "zone", + "targetInstance" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetInstance": { + "description": "Name of the TargetInstance resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/targetInstances/{targetInstance}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified TargetInstance resource. Gets a list of available target instances by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetInstances.get", + "parameterOrder": [ + "project", + "zone", + "targetInstance" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "targetInstance": { + "description": "Name of the TargetInstance resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/targetInstances/{targetInstance}", + "response": { + "$ref": "TargetInstance" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a TargetInstance resource in the specified project and zone using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetInstances.insert", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "zone": { + "description": "Name of the zone scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/targetInstances", + "request": { + "$ref": "TargetInstance" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of TargetInstance resources available to the specified project and zone.", + "httpMethod": "GET", + "id": "compute.targetInstances.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/targetInstances", + "response": { + "$ref": "TargetInstanceList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "targetPools": { + "methods": { + "addHealthCheck": { + "description": "Adds health check URLs to a target pool.", + "httpMethod": "POST", + "id": "compute.targetPools.addHealthCheck", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetPool": { + "description": "Name of the target pool to add a health check to.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}/addHealthCheck", + "request": { + "$ref": "TargetPoolsAddHealthCheckRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "addInstance": { + "description": "Adds an instance to a target pool.", + "httpMethod": "POST", + "id": "compute.targetPools.addInstance", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetPool": { + "description": "Name of the TargetPool resource to add instances to.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}/addInstance", + "request": { + "$ref": "TargetPoolsAddInstanceRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "aggregatedList": { + "description": "Retrieves an aggregated list of target pools.", + "httpMethod": "GET", + "id": "compute.targetPools.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/targetPools", + "response": { + "$ref": "TargetPoolAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified target pool.", + "httpMethod": "DELETE", + "id": "compute.targetPools.delete", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetPool": { + "description": "Name of the TargetPool resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified target pool. Gets a list of available target pools by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetPools.get", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "targetPool": { + "description": "Name of the TargetPool resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}", + "response": { + "$ref": "TargetPool" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "getHealth": { + "description": "Gets the most recent health check results for each IP for the instance that is referenced by the given target pool.", + "httpMethod": "POST", + "id": "compute.targetPools.getHealth", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "targetPool": { + "description": "Name of the TargetPool resource to which the queried instance belongs.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}/getHealth", + "request": { + "$ref": "InstanceReference" + }, + "response": { + "$ref": "TargetPoolInstanceHealth" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a target pool in the specified project and region using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetPools.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools", + "request": { + "$ref": "TargetPool" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of target pools available to the specified project and region.", + "httpMethod": "GET", + "id": "compute.targetPools.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools", + "response": { + "$ref": "TargetPoolList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "removeHealthCheck": { + "description": "Removes health check URL from a target pool.", + "httpMethod": "POST", + "id": "compute.targetPools.removeHealthCheck", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetPool": { + "description": "Name of the target pool to remove health checks from.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}/removeHealthCheck", + "request": { + "$ref": "TargetPoolsRemoveHealthCheckRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "removeInstance": { + "description": "Removes instance URL from a target pool.", + "httpMethod": "POST", + "id": "compute.targetPools.removeInstance", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetPool": { + "description": "Name of the TargetPool resource to remove instances from.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}/removeInstance", + "request": { + "$ref": "TargetPoolsRemoveInstanceRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setBackup": { + "description": "Changes a backup target pool's configurations.", + "httpMethod": "POST", + "id": "compute.targetPools.setBackup", + "parameterOrder": [ + "project", + "region", + "targetPool" + ], + "parameters": { + "failoverRatio": { + "description": "New failoverRatio value for the target pool.", + "format": "float", + "location": "query", + "type": "number" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetPool": { + "description": "Name of the TargetPool resource to set a backup pool for.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetPools/{targetPool}/setBackup", + "request": { + "$ref": "TargetReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "targetSslProxies": { + "methods": { + "delete": { + "description": "Deletes the specified TargetSslProxy resource.", + "httpMethod": "DELETE", + "id": "compute.targetSslProxies.delete", + "parameterOrder": [ + "project", + "targetSslProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetSslProxy": { + "description": "Name of the TargetSslProxy resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies/{targetSslProxy}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified TargetSslProxy resource. Gets a list of available target SSL proxies by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetSslProxies.get", + "parameterOrder": [ + "project", + "targetSslProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "targetSslProxy": { + "description": "Name of the TargetSslProxy resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies/{targetSslProxy}", + "response": { + "$ref": "TargetSslProxy" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a TargetSslProxy resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetSslProxies.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies", + "request": { + "$ref": "TargetSslProxy" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of TargetSslProxy resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.targetSslProxies.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies", + "response": { + "$ref": "TargetSslProxyList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setBackendService": { + "description": "Changes the BackendService for TargetSslProxy.", + "httpMethod": "POST", + "id": "compute.targetSslProxies.setBackendService", + "parameterOrder": [ + "project", + "targetSslProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetSslProxy": { + "description": "Name of the TargetSslProxy resource whose BackendService resource is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies/{targetSslProxy}/setBackendService", + "request": { + "$ref": "TargetSslProxiesSetBackendServiceRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setProxyHeader": { + "description": "Changes the ProxyHeaderType for TargetSslProxy.", + "httpMethod": "POST", + "id": "compute.targetSslProxies.setProxyHeader", + "parameterOrder": [ + "project", + "targetSslProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetSslProxy": { + "description": "Name of the TargetSslProxy resource whose ProxyHeader is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies/{targetSslProxy}/setProxyHeader", + "request": { + "$ref": "TargetSslProxiesSetProxyHeaderRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setSslCertificates": { + "description": "Changes SslCertificates for TargetSslProxy.", + "httpMethod": "POST", + "id": "compute.targetSslProxies.setSslCertificates", + "parameterOrder": [ + "project", + "targetSslProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetSslProxy": { + "description": "Name of the TargetSslProxy resource whose SslCertificate resource is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies/{targetSslProxy}/setSslCertificates", + "request": { + "$ref": "TargetSslProxiesSetSslCertificatesRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setSslPolicy": { + "description": "Sets the SSL policy for TargetSslProxy. The SSL policy specifies the server-side support for SSL features. This affects connections between clients and the SSL proxy load balancer. They do not affect the connection between the load balancer and the backends.", + "httpMethod": "POST", + "id": "compute.targetSslProxies.setSslPolicy", + "parameterOrder": [ + "project", + "targetSslProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetSslProxy": { + "description": "Name of the TargetSslProxy resource whose SSL policy is to be set. The name must be 1-63 characters long, and comply with RFC1035.", + "location": "path", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetSslProxies/{targetSslProxy}/setSslPolicy", + "request": { + "$ref": "SslPolicyReference" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "targetTcpProxies": { + "methods": { + "delete": { + "description": "Deletes the specified TargetTcpProxy resource.", + "httpMethod": "DELETE", + "id": "compute.targetTcpProxies.delete", + "parameterOrder": [ + "project", + "targetTcpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetTcpProxy": { + "description": "Name of the TargetTcpProxy resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetTcpProxies/{targetTcpProxy}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified TargetTcpProxy resource. Gets a list of available target TCP proxies by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetTcpProxies.get", + "parameterOrder": [ + "project", + "targetTcpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "targetTcpProxy": { + "description": "Name of the TargetTcpProxy resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetTcpProxies/{targetTcpProxy}", + "response": { + "$ref": "TargetTcpProxy" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a TargetTcpProxy resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetTcpProxies.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/targetTcpProxies", + "request": { + "$ref": "TargetTcpProxy" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of TargetTcpProxy resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.targetTcpProxies.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetTcpProxies", + "response": { + "$ref": "TargetTcpProxyList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "setBackendService": { + "description": "Changes the BackendService for TargetTcpProxy.", + "httpMethod": "POST", + "id": "compute.targetTcpProxies.setBackendService", + "parameterOrder": [ + "project", + "targetTcpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetTcpProxy": { + "description": "Name of the TargetTcpProxy resource whose BackendService resource is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetTcpProxies/{targetTcpProxy}/setBackendService", + "request": { + "$ref": "TargetTcpProxiesSetBackendServiceRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "setProxyHeader": { + "description": "Changes the ProxyHeaderType for TargetTcpProxy.", + "httpMethod": "POST", + "id": "compute.targetTcpProxies.setProxyHeader", + "parameterOrder": [ + "project", + "targetTcpProxy" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetTcpProxy": { + "description": "Name of the TargetTcpProxy resource whose ProxyHeader is to be set.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/targetTcpProxies/{targetTcpProxy}/setProxyHeader", + "request": { + "$ref": "TargetTcpProxiesSetProxyHeaderRequest" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "targetVpnGateways": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of target VPN gateways.", + "httpMethod": "GET", + "id": "compute.targetVpnGateways.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/targetVpnGateways", + "response": { + "$ref": "TargetVpnGatewayAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified target VPN gateway.", + "httpMethod": "DELETE", + "id": "compute.targetVpnGateways.delete", + "parameterOrder": [ + "project", + "region", + "targetVpnGateway" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "targetVpnGateway": { + "description": "Name of the target VPN gateway to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetVpnGateways/{targetVpnGateway}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified target VPN gateway. Gets a list of available target VPN gateways by making a list() request.", + "httpMethod": "GET", + "id": "compute.targetVpnGateways.get", + "parameterOrder": [ + "project", + "region", + "targetVpnGateway" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "targetVpnGateway": { + "description": "Name of the target VPN gateway to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetVpnGateways/{targetVpnGateway}", + "response": { + "$ref": "TargetVpnGateway" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a target VPN gateway in the specified project and region using the data included in the request.", + "httpMethod": "POST", + "id": "compute.targetVpnGateways.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetVpnGateways", + "request": { + "$ref": "TargetVpnGateway" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of target VPN gateways available to the specified project and region.", + "httpMethod": "GET", + "id": "compute.targetVpnGateways.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/targetVpnGateways", + "response": { + "$ref": "TargetVpnGatewayList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "urlMaps": { + "methods": { + "delete": { + "description": "Deletes the specified UrlMap resource.", + "httpMethod": "DELETE", + "id": "compute.urlMaps.delete", + "parameterOrder": [ + "project", + "urlMap" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "urlMap": { + "description": "Name of the UrlMap resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps/{urlMap}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified UrlMap resource. Gets a list of available URL maps by making a list() request.", + "httpMethod": "GET", + "id": "compute.urlMaps.get", + "parameterOrder": [ + "project", + "urlMap" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "urlMap": { + "description": "Name of the UrlMap resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps/{urlMap}", + "response": { + "$ref": "UrlMap" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a UrlMap resource in the specified project using the data included in the request.", + "httpMethod": "POST", + "id": "compute.urlMaps.insert", + "parameterOrder": [ + "project" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/global/urlMaps", + "request": { + "$ref": "UrlMap" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "invalidateCache": { + "description": "Initiates a cache invalidation operation, invalidating the specified path, scoped to the specified UrlMap.", + "httpMethod": "POST", + "id": "compute.urlMaps.invalidateCache", + "parameterOrder": [ + "project", + "urlMap" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "urlMap": { + "description": "Name of the UrlMap scoping this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps/{urlMap}/invalidateCache", + "request": { + "$ref": "CacheInvalidationRule" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves the list of UrlMap resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.urlMaps.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps", + "response": { + "$ref": "UrlMapList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "patch": { + "description": "Patches the specified UrlMap resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules.", + "httpMethod": "PATCH", + "id": "compute.urlMaps.patch", + "parameterOrder": [ + "project", + "urlMap" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "urlMap": { + "description": "Name of the UrlMap resource to patch.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps/{urlMap}", + "request": { + "$ref": "UrlMap" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "update": { + "description": "Updates the specified UrlMap resource with the data included in the request.", + "httpMethod": "PUT", + "id": "compute.urlMaps.update", + "parameterOrder": [ + "project", + "urlMap" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "urlMap": { + "description": "Name of the UrlMap resource to update.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps/{urlMap}", + "request": { + "$ref": "UrlMap" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "validate": { + "description": "Runs static validation for the UrlMap. In particular, the tests of the provided UrlMap will be run. Calling this method does NOT create the UrlMap.", + "httpMethod": "POST", + "id": "compute.urlMaps.validate", + "parameterOrder": [ + "project", + "urlMap" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "urlMap": { + "description": "Name of the UrlMap resource to be validated as.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/global/urlMaps/{urlMap}/validate", + "request": { + "$ref": "UrlMapsValidateRequest" + }, + "response": { + "$ref": "UrlMapsValidateResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + } + } + }, + "vpnTunnels": { + "methods": { + "aggregatedList": { + "description": "Retrieves an aggregated list of VPN tunnels.", + "httpMethod": "GET", + "id": "compute.vpnTunnels.aggregatedList", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/aggregated/vpnTunnels", + "response": { + "$ref": "VpnTunnelAggregatedList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "delete": { + "description": "Deletes the specified VpnTunnel resource.", + "httpMethod": "DELETE", + "id": "compute.vpnTunnels.delete", + "parameterOrder": [ + "project", + "region", + "vpnTunnel" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + }, + "vpnTunnel": { + "description": "Name of the VpnTunnel resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/vpnTunnels/{vpnTunnel}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Returns the specified VpnTunnel resource. Gets a list of available VPN tunnels by making a list() request.", + "httpMethod": "GET", + "id": "compute.vpnTunnels.get", + "parameterOrder": [ + "project", + "region", + "vpnTunnel" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "vpnTunnel": { + "description": "Name of the VpnTunnel resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/vpnTunnels/{vpnTunnel}", + "response": { + "$ref": "VpnTunnel" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "insert": { + "description": "Creates a VpnTunnel resource in the specified project and region using the data included in the request.", + "httpMethod": "POST", + "id": "compute.vpnTunnels.insert", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "requestId": { + "description": "An optional request ID to identify requests. Specify a unique request ID so that if you must retry your request, the server will know to ignore the request if it has already been completed.\n\nFor example, consider a situation where you make an initial request and the request times out. If you make the request again with the same request ID, the server can check if original operation with the same request ID was received, and if so, will ignore the second request. This prevents clients from accidentally creating duplicate commitments.\n\nThe request ID must be a valid UUID with the exception that zero UUID is not supported (00000000-0000-0000-0000-000000000000).", + "location": "query", + "type": "string" + } + }, + "path": "{project}/regions/{region}/vpnTunnels", + "request": { + "$ref": "VpnTunnel" + }, + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "list": { + "description": "Retrieves a list of VpnTunnel resources contained in the specified project and region.", + "httpMethod": "GET", + "id": "compute.vpnTunnels.list", + "parameterOrder": [ + "project", + "region" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "region": { + "description": "Name of the region for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/regions/{region}/vpnTunnels", + "response": { + "$ref": "VpnTunnelList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "zoneOperations": { + "methods": { + "delete": { + "description": "Deletes the specified zone-specific Operations resource.", + "httpMethod": "DELETE", + "id": "compute.zoneOperations.delete", + "parameterOrder": [ + "project", + "zone", + "operation" + ], + "parameters": { + "operation": { + "description": "Name of the Operations resource to delete.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/operations/{operation}", + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute" + ] + }, + "get": { + "description": "Retrieves the specified zone-specific Operations resource.", + "httpMethod": "GET", + "id": "compute.zoneOperations.get", + "parameterOrder": [ + "project", + "zone", + "operation" + ], + "parameters": { + "operation": { + "description": "Name of the Operations resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone for this request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/operations/{operation}", + "response": { + "$ref": "Operation" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves a list of Operation resources contained within the specified zone.", + "httpMethod": "GET", + "id": "compute.zoneOperations.list", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone for request.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}/operations", + "response": { + "$ref": "OperationList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + }, + "zones": { + "methods": { + "get": { + "description": "Returns the specified Zone resource. Gets a list of available zones by making a list() request.", + "httpMethod": "GET", + "id": "compute.zones.get", + "parameterOrder": [ + "project", + "zone" + ], + "parameters": { + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + }, + "zone": { + "description": "Name of the zone resource to return.", + "location": "path", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones/{zone}", + "response": { + "$ref": "Zone" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + }, + "list": { + "description": "Retrieves the list of Zone resources available to the specified project.", + "httpMethod": "GET", + "id": "compute.zones.list", + "parameterOrder": [ + "project" + ], + "parameters": { + "filter": { + "description": "A filter expression that filters resources listed in the response. The expression must specify the field name, a comparison operator, and the value that you want to use for filtering. The value must be a string, a number, or a boolean. The comparison operator must be either =, !=, \u003e, or \u003c.\n\nFor example, if you are filtering Compute Engine instances, you can exclude instances named example-instance by specifying name != example-instance.\n\nYou can also filter nested fields. For example, you could specify scheduling.automaticRestart = false to include instances only if they are not scheduled for automatic restarts. You can use filtering on nested fields to filter based on resource labels.\n\nTo filter on multiple expressions, provide each separate expression within parentheses. For example, (scheduling.automaticRestart = true) (cpuPlatform = \"Intel Skylake\"). By default, each expression is an AND expression. However, you can include AND and OR expressions explicitly. For example, (cpuPlatform = \"Intel Skylake\") OR (cpuPlatform = \"Intel Broadwell\") AND (scheduling.automaticRestart = true).", + "location": "query", + "type": "string" + }, + "maxResults": { + "default": "500", + "description": "The maximum number of results per page that should be returned. If the number of available results is larger than maxResults, Compute Engine returns a nextPageToken that can be used to get the next page of results in subsequent list requests. Acceptable values are 0 to 500, inclusive. (Default: 500)", + "format": "uint32", + "location": "query", + "minimum": "0", + "type": "integer" + }, + "orderBy": { + "description": "Sorts list results by a certain order. By default, results are returned in alphanumerical order based on the resource name.\n\nYou can also sort results in descending order based on the creation timestamp using orderBy=\"creationTimestamp desc\". This sorts results based on the creationTimestamp field in reverse chronological order (newest result first). Use this to sort resources like operations so that the newest operation is returned first.\n\nCurrently, only sorting by name or creationTimestamp desc is supported.", + "location": "query", + "type": "string" + }, + "pageToken": { + "description": "Specifies a page token to use. Set pageToken to the nextPageToken returned by a previous list request to get the next page of results.", + "location": "query", + "type": "string" + }, + "project": { + "description": "Project ID for this request.", + "location": "path", + "pattern": "(?:(?:[-a-z0-9]{1,63}\\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?(?:[0-9]{1,19}|(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))", + "required": true, + "type": "string" + } + }, + "path": "{project}/zones", + "response": { + "$ref": "ZoneList" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly" + ] + } + } + } + }, + "revision": "20180516", + "rootUrl": "https://www.googleapis.com/", + "schemas": { + "AcceleratorConfig": { + "description": "A specification of the type and number of accelerator cards attached to the instance.", + "id": "AcceleratorConfig", + "properties": { + "acceleratorCount": { + "description": "The number of the guest accelerator cards exposed to this instance.", + "format": "int32", + "type": "integer" + }, + "acceleratorType": { + "description": "Full or partial URL of the accelerator type resource to attach to this instance. If you are creating an instance template, specify only the accelerator name.", + "type": "string" + } + }, + "type": "object" + }, + "AcceleratorType": { + "description": "An Accelerator Type resource. (== resource_for beta.acceleratorTypes ==) (== resource_for v1.acceleratorTypes ==)", + "id": "AcceleratorType", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "deprecated": { + "$ref": "DeprecationStatus", + "description": "[Output Only] The deprecation status associated with this accelerator type." + }, + "description": { + "description": "[Output Only] An optional textual description of the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#acceleratorType", + "description": "[Output Only] The type of the resource. Always compute#acceleratorType for accelerator types.", + "type": "string" + }, + "maximumCardsPerInstance": { + "description": "[Output Only] Maximum accelerator cards allowed per instance.", + "format": "int32", + "type": "integer" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined fully-qualified URL for this resource.", + "type": "string" + }, + "zone": { + "description": "[Output Only] The name of the zone where the accelerator type resides, such as us-central1-a. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + } + }, + "type": "object" + }, + "AcceleratorTypeAggregatedList": { + "id": "AcceleratorTypeAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "AcceleratorTypesScopedList", + "description": "[Output Only] Name of the scope containing this set of accelerator types." + }, + "description": "A list of AcceleratorTypesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#acceleratorTypeAggregatedList", + "description": "[Output Only] Type of resource. Always compute#acceleratorTypeAggregatedList for aggregated lists of accelerator types.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AcceleratorTypeList": { + "description": "Contains a list of accelerator types.", + "id": "AcceleratorTypeList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of AcceleratorType resources.", + "items": { + "$ref": "AcceleratorType" + }, + "type": "array" + }, + "kind": { + "default": "compute#acceleratorTypeList", + "description": "[Output Only] Type of resource. Always compute#acceleratorTypeList for lists of accelerator types.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AcceleratorTypesScopedList": { + "id": "AcceleratorTypesScopedList", + "properties": { + "acceleratorTypes": { + "description": "[Output Only] A list of accelerator types contained in this scope.", + "items": { + "$ref": "AcceleratorType" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] An informational warning that appears when the accelerator types list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AccessConfig": { + "description": "An access configuration attached to an instance's network interface. Only one access config per instance is supported.", + "id": "AccessConfig", + "properties": { + "kind": { + "default": "compute#accessConfig", + "description": "[Output Only] Type of the resource. Always compute#accessConfig for access configs.", + "type": "string" + }, + "name": { + "description": "The name of this access configuration. The default and recommended name is External NAT but you can use any arbitrary string you would like. For example, My external IP or Network Access.", + "type": "string" + }, + "natIP": { + "description": "An external IP address associated with this instance. Specify an unused static external IP address available to the project or leave this field undefined to use an IP from a shared ephemeral IP address pool. If you specify a static external IP address, it must live in the same region as the zone of the instance.", + "type": "string" + }, + "publicPtrDomainName": { + "description": "The DNS domain name for the public PTR record. This field can only be set when the set_public_ptr field is enabled.", + "type": "string" + }, + "setPublicPtr": { + "description": "Specifies whether a public DNS ?PTR? record should be created to map the external IP address of the instance to a DNS domain name.", + "type": "boolean" + }, + "type": { + "default": "ONE_TO_ONE_NAT", + "description": "The type of configuration. The default and only option is ONE_TO_ONE_NAT.", + "enum": [ + "ONE_TO_ONE_NAT" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "Address": { + "description": "A reserved address resource. (== resource_for beta.addresses ==) (== resource_for v1.addresses ==) (== resource_for beta.globalAddresses ==) (== resource_for v1.globalAddresses ==)", + "id": "Address", + "properties": { + "address": { + "description": "The static IP address represented by this resource.", + "type": "string" + }, + "addressType": { + "description": "The type of address to reserve, either INTERNAL or EXTERNAL. If unspecified, defaults to EXTERNAL.", + "enum": [ + "EXTERNAL", + "INTERNAL", + "UNSPECIFIED_TYPE" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "ipVersion": { + "description": "The IP Version that will be used by this address. Valid options are IPV4 or IPV6. This can only be specified for a global address.", + "enum": [ + "IPV4", + "IPV6", + "UNSPECIFIED_VERSION" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "kind": { + "default": "compute#address", + "description": "[Output Only] Type of the resource. Always compute#address for addresses.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.addresses.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the regional address resides. This field is not applicable to global addresses. You must specify this field as part of the HTTP request URL. You cannot set this field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the address, which can be one of RESERVING, RESERVED, or IN_USE. An address that is RESERVING is currently in the process of being reserved. A RESERVED address is currently reserved and available to use. An IN_USE address is currently being used by another resource and is not available.", + "enum": [ + "IN_USE", + "RESERVED" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "subnetwork": { + "description": "The URL of the subnetwork in which to reserve the address. If an IP address is specified, it must be within the subnetwork's IP range. This field can only be used with INTERNAL type with GCE_ENDPOINT/DNS_RESOLVER purposes.", + "type": "string" + }, + "users": { + "description": "[Output Only] The URLs of the resources that are using this address.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "AddressAggregatedList": { + "id": "AddressAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "AddressesScopedList", + "description": "[Output Only] Name of the scope containing this set of addresses." + }, + "description": "A list of AddressesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#addressAggregatedList", + "description": "[Output Only] Type of resource. Always compute#addressAggregatedList for aggregated lists of addresses.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AddressList": { + "description": "Contains a list of addresses.", + "id": "AddressList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Address resources.", + "items": { + "$ref": "Address" + }, + "type": "array" + }, + "kind": { + "default": "compute#addressList", + "description": "[Output Only] Type of resource. Always compute#addressList for lists of addresses.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AddressesScopedList": { + "id": "AddressesScopedList", + "properties": { + "addresses": { + "description": "[Output Only] A list of addresses contained in this scope.", + "items": { + "$ref": "Address" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of addresses when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AliasIpRange": { + "description": "An alias IP range attached to an instance's network interface.", + "id": "AliasIpRange", + "properties": { + "ipCidrRange": { + "description": "The IP CIDR range represented by this alias IP range. This IP CIDR range must belong to the specified subnetwork and cannot contain IP addresses reserved by system or used by other network interfaces. This range may be a single IP address (e.g. 10.2.3.4), a netmask (e.g. /24) or a CIDR format string (e.g. 10.1.2.0/24).", + "type": "string" + }, + "subnetworkRangeName": { + "description": "Optional subnetwork secondary range name specifying the secondary range from which to allocate the IP CIDR range for this alias IP range. If left unspecified, the primary range of the subnetwork will be used.", + "type": "string" + } + }, + "type": "object" + }, + "AttachedDisk": { + "description": "An instance-attached disk resource.", + "id": "AttachedDisk", + "properties": { + "autoDelete": { + "description": "Specifies whether the disk will be auto-deleted when the instance is deleted (but not when the disk is detached from the instance).", + "type": "boolean" + }, + "boot": { + "description": "Indicates that this is a boot disk. The virtual machine will use the first partition of the disk for its root filesystem.", + "type": "boolean" + }, + "deviceName": { + "description": "Specifies a unique device name of your choice that is reflected into the /dev/disk/by-id/google-* tree of a Linux operating system running within the instance. This name can be used to reference the device for mounting, resizing, and so on, from within the instance.\n\nIf not specified, the server chooses a default device name to apply to this disk, in the form persistent-disks-x, where x is a number assigned by Google Compute Engine. This field is only applicable for persistent disks.", + "type": "string" + }, + "diskEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "Encrypts or decrypts a disk using a customer-supplied encryption key.\n\nIf you are creating a new disk, this field encrypts the new disk using an encryption key that you provide. If you are attaching an existing disk that is already encrypted, this field decrypts the disk using the customer-supplied encryption key.\n\nIf you encrypt a disk using a customer-supplied key, you must provide the same key again when you attempt to use this resource at a later time. For example, you must provide the key when you create a snapshot or an image from the disk or when you attach the disk to a virtual machine instance.\n\nIf you do not provide an encryption key, then the disk will be encrypted using an automatically generated key and you do not need to provide a key to use the disk later.\n\nInstance templates do not store customer-supplied encryption keys, so you cannot use your own keys to encrypt disks in a managed instance group." + }, + "guestOsFeatures": { + "description": "A list of features to enable on the guest operating system. Applicable only for bootable images. Read Enabling guest operating system features to see a list of available options.", + "items": { + "$ref": "GuestOsFeature" + }, + "type": "array" + }, + "index": { + "description": "[Output Only] A zero-based index to this disk, where 0 is reserved for the boot disk. If you have many disks attached to an instance, each disk would have a unique index number.", + "format": "int32", + "type": "integer" + }, + "initializeParams": { + "$ref": "AttachedDiskInitializeParams", + "description": "[Input Only] Specifies the parameters for a new disk that will be created alongside the new instance. Use initialization parameters to create boot disks or local SSDs attached to the new instance.\n\nThis property is mutually exclusive with the source property; you can only define one or the other, but not both." + }, + "interface": { + "description": "Specifies the disk interface to use for attaching this disk, which is either SCSI or NVME. The default is SCSI. Persistent disks must always use SCSI and the request will fail if you attempt to attach a persistent disk in any other format than SCSI. Local SSDs can use either NVME or SCSI. For performance characteristics of SCSI over NVMe, see Local SSD performance.", + "enum": [ + "NVME", + "SCSI" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "kind": { + "default": "compute#attachedDisk", + "description": "[Output Only] Type of the resource. Always compute#attachedDisk for attached disks.", + "type": "string" + }, + "licenses": { + "description": "[Output Only] Any valid publicly visible licenses.", + "items": { + "type": "string" + }, + "type": "array" + }, + "mode": { + "description": "The mode in which to attach this disk, either READ_WRITE or READ_ONLY. If not specified, the default is to attach the disk in READ_WRITE mode.", + "enum": [ + "READ_ONLY", + "READ_WRITE" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "source": { + "description": "Specifies a valid partial or full URL to an existing Persistent Disk resource. When creating a new instance, one of initializeParams.sourceImage or disks.source is required except for local SSD.\n\nIf desired, you can also attach existing non-root persistent disks using this property. This field is only applicable for persistent disks.\n\nNote that for InstanceTemplate, specify the disk name, not the URL for the disk.", + "type": "string" + }, + "type": { + "description": "Specifies the type of the disk, either SCRATCH or PERSISTENT. If not specified, the default is PERSISTENT.", + "enum": [ + "PERSISTENT", + "SCRATCH" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "AttachedDiskInitializeParams": { + "description": "[Input Only] Specifies the parameters for a new disk that will be created alongside the new instance. Use initialization parameters to create boot disks or local SSDs attached to the new instance.\n\nThis property is mutually exclusive with the source property; you can only define one or the other, but not both.", + "id": "AttachedDiskInitializeParams", + "properties": { + "diskName": { + "description": "Specifies the disk name. If not specified, the default is to use the name of the instance.", + "type": "string" + }, + "diskSizeGb": { + "description": "Specifies the size of the disk in base-2 GB.", + "format": "int64", + "type": "string" + }, + "diskType": { + "description": "Specifies the disk type to use to create the instance. If not specified, the default is pd-standard, specified using the full URL. For example:\nhttps://www.googleapis.com/compute/v1/projects/project/zones/zone/diskTypes/pd-standard\n\n\nOther values include pd-ssd and local-ssd. If you define this field, you can provide either the full or partial URL. For example, the following are valid values: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/diskTypes/diskType \n- projects/project/zones/zone/diskTypes/diskType \n- zones/zone/diskTypes/diskType Note that for InstanceTemplate, this is the name of the disk type, not URL.", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels to apply to this disk. These can be later modified by the disks.setLabels method. This field is only applicable for persistent disks.", + "type": "object" + }, + "sourceImage": { + "description": "The source image to create this disk. When creating a new instance, one of initializeParams.sourceImage or disks.source is required except for local SSD.\n\nTo create a disk with one of the public operating system images, specify the image by its family name. For example, specify family/debian-8 to use the latest Debian 8 image:\nprojects/debian-cloud/global/images/family/debian-8\n\n\nAlternatively, use a specific version of a public operating system image:\nprojects/debian-cloud/global/images/debian-8-jessie-vYYYYMMDD\n\n\nTo create a disk with a custom image that you created, specify the image name in the following format:\nglobal/images/my-custom-image\n\n\nYou can also specify a custom image by its image family, which returns the latest version of the image in that family. Replace the image name with family/family-name:\nglobal/images/family/my-image-family\n\n\nIf the source image is deleted later, this field will not be set.", + "type": "string" + }, + "sourceImageEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source image. Required if the source image is protected by a customer-supplied encryption key.\n\nInstance templates do not store customer-supplied encryption keys, so you cannot create disks for instances in a managed instance group if the source images are encrypted with your own keys." + } + }, + "type": "object" + }, + "Autoscaler": { + "description": "Represents an Autoscaler resource. Autoscalers allow you to automatically scale virtual machine instances in managed instance groups according to an autoscaling policy that you define. For more information, read Autoscaling Groups of Instances. (== resource_for beta.autoscalers ==) (== resource_for v1.autoscalers ==) (== resource_for beta.regionAutoscalers ==) (== resource_for v1.regionAutoscalers ==)", + "id": "Autoscaler", + "properties": { + "autoscalingPolicy": { + "$ref": "AutoscalingPolicy", + "description": "The configuration parameters for the autoscaling algorithm. You can define one or more of the policies for an autoscaler: cpuUtilization, customMetricUtilizations, and loadBalancingUtilization.\n\nIf none of these are specified, the default will be to autoscale based on cpuUtilization to 0.6 or 60%." + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#autoscaler", + "description": "[Output Only] Type of the resource. Always compute#autoscaler for autoscalers.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.instanceGroups.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the instance group resides (for autoscalers living in regional scope).", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the autoscaler configuration.", + "enum": [ + "ACTIVE", + "DELETING", + "ERROR", + "PENDING" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "statusDetails": { + "description": "[Output Only] Human-readable details about the current state of the autoscaler. Read the documentation for Commonly returned status messages for examples of status messages you might encounter.", + "items": { + "$ref": "AutoscalerStatusDetails" + }, + "type": "array" + }, + "target": { + "description": "URL of the managed instance group that this autoscaler will scale.", + "type": "string" + }, + "zone": { + "description": "[Output Only] URL of the zone where the instance group resides (for autoscalers living in zonal scope).", + "type": "string" + } + }, + "type": "object" + }, + "AutoscalerAggregatedList": { + "id": "AutoscalerAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "AutoscalersScopedList", + "description": "[Output Only] Name of the scope containing this set of autoscalers." + }, + "description": "A list of AutoscalersScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#autoscalerAggregatedList", + "description": "[Output Only] Type of resource. Always compute#autoscalerAggregatedList for aggregated lists of autoscalers.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AutoscalerList": { + "description": "Contains a list of Autoscaler resources.", + "id": "AutoscalerList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Autoscaler resources.", + "items": { + "$ref": "Autoscaler" + }, + "type": "array" + }, + "kind": { + "default": "compute#autoscalerList", + "description": "[Output Only] Type of resource. Always compute#autoscalerList for lists of autoscalers.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AutoscalerStatusDetails": { + "id": "AutoscalerStatusDetails", + "properties": { + "message": { + "description": "The status message.", + "type": "string" + }, + "type": { + "description": "The type of error returned.", + "enum": [ + "ALL_INSTANCES_UNHEALTHY", + "BACKEND_SERVICE_DOES_NOT_EXIST", + "CAPPED_AT_MAX_NUM_REPLICAS", + "CUSTOM_METRIC_DATA_POINTS_TOO_SPARSE", + "CUSTOM_METRIC_INVALID", + "MIN_EQUALS_MAX", + "MISSING_CUSTOM_METRIC_DATA_POINTS", + "MISSING_LOAD_BALANCING_DATA_POINTS", + "MORE_THAN_ONE_BACKEND_SERVICE", + "NOT_ENOUGH_QUOTA_AVAILABLE", + "REGION_RESOURCE_STOCKOUT", + "SCALING_TARGET_DOES_NOT_EXIST", + "UNKNOWN", + "UNSUPPORTED_MAX_RATE_LOAD_BALANCING_CONFIGURATION", + "ZONE_RESOURCE_STOCKOUT" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "AutoscalersScopedList": { + "id": "AutoscalersScopedList", + "properties": { + "autoscalers": { + "description": "[Output Only] A list of autoscalers contained in this scope.", + "items": { + "$ref": "Autoscaler" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of autoscalers when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "AutoscalingPolicy": { + "description": "Cloud Autoscaler policy.", + "id": "AutoscalingPolicy", + "properties": { + "coolDownPeriodSec": { + "description": "The number of seconds that the autoscaler should wait before it starts collecting information from a new instance. This prevents the autoscaler from collecting information when the instance is initializing, during which the collected usage would not be reliable. The default time autoscaler waits is 60 seconds.\n\nVirtual machine initialization times might vary because of numerous factors. We recommend that you test how long an instance may take to initialize. To do this, create an instance and time the startup process.", + "format": "int32", + "type": "integer" + }, + "cpuUtilization": { + "$ref": "AutoscalingPolicyCpuUtilization", + "description": "Defines the CPU utilization policy that allows the autoscaler to scale based on the average CPU utilization of a managed instance group." + }, + "customMetricUtilizations": { + "description": "Configuration parameters of autoscaling based on a custom metric.", + "items": { + "$ref": "AutoscalingPolicyCustomMetricUtilization" + }, + "type": "array" + }, + "loadBalancingUtilization": { + "$ref": "AutoscalingPolicyLoadBalancingUtilization", + "description": "Configuration parameters of autoscaling based on load balancer." + }, + "maxNumReplicas": { + "description": "The maximum number of instances that the autoscaler can scale up to. This is required when creating or updating an autoscaler. The maximum number of replicas should not be lower than minimal number of replicas.", + "format": "int32", + "type": "integer" + }, + "minNumReplicas": { + "description": "The minimum number of replicas that the autoscaler can scale down to. This cannot be less than 0. If not provided, autoscaler will choose a default value depending on maximum number of instances allowed.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "AutoscalingPolicyCpuUtilization": { + "description": "CPU utilization policy.", + "id": "AutoscalingPolicyCpuUtilization", + "properties": { + "utilizationTarget": { + "description": "The target CPU utilization that the autoscaler should maintain. Must be a float value in the range (0, 1]. If not specified, the default is 0.6.\n\nIf the CPU level is below the target utilization, the autoscaler scales down the number of instances until it reaches the minimum number of instances you specified or until the average CPU of your instances reaches the target utilization.\n\nIf the average CPU is above the target utilization, the autoscaler scales up until it reaches the maximum number of instances you specified or until the average utilization reaches the target utilization.", + "format": "double", + "type": "number" + } + }, + "type": "object" + }, + "AutoscalingPolicyCustomMetricUtilization": { + "description": "Custom utilization metric policy.", + "id": "AutoscalingPolicyCustomMetricUtilization", + "properties": { + "metric": { + "description": "The identifier (type) of the Stackdriver Monitoring metric. The metric cannot have negative values.\n\nThe metric must have a value type of INT64 or DOUBLE.", + "type": "string" + }, + "utilizationTarget": { + "description": "The target value of the metric that autoscaler should maintain. This must be a positive value. A utilization metric scales number of virtual machines handling requests to increase or decrease proportionally to the metric.\n\nFor example, a good metric to use as a utilization_target is compute.googleapis.com/instance/network/received_bytes_count. The autoscaler will work to keep this value constant for each of the instances.", + "format": "double", + "type": "number" + }, + "utilizationTargetType": { + "description": "Defines how target utilization value is expressed for a Stackdriver Monitoring metric. Either GAUGE, DELTA_PER_SECOND, or DELTA_PER_MINUTE. If not specified, the default is GAUGE.", + "enum": [ + "DELTA_PER_MINUTE", + "DELTA_PER_SECOND", + "GAUGE" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "AutoscalingPolicyLoadBalancingUtilization": { + "description": "Configuration parameters of autoscaling based on load balancing.", + "id": "AutoscalingPolicyLoadBalancingUtilization", + "properties": { + "utilizationTarget": { + "description": "Fraction of backend capacity utilization (set in HTTP(s) load balancing configuration) that autoscaler should maintain. Must be a positive float value. If not defined, the default is 0.8.", + "format": "double", + "type": "number" + } + }, + "type": "object" + }, + "Backend": { + "description": "Message containing information of one individual backend.", + "id": "Backend", + "properties": { + "balancingMode": { + "description": "Specifies the balancing mode for this backend. For global HTTP(S) or TCP/SSL load balancing, the default is UTILIZATION. Valid values are UTILIZATION, RATE (for HTTP(S)) and CONNECTION (for TCP/SSL).\n\nFor Internal Load Balancing, the default and only supported mode is CONNECTION.", + "enum": [ + "CONNECTION", + "RATE", + "UTILIZATION" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "capacityScaler": { + "description": "A multiplier applied to the group's maximum servicing capacity (based on UTILIZATION, RATE or CONNECTION). Default value is 1, which means the group will serve up to 100% of its configured capacity (depending on balancingMode). A setting of 0 means the group is completely drained, offering 0% of its available Capacity. Valid range is [0.0,1.0].\n\nThis cannot be used for internal load balancing.", + "format": "float", + "type": "number" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "group": { + "description": "The fully-qualified URL of a Instance Group resource. This instance group defines the list of instances that serve traffic. Member virtual machine instances from each instance group must live in the same zone as the instance group itself. No two backends in a backend service are allowed to use same Instance Group resource.\n\nNote that you must specify an Instance Group resource using the fully-qualified URL, rather than a partial URL.\n\nWhen the BackendService has load balancing scheme INTERNAL, the instance group must be within the same region as the BackendService.", + "type": "string" + }, + "maxConnections": { + "description": "The max number of simultaneous connections for the group. Can be used with either CONNECTION or UTILIZATION balancing modes. For CONNECTION mode, either maxConnections or maxConnectionsPerInstance must be set.\n\nThis cannot be used for internal load balancing.", + "format": "int32", + "type": "integer" + }, + "maxConnectionsPerInstance": { + "description": "The max number of simultaneous connections that a single backend instance can handle. This is used to calculate the capacity of the group. Can be used in either CONNECTION or UTILIZATION balancing modes. For CONNECTION mode, either maxConnections or maxConnectionsPerInstance must be set.\n\nThis cannot be used for internal load balancing.", + "format": "int32", + "type": "integer" + }, + "maxRate": { + "description": "The max requests per second (RPS) of the group. Can be used with either RATE or UTILIZATION balancing modes, but required if RATE mode. For RATE mode, either maxRate or maxRatePerInstance must be set.\n\nThis cannot be used for internal load balancing.", + "format": "int32", + "type": "integer" + }, + "maxRatePerInstance": { + "description": "The max requests per second (RPS) that a single backend instance can handle. This is used to calculate the capacity of the group. Can be used in either balancing mode. For RATE mode, either maxRate or maxRatePerInstance must be set.\n\nThis cannot be used for internal load balancing.", + "format": "float", + "type": "number" + }, + "maxUtilization": { + "description": "Used when balancingMode is UTILIZATION. This ratio defines the CPU utilization target for the group. The default is 0.8. Valid range is [0.0, 1.0].\n\nThis cannot be used for internal load balancing.", + "format": "float", + "type": "number" + } + }, + "type": "object" + }, + "BackendBucket": { + "description": "A BackendBucket resource. This resource defines a Cloud Storage bucket.", + "id": "BackendBucket", + "properties": { + "bucketName": { + "description": "Cloud Storage bucket name.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional textual description of the resource; provided by the client when the resource is created.", + "type": "string" + }, + "enableCdn": { + "description": "If true, enable Cloud CDN for this BackendBucket.", + "type": "boolean" + }, + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#backendBucket", + "description": "Type of the resource.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "BackendBucketList": { + "description": "Contains a list of BackendBucket resources.", + "id": "BackendBucketList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of BackendBucket resources.", + "items": { + "$ref": "BackendBucket" + }, + "type": "array" + }, + "kind": { + "default": "compute#backendBucketList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "BackendService": { + "description": "A BackendService resource. This resource defines a group of backend virtual machines and their serving capacity. (== resource_for v1.backendService ==) (== resource_for beta.backendService ==)", + "id": "BackendService", + "properties": { + "affinityCookieTtlSec": { + "description": "Lifetime of cookies in seconds if session_affinity is GENERATED_COOKIE. If set to 0, the cookie is non-persistent and lasts only until the end of the browser session (or equivalent). The maximum allowed value for TTL is one day.\n\nWhen the load balancing scheme is INTERNAL, this field is not used.", + "format": "int32", + "type": "integer" + }, + "backends": { + "description": "The list of backends that serve this BackendService.", + "items": { + "$ref": "Backend" + }, + "type": "array" + }, + "cdnPolicy": { + "$ref": "BackendServiceCdnPolicy", + "description": "Cloud CDN configuration for this BackendService." + }, + "connectionDraining": { + "$ref": "ConnectionDraining" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "enableCDN": { + "description": "If true, enable Cloud CDN for this BackendService.\n\nWhen the load balancing scheme is INTERNAL, this field is not used.", + "type": "boolean" + }, + "fingerprint": { + "description": "Fingerprint of this resource. A hash of the contents stored in this object. This field is used in optimistic locking. This field will be ignored when inserting a BackendService. An up-to-date fingerprint must be provided in order to update the BackendService.", + "format": "byte", + "type": "string" + }, + "healthChecks": { + "description": "The list of URLs to the HttpHealthCheck or HttpsHealthCheck resource for health checking this BackendService. Currently at most one health check can be specified, and a health check is required for Compute Engine backend services. A health check must not be specified for App Engine backend and Cloud Function backend.\n\nFor internal load balancing, a URL to a HealthCheck resource must be specified instead.", + "items": { + "type": "string" + }, + "type": "array" + }, + "iap": { + "$ref": "BackendServiceIAP" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#backendService", + "description": "[Output Only] Type of resource. Always compute#backendService for backend services.", + "type": "string" + }, + "loadBalancingScheme": { + "description": "Indicates whether the backend service will be used with internal or external load balancing. A backend service created for one type of load balancing cannot be used with the other. Possible values are INTERNAL and EXTERNAL.", + "enum": [ + "EXTERNAL", + "INTERNAL", + "INVALID_LOAD_BALANCING_SCHEME" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "port": { + "description": "Deprecated in favor of portName. The TCP port to connect on the backend. The default value is 80.\n\nThis cannot be used for internal load balancing.", + "format": "int32", + "type": "integer" + }, + "portName": { + "description": "Name of backend port. The same name should appear in the instance groups referenced by this service. Required when the load balancing scheme is EXTERNAL.\n\nWhen the load balancing scheme is INTERNAL, this field is not used.", + "type": "string" + }, + "protocol": { + "description": "The protocol this BackendService uses to communicate with backends.\n\nPossible values are HTTP, HTTPS, TCP, and SSL. The default is HTTP.\n\nFor internal load balancing, the possible values are TCP and UDP, and the default is TCP.", + "enum": [ + "HTTP", + "HTTPS", + "SSL", + "TCP", + "UDP" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the regional backend service resides. This field is not applicable to global backend services. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sessionAffinity": { + "description": "Type of session affinity to use. The default is NONE.\n\nWhen the load balancing scheme is EXTERNAL, can be NONE, CLIENT_IP, or GENERATED_COOKIE.\n\nWhen the load balancing scheme is INTERNAL, can be NONE, CLIENT_IP, CLIENT_IP_PROTO, or CLIENT_IP_PORT_PROTO.\n\nWhen the protocol is UDP, this field is not used.", + "enum": [ + "CLIENT_IP", + "CLIENT_IP_PORT_PROTO", + "CLIENT_IP_PROTO", + "GENERATED_COOKIE", + "NONE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "timeoutSec": { + "description": "How many seconds to wait for the backend before considering it a failed request. Default is 30 seconds.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "BackendServiceAggregatedList": { + "description": "Contains a list of BackendServicesScopedList.", + "id": "BackendServiceAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "BackendServicesScopedList", + "description": "Name of the scope containing this set of BackendServices." + }, + "description": "A list of BackendServicesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#backendServiceAggregatedList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "BackendServiceCdnPolicy": { + "description": "Message containing Cloud CDN configuration for a backend service.", + "id": "BackendServiceCdnPolicy", + "properties": { + "cacheKeyPolicy": { + "$ref": "CacheKeyPolicy", + "description": "The CacheKeyPolicy for this CdnPolicy." + } + }, + "type": "object" + }, + "BackendServiceGroupHealth": { + "id": "BackendServiceGroupHealth", + "properties": { + "healthStatus": { + "items": { + "$ref": "HealthStatus" + }, + "type": "array" + }, + "kind": { + "default": "compute#backendServiceGroupHealth", + "description": "[Output Only] Type of resource. Always compute#backendServiceGroupHealth for the health of backend services.", + "type": "string" + } + }, + "type": "object" + }, + "BackendServiceIAP": { + "description": "Identity-Aware Proxy", + "id": "BackendServiceIAP", + "properties": { + "enabled": { + "type": "boolean" + }, + "oauth2ClientId": { + "type": "string" + }, + "oauth2ClientSecret": { + "type": "string" + }, + "oauth2ClientSecretSha256": { + "description": "[Output Only] SHA256 hash value for the field oauth2_client_secret above.", + "type": "string" + } + }, + "type": "object" + }, + "BackendServiceList": { + "description": "Contains a list of BackendService resources.", + "id": "BackendServiceList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of BackendService resources.", + "items": { + "$ref": "BackendService" + }, + "type": "array" + }, + "kind": { + "default": "compute#backendServiceList", + "description": "[Output Only] Type of resource. Always compute#backendServiceList for lists of backend services.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "BackendServicesScopedList": { + "id": "BackendServicesScopedList", + "properties": { + "backendServices": { + "description": "A list of BackendServices contained in this scope.", + "items": { + "$ref": "BackendService" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of backend services when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CacheInvalidationRule": { + "id": "CacheInvalidationRule", + "properties": { + "host": { + "description": "If set, this invalidation rule will only apply to requests with a Host header matching host.", + "type": "string" + }, + "path": { + "type": "string" + } + }, + "type": "object" + }, + "CacheKeyPolicy": { + "description": "Message containing what to include in the cache key for a request for Cloud CDN.", + "id": "CacheKeyPolicy", + "properties": { + "includeHost": { + "description": "If true, requests to different hosts will be cached separately.", + "type": "boolean" + }, + "includeProtocol": { + "description": "If true, http and https requests will be cached separately.", + "type": "boolean" + }, + "includeQueryString": { + "description": "If true, include query string parameters in the cache key according to query_string_whitelist and query_string_blacklist. If neither is set, the entire query string will be included. If false, the query string will be excluded from the cache key entirely.", + "type": "boolean" + }, + "queryStringBlacklist": { + "description": "Names of query string parameters to exclude in cache keys. All other parameters will be included. Either specify query_string_whitelist or query_string_blacklist, not both. '\u0026' and '=' will be percent encoded and not treated as delimiters.", + "items": { + "type": "string" + }, + "type": "array" + }, + "queryStringWhitelist": { + "description": "Names of query string parameters to include in cache keys. All other parameters will be excluded. Either specify query_string_whitelist or query_string_blacklist, not both. '\u0026' and '=' will be percent encoded and not treated as delimiters.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "Commitment": { + "description": "Represents a Commitment resource. Creating a Commitment resource means that you are purchasing a committed use contract with an explicit start and end time. You can create commitments based on vCPUs and memory usage and receive discounted rates. For full details, read Signing Up for Committed Use Discounts.\n\nCommitted use discounts are subject to Google Cloud Platform's Service Specific Terms. By purchasing a committed use discount, you agree to these terms. Committed use discounts will not renew, so you must purchase a new commitment to continue receiving discounts. (== resource_for beta.commitments ==) (== resource_for v1.commitments ==)", + "id": "Commitment", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "endTimestamp": { + "description": "[Output Only] Commitment end time in RFC3339 text format.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#commitment", + "description": "[Output Only] Type of the resource. Always compute#commitment for commitments.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "plan": { + "description": "The plan for this commitment, which determines duration and discount rate. The currently supported plans are TWELVE_MONTH (1 year), and THIRTY_SIX_MONTH (3 years).", + "enum": [ + "INVALID", + "THIRTY_SIX_MONTH", + "TWELVE_MONTH" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where this commitment may be used.", + "type": "string" + }, + "resources": { + "description": "A list of commitment amounts for particular resources. Note that VCPU and MEMORY resource commitments must occur together.", + "items": { + "$ref": "ResourceCommitment" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "startTimestamp": { + "description": "[Output Only] Commitment start time in RFC3339 text format.", + "type": "string" + }, + "status": { + "description": "[Output Only] Status of the commitment with regards to eventual expiration (each commitment has an end date defined). One of the following values: NOT_YET_ACTIVE, ACTIVE, EXPIRED.", + "enum": [ + "ACTIVE", + "CREATING", + "EXPIRED", + "NOT_YET_ACTIVE" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "statusMessage": { + "description": "[Output Only] An optional, human-readable explanation of the status.", + "type": "string" + } + }, + "type": "object" + }, + "CommitmentAggregatedList": { + "id": "CommitmentAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "CommitmentsScopedList", + "description": "[Output Only] Name of the scope containing this set of commitments." + }, + "description": "A list of CommitmentsScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#commitmentAggregatedList", + "description": "[Output Only] Type of resource. Always compute#commitmentAggregatedList for aggregated lists of commitments.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CommitmentList": { + "description": "Contains a list of Commitment resources.", + "id": "CommitmentList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Commitment resources.", + "items": { + "$ref": "Commitment" + }, + "type": "array" + }, + "kind": { + "default": "compute#commitmentList", + "description": "[Output Only] Type of resource. Always compute#commitmentList for lists of commitments.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "CommitmentsScopedList": { + "id": "CommitmentsScopedList", + "properties": { + "commitments": { + "description": "[Output Only] A list of commitments contained in this scope.", + "items": { + "$ref": "Commitment" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of commitments when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ConnectionDraining": { + "description": "Message containing connection draining configuration.", + "id": "ConnectionDraining", + "properties": { + "drainingTimeoutSec": { + "description": "Time for which instance will be drained (not accept new connections, but still work to finish started).", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "CustomerEncryptionKey": { + "description": "Represents a customer-supplied encryption key", + "id": "CustomerEncryptionKey", + "properties": { + "rawKey": { + "description": "Specifies a 256-bit customer-supplied encryption key, encoded in RFC 4648 base64 to either encrypt or decrypt this resource.", + "type": "string" + }, + "sha256": { + "description": "[Output only] The RFC 4648 base64 encoded SHA-256 hash of the customer-supplied encryption key that protects this resource.", + "type": "string" + } + }, + "type": "object" + }, + "CustomerEncryptionKeyProtectedDisk": { + "id": "CustomerEncryptionKeyProtectedDisk", + "properties": { + "diskEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "Decrypts data associated with the disk with a customer-supplied encryption key." + }, + "source": { + "description": "Specifies a valid partial or full URL to an existing Persistent Disk resource. This field is only applicable for persistent disks.", + "type": "string" + } + }, + "type": "object" + }, + "DeprecationStatus": { + "description": "Deprecation status for a public resource.", + "id": "DeprecationStatus", + "properties": { + "deleted": { + "description": "An optional RFC3339 timestamp on or after which the state of this resource is intended to change to DELETED. This is only informational and the status will not change unless the client explicitly changes it.", + "type": "string" + }, + "deprecated": { + "description": "An optional RFC3339 timestamp on or after which the state of this resource is intended to change to DEPRECATED. This is only informational and the status will not change unless the client explicitly changes it.", + "type": "string" + }, + "obsolete": { + "description": "An optional RFC3339 timestamp on or after which the state of this resource is intended to change to OBSOLETE. This is only informational and the status will not change unless the client explicitly changes it.", + "type": "string" + }, + "replacement": { + "description": "The URL of the suggested replacement for a deprecated resource. The suggested replacement resource must be the same kind of resource as the deprecated resource.", + "type": "string" + }, + "state": { + "description": "The deprecation state of this resource. This can be DEPRECATED, OBSOLETE, or DELETED. Operations which create a new resource using a DEPRECATED resource will return successfully, but with a warning indicating the deprecated resource and recommending its replacement. Operations which use OBSOLETE or DELETED resources will be rejected and result in an error.", + "enum": [ + "DELETED", + "DEPRECATED", + "OBSOLETE" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "Disk": { + "description": "A Disk resource. (== resource_for beta.disks ==) (== resource_for v1.disks ==)", + "id": "Disk", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "diskEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "Encrypts the disk using a customer-supplied encryption key.\n\nAfter you encrypt a disk with a customer-supplied key, you must provide the same key if you use the disk later (e.g. to create a disk snapshot or an image, or to attach the disk to a virtual machine).\n\nCustomer-supplied encryption keys do not protect access to metadata of the disk.\n\nIf you do not provide an encryption key when creating the disk, then the disk will be encrypted using an automatically generated key and you do not need to provide a key to use the disk later." + }, + "guestOsFeatures": { + "description": "A list of features to enable on the guest operating system. Applicable only for bootable images. Read Enabling guest operating system features to see a list of available options.", + "items": { + "$ref": "GuestOsFeature" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#disk", + "description": "[Output Only] Type of the resource. Always compute#disk for disks.", + "type": "string" + }, + "labelFingerprint": { + "description": "A fingerprint for the labels being applied to this disk, which is essentially a hash of the labels set used for optimistic locking. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash in order to update or change labels.\n\nTo see the latest fingerprint, make a get() request to retrieve a disk.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels to apply to this disk. These can be later modified by the setLabels method.", + "type": "object" + }, + "lastAttachTimestamp": { + "description": "[Output Only] Last attach timestamp in RFC3339 text format.", + "type": "string" + }, + "lastDetachTimestamp": { + "description": "[Output Only] Last detach timestamp in RFC3339 text format.", + "type": "string" + }, + "licenseCodes": { + "description": "Integer license codes indicating which licenses are attached to this disk.", + "items": { + "format": "int64", + "type": "string" + }, + "type": "array" + }, + "licenses": { + "description": "Any applicable publicly visible licenses.", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "annotations": { + "required": [ + "compute.disks.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "options": { + "description": "Internal use only.", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the disk resides. Only applicable for regional resources. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "replicaZones": { + "description": "URLs of the zones where the disk should be replicated to. Only applicable for regional resources.", + "items": { + "type": "string" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined fully-qualified URL for this resource.", + "type": "string" + }, + "sizeGb": { + "description": "Size of the persistent disk, specified in GB. You can specify this field when creating a persistent disk using the sourceImage or sourceSnapshot parameter, or specify it alone to create an empty persistent disk.\n\nIf you specify this field along with sourceImage or sourceSnapshot, the value of sizeGb must not be less than the size of the sourceImage or the size of the snapshot. Acceptable values are 1 to 65536, inclusive.", + "format": "int64", + "type": "string" + }, + "sourceImage": { + "description": "The source image used to create this disk. If the source image is deleted, this field will not be set.\n\nTo create a disk with one of the public operating system images, specify the image by its family name. For example, specify family/debian-8 to use the latest Debian 8 image:\nprojects/debian-cloud/global/images/family/debian-8\n\n\nAlternatively, use a specific version of a public operating system image:\nprojects/debian-cloud/global/images/debian-8-jessie-vYYYYMMDD\n\n\nTo create a disk with a custom image that you created, specify the image name in the following format:\nglobal/images/my-custom-image\n\n\nYou can also specify a custom image by its image family, which returns the latest version of the image in that family. Replace the image name with family/family-name:\nglobal/images/family/my-image-family", + "type": "string" + }, + "sourceImageEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source image. Required if the source image is protected by a customer-supplied encryption key." + }, + "sourceImageId": { + "description": "[Output Only] The ID value of the image used to create this disk. This value identifies the exact image that was used to create this persistent disk. For example, if you created the persistent disk from an image that was later deleted and recreated under the same name, the source image ID would identify the exact version of the image that was used.", + "type": "string" + }, + "sourceSnapshot": { + "description": "The source snapshot used to create this disk. You can provide this as a partial or full URL to the resource. For example, the following are valid values: \n- https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot \n- projects/project/global/snapshots/snapshot \n- global/snapshots/snapshot", + "type": "string" + }, + "sourceSnapshotEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source snapshot. Required if the source snapshot is protected by a customer-supplied encryption key." + }, + "sourceSnapshotId": { + "description": "[Output Only] The unique ID of the snapshot used to create this disk. This value identifies the exact snapshot that was used to create this persistent disk. For example, if you created the persistent disk from a snapshot that was later deleted and recreated under the same name, the source snapshot ID would identify the exact version of the snapshot that was used.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of disk creation.", + "enum": [ + "CREATING", + "FAILED", + "READY", + "RESTORING" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "type": { + "description": "URL of the disk type resource describing which disk type to use to create the disk. Provide this when creating the disk. For example: project/zones/zone/diskTypes/pd-standard or pd-ssd", + "type": "string" + }, + "users": { + "description": "[Output Only] Links to the users of the disk (attached instances) in form: project/zones/zone/instances/instance", + "items": { + "type": "string" + }, + "type": "array" + }, + "zone": { + "description": "[Output Only] URL of the zone where the disk resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + } + }, + "type": "object" + }, + "DiskAggregatedList": { + "id": "DiskAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "DisksScopedList", + "description": "[Output Only] Name of the scope containing this set of disks." + }, + "description": "A list of DisksScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#diskAggregatedList", + "description": "[Output Only] Type of resource. Always compute#diskAggregatedList for aggregated lists of persistent disks.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DiskList": { + "description": "A list of Disk resources.", + "id": "DiskList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Disk resources.", + "items": { + "$ref": "Disk" + }, + "type": "array" + }, + "kind": { + "default": "compute#diskList", + "description": "[Output Only] Type of resource. Always compute#diskList for lists of disks.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DiskMoveRequest": { + "id": "DiskMoveRequest", + "properties": { + "destinationZone": { + "description": "The URL of the destination zone to move the disk. This can be a full or partial URL. For example, the following are all valid URLs to a zone: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone \n- projects/project/zones/zone \n- zones/zone", + "type": "string" + }, + "targetDisk": { + "description": "The URL of the target disk to move. This can be a full or partial URL. For example, the following are all valid URLs to a disk: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/disks/disk \n- projects/project/zones/zone/disks/disk \n- zones/zone/disks/disk", + "type": "string" + } + }, + "type": "object" + }, + "DiskType": { + "description": "A DiskType resource. (== resource_for beta.diskTypes ==) (== resource_for v1.diskTypes ==)", + "id": "DiskType", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "defaultDiskSizeGb": { + "description": "[Output Only] Server-defined default disk size in GB.", + "format": "int64", + "type": "string" + }, + "deprecated": { + "$ref": "DeprecationStatus", + "description": "[Output Only] The deprecation status associated with this disk type." + }, + "description": { + "description": "[Output Only] An optional description of this resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#diskType", + "description": "[Output Only] Type of the resource. Always compute#diskType for disk types.", + "type": "string" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the disk type resides. Only applicable for regional resources. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "validDiskSize": { + "description": "[Output Only] An optional textual description of the valid disk size, such as \"10GB-10TB\".", + "type": "string" + }, + "zone": { + "description": "[Output Only] URL of the zone where the disk type resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + } + }, + "type": "object" + }, + "DiskTypeAggregatedList": { + "id": "DiskTypeAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "DiskTypesScopedList", + "description": "[Output Only] Name of the scope containing this set of disk types." + }, + "description": "A list of DiskTypesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#diskTypeAggregatedList", + "description": "[Output Only] Type of resource. Always compute#diskTypeAggregatedList.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DiskTypeList": { + "description": "Contains a list of disk types.", + "id": "DiskTypeList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of DiskType resources.", + "items": { + "$ref": "DiskType" + }, + "type": "array" + }, + "kind": { + "default": "compute#diskTypeList", + "description": "[Output Only] Type of resource. Always compute#diskTypeList for disk types.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DiskTypesScopedList": { + "id": "DiskTypesScopedList", + "properties": { + "diskTypes": { + "description": "[Output Only] A list of disk types contained in this scope.", + "items": { + "$ref": "DiskType" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of disk types when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "DisksResizeRequest": { + "id": "DisksResizeRequest", + "properties": { + "sizeGb": { + "description": "The new size of the persistent disk, which is specified in GB.", + "format": "int64", + "type": "string" + } + }, + "type": "object" + }, + "DisksScopedList": { + "id": "DisksScopedList", + "properties": { + "disks": { + "description": "[Output Only] A list of disks contained in this scope.", + "items": { + "$ref": "Disk" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of disks when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Firewall": { + "description": "Represents a Firewall resource.", + "id": "Firewall", + "properties": { + "allowed": { + "description": "The list of ALLOW rules specified by this firewall. Each rule specifies a protocol and port-range tuple that describes a permitted connection.", + "items": { + "properties": { + "IPProtocol": { + "description": "The IP protocol to which this rule applies. The protocol type is required when creating a firewall rule. This value can either be one of the following well known protocol strings (tcp, udp, icmp, esp, ah, ipip, sctp), or the IP protocol number.", + "type": "string" + }, + "ports": { + "description": "An optional list of ports to which this rule applies. This field is only applicable for UDP or TCP protocol. Each entry must be either an integer or a range. If not specified, this rule applies to connections through any port.\n\nExample inputs include: [\"22\"], [\"80\",\"443\"], and [\"12345-12349\"].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "denied": { + "description": "The list of DENY rules specified by this firewall. Each rule specifies a protocol and port-range tuple that describes a denied connection.", + "items": { + "properties": { + "IPProtocol": { + "description": "The IP protocol to which this rule applies. The protocol type is required when creating a firewall rule. This value can either be one of the following well known protocol strings (tcp, udp, icmp, esp, ah, ipip, sctp), or the IP protocol number.", + "type": "string" + }, + "ports": { + "description": "An optional list of ports to which this rule applies. This field is only applicable for UDP or TCP protocol. Each entry must be either an integer or a range. If not specified, this rule applies to connections through any port.\n\nExample inputs include: [\"22\"], [\"80\",\"443\"], and [\"12345-12349\"].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "destinationRanges": { + "description": "If destination ranges are specified, the firewall will apply only to traffic that has destination IP address in these ranges. These ranges must be expressed in CIDR format. Only IPv4 is supported.", + "items": { + "type": "string" + }, + "type": "array" + }, + "direction": { + "description": "Direction of traffic to which this firewall applies; default is INGRESS. Note: For INGRESS traffic, it is NOT supported to specify destinationRanges; For EGRESS traffic, it is NOT supported to specify sourceRanges OR sourceTags.", + "enum": [ + "EGRESS", + "INGRESS" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#firewall", + "description": "[Output Only] Type of the resource. Always compute#firewall for firewall rules.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.firewalls.insert", + "compute.firewalls.patch" + ] + }, + "description": "Name of the resource; provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "network": { + "description": "URL of the network resource for this firewall rule. If not specified when creating a firewall rule, the default network is used:\nglobal/networks/default\nIf you choose to specify this property, you can specify the network as a full or partial URL. For example, the following are all valid URLs: \n- https://www.googleapis.com/compute/v1/projects/myproject/global/networks/my-network \n- projects/myproject/global/networks/my-network \n- global/networks/default", + "type": "string" + }, + "priority": { + "description": "Priority for this rule. This is an integer between 0 and 65535, both inclusive. When not specified, the value assumed is 1000. Relative priorities determine precedence of conflicting rules. Lower value of priority implies higher precedence (eg, a rule with priority 0 has higher precedence than a rule with priority 1). DENY rules take precedence over ALLOW rules having equal priority.", + "format": "int32", + "type": "integer" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sourceRanges": { + "description": "If source ranges are specified, the firewall will apply only to traffic that has source IP address in these ranges. These ranges must be expressed in CIDR format. One or both of sourceRanges and sourceTags may be set. If both properties are set, the firewall will apply to traffic that has source IP address within sourceRanges OR the source IP that belongs to a tag listed in the sourceTags property. The connection does not need to match both properties for the firewall to apply. Only IPv4 is supported.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sourceServiceAccounts": { + "description": "If source service accounts are specified, the firewall will apply only to traffic originating from an instance with a service account in this list. Source service accounts cannot be used to control traffic to an instance's external IP address because service accounts are associated with an instance, not an IP address. sourceRanges can be set at the same time as sourceServiceAccounts. If both are set, the firewall will apply to traffic that has source IP address within sourceRanges OR the source IP belongs to an instance with service account listed in sourceServiceAccount. The connection does not need to match both properties for the firewall to apply. sourceServiceAccounts cannot be used at the same time as sourceTags or targetTags.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sourceTags": { + "description": "If source tags are specified, the firewall rule applies only to traffic with source IPs that match the primary network interfaces of VM instances that have the tag and are in the same VPC network. Source tags cannot be used to control traffic to an instance's external IP address, it only applies to traffic between instances in the same virtual network. Because tags are associated with instances, not IP addresses. One or both of sourceRanges and sourceTags may be set. If both properties are set, the firewall will apply to traffic that has source IP address within sourceRanges OR the source IP that belongs to a tag listed in the sourceTags property. The connection does not need to match both properties for the firewall to apply.", + "items": { + "type": "string" + }, + "type": "array" + }, + "targetServiceAccounts": { + "description": "A list of service accounts indicating sets of instances located in the network that may make network connections as specified in allowed[]. targetServiceAccounts cannot be used at the same time as targetTags or sourceTags. If neither targetServiceAccounts nor targetTags are specified, the firewall rule applies to all instances on the specified network.", + "items": { + "type": "string" + }, + "type": "array" + }, + "targetTags": { + "description": "A list of tags that controls which instances the firewall rule applies to. If targetTags are specified, then the firewall rule applies only to instances in the VPC network that have one of those tags. If no targetTags are specified, the firewall rule applies to all instances on the specified network.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "FirewallList": { + "description": "Contains a list of firewalls.", + "id": "FirewallList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Firewall resources.", + "items": { + "$ref": "Firewall" + }, + "type": "array" + }, + "kind": { + "default": "compute#firewallList", + "description": "[Output Only] Type of resource. Always compute#firewallList for lists of firewalls.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ForwardingRule": { + "description": "A ForwardingRule resource. A ForwardingRule resource specifies which pool of target virtual machines to forward a packet to if it matches the given [IPAddress, IPProtocol, ports] tuple. (== resource_for beta.forwardingRules ==) (== resource_for v1.forwardingRules ==) (== resource_for beta.globalForwardingRules ==) (== resource_for v1.globalForwardingRules ==) (== resource_for beta.regionForwardingRules ==) (== resource_for v1.regionForwardingRules ==)", + "id": "ForwardingRule", + "properties": { + "IPAddress": { + "description": "The IP address that this forwarding rule is serving on behalf of.\n\nAddresses are restricted based on the forwarding rule's load balancing scheme (EXTERNAL or INTERNAL) and scope (global or regional).\n\nWhen the load balancing scheme is EXTERNAL, for global forwarding rules, the address must be a global IP, and for regional forwarding rules, the address must live in the same region as the forwarding rule. If this field is empty, an ephemeral IPv4 address from the same scope (global or regional) will be assigned. A regional forwarding rule supports IPv4 only. A global forwarding rule supports either IPv4 or IPv6.\n\nWhen the load balancing scheme is INTERNAL, this can only be an RFC 1918 IP address belonging to the network/subnet configured for the forwarding rule. By default, if this field is empty, an ephemeral internal IP address will be automatically allocated from the IP range of the subnet or network configured for this forwarding rule.\n\nAn address can be specified either by a literal IP address or a URL reference to an existing Address resource. The following examples are all valid: \n- 100.1.2.3 \n- https://www.googleapis.com/compute/v1/projects/project/regions/region/addresses/address \n- projects/project/regions/region/addresses/address \n- regions/region/addresses/address \n- global/addresses/address \n- address", + "type": "string" + }, + "IPProtocol": { + "description": "The IP protocol to which this rule applies. Valid options are TCP, UDP, ESP, AH, SCTP or ICMP.\n\nWhen the load balancing scheme is INTERNAL, only TCP and UDP are valid.", + "enum": [ + "AH", + "ESP", + "ICMP", + "SCTP", + "TCP", + "UDP" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "backendService": { + "description": "This field is not used for external load balancing.\n\nFor internal load balancing, this field identifies the BackendService resource to receive the matched traffic.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "ipVersion": { + "description": "The IP Version that will be used by this forwarding rule. Valid options are IPV4 or IPV6. This can only be specified for a global forwarding rule.", + "enum": [ + "IPV4", + "IPV6", + "UNSPECIFIED_VERSION" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "kind": { + "default": "compute#forwardingRule", + "description": "[Output Only] Type of the resource. Always compute#forwardingRule for Forwarding Rule resources.", + "type": "string" + }, + "loadBalancingScheme": { + "description": "This signifies what the ForwardingRule will be used for and can only take the following values: INTERNAL, EXTERNAL The value of INTERNAL means that this will be used for Internal Network Load Balancing (TCP, UDP). The value of EXTERNAL means that this will be used for External Load Balancing (HTTP(S) LB, External TCP/UDP LB, SSL Proxy)", + "enum": [ + "EXTERNAL", + "INTERNAL", + "INVALID" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "name": { + "description": "Name of the resource; provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "network": { + "description": "This field is not used for external load balancing.\n\nFor internal load balancing, this field identifies the network that the load balanced IP should belong to for this Forwarding Rule. If this field is not specified, the default network will be used.", + "type": "string" + }, + "portRange": { + "description": "This field is used along with the target field for TargetHttpProxy, TargetHttpsProxy, TargetSslProxy, TargetTcpProxy, TargetVpnGateway, TargetPool, TargetInstance.\n\nApplicable only when IPProtocol is TCP, UDP, or SCTP, only packets addressed to ports in the specified range will be forwarded to target. Forwarding rules with the same [IPAddress, IPProtocol] pair must have disjoint port ranges.\n\nSome types of forwarding target have constraints on the acceptable ports: \n- TargetHttpProxy: 80, 8080 \n- TargetHttpsProxy: 443 \n- TargetTcpProxy: 25, 43, 110, 143, 195, 443, 465, 587, 700, 993, 995, 1688, 1883, 5222 \n- TargetSslProxy: 25, 43, 110, 143, 195, 443, 465, 587, 700, 993, 995, 1688, 1883, 5222 \n- TargetVpnGateway: 500, 4500", + "type": "string" + }, + "ports": { + "description": "This field is used along with the backend_service field for internal load balancing.\n\nWhen the load balancing scheme is INTERNAL, a single port or a comma separated list of ports can be configured. Only packets addressed to these ports will be forwarded to the backends configured with this forwarding rule.\n\nYou may specify a maximum of up to 5 ports.", + "items": { + "type": "string" + }, + "type": "array" + }, + "region": { + "description": "[Output Only] URL of the region where the regional forwarding rule resides. This field is not applicable to global forwarding rules. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "subnetwork": { + "description": "This field is not used for external load balancing.\n\nFor internal load balancing, this field identifies the subnetwork that the load balanced IP should belong to for this Forwarding Rule.\n\nIf the network specified is in auto subnet mode, this field is optional. However, if the network is in custom subnet mode, a subnetwork must be specified.", + "type": "string" + }, + "target": { + "description": "The URL of the target resource to receive the matched traffic. For regional forwarding rules, this target must live in the same region as the forwarding rule. For global forwarding rules, this target must be a global load balancing resource. The forwarded traffic must be of a type appropriate to the target object.", + "type": "string" + } + }, + "type": "object" + }, + "ForwardingRuleAggregatedList": { + "id": "ForwardingRuleAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "ForwardingRulesScopedList", + "description": "Name of the scope containing this set of addresses." + }, + "description": "A list of ForwardingRulesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#forwardingRuleAggregatedList", + "description": "[Output Only] Type of resource. Always compute#forwardingRuleAggregatedList for lists of forwarding rules.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ForwardingRuleList": { + "description": "Contains a list of ForwardingRule resources.", + "id": "ForwardingRuleList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of ForwardingRule resources.", + "items": { + "$ref": "ForwardingRule" + }, + "type": "array" + }, + "kind": { + "default": "compute#forwardingRuleList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ForwardingRulesScopedList": { + "id": "ForwardingRulesScopedList", + "properties": { + "forwardingRules": { + "description": "A list of forwarding rules contained in this scope.", + "items": { + "$ref": "ForwardingRule" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of forwarding rules when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "GlobalSetLabelsRequest": { + "id": "GlobalSetLabelsRequest", + "properties": { + "labelFingerprint": { + "description": "The fingerprint of the previous set of labels for this resource, used to detect conflicts. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash when updating or changing labels. Make a get() request to the resource to get the latest fingerprint.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "A list of labels to apply for this resource. Each label key \u0026 value must comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash. For example, \"webserver-frontend\": \"images\". A label value can also be empty (e.g. \"my-label\": \"\").", + "type": "object" + } + }, + "type": "object" + }, + "GuestOsFeature": { + "description": "Guest OS features.", + "id": "GuestOsFeature", + "properties": { + "type": { + "description": "The ID of a supported feature. Read Enabling guest operating system features to see a list of available options.", + "enum": [ + "FEATURE_TYPE_UNSPECIFIED", + "MULTI_IP_SUBNET", + "SECURE_BOOT", + "UEFI_COMPATIBLE", + "VIRTIO_SCSI_MULTIQUEUE", + "WINDOWS" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "HTTPHealthCheck": { + "id": "HTTPHealthCheck", + "properties": { + "host": { + "description": "The value of the host header in the HTTP health check request. If left empty (default value), the IP on behalf of which this health check is performed will be used.", + "type": "string" + }, + "port": { + "description": "The TCP port number for the health check request. The default value is 80. Valid values are 1 through 65535.", + "format": "int32", + "type": "integer" + }, + "portName": { + "description": "Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name are defined, port takes precedence.", + "type": "string" + }, + "proxyHeader": { + "description": "Specifies the type of proxy header to append before sending data to the backend, either NONE or PROXY_V1. The default is NONE.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "requestPath": { + "description": "The request path of the HTTP health check request. The default value is /.", + "type": "string" + } + }, + "type": "object" + }, + "HTTPSHealthCheck": { + "id": "HTTPSHealthCheck", + "properties": { + "host": { + "description": "The value of the host header in the HTTPS health check request. If left empty (default value), the IP on behalf of which this health check is performed will be used.", + "type": "string" + }, + "port": { + "description": "The TCP port number for the health check request. The default value is 443. Valid values are 1 through 65535.", + "format": "int32", + "type": "integer" + }, + "portName": { + "description": "Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name are defined, port takes precedence.", + "type": "string" + }, + "proxyHeader": { + "description": "Specifies the type of proxy header to append before sending data to the backend, either NONE or PROXY_V1. The default is NONE.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "requestPath": { + "description": "The request path of the HTTPS health check request. The default value is /.", + "type": "string" + } + }, + "type": "object" + }, + "HealthCheck": { + "description": "An HealthCheck resource. This resource defines a template for how individual virtual machines should be checked for health, via one of the supported protocols.", + "id": "HealthCheck", + "properties": { + "checkIntervalSec": { + "description": "How often (in seconds) to send a health check. The default value is 5 seconds.", + "format": "int32", + "type": "integer" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in 3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "healthyThreshold": { + "description": "A so-far unhealthy instance will be marked healthy after this many consecutive successes. The default value is 2.", + "format": "int32", + "type": "integer" + }, + "httpHealthCheck": { + "$ref": "HTTPHealthCheck" + }, + "httpsHealthCheck": { + "$ref": "HTTPSHealthCheck" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#healthCheck", + "description": "Type of the resource.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sslHealthCheck": { + "$ref": "SSLHealthCheck" + }, + "tcpHealthCheck": { + "$ref": "TCPHealthCheck" + }, + "timeoutSec": { + "description": "How long (in seconds) to wait before claiming failure. The default value is 5 seconds. It is invalid for timeoutSec to have greater value than checkIntervalSec.", + "format": "int32", + "type": "integer" + }, + "type": { + "description": "Specifies the type of the healthCheck, either TCP, SSL, HTTP or HTTPS. If not specified, the default is TCP. Exactly one of the protocol-specific health check field must be specified, which must match type field.", + "enum": [ + "HTTP", + "HTTPS", + "INVALID", + "SSL", + "TCP" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "unhealthyThreshold": { + "description": "A so-far healthy instance will be marked unhealthy after this many consecutive failures. The default value is 2.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "HealthCheckList": { + "description": "Contains a list of HealthCheck resources.", + "id": "HealthCheckList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of HealthCheck resources.", + "items": { + "$ref": "HealthCheck" + }, + "type": "array" + }, + "kind": { + "default": "compute#healthCheckList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "HealthCheckReference": { + "description": "A full or valid partial URL to a health check. For example, the following are valid URLs: \n- https://www.googleapis.com/compute/beta/projects/project-id/global/httpHealthChecks/health-check \n- projects/project-id/global/httpHealthChecks/health-check \n- global/httpHealthChecks/health-check", + "id": "HealthCheckReference", + "properties": { + "healthCheck": { + "type": "string" + } + }, + "type": "object" + }, + "HealthStatus": { + "id": "HealthStatus", + "properties": { + "healthState": { + "description": "Health state of the instance.", + "enum": [ + "HEALTHY", + "UNHEALTHY" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "instance": { + "description": "URL of the instance resource.", + "type": "string" + }, + "ipAddress": { + "description": "The IP address represented by this resource.", + "type": "string" + }, + "port": { + "description": "The port on the instance.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "HostRule": { + "description": "UrlMaps A host-matching rule for a URL. If matched, will use the named PathMatcher to select the BackendService.", + "id": "HostRule", + "properties": { + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "hosts": { + "description": "The list of host patterns to match. They must be valid hostnames, except * will match any string of ([a-z0-9-.]*). In that case, * must be the first character and must be followed in the pattern by either - or ..", + "items": { + "type": "string" + }, + "type": "array" + }, + "pathMatcher": { + "description": "The name of the PathMatcher to use to match the path portion of the URL if the hostRule matches the URL's host portion.", + "type": "string" + } + }, + "type": "object" + }, + "HttpHealthCheck": { + "description": "An HttpHealthCheck resource. This resource defines a template for how individual instances should be checked for health, via HTTP.", + "id": "HttpHealthCheck", + "properties": { + "checkIntervalSec": { + "description": "How often (in seconds) to send a health check. The default value is 5 seconds.", + "format": "int32", + "type": "integer" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "healthyThreshold": { + "description": "A so-far unhealthy instance will be marked healthy after this many consecutive successes. The default value is 2.", + "format": "int32", + "type": "integer" + }, + "host": { + "description": "The value of the host header in the HTTP health check request. If left empty (default value), the public IP on behalf of which this health check is performed will be used.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#httpHealthCheck", + "description": "[Output Only] Type of the resource. Always compute#httpHealthCheck for HTTP health checks.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "port": { + "description": "The TCP port number for the HTTP health check request. The default value is 80.", + "format": "int32", + "type": "integer" + }, + "requestPath": { + "description": "The request path of the HTTP health check request. The default value is /.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "timeoutSec": { + "description": "How long (in seconds) to wait before claiming failure. The default value is 5 seconds. It is invalid for timeoutSec to have greater value than checkIntervalSec.", + "format": "int32", + "type": "integer" + }, + "unhealthyThreshold": { + "description": "A so-far healthy instance will be marked unhealthy after this many consecutive failures. The default value is 2.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "HttpHealthCheckList": { + "description": "Contains a list of HttpHealthCheck resources.", + "id": "HttpHealthCheckList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of HttpHealthCheck resources.", + "items": { + "$ref": "HttpHealthCheck" + }, + "type": "array" + }, + "kind": { + "default": "compute#httpHealthCheckList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "HttpsHealthCheck": { + "description": "An HttpsHealthCheck resource. This resource defines a template for how individual instances should be checked for health, via HTTPS.", + "id": "HttpsHealthCheck", + "properties": { + "checkIntervalSec": { + "description": "How often (in seconds) to send a health check. The default value is 5 seconds.", + "format": "int32", + "type": "integer" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "healthyThreshold": { + "description": "A so-far unhealthy instance will be marked healthy after this many consecutive successes. The default value is 2.", + "format": "int32", + "type": "integer" + }, + "host": { + "description": "The value of the host header in the HTTPS health check request. If left empty (default value), the public IP on behalf of which this health check is performed will be used.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#httpsHealthCheck", + "description": "Type of the resource.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "port": { + "description": "The TCP port number for the HTTPS health check request. The default value is 443.", + "format": "int32", + "type": "integer" + }, + "requestPath": { + "description": "The request path of the HTTPS health check request. The default value is \"/\".", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "timeoutSec": { + "description": "How long (in seconds) to wait before claiming failure. The default value is 5 seconds. It is invalid for timeoutSec to have a greater value than checkIntervalSec.", + "format": "int32", + "type": "integer" + }, + "unhealthyThreshold": { + "description": "A so-far healthy instance will be marked unhealthy after this many consecutive failures. The default value is 2.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "HttpsHealthCheckList": { + "description": "Contains a list of HttpsHealthCheck resources.", + "id": "HttpsHealthCheckList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of HttpsHealthCheck resources.", + "items": { + "$ref": "HttpsHealthCheck" + }, + "type": "array" + }, + "kind": { + "default": "compute#httpsHealthCheckList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Image": { + "description": "An Image resource. (== resource_for beta.images ==) (== resource_for v1.images ==)", + "id": "Image", + "properties": { + "archiveSizeBytes": { + "description": "Size of the image tar.gz archive stored in Google Cloud Storage (in bytes).", + "format": "int64", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "deprecated": { + "$ref": "DeprecationStatus", + "description": "The deprecation status associated with this image." + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "diskSizeGb": { + "description": "Size of the image when restored onto a persistent disk (in GB).", + "format": "int64", + "type": "string" + }, + "family": { + "description": "The name of the image family to which this image belongs. You can create disks by specifying an image family instead of a specific image name. The image family always returns its latest image that is not deprecated. The name of the image family must comply with RFC1035.", + "type": "string" + }, + "guestOsFeatures": { + "description": "A list of features to enable on the guest operating system. Applicable only for bootable images. Read Enabling guest operating system features to see a list of available options.", + "items": { + "$ref": "GuestOsFeature" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "imageEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "Encrypts the image using a customer-supplied encryption key.\n\nAfter you encrypt an image with a customer-supplied key, you must provide the same key if you use the image later (e.g. to create a disk from the image).\n\nCustomer-supplied encryption keys do not protect access to metadata of the disk.\n\nIf you do not provide an encryption key when creating the image, then the disk will be encrypted using an automatically generated key and you do not need to provide a key to use the image later." + }, + "kind": { + "default": "compute#image", + "description": "[Output Only] Type of the resource. Always compute#image for images.", + "type": "string" + }, + "labelFingerprint": { + "description": "A fingerprint for the labels being applied to this image, which is essentially a hash of the labels used for optimistic locking. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash in order to update or change labels.\n\nTo see the latest fingerprint, make a get() request to retrieve an image.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels to apply to this image. These can be later modified by the setLabels method.", + "type": "object" + }, + "licenseCodes": { + "description": "Integer license codes indicating which licenses are attached to this image.", + "items": { + "format": "int64", + "type": "string" + }, + "type": "array" + }, + "licenses": { + "description": "Any applicable license URI.", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "annotations": { + "required": [ + "compute.images.insert" + ] + }, + "description": "Name of the resource; provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "rawDisk": { + "description": "The parameters of the raw disk image.", + "properties": { + "containerType": { + "description": "The format used to encode and transmit the block device, which should be TAR. This is just a container and transmission format and not a runtime format. Provided by the client when the disk image is created.", + "enum": [ + "TAR" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + }, + "sha1Checksum": { + "description": "An optional SHA1 checksum of the disk image before unpackaging; provided by the client when the disk image is created.", + "pattern": "[a-f0-9]{40}", + "type": "string" + }, + "source": { + "annotations": { + "required": [ + "compute.images.insert" + ] + }, + "description": "The full Google Cloud Storage URL where the disk image is stored. You must provide either this property or the sourceDisk property but not both.", + "type": "string" + } + }, + "type": "object" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sourceDisk": { + "description": "URL of the source disk used to create this image. This can be a full or valid partial URL. You must provide either this property or the rawDisk.source property but not both to create an image. For example, the following are valid values: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/disks/disk \n- projects/project/zones/zone/disks/disk \n- zones/zone/disks/disk", + "type": "string" + }, + "sourceDiskEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source disk. Required if the source disk is protected by a customer-supplied encryption key." + }, + "sourceDiskId": { + "description": "The ID value of the disk used to create this image. This value may be used to determine whether the image was taken from the current or a previous instance of a given disk name.", + "type": "string" + }, + "sourceImage": { + "description": "URL of the source image used to create this image. This can be a full or valid partial URL. You must provide exactly one of: \n- this property, or \n- the rawDisk.source property, or \n- the sourceDisk property in order to create an image.", + "type": "string" + }, + "sourceImageEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source image. Required if the source image is protected by a customer-supplied encryption key." + }, + "sourceImageId": { + "description": "[Output Only] The ID value of the image used to create this image. This value may be used to determine whether the image was taken from the current or a previous instance of a given image name.", + "type": "string" + }, + "sourceSnapshot": { + "description": "URL of the source snapshot used to create this image. This can be a full or valid partial URL. You must provide exactly one of: \n- this property, or \n- the sourceImage property, or \n- the rawDisk.source property, or \n- the sourceDisk property in order to create an image.", + "type": "string" + }, + "sourceSnapshotEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source snapshot. Required if the source snapshot is protected by a customer-supplied encryption key." + }, + "sourceSnapshotId": { + "description": "[Output Only] The ID value of the snapshot used to create this image. This value may be used to determine whether the snapshot was taken from the current or a previous instance of a given snapshot name.", + "type": "string" + }, + "sourceType": { + "default": "RAW", + "description": "The type of the image used to create this disk. The default and only value is RAW", + "enum": [ + "RAW" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the image. An image can be used to create other resources, such as instances, only after the image has been successfully created and the status is set to READY. Possible values are FAILED, PENDING, or READY.", + "enum": [ + "FAILED", + "PENDING", + "READY" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "ImageList": { + "description": "Contains a list of images.", + "id": "ImageList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Image resources.", + "items": { + "$ref": "Image" + }, + "type": "array" + }, + "kind": { + "default": "compute#imageList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Instance": { + "description": "An Instance resource. (== resource_for beta.instances ==) (== resource_for v1.instances ==)", + "id": "Instance", + "properties": { + "canIpForward": { + "description": "Allows this instance to send and receive packets with non-matching destination or source IPs. This is required if you plan to use this instance to forward routes. For more information, see Enabling IP Forwarding.", + "type": "boolean" + }, + "cpuPlatform": { + "description": "[Output Only] The CPU platform used by this instance.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "deletionProtection": { + "description": "Whether the resource should be protected against deletion.", + "type": "boolean" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "disks": { + "description": "Array of disks associated with this instance. Persistent disks must be created before you can assign them.", + "items": { + "$ref": "AttachedDisk" + }, + "type": "array" + }, + "guestAccelerators": { + "description": "A list of the type and count of accelerator cards attached to the instance.", + "items": { + "$ref": "AcceleratorConfig" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#instance", + "description": "[Output Only] Type of the resource. Always compute#instance for instances.", + "type": "string" + }, + "labelFingerprint": { + "description": "A fingerprint for this request, which is essentially a hash of the label's contents and used for optimistic locking. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash in order to update or change labels.\n\nTo see the latest fingerprint, make get() request to the instance.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels to apply to this instance. These can be later modified by the setLabels method.", + "type": "object" + }, + "machineType": { + "annotations": { + "required": [ + "compute.instances.insert" + ] + }, + "description": "Full or partial URL of the machine type resource to use for this instance, in the format: zones/zone/machineTypes/machine-type. This is provided by the client when the instance is created. For example, the following is a valid partial url to a predefined machine type:\nzones/us-central1-f/machineTypes/n1-standard-1\n\n\nTo create a custom machine type, provide a URL to a machine type in the following format, where CPUS is 1 or an even number up to 32 (2, 4, 6, ... 24, etc), and MEMORY is the total memory for this instance. Memory must be a multiple of 256 MB and must be supplied in MB (e.g. 5 GB of memory is 5120 MB):\nzones/zone/machineTypes/custom-CPUS-MEMORY\n\n\nFor example: zones/us-central1-f/machineTypes/custom-4-5120 \n\nFor a full list of restrictions, read the Specifications for custom machine types.", + "type": "string" + }, + "metadata": { + "$ref": "Metadata", + "description": "The metadata key/value pairs assigned to this instance. This includes custom metadata and predefined keys." + }, + "minCpuPlatform": { + "description": "Specifies a minimum CPU platform for the VM instance. Applicable values are the friendly names of CPU platforms, such as minCpuPlatform: \"Intel Haswell\" or minCpuPlatform: \"Intel Sandy Bridge\".", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.instances.insert" + ] + }, + "description": "The name of the resource, provided by the client when initially creating the resource. The resource name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "networkInterfaces": { + "description": "An array of network configurations for this instance. These specify how interfaces are configured to interact with other network services, such as connecting to the internet. Multiple interfaces are supported per instance.", + "items": { + "$ref": "NetworkInterface" + }, + "type": "array" + }, + "scheduling": { + "$ref": "Scheduling", + "description": "Sets the scheduling options for this instance." + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "serviceAccounts": { + "description": "A list of service accounts, with their specified scopes, authorized for this instance. Only one service account per VM instance is supported.\n\nService accounts generate access tokens that can be accessed through the metadata server and used to authenticate applications on the instance. See Service Accounts for more information.", + "items": { + "$ref": "ServiceAccount" + }, + "type": "array" + }, + "startRestricted": { + "description": "[Output Only] Whether a VM has been restricted for start because Compute Engine has detected suspicious activity.", + "type": "boolean" + }, + "status": { + "description": "[Output Only] The status of the instance. One of the following values: PROVISIONING, STAGING, RUNNING, STOPPING, STOPPED, SUSPENDING, SUSPENDED, and TERMINATED.", + "enum": [ + "PROVISIONING", + "RUNNING", + "STAGING", + "STOPPED", + "STOPPING", + "SUSPENDED", + "SUSPENDING", + "TERMINATED" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "statusMessage": { + "description": "[Output Only] An optional, human-readable explanation of the status.", + "type": "string" + }, + "tags": { + "$ref": "Tags", + "description": "A list of tags to apply to this instance. Tags are used to identify valid sources or targets for network firewalls and are specified by the client during instance creation. The tags can be later modified by the setTags method. Each tag within the list must comply with RFC1035." + }, + "zone": { + "description": "[Output Only] URL of the zone where the instance resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + } + }, + "type": "object" + }, + "InstanceAggregatedList": { + "id": "InstanceAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "InstancesScopedList", + "description": "[Output Only] Name of the scope containing this set of instances." + }, + "description": "A list of InstancesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#instanceAggregatedList", + "description": "[Output Only] Type of resource. Always compute#instanceAggregatedList for aggregated lists of Instance resources.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroup": { + "description": "InstanceGroups (== resource_for beta.instanceGroups ==) (== resource_for v1.instanceGroups ==) (== resource_for beta.regionInstanceGroups ==) (== resource_for v1.regionInstanceGroups ==)", + "id": "InstanceGroup", + "properties": { + "creationTimestamp": { + "description": "[Output Only] The creation timestamp for this instance group in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "fingerprint": { + "description": "[Output Only] The fingerprint of the named ports. The system uses this fingerprint to detect conflicts when multiple users change the named ports concurrently.", + "format": "byte", + "type": "string" + }, + "id": { + "description": "[Output Only] A unique identifier for this instance group, generated by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#instanceGroup", + "description": "[Output Only] The resource type, which is always compute#instanceGroup for instance groups.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.instanceGroupManagers.insert" + ] + }, + "description": "The name of the instance group. The name must be 1-63 characters long, and comply with RFC1035.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "namedPorts": { + "description": "Assigns a name to a port number. For example: {name: \"http\", port: 80}\n\nThis allows the system to reference ports by the assigned name instead of a port number. Named ports can also contain multiple ports. For example: [{name: \"http\", port: 80},{name: \"http\", port: 8080}] \n\nNamed ports apply to all instances in this instance group.", + "items": { + "$ref": "NamedPort" + }, + "type": "array" + }, + "network": { + "description": "The URL of the network to which all instances in the instance group belong.", + "type": "string" + }, + "region": { + "description": "[Output Only] The URL of the region where the instance group is located (for regional resources).", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] The URL for this instance group. The server generates this URL.", + "type": "string" + }, + "size": { + "description": "[Output Only] The total number of instances in the instance group.", + "format": "int32", + "type": "integer" + }, + "subnetwork": { + "description": "[Output Only] The URL of the subnetwork to which all instances in the instance group belong.", + "type": "string" + }, + "zone": { + "description": "[Output Only] The URL of the zone where the instance group is located (for zonal resources).", + "type": "string" + } + }, + "type": "object" + }, + "InstanceGroupAggregatedList": { + "id": "InstanceGroupAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "InstanceGroupsScopedList", + "description": "The name of the scope that contains this set of instance groups." + }, + "description": "A list of InstanceGroupsScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#instanceGroupAggregatedList", + "description": "[Output Only] The resource type, which is always compute#instanceGroupAggregatedList for aggregated lists of instance groups.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupList": { + "description": "A list of InstanceGroup resources.", + "id": "InstanceGroupList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceGroup resources.", + "items": { + "$ref": "InstanceGroup" + }, + "type": "array" + }, + "kind": { + "default": "compute#instanceGroupList", + "description": "[Output Only] The resource type, which is always compute#instanceGroupList for instance group lists.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupManager": { + "description": "An Instance Group Manager resource. (== resource_for beta.instanceGroupManagers ==) (== resource_for v1.instanceGroupManagers ==) (== resource_for beta.regionInstanceGroupManagers ==) (== resource_for v1.regionInstanceGroupManagers ==)", + "id": "InstanceGroupManager", + "properties": { + "baseInstanceName": { + "annotations": { + "required": [ + "compute.instanceGroupManagers.insert" + ] + }, + "description": "The base instance name to use for instances in this group. The value must be 1-58 characters long. Instances are named by appending a hyphen and a random four-character string to the base instance name. The base instance name must comply with RFC1035.", + "pattern": "[a-z][-a-z0-9]{0,57}", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] The creation timestamp for this managed instance group in RFC3339 text format.", + "type": "string" + }, + "currentActions": { + "$ref": "InstanceGroupManagerActionsSummary", + "description": "[Output Only] The list of instance actions and the number of instances in this managed instance group that are scheduled for each of those actions." + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "fingerprint": { + "description": "Fingerprint of this resource. This field may be used in optimistic locking. It will be ignored when inserting an InstanceGroupManager. An up-to-date fingerprint must be provided in order to update the InstanceGroupManager or the field need to be unset.", + "format": "byte", + "type": "string" + }, + "id": { + "description": "[Output Only] A unique identifier for this resource type. The server generates this identifier.", + "format": "uint64", + "type": "string" + }, + "instanceGroup": { + "description": "[Output Only] The URL of the Instance Group resource.", + "type": "string" + }, + "instanceTemplate": { + "description": "The URL of the instance template that is specified for this managed instance group. The group uses this template to create all new instances in the managed instance group.", + "type": "string" + }, + "kind": { + "default": "compute#instanceGroupManager", + "description": "[Output Only] The resource type, which is always compute#instanceGroupManager for managed instance groups.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.instanceGroupManagers.insert", + "compute.regionInstanceGroupManagers.insert" + ] + }, + "description": "The name of the managed instance group. The name must be 1-63 characters long, and comply with RFC1035.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "namedPorts": { + "description": "Named ports configured for the Instance Groups complementary to this Instance Group Manager.", + "items": { + "$ref": "NamedPort" + }, + "type": "array" + }, + "region": { + "description": "[Output Only] The URL of the region where the managed instance group resides (for regional resources).", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] The URL for this managed instance group. The server defines this URL.", + "type": "string" + }, + "targetPools": { + "description": "The URLs for all TargetPool resources to which instances in the instanceGroup field are added. The target pools automatically apply to all of the instances in the managed instance group.", + "items": { + "type": "string" + }, + "type": "array" + }, + "targetSize": { + "annotations": { + "required": [ + "compute.instanceGroupManagers.insert", + "compute.regionInstanceGroupManagers.insert" + ] + }, + "description": "The target number of running instances for this managed instance group. Deleting or abandoning instances reduces this number. Resizing the group changes this number.", + "format": "int32", + "type": "integer" + }, + "zone": { + "description": "[Output Only] The URL of the zone where the managed instance group is located (for zonal resources).", + "type": "string" + } + }, + "type": "object" + }, + "InstanceGroupManagerActionsSummary": { + "id": "InstanceGroupManagerActionsSummary", + "properties": { + "abandoning": { + "description": "[Output Only] The total number of instances in the managed instance group that are scheduled to be abandoned. Abandoning an instance removes it from the managed instance group without deleting it.", + "format": "int32", + "type": "integer" + }, + "creating": { + "description": "[Output Only] The number of instances in the managed instance group that are scheduled to be created or are currently being created. If the group fails to create any of these instances, it tries again until it creates the instance successfully.\n\nIf you have disabled creation retries, this field will not be populated; instead, the creatingWithoutRetries field will be populated.", + "format": "int32", + "type": "integer" + }, + "creatingWithoutRetries": { + "description": "[Output Only] The number of instances that the managed instance group will attempt to create. The group attempts to create each instance only once. If the group fails to create any of these instances, it decreases the group's targetSize value accordingly.", + "format": "int32", + "type": "integer" + }, + "deleting": { + "description": "[Output Only] The number of instances in the managed instance group that are scheduled to be deleted or are currently being deleted.", + "format": "int32", + "type": "integer" + }, + "none": { + "description": "[Output Only] The number of instances in the managed instance group that are running and have no scheduled actions.", + "format": "int32", + "type": "integer" + }, + "recreating": { + "description": "[Output Only] The number of instances in the managed instance group that are scheduled to be recreated or are currently being being recreated. Recreating an instance deletes the existing root persistent disk and creates a new disk from the image that is defined in the instance template.", + "format": "int32", + "type": "integer" + }, + "refreshing": { + "description": "[Output Only] The number of instances in the managed instance group that are being reconfigured with properties that do not require a restart or a recreate action. For example, setting or removing target pools for the instance.", + "format": "int32", + "type": "integer" + }, + "restarting": { + "description": "[Output Only] The number of instances in the managed instance group that are scheduled to be restarted or are currently being restarted.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "InstanceGroupManagerAggregatedList": { + "id": "InstanceGroupManagerAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "InstanceGroupManagersScopedList", + "description": "[Output Only] The name of the scope that contains this set of managed instance groups." + }, + "description": "A list of InstanceGroupManagersScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#instanceGroupManagerAggregatedList", + "description": "[Output Only] The resource type, which is always compute#instanceGroupManagerAggregatedList for an aggregated list of managed instance groups.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupManagerList": { + "description": "[Output Only] A list of managed instance groups.", + "id": "InstanceGroupManagerList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceGroupManager resources.", + "items": { + "$ref": "InstanceGroupManager" + }, + "type": "array" + }, + "kind": { + "default": "compute#instanceGroupManagerList", + "description": "[Output Only] The resource type, which is always compute#instanceGroupManagerList for a list of managed instance groups.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupManagersAbandonInstancesRequest": { + "id": "InstanceGroupManagersAbandonInstancesRequest", + "properties": { + "instances": { + "description": "The URLs of one or more instances to abandon. This can be a full URL or a partial URL, such as zones/[ZONE]/instances/[INSTANCE_NAME].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupManagersDeleteInstancesRequest": { + "id": "InstanceGroupManagersDeleteInstancesRequest", + "properties": { + "instances": { + "description": "The URLs of one or more instances to delete. This can be a full URL or a partial URL, such as zones/[ZONE]/instances/[INSTANCE_NAME].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupManagersListManagedInstancesResponse": { + "id": "InstanceGroupManagersListManagedInstancesResponse", + "properties": { + "managedInstances": { + "description": "[Output Only] The list of instances in the managed instance group.", + "items": { + "$ref": "ManagedInstance" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupManagersRecreateInstancesRequest": { + "id": "InstanceGroupManagersRecreateInstancesRequest", + "properties": { + "instances": { + "description": "The URLs of one or more instances to recreate. This can be a full URL or a partial URL, such as zones/[ZONE]/instances/[INSTANCE_NAME].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupManagersScopedList": { + "id": "InstanceGroupManagersScopedList", + "properties": { + "instanceGroupManagers": { + "description": "[Output Only] The list of managed instance groups that are contained in the specified project and zone.", + "items": { + "$ref": "InstanceGroupManager" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] The warning that replaces the list of managed instance groups when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupManagersSetInstanceTemplateRequest": { + "id": "InstanceGroupManagersSetInstanceTemplateRequest", + "properties": { + "instanceTemplate": { + "description": "The URL of the instance template that is specified for this managed instance group. The group uses this template to create all new instances in the managed instance group.", + "type": "string" + } + }, + "type": "object" + }, + "InstanceGroupManagersSetTargetPoolsRequest": { + "id": "InstanceGroupManagersSetTargetPoolsRequest", + "properties": { + "fingerprint": { + "description": "The fingerprint of the target pools information. Use this optional property to prevent conflicts when multiple users change the target pools settings concurrently. Obtain the fingerprint with the instanceGroupManagers.get method. Then, include the fingerprint in your request to ensure that you do not overwrite changes that were applied from another concurrent request.", + "format": "byte", + "type": "string" + }, + "targetPools": { + "description": "The list of target pool URLs that instances in this managed instance group belong to. The managed instance group applies these target pools to all of the instances in the group. Existing instances and new instances in the group all receive these target pool settings.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupsAddInstancesRequest": { + "id": "InstanceGroupsAddInstancesRequest", + "properties": { + "instances": { + "description": "The list of instances to add to the instance group.", + "items": { + "$ref": "InstanceReference" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupsListInstances": { + "id": "InstanceGroupsListInstances", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceWithNamedPorts resources.", + "items": { + "$ref": "InstanceWithNamedPorts" + }, + "type": "array" + }, + "kind": { + "default": "compute#instanceGroupsListInstances", + "description": "[Output Only] The resource type, which is always compute#instanceGroupsListInstances for the list of instances in the specified instance group.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupsListInstancesRequest": { + "id": "InstanceGroupsListInstancesRequest", + "properties": { + "instanceState": { + "description": "A filter for the state of the instances in the instance group. Valid options are ALL or RUNNING. If you do not specify this parameter the list includes all instances regardless of their state.", + "enum": [ + "ALL", + "RUNNING" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "InstanceGroupsRemoveInstancesRequest": { + "id": "InstanceGroupsRemoveInstancesRequest", + "properties": { + "instances": { + "description": "The list of instances to remove from the instance group.", + "items": { + "$ref": "InstanceReference" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceGroupsScopedList": { + "id": "InstanceGroupsScopedList", + "properties": { + "instanceGroups": { + "description": "[Output Only] The list of instance groups that are contained in this scope.", + "items": { + "$ref": "InstanceGroup" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] An informational warning that replaces the list of instance groups when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceGroupsSetNamedPortsRequest": { + "id": "InstanceGroupsSetNamedPortsRequest", + "properties": { + "fingerprint": { + "description": "The fingerprint of the named ports information for this instance group. Use this optional property to prevent conflicts when multiple users change the named ports settings concurrently. Obtain the fingerprint with the instanceGroups.get method. Then, include the fingerprint in your request to ensure that you do not overwrite changes that were applied from another concurrent request.", + "format": "byte", + "type": "string" + }, + "namedPorts": { + "description": "The list of named ports to set for this instance group.", + "items": { + "$ref": "NamedPort" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstanceList": { + "description": "Contains a list of instances.", + "id": "InstanceList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Instance resources.", + "items": { + "$ref": "Instance" + }, + "type": "array" + }, + "kind": { + "default": "compute#instanceList", + "description": "[Output Only] Type of resource. Always compute#instanceList for lists of Instance resources.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceListReferrers": { + "description": "Contains a list of instance referrers.", + "id": "InstanceListReferrers", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Reference resources.", + "items": { + "$ref": "Reference" + }, + "type": "array" + }, + "kind": { + "default": "compute#instanceListReferrers", + "description": "[Output Only] Type of resource. Always compute#instanceListReferrers for lists of Instance referrers.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceMoveRequest": { + "id": "InstanceMoveRequest", + "properties": { + "destinationZone": { + "description": "The URL of the destination zone to move the instance. This can be a full or partial URL. For example, the following are all valid URLs to a zone: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone \n- projects/project/zones/zone \n- zones/zone", + "type": "string" + }, + "targetInstance": { + "description": "The URL of the target instance to move. This can be a full or partial URL. For example, the following are all valid URLs to an instance: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/instances/instance \n- projects/project/zones/zone/instances/instance \n- zones/zone/instances/instance", + "type": "string" + } + }, + "type": "object" + }, + "InstanceProperties": { + "description": "", + "id": "InstanceProperties", + "properties": { + "canIpForward": { + "description": "Enables instances created based on this template to send packets with source IP addresses other than their own and receive packets with destination IP addresses other than their own. If these instances will be used as an IP gateway or it will be set as the next-hop in a Route resource, specify true. If unsure, leave this set to false. See the Enable IP forwarding documentation for more information.", + "type": "boolean" + }, + "description": { + "description": "An optional text description for the instances that are created from this instance template.", + "type": "string" + }, + "disks": { + "description": "An array of disks that are associated with the instances that are created from this template.", + "items": { + "$ref": "AttachedDisk" + }, + "type": "array" + }, + "guestAccelerators": { + "description": "A list of guest accelerator cards' type and count to use for instances created from the instance template.", + "items": { + "$ref": "AcceleratorConfig" + }, + "type": "array" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels to apply to instances that are created from this template.", + "type": "object" + }, + "machineType": { + "annotations": { + "required": [ + "compute.instanceTemplates.insert" + ] + }, + "description": "The machine type to use for instances that are created from this template.", + "type": "string" + }, + "metadata": { + "$ref": "Metadata", + "description": "The metadata key/value pairs to assign to instances that are created from this template. These pairs can consist of custom metadata or predefined keys. See Project and instance metadata for more information." + }, + "minCpuPlatform": { + "description": "Minimum cpu/platform to be used by this instance. The instance may be scheduled on the specified or newer cpu/platform. Applicable values are the friendly names of CPU platforms, such as minCpuPlatform: \"Intel Haswell\" or minCpuPlatform: \"Intel Sandy Bridge\". For more information, read Specifying a Minimum CPU Platform.", + "type": "string" + }, + "networkInterfaces": { + "description": "An array of network access configurations for this interface.", + "items": { + "$ref": "NetworkInterface" + }, + "type": "array" + }, + "scheduling": { + "$ref": "Scheduling", + "description": "Specifies the scheduling options for the instances that are created from this template." + }, + "serviceAccounts": { + "description": "A list of service accounts with specified scopes. Access tokens for these service accounts are available to the instances that are created from this template. Use metadata queries to obtain the access tokens for these instances.", + "items": { + "$ref": "ServiceAccount" + }, + "type": "array" + }, + "tags": { + "$ref": "Tags", + "description": "A list of tags to apply to the instances that are created from this template. The tags identify valid sources or targets for network firewalls. The setTags method can modify this list of tags. Each tag within the list must comply with RFC1035." + } + }, + "type": "object" + }, + "InstanceReference": { + "id": "InstanceReference", + "properties": { + "instance": { + "description": "The URL for a specific instance.", + "type": "string" + } + }, + "type": "object" + }, + "InstanceTemplate": { + "description": "An Instance Template resource. (== resource_for beta.instanceTemplates ==) (== resource_for v1.instanceTemplates ==)", + "id": "InstanceTemplate", + "properties": { + "creationTimestamp": { + "description": "[Output Only] The creation timestamp for this instance template in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] A unique identifier for this instance template. The server defines this identifier.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#instanceTemplate", + "description": "[Output Only] The resource type, which is always compute#instanceTemplate for instance templates.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.instanceTemplates.insert" + ] + }, + "description": "Name of the resource; provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "properties": { + "$ref": "InstanceProperties", + "description": "The instance properties for this instance template." + }, + "selfLink": { + "description": "[Output Only] The URL for this instance template. The server defines this URL.", + "type": "string" + } + }, + "type": "object" + }, + "InstanceTemplateList": { + "description": "A list of instance templates.", + "id": "InstanceTemplateList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceTemplate resources.", + "items": { + "$ref": "InstanceTemplate" + }, + "type": "array" + }, + "kind": { + "default": "compute#instanceTemplateList", + "description": "[Output Only] The resource type, which is always compute#instanceTemplatesListResponse for instance template lists.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstanceWithNamedPorts": { + "id": "InstanceWithNamedPorts", + "properties": { + "instance": { + "description": "[Output Only] The URL of the instance.", + "type": "string" + }, + "namedPorts": { + "description": "[Output Only] The named ports that belong to this instance group.", + "items": { + "$ref": "NamedPort" + }, + "type": "array" + }, + "status": { + "description": "[Output Only] The status of the instance.", + "enum": [ + "PROVISIONING", + "RUNNING", + "STAGING", + "STOPPED", + "STOPPING", + "SUSPENDED", + "SUSPENDING", + "TERMINATED" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "InstancesScopedList": { + "id": "InstancesScopedList", + "properties": { + "instances": { + "description": "[Output Only] A list of instances contained in this scope.", + "items": { + "$ref": "Instance" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of instances when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InstancesSetLabelsRequest": { + "id": "InstancesSetLabelsRequest", + "properties": { + "labelFingerprint": { + "description": "Fingerprint of the previous set of labels for this resource, used to prevent conflicts. Provide the latest fingerprint value when making a request to add or change labels.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + }, + "InstancesSetMachineResourcesRequest": { + "id": "InstancesSetMachineResourcesRequest", + "properties": { + "guestAccelerators": { + "description": "A list of the type and count of accelerator cards attached to the instance.", + "items": { + "$ref": "AcceleratorConfig" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstancesSetMachineTypeRequest": { + "id": "InstancesSetMachineTypeRequest", + "properties": { + "machineType": { + "description": "Full or partial URL of the machine type resource. See Machine Types for a full list of machine types. For example: zones/us-central1-f/machineTypes/n1-standard-1", + "type": "string" + } + }, + "type": "object" + }, + "InstancesSetMinCpuPlatformRequest": { + "id": "InstancesSetMinCpuPlatformRequest", + "properties": { + "minCpuPlatform": { + "description": "Minimum cpu/platform this instance should be started at.", + "type": "string" + } + }, + "type": "object" + }, + "InstancesSetServiceAccountRequest": { + "id": "InstancesSetServiceAccountRequest", + "properties": { + "email": { + "description": "Email address of the service account.", + "type": "string" + }, + "scopes": { + "description": "The list of scopes to be made available for this service account.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "InstancesStartWithEncryptionKeyRequest": { + "id": "InstancesStartWithEncryptionKeyRequest", + "properties": { + "disks": { + "description": "Array of disks associated with this instance that are protected with a customer-supplied encryption key.\n\nIn order to start the instance, the disk url and its corresponding key must be provided.\n\nIf the disk is not protected with a customer-supplied encryption key it should not be specified.", + "items": { + "$ref": "CustomerEncryptionKeyProtectedDisk" + }, + "type": "array" + } + }, + "type": "object" + }, + "Interconnect": { + "description": "Represents an Interconnects resource. The Interconnects resource is a dedicated connection between Google's network and your on-premises network. For more information, see the Dedicated overview page. (== resource_for v1.interconnects ==) (== resource_for beta.interconnects ==)", + "id": "Interconnect", + "properties": { + "adminEnabled": { + "description": "Administrative status of the interconnect. When this is set to true, the Interconnect is functional and can carry traffic. When set to false, no packets can be carried over the interconnect and no BGP routes are exchanged over it. By default, the status is set to true.", + "type": "boolean" + }, + "circuitInfos": { + "description": "[Output Only] A list of CircuitInfo objects, that describe the individual circuits in this LAG.", + "items": { + "$ref": "InterconnectCircuitInfo" + }, + "type": "array" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "customerName": { + "description": "Customer name, to put in the Letter of Authorization as the party authorized to request a crossconnect.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "expectedOutages": { + "description": "[Output Only] A list of outages expected for this Interconnect.", + "items": { + "$ref": "InterconnectOutageNotification" + }, + "type": "array" + }, + "googleIpAddress": { + "description": "[Output Only] IP address configured on the Google side of the Interconnect link. This can be used only for ping tests.", + "type": "string" + }, + "googleReferenceId": { + "description": "[Output Only] Google reference ID; to be used when raising support tickets with Google or otherwise to debug backend connectivity issues.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "interconnectAttachments": { + "description": "[Output Only] A list of the URLs of all InterconnectAttachments configured to use this Interconnect.", + "items": { + "type": "string" + }, + "type": "array" + }, + "interconnectType": { + "description": "Type of interconnect. Note that \"IT_PRIVATE\" has been deprecated in favor of \"DEDICATED\"", + "enum": [ + "DEDICATED", + "IT_PRIVATE" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "kind": { + "default": "compute#interconnect", + "description": "[Output Only] Type of the resource. Always compute#interconnect for interconnects.", + "type": "string" + }, + "linkType": { + "description": "Type of link requested. This field indicates speed of each of the links in the bundle, not the entire bundle. Only 10G per link is allowed for a dedicated interconnect. Options: Ethernet_10G_LR", + "enum": [ + "LINK_TYPE_ETHERNET_10G_LR" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + }, + "location": { + "description": "URL of the InterconnectLocation object that represents where this connection is to be provisioned.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.interconnects.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "nocContactEmail": { + "description": "Email address to contact the customer NOC for operations and maintenance notifications regarding this Interconnect. If specified, this will be used for notifications in addition to all other forms described, such as Stackdriver logs alerting and Cloud Notifications.", + "type": "string" + }, + "operationalStatus": { + "description": "[Output Only] The current status of whether or not this Interconnect is functional.", + "enum": [ + "OS_ACTIVE", + "OS_UNPROVISIONED" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "peerIpAddress": { + "description": "[Output Only] IP address configured on the customer side of the Interconnect link. The customer should configure this IP address during turnup when prompted by Google NOC. This can be used only for ping tests.", + "type": "string" + }, + "provisionedLinkCount": { + "description": "[Output Only] Number of links actually provisioned in this interconnect.", + "format": "int32", + "type": "integer" + }, + "requestedLinkCount": { + "description": "Target number of physical links in the link bundle, as requested by the customer.", + "format": "int32", + "type": "integer" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "InterconnectAttachment": { + "description": "Represents an InterconnectAttachment (VLAN attachment) resource. For more information, see Creating VLAN Attachments. (== resource_for beta.interconnectAttachments ==) (== resource_for v1.interconnectAttachments ==)", + "id": "InterconnectAttachment", + "properties": { + "cloudRouterIpAddress": { + "description": "[Output Only] IPv4 address + prefix length to be configured on Cloud Router Interface for this interconnect attachment.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "customerRouterIpAddress": { + "description": "[Output Only] IPv4 address + prefix length to be configured on the customer router subinterface for this interconnect attachment.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource.", + "type": "string" + }, + "googleReferenceId": { + "description": "[Output Only] Google reference ID, to be used when raising support tickets with Google or otherwise to debug backend connectivity issues.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "interconnect": { + "description": "URL of the underlying Interconnect object that this attachment's traffic will traverse through.", + "type": "string" + }, + "kind": { + "default": "compute#interconnectAttachment", + "description": "[Output Only] Type of the resource. Always compute#interconnectAttachment for interconnect attachments.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "operationalStatus": { + "description": "[Output Only] The current status of whether or not this interconnect attachment is functional.", + "enum": [ + "OS_ACTIVE", + "OS_UNPROVISIONED" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "privateInterconnectInfo": { + "$ref": "InterconnectAttachmentPrivateInfo", + "description": "[Output Only] Information specific to an InterconnectAttachment. This property is populated if the interconnect that this is attached to is of type DEDICATED." + }, + "region": { + "description": "[Output Only] URL of the region where the regional interconnect attachment resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "router": { + "description": "URL of the cloud router to be used for dynamic routing. This router must be in the same region as this InterconnectAttachment. The InterconnectAttachment will automatically connect the Interconnect to the network \u0026 region within which the Cloud Router is configured.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "InterconnectAttachmentAggregatedList": { + "id": "InterconnectAttachmentAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "InterconnectAttachmentsScopedList", + "description": "Name of the scope containing this set of interconnect attachments." + }, + "description": "A list of InterconnectAttachmentsScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#interconnectAttachmentAggregatedList", + "description": "[Output Only] Type of resource. Always compute#interconnectAttachmentAggregatedList for aggregated lists of interconnect attachments.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InterconnectAttachmentList": { + "description": "Response to the list request, and contains a list of interconnect attachments.", + "id": "InterconnectAttachmentList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InterconnectAttachment resources.", + "items": { + "$ref": "InterconnectAttachment" + }, + "type": "array" + }, + "kind": { + "default": "compute#interconnectAttachmentList", + "description": "[Output Only] Type of resource. Always compute#interconnectAttachmentList for lists of interconnect attachments.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InterconnectAttachmentPrivateInfo": { + "description": "Information for an interconnect attachment when this belongs to an interconnect of type DEDICATED.", + "id": "InterconnectAttachmentPrivateInfo", + "properties": { + "tag8021q": { + "description": "[Output Only] 802.1q encapsulation tag to be used for traffic between Google and the customer, going to and from this network and region.", + "format": "uint32", + "type": "integer" + } + }, + "type": "object" + }, + "InterconnectAttachmentsScopedList": { + "id": "InterconnectAttachmentsScopedList", + "properties": { + "interconnectAttachments": { + "description": "A list of interconnect attachments contained in this scope.", + "items": { + "$ref": "InterconnectAttachment" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of addresses when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InterconnectCircuitInfo": { + "description": "Describes a single physical circuit between the Customer and Google. CircuitInfo objects are created by Google, so all fields are output only. Next id: 4", + "id": "InterconnectCircuitInfo", + "properties": { + "customerDemarcId": { + "description": "Customer-side demarc ID for this circuit.", + "type": "string" + }, + "googleCircuitId": { + "description": "Google-assigned unique ID for this circuit. Assigned at circuit turn-up.", + "type": "string" + }, + "googleDemarcId": { + "description": "Google-side demarc ID for this circuit. Assigned at circuit turn-up and provided by Google to the customer in the LOA.", + "type": "string" + } + }, + "type": "object" + }, + "InterconnectList": { + "description": "Response to the list request, and contains a list of interconnects.", + "id": "InterconnectList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Interconnect resources.", + "items": { + "$ref": "Interconnect" + }, + "type": "array" + }, + "kind": { + "default": "compute#interconnectList", + "description": "[Output Only] Type of resource. Always compute#interconnectList for lists of interconnects.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InterconnectLocation": { + "description": "Represents an InterconnectLocations resource. The InterconnectLocations resource describes the locations where you can connect to Google's networks. For more information, see Colocation Facilities.", + "id": "InterconnectLocation", + "properties": { + "address": { + "description": "[Output Only] The postal address of the Point of Presence, each line in the address is separated by a newline character.", + "type": "string" + }, + "availabilityZone": { + "description": "[Output Only] Availability zone for this location. Within a metropolitan area (metro), maintenance will not be simultaneously scheduled in more than one availability zone. Example: \"zone1\" or \"zone2\".", + "type": "string" + }, + "city": { + "description": "[Output Only] Metropolitan area designator that indicates which city an interconnect is located. For example: \"Chicago, IL\", \"Amsterdam, Netherlands\".", + "type": "string" + }, + "continent": { + "description": "[Output Only] Continent for this location.", + "enum": [ + "AFRICA", + "ASIA_PAC", + "C_AFRICA", + "C_ASIA_PAC", + "C_EUROPE", + "C_NORTH_AMERICA", + "C_SOUTH_AMERICA", + "EUROPE", + "NORTH_AMERICA", + "SOUTH_AMERICA" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "[Output Only] An optional description of the resource.", + "type": "string" + }, + "facilityProvider": { + "description": "[Output Only] The name of the provider for this facility (e.g., EQUINIX).", + "type": "string" + }, + "facilityProviderFacilityId": { + "description": "[Output Only] A provider-assigned Identifier for this facility (e.g., Ashburn-DC1).", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#interconnectLocation", + "description": "[Output Only] Type of the resource. Always compute#interconnectLocation for interconnect locations.", + "type": "string" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "type": "string" + }, + "peeringdbFacilityId": { + "description": "[Output Only] The peeringdb identifier for this facility (corresponding with a netfac type in peeringdb).", + "type": "string" + }, + "regionInfos": { + "description": "[Output Only] A list of InterconnectLocation.RegionInfo objects, that describe parameters pertaining to the relation between this InterconnectLocation and various Google Cloud regions.", + "items": { + "$ref": "InterconnectLocationRegionInfo" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "InterconnectLocationList": { + "description": "Response to the list request, and contains a list of interconnect locations.", + "id": "InterconnectLocationList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InterconnectLocation resources.", + "items": { + "$ref": "InterconnectLocation" + }, + "type": "array" + }, + "kind": { + "default": "compute#interconnectLocationList", + "description": "[Output Only] Type of resource. Always compute#interconnectLocationList for lists of interconnect locations.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "InterconnectLocationRegionInfo": { + "description": "Information about any potential InterconnectAttachments between an Interconnect at a specific InterconnectLocation, and a specific Cloud Region.", + "id": "InterconnectLocationRegionInfo", + "properties": { + "expectedRttMs": { + "description": "Expected round-trip time in milliseconds, from this InterconnectLocation to a VM in this region.", + "format": "int64", + "type": "string" + }, + "locationPresence": { + "description": "Identifies the network presence of this location.", + "enum": [ + "GLOBAL", + "LOCAL_REGION", + "LP_GLOBAL", + "LP_LOCAL_REGION" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "region": { + "description": "URL for the region of this location.", + "type": "string" + } + }, + "type": "object" + }, + "InterconnectOutageNotification": { + "description": "Description of a planned outage on this Interconnect. Next id: 9", + "id": "InterconnectOutageNotification", + "properties": { + "affectedCircuits": { + "description": "If issue_type is IT_PARTIAL_OUTAGE, a list of the Google-side circuit IDs that will be affected.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "A description about the purpose of the outage.", + "type": "string" + }, + "endTime": { + "description": "Scheduled end time for the outage (milliseconds since Unix epoch).", + "format": "int64", + "type": "string" + }, + "issueType": { + "description": "Form this outage is expected to take. Note that the \"IT_\" versions of this enum have been deprecated in favor of the unprefixed values.", + "enum": [ + "IT_OUTAGE", + "IT_PARTIAL_OUTAGE", + "OUTAGE", + "PARTIAL_OUTAGE" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "name": { + "description": "Unique identifier for this outage notification.", + "type": "string" + }, + "source": { + "description": "The party that generated this notification. Note that \"NSRC_GOOGLE\" has been deprecated in favor of \"GOOGLE\"", + "enum": [ + "GOOGLE", + "NSRC_GOOGLE" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "startTime": { + "description": "Scheduled start time for the outage (milliseconds since Unix epoch).", + "format": "int64", + "type": "string" + }, + "state": { + "description": "State of this notification. Note that the \"NS_\" versions of this enum have been deprecated in favor of the unprefixed values.", + "enum": [ + "ACTIVE", + "CANCELLED", + "NS_ACTIVE", + "NS_CANCELED" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "License": { + "description": "A license resource.", + "id": "License", + "properties": { + "chargesUseFee": { + "description": "[Output Only] Deprecated. This field no longer reflects whether a license charges a usage fee.", + "type": "boolean" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional textual description of the resource; provided by the client when the resource is created.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#license", + "description": "[Output Only] Type of resource. Always compute#license for licenses.", + "type": "string" + }, + "licenseCode": { + "description": "[Output Only] The unique code used to attach this license to images, snapshots, and disks.", + "format": "uint64", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.images.insert" + ] + }, + "description": "[Output Only] Name of the resource. The name is 1-63 characters long and complies with RFC1035.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "resourceRequirements": { + "$ref": "LicenseResourceRequirements" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "transferable": { + "description": "If false, licenses will not be copied from the source resource when creating an image from a disk, disk from snapshot, or snapshot from disk.", + "type": "boolean" + } + }, + "type": "object" + }, + "LicenseCode": { + "id": "LicenseCode", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "[Output Only] Description of this License Code.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#licenseCode", + "description": "[Output Only] Type of resource. Always compute#licenseCode for licenses.", + "type": "string" + }, + "licenseAlias": { + "description": "[Output Only] URL and description aliases of Licenses with the same License Code.", + "items": { + "$ref": "LicenseCodeLicenseAlias" + }, + "type": "array" + }, + "name": { + "annotations": { + "required": [ + "compute.licenses.insert" + ] + }, + "description": "[Output Only] Name of the resource. The name is 1-20 characters long and must be a valid 64 bit integer.", + "pattern": "[0-9]{0,20}?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "state": { + "description": "[Output Only] Current state of this License Code.", + "enum": [ + "DISABLED", + "ENABLED", + "RESTRICTED", + "STATE_UNSPECIFIED", + "TERMINATED" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "transferable": { + "description": "[Output Only] If true, the license will remain attached when creating images or snapshots from disks. Otherwise, the license is not transferred.", + "type": "boolean" + } + }, + "type": "object" + }, + "LicenseCodeLicenseAlias": { + "id": "LicenseCodeLicenseAlias", + "properties": { + "description": { + "description": "[Output Only] Description of this License Code.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] URL of license corresponding to this License Code.", + "type": "string" + } + }, + "type": "object" + }, + "LicenseResourceRequirements": { + "id": "LicenseResourceRequirements", + "properties": { + "minGuestCpuCount": { + "description": "Minimum number of guest cpus required to use the Instance. Enforced at Instance creation and Instance start.", + "format": "int32", + "type": "integer" + }, + "minMemoryMb": { + "description": "Minimum memory required to use the Instance. Enforced at Instance creation and Instance start.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "LicensesListResponse": { + "id": "LicensesListResponse", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of License resources.", + "items": { + "$ref": "License" + }, + "type": "array" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "MachineType": { + "description": "A Machine Type resource. (== resource_for v1.machineTypes ==) (== resource_for beta.machineTypes ==)", + "id": "MachineType", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "deprecated": { + "$ref": "DeprecationStatus", + "description": "[Output Only] The deprecation status associated with this machine type." + }, + "description": { + "description": "[Output Only] An optional textual description of the resource.", + "type": "string" + }, + "guestCpus": { + "description": "[Output Only] The number of virtual CPUs that are available to the instance.", + "format": "int32", + "type": "integer" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "imageSpaceGb": { + "description": "[Deprecated] This property is deprecated and will never be populated with any relevant values.", + "format": "int32", + "type": "integer" + }, + "isSharedCpu": { + "description": "[Output Only] Whether this machine type has a shared CPU. See Shared-core machine types for more information.", + "type": "boolean" + }, + "kind": { + "default": "compute#machineType", + "description": "[Output Only] The type of the resource. Always compute#machineType for machine types.", + "type": "string" + }, + "maximumPersistentDisks": { + "description": "[Output Only] Maximum persistent disks allowed.", + "format": "int32", + "type": "integer" + }, + "maximumPersistentDisksSizeGb": { + "description": "[Output Only] Maximum total persistent disks size (GB) allowed.", + "format": "int64", + "type": "string" + }, + "memoryMb": { + "description": "[Output Only] The amount of physical memory available to the instance, defined in MB.", + "format": "int32", + "type": "integer" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "scratchDisks": { + "description": "[Output Only] A list of extended scratch disks assigned to the instance.", + "items": { + "properties": { + "diskGb": { + "description": "Size of the scratch disk, defined in GB.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "zone": { + "description": "[Output Only] The name of the zone where the machine type resides, such as us-central1-a.", + "type": "string" + } + }, + "type": "object" + }, + "MachineTypeAggregatedList": { + "id": "MachineTypeAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "MachineTypesScopedList", + "description": "[Output Only] Name of the scope containing this set of machine types." + }, + "description": "A list of MachineTypesScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#machineTypeAggregatedList", + "description": "[Output Only] Type of resource. Always compute#machineTypeAggregatedList for aggregated lists of machine types.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "MachineTypeList": { + "description": "Contains a list of machine types.", + "id": "MachineTypeList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of MachineType resources.", + "items": { + "$ref": "MachineType" + }, + "type": "array" + }, + "kind": { + "default": "compute#machineTypeList", + "description": "[Output Only] Type of resource. Always compute#machineTypeList for lists of machine types.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "MachineTypesScopedList": { + "id": "MachineTypesScopedList", + "properties": { + "machineTypes": { + "description": "[Output Only] A list of machine types contained in this scope.", + "items": { + "$ref": "MachineType" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] An informational warning that appears when the machine types list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ManagedInstance": { + "description": "Next available tag: 12", + "id": "ManagedInstance", + "properties": { + "currentAction": { + "description": "[Output Only] The current action that the managed instance group has scheduled for the instance. Possible values: \n- NONE The instance is running, and the managed instance group does not have any scheduled actions for this instance. \n- CREATING The managed instance group is creating this instance. If the group fails to create this instance, it will try again until it is successful. \n- CREATING_WITHOUT_RETRIES The managed instance group is attempting to create this instance only once. If the group fails to create this instance, it does not try again and the group's targetSize value is decreased instead. \n- RECREATING The managed instance group is recreating this instance. \n- DELETING The managed instance group is permanently deleting this instance. \n- ABANDONING The managed instance group is abandoning this instance. The instance will be removed from the instance group and from any target pools that are associated with this group. \n- RESTARTING The managed instance group is restarting the instance. \n- REFRESHING The managed instance group is applying configuration changes to the instance without stopping it. For example, the group can update the target pool list for an instance without stopping that instance. \n- VERIFYING The managed instance group has created the instance and it is in the process of being verified.", + "enum": [ + "ABANDONING", + "CREATING", + "CREATING_WITHOUT_RETRIES", + "DELETING", + "NONE", + "RECREATING", + "REFRESHING", + "RESTARTING" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "id": { + "description": "[Output only] The unique identifier for this resource. This field is empty when instance does not exist.", + "format": "uint64", + "type": "string" + }, + "instance": { + "description": "[Output Only] The URL of the instance. The URL can exist even if the instance has not yet been created.", + "type": "string" + }, + "instanceStatus": { + "description": "[Output Only] The status of the instance. This field is empty when the instance does not exist.", + "enum": [ + "PROVISIONING", + "RUNNING", + "STAGING", + "STOPPED", + "STOPPING", + "SUSPENDED", + "SUSPENDING", + "TERMINATED" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "lastAttempt": { + "$ref": "ManagedInstanceLastAttempt", + "description": "[Output Only] Information about the last attempt to create or delete the instance." + } + }, + "type": "object" + }, + "ManagedInstanceLastAttempt": { + "id": "ManagedInstanceLastAttempt", + "properties": { + "errors": { + "description": "[Output Only] Encountered errors during the last attempt to create or delete the instance.", + "properties": { + "errors": { + "description": "[Output Only] The array of errors encountered while processing this operation.", + "items": { + "properties": { + "code": { + "description": "[Output Only] The error type identifier for this error.", + "type": "string" + }, + "location": { + "description": "[Output Only] Indicates the field in the request that caused the error. This property is optional.", + "type": "string" + }, + "message": { + "description": "[Output Only] An optional, human-readable error message.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Metadata": { + "description": "A metadata key/value entry.", + "id": "Metadata", + "properties": { + "fingerprint": { + "description": "Specifies a fingerprint for this request, which is essentially a hash of the metadata's contents and used for optimistic locking. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update metadata. You must always provide an up-to-date fingerprint hash in order to update or change metadata.", + "format": "byte", + "type": "string" + }, + "items": { + "description": "Array of key/value pairs. The total size of all keys and values must be less than 512 KB.", + "items": { + "properties": { + "key": { + "annotations": { + "required": [ + "compute.instances.insert", + "compute.projects.setCommonInstanceMetadata" + ] + }, + "description": "Key for the metadata entry. Keys must conform to the following regexp: [a-zA-Z0-9-_]+, and be less than 128 bytes in length. This is reflected as part of a URL in the metadata server. Additionally, to avoid ambiguity, keys must not conflict with any other metadata keys for the project.", + "pattern": "[a-zA-Z0-9-_]{1,128}", + "type": "string" + }, + "value": { + "annotations": { + "required": [ + "compute.instances.insert", + "compute.projects.setCommonInstanceMetadata" + ] + }, + "description": "Value for the metadata entry. These are free-form strings, and only have meaning as interpreted by the image running in the instance. The only restriction placed on values is that their size must be less than or equal to 262144 bytes (256 KiB).", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "kind": { + "default": "compute#metadata", + "description": "[Output Only] Type of the resource. Always compute#metadata for metadata.", + "type": "string" + } + }, + "type": "object" + }, + "NamedPort": { + "description": "The named port. For example: .", + "id": "NamedPort", + "properties": { + "name": { + "description": "The name for this named port. The name must be 1-63 characters long, and comply with RFC1035.", + "type": "string" + }, + "port": { + "description": "The port number, which can be a value between 1 and 65535.", + "format": "int32", + "type": "integer" + } + }, + "type": "object" + }, + "Network": { + "description": "Represents a Network resource. Read Networks and Firewalls for more information. (== resource_for v1.networks ==) (== resource_for beta.networks ==)", + "id": "Network", + "properties": { + "IPv4Range": { + "description": "The range of internal addresses that are legal on this network. This range is a CIDR specification, for example: 192.168.0.0/16. Provided by the client when the network is created.", + "pattern": "[0-9]{1,3}(?:\\.[0-9]{1,3}){3}/[0-9]{1,2}", + "type": "string" + }, + "autoCreateSubnetworks": { + "description": "When set to true, the network is created in \"auto subnet mode\". When set to false, the network is in \"custom subnet mode\".\n\nIn \"auto subnet mode\", a newly created network is assigned the default CIDR of 10.128.0.0/9 and it automatically creates one subnetwork per region.", + "type": "boolean" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "gatewayIPv4": { + "description": "A gateway address for default routing to other networks. This value is read only and is selected by the Google Compute Engine, typically as the first usable address in the IPv4Range.", + "pattern": "[0-9]{1,3}(?:\\.[0-9]{1,3}){3}", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#network", + "description": "[Output Only] Type of the resource. Always compute#network for networks.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.networks.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "peerings": { + "description": "[Output Only] A list of network peerings for the resource.", + "items": { + "$ref": "NetworkPeering" + }, + "type": "array" + }, + "routingConfig": { + "$ref": "NetworkRoutingConfig", + "description": "The network-level routing configuration for this network. Used by Cloud Router to determine what type of network-wide routing behavior to enforce." + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "subnetworks": { + "description": "[Output Only] Server-defined fully-qualified URLs for all subnetworks in this network.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "NetworkInterface": { + "description": "A network interface resource attached to an instance.", + "id": "NetworkInterface", + "properties": { + "accessConfigs": { + "description": "An array of configurations for this interface. Currently, only one access config, ONE_TO_ONE_NAT, is supported. If there are no accessConfigs specified, then this instance will have no external internet access.", + "items": { + "$ref": "AccessConfig" + }, + "type": "array" + }, + "aliasIpRanges": { + "description": "An array of alias IP ranges for this network interface. Can only be specified for network interfaces on subnet-mode networks.", + "items": { + "$ref": "AliasIpRange" + }, + "type": "array" + }, + "fingerprint": { + "description": "Fingerprint hash of contents stored in this network interface. This field will be ignored when inserting an Instance or adding a NetworkInterface. An up-to-date fingerprint must be provided in order to update the NetworkInterface.", + "format": "byte", + "type": "string" + }, + "kind": { + "default": "compute#networkInterface", + "description": "[Output Only] Type of the resource. Always compute#networkInterface for network interfaces.", + "type": "string" + }, + "name": { + "description": "[Output Only] The name of the network interface, generated by the server. For network devices, these are eth0, eth1, etc.", + "type": "string" + }, + "network": { + "description": "URL of the network resource for this instance. When creating an instance, if neither the network nor the subnetwork is specified, the default network global/networks/default is used; if the network is not specified but the subnetwork is specified, the network is inferred.\n\nThis field is optional when creating a firewall rule. If not specified when creating a firewall rule, the default network global/networks/default is used.\n\nIf you specify this property, you can specify the network as a full or partial URL. For example, the following are all valid URLs: \n- https://www.googleapis.com/compute/v1/projects/project/global/networks/network \n- projects/project/global/networks/network \n- global/networks/default", + "type": "string" + }, + "networkIP": { + "description": "An IPv4 internal network address to assign to the instance for this network interface. If not specified by the user, an unused internal IP is assigned by the system.", + "type": "string" + }, + "subnetwork": { + "description": "The URL of the Subnetwork resource for this instance. If the network resource is in legacy mode, do not provide this property. If the network is in auto subnet mode, providing the subnetwork is optional. If the network is in custom subnet mode, then this field should be specified. If you specify this property, you can specify the subnetwork as a full or partial URL. For example, the following are all valid URLs: \n- https://www.googleapis.com/compute/v1/projects/project/regions/region/subnetworks/subnetwork \n- regions/region/subnetworks/subnetwork", + "type": "string" + } + }, + "type": "object" + }, + "NetworkList": { + "description": "Contains a list of networks.", + "id": "NetworkList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Network resources.", + "items": { + "$ref": "Network" + }, + "type": "array" + }, + "kind": { + "default": "compute#networkList", + "description": "[Output Only] Type of resource. Always compute#networkList for lists of networks.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "NetworkPeering": { + "description": "A network peering attached to a network resource. The message includes the peering name, peer network, peering state, and a flag indicating whether Google Compute Engine should automatically create routes for the peering.", + "id": "NetworkPeering", + "properties": { + "autoCreateRoutes": { + "description": "Whether full mesh connectivity is created and managed automatically. When it is set to true, Google Compute Engine will automatically create and manage the routes between two networks when the state is ACTIVE. Otherwise, user needs to create routes manually to route packets to peer network.", + "type": "boolean" + }, + "name": { + "description": "Name of this peering. Provided by the client when the peering is created. The name must comply with RFC1035. Specifically, the name must be 1-63 characters long and match regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all the following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "type": "string" + }, + "network": { + "description": "The URL of the peer network. It can be either full URL or partial URL. The peer network may belong to a different project. If the partial URL does not contain project, it is assumed that the peer network is in the same project as the current network.", + "type": "string" + }, + "state": { + "description": "[Output Only] State for the peering.", + "enum": [ + "ACTIVE", + "INACTIVE" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "stateDetails": { + "description": "[Output Only] Details about the current state of the peering.", + "type": "string" + } + }, + "type": "object" + }, + "NetworkRoutingConfig": { + "description": "A routing configuration attached to a network resource. The message includes the list of routers associated with the network, and a flag indicating the type of routing behavior to enforce network-wide.", + "id": "NetworkRoutingConfig", + "properties": { + "routingMode": { + "description": "The network-wide routing mode to use. If set to REGIONAL, this network's cloud routers will only advertise routes with subnetworks of this network in the same region as the router. If set to GLOBAL, this network's cloud routers will advertise routes with all subnetworks of this network, across regions.", + "enum": [ + "GLOBAL", + "REGIONAL" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "NetworksAddPeeringRequest": { + "id": "NetworksAddPeeringRequest", + "properties": { + "autoCreateRoutes": { + "description": "Whether Google Compute Engine manages the routes automatically.", + "type": "boolean" + }, + "name": { + "annotations": { + "required": [ + "compute.networks.addPeering" + ] + }, + "description": "Name of the peering, which should conform to RFC1035.", + "type": "string" + }, + "peerNetwork": { + "description": "URL of the peer network. It can be either full URL or partial URL. The peer network may belong to a different project. If the partial URL does not contain project, it is assumed that the peer network is in the same project as the current network.", + "type": "string" + } + }, + "type": "object" + }, + "NetworksRemovePeeringRequest": { + "id": "NetworksRemovePeeringRequest", + "properties": { + "name": { + "description": "Name of the peering, which should conform to RFC1035.", + "type": "string" + } + }, + "type": "object" + }, + "Operation": { + "description": "An Operation resource, used to manage asynchronous API requests. (== resource_for v1.globalOperations ==) (== resource_for beta.globalOperations ==) (== resource_for v1.regionOperations ==) (== resource_for beta.regionOperations ==) (== resource_for v1.zoneOperations ==) (== resource_for beta.zoneOperations ==)", + "id": "Operation", + "properties": { + "clientOperationId": { + "description": "[Output Only] The value of `requestId` if you provided it in the request. Not present otherwise.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Deprecated] This field is deprecated.", + "type": "string" + }, + "description": { + "description": "[Output Only] A textual description of the operation, which is set when the operation is created.", + "type": "string" + }, + "endTime": { + "description": "[Output Only] The time that this operation was completed. This value is in RFC3339 text format.", + "type": "string" + }, + "error": { + "description": "[Output Only] If errors are generated during processing of the operation, this field will be populated.", + "properties": { + "errors": { + "description": "[Output Only] The array of errors encountered while processing this operation.", + "items": { + "properties": { + "code": { + "description": "[Output Only] The error type identifier for this error.", + "type": "string" + }, + "location": { + "description": "[Output Only] Indicates the field in the request that caused the error. This property is optional.", + "type": "string" + }, + "message": { + "description": "[Output Only] An optional, human-readable error message.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "httpErrorMessage": { + "description": "[Output Only] If the operation fails, this field contains the HTTP error message that was returned, such as NOT FOUND.", + "type": "string" + }, + "httpErrorStatusCode": { + "description": "[Output Only] If the operation fails, this field contains the HTTP error status code that was returned. For example, a 404 means the resource was not found.", + "format": "int32", + "type": "integer" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "insertTime": { + "description": "[Output Only] The time that this operation was requested. This value is in RFC3339 text format.", + "type": "string" + }, + "kind": { + "default": "compute#operation", + "description": "[Output Only] Type of the resource. Always compute#operation for Operation resources.", + "type": "string" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "type": "string" + }, + "operationType": { + "description": "[Output Only] The type of operation, such as insert, update, or delete, and so on.", + "type": "string" + }, + "progress": { + "description": "[Output Only] An optional progress indicator that ranges from 0 to 100. There is no requirement that this be linear or support any granularity of operations. This should not be used to guess when the operation will be complete. This number should monotonically increase as the operation progresses.", + "format": "int32", + "type": "integer" + }, + "region": { + "description": "[Output Only] The URL of the region where the operation resides. Only available when performing regional operations. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "startTime": { + "description": "[Output Only] The time that this operation was started by the server. This value is in RFC3339 text format.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the operation, which can be one of the following: PENDING, RUNNING, or DONE.", + "enum": [ + "DONE", + "PENDING", + "RUNNING" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "statusMessage": { + "description": "[Output Only] An optional textual description of the current status of the operation.", + "type": "string" + }, + "targetId": { + "description": "[Output Only] The unique target ID, which identifies a specific incarnation of the target resource.", + "format": "uint64", + "type": "string" + }, + "targetLink": { + "description": "[Output Only] The URL of the resource that the operation modifies. For operations related to creating a snapshot, this points to the persistent disk that the snapshot was created from.", + "type": "string" + }, + "user": { + "description": "[Output Only] User who requested the operation, for example: user@example.com.", + "type": "string" + }, + "warnings": { + "description": "[Output Only] If warning messages are generated during processing of the operation, this field will be populated.", + "items": { + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "zone": { + "description": "[Output Only] The URL of the zone where the operation resides. Only available when performing per-zone operations. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + } + }, + "type": "object" + }, + "OperationAggregatedList": { + "id": "OperationAggregatedList", + "properties": { + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "OperationsScopedList", + "description": "[Output Only] Name of the scope containing this set of operations." + }, + "description": "[Output Only] A map of scoped operation lists.", + "type": "object" + }, + "kind": { + "default": "compute#operationAggregatedList", + "description": "[Output Only] Type of resource. Always compute#operationAggregatedList for aggregated lists of operations.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "OperationList": { + "description": "Contains a list of Operation resources.", + "id": "OperationList", + "properties": { + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "type": "string" + }, + "items": { + "description": "[Output Only] A list of Operation resources.", + "items": { + "$ref": "Operation" + }, + "type": "array" + }, + "kind": { + "default": "compute#operationList", + "description": "[Output Only] Type of resource. Always compute#operations for Operations resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "OperationsScopedList": { + "id": "OperationsScopedList", + "properties": { + "operations": { + "description": "[Output Only] A list of operations contained in this scope.", + "items": { + "$ref": "Operation" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of operations when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "PathMatcher": { + "description": "A matcher for the path portion of the URL. The BackendService from the longest-matched rule will serve the URL. If no rule was matched, the default service will be used.", + "id": "PathMatcher", + "properties": { + "defaultService": { + "description": "The full or partial URL to the BackendService resource. This will be used if none of the pathRules defined by this PathMatcher is matched by the URL's path portion. For example, the following are all valid URLs to a BackendService resource: \n- https://www.googleapis.com/compute/v1/projects/project/global/backendServices/backendService \n- compute/v1/projects/project/global/backendServices/backendService \n- global/backendServices/backendService", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "name": { + "description": "The name to which this PathMatcher is referred by the HostRule.", + "type": "string" + }, + "pathRules": { + "description": "The list of path rules.", + "items": { + "$ref": "PathRule" + }, + "type": "array" + } + }, + "type": "object" + }, + "PathRule": { + "description": "A path-matching rule for a URL. If matched, will use the specified BackendService to handle the traffic arriving at this URL.", + "id": "PathRule", + "properties": { + "paths": { + "description": "The list of path patterns to match. Each must start with / and the only place a * is allowed is at the end following a /. The string fed to the path matcher does not include any text after the first ? or #, and those chars are not allowed here.", + "items": { + "type": "string" + }, + "type": "array" + }, + "service": { + "description": "The URL of the BackendService resource if this rule is matched.", + "type": "string" + } + }, + "type": "object" + }, + "Project": { + "description": "A Project resource. For an overview of projects, see Cloud Platform Resource Hierarchy. (== resource_for v1.projects ==) (== resource_for beta.projects ==)", + "id": "Project", + "properties": { + "commonInstanceMetadata": { + "$ref": "Metadata", + "description": "Metadata key/value pairs available to all instances contained in this project. See Custom metadata for more information." + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "defaultServiceAccount": { + "description": "[Output Only] Default service account used by VMs running in this project.", + "type": "string" + }, + "description": { + "description": "An optional textual description of the resource.", + "type": "string" + }, + "enabledFeatures": { + "description": "Restricted features enabled for use on this project.", + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server. This is not the project ID, and is just a unique ID used by Compute Engine to identify resources.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#project", + "description": "[Output Only] Type of the resource. Always compute#project for projects.", + "type": "string" + }, + "name": { + "description": "The project ID. For example: my-example-project. Use the project ID to make requests to Compute Engine.", + "type": "string" + }, + "quotas": { + "description": "[Output Only] Quotas assigned to this project.", + "items": { + "$ref": "Quota" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "usageExportLocation": { + "$ref": "UsageExportLocation", + "description": "The naming prefix for daily usage reports and the Google Cloud Storage bucket where they are stored." + }, + "xpnProjectStatus": { + "description": "[Output Only] The role this project has in a shared VPC configuration. Currently only HOST projects are differentiated.", + "enum": [ + "HOST", + "UNSPECIFIED_XPN_PROJECT_STATUS" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "ProjectsDisableXpnResourceRequest": { + "id": "ProjectsDisableXpnResourceRequest", + "properties": { + "xpnResource": { + "$ref": "XpnResourceId", + "description": "Service resource (a.k.a service project) ID." + } + }, + "type": "object" + }, + "ProjectsEnableXpnResourceRequest": { + "id": "ProjectsEnableXpnResourceRequest", + "properties": { + "xpnResource": { + "$ref": "XpnResourceId", + "description": "Service resource (a.k.a service project) ID." + } + }, + "type": "object" + }, + "ProjectsGetXpnResources": { + "id": "ProjectsGetXpnResources", + "properties": { + "kind": { + "default": "compute#projectsGetXpnResources", + "description": "[Output Only] Type of resource. Always compute#projectsGetXpnResources for lists of service resources (a.k.a service projects)", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "resources": { + "description": "Service resources (a.k.a service projects) attached to this project as their shared VPC host.", + "items": { + "$ref": "XpnResourceId" + }, + "type": "array" + } + }, + "type": "object" + }, + "ProjectsListXpnHostsRequest": { + "id": "ProjectsListXpnHostsRequest", + "properties": { + "organization": { + "description": "Optional organization ID managed by Cloud Resource Manager, for which to list shared VPC host projects. If not specified, the organization will be inferred from the project.", + "type": "string" + } + }, + "type": "object" + }, + "Quota": { + "description": "A quotas entry.", + "id": "Quota", + "properties": { + "limit": { + "description": "[Output Only] Quota limit for this metric.", + "format": "double", + "type": "number" + }, + "metric": { + "description": "[Output Only] Name of the quota metric.", + "enum": [ + "AUTOSCALERS", + "BACKEND_BUCKETS", + "BACKEND_SERVICES", + "COMMITMENTS", + "CPUS", + "CPUS_ALL_REGIONS", + "DISKS_TOTAL_GB", + "FIREWALLS", + "FORWARDING_RULES", + "HEALTH_CHECKS", + "IMAGES", + "INSTANCES", + "INSTANCE_GROUPS", + "INSTANCE_GROUP_MANAGERS", + "INSTANCE_TEMPLATES", + "INTERCONNECTS", + "INTERCONNECT_ATTACHMENTS_PER_REGION", + "INTERCONNECT_ATTACHMENTS_TOTAL_MBPS", + "INTERNAL_ADDRESSES", + "IN_USE_ADDRESSES", + "LOCAL_SSD_TOTAL_GB", + "NETWORKS", + "NVIDIA_K80_GPUS", + "NVIDIA_P100_GPUS", + "NVIDIA_V100_GPUS", + "PREEMPTIBLE_CPUS", + "PREEMPTIBLE_LOCAL_SSD_GB", + "PREEMPTIBLE_NVIDIA_K80_GPUS", + "PREEMPTIBLE_NVIDIA_P100_GPUS", + "REGIONAL_AUTOSCALERS", + "REGIONAL_INSTANCE_GROUP_MANAGERS", + "ROUTERS", + "ROUTES", + "SECURITY_POLICIES", + "SECURITY_POLICY_RULES", + "SNAPSHOTS", + "SSD_TOTAL_GB", + "SSL_CERTIFICATES", + "STATIC_ADDRESSES", + "SUBNETWORKS", + "TARGET_HTTPS_PROXIES", + "TARGET_HTTP_PROXIES", + "TARGET_INSTANCES", + "TARGET_POOLS", + "TARGET_SSL_PROXIES", + "TARGET_TCP_PROXIES", + "TARGET_VPN_GATEWAYS", + "URL_MAPS", + "VPN_TUNNELS" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "usage": { + "description": "[Output Only] Current usage of this metric.", + "format": "double", + "type": "number" + } + }, + "type": "object" + }, + "Reference": { + "description": "Represents a reference to a resource.", + "id": "Reference", + "properties": { + "kind": { + "default": "compute#reference", + "description": "[Output Only] Type of the resource. Always compute#reference for references.", + "type": "string" + }, + "referenceType": { + "description": "A description of the reference type with no implied semantics. Possible values include: \n- MEMBER_OF", + "type": "string" + }, + "referrer": { + "description": "URL of the resource which refers to the target.", + "type": "string" + }, + "target": { + "description": "URL of the resource to which this reference points.", + "type": "string" + } + }, + "type": "object" + }, + "Region": { + "description": "Region resource. (== resource_for beta.regions ==) (== resource_for v1.regions ==)", + "id": "Region", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "deprecated": { + "$ref": "DeprecationStatus", + "description": "[Output Only] The deprecation status associated with this region." + }, + "description": { + "description": "[Output Only] Textual description of the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#region", + "description": "[Output Only] Type of the resource. Always compute#region for regions.", + "type": "string" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "type": "string" + }, + "quotas": { + "description": "[Output Only] Quotas assigned to this region.", + "items": { + "$ref": "Quota" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "status": { + "description": "[Output Only] Status of the region, either UP or DOWN.", + "enum": [ + "DOWN", + "UP" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "zones": { + "description": "[Output Only] A list of zones available in this region, in the form of resource URLs.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionAutoscalerList": { + "description": "Contains a list of autoscalers.", + "id": "RegionAutoscalerList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Autoscaler resources.", + "items": { + "$ref": "Autoscaler" + }, + "type": "array" + }, + "kind": { + "default": "compute#regionAutoscalerList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RegionDiskTypeList": { + "id": "RegionDiskTypeList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of DiskType resources.", + "items": { + "$ref": "DiskType" + }, + "type": "array" + }, + "kind": { + "default": "compute#regionDiskTypeList", + "description": "[Output Only] Type of resource. Always compute#regionDiskTypeList for region disk types.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RegionDisksResizeRequest": { + "id": "RegionDisksResizeRequest", + "properties": { + "sizeGb": { + "description": "The new size of the regional persistent disk, which is specified in GB.", + "format": "int64", + "type": "string" + } + }, + "type": "object" + }, + "RegionInstanceGroupList": { + "description": "Contains a list of InstanceGroup resources.", + "id": "RegionInstanceGroupList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceGroup resources.", + "items": { + "$ref": "InstanceGroup" + }, + "type": "array" + }, + "kind": { + "default": "compute#regionInstanceGroupList", + "description": "The resource type.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagerList": { + "description": "Contains a list of managed instance groups.", + "id": "RegionInstanceGroupManagerList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceGroupManager resources.", + "items": { + "$ref": "InstanceGroupManager" + }, + "type": "array" + }, + "kind": { + "default": "compute#regionInstanceGroupManagerList", + "description": "[Output Only] The resource type, which is always compute#instanceGroupManagerList for a list of managed instance groups that exist in th regional scope.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagersAbandonInstancesRequest": { + "id": "RegionInstanceGroupManagersAbandonInstancesRequest", + "properties": { + "instances": { + "description": "The URLs of one or more instances to abandon. This can be a full URL or a partial URL, such as zones/[ZONE]/instances/[INSTANCE_NAME].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagersDeleteInstancesRequest": { + "id": "RegionInstanceGroupManagersDeleteInstancesRequest", + "properties": { + "instances": { + "description": "The URLs of one or more instances to delete. This can be a full URL or a partial URL, such as zones/[ZONE]/instances/[INSTANCE_NAME].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagersListInstancesResponse": { + "id": "RegionInstanceGroupManagersListInstancesResponse", + "properties": { + "managedInstances": { + "description": "A list of managed instances.", + "items": { + "$ref": "ManagedInstance" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagersRecreateRequest": { + "id": "RegionInstanceGroupManagersRecreateRequest", + "properties": { + "instances": { + "description": "The URLs of one or more instances to recreate. This can be a full URL or a partial URL, such as zones/[ZONE]/instances/[INSTANCE_NAME].", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagersSetTargetPoolsRequest": { + "id": "RegionInstanceGroupManagersSetTargetPoolsRequest", + "properties": { + "fingerprint": { + "description": "Fingerprint of the target pools information, which is a hash of the contents. This field is used for optimistic locking when you update the target pool entries. This field is optional.", + "format": "byte", + "type": "string" + }, + "targetPools": { + "description": "The URL of all TargetPool resources to which instances in the instanceGroup field are added. The target pools automatically apply to all of the instances in the managed instance group.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionInstanceGroupManagersSetTemplateRequest": { + "id": "RegionInstanceGroupManagersSetTemplateRequest", + "properties": { + "instanceTemplate": { + "description": "URL of the InstanceTemplate resource from which all new instances will be created.", + "type": "string" + } + }, + "type": "object" + }, + "RegionInstanceGroupsListInstances": { + "id": "RegionInstanceGroupsListInstances", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of InstanceWithNamedPorts resources.", + "items": { + "$ref": "InstanceWithNamedPorts" + }, + "type": "array" + }, + "kind": { + "default": "compute#regionInstanceGroupsListInstances", + "description": "The resource type.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RegionInstanceGroupsListInstancesRequest": { + "id": "RegionInstanceGroupsListInstancesRequest", + "properties": { + "instanceState": { + "description": "Instances in which state should be returned. Valid options are: 'ALL', 'RUNNING'. By default, it lists all instances.", + "enum": [ + "ALL", + "RUNNING" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "portName": { + "description": "Name of port user is interested in. It is optional. If it is set, only information about this ports will be returned. If it is not set, all the named ports will be returned. Always lists all instances.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + } + }, + "type": "object" + }, + "RegionInstanceGroupsSetNamedPortsRequest": { + "id": "RegionInstanceGroupsSetNamedPortsRequest", + "properties": { + "fingerprint": { + "description": "The fingerprint of the named ports information for this instance group. Use this optional property to prevent conflicts when multiple users change the named ports settings concurrently. Obtain the fingerprint with the instanceGroups.get method. Then, include the fingerprint in your request to ensure that you do not overwrite changes that were applied from another concurrent request.", + "format": "byte", + "type": "string" + }, + "namedPorts": { + "description": "The list of named ports to set for this instance group.", + "items": { + "$ref": "NamedPort" + }, + "type": "array" + } + }, + "type": "object" + }, + "RegionList": { + "description": "Contains a list of region resources.", + "id": "RegionList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Region resources.", + "items": { + "$ref": "Region" + }, + "type": "array" + }, + "kind": { + "default": "compute#regionList", + "description": "[Output Only] Type of resource. Always compute#regionList for lists of regions.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RegionSetLabelsRequest": { + "id": "RegionSetLabelsRequest", + "properties": { + "labelFingerprint": { + "description": "The fingerprint of the previous set of labels for this resource, used to detect conflicts. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash in order to update or change labels. Make a get() request to the resource to get the latest fingerprint.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "The labels to set for this resource.", + "type": "object" + } + }, + "type": "object" + }, + "ResourceCommitment": { + "description": "Commitment for a particular resource (a Commitment is composed of one or more of these).", + "id": "ResourceCommitment", + "properties": { + "amount": { + "description": "The amount of the resource purchased (in a type-dependent unit, such as bytes). For vCPUs, this can just be an integer. For memory, this must be provided in MB. Memory must be a multiple of 256 MB, with up to 6.5GB of memory per every vCPU.", + "format": "int64", + "type": "string" + }, + "type": { + "description": "Type of resource for which this commitment applies. Possible values are VCPU and MEMORY", + "enum": [ + "MEMORY", + "UNSPECIFIED", + "VCPU" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "ResourceGroupReference": { + "id": "ResourceGroupReference", + "properties": { + "group": { + "description": "A URI referencing one of the instance groups listed in the backend service.", + "type": "string" + } + }, + "type": "object" + }, + "Route": { + "description": "Represents a Route resource. A route specifies how certain packets should be handled by the network. Routes are associated with instances by tags and the set of routes for a particular instance is called its routing table.\n\nFor each packet leaving an instance, the system searches that instance's routing table for a single best matching route. Routes match packets by destination IP address, preferring smaller or more specific ranges over larger ones. If there is a tie, the system selects the route with the smallest priority value. If there is still a tie, it uses the layer three and four packet headers to select just one of the remaining matching routes. The packet is then forwarded as specified by the nextHop field of the winning route - either to another instance destination, an instance gateway, or a Google Compute Engine-operated gateway.\n\nPackets that do not match any route in the sending instance's routing table are dropped. (== resource_for beta.routes ==) (== resource_for v1.routes ==)", + "id": "Route", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "destRange": { + "annotations": { + "required": [ + "compute.routes.insert" + ] + }, + "description": "The destination range of outgoing packets that this route applies to. Only IPv4 is supported.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#route", + "description": "[Output Only] Type of this resource. Always compute#routes for Route resources.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.routes.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "network": { + "annotations": { + "required": [ + "compute.routes.insert" + ] + }, + "description": "Fully-qualified URL of the network that this route applies to.", + "type": "string" + }, + "nextHopGateway": { + "description": "The URL to a gateway that should handle matching packets. You can only specify the internet gateway using a full or partial valid URL: projects/\u003cproject-id\u003e/global/gateways/default-internet-gateway", + "type": "string" + }, + "nextHopInstance": { + "description": "The URL to an instance that should handle matching packets. You can specify this as a full or partial URL. For example:\nhttps://www.googleapis.com/compute/v1/projects/project/zones/zone/instances/", + "type": "string" + }, + "nextHopIp": { + "description": "The network IP address of an instance that should handle matching packets. Only IPv4 is supported.", + "type": "string" + }, + "nextHopNetwork": { + "description": "The URL of the local network if it should handle matching packets.", + "type": "string" + }, + "nextHopPeering": { + "description": "[Output Only] The network peering name that should handle matching packets, which should conform to RFC1035.", + "type": "string" + }, + "nextHopVpnTunnel": { + "description": "The URL to a VpnTunnel that should handle matching packets.", + "type": "string" + }, + "priority": { + "annotations": { + "required": [ + "compute.routes.insert" + ] + }, + "description": "The priority of this route. Priority is used to break ties in cases where there is more than one matching route of equal prefix length. In the case of two routes with equal prefix length, the one with the lowest-numbered priority value wins. Default value is 1000. Valid range is 0 through 65535.", + "format": "uint32", + "type": "integer" + }, + "selfLink": { + "description": "[Output Only] Server-defined fully-qualified URL for this resource.", + "type": "string" + }, + "tags": { + "annotations": { + "required": [ + "compute.routes.insert" + ] + }, + "description": "A list of instance tags to which this route applies.", + "items": { + "type": "string" + }, + "type": "array" + }, + "warnings": { + "description": "[Output Only] If potential misconfigurations are detected for this route, this field will be populated with warning messages.", + "items": { + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "RouteList": { + "description": "Contains a list of Route resources.", + "id": "RouteList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Route resources.", + "items": { + "$ref": "Route" + }, + "type": "array" + }, + "kind": { + "default": "compute#routeList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Router": { + "description": "Router resource.", + "id": "Router", + "properties": { + "bgp": { + "$ref": "RouterBgp", + "description": "BGP information specific to this router." + }, + "bgpPeers": { + "description": "BGP information that needs to be configured into the routing stack to establish the BGP peering. It must specify peer ASN and either interface name, IP, or peer IP. Please refer to RFC4273.", + "items": { + "$ref": "RouterBgpPeer" + }, + "type": "array" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "interfaces": { + "description": "Router interfaces. Each interface requires either one linked resource (e.g. linkedVpnTunnel), or IP address and IP address range (e.g. ipRange), or both.", + "items": { + "$ref": "RouterInterface" + }, + "type": "array" + }, + "kind": { + "default": "compute#router", + "description": "[Output Only] Type of resource. Always compute#router for routers.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.routers.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "network": { + "annotations": { + "required": [ + "compute.routers.insert" + ] + }, + "description": "URI of the network to which this router belongs.", + "type": "string" + }, + "region": { + "description": "[Output Only] URI of the region where the router resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "RouterAdvertisedIpRange": { + "description": "Description-tagged IP ranges for the router to advertise.", + "id": "RouterAdvertisedIpRange", + "properties": { + "description": { + "description": "User-specified description for the IP range.", + "type": "string" + }, + "range": { + "description": "The IP range to advertise. The value must be a CIDR-formatted string.", + "type": "string" + } + }, + "type": "object" + }, + "RouterAggregatedList": { + "description": "Contains a list of routers.", + "id": "RouterAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "RoutersScopedList", + "description": "Name of the scope containing this set of routers." + }, + "description": "A list of Router resources.", + "type": "object" + }, + "kind": { + "default": "compute#routerAggregatedList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RouterBgp": { + "id": "RouterBgp", + "properties": { + "advertiseMode": { + "description": "User-specified flag to indicate which mode to use for advertisement.", + "enum": [ + "CUSTOM", + "DEFAULT" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "advertisedGroups": { + "description": "User-specified list of prefix groups to advertise in custom mode. This field can only be populated if advertise_mode is CUSTOM and is advertised to all peers of the router. These groups will be advertised in addition to any specified prefixes. Leave this field blank to advertise no custom groups.", + "items": { + "enum": [ + "ALL_SUBNETS" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + }, + "type": "array" + }, + "advertisedIpRanges": { + "description": "User-specified list of individual IP ranges to advertise in custom mode. This field can only be populated if advertise_mode is CUSTOM and is advertised to all peers of the router. These IP ranges will be advertised in addition to any specified groups. Leave this field blank to advertise no custom IP ranges.", + "items": { + "$ref": "RouterAdvertisedIpRange" + }, + "type": "array" + }, + "asn": { + "description": "Local BGP Autonomous System Number (ASN). Must be an RFC6996 private ASN, either 16-bit or 32-bit. The value will be fixed for this router resource. All VPN tunnels that link to this router will have the same local ASN.", + "format": "uint32", + "type": "integer" + } + }, + "type": "object" + }, + "RouterBgpPeer": { + "id": "RouterBgpPeer", + "properties": { + "advertiseMode": { + "description": "User-specified flag to indicate which mode to use for advertisement.", + "enum": [ + "CUSTOM", + "DEFAULT" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "advertisedGroups": { + "description": "User-specified list of prefix groups to advertise in custom mode. This field can only be populated if advertise_mode is CUSTOM and overrides the list defined for the router (in Bgp message). These groups will be advertised in addition to any specified prefixes. Leave this field blank to advertise no custom groups.", + "items": { + "enum": [ + "ALL_SUBNETS" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + }, + "type": "array" + }, + "advertisedIpRanges": { + "description": "User-specified list of individual IP ranges to advertise in custom mode. This field can only be populated if advertise_mode is CUSTOM and overrides the list defined for the router (in Bgp message). These IP ranges will be advertised in addition to any specified groups. Leave this field blank to advertise no custom IP ranges.", + "items": { + "$ref": "RouterAdvertisedIpRange" + }, + "type": "array" + }, + "advertisedRoutePriority": { + "description": "The priority of routes advertised to this BGP peer. In the case where there is more than one matching route of maximum length, the routes with lowest priority value win.", + "format": "uint32", + "type": "integer" + }, + "interfaceName": { + "description": "Name of the interface the BGP peer is associated with.", + "type": "string" + }, + "ipAddress": { + "description": "IP address of the interface inside Google Cloud Platform. Only IPv4 is supported.", + "type": "string" + }, + "name": { + "description": "Name of this BGP peer. The name must be 1-63 characters long and comply with RFC1035.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "peerAsn": { + "description": "Peer BGP Autonomous System Number (ASN). For VPN use case, this value can be different for every tunnel.", + "format": "uint32", + "type": "integer" + }, + "peerIpAddress": { + "description": "IP address of the BGP interface outside Google cloud. Only IPv4 is supported.", + "type": "string" + } + }, + "type": "object" + }, + "RouterInterface": { + "id": "RouterInterface", + "properties": { + "ipRange": { + "description": "IP address and range of the interface. The IP range must be in the RFC3927 link-local IP space. The value must be a CIDR-formatted string, for example: 169.254.0.1/30. NOTE: Do not truncate the address as it represents the IP address of the interface.", + "type": "string" + }, + "linkedInterconnectAttachment": { + "description": "URI of the linked interconnect attachment. It must be in the same region as the router. Each interface can have at most one linked resource and it could either be a VPN Tunnel or an interconnect attachment.", + "type": "string" + }, + "linkedVpnTunnel": { + "description": "URI of the linked VPN tunnel. It must be in the same region as the router. Each interface can have at most one linked resource and it could either be a VPN Tunnel or an interconnect attachment.", + "type": "string" + }, + "name": { + "description": "Name of this interface entry. The name must be 1-63 characters long and comply with RFC1035.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + } + }, + "type": "object" + }, + "RouterList": { + "description": "Contains a list of Router resources.", + "id": "RouterList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Router resources.", + "items": { + "$ref": "Router" + }, + "type": "array" + }, + "kind": { + "default": "compute#routerList", + "description": "[Output Only] Type of resource. Always compute#router for routers.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RouterStatus": { + "id": "RouterStatus", + "properties": { + "bestRoutes": { + "description": "Best routes for this router's network.", + "items": { + "$ref": "Route" + }, + "type": "array" + }, + "bestRoutesForRouter": { + "description": "Best routes learned by this router.", + "items": { + "$ref": "Route" + }, + "type": "array" + }, + "bgpPeerStatus": { + "items": { + "$ref": "RouterStatusBgpPeerStatus" + }, + "type": "array" + }, + "network": { + "description": "URI of the network to which this router belongs.", + "type": "string" + } + }, + "type": "object" + }, + "RouterStatusBgpPeerStatus": { + "id": "RouterStatusBgpPeerStatus", + "properties": { + "advertisedRoutes": { + "description": "Routes that were advertised to the remote BGP peer", + "items": { + "$ref": "Route" + }, + "type": "array" + }, + "ipAddress": { + "description": "IP address of the local BGP interface.", + "type": "string" + }, + "linkedVpnTunnel": { + "description": "URL of the VPN tunnel that this BGP peer controls.", + "type": "string" + }, + "name": { + "description": "Name of this BGP peer. Unique within the Routers resource.", + "type": "string" + }, + "numLearnedRoutes": { + "description": "Number of routes learned from the remote BGP Peer.", + "format": "uint32", + "type": "integer" + }, + "peerIpAddress": { + "description": "IP address of the remote BGP interface.", + "type": "string" + }, + "state": { + "description": "BGP state as specified in RFC1771.", + "type": "string" + }, + "status": { + "description": "Status of the BGP peer: {UP, DOWN}", + "enum": [ + "DOWN", + "UNKNOWN", + "UP" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "uptime": { + "description": "Time this session has been up. Format: 14 years, 51 weeks, 6 days, 23 hours, 59 minutes, 59 seconds", + "type": "string" + }, + "uptimeSeconds": { + "description": "Time this session has been up, in seconds. Format: 145", + "type": "string" + } + }, + "type": "object" + }, + "RouterStatusResponse": { + "id": "RouterStatusResponse", + "properties": { + "kind": { + "default": "compute#routerStatusResponse", + "description": "Type of resource.", + "type": "string" + }, + "result": { + "$ref": "RouterStatus" + } + }, + "type": "object" + }, + "RoutersPreviewResponse": { + "id": "RoutersPreviewResponse", + "properties": { + "resource": { + "$ref": "Router", + "description": "Preview of given router." + } + }, + "type": "object" + }, + "RoutersScopedList": { + "id": "RoutersScopedList", + "properties": { + "routers": { + "description": "A list of routers contained in this scope.", + "items": { + "$ref": "Router" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of routers when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SSLHealthCheck": { + "id": "SSLHealthCheck", + "properties": { + "port": { + "description": "The TCP port number for the health check request. The default value is 443. Valid values are 1 through 65535.", + "format": "int32", + "type": "integer" + }, + "portName": { + "description": "Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name are defined, port takes precedence.", + "type": "string" + }, + "proxyHeader": { + "description": "Specifies the type of proxy header to append before sending data to the backend, either NONE or PROXY_V1. The default is NONE.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "request": { + "description": "The application data to send once the SSL connection has been established (default value is empty). If both request and response are empty, the connection establishment alone will indicate health. The request data can only be ASCII.", + "type": "string" + }, + "response": { + "description": "The bytes to match against the beginning of the response data. If left empty (the default value), any response will indicate health. The response data can only be ASCII.", + "type": "string" + } + }, + "type": "object" + }, + "Scheduling": { + "description": "Sets the scheduling options for an Instance.", + "id": "Scheduling", + "properties": { + "automaticRestart": { + "description": "Specifies whether the instance should be automatically restarted if it is terminated by Compute Engine (not terminated by a user). You can only set the automatic restart option for standard instances. Preemptible instances cannot be automatically restarted.\n\nBy default, this is set to true so an instance is automatically restarted if it is terminated by Compute Engine.", + "type": "boolean" + }, + "onHostMaintenance": { + "description": "Defines the maintenance behavior for this instance. For standard instances, the default behavior is MIGRATE. For preemptible instances, the default and only possible behavior is TERMINATE. For more information, see Setting Instance Scheduling Options.", + "enum": [ + "MIGRATE", + "TERMINATE" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "preemptible": { + "description": "Defines whether the instance is preemptible. This can only be set during instance creation, it cannot be set or changed after the instance has been created.", + "type": "boolean" + } + }, + "type": "object" + }, + "SerialPortOutput": { + "description": "An instance's serial console output.", + "id": "SerialPortOutput", + "properties": { + "contents": { + "description": "[Output Only] The contents of the console output.", + "type": "string" + }, + "kind": { + "default": "compute#serialPortOutput", + "description": "[Output Only] Type of the resource. Always compute#serialPortOutput for serial port output.", + "type": "string" + }, + "next": { + "description": "[Output Only] The position of the next byte of content from the serial console output. Use this value in the next request as the start parameter.", + "format": "int64", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "start": { + "description": "The starting byte position of the output that was returned. This should match the start parameter sent with the request. If the serial console output exceeds the size of the buffer, older output will be overwritten by newer content and the start values will be mismatched.", + "format": "int64", + "type": "string" + } + }, + "type": "object" + }, + "ServiceAccount": { + "description": "A service account.", + "id": "ServiceAccount", + "properties": { + "email": { + "description": "Email address of the service account.", + "type": "string" + }, + "scopes": { + "description": "The list of scopes to be made available for this service account.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "Snapshot": { + "description": "A persistent disk snapshot resource. (== resource_for beta.snapshots ==) (== resource_for v1.snapshots ==)", + "id": "Snapshot", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "diskSizeGb": { + "description": "[Output Only] Size of the snapshot, specified in GB.", + "format": "int64", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#snapshot", + "description": "[Output Only] Type of the resource. Always compute#snapshot for Snapshot resources.", + "type": "string" + }, + "labelFingerprint": { + "description": "A fingerprint for the labels being applied to this snapshot, which is essentially a hash of the labels set used for optimistic locking. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash in order to update or change labels.\n\nTo see the latest fingerprint, make a get() request to retrieve a snapshot.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Labels to apply to this snapshot. These can be later modified by the setLabels method. Label values may be empty.", + "type": "object" + }, + "licenseCodes": { + "description": "Integer license codes indicating which licenses are attached to this snapshot.", + "items": { + "format": "int64", + "type": "string" + }, + "type": "array" + }, + "licenses": { + "description": "[Output Only] A list of public visible licenses that apply to this snapshot. This can be because the original image had licenses attached (such as a Windows image).", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "description": "Name of the resource; provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "snapshotEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "Encrypts the snapshot using a customer-supplied encryption key.\n\nAfter you encrypt a snapshot using a customer-supplied key, you must provide the same key if you use the image later For example, you must provide the encryption key when you create a disk from the encrypted snapshot in a future request.\n\nCustomer-supplied encryption keys do not protect access to metadata of the disk.\n\nIf you do not provide an encryption key when creating the snapshot, then the snapshot will be encrypted using an automatically generated key and you do not need to provide a key to use the snapshot later." + }, + "sourceDisk": { + "description": "[Output Only] The source disk used to create this snapshot.", + "type": "string" + }, + "sourceDiskEncryptionKey": { + "$ref": "CustomerEncryptionKey", + "description": "The customer-supplied encryption key of the source disk. Required if the source disk is protected by a customer-supplied encryption key." + }, + "sourceDiskId": { + "description": "[Output Only] The ID value of the disk used to create this snapshot. This value may be used to determine whether the snapshot was taken from the current or a previous instance of a given disk name.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the snapshot. This can be CREATING, DELETING, FAILED, READY, or UPLOADING.", + "enum": [ + "CREATING", + "DELETING", + "FAILED", + "READY", + "UPLOADING" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "storageBytes": { + "description": "[Output Only] A size of the storage used by the snapshot. As snapshots share storage, this number is expected to change with snapshot creation/deletion.", + "format": "int64", + "type": "string" + }, + "storageBytesStatus": { + "description": "[Output Only] An indicator whether storageBytes is in a stable state or it is being adjusted as a result of shared storage reallocation. This status can either be UPDATING, meaning the size of the snapshot is being updated, or UP_TO_DATE, meaning the size of the snapshot is up-to-date.", + "enum": [ + "UPDATING", + "UP_TO_DATE" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "SnapshotList": { + "description": "Contains a list of Snapshot resources.", + "id": "SnapshotList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Snapshot resources.", + "items": { + "$ref": "Snapshot" + }, + "type": "array" + }, + "kind": { + "default": "compute#snapshotList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SslCertificate": { + "description": "An SslCertificate resource. This resource provides a mechanism to upload an SSL key and certificate to the load balancer to serve secure connections from the user. (== resource_for beta.sslCertificates ==) (== resource_for v1.sslCertificates ==)", + "id": "SslCertificate", + "properties": { + "certificate": { + "description": "A local certificate file. The certificate must be in PEM format. The certificate chain must be no greater than 5 certs long. The chain must include at least one intermediate cert.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#sslCertificate", + "description": "[Output Only] Type of the resource. Always compute#sslCertificate for SSL certificates.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "privateKey": { + "description": "A write-only private key in PEM format. Only insert requests will include this field.", + "type": "string" + }, + "selfLink": { + "description": "[Output only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "SslCertificateList": { + "description": "Contains a list of SslCertificate resources.", + "id": "SslCertificateList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of SslCertificate resources.", + "items": { + "$ref": "SslCertificate" + }, + "type": "array" + }, + "kind": { + "default": "compute#sslCertificateList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SslPoliciesList": { + "id": "SslPoliciesList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of SslPolicy resources.", + "items": { + "$ref": "SslPolicy" + }, + "type": "array" + }, + "kind": { + "default": "compute#sslPoliciesList", + "description": "[Output Only] Type of the resource. Always compute#sslPoliciesList for lists of sslPolicies.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SslPoliciesListAvailableFeaturesResponse": { + "id": "SslPoliciesListAvailableFeaturesResponse", + "properties": { + "features": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "SslPolicy": { + "description": "A SSL policy specifies the server-side support for SSL features. This can be attached to a TargetHttpsProxy or a TargetSslProxy. This affects connections between clients and the HTTPS or SSL proxy load balancer. They do not affect the connection between the load balancers and the backends.", + "id": "SslPolicy", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "customFeatures": { + "description": "A list of features enabled when the selected profile is CUSTOM. The\n- method returns the set of features that can be specified in this list. This field must be empty if the profile is not CUSTOM.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "enabledFeatures": { + "description": "[Output Only] The list of features enabled in the SSL policy.", + "items": { + "type": "string" + }, + "type": "array" + }, + "fingerprint": { + "description": "Fingerprint of this resource. A hash of the contents stored in this object. This field is used in optimistic locking. This field will be ignored when inserting a SslPolicy. An up-to-date fingerprint must be provided in order to update the SslPolicy.", + "format": "byte", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#sslPolicy", + "description": "[Output only] Type of the resource. Always compute#sslPolicyfor SSL policies.", + "type": "string" + }, + "minTlsVersion": { + "description": "The minimum version of SSL protocol that can be used by the clients to establish a connection with the load balancer. This can be one of TLS_1_0, TLS_1_1, TLS_1_2.", + "enum": [ + "TLS_1_0", + "TLS_1_1", + "TLS_1_2" + ], + "enumDescriptions": [ + "", + "", + "" + ], + "type": "string" + }, + "name": { + "description": "Name of the resource. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "profile": { + "description": "Profile specifies the set of SSL features that can be used by the load balancer when negotiating SSL with clients. This can be one of COMPATIBLE, MODERN, RESTRICTED, or CUSTOM. If using CUSTOM, the set of SSL features to enable must be specified in the customFeatures field.", + "enum": [ + "COMPATIBLE", + "CUSTOM", + "MODERN", + "RESTRICTED" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "warnings": { + "description": "[Output Only] If potential misconfigurations are detected for this SSL policy, this field will be populated with warning messages.", + "items": { + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "SslPolicyReference": { + "id": "SslPolicyReference", + "properties": { + "sslPolicy": { + "description": "URL of the SSL policy resource. Set this to empty string to clear any existing SSL policy associated with the target proxy resource.", + "type": "string" + } + }, + "type": "object" + }, + "Subnetwork": { + "description": "A Subnetwork resource. (== resource_for beta.subnetworks ==) (== resource_for v1.subnetworks ==)", + "id": "Subnetwork", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource. This field can be set only at resource creation time.", + "type": "string" + }, + "enableFlowLogs": { + "description": "Whether to enable flow logging for this subnetwork.", + "type": "boolean" + }, + "fingerprint": { + "description": "Fingerprint of this resource. A hash of the contents stored in this object. This field is used in optimistic locking. This field will be ignored when inserting a Subnetwork. An up-to-date fingerprint must be provided in order to update the Subnetwork.", + "format": "byte", + "type": "string" + }, + "gatewayAddress": { + "description": "[Output Only] The gateway address for default routes to reach destination addresses outside this subnetwork.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "ipCidrRange": { + "description": "The range of internal addresses that are owned by this subnetwork. Provide this property when you create the subnetwork. For example, 10.0.0.0/8 or 192.168.0.0/16. Ranges must be unique and non-overlapping within a network. Only IPv4 is supported. This field can be set only at resource creation time.", + "type": "string" + }, + "kind": { + "default": "compute#subnetwork", + "description": "[Output Only] Type of the resource. Always compute#subnetwork for Subnetwork resources.", + "type": "string" + }, + "name": { + "description": "The name of the resource, provided by the client when initially creating the resource. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "network": { + "description": "The URL of the network to which this subnetwork belongs, provided by the client when initially creating the subnetwork. Only networks that are in the distributed mode can have subnetworks. This field can be set only at resource creation time.", + "type": "string" + }, + "privateIpGoogleAccess": { + "description": "Whether the VMs in this subnet can access Google services without assigned external IP addresses. This field can be both set at resource creation time and updated using setPrivateIpGoogleAccess.", + "type": "boolean" + }, + "region": { + "description": "URL of the region where the Subnetwork resides. This field can be set only at resource creation time.", + "type": "string" + }, + "secondaryIpRanges": { + "description": "An array of configurations for secondary IP ranges for VM instances contained in this subnetwork. The primary IP of such VM must belong to the primary ipCidrRange of the subnetwork. The alias IPs may belong to either primary or secondary ranges.", + "items": { + "$ref": "SubnetworkSecondaryRange" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + } + }, + "type": "object" + }, + "SubnetworkAggregatedList": { + "id": "SubnetworkAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "SubnetworksScopedList", + "description": "Name of the scope containing this set of Subnetworks." + }, + "description": "A list of SubnetworksScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#subnetworkAggregatedList", + "description": "[Output Only] Type of resource. Always compute#subnetworkAggregatedList for aggregated lists of subnetworks.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SubnetworkList": { + "description": "Contains a list of Subnetwork resources.", + "id": "SubnetworkList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Subnetwork resources.", + "items": { + "$ref": "Subnetwork" + }, + "type": "array" + }, + "kind": { + "default": "compute#subnetworkList", + "description": "[Output Only] Type of resource. Always compute#subnetworkList for lists of subnetworks.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SubnetworkSecondaryRange": { + "description": "Represents a secondary IP range of a subnetwork.", + "id": "SubnetworkSecondaryRange", + "properties": { + "ipCidrRange": { + "description": "The range of IP addresses belonging to this subnetwork secondary range. Provide this property when you create the subnetwork. Ranges must be unique and non-overlapping with all primary and secondary IP ranges within a network. Only IPv4 is supported.", + "type": "string" + }, + "rangeName": { + "description": "The name associated with this subnetwork secondary range, used when adding an alias IP range to a VM instance. The name must be 1-63 characters long, and comply with RFC1035. The name must be unique within the subnetwork.", + "type": "string" + } + }, + "type": "object" + }, + "SubnetworksExpandIpCidrRangeRequest": { + "id": "SubnetworksExpandIpCidrRangeRequest", + "properties": { + "ipCidrRange": { + "description": "The IP (in CIDR format or netmask) of internal addresses that are legal on this Subnetwork. This range should be disjoint from other subnetworks within this network. This range can only be larger than (i.e. a superset of) the range previously defined before the update.", + "type": "string" + } + }, + "type": "object" + }, + "SubnetworksScopedList": { + "id": "SubnetworksScopedList", + "properties": { + "subnetworks": { + "description": "A list of subnetworks contained in this scope.", + "items": { + "$ref": "Subnetwork" + }, + "type": "array" + }, + "warning": { + "description": "An informational warning that appears when the list of addresses is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "SubnetworksSetPrivateIpGoogleAccessRequest": { + "id": "SubnetworksSetPrivateIpGoogleAccessRequest", + "properties": { + "privateIpGoogleAccess": { + "type": "boolean" + } + }, + "type": "object" + }, + "TCPHealthCheck": { + "id": "TCPHealthCheck", + "properties": { + "port": { + "description": "The TCP port number for the health check request. The default value is 80. Valid values are 1 through 65535.", + "format": "int32", + "type": "integer" + }, + "portName": { + "description": "Port name as defined in InstanceGroup#NamedPort#name. If both port and port_name are defined, port takes precedence.", + "type": "string" + }, + "proxyHeader": { + "description": "Specifies the type of proxy header to append before sending data to the backend, either NONE or PROXY_V1. The default is NONE.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "request": { + "description": "The application data to send once the TCP connection has been established (default value is empty). If both request and response are empty, the connection establishment alone will indicate health. The request data can only be ASCII.", + "type": "string" + }, + "response": { + "description": "The bytes to match against the beginning of the response data. If left empty (the default value), any response will indicate health. The response data can only be ASCII.", + "type": "string" + } + }, + "type": "object" + }, + "Tags": { + "description": "A set of instance tags.", + "id": "Tags", + "properties": { + "fingerprint": { + "description": "Specifies a fingerprint for this request, which is essentially a hash of the tags' contents and used for optimistic locking. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update tags. You must always provide an up-to-date fingerprint hash in order to update or change tags.\n\nTo see the latest fingerprint, make get() request to the instance.", + "format": "byte", + "type": "string" + }, + "items": { + "description": "An array of tags. Each tag must be 1-63 characters long, and comply with RFC1035.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetHttpProxy": { + "description": "A TargetHttpProxy resource. This resource defines an HTTP proxy. (== resource_for beta.targetHttpProxies ==) (== resource_for v1.targetHttpProxies ==)", + "id": "TargetHttpProxy", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#targetHttpProxy", + "description": "[Output Only] Type of resource. Always compute#targetHttpProxy for target HTTP proxies.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "urlMap": { + "description": "URL to the UrlMap resource that defines the mapping from URL to the BackendService.", + "type": "string" + } + }, + "type": "object" + }, + "TargetHttpProxyList": { + "description": "A list of TargetHttpProxy resources.", + "id": "TargetHttpProxyList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetHttpProxy resources.", + "items": { + "$ref": "TargetHttpProxy" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetHttpProxyList", + "description": "Type of resource. Always compute#targetHttpProxyList for lists of target HTTP proxies.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetHttpsProxiesSetSslCertificatesRequest": { + "id": "TargetHttpsProxiesSetSslCertificatesRequest", + "properties": { + "sslCertificates": { + "description": "New set of SslCertificate resources to associate with this TargetHttpsProxy resource. Currently exactly one SslCertificate resource must be specified.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetHttpsProxy": { + "description": "A TargetHttpsProxy resource. This resource defines an HTTPS proxy. (== resource_for beta.targetHttpsProxies ==) (== resource_for v1.targetHttpsProxies ==)", + "id": "TargetHttpsProxy", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#targetHttpsProxy", + "description": "[Output Only] Type of resource. Always compute#targetHttpsProxy for target HTTPS proxies.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sslCertificates": { + "description": "URLs to SslCertificate resources that are used to authenticate connections between users and the load balancer. Currently, exactly one SSL certificate must be specified.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sslPolicy": { + "description": "URL of SslPolicy resource that will be associated with the TargetHttpsProxy resource. If not set, the TargetHttpsProxy resource will not have any SSL policy configured.", + "type": "string" + }, + "urlMap": { + "description": "A fully-qualified or valid partial URL to the UrlMap resource that defines the mapping from URL to the BackendService. For example, the following are all valid URLs for specifying a URL map: \n- https://www.googleapis.compute/v1/projects/project/global/urlMaps/url-map \n- projects/project/global/urlMaps/url-map \n- global/urlMaps/url-map", + "type": "string" + } + }, + "type": "object" + }, + "TargetHttpsProxyList": { + "description": "Contains a list of TargetHttpsProxy resources.", + "id": "TargetHttpsProxyList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetHttpsProxy resources.", + "items": { + "$ref": "TargetHttpsProxy" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetHttpsProxyList", + "description": "Type of resource. Always compute#targetHttpsProxyList for lists of target HTTPS proxies.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetInstance": { + "description": "A TargetInstance resource. This resource defines an endpoint instance that terminates traffic of certain protocols. (== resource_for beta.targetInstances ==) (== resource_for v1.targetInstances ==)", + "id": "TargetInstance", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "instance": { + "description": "A URL to the virtual machine instance that handles traffic for this target instance. When creating a target instance, you can provide the fully-qualified URL or a valid partial URL to the desired virtual machine. For example, the following are all valid URLs: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/instances/instance \n- projects/project/zones/zone/instances/instance \n- zones/zone/instances/instance", + "type": "string" + }, + "kind": { + "default": "compute#targetInstance", + "description": "[Output Only] The type of the resource. Always compute#targetInstance for target instances.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "natPolicy": { + "description": "NAT option controlling how IPs are NAT'ed to the instance. Currently only NO_NAT (default value) is supported.", + "enum": [ + "NO_NAT" + ], + "enumDescriptions": [ + "" + ], + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "zone": { + "description": "[Output Only] URL of the zone where the target instance resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + } + }, + "type": "object" + }, + "TargetInstanceAggregatedList": { + "id": "TargetInstanceAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "TargetInstancesScopedList", + "description": "Name of the scope containing this set of target instances." + }, + "description": "A list of TargetInstance resources.", + "type": "object" + }, + "kind": { + "default": "compute#targetInstanceAggregatedList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetInstanceList": { + "description": "Contains a list of TargetInstance resources.", + "id": "TargetInstanceList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetInstance resources.", + "items": { + "$ref": "TargetInstance" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetInstanceList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetInstancesScopedList": { + "id": "TargetInstancesScopedList", + "properties": { + "targetInstances": { + "description": "A list of target instances contained in this scope.", + "items": { + "$ref": "TargetInstance" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of addresses when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetPool": { + "description": "A TargetPool resource. This resource defines a pool of instances, an associated HttpHealthCheck resource, and the fallback target pool. (== resource_for beta.targetPools ==) (== resource_for v1.targetPools ==)", + "id": "TargetPool", + "properties": { + "backupPool": { + "description": "This field is applicable only when the containing target pool is serving a forwarding rule as the primary pool, and its failoverRatio field is properly set to a value between [0, 1].\n\nbackupPool and failoverRatio together define the fallback behavior of the primary target pool: if the ratio of the healthy instances in the primary pool is at or below failoverRatio, traffic arriving at the load-balanced IP will be directed to the backup pool.\n\nIn case where failoverRatio and backupPool are not set, or all the instances in the backup pool are unhealthy, the traffic will be directed back to the primary pool in the \"force\" mode, where traffic will be spread to the healthy instances with the best effort, or to all instances when no instance is healthy.", + "type": "string" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "failoverRatio": { + "description": "This field is applicable only when the containing target pool is serving a forwarding rule as the primary pool (i.e., not as a backup pool to some other target pool). The value of the field must be in [0, 1].\n\nIf set, backupPool must also be set. They together define the fallback behavior of the primary target pool: if the ratio of the healthy instances in the primary pool is at or below this number, traffic arriving at the load-balanced IP will be directed to the backup pool.\n\nIn case where failoverRatio is not set or all the instances in the backup pool are unhealthy, the traffic will be directed back to the primary pool in the \"force\" mode, where traffic will be spread to the healthy instances with the best effort, or to all instances when no instance is healthy.", + "format": "float", + "type": "number" + }, + "healthChecks": { + "description": "The URL of the HttpHealthCheck resource. A member instance in this pool is considered healthy if and only if the health checks pass. An empty list means all member instances will be considered healthy at all times. Only HttpHealthChecks are supported. Only one health check may be specified.", + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "instances": { + "description": "A list of resource URLs to the virtual machine instances serving this pool. They must live in zones contained in the same region as this pool.", + "items": { + "type": "string" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetPool", + "description": "[Output Only] Type of the resource. Always compute#targetPool for target pools.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the target pool resides.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sessionAffinity": { + "description": "Sesssion affinity option, must be one of the following values:\nNONE: Connections from the same client IP may go to any instance in the pool.\nCLIENT_IP: Connections from the same client IP will go to the same instance in the pool while that instance remains healthy.\nCLIENT_IP_PROTO: Connections from the same client IP with the same IP protocol will go to the same instance in the pool while that instance remains healthy.", + "enum": [ + "CLIENT_IP", + "CLIENT_IP_PORT_PROTO", + "CLIENT_IP_PROTO", + "GENERATED_COOKIE", + "NONE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "TargetPoolAggregatedList": { + "id": "TargetPoolAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "TargetPoolsScopedList", + "description": "Name of the scope containing this set of target pools." + }, + "description": "A list of TargetPool resources.", + "type": "object" + }, + "kind": { + "default": "compute#targetPoolAggregatedList", + "description": "[Output Only] Type of resource. Always compute#targetPoolAggregatedList for aggregated lists of target pools.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetPoolInstanceHealth": { + "id": "TargetPoolInstanceHealth", + "properties": { + "healthStatus": { + "items": { + "$ref": "HealthStatus" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetPoolInstanceHealth", + "description": "[Output Only] Type of resource. Always compute#targetPoolInstanceHealth when checking the health of an instance.", + "type": "string" + } + }, + "type": "object" + }, + "TargetPoolList": { + "description": "Contains a list of TargetPool resources.", + "id": "TargetPoolList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetPool resources.", + "items": { + "$ref": "TargetPool" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetPoolList", + "description": "[Output Only] Type of resource. Always compute#targetPoolList for lists of target pools.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetPoolsAddHealthCheckRequest": { + "id": "TargetPoolsAddHealthCheckRequest", + "properties": { + "healthChecks": { + "description": "The HttpHealthCheck to add to the target pool.", + "items": { + "$ref": "HealthCheckReference" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetPoolsAddInstanceRequest": { + "id": "TargetPoolsAddInstanceRequest", + "properties": { + "instances": { + "description": "A full or partial URL to an instance to add to this target pool. This can be a full or partial URL. For example, the following are valid URLs: \n- https://www.googleapis.com/compute/v1/projects/project-id/zones/zone/instances/instance-name \n- projects/project-id/zones/zone/instances/instance-name \n- zones/zone/instances/instance-name", + "items": { + "$ref": "InstanceReference" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetPoolsRemoveHealthCheckRequest": { + "id": "TargetPoolsRemoveHealthCheckRequest", + "properties": { + "healthChecks": { + "description": "Health check URL to be removed. This can be a full or valid partial URL. For example, the following are valid URLs: \n- https://www.googleapis.com/compute/beta/projects/project/global/httpHealthChecks/health-check \n- projects/project/global/httpHealthChecks/health-check \n- global/httpHealthChecks/health-check", + "items": { + "$ref": "HealthCheckReference" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetPoolsRemoveInstanceRequest": { + "id": "TargetPoolsRemoveInstanceRequest", + "properties": { + "instances": { + "description": "URLs of the instances to be removed from target pool.", + "items": { + "$ref": "InstanceReference" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetPoolsScopedList": { + "id": "TargetPoolsScopedList", + "properties": { + "targetPools": { + "description": "A list of target pools contained in this scope.", + "items": { + "$ref": "TargetPool" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of addresses when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetReference": { + "id": "TargetReference", + "properties": { + "target": { + "type": "string" + } + }, + "type": "object" + }, + "TargetSslProxiesSetBackendServiceRequest": { + "id": "TargetSslProxiesSetBackendServiceRequest", + "properties": { + "service": { + "description": "The URL of the new BackendService resource for the targetSslProxy.", + "type": "string" + } + }, + "type": "object" + }, + "TargetSslProxiesSetProxyHeaderRequest": { + "id": "TargetSslProxiesSetProxyHeaderRequest", + "properties": { + "proxyHeader": { + "description": "The new type of proxy header to append before sending data to the backend. NONE or PROXY_V1 are allowed.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "TargetSslProxiesSetSslCertificatesRequest": { + "id": "TargetSslProxiesSetSslCertificatesRequest", + "properties": { + "sslCertificates": { + "description": "New set of URLs to SslCertificate resources to associate with this TargetSslProxy. Currently exactly one ssl certificate must be specified.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetSslProxy": { + "description": "A TargetSslProxy resource. This resource defines an SSL proxy. (== resource_for beta.targetSslProxies ==) (== resource_for v1.targetSslProxies ==)", + "id": "TargetSslProxy", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#targetSslProxy", + "description": "[Output Only] Type of the resource. Always compute#targetSslProxy for target SSL proxies.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "proxyHeader": { + "description": "Specifies the type of proxy header to append before sending data to the backend, either NONE or PROXY_V1. The default is NONE.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "service": { + "description": "URL to the BackendService resource.", + "type": "string" + }, + "sslCertificates": { + "description": "URLs to SslCertificate resources that are used to authenticate connections to Backends. Currently exactly one SSL certificate must be specified.", + "items": { + "type": "string" + }, + "type": "array" + }, + "sslPolicy": { + "description": "URL of SslPolicy resource that will be associated with the TargetSslProxy resource. If not set, the TargetSslProxy resource will not have any SSL policy configured.", + "type": "string" + } + }, + "type": "object" + }, + "TargetSslProxyList": { + "description": "Contains a list of TargetSslProxy resources.", + "id": "TargetSslProxyList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetSslProxy resources.", + "items": { + "$ref": "TargetSslProxy" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetSslProxyList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetTcpProxiesSetBackendServiceRequest": { + "id": "TargetTcpProxiesSetBackendServiceRequest", + "properties": { + "service": { + "description": "The URL of the new BackendService resource for the targetTcpProxy.", + "type": "string" + } + }, + "type": "object" + }, + "TargetTcpProxiesSetProxyHeaderRequest": { + "id": "TargetTcpProxiesSetProxyHeaderRequest", + "properties": { + "proxyHeader": { + "description": "The new type of proxy header to append before sending data to the backend. NONE or PROXY_V1 are allowed.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "TargetTcpProxy": { + "description": "A TargetTcpProxy resource. This resource defines a TCP proxy. (== resource_for beta.targetTcpProxies ==) (== resource_for v1.targetTcpProxies ==)", + "id": "TargetTcpProxy", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#targetTcpProxy", + "description": "[Output Only] Type of the resource. Always compute#targetTcpProxy for target TCP proxies.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "proxyHeader": { + "description": "Specifies the type of proxy header to append before sending data to the backend, either NONE or PROXY_V1. The default is NONE.", + "enum": [ + "NONE", + "PROXY_V1" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "service": { + "description": "URL to the BackendService resource.", + "type": "string" + } + }, + "type": "object" + }, + "TargetTcpProxyList": { + "description": "Contains a list of TargetTcpProxy resources.", + "id": "TargetTcpProxyList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetTcpProxy resources.", + "items": { + "$ref": "TargetTcpProxy" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetTcpProxyList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetVpnGateway": { + "description": "Represents a Target VPN gateway resource. (== resource_for beta.targetVpnGateways ==) (== resource_for v1.targetVpnGateways ==)", + "id": "TargetVpnGateway", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "forwardingRules": { + "description": "[Output Only] A list of URLs to the ForwardingRule resources. ForwardingRules are created using compute.forwardingRules.insert and associated to a VPN gateway.", + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#targetVpnGateway", + "description": "[Output Only] Type of resource. Always compute#targetVpnGateway for target VPN gateways.", + "type": "string" + }, + "name": { + "annotations": { + "required": [ + "compute.targetVpnGateways.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "network": { + "annotations": { + "required": [ + "compute.targetVpnGateways.insert" + ] + }, + "description": "URL of the network to which this VPN gateway is attached. Provided by the client when the VPN gateway is created.", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the target VPN gateway resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the VPN gateway.", + "enum": [ + "CREATING", + "DELETING", + "FAILED", + "READY" + ], + "enumDescriptions": [ + "", + "", + "", + "" + ], + "type": "string" + }, + "tunnels": { + "description": "[Output Only] A list of URLs to VpnTunnel resources. VpnTunnels are created using compute.vpntunnels.insert method and associated to a VPN gateway.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "TargetVpnGatewayAggregatedList": { + "id": "TargetVpnGatewayAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "TargetVpnGatewaysScopedList", + "description": "[Output Only] Name of the scope containing this set of target VPN gateways." + }, + "description": "A list of TargetVpnGateway resources.", + "type": "object" + }, + "kind": { + "default": "compute#targetVpnGatewayAggregatedList", + "description": "[Output Only] Type of resource. Always compute#targetVpnGateway for target VPN gateways.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetVpnGatewayList": { + "description": "Contains a list of TargetVpnGateway resources.", + "id": "TargetVpnGatewayList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of TargetVpnGateway resources.", + "items": { + "$ref": "TargetVpnGateway" + }, + "type": "array" + }, + "kind": { + "default": "compute#targetVpnGatewayList", + "description": "[Output Only] Type of resource. Always compute#targetVpnGateway for target VPN gateways.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TargetVpnGatewaysScopedList": { + "id": "TargetVpnGatewaysScopedList", + "properties": { + "targetVpnGateways": { + "description": "[Output Only] A list of target vpn gateways contained in this scope.", + "items": { + "$ref": "TargetVpnGateway" + }, + "type": "array" + }, + "warning": { + "description": "[Output Only] Informational warning which replaces the list of addresses when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "TestFailure": { + "id": "TestFailure", + "properties": { + "actualService": { + "type": "string" + }, + "expectedService": { + "type": "string" + }, + "host": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "type": "object" + }, + "TestPermissionsRequest": { + "id": "TestPermissionsRequest", + "properties": { + "permissions": { + "description": "The set of permissions to check for the 'resource'. Permissions with wildcards (such as '*' or 'storage.*') are not allowed.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "TestPermissionsResponse": { + "id": "TestPermissionsResponse", + "properties": { + "permissions": { + "description": "A subset of `TestPermissionsRequest.permissions` that the caller is allowed.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "UrlMap": { + "description": "A UrlMap resource. This resource defines the mapping from URL to the BackendService resource, based on the \"longest-match\" of the URL's host and path.", + "id": "UrlMap", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "defaultService": { + "description": "The URL of the BackendService resource if none of the hostRules match.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "fingerprint": { + "description": "Fingerprint of this resource. A hash of the contents stored in this object. This field is used in optimistic locking. This field will be ignored when inserting a UrlMap. An up-to-date fingerprint must be provided in order to update the UrlMap.", + "format": "byte", + "type": "string" + }, + "hostRules": { + "description": "The list of HostRules to use against the URL.", + "items": { + "$ref": "HostRule" + }, + "type": "array" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#urlMap", + "description": "[Output Only] Type of the resource. Always compute#urlMaps for url maps.", + "type": "string" + }, + "name": { + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "pathMatchers": { + "description": "The list of named PathMatchers to use against the URL.", + "items": { + "$ref": "PathMatcher" + }, + "type": "array" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "tests": { + "description": "The list of expected URL mapping tests. Request to update this UrlMap will succeed only if all of the test cases pass. You can specify a maximum of 100 tests per UrlMap.", + "items": { + "$ref": "UrlMapTest" + }, + "type": "array" + } + }, + "type": "object" + }, + "UrlMapList": { + "description": "Contains a list of UrlMap resources.", + "id": "UrlMapList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of UrlMap resources.", + "items": { + "$ref": "UrlMap" + }, + "type": "array" + }, + "kind": { + "default": "compute#urlMapList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "UrlMapReference": { + "id": "UrlMapReference", + "properties": { + "urlMap": { + "type": "string" + } + }, + "type": "object" + }, + "UrlMapTest": { + "description": "Message for the expected URL mappings.", + "id": "UrlMapTest", + "properties": { + "description": { + "description": "Description of this test case.", + "type": "string" + }, + "host": { + "description": "Host portion of the URL.", + "type": "string" + }, + "path": { + "description": "Path portion of the URL.", + "type": "string" + }, + "service": { + "description": "Expected BackendService resource the given URL should be mapped to.", + "type": "string" + } + }, + "type": "object" + }, + "UrlMapValidationResult": { + "description": "Message representing the validation result for a UrlMap.", + "id": "UrlMapValidationResult", + "properties": { + "loadErrors": { + "items": { + "type": "string" + }, + "type": "array" + }, + "loadSucceeded": { + "description": "Whether the given UrlMap can be successfully loaded. If false, 'loadErrors' indicates the reasons.", + "type": "boolean" + }, + "testFailures": { + "items": { + "$ref": "TestFailure" + }, + "type": "array" + }, + "testPassed": { + "description": "If successfully loaded, this field indicates whether the test passed. If false, 'testFailures's indicate the reason of failure.", + "type": "boolean" + } + }, + "type": "object" + }, + "UrlMapsValidateRequest": { + "id": "UrlMapsValidateRequest", + "properties": { + "resource": { + "$ref": "UrlMap", + "description": "Content of the UrlMap to be validated." + } + }, + "type": "object" + }, + "UrlMapsValidateResponse": { + "id": "UrlMapsValidateResponse", + "properties": { + "result": { + "$ref": "UrlMapValidationResult" + } + }, + "type": "object" + }, + "UsageExportLocation": { + "description": "The location in Cloud Storage and naming method of the daily usage report. Contains bucket_name and report_name prefix.", + "id": "UsageExportLocation", + "properties": { + "bucketName": { + "description": "The name of an existing bucket in Cloud Storage where the usage report object is stored. The Google Service Account is granted write access to this bucket. This can either be the bucket name by itself, such as example-bucket, or the bucket name with gs:// or https://storage.googleapis.com/ in front of it, such as gs://example-bucket.", + "type": "string" + }, + "reportNamePrefix": { + "description": "An optional prefix for the name of the usage report object stored in bucketName. If not supplied, defaults to usage. The report is stored as a CSV file named report_name_prefix_gce_YYYYMMDD.csv where YYYYMMDD is the day of the usage according to Pacific Time. If you supply a prefix, it should conform to Cloud Storage object naming conventions.", + "type": "string" + } + }, + "type": "object" + }, + "VpnTunnel": { + "description": "VPN tunnel resource. (== resource_for beta.vpnTunnels ==) (== resource_for v1.vpnTunnels ==)", + "id": "VpnTunnel", + "properties": { + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "description": { + "description": "An optional description of this resource. Provide this property when you create the resource.", + "type": "string" + }, + "detailedStatus": { + "description": "[Output Only] Detailed status message for the VPN tunnel.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "ikeVersion": { + "description": "IKE protocol version to use when establishing the VPN tunnel with peer VPN gateway. Acceptable IKE versions are 1 or 2. Default version is 2.", + "format": "int32", + "type": "integer" + }, + "kind": { + "default": "compute#vpnTunnel", + "description": "[Output Only] Type of resource. Always compute#vpnTunnel for VPN tunnels.", + "type": "string" + }, + "localTrafficSelector": { + "description": "Local traffic selector to use when establishing the VPN tunnel with peer VPN gateway. The value should be a CIDR formatted string, for example: 192.168.0.0/16. The ranges should be disjoint. Only IPv4 is supported.", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "annotations": { + "required": [ + "compute.vpnTunnels.insert" + ] + }, + "description": "Name of the resource. Provided by the client when the resource is created. The name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 characters long and match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the first character must be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, except the last character, which cannot be a dash.", + "pattern": "[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?", + "type": "string" + }, + "peerIp": { + "description": "IP address of the peer VPN gateway. Only IPv4 is supported.", + "type": "string" + }, + "region": { + "description": "[Output Only] URL of the region where the VPN tunnel resides. You must specify this field as part of the HTTP request URL. It is not settable as a field in the request body.", + "type": "string" + }, + "remoteTrafficSelector": { + "description": "Remote traffic selectors to use when establishing the VPN tunnel with peer VPN gateway. The value should be a CIDR formatted string, for example: 192.168.0.0/16. The ranges should be disjoint. Only IPv4 is supported.", + "items": { + "type": "string" + }, + "type": "array" + }, + "router": { + "description": "URL of router resource to be used for dynamic routing.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "sharedSecret": { + "description": "Shared secret used to set the secure session between the Cloud VPN gateway and the peer VPN gateway.", + "type": "string" + }, + "sharedSecretHash": { + "description": "Hash of the shared secret.", + "type": "string" + }, + "status": { + "description": "[Output Only] The status of the VPN tunnel.", + "enum": [ + "ALLOCATING_RESOURCES", + "AUTHORIZATION_ERROR", + "DEPROVISIONING", + "ESTABLISHED", + "FAILED", + "FIRST_HANDSHAKE", + "NEGOTIATION_FAILURE", + "NETWORK_ERROR", + "NO_INCOMING_PACKETS", + "PROVISIONING", + "REJECTED", + "WAITING_FOR_FULL_CONFIG" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "targetVpnGateway": { + "description": "URL of the Target VPN gateway with which this VPN tunnel is associated. Provided by the client when the VPN tunnel is created.", + "type": "string" + } + }, + "type": "object" + }, + "VpnTunnelAggregatedList": { + "id": "VpnTunnelAggregatedList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "additionalProperties": { + "$ref": "VpnTunnelsScopedList", + "description": "Name of the scope containing this set of vpn tunnels." + }, + "description": "A list of VpnTunnelsScopedList resources.", + "type": "object" + }, + "kind": { + "default": "compute#vpnTunnelAggregatedList", + "description": "[Output Only] Type of resource. Always compute#vpnTunnel for VPN tunnels.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "VpnTunnelList": { + "description": "Contains a list of VpnTunnel resources.", + "id": "VpnTunnelList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of VpnTunnel resources.", + "items": { + "$ref": "VpnTunnel" + }, + "type": "array" + }, + "kind": { + "default": "compute#vpnTunnelList", + "description": "[Output Only] Type of resource. Always compute#vpnTunnel for VPN tunnels.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "VpnTunnelsScopedList": { + "id": "VpnTunnelsScopedList", + "properties": { + "vpnTunnels": { + "description": "A list of vpn tunnels contained in this scope.", + "items": { + "$ref": "VpnTunnel" + }, + "type": "array" + }, + "warning": { + "description": "Informational warning which replaces the list of addresses when the list is empty.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "XpnHostList": { + "id": "XpnHostList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "[Output Only] A list of shared VPC host project URLs.", + "items": { + "$ref": "Project" + }, + "type": "array" + }, + "kind": { + "default": "compute#xpnHostList", + "description": "[Output Only] Type of resource. Always compute#xpnHostList for lists of shared VPC hosts.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "XpnResourceId": { + "description": "Service resource (a.k.a service project) ID.", + "id": "XpnResourceId", + "properties": { + "id": { + "description": "The ID of the service resource. In the case of projects, this field matches the project ID (e.g., my-project), not the project number (e.g., 12345678).", + "type": "string" + }, + "type": { + "description": "The type of the service resource.", + "enum": [ + "PROJECT", + "XPN_RESOURCE_TYPE_UNSPECIFIED" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "Zone": { + "description": "A Zone resource. (== resource_for beta.zones ==) (== resource_for v1.zones ==)", + "id": "Zone", + "properties": { + "availableCpuPlatforms": { + "description": "[Output Only] Available cpu/platform selections for the zone.", + "items": { + "type": "string" + }, + "type": "array" + }, + "creationTimestamp": { + "description": "[Output Only] Creation timestamp in RFC3339 text format.", + "type": "string" + }, + "deprecated": { + "$ref": "DeprecationStatus", + "description": "[Output Only] The deprecation status associated with this zone." + }, + "description": { + "description": "[Output Only] Textual description of the resource.", + "type": "string" + }, + "id": { + "description": "[Output Only] The unique identifier for the resource. This identifier is defined by the server.", + "format": "uint64", + "type": "string" + }, + "kind": { + "default": "compute#zone", + "description": "[Output Only] Type of the resource. Always compute#zone for zones.", + "type": "string" + }, + "name": { + "description": "[Output Only] Name of the resource.", + "type": "string" + }, + "region": { + "description": "[Output Only] Full URL reference to the region which hosts the zone.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for the resource.", + "type": "string" + }, + "status": { + "description": "[Output Only] Status of the zone, either UP or DOWN.", + "enum": [ + "DOWN", + "UP" + ], + "enumDescriptions": [ + "", + "" + ], + "type": "string" + } + }, + "type": "object" + }, + "ZoneList": { + "description": "Contains a list of zone resources.", + "id": "ZoneList", + "properties": { + "id": { + "description": "[Output Only] Unique identifier for the resource; defined by the server.", + "type": "string" + }, + "items": { + "description": "A list of Zone resources.", + "items": { + "$ref": "Zone" + }, + "type": "array" + }, + "kind": { + "default": "compute#zoneList", + "description": "Type of resource.", + "type": "string" + }, + "nextPageToken": { + "description": "[Output Only] This token allows you to get the next page of results for list requests. If the number of results is larger than maxResults, use the nextPageToken as a value for the query parameter pageToken in the next list request. Subsequent list requests will have their own nextPageToken to continue paging through the results.", + "type": "string" + }, + "selfLink": { + "description": "[Output Only] Server-defined URL for this resource.", + "type": "string" + }, + "warning": { + "description": "[Output Only] Informational warning message.", + "properties": { + "code": { + "description": "[Output Only] A warning code, if applicable. For example, Compute Engine returns NO_RESULTS_ON_PAGE if there are no results in the response.", + "enum": [ + "CLEANUP_FAILED", + "DEPRECATED_RESOURCE_USED", + "DEPRECATED_TYPE_USED", + "DISK_SIZE_LARGER_THAN_IMAGE_SIZE", + "EXPERIMENTAL_TYPE_USED", + "EXTERNAL_API_WARNING", + "FIELD_VALUE_OVERRIDEN", + "INJECTED_KERNELS_DEPRECATED", + "MISSING_TYPE_DEPENDENCY", + "NEXT_HOP_ADDRESS_NOT_ASSIGNED", + "NEXT_HOP_CANNOT_IP_FORWARD", + "NEXT_HOP_INSTANCE_NOT_FOUND", + "NEXT_HOP_INSTANCE_NOT_ON_NETWORK", + "NEXT_HOP_NOT_RUNNING", + "NOT_CRITICAL_ERROR", + "NO_RESULTS_ON_PAGE", + "REQUIRED_TOS_AGREEMENT", + "RESOURCE_IN_USE_BY_OTHER_RESOURCE_WARNING", + "RESOURCE_NOT_DELETED", + "SCHEMA_VALIDATION_IGNORED", + "SINGLE_INSTANCE_PROPERTY_TEMPLATE", + "UNDECLARED_PROPERTIES", + "UNREACHABLE" + ], + "enumDescriptions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "type": "string" + }, + "data": { + "description": "[Output Only] Metadata about this warning in key: value format. For example:\n\"data\": [ { \"key\": \"scope\", \"value\": \"zones/us-east1-d\" }", + "items": { + "properties": { + "key": { + "description": "[Output Only] A key that provides more detail on the warning being returned. For example, for warnings where there are no results in a list request for a particular zone, this key might be scope and the key value might be the zone name. Other examples might be a key indicating a deprecated resource and a suggested replacement, or a warning about invalid network settings (for example, if an instance attempts to perform IP forwarding but is not enabled for IP forwarding).", + "type": "string" + }, + "value": { + "description": "[Output Only] A warning data value corresponding to the key.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "message": { + "description": "[Output Only] A human-readable description of the warning code.", + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ZoneSetLabelsRequest": { + "id": "ZoneSetLabelsRequest", + "properties": { + "labelFingerprint": { + "description": "The fingerprint of the previous set of labels for this resource, used to detect conflicts. The fingerprint is initially generated by Compute Engine and changes after every request to modify or update labels. You must always provide an up-to-date fingerprint hash in order to update or change labels. Make a get() request to the resource to get the latest fingerprint.", + "format": "byte", + "type": "string" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "The labels to set for this resource.", + "type": "object" + } + }, + "type": "object" + } + }, + "servicePath": "compute/v1/projects/", + "title": "Compute Engine API", + "version": "v1" +} \ No newline at end of file diff --git a/vendor/google.golang.org/api/gensupport/backoff_test.go b/vendor/google.golang.org/api/gensupport/backoff_test.go new file mode 100644 index 000000000..ef8296b8b --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/backoff_test.go @@ -0,0 +1,46 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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 gensupport + +import ( + "testing" + "time" +) + +func TestBackoff(t *testing.T) { + eb := &ExponentialBackoff{Base: time.Millisecond, Max: time.Second} + + var total time.Duration + for n, max := 0, 2*time.Millisecond; ; n, max = n+1, max*2 { + if n > 100 { + // There's less than 1 in 10^28 of taking longer than 100 iterations, + // so this is just to check we don't have an infinite loop. + t.Fatalf("Failed to timeout after 100 iterations.") + } + pause, retry := eb.Pause() + if !retry { + break + } + + if 0 > pause || pause >= max { + t.Errorf("Iteration %d: pause = %v; want in range [0, %v)", n, pause, max) + } + total += pause + } + + if total < time.Second { + t.Errorf("Total time = %v; want > %v", total, time.Second) + } +} diff --git a/vendor/google.golang.org/api/gensupport/buffer_test.go b/vendor/google.golang.org/api/gensupport/buffer_test.go new file mode 100644 index 000000000..15ccc0424 --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/buffer_test.go @@ -0,0 +1,296 @@ +// Copyright 2015 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "bytes" + "io" + "io/ioutil" + "reflect" + "testing" + "testing/iotest" + + "google.golang.org/api/googleapi" +) + +// getChunkAsString reads a chunk from mb, but does not call Next. +func getChunkAsString(t *testing.T, mb *MediaBuffer) (string, error) { + chunk, _, size, err := mb.Chunk() + + buf, e := ioutil.ReadAll(chunk) + if e != nil { + t.Fatalf("Failed reading chunk: %v", e) + } + if size != len(buf) { + t.Fatalf("reported chunk size doesn't match actual chunk size: got: %v; want: %v", size, len(buf)) + } + return string(buf), err +} + +func TestChunking(t *testing.T) { + type testCase struct { + data string // the data to read from the Reader + finalErr error // error to return after data has been read + chunkSize int + wantChunks []string + } + + for _, singleByteReads := range []bool{true, false} { + for _, tc := range []testCase{ + { + data: "abcdefg", + finalErr: nil, + chunkSize: 3, + wantChunks: []string{"abc", "def", "g"}, + }, + { + data: "abcdefg", + finalErr: nil, + chunkSize: 1, + wantChunks: []string{"a", "b", "c", "d", "e", "f", "g"}, + }, + { + data: "abcdefg", + finalErr: nil, + chunkSize: 7, + wantChunks: []string{"abcdefg"}, + }, + { + data: "abcdefg", + finalErr: nil, + chunkSize: 8, + wantChunks: []string{"abcdefg"}, + }, + { + data: "abcdefg", + finalErr: io.ErrUnexpectedEOF, + chunkSize: 3, + wantChunks: []string{"abc", "def", "g"}, + }, + { + data: "abcdefg", + finalErr: io.ErrUnexpectedEOF, + chunkSize: 8, + wantChunks: []string{"abcdefg"}, + }, + } { + var r io.Reader = &errReader{buf: []byte(tc.data), err: tc.finalErr} + + if singleByteReads { + r = iotest.OneByteReader(r) + } + + mb := NewMediaBuffer(r, tc.chunkSize) + var gotErr error + got := []string{} + for { + chunk, err := getChunkAsString(t, mb) + if len(chunk) != 0 { + got = append(got, string(chunk)) + } + if err != nil { + gotErr = err + break + } + mb.Next() + } + + if !reflect.DeepEqual(got, tc.wantChunks) { + t.Errorf("Failed reading buffer: got: %v; want:%v", got, tc.wantChunks) + } + + expectedErr := tc.finalErr + if expectedErr == nil { + expectedErr = io.EOF + } + if gotErr != expectedErr { + t.Errorf("Reading buffer error: got: %v; want: %v", gotErr, expectedErr) + } + } + } +} + +func TestChunkCanBeReused(t *testing.T) { + er := &errReader{buf: []byte("abcdefg")} + mb := NewMediaBuffer(er, 3) + + // expectChunk reads a chunk and checks that it got what was wanted. + expectChunk := func(want string, wantErr error) { + got, err := getChunkAsString(t, mb) + if err != wantErr { + t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Failed reading buffer: got: %q; want:%q", got, want) + } + } + expectChunk("abc", nil) + // On second call, should get same chunk again. + expectChunk("abc", nil) + mb.Next() + expectChunk("def", nil) + expectChunk("def", nil) + mb.Next() + expectChunk("g", io.EOF) + expectChunk("g", io.EOF) + mb.Next() + expectChunk("", io.EOF) +} + +func TestPos(t *testing.T) { + er := &errReader{buf: []byte("abcdefg")} + mb := NewMediaBuffer(er, 3) + + expectChunkAtOffset := func(want int64, wantErr error) { + _, off, _, err := mb.Chunk() + if err != wantErr { + t.Errorf("error reading buffer: got: %v; want: %v", err, wantErr) + } + if got := off; got != want { + t.Errorf("resumable buffer Pos: got: %v; want: %v", got, want) + } + } + + // We expect the first chunk to be at offset 0. + expectChunkAtOffset(0, nil) + // Fetching the same chunk should return the same offset. + expectChunkAtOffset(0, nil) + + // Calling Next multiple times should only cause off to advance by 3, since off is not advanced until + // the chunk is actually read. + mb.Next() + mb.Next() + expectChunkAtOffset(3, nil) + + mb.Next() + + // Load the final 1-byte chunk. + expectChunkAtOffset(6, io.EOF) + + // Next will advance 1 byte. But there are no more chunks, so off will not increase beyond 7. + mb.Next() + expectChunkAtOffset(7, io.EOF) + mb.Next() + expectChunkAtOffset(7, io.EOF) +} + +// bytes.Reader implements both Reader and ReaderAt. The following types +// implement various combinations of Reader, ReaderAt and ContentTyper, by +// wrapping bytes.Reader. All implement at least ReaderAt, so they can be +// passed to ReaderAtToReader. The following table summarizes which types +// implement which interfaces: +// +// ReaderAt Reader ContentTyper +// reader x x +// typerReader x x x +// readerAt x +// typerReaderAt x x + +// reader implements Reader, in addition to ReaderAt. +type reader struct { + r *bytes.Reader +} + +func (r *reader) ReadAt(b []byte, off int64) (n int, err error) { + return r.r.ReadAt(b, off) +} + +func (r *reader) Read(b []byte) (n int, err error) { + return r.r.Read(b) +} + +// typerReader implements Reader and ContentTyper, in addition to ReaderAt. +type typerReader struct { + r *bytes.Reader +} + +func (tr *typerReader) ReadAt(b []byte, off int64) (n int, err error) { + return tr.r.ReadAt(b, off) +} + +func (tr *typerReader) Read(b []byte) (n int, err error) { + return tr.r.Read(b) +} + +func (tr *typerReader) ContentType() string { + return "ctype" +} + +// readerAt implements only ReaderAt. +type readerAt struct { + r *bytes.Reader +} + +func (ra *readerAt) ReadAt(b []byte, off int64) (n int, err error) { + return ra.r.ReadAt(b, off) +} + +// typerReaderAt implements ContentTyper, in addition to ReaderAt. +type typerReaderAt struct { + r *bytes.Reader +} + +func (tra *typerReaderAt) ReadAt(b []byte, off int64) (n int, err error) { + return tra.r.ReadAt(b, off) +} + +func (tra *typerReaderAt) ContentType() string { + return "ctype" +} + +func TestAdapter(t *testing.T) { + data := "abc" + + checkConversion := func(to io.Reader, wantTyper bool) { + if _, ok := to.(googleapi.ContentTyper); ok != wantTyper { + t.Errorf("reader implements typer? got: %v; want: %v", ok, wantTyper) + } + if typer, ok := to.(googleapi.ContentTyper); ok && typer.ContentType() != "ctype" { + t.Errorf("content type: got: %s; want: ctype", typer.ContentType()) + } + buf, err := ioutil.ReadAll(to) + if err != nil { + t.Errorf("error reading data: %v", err) + return + } + if !bytes.Equal(buf, []byte(data)) { + t.Errorf("failed reading data: got: %s; want: %s", buf, data) + } + } + + type testCase struct { + from io.ReaderAt + wantTyper bool + } + for _, tc := range []testCase{ + { + from: &reader{bytes.NewReader([]byte(data))}, + wantTyper: false, + }, + { + // Reader and ContentTyper + from: &typerReader{bytes.NewReader([]byte(data))}, + wantTyper: true, + }, + { + // ReaderAt + from: &readerAt{bytes.NewReader([]byte(data))}, + wantTyper: false, + }, + { + // ReaderAt and ContentTyper + from: &typerReaderAt{bytes.NewReader([]byte(data))}, + wantTyper: true, + }, + } { + to := ReaderAtToReader(tc.from, int64(len(data))) + checkConversion(to, tc.wantTyper) + // tc.from is a ReaderAt, and should be treated like one, even + // if it also implements Reader. Specifically, it can be + // reused and read from the beginning. + to = ReaderAtToReader(tc.from, int64(len(data))) + checkConversion(to, tc.wantTyper) + } +} diff --git a/vendor/google.golang.org/api/gensupport/header_test.go b/vendor/google.golang.org/api/gensupport/header_test.go new file mode 100644 index 000000000..8fdb8633e --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/header_test.go @@ -0,0 +1,28 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "fmt" + "runtime" + "strings" + "testing" +) + +func TestGoogleClientHeader(t *testing.T) { + const genVersion = "20170101" + gv := strings.Replace(runtime.Version(), " ", "_", -1) + got := GoogleClientHeader(genVersion, "gccl/xyz") + want := fmt.Sprintf("gl-go/%s gccl/xyz gdcl/%s", gv, genVersion) + if got != want { + t.Errorf("got %q, want %q", got, want) + } + + got = GoogleClientHeader(genVersion, "") + want = fmt.Sprintf("gl-go/%s gdcl/%s", gv, genVersion) + if got != want { + t.Errorf("got %q, want %q", got, want) + } +} diff --git a/vendor/google.golang.org/api/gensupport/json_test.go b/vendor/google.golang.org/api/gensupport/json_test.go new file mode 100644 index 000000000..6d83eadbd --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/json_test.go @@ -0,0 +1,516 @@ +// Copyright 2015 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "encoding/json" + "reflect" + "testing" + + "google.golang.org/api/googleapi" +) + +type schema struct { + // Basic types + B bool `json:"b,omitempty"` + F float64 `json:"f,omitempty"` + I int64 `json:"i,omitempty"` + Istr int64 `json:"istr,omitempty,string"` + Str string `json:"str,omitempty"` + + // Pointers to basic types + PB *bool `json:"pb,omitempty"` + PF *float64 `json:"pf,omitempty"` + PI *int64 `json:"pi,omitempty"` + PIStr *int64 `json:"pistr,omitempty,string"` + PStr *string `json:"pstr,omitempty"` + + // Other types + Int64s googleapi.Int64s `json:"i64s,omitempty"` + S []int `json:"s,omitempty"` + M map[string]string `json:"m,omitempty"` + Any interface{} `json:"any,omitempty"` + Child *child `json:"child,omitempty"` + MapToAnyArray map[string][]interface{} `json:"maptoanyarray,omitempty"` + + ForceSendFields []string `json:"-"` + NullFields []string `json:"-"` +} + +type child struct { + B bool `json:"childbool,omitempty"` +} + +type testCase struct { + s schema + want string +} + +func TestBasics(t *testing.T) { + for _, tc := range []testCase{ + { + s: schema{}, + want: `{}`, + }, + { + s: schema{ + ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"}, + }, + want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":""}`, + }, + { + s: schema{ + NullFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"}, + }, + want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":null,"pf":null,"pi":null,"pistr":null,"pstr":null}`, + }, + { + s: schema{ + B: true, + F: 1.2, + I: 1, + Istr: 2, + Str: "a", + PB: googleapi.Bool(true), + PF: googleapi.Float64(1.2), + PI: googleapi.Int64(int64(1)), + PIStr: googleapi.Int64(int64(2)), + PStr: googleapi.String("a"), + }, + want: `{"b":true,"f":1.2,"i":1,"istr":"2","str":"a","pb":true,"pf":1.2,"pi":1,"pistr":"2","pstr":"a"}`, + }, + { + s: schema{ + B: false, + F: 0.0, + I: 0, + Istr: 0, + Str: "", + PB: googleapi.Bool(false), + PF: googleapi.Float64(0.0), + PI: googleapi.Int64(int64(0)), + PIStr: googleapi.Int64(int64(0)), + PStr: googleapi.String(""), + }, + want: `{"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`, + }, + { + s: schema{ + B: false, + F: 0.0, + I: 0, + Istr: 0, + Str: "", + PB: googleapi.Bool(false), + PF: googleapi.Float64(0.0), + PI: googleapi.Int64(int64(0)), + PIStr: googleapi.Int64(int64(0)), + PStr: googleapi.String(""), + ForceSendFields: []string{"B", "F", "I", "Istr", "Str", "PB", "PF", "PI", "PIStr", "PStr"}, + }, + want: `{"b":false,"f":0.0,"i":0,"istr":"0","str":"","pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`, + }, + { + s: schema{ + B: false, + F: 0.0, + I: 0, + Istr: 0, + Str: "", + PB: googleapi.Bool(false), + PF: googleapi.Float64(0.0), + PI: googleapi.Int64(int64(0)), + PIStr: googleapi.Int64(int64(0)), + PStr: googleapi.String(""), + NullFields: []string{"B", "F", "I", "Istr", "Str"}, + }, + want: `{"b":null,"f":null,"i":null,"istr":null,"str":null,"pb":false,"pf":0.0,"pi":0,"pistr":"0","pstr":""}`, + }, + } { + checkMarshalJSON(t, tc) + } +} + +func TestSliceFields(t *testing.T) { + for _, tc := range []testCase{ + { + s: schema{}, + want: `{}`, + }, + { + s: schema{S: []int{}, Int64s: googleapi.Int64s{}}, + want: `{}`, + }, + { + s: schema{S: []int{1}, Int64s: googleapi.Int64s{1}}, + want: `{"s":[1],"i64s":["1"]}`, + }, + { + s: schema{ + ForceSendFields: []string{"S", "Int64s"}, + }, + want: `{"s":[],"i64s":[]}`, + }, + { + s: schema{ + S: []int{}, + Int64s: googleapi.Int64s{}, + ForceSendFields: []string{"S", "Int64s"}, + }, + want: `{"s":[],"i64s":[]}`, + }, + { + s: schema{ + S: []int{1}, + Int64s: googleapi.Int64s{1}, + ForceSendFields: []string{"S", "Int64s"}, + }, + want: `{"s":[1],"i64s":["1"]}`, + }, + { + s: schema{ + NullFields: []string{"S", "Int64s"}, + }, + want: `{"s":null,"i64s":null}`, + }, + } { + checkMarshalJSON(t, tc) + } +} + +func TestMapField(t *testing.T) { + for _, tc := range []testCase{ + { + s: schema{}, + want: `{}`, + }, + { + s: schema{M: make(map[string]string)}, + want: `{}`, + }, + { + s: schema{M: map[string]string{"a": "b"}}, + want: `{"m":{"a":"b"}}`, + }, + { + s: schema{ + ForceSendFields: []string{"M"}, + }, + want: `{"m":{}}`, + }, + { + s: schema{ + NullFields: []string{"M"}, + }, + want: `{"m":null}`, + }, + { + s: schema{ + M: make(map[string]string), + ForceSendFields: []string{"M"}, + }, + want: `{"m":{}}`, + }, + { + s: schema{ + M: make(map[string]string), + NullFields: []string{"M"}, + }, + want: `{"m":null}`, + }, + { + s: schema{ + M: map[string]string{"a": "b"}, + ForceSendFields: []string{"M"}, + }, + want: `{"m":{"a":"b"}}`, + }, + { + s: schema{ + M: map[string]string{"a": "b"}, + NullFields: []string{"M.a", "M."}, + }, + want: `{"m": {"a": null, "":null}}`, + }, + { + s: schema{ + M: map[string]string{"a": "b"}, + NullFields: []string{"M.c"}, + }, + want: `{"m": {"a": "b", "c": null}}`, + }, + { + s: schema{ + NullFields: []string{"M.a"}, + ForceSendFields: []string{"M"}, + }, + want: `{"m": {"a": null}}`, + }, + { + s: schema{ + NullFields: []string{"M.a"}, + }, + want: `{}`, + }, + } { + checkMarshalJSON(t, tc) + } +} + +func TestMapToAnyArray(t *testing.T) { + for _, tc := range []testCase{ + { + s: schema{}, + want: `{}`, + }, + { + s: schema{MapToAnyArray: make(map[string][]interface{})}, + want: `{}`, + }, + { + s: schema{ + MapToAnyArray: map[string][]interface{}{ + "a": []interface{}{2, "b"}, + }, + }, + want: `{"maptoanyarray":{"a":[2, "b"]}}`, + }, + { + s: schema{ + MapToAnyArray: map[string][]interface{}{ + "a": nil, + }, + }, + want: `{"maptoanyarray":{"a": null}}`, + }, + { + s: schema{ + MapToAnyArray: map[string][]interface{}{ + "a": []interface{}{nil}, + }, + }, + want: `{"maptoanyarray":{"a":[null]}}`, + }, + { + s: schema{ + ForceSendFields: []string{"MapToAnyArray"}, + }, + want: `{"maptoanyarray":{}}`, + }, + { + s: schema{ + NullFields: []string{"MapToAnyArray"}, + }, + want: `{"maptoanyarray":null}`, + }, + { + s: schema{ + MapToAnyArray: make(map[string][]interface{}), + ForceSendFields: []string{"MapToAnyArray"}, + }, + want: `{"maptoanyarray":{}}`, + }, + { + s: schema{ + MapToAnyArray: map[string][]interface{}{ + "a": []interface{}{2, "b"}, + }, + ForceSendFields: []string{"MapToAnyArray"}, + }, + want: `{"maptoanyarray":{"a":[2, "b"]}}`, + }, + } { + checkMarshalJSON(t, tc) + } +} + +type anyType struct { + Field int +} + +func (a anyType) MarshalJSON() ([]byte, error) { + return []byte(`"anyType value"`), nil +} + +func TestAnyField(t *testing.T) { + // ForceSendFields has no effect on nil interfaces and interfaces that contain nil pointers. + var nilAny *anyType + for _, tc := range []testCase{ + { + s: schema{}, + want: `{}`, + }, + { + s: schema{Any: nilAny}, + want: `{"any": null}`, + }, + { + s: schema{Any: &anyType{}}, + want: `{"any":"anyType value"}`, + }, + { + s: schema{Any: anyType{}}, + want: `{"any":"anyType value"}`, + }, + { + s: schema{ + ForceSendFields: []string{"Any"}, + }, + want: `{}`, + }, + { + s: schema{ + NullFields: []string{"Any"}, + }, + want: `{"any":null}`, + }, + { + s: schema{ + Any: nilAny, + ForceSendFields: []string{"Any"}, + }, + want: `{"any": null}`, + }, + { + s: schema{ + Any: &anyType{}, + ForceSendFields: []string{"Any"}, + }, + want: `{"any":"anyType value"}`, + }, + { + s: schema{ + Any: anyType{}, + ForceSendFields: []string{"Any"}, + }, + want: `{"any":"anyType value"}`, + }, + } { + checkMarshalJSON(t, tc) + } +} + +func TestSubschema(t *testing.T) { + // Subschemas are always stored as pointers, so ForceSendFields has no effect on them. + for _, tc := range []testCase{ + { + s: schema{}, + want: `{}`, + }, + { + s: schema{ + ForceSendFields: []string{"Child"}, + }, + want: `{}`, + }, + { + s: schema{ + NullFields: []string{"Child"}, + }, + want: `{"child":null}`, + }, + { + s: schema{Child: &child{}}, + want: `{"child":{}}`, + }, + { + s: schema{ + Child: &child{}, + ForceSendFields: []string{"Child"}, + }, + want: `{"child":{}}`, + }, + { + s: schema{Child: &child{B: true}}, + want: `{"child":{"childbool":true}}`, + }, + + { + s: schema{ + Child: &child{B: true}, + ForceSendFields: []string{"Child"}, + }, + want: `{"child":{"childbool":true}}`, + }, + } { + checkMarshalJSON(t, tc) + } +} + +// checkMarshalJSON verifies that calling schemaToMap on tc.s yields a result which is equivalent to tc.want. +func checkMarshalJSON(t *testing.T, tc testCase) { + doCheckMarshalJSON(t, tc.s, tc.s.ForceSendFields, tc.s.NullFields, tc.want) + if len(tc.s.ForceSendFields) == 0 && len(tc.s.NullFields) == 0 { + // verify that the code path used when ForceSendFields and NullFields + // are non-empty produces the same output as the fast path that is used + // when they are empty. + doCheckMarshalJSON(t, tc.s, []string{"dummy"}, []string{"dummy"}, tc.want) + } +} + +func doCheckMarshalJSON(t *testing.T, s schema, forceSendFields, nullFields []string, wantJSON string) { + encoded, err := MarshalJSON(s, forceSendFields, nullFields) + if err != nil { + t.Fatalf("encoding json:\n got err: %v", err) + } + + // The expected and obtained JSON can differ in field ordering, so unmarshal before comparing. + var got interface{} + var want interface{} + err = json.Unmarshal(encoded, &got) + if err != nil { + t.Fatalf("decoding json:\n got err: %v", err) + } + err = json.Unmarshal([]byte(wantJSON), &want) + if err != nil { + t.Fatalf("decoding json:\n got err: %v", err) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("schemaToMap:\ngot :%v\nwant: %v", got, want) + } +} + +func TestParseJSONTag(t *testing.T) { + for _, tc := range []struct { + tag string + want jsonTag + }{ + { + tag: "-", + want: jsonTag{ignore: true}, + }, { + tag: "name,omitempty", + want: jsonTag{apiName: "name"}, + }, { + tag: "name,omitempty,string", + want: jsonTag{apiName: "name", stringFormat: true}, + }, + } { + got, err := parseJSONTag(tc.tag) + if err != nil { + t.Fatalf("parsing json:\n got err: %v\ntag: %q", err, tc.tag) + } + if !reflect.DeepEqual(got, tc.want) { + t.Errorf("parseJSONTage:\ngot :%v\nwant:%v", got, tc.want) + } + } +} +func TestParseMalformedJSONTag(t *testing.T) { + for _, tag := range []string{ + "", + "name", + "name,", + "name,blah", + "name,blah,string", + ",omitempty", + ",omitempty,string", + "name,omitempty,string,blah", + } { + _, err := parseJSONTag(tag) + if err == nil { + t.Fatalf("parsing json: expected err, got nil for tag: %v", tag) + } + } +} diff --git a/vendor/google.golang.org/api/gensupport/jsonfloat_test.go b/vendor/google.golang.org/api/gensupport/jsonfloat_test.go new file mode 100644 index 000000000..aec41eeb9 --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/jsonfloat_test.go @@ -0,0 +1,53 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// 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 gensupport + +import ( + "encoding/json" + "math" + "testing" +) + +func TestJSONFloat(t *testing.T) { + for _, test := range []struct { + in string + want float64 + }{ + {"0", 0}, + {"-10", -10}, + {"1e23", 1e23}, + {`"Infinity"`, math.Inf(1)}, + {`"-Infinity"`, math.Inf(-1)}, + {`"NaN"`, math.NaN()}, + } { + var f64 JSONFloat64 + if err := json.Unmarshal([]byte(test.in), &f64); err != nil { + t.Fatal(err) + } + got := float64(f64) + if got != test.want && math.IsNaN(got) != math.IsNaN(test.want) { + t.Errorf("%s: got %f, want %f", test.in, got, test.want) + } + } +} + +func TestJSONFloatErrors(t *testing.T) { + var f64 JSONFloat64 + for _, in := range []string{"", "a", `"Inf"`, `"-Inf"`, `"nan"`, `"nana"`} { + if err := json.Unmarshal([]byte(in), &f64); err == nil { + t.Errorf("%q: got nil, want error", in) + } + } +} diff --git a/vendor/google.golang.org/api/gensupport/media_test.go b/vendor/google.golang.org/api/gensupport/media_test.go new file mode 100644 index 000000000..6bf2b4171 --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/media_test.go @@ -0,0 +1,407 @@ +// Copyright 2015 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "bytes" + "crypto/rand" + "io" + "io/ioutil" + "net/http" + "reflect" + "strings" + "testing" + + "google.golang.org/api/googleapi" +) + +func TestContentSniffing(t *testing.T) { + type testCase struct { + data []byte // the data to read from the Reader + finalErr error // error to return after data has been read + + wantContentType string + wantContentTypeResult bool + } + + for _, tc := range []testCase{ + { + data: []byte{0, 0, 0, 0}, + finalErr: nil, + wantContentType: "application/octet-stream", + wantContentTypeResult: true, + }, + { + data: []byte(""), + finalErr: nil, + wantContentType: "text/plain; charset=utf-8", + wantContentTypeResult: true, + }, + { + data: []byte(""), + finalErr: io.ErrUnexpectedEOF, + wantContentType: "text/plain; charset=utf-8", + wantContentTypeResult: false, + }, + { + data: []byte("abc"), + finalErr: nil, + wantContentType: "text/plain; charset=utf-8", + wantContentTypeResult: true, + }, + { + data: []byte("abc"), + finalErr: io.ErrUnexpectedEOF, + wantContentType: "text/plain; charset=utf-8", + wantContentTypeResult: false, + }, + // The following examples contain more bytes than are buffered for sniffing. + { + data: bytes.Repeat([]byte("a"), 513), + finalErr: nil, + wantContentType: "text/plain; charset=utf-8", + wantContentTypeResult: true, + }, + { + data: bytes.Repeat([]byte("a"), 513), + finalErr: io.ErrUnexpectedEOF, + wantContentType: "text/plain; charset=utf-8", + wantContentTypeResult: true, // true because error is after first 512 bytes. + }, + } { + er := &errReader{buf: tc.data, err: tc.finalErr} + + sct := newContentSniffer(er) + + // Even if was an error during the first 512 bytes, we should still be able to read those bytes. + buf, err := ioutil.ReadAll(sct) + + if !reflect.DeepEqual(buf, tc.data) { + t.Fatalf("Failed reading buffer: got: %q; want:%q", buf, tc.data) + } + + if err != tc.finalErr { + t.Fatalf("Reading buffer error: got: %v; want: %v", err, tc.finalErr) + } + + ct, ok := sct.ContentType() + if ok != tc.wantContentTypeResult { + t.Fatalf("Content type result got: %v; want: %v", ok, tc.wantContentTypeResult) + } + if ok && ct != tc.wantContentType { + t.Fatalf("Content type got: %q; want: %q", ct, tc.wantContentType) + } + } +} + +type staticContentTyper struct { + io.Reader +} + +func (sct staticContentTyper) ContentType() string { + return "static content type" +} + +func TestDetermineContentType(t *testing.T) { + data := []byte("abc") + rdr := func() io.Reader { + return bytes.NewBuffer(data) + } + + type testCase struct { + r io.Reader + explicitConentType string + wantContentType string + } + + for _, tc := range []testCase{ + { + r: rdr(), + wantContentType: "text/plain; charset=utf-8", + }, + { + r: staticContentTyper{rdr()}, + wantContentType: "static content type", + }, + { + r: staticContentTyper{rdr()}, + explicitConentType: "explicit", + wantContentType: "explicit", + }, + } { + r, ctype := DetermineContentType(tc.r, tc.explicitConentType) + got, err := ioutil.ReadAll(r) + if err != nil { + t.Fatalf("Failed reading buffer: %v", err) + } + if !reflect.DeepEqual(got, data) { + t.Fatalf("Failed reading buffer: got: %q; want:%q", got, data) + } + + if ctype != tc.wantContentType { + t.Fatalf("Content type got: %q; want: %q", ctype, tc.wantContentType) + } + } +} + +func TestNewInfoFromMedia(t *testing.T) { + const textType = "text/plain; charset=utf-8" + for _, test := range []struct { + desc string + r io.Reader + opts []googleapi.MediaOption + wantType string + wantMedia, wantBuffer, wantSingleChunk bool + }{ + { + desc: "an empty reader results in a MediaBuffer with a single, empty chunk", + r: new(bytes.Buffer), + opts: nil, + wantType: textType, + wantBuffer: true, + wantSingleChunk: true, + }, + { + desc: "ContentType is observed", + r: new(bytes.Buffer), + opts: []googleapi.MediaOption{googleapi.ContentType("xyz")}, + wantType: "xyz", + wantBuffer: true, + wantSingleChunk: true, + }, + { + desc: "chunk size of zero: don't use a MediaBuffer; upload as a single chunk", + r: strings.NewReader("12345"), + opts: []googleapi.MediaOption{googleapi.ChunkSize(0)}, + wantType: textType, + wantMedia: true, + wantSingleChunk: true, + }, + { + desc: "chunk size > data size: MediaBuffer with single chunk", + r: strings.NewReader("12345"), + opts: []googleapi.MediaOption{googleapi.ChunkSize(100)}, + wantType: textType, + wantBuffer: true, + wantSingleChunk: true, + }, + { + desc: "chunk size == data size: MediaBuffer with single chunk", + r: &nullReader{googleapi.MinUploadChunkSize}, + opts: []googleapi.MediaOption{googleapi.ChunkSize(1)}, + wantType: "application/octet-stream", + wantBuffer: true, + wantSingleChunk: true, + }, + { + desc: "chunk size < data size: MediaBuffer, not single chunk", + // Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize. + r: &nullReader{2 * googleapi.MinUploadChunkSize}, + opts: []googleapi.MediaOption{googleapi.ChunkSize(1)}, + wantType: "application/octet-stream", + wantBuffer: true, + wantSingleChunk: false, + }, + } { + + mi := NewInfoFromMedia(test.r, test.opts) + if got, want := mi.mType, test.wantType; got != want { + t.Errorf("%s: type: got %q, want %q", test.desc, got, want) + } + if got, want := (mi.media != nil), test.wantMedia; got != want { + t.Errorf("%s: media non-nil: got %t, want %t", test.desc, got, want) + } + if got, want := (mi.buffer != nil), test.wantBuffer; got != want { + t.Errorf("%s: buffer non-nil: got %t, want %t", test.desc, got, want) + } + if got, want := mi.singleChunk, test.wantSingleChunk; got != want { + t.Errorf("%s: singleChunk: got %t, want %t", test.desc, got, want) + } + } +} + +func TestUploadRequest(t *testing.T) { + for _, test := range []struct { + desc string + r io.Reader + chunkSize int + wantContentType string + wantUploadType string + }{ + { + desc: "chunk size of zero: don't use a MediaBuffer; upload as a single chunk", + r: strings.NewReader("12345"), + chunkSize: 0, + wantContentType: "multipart/related;", + }, + { + desc: "chunk size > data size: MediaBuffer with single chunk", + r: strings.NewReader("12345"), + chunkSize: 100, + wantContentType: "multipart/related;", + }, + { + desc: "chunk size == data size: MediaBuffer with single chunk", + r: &nullReader{googleapi.MinUploadChunkSize}, + chunkSize: 1, + wantContentType: "multipart/related;", + }, + { + desc: "chunk size < data size: MediaBuffer, not single chunk", + // Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize. + r: &nullReader{2 * googleapi.MinUploadChunkSize}, + chunkSize: 1, + wantUploadType: "application/octet-stream", + }, + } { + mi := NewInfoFromMedia(test.r, []googleapi.MediaOption{googleapi.ChunkSize(test.chunkSize)}) + h := http.Header{} + mi.UploadRequest(h, new(bytes.Buffer)) + if got, want := h.Get("Content-Type"), test.wantContentType; !strings.HasPrefix(got, want) { + t.Errorf("%s: Content-Type: got %q, want prefix %q", test.desc, got, want) + } + if got, want := h.Get("X-Upload-Content-Type"), test.wantUploadType; got != want { + t.Errorf("%s: X-Upload-Content-Type: got %q, want %q", test.desc, got, want) + } + } +} + +func TestUploadRequestGetBody(t *testing.T) { + // Test that a single chunk results in a getBody function that is non-nil, and + // that produces the same content as the original body. + + // Mock out rand.Reader so we use the same multipart boundary every time. + rr := rand.Reader + rand.Reader = &nullReader{1000} + defer func() { + rand.Reader = rr + }() + + for _, test := range []struct { + desc string + r io.Reader + chunkSize int + wantGetBody bool + wantContentType string + wantUploadType string + }{ + { + desc: "chunk size of zero: no getBody", + r: &nullReader{10}, + chunkSize: 0, + wantGetBody: false, + }, + { + desc: "chunk size == data size: 1 chunk, getBody", + r: &nullReader{googleapi.MinUploadChunkSize}, + chunkSize: 1, + wantGetBody: true, + }, + { + desc: "chunk size < data size: MediaBuffer, >1 chunk, no getBody", + // No getBody here, because the initial request contains no media data + // Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize. + r: &nullReader{2 * googleapi.MinUploadChunkSize}, + chunkSize: 1, + wantGetBody: false, + }, + } { + mi := NewInfoFromMedia(test.r, []googleapi.MediaOption{googleapi.ChunkSize(test.chunkSize)}) + r, getBody, _ := mi.UploadRequest(http.Header{}, bytes.NewBuffer([]byte("body"))) + if got, want := (getBody != nil), test.wantGetBody; got != want { + t.Errorf("%s: getBody: got %t, want %t", test.desc, got, want) + continue + } + if getBody == nil { + continue + } + want, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + for i := 0; i < 3; i++ { + rc, err := getBody() + if err != nil { + t.Fatal(err) + } + got, err := ioutil.ReadAll(rc) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, want) { + t.Errorf("%s, %d:\ngot:\n%s\nwant:\n%s", test.desc, i, string(got), string(want)) + } + } + } +} + +func TestResumableUpload(t *testing.T) { + for _, test := range []struct { + desc string + r io.Reader + chunkSize int + wantUploadType string + wantResumableUpload bool + }{ + { + desc: "chunk size of zero: don't use a MediaBuffer; upload as a single chunk", + r: strings.NewReader("12345"), + chunkSize: 0, + wantUploadType: "multipart", + wantResumableUpload: false, + }, + { + desc: "chunk size > data size: MediaBuffer with single chunk", + r: strings.NewReader("12345"), + chunkSize: 100, + wantUploadType: "multipart", + wantResumableUpload: false, + }, + { + desc: "chunk size == data size: MediaBuffer with single chunk", + // (Because nullReader returns EOF with the last bytes.) + r: &nullReader{googleapi.MinUploadChunkSize}, + chunkSize: googleapi.MinUploadChunkSize, + wantUploadType: "multipart", + wantResumableUpload: false, + }, + { + desc: "chunk size < data size: MediaBuffer, not single chunk", + // Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize. + r: &nullReader{2 * googleapi.MinUploadChunkSize}, + chunkSize: 1, + wantUploadType: "resumable", + wantResumableUpload: true, + }, + } { + mi := NewInfoFromMedia(test.r, []googleapi.MediaOption{googleapi.ChunkSize(test.chunkSize)}) + if got, want := mi.UploadType(), test.wantUploadType; got != want { + t.Errorf("%s: upload type: got %q, want %q", test.desc, got, want) + } + if got, want := mi.ResumableUpload("") != nil, test.wantResumableUpload; got != want { + t.Errorf("%s: resumable upload non-nil: got %t, want %t", test.desc, got, want) + } + } +} + +// A nullReader simulates reading a fixed number of bytes. +type nullReader struct { + remain int +} + +// Read doesn't touch buf, but it does reduce the amount of bytes remaining +// by len(buf). +func (r *nullReader) Read(buf []byte) (int, error) { + n := len(buf) + if r.remain < n { + n = r.remain + } + r.remain -= n + var err error + if r.remain == 0 { + err = io.EOF + } + return n, err +} diff --git a/vendor/google.golang.org/api/gensupport/resumable_test.go b/vendor/google.golang.org/api/gensupport/resumable_test.go new file mode 100644 index 000000000..1934603a0 --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/resumable_test.go @@ -0,0 +1,281 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "fmt" + "io" + "io/ioutil" + "net/http" + "reflect" + "strings" + "testing" + + "golang.org/x/net/context" +) + +type unexpectedReader struct{} + +func (unexpectedReader) Read([]byte) (int, error) { + return 0, fmt.Errorf("unexpected read in test") +} + +// event is an expected request/response pair +type event struct { + // the byte range header that should be present in a request. + byteRange string + // the http status code to send in response. + responseStatus int +} + +// interruptibleTransport is configured with a canned set of requests/responses. +// It records the incoming data, unless the corresponding event is configured to return +// http.StatusServiceUnavailable. +type interruptibleTransport struct { + events []event + buf []byte + bodies bodyTracker +} + +// bodyTracker keeps track of response bodies that have not been closed. +type bodyTracker map[io.ReadCloser]struct{} + +func (bt bodyTracker) Add(body io.ReadCloser) { + bt[body] = struct{}{} +} + +func (bt bodyTracker) Close(body io.ReadCloser) { + delete(bt, body) +} + +type trackingCloser struct { + io.Reader + tracker bodyTracker +} + +func (tc *trackingCloser) Close() error { + tc.tracker.Close(tc) + return nil +} + +func (tc *trackingCloser) Open() { + tc.tracker.Add(tc) +} + +func (t *interruptibleTransport) RoundTrip(req *http.Request) (*http.Response, error) { + ev := t.events[0] + t.events = t.events[1:] + if got, want := req.Header.Get("Content-Range"), ev.byteRange; got != want { + return nil, fmt.Errorf("byte range: got %s; want %s", got, want) + } + + if ev.responseStatus != http.StatusServiceUnavailable { + buf, err := ioutil.ReadAll(req.Body) + if err != nil { + return nil, fmt.Errorf("error reading from request data: %v", err) + } + t.buf = append(t.buf, buf...) + } + + tc := &trackingCloser{unexpectedReader{}, t.bodies} + tc.Open() + h := http.Header{} + status := ev.responseStatus + + // Support "X-GUploader-No-308" like Google: + if status == 308 && req.Header.Get("X-GUploader-No-308") == "yes" { + status = 200 + h.Set("X-Http-Status-Code-Override", "308") + } + + res := &http.Response{ + StatusCode: status, + Header: h, + Body: tc, + } + return res, nil +} + +// progressRecorder records updates, and calls f for every invocation of ProgressUpdate. +type progressRecorder struct { + updates []int64 + f func() +} + +func (pr *progressRecorder) ProgressUpdate(current int64) { + pr.updates = append(pr.updates, current) + if pr.f != nil { + pr.f() + } +} + +func TestInterruptedTransferChunks(t *testing.T) { + type testCase struct { + data string + chunkSize int + events []event + wantProgress []int64 + } + + for _, tc := range []testCase{ + { + data: strings.Repeat("a", 300), + chunkSize: 90, + events: []event{ + {"bytes 0-89/*", http.StatusServiceUnavailable}, + {"bytes 0-89/*", 308}, + {"bytes 90-179/*", 308}, + {"bytes 180-269/*", http.StatusServiceUnavailable}, + {"bytes 180-269/*", 308}, + {"bytes 270-299/300", 200}, + }, + + wantProgress: []int64{90, 180, 270, 300}, + }, + { + data: strings.Repeat("a", 20), + chunkSize: 10, + events: []event{ + {"bytes 0-9/*", http.StatusServiceUnavailable}, + {"bytes 0-9/*", 308}, + {"bytes 10-19/*", http.StatusServiceUnavailable}, + {"bytes 10-19/*", 308}, + // 0 byte final request demands a byte range with leading asterix. + {"bytes */20", http.StatusServiceUnavailable}, + {"bytes */20", 200}, + }, + + wantProgress: []int64{10, 20}, + }, + } { + media := strings.NewReader(tc.data) + + tr := &interruptibleTransport{ + buf: make([]byte, 0, len(tc.data)), + events: tc.events, + bodies: bodyTracker{}, + } + + pr := progressRecorder{} + rx := &ResumableUpload{ + Client: &http.Client{Transport: tr}, + Media: NewMediaBuffer(media, tc.chunkSize), + MediaType: "text/plain", + Callback: pr.ProgressUpdate, + Backoff: NoPauseStrategy, + } + res, err := rx.Upload(context.Background()) + if err == nil { + res.Body.Close() + } + if err != nil || res == nil || res.StatusCode != http.StatusOK { + if res == nil { + t.Errorf("Upload not successful, res=nil: %v", err) + } else { + t.Errorf("Upload not successful, statusCode=%v: %v", res.StatusCode, err) + } + } + if !reflect.DeepEqual(tr.buf, []byte(tc.data)) { + t.Errorf("transferred contents:\ngot %s\nwant %s", tr.buf, tc.data) + } + + if !reflect.DeepEqual(pr.updates, tc.wantProgress) { + t.Errorf("progress updates: got %v, want %v", pr.updates, tc.wantProgress) + } + + if len(tr.events) > 0 { + t.Errorf("did not observe all expected events. leftover events: %v", tr.events) + } + if len(tr.bodies) > 0 { + t.Errorf("unclosed request bodies: %v", tr.bodies) + } + } +} + +func TestCancelUploadFast(t *testing.T) { + const ( + chunkSize = 90 + mediaSize = 300 + ) + media := strings.NewReader(strings.Repeat("a", mediaSize)) + + tr := &interruptibleTransport{ + buf: make([]byte, 0, mediaSize), + } + + pr := progressRecorder{} + rx := &ResumableUpload{ + Client: &http.Client{Transport: tr}, + Media: NewMediaBuffer(media, chunkSize), + MediaType: "text/plain", + Callback: pr.ProgressUpdate, + Backoff: NoPauseStrategy, + } + ctx, cancelFunc := context.WithCancel(context.Background()) + cancelFunc() // stop the upload that hasn't started yet + res, err := rx.Upload(ctx) + if err != context.Canceled { + t.Errorf("Upload err: got: %v; want: context cancelled", err) + } + if res != nil { + t.Errorf("Upload result: got: %v; want: nil", res) + } + if pr.updates != nil { + t.Errorf("progress updates: got %v; want: nil", pr.updates) + } +} + +func TestCancelUpload(t *testing.T) { + const ( + chunkSize = 90 + mediaSize = 300 + ) + media := strings.NewReader(strings.Repeat("a", mediaSize)) + + tr := &interruptibleTransport{ + buf: make([]byte, 0, mediaSize), + events: []event{ + {"bytes 0-89/*", http.StatusServiceUnavailable}, + {"bytes 0-89/*", 308}, + {"bytes 90-179/*", 308}, + {"bytes 180-269/*", 308}, // Upload should be cancelled before this event. + }, + bodies: bodyTracker{}, + } + + ctx, cancelFunc := context.WithCancel(context.Background()) + numUpdates := 0 + + pr := progressRecorder{f: func() { + numUpdates++ + if numUpdates >= 2 { + cancelFunc() + } + }} + + rx := &ResumableUpload{ + Client: &http.Client{Transport: tr}, + Media: NewMediaBuffer(media, chunkSize), + MediaType: "text/plain", + Callback: pr.ProgressUpdate, + Backoff: NoPauseStrategy, + } + res, err := rx.Upload(ctx) + if err != context.Canceled { + t.Errorf("Upload err: got: %v; want: context cancelled", err) + } + if res != nil { + t.Errorf("Upload result: got: %v; want: nil", res) + } + if got, want := tr.buf, []byte(strings.Repeat("a", chunkSize*2)); !reflect.DeepEqual(got, want) { + t.Errorf("transferred contents:\ngot %s\nwant %s", got, want) + } + if got, want := pr.updates, []int64{chunkSize, chunkSize * 2}; !reflect.DeepEqual(got, want) { + t.Errorf("progress updates: got %v; want: %v", got, want) + } + if len(tr.bodies) > 0 { + t.Errorf("unclosed request bodies: %v", tr.bodies) + } +} diff --git a/vendor/google.golang.org/api/gensupport/retry_test.go b/vendor/google.golang.org/api/gensupport/retry_test.go new file mode 100644 index 000000000..dd5e96d9b --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/retry_test.go @@ -0,0 +1,176 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// 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 gensupport + +import ( + "errors" + "io" + "net" + "net/http" + "testing" + "time" + + "golang.org/x/net/context" +) + +func TestRetry(t *testing.T) { + testCases := []struct { + desc string + respStatus []int // HTTP status codes returned (length indicates number of calls we expect). + maxRetry int // Max number of calls allowed by the BackoffStrategy. + wantStatus int // StatusCode of returned response. + }{ + { + desc: "First call successful", + respStatus: []int{200}, + maxRetry: 3, + wantStatus: 200, + }, + { + desc: "Retry before success", + respStatus: []int{500, 500, 500, 200}, + maxRetry: 3, + wantStatus: 200, + }, + { + desc: "Backoff strategy abandons after 3 retries", + respStatus: []int{500, 500, 500, 500}, + maxRetry: 3, + wantStatus: 500, + }, + { + desc: "Backoff strategy abandons after 2 retries", + respStatus: []int{500, 500, 500}, + maxRetry: 2, + wantStatus: 500, + }, + } + for _, tt := range testCases { + // Function consumes tt.respStatus + f := func() (*http.Response, error) { + if len(tt.respStatus) == 0 { + return nil, errors.New("too many requests to function") + } + resp := &http.Response{StatusCode: tt.respStatus[0]} + tt.respStatus = tt.respStatus[1:] + return resp, nil + } + + backoff := &LimitRetryStrategy{ + Max: tt.maxRetry, + Strategy: NoPauseStrategy, + } + + resp, err := Retry(nil, f, backoff) + if err != nil { + t.Errorf("%s: Retry returned err %v", tt.desc, err) + } + if got := resp.StatusCode; got != tt.wantStatus { + t.Errorf("%s: Retry returned response with StatusCode=%d; want %d", tt.desc, got, tt.wantStatus) + } + if len(tt.respStatus) != 0 { + t.Errorf("%s: f was not called enough; status codes remaining: %v", tt.desc, tt.respStatus) + } + } +} + +type checkCloseReader struct { + closed bool +} + +func (c *checkCloseReader) Read(p []byte) (n int, err error) { return 0, io.EOF } +func (c *checkCloseReader) Close() error { + c.closed = true + return nil +} + +func TestRetryClosesBody(t *testing.T) { + var i int + responses := []*http.Response{ + {StatusCode: 500, Body: &checkCloseReader{}}, + {StatusCode: 500, Body: &checkCloseReader{}}, + {StatusCode: 200, Body: &checkCloseReader{}}, + } + f := func() (*http.Response, error) { + resp := responses[i] + i++ + return resp, nil + } + + resp, err := Retry(nil, f, NoPauseStrategy) + if err != nil { + t.Fatalf("Retry returned error: %v", err) + } + if resp != responses[2] { + t.Errorf("Retry returned %v; want %v", resp, responses[2]) + } + for i, resp := range responses { + want := i != 2 // Only the last response should not be closed. + got := resp.Body.(*checkCloseReader).closed + if got != want { + t.Errorf("response[%d].Body closed = %t, want %t", i, got, want) + } + } +} + +func RetryReturnsOnContextCancel(t *testing.T) { + f := func() (*http.Response, error) { + return nil, io.ErrUnexpectedEOF + } + backoff := UniformPauseStrategy(time.Hour) + ctx, cancel := context.WithCancel(context.Background()) + + errc := make(chan error, 1) + go func() { + _, err := Retry(ctx, f, backoff) + errc <- err + }() + + cancel() + select { + case err := <-errc: + if err != ctx.Err() { + t.Errorf("Retry returned err: %v, want %v", err, ctx.Err()) + } + case <-time.After(5 * time.Second): + t.Errorf("Timed out waiting for Retry to return") + } +} + +func TestShouldRetry(t *testing.T) { + testCases := []struct { + status int + err error + want bool + }{ + {status: 200, want: false}, + {status: 308, want: false}, + {status: 403, want: false}, + {status: 429, want: true}, + {status: 500, want: true}, + {status: 503, want: true}, + {status: 600, want: false}, + {err: io.EOF, want: false}, + {err: errors.New("random badness"), want: false}, + {err: io.ErrUnexpectedEOF, want: true}, + {err: &net.AddrError{}, want: false}, // Not temporary. + {err: &net.DNSError{IsTimeout: true}, want: true}, // Temporary. + } + for _, tt := range testCases { + if got := shouldRetry(tt.status, tt.err); got != tt.want { + t.Errorf("shouldRetry(%d, %v) = %t; want %t", tt.status, tt.err, got, tt.want) + } + } +} diff --git a/vendor/google.golang.org/api/gensupport/send_test.go b/vendor/google.golang.org/api/gensupport/send_test.go new file mode 100644 index 000000000..2219eb39e --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/send_test.go @@ -0,0 +1,20 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "net/http" + "testing" +) + +func TestSendRequest(t *testing.T) { + // Setting Accept-Encoding should give an error immediately. + req, _ := http.NewRequest("GET", "url", nil) + req.Header.Set("Accept-Encoding", "") + _, err := SendRequest(nil, nil, req) + if err == nil { + t.Error("got nil, want error") + } +} diff --git a/vendor/google.golang.org/api/gensupport/util_test.go b/vendor/google.golang.org/api/gensupport/util_test.go new file mode 100644 index 000000000..3b1305692 --- /dev/null +++ b/vendor/google.golang.org/api/gensupport/util_test.go @@ -0,0 +1,57 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "io" + "time" +) + +// errReader reads out of a buffer until it is empty, then returns the specified error. +type errReader struct { + buf []byte + err error +} + +func (er *errReader) Read(p []byte) (int, error) { + if len(er.buf) == 0 { + if er.err == nil { + return 0, io.EOF + } + return 0, er.err + } + n := copy(p, er.buf) + er.buf = er.buf[n:] + return n, nil +} + +// UniformPauseStrategy implements BackoffStrategy with uniform pause. +type UniformPauseStrategy time.Duration + +func (p UniformPauseStrategy) Pause() (time.Duration, bool) { return time.Duration(p), true } +func (p UniformPauseStrategy) Reset() {} + +// NoPauseStrategy implements BackoffStrategy with infinite 0-length pauses. +const NoPauseStrategy = UniformPauseStrategy(0) + +// LimitRetryStrategy wraps a BackoffStrategy but limits the number of retries. +type LimitRetryStrategy struct { + Max int + Strategy BackoffStrategy + n int +} + +func (l *LimitRetryStrategy) Pause() (time.Duration, bool) { + l.n++ + if l.n > l.Max { + return 0, false + } + return l.Strategy.Pause() +} + +func (l *LimitRetryStrategy) Reset() { + l.n = 0 + l.Strategy.Reset() +} diff --git a/vendor/google.golang.org/api/googleapi/googleapi_test.go b/vendor/google.golang.org/api/googleapi/googleapi_test.go new file mode 100644 index 000000000..dd39a5cdc --- /dev/null +++ b/vendor/google.golang.org/api/googleapi/googleapi_test.go @@ -0,0 +1,291 @@ +// Copyright 2011 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package googleapi + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "strings" + "testing" +) + +type ExpandTest struct { + in string + expansions map[string]string + want string +} + +var expandTests = []ExpandTest{ + // no expansions + { + "http://www.golang.org/", + map[string]string{}, + "http://www.golang.org/", + }, + // one expansion, no escaping + { + "http://www.golang.org/{bucket}/delete", + map[string]string{ + "bucket": "red", + }, + "http://www.golang.org/red/delete", + }, + // one expansion, with hex escapes + { + "http://www.golang.org/{bucket}/delete", + map[string]string{ + "bucket": "red/blue", + }, + "http://www.golang.org/red%2Fblue/delete", + }, + // one expansion, with space + { + "http://www.golang.org/{bucket}/delete", + map[string]string{ + "bucket": "red or blue", + }, + "http://www.golang.org/red%20or%20blue/delete", + }, + // expansion not found + { + "http://www.golang.org/{object}/delete", + map[string]string{ + "bucket": "red or blue", + }, + "http://www.golang.org//delete", + }, + // multiple expansions + { + "http://www.golang.org/{one}/{two}/{three}/get", + map[string]string{ + "one": "ONE", + "two": "TWO", + "three": "THREE", + }, + "http://www.golang.org/ONE/TWO/THREE/get", + }, + // utf-8 characters + { + "http://www.golang.org/{bucket}/get", + map[string]string{ + "bucket": "£100", + }, + "http://www.golang.org/%C2%A3100/get", + }, + // punctuations + { + "http://www.golang.org/{bucket}/get", + map[string]string{ + "bucket": `/\@:,.`, + }, + "http://www.golang.org/%2F%5C%40%3A%2C./get", + }, + // mis-matched brackets + { + "http://www.golang.org/{bucket/get", + map[string]string{ + "bucket": "red", + }, + "http://www.golang.org/%7Bbucket/get", + }, + // "+" prefix for suppressing escape + // See also: http://tools.ietf.org/html/rfc6570#section-3.2.3 + { + "http://www.golang.org/{+topic}", + map[string]string{ + "topic": "/topics/myproject/mytopic", + }, + // The double slashes here look weird, but it's intentional + "http://www.golang.org//topics/myproject/mytopic", + }, +} + +func TestExpand(t *testing.T) { + for i, test := range expandTests { + u := url.URL{ + Path: test.in, + } + Expand(&u, test.expansions) + got := u.EscapedPath() + if got != test.want { + t.Errorf("got %q expected %q in test %d", got, test.want, i+1) + } + } +} + +type CheckResponseTest struct { + in *http.Response + bodyText string + want error + errText string +} + +var checkResponseTests = []CheckResponseTest{ + { + &http.Response{ + StatusCode: http.StatusOK, + }, + "", + nil, + "", + }, + { + &http.Response{ + StatusCode: http.StatusInternalServerError, + }, + `{"error":{}}`, + &Error{ + Code: http.StatusInternalServerError, + Body: `{"error":{}}`, + }, + `googleapi: got HTTP response code 500 with body: {"error":{}}`, + }, + { + &http.Response{ + StatusCode: http.StatusNotFound, + }, + `{"error":{"message":"Error message for StatusNotFound."}}`, + &Error{ + Code: http.StatusNotFound, + Message: "Error message for StatusNotFound.", + Body: `{"error":{"message":"Error message for StatusNotFound."}}`, + }, + "googleapi: Error 404: Error message for StatusNotFound.", + }, + { + &http.Response{ + StatusCode: http.StatusBadRequest, + }, + `{"error":"invalid_token","error_description":"Invalid Value"}`, + &Error{ + Code: http.StatusBadRequest, + Body: `{"error":"invalid_token","error_description":"Invalid Value"}`, + }, + `googleapi: got HTTP response code 400 with body: {"error":"invalid_token","error_description":"Invalid Value"}`, + }, + { + &http.Response{ + StatusCode: http.StatusBadRequest, + }, + `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`, + &Error{ + Code: http.StatusBadRequest, + Errors: []ErrorItem{ + { + Reason: "keyInvalid", + Message: "Bad Request", + }, + }, + Body: `{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}`, + Message: "Bad Request", + }, + "googleapi: Error 400: Bad Request, keyInvalid", + }, +} + +func TestCheckResponse(t *testing.T) { + for _, test := range checkResponseTests { + res := test.in + if test.bodyText != "" { + res.Body = ioutil.NopCloser(strings.NewReader(test.bodyText)) + } + g := CheckResponse(res) + if !reflect.DeepEqual(g, test.want) { + t.Errorf("CheckResponse: got %v, want %v", g, test.want) + gotJson, err := json.Marshal(g) + if err != nil { + t.Error(err) + } + wantJson, err := json.Marshal(test.want) + if err != nil { + t.Error(err) + } + t.Errorf("json(got): %q\njson(want): %q", string(gotJson), string(wantJson)) + } + if g != nil && g.Error() != test.errText { + t.Errorf("CheckResponse: unexpected error message.\nGot: %q\nwant: %q", g, test.errText) + } + } +} + +type VariantPoint struct { + Type string + Coordinates []float64 +} + +type VariantTest struct { + in map[string]interface{} + result bool + want VariantPoint +} + +var coords = []interface{}{1.0, 2.0} + +var variantTests = []VariantTest{ + { + in: map[string]interface{}{ + "type": "Point", + "coordinates": coords, + }, + result: true, + want: VariantPoint{ + Type: "Point", + Coordinates: []float64{1.0, 2.0}, + }, + }, + { + in: map[string]interface{}{ + "type": "Point", + "bogus": coords, + }, + result: true, + want: VariantPoint{ + Type: "Point", + }, + }, +} + +func TestVariantType(t *testing.T) { + for _, test := range variantTests { + if g := VariantType(test.in); g != test.want.Type { + t.Errorf("VariantType(%v): got %v, want %v", test.in, g, test.want.Type) + } + } +} + +func TestConvertVariant(t *testing.T) { + for _, test := range variantTests { + g := VariantPoint{} + r := ConvertVariant(test.in, &g) + if r != test.result { + t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, r, test.result) + } + if !reflect.DeepEqual(g, test.want) { + t.Errorf("ConvertVariant(%v): got %v, want %v", test.in, g, test.want) + } + } +} + +func TestRoundChunkSize(t *testing.T) { + type testCase struct { + in int + want int + } + for _, tc := range []testCase{ + {0, 0}, + {256*1024 - 1, 256 * 1024}, + {256 * 1024, 256 * 1024}, + {256*1024 + 1, 2 * 256 * 1024}, + } { + mo := &MediaOptions{} + ChunkSize(tc.in).setOptions(mo) + if got := mo.ChunkSize; got != tc.want { + t.Errorf("rounding chunk size: got: %v; want %v", got, tc.want) + } + } +} diff --git a/vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates_test.go b/vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates_test.go new file mode 100644 index 000000000..a60c4efe3 --- /dev/null +++ b/vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates_test.go @@ -0,0 +1,280 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uritemplates + +import ( + "fmt" + "log" + "net/url" + "testing" +) + +func ExampleExpand() { + values := map[string]string{ + "user": "golang", + "repo": "go", + } + expanded, _, err := Expand("https://api.github.com/repos{/user,repo}", values) + if err != nil { + log.Fatalf("Error expanding template: %v", err) + } + fmt.Println(expanded) + // Output: + // https://api.github.com/repos/golang/go +} + +func TestExpand(t *testing.T) { + testCases := []struct { + tmpl string + values map[string]string + want string + }{ + // These examples come from the RFC: + // http://tools.ietf.org/html/rfc6570 + { + tmpl: "http://www.example.com/foo{?query,number}", + values: map[string]string{"query": "mycelium", "number": "100"}, + want: "http://www.example.com/foo?query=mycelium&number=100", + }, + { + tmpl: "http://www.example.com/foo{?query,number}", + values: map[string]string{"query": "mycelium"}, + want: "http://www.example.com/foo?query=mycelium", + }, + { + tmpl: "http://www.example.com/foo{?query,number}", + values: map[string]string{}, + want: "http://www.example.com/foo", + }, + } + + for _, tt := range testCases { + exp, _, err := Expand(tt.tmpl, tt.values) + if err != nil { + t.Errorf("Expand(%q, %v) error: %v", tt.tmpl, tt.values, err) + continue + } + if exp != tt.want { + t.Errorf("Expand(%q, %v)\ngot %q\nwant %q", tt.tmpl, tt.values, exp, tt.want) + } + } +} + +func TestExpandRFCLevels(t *testing.T) { + values := map[string]string{ + "dub": "me/too", + "hello": "Hello World!", + "half": "50%", + "var": "value", + "who": "fred", + "base": "http://example.com/home/", + "path": "/foo/bar", + "semi": ";", + "v": "6", + "x": "1024", + "y": "768", + "empty": "", + // undef not mapped. + } + testCases := []struct { + tmpl, want string + }{ + // These examples come from the RFC levels specification. + // http://tools.ietf.org/html/rfc6570 + // Level 1 examples. + {tmpl: "{var}", want: "value"}, + {tmpl: "{hello}", want: "Hello%20World%21"}, + + // Level 2 examples. + {tmpl: "{+var}", want: "value"}, + {tmpl: "{+hello}", want: "Hello%20World!"}, + {tmpl: "{+path}/here", want: "/foo/bar/here"}, + {tmpl: "here?ref={+path}", want: "here?ref=/foo/bar"}, + {tmpl: "X{#var}", want: "X#value"}, + {tmpl: "X{#hello}", want: "X#Hello%20World!"}, + + // Level 3 examples. + {tmpl: "map?{x,y}", want: "map?1024,768"}, + {tmpl: "{x,hello,y}", want: "1024,Hello%20World%21,768"}, + {tmpl: "{+x,hello,y}", want: "1024,Hello%20World!,768"}, + {tmpl: "{+path,x}/here", want: "/foo/bar,1024/here"}, + {tmpl: "{#x,hello,y}", want: "#1024,Hello%20World!,768"}, + {tmpl: "{#path,x}/here", want: "#/foo/bar,1024/here"}, + {tmpl: "X{.var}", want: "X.value"}, + {tmpl: "X{.x,y}", want: "X.1024.768"}, + {tmpl: "{/var}", want: "/value"}, + {tmpl: "{/var,x}/here", want: "/value/1024/here"}, + {tmpl: "{;x,y}", want: ";x=1024;y=768"}, + {tmpl: "{;x,y,empty}", want: ";x=1024;y=768;empty"}, + {tmpl: "{?x,y}", want: "?x=1024&y=768"}, + {tmpl: "{?x,y,empty}", want: "?x=1024&y=768&empty="}, + {tmpl: "?fixed=yes{&x}", want: "?fixed=yes&x=1024"}, + {tmpl: "{&x,y,empty}", want: "&x=1024&y=768&empty="}, + + {tmpl: "{var:3}", want: "val"}, + {tmpl: "{var:30}", want: "value"}, + {tmpl: "{+path:6}/here", want: "/foo/b/here"}, + {tmpl: "{#path:6}/here", want: "#/foo/b/here"}, + {tmpl: "X{.var:3}", want: "X.val"}, + {tmpl: "{/var:1,var}", want: "/v/value"}, + {tmpl: "{;hello:5}", want: ";hello=Hello"}, + {tmpl: "{?var:3}", want: "?var=val"}, + {tmpl: "{&var:3}", want: "&var=val"}, + + // 2.4.1 Prefix values. + {tmpl: "{var}", want: "value"}, + {tmpl: "{var:20}", want: "value"}, + {tmpl: "{var:3}", want: "val"}, + {tmpl: "{semi}", want: "%3B"}, + {tmpl: "{semi:2}", want: "%3B"}, + // 3.2.2. Simple String Expansion: {var} + {tmpl: "{var}", want: "value"}, + {tmpl: "{hello}", want: "Hello%20World%21"}, + {tmpl: "{half}", want: "50%25"}, + {tmpl: "O{empty}X", want: "OX"}, + {tmpl: "O{undef}X", want: "OX"}, + {tmpl: "{x,y}", want: "1024,768"}, + {tmpl: "{x,hello,y}", want: "1024,Hello%20World%21,768"}, + {tmpl: "?{x,empty}", want: "?1024,"}, + {tmpl: "?{x,undef}", want: "?1024"}, + {tmpl: "?{undef,y}", want: "?768"}, + {tmpl: "{var:3}", want: "val"}, + {tmpl: "{var:30}", want: "value"}, + // 3.2.3. Reserved Expansion: {+var} + {tmpl: "{+var}", want: "value"}, + {tmpl: "{+hello}", want: "Hello%20World!"}, + {tmpl: "{+half}", want: "50%25"}, + {tmpl: "{base}index", want: "http%3A%2F%2Fexample.com%2Fhome%2Findex"}, + {tmpl: "{+base}index", want: "http://example.com/home/index"}, + {tmpl: "O{+empty}X", want: "OX"}, + {tmpl: "O{+undef}X", want: "OX"}, + {tmpl: "{+path}/here", want: "/foo/bar/here"}, + {tmpl: "here?ref={+path}", want: "here?ref=/foo/bar"}, + {tmpl: "up{+path}{var}/here", want: "up/foo/barvalue/here"}, + {tmpl: "{+x,hello,y}", want: "1024,Hello%20World!,768"}, + {tmpl: "{+path,x}/here", want: "/foo/bar,1024/here"}, + {tmpl: "{+path:6}/here", want: "/foo/b/here"}, + // 3.2.4. Fragment Expansion: {#var} + {tmpl: "{#var}", want: "#value"}, + {tmpl: "{#hello}", want: "#Hello%20World!"}, + {tmpl: "{#half}", want: "#50%25"}, + {tmpl: "foo{#empty}", want: "foo#"}, + {tmpl: "foo{#undef}", want: "foo"}, + {tmpl: "{#x,hello,y}", want: "#1024,Hello%20World!,768"}, + {tmpl: "{#path,x}/here", want: "#/foo/bar,1024/here"}, + {tmpl: "{#path:6}/here", want: "#/foo/b/here"}, + // 3.2.5. Label Expansion with Dot-Prefix: {.var} + {tmpl: "{.who}", want: ".fred"}, + {tmpl: "{.who,who}", want: ".fred.fred"}, + {tmpl: "{.half,who}", want: ".50%25.fred"}, + {tmpl: "X{.var}", want: "X.value"}, + {tmpl: "X{.empty}", want: "X."}, + {tmpl: "X{.undef}", want: "X"}, + {tmpl: "X{.var:3}", want: "X.val"}, + // 3.2.6. Path Segment Expansion: {/var} + {tmpl: "{/who}", want: "/fred"}, + {tmpl: "{/who,who}", want: "/fred/fred"}, + {tmpl: "{/half,who}", want: "/50%25/fred"}, + {tmpl: "{/who,dub}", want: "/fred/me%2Ftoo"}, + {tmpl: "{/var}", want: "/value"}, + {tmpl: "{/var,empty}", want: "/value/"}, + {tmpl: "{/var,undef}", want: "/value"}, + {tmpl: "{/var,x}/here", want: "/value/1024/here"}, + {tmpl: "{/var:1,var}", want: "/v/value"}, + // 3.2.7. Path-Style Parameter Expansion: {;var} + {tmpl: "{;who}", want: ";who=fred"}, + {tmpl: "{;half}", want: ";half=50%25"}, + {tmpl: "{;empty}", want: ";empty"}, + {tmpl: "{;v,empty,who}", want: ";v=6;empty;who=fred"}, + {tmpl: "{;v,bar,who}", want: ";v=6;who=fred"}, + {tmpl: "{;x,y}", want: ";x=1024;y=768"}, + {tmpl: "{;x,y,empty}", want: ";x=1024;y=768;empty"}, + {tmpl: "{;x,y,undef}", want: ";x=1024;y=768"}, + {tmpl: "{;hello:5}", want: ";hello=Hello"}, + // 3.2.8. Form-Style Query Expansion: {?var} + {tmpl: "{?who}", want: "?who=fred"}, + {tmpl: "{?half}", want: "?half=50%25"}, + {tmpl: "{?x,y}", want: "?x=1024&y=768"}, + {tmpl: "{?x,y,empty}", want: "?x=1024&y=768&empty="}, + {tmpl: "{?x,y,undef}", want: "?x=1024&y=768"}, + {tmpl: "{?var:3}", want: "?var=val"}, + // 3.2.9. Form-Style Query Continuation: {&var} + {tmpl: "{&who}", want: "&who=fred"}, + {tmpl: "{&half}", want: "&half=50%25"}, + {tmpl: "?fixed=yes{&x}", want: "?fixed=yes&x=1024"}, + {tmpl: "{&x,y,empty}", want: "&x=1024&y=768&empty="}, + {tmpl: "{&x,y,undef}", want: "&x=1024&y=768"}, + {tmpl: "{&var:3}", want: "&var=val"}, + } + for _, tt := range testCases { + esc, unesc, err := Expand(tt.tmpl, values) + if err != nil { + t.Errorf("Expand(%q) error: %v", tt.tmpl, err) + continue + } + if esc != tt.want { + t.Errorf("Expand(%q)\ngot %q\nwant %q", tt.tmpl, esc, tt.want) + } + // Check that the escaped form is equivalent to unescaped. + urlUnesc, err := url.QueryUnescape(esc) + if err != nil { + t.Errorf("Expand(%q) gave invalid escaping %q: %v", tt.tmpl, esc, err) + continue + } + if urlUnesc != unesc { + t.Errorf("Expand(%q) gave inconsistent escaped/unescaped\nunescaped %q\nescaped %q\nwhich is %q", tt.tmpl, unesc, esc, urlUnesc) + } + } +} + +func TestExpandUnescaped(t *testing.T) { + testCases := []struct { + tmpl, wantEsc, wantUnesc string + values map[string]string + }{ + { + tmpl: "/foo/{bucket}/bar", + values: map[string]string{ + "bucket": "simple", + }, + wantEsc: "/foo/simple/bar", + wantUnesc: "/foo/simple/bar", + }, + { + tmpl: "/foo/{bucket}/bar", + values: map[string]string{ + "bucket": "path/with/slash", + }, + wantEsc: "/foo/path%2Fwith%2Fslash/bar", + wantUnesc: "/foo/path/with/slash/bar", + }, + { + tmpl: "/foo/{+bucket}/bar", + values: map[string]string{ + "bucket": "path/with/slash", + }, + wantEsc: "/foo/path/with/slash/bar", + wantUnesc: "/foo/path/with/slash/bar", + }, + { + tmpl: "/foo/{bucket}/bar", + values: map[string]string{ + "bucket": "double%2Fescaped", + }, + wantEsc: "/foo/double%252Fescaped/bar", + wantUnesc: "/foo/double%2Fescaped/bar", + }, + } + for _, tt := range testCases { + esc, unesc, err := Expand(tt.tmpl, tt.values) + if err != nil { + t.Errorf("Expand(%q) error: %v", tt.tmpl, err) + continue + } + if esc != tt.wantEsc || unesc != tt.wantUnesc { + t.Errorf("Expand(%q)\ngot esc=%q, unesc=%q\nwant esc=%q, unesc=%q", tt.tmpl, esc, unesc, tt.wantEsc, tt.wantUnesc) + } + } +} diff --git a/vendor/google.golang.org/api/googleapi/types_test.go b/vendor/google.golang.org/api/googleapi/types_test.go new file mode 100644 index 000000000..da386471f --- /dev/null +++ b/vendor/google.golang.org/api/googleapi/types_test.go @@ -0,0 +1,68 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package googleapi + +import ( + "bytes" + "encoding/json" + "reflect" + "testing" +) + +func TestTypes(t *testing.T) { + type T struct { + I32 Int32s + I64 Int64s + U32 Uint32s + U64 Uint64s + F64 Float64s + } + v := &T{ + I32: Int32s{-1, 2, 3}, + I64: Int64s{-1, 2, 1 << 33}, + U32: Uint32s{1, 2}, + U64: Uint64s{1, 2, 1 << 33}, + F64: Float64s{1.5, 3.33}, + } + got, err := json.Marshal(v) + if err != nil { + t.Fatal(err) + } + want := `{"I32":["-1","2","3"],"I64":["-1","2","8589934592"],"U32":["1","2"],"U64":["1","2","8589934592"],"F64":["1.5","3.33"]}` + if string(got) != want { + t.Fatalf("Marshal mismatch.\n got: %s\nwant: %s\n", got, want) + } + + v2 := new(T) + if err := json.Unmarshal(got, v2); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !reflect.DeepEqual(v, v2) { + t.Fatalf("Unmarshal didn't produce same results.\n got: %#v\nwant: %#v\n", v, v2) + } +} + +func TestRawMessageMarshal(t *testing.T) { + // https://golang.org/issue/14493 + const want = "{}" + b, err := json.Marshal(RawMessage(want)) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + if !bytes.Equal(b, []byte(want)) { + t.Errorf("Marshal(RawMessage(%q)) = %q; want %q", want, b, want) + } +} + +func TestRawMessageUnmarshal(t *testing.T) { + const want = "{}" + var m RawMessage + if err := json.Unmarshal([]byte(want), &m); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !bytes.Equal([]byte(m), []byte(want)) { + t.Errorf("Unmarshal([]byte(%q), &m); m = %q; want %q", want, string(m), want) + } +} diff --git a/vendor/google.golang.org/api/key.json.enc b/vendor/google.golang.org/api/key.json.enc new file mode 100644 index 0000000000000000000000000000000000000000..1286368010e083568344f647654071f7ceb8b97b GIT binary patch literal 2432 zcmV-`34iv1%C6-HLz|k4h;vcrNKKz7QY$uvqLZrA#+ENMaijsr2O^{nlC~UeXsauO zyYC8hS)d;K)UHb-QtlD#IKYdJ?g}fxv6g?6vTk#!0L=Vf3fPH)eBOm5U~8RID32xj z!lLCp_&HFw`%U#Tys4(-#FgY|R$>uPJ7w;orm0Oc>(uZ<l6D3A41HE&9CZ7+{nZH^ zmokF88;4?sQsD!S6a4jmmGW|kqD%!t$fihqwLKQ)$lcP|B;`mL5oEA;)fdr8-cNOk zN2J1$oh%6#{IV1xYuGc9ECSjdB-@?+l6HOi=DKb33a?7f^#e2U`T)@bE-Z@KF`<#8 z>qL>UM3789vKL;ynRdAMh6;6TW5aMs+{3tB^Yc6w*{Cl{GH4Czv@r>GO`DSp!3dzo zR3uepj;3ZqnW<W(j%j%KU^G!Dk8m*3suV(DtejcU{2gIkbqZ4STqFiRPwq{J6dwgz zI|7s!68xXw6Riyr+s|i>fD}rNkoyWgz@_1lrhU1G(&G0Ufz<OY^2$5>eBANC#d?Gj z8$uhd=K|SSFC=S8TgPPvJpv{j?Vy-vE+5n5t-cG!$*~5~6^&c5sD%R-7!QlkDU40Z zlD@Y9kS}fnbJ24Mma6v1r6*9qwXW>;C6%b~>gdgTBGG?+scG)OC>M$E5BNXbUW8;7 zc8i3cDaOc1Y6LhRvBw6JbT80Fhi$HaYini#G)kk~!E#LlsRQq=16HTHM-_CfBzToM zj8%ZqYnlH)fdWV1#41R67OFrpWD)_=MLFQqOokkW4o7BuG`Knp&36oWYIqQVEe?4I ztncN^cxebyD-z=9CzXhhf;iu+2tl-DQRIXuze*rO0=7oD7RPu+bICNWzdY}qc;R?1 zkyR18aH*LL^y@!jQpHA4x)sB8f6zdHm6G+cFY(69HgC?Uj=t^G;D<0(EC=QU{+5qU z?fsf>_9Av!U8ZP8%@okz;q%TE?z}&CiRf;dT7_aFrtVWH!jAAoguht{Uhj!S(sz$f z*%7NLG)!%&kGW{+(HUW{Q&8J(d}V!<=^8>+lsS3FkBYLHG*(h|?DW2TJ{)byUFA1C znor2|5@&ZN@Sg{bFA=;R0xzJr#J6*+bqHwYL0AG5%M&GlFhq2V%wj0b6HEk{Lyd+M zcMiac2axL@)s?BrEnoCdqK<<D0m@p*nD1`5XA0`rXtTV5(fN{CK913iQ3mM#pK}A{ zyX5<`etXQ@5oQ*PAyw9qOq1|e&%<a5QB>-@P~J3LQqhFU94)8iZB&S2c<@KnZfLAm zNCWRle&_F~{0J|scVj=y=sS8USPOlRAUgiu1d#2qOH?IXrV`34*c}c%fW$G4Jzhf> zGvbqKd=144q$(kRH#OSM{5OyGZgSV;+@UvFdJ3)+PGEKl<H4nz4|YL8#)MDFoJ;5y z|C|0mo=6Tj5fwPRw*ZjEbB7UHi9eKoipxVU%2?_!%8jWVC;8>GB-l1Hnbz4UI0ii> zXN)^<!s~BQ-qsx+wCB5bc-QMFS5NbeM_Ua*J(P`bWRjp7pgEx?h}(6zyOXH*1VuqJ zo*X?antfENjHH73AFidyy<1#W=9<jh&N}i(1SqP-Phn5%?3xc)g00Ocm=BSZUZjK% zeqnb?9FoG?h*0%X3ZLM`79h^H&6+!?a(+*qGeuHbGXFCh*u-1oKp3)qrY|hkO(t_| z!Iyo`UPgy-br%c^#Lln7l_;YuXyWoONsx(!xB8E-KS(Zt0l`UsMT=k*;<d%0jjP(r z8m*MPyFSG__JjPXg&|W@7@=ALo^H90p^jw;sHt<U^%tw(4k>d`D<!m7ICT*h^|_b8 zSw#5lrf8{Fxh;bqd;<$7aga3Tu1{&!&}HZpjl`vw1+?A(=V7uMMrpu<<?tVKafkAX zg+BTG9WiW@=Z3_z$^bOjM_1&T(M3Zc_`xU~ciz8LhEoXr&K?gLWc!J4htV=0o9o%~ z0#S|u6kQ_d+xY}?X3w5k(<_Vrf!cCmDuKv|CI>iU(TgWx;L191Le9)veY+s~Drx8- z<stE3bXdnC{k8xaT;pVWfpV=j({PM^z3t#Ml+OwBcn*FSbz?1-`<6AZIa(o;Ex&xZ zOOO|z4iM@Q`hr9H_S9y*`)xZw7%XzS;0056G8TIvjddJnmczTEr`ESy^#$r9l<*vQ zUT&C>pyY_kxT0mLv9&V8Dn8YsvWf@4e7Kd;Gaid|=+))CiiRty{5@B~%ABJSP#7L; zMz07@PP9bY$uKt0^xDVV9GU!xUEIt1AQ5wEJd(kzrAKE{-dt+s&Cni~eWGw}<HnHj z%+!odhdP<)QZh?p%PAMeq~nPYYAc&8QvfPiys)64-A?zzzTU}JIs+v6s@%Mt%34{H zLUeafJwbj2`kPv@(H@3K`+fRn0H?3W*#A@6hAQ0N8te+rEkd>kX0zM<e6mAvG0rxl zkDOIIh%T<gds4xO`P~t>WYSj#!?Bc2PT6+;RU}RkzgPbqlLu4h4J9z*$Sj{&V?*FS ziRI(AY=-x6Hp6wYo&v+7gAwHs)eeiP;Jx?_8i_T5(WyTD+z0lvBLrJz=><PzMIc}? zYDU2tzyp#nx$v<GdeZfwT%#>g4*_cM@?U#t(GCvmsYeKlA&RON^GQ~U_W{$dp+|-R zoU21CG7kyafD0Ga>!q>G51XtnMu^O8726k|O2H|>iamt~oWAREElPma?xBU)7$s|9 z<=Jj+*Kj8ZI^lGK7Jh2(kPi7M8tgiTGi}m!qG13zB$^TIKyX|EPrnayRWF=uw{%c# z@kXpI-e~J3(qA?4o(4L?_fw+7mkt1>WU_E_=i=(!jc;ep=2iX2|4S`}PWTU-8_?$o zn~w9Hw!YVezofK)d->quDBY)~__2rv2dD6H4hNMgzk8GiTdl`1kIYt!Puj4)usus( z^w8HQcU-k&)W^py)N{Oa2KPnetpmbJTi2sBWYp3%rLU9bN**|Qvsm44Y|EhQT-$w6 z>h%&u5S%oMku+El8pC(CE64QgZ`I@$tJn!JdM$O!LmZK1*bU?iwGHb`EYRh3fUY}s zbu?f~HG#eXk-Q!0yU=;@ut;L`zA603{4g51>h(HfMriPid>X@?Xgi{vlNPq*7M-T@ yw(pSQU{u||=+p-tA;gzyD6))#<~f@qU4sSK<16G359nTZ3^o2G67!Z^Xw-)Qqq7VE literal 0 HcmV?d00001 diff --git a/vendor/google.golang.org/appengine/.travis.yml b/vendor/google.golang.org/appengine/.travis.yml new file mode 100644 index 000000000..0762cb91b --- /dev/null +++ b/vendor/google.golang.org/appengine/.travis.yml @@ -0,0 +1,18 @@ +language: go + +go: + - 1.6.3 + - 1.7.1 + +install: + - go get -v -t -d google.golang.org/appengine/... + - mkdir sdk + - curl -o sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.40.zip" + - unzip -q sdk.zip -d sdk + - export APPENGINE_DEV_APPSERVER=$(pwd)/sdk/go_appengine/dev_appserver.py + +script: + - go version + - go test -v google.golang.org/appengine/... + - go test -v -race google.golang.org/appengine/... + - sdk/go_appengine/goapp test -v google.golang.org/appengine/... diff --git a/vendor/google.golang.org/appengine/README.md b/vendor/google.golang.org/appengine/README.md new file mode 100644 index 000000000..b6b11d958 --- /dev/null +++ b/vendor/google.golang.org/appengine/README.md @@ -0,0 +1,73 @@ +# Go App Engine packages + +[![Build Status](https://travis-ci.org/golang/appengine.svg)](https://travis-ci.org/golang/appengine) + +This repository supports the Go runtime on App Engine, +including both the standard App Engine and the +"App Engine flexible environment" (formerly known as "Managed VMs"). +It provides APIs for interacting with App Engine services. +Its canonical import path is `google.golang.org/appengine`. + +See https://cloud.google.com/appengine/docs/go/ +for more information. + +File issue reports and feature requests on the [Google App Engine issue +tracker](https://code.google.com/p/googleappengine/issues/entry?template=Go%20defect). + +## Directory structure +The top level directory of this repository is the `appengine` package. It +contains the +basic APIs (e.g. `appengine.NewContext`) that apply across APIs. Specific API +packages are in subdirectories (e.g. `datastore`). + +There is an `internal` subdirectory that contains service protocol buffers, +plus packages required for connectivity to make API calls. App Engine apps +should not directly import any package under `internal`. + +## Updating a Go App Engine app + +This section describes how to update an older Go App Engine app to use +these packages. A provided tool, `aefix`, can help automate steps 2 and 3 +(run `go get google.golang.org/appengine/cmd/aefix` to install it), but +read the details below since `aefix` can't perform all the changes. + +### 1. Update YAML files (App Engine flexible environment / Managed VMs only) + +The `app.yaml` file (and YAML files for modules) should have these new lines added: +``` +vm: true +``` +See https://cloud.google.com/appengine/docs/go/modules/#Go_Instance_scaling_and_class for details. + +### 2. Update import paths + +The import paths for App Engine packages are now fully qualified, based at `google.golang.org/appengine`. +You will need to update your code to use import paths starting with that; for instance, +code importing `appengine/datastore` will now need to import `google.golang.org/appengine/datastore`. + +### 3. Update code using deprecated, removed or modified APIs + +Most App Engine services are available with exactly the same API. +A few APIs were cleaned up, and some are not available yet. +This list summarises the differences: + +* `appengine.Context` has been replaced with the `Context` type from `golang.org/x/net/context`. +* Logging methods that were on `appengine.Context` are now functions in `google.golang.org/appengine/log`. +* `appengine.Timeout` has been removed. Use `context.WithTimeout` instead. +* `appengine.Datacenter` now takes a `context.Context` argument. +* `datastore.PropertyLoadSaver` has been simplified to use slices in place of channels. +* `delay.Call` now returns an error. +* `search.FieldLoadSaver` now handles document metadata. +* `urlfetch.Transport` no longer has a Deadline field; set a deadline on the + `context.Context` instead. +* `aetest` no longer declares its own Context type, and uses the standard one instead. +* `taskqueue.QueueStats` no longer takes a maxTasks argument. That argument has been + deprecated and unused for a long time. +* `appengine.BackendHostname` and `appengine.BackendInstance` were for the deprecated backends feature. + Use `appengine.ModuleHostname`and `appengine.ModuleName` instead. +* Most of `appengine/file` and parts of `appengine/blobstore` are deprecated. + Use [Google Cloud Storage](https://godoc.org/cloud.google.com/go/storage) if the + feature you require is not present in the new + [blobstore package](https://google.golang.org/appengine/blobstore). +* `appengine/socket` is not required on App Engine flexible environment / Managed VMs. + Use the standard `net` package instead. diff --git a/vendor/google.golang.org/appengine/appengine_test.go b/vendor/google.golang.org/appengine/appengine_test.go new file mode 100644 index 000000000..f1cf0a1b9 --- /dev/null +++ b/vendor/google.golang.org/appengine/appengine_test.go @@ -0,0 +1,49 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package appengine + +import ( + "testing" +) + +func TestValidGeoPoint(t *testing.T) { + testCases := []struct { + desc string + pt GeoPoint + want bool + }{ + { + "valid", + GeoPoint{67.21, 13.37}, + true, + }, + { + "high lat", + GeoPoint{-90.01, 13.37}, + false, + }, + { + "low lat", + GeoPoint{90.01, 13.37}, + false, + }, + { + "high lng", + GeoPoint{67.21, 182}, + false, + }, + { + "low lng", + GeoPoint{67.21, -181}, + false, + }, + } + + for _, tc := range testCases { + if got := tc.pt.Valid(); got != tc.want { + t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want) + } + } +} diff --git a/vendor/google.golang.org/appengine/internal/api_race_test.go b/vendor/google.golang.org/appengine/internal/api_race_test.go new file mode 100644 index 000000000..6cfe90649 --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/api_race_test.go @@ -0,0 +1,9 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +// +build race + +package internal + +func init() { raceDetector = true } diff --git a/vendor/google.golang.org/appengine/internal/api_test.go b/vendor/google.golang.org/appengine/internal/api_test.go new file mode 100644 index 000000000..386d7f6cf --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/api_test.go @@ -0,0 +1,467 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +// +build !appengine + +package internal + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "net/url" + "os" + "os/exec" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/golang/protobuf/proto" + netcontext "golang.org/x/net/context" + + basepb "google.golang.org/appengine/internal/base" + remotepb "google.golang.org/appengine/internal/remote_api" +) + +const testTicketHeader = "X-Magic-Ticket-Header" + +func init() { + ticketHeader = testTicketHeader +} + +type fakeAPIHandler struct { + hang chan int // used for RunSlowly RPC + + LogFlushes int32 // atomic +} + +func (f *fakeAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + writeResponse := func(res *remotepb.Response) { + hresBody, err := proto.Marshal(res) + if err != nil { + http.Error(w, fmt.Sprintf("Failed encoding API response: %v", err), 500) + return + } + w.Write(hresBody) + } + + if r.URL.Path != "/rpc_http" { + http.NotFound(w, r) + return + } + hreqBody, err := ioutil.ReadAll(r.Body) + if err != nil { + http.Error(w, fmt.Sprintf("Bad body: %v", err), 500) + return + } + apiReq := &remotepb.Request{} + if err := proto.Unmarshal(hreqBody, apiReq); err != nil { + http.Error(w, fmt.Sprintf("Bad encoded API request: %v", err), 500) + return + } + if *apiReq.RequestId != "s3cr3t" { + writeResponse(&remotepb.Response{ + RpcError: &remotepb.RpcError{ + Code: proto.Int32(int32(remotepb.RpcError_SECURITY_VIOLATION)), + Detail: proto.String("bad security ticket"), + }, + }) + return + } + if got, want := r.Header.Get(dapperHeader), "trace-001"; got != want { + writeResponse(&remotepb.Response{ + RpcError: &remotepb.RpcError{ + Code: proto.Int32(int32(remotepb.RpcError_BAD_REQUEST)), + Detail: proto.String(fmt.Sprintf("trace info = %q, want %q", got, want)), + }, + }) + return + } + + service, method := *apiReq.ServiceName, *apiReq.Method + var resOut proto.Message + if service == "actordb" && method == "LookupActor" { + req := &basepb.StringProto{} + res := &basepb.StringProto{} + if err := proto.Unmarshal(apiReq.Request, req); err != nil { + http.Error(w, fmt.Sprintf("Bad encoded request: %v", err), 500) + return + } + if *req.Value == "Doctor Who" { + res.Value = proto.String("David Tennant") + } + resOut = res + } + if service == "errors" { + switch method { + case "Non200": + http.Error(w, "I'm a little teapot.", 418) + return + case "ShortResponse": + w.Header().Set("Content-Length", "100") + w.Write([]byte("way too short")) + return + case "OverQuota": + writeResponse(&remotepb.Response{ + RpcError: &remotepb.RpcError{ + Code: proto.Int32(int32(remotepb.RpcError_OVER_QUOTA)), + Detail: proto.String("you are hogging the resources!"), + }, + }) + return + case "RunSlowly": + // TestAPICallRPCFailure creates f.hang, but does not strobe it + // until Call returns with remotepb.RpcError_CANCELLED. + // This is here to force a happens-before relationship between + // the httptest server handler and shutdown. + <-f.hang + resOut = &basepb.VoidProto{} + } + } + if service == "logservice" && method == "Flush" { + // Pretend log flushing is slow. + time.Sleep(50 * time.Millisecond) + atomic.AddInt32(&f.LogFlushes, 1) + resOut = &basepb.VoidProto{} + } + + encOut, err := proto.Marshal(resOut) + if err != nil { + http.Error(w, fmt.Sprintf("Failed encoding response: %v", err), 500) + return + } + writeResponse(&remotepb.Response{ + Response: encOut, + }) +} + +func setup() (f *fakeAPIHandler, c *context, cleanup func()) { + f = &fakeAPIHandler{} + srv := httptest.NewServer(f) + u, err := url.Parse(srv.URL + apiPath) + if err != nil { + panic(fmt.Sprintf("url.Parse(%q): %v", srv.URL+apiPath, err)) + } + return f, &context{ + req: &http.Request{ + Header: http.Header{ + ticketHeader: []string{"s3cr3t"}, + dapperHeader: []string{"trace-001"}, + }, + }, + apiURL: u, + }, srv.Close +} + +func TestAPICall(t *testing.T) { + _, c, cleanup := setup() + defer cleanup() + + req := &basepb.StringProto{ + Value: proto.String("Doctor Who"), + } + res := &basepb.StringProto{} + err := Call(toContext(c), "actordb", "LookupActor", req, res) + if err != nil { + t.Fatalf("API call failed: %v", err) + } + if got, want := *res.Value, "David Tennant"; got != want { + t.Errorf("Response is %q, want %q", got, want) + } +} + +func TestAPICallRPCFailure(t *testing.T) { + f, c, cleanup := setup() + defer cleanup() + + testCases := []struct { + method string + code remotepb.RpcError_ErrorCode + }{ + {"Non200", remotepb.RpcError_UNKNOWN}, + {"ShortResponse", remotepb.RpcError_UNKNOWN}, + {"OverQuota", remotepb.RpcError_OVER_QUOTA}, + {"RunSlowly", remotepb.RpcError_CANCELLED}, + } + f.hang = make(chan int) // only for RunSlowly + for _, tc := range testCases { + ctx, _ := netcontext.WithTimeout(toContext(c), 100*time.Millisecond) + err := Call(ctx, "errors", tc.method, &basepb.VoidProto{}, &basepb.VoidProto{}) + ce, ok := err.(*CallError) + if !ok { + t.Errorf("%s: API call error is %T (%v), want *CallError", tc.method, err, err) + continue + } + if ce.Code != int32(tc.code) { + t.Errorf("%s: ce.Code = %d, want %d", tc.method, ce.Code, tc.code) + } + if tc.method == "RunSlowly" { + f.hang <- 1 // release the HTTP handler + } + } +} + +func TestAPICallDialFailure(t *testing.T) { + // See what happens if the API host is unresponsive. + // This should time out quickly, not hang forever. + _, c, cleanup := setup() + defer cleanup() + // Reset the URL to the production address so that dialing fails. + c.apiURL = apiURL() + + start := time.Now() + err := Call(toContext(c), "foo", "bar", &basepb.VoidProto{}, &basepb.VoidProto{}) + const max = 1 * time.Second + if taken := time.Since(start); taken > max { + t.Errorf("Dial hang took too long: %v > %v", taken, max) + } + if err == nil { + t.Error("Call did not fail") + } +} + +func TestDelayedLogFlushing(t *testing.T) { + f, c, cleanup := setup() + defer cleanup() + + http.HandleFunc("/quick_log", func(w http.ResponseWriter, r *http.Request) { + logC := WithContext(netcontext.Background(), r) + fromContext(logC).apiURL = c.apiURL // Otherwise it will try to use the default URL. + Logf(logC, 1, "It's a lovely day.") + w.WriteHeader(200) + w.Write(make([]byte, 100<<10)) // write 100 KB to force HTTP flush + }) + + r := &http.Request{ + Method: "GET", + URL: &url.URL{ + Scheme: "http", + Path: "/quick_log", + }, + Header: c.req.Header, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + } + w := httptest.NewRecorder() + + // Check that log flushing does not hold up the HTTP response. + start := time.Now() + handleHTTP(w, r) + if d := time.Since(start); d > 10*time.Millisecond { + t.Errorf("handleHTTP took %v, want under 10ms", d) + } + const hdr = "X-AppEngine-Log-Flush-Count" + if h := w.HeaderMap.Get(hdr); h != "1" { + t.Errorf("%s header = %q, want %q", hdr, h, "1") + } + if f := atomic.LoadInt32(&f.LogFlushes); f != 0 { + t.Errorf("After HTTP response: f.LogFlushes = %d, want 0", f) + } + + // Check that the log flush eventually comes in. + time.Sleep(100 * time.Millisecond) + if f := atomic.LoadInt32(&f.LogFlushes); f != 1 { + t.Errorf("After 100ms: f.LogFlushes = %d, want 1", f) + } +} + +func TestRemoteAddr(t *testing.T) { + var addr string + http.HandleFunc("/remote_addr", func(w http.ResponseWriter, r *http.Request) { + addr = r.RemoteAddr + }) + + testCases := []struct { + headers http.Header + addr string + }{ + {http.Header{"X-Appengine-User-Ip": []string{"10.5.2.1"}}, "10.5.2.1:80"}, + {http.Header{"X-Appengine-Remote-Addr": []string{"1.2.3.4"}}, "1.2.3.4:80"}, + {http.Header{"X-Appengine-Remote-Addr": []string{"1.2.3.4:8080"}}, "1.2.3.4:8080"}, + { + http.Header{"X-Appengine-Remote-Addr": []string{"2401:fa00:9:1:7646:a0ff:fe90:ca66"}}, + "[2401:fa00:9:1:7646:a0ff:fe90:ca66]:80", + }, + { + http.Header{"X-Appengine-Remote-Addr": []string{"[::1]:http"}}, + "[::1]:http", + }, + {http.Header{}, "127.0.0.1:80"}, + } + + for _, tc := range testCases { + r := &http.Request{ + Method: "GET", + URL: &url.URL{Scheme: "http", Path: "/remote_addr"}, + Header: tc.headers, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + } + handleHTTP(httptest.NewRecorder(), r) + if addr != tc.addr { + t.Errorf("Header %v, got %q, want %q", tc.headers, addr, tc.addr) + } + } +} + +func TestPanickingHandler(t *testing.T) { + http.HandleFunc("/panic", func(http.ResponseWriter, *http.Request) { + panic("whoops!") + }) + r := &http.Request{ + Method: "GET", + URL: &url.URL{Scheme: "http", Path: "/panic"}, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + } + rec := httptest.NewRecorder() + handleHTTP(rec, r) + if rec.Code != 500 { + t.Errorf("Panicking handler returned HTTP %d, want HTTP %d", rec.Code, 500) + } +} + +var raceDetector = false + +func TestAPICallAllocations(t *testing.T) { + if raceDetector { + t.Skip("not running under race detector") + } + + // Run the test API server in a subprocess so we aren't counting its allocations. + u, cleanup := launchHelperProcess(t) + defer cleanup() + c := &context{ + req: &http.Request{ + Header: http.Header{ + ticketHeader: []string{"s3cr3t"}, + dapperHeader: []string{"trace-001"}, + }, + }, + apiURL: u, + } + + req := &basepb.StringProto{ + Value: proto.String("Doctor Who"), + } + res := &basepb.StringProto{} + var apiErr error + avg := testing.AllocsPerRun(100, func() { + ctx, _ := netcontext.WithTimeout(toContext(c), 100*time.Millisecond) + if err := Call(ctx, "actordb", "LookupActor", req, res); err != nil && apiErr == nil { + apiErr = err // get the first error only + } + }) + if apiErr != nil { + t.Errorf("API call failed: %v", apiErr) + } + + // Lots of room for improvement... + // TODO(djd): Reduce maximum to 85 once the App Engine SDK is based on 1.6. + const min, max float64 = 70, 90 + if avg < min || max < avg { + t.Errorf("Allocations per API call = %g, want in [%g,%g]", avg, min, max) + } +} + +func launchHelperProcess(t *testing.T) (apiURL *url.URL, cleanup func()) { + cmd := exec.Command(os.Args[0], "-test.run=TestHelperProcess") + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + stdin, err := cmd.StdinPipe() + if err != nil { + t.Fatalf("StdinPipe: %v", err) + } + stdout, err := cmd.StdoutPipe() + if err != nil { + t.Fatalf("StdoutPipe: %v", err) + } + if err := cmd.Start(); err != nil { + t.Fatalf("Starting helper process: %v", err) + } + + scan := bufio.NewScanner(stdout) + var u *url.URL + for scan.Scan() { + line := scan.Text() + if hp := strings.TrimPrefix(line, helperProcessMagic); hp != line { + var err error + u, err = url.Parse(hp) + if err != nil { + t.Fatalf("Failed to parse %q: %v", hp, err) + } + break + } + } + if err := scan.Err(); err != nil { + t.Fatalf("Scanning helper process stdout: %v", err) + } + if u == nil { + t.Fatal("Helper process never reported") + } + + return u, func() { + stdin.Close() + if err := cmd.Wait(); err != nil { + t.Errorf("Helper process did not exit cleanly: %v", err) + } + } +} + +const helperProcessMagic = "A lovely helper process is listening at " + +// This isn't a real test. It's used as a helper process. +func TestHelperProcess(*testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + defer os.Exit(0) + + f := &fakeAPIHandler{} + srv := httptest.NewServer(f) + defer srv.Close() + fmt.Println(helperProcessMagic + srv.URL + apiPath) + + // Wait for stdin to be closed. + io.Copy(ioutil.Discard, os.Stdin) +} + +func TestBackgroundContext(t *testing.T) { + environ := []struct { + key, value string + }{ + {"GAE_LONG_APP_ID", "my-app-id"}, + {"GAE_MINOR_VERSION", "067924799508853122"}, + {"GAE_MODULE_INSTANCE", "0"}, + {"GAE_MODULE_NAME", "default"}, + {"GAE_MODULE_VERSION", "20150612t184001"}, + } + for _, v := range environ { + old := os.Getenv(v.key) + os.Setenv(v.key, v.value) + v.value = old + } + defer func() { // Restore old environment after the test completes. + for _, v := range environ { + if v.value == "" { + os.Unsetenv(v.key) + continue + } + os.Setenv(v.key, v.value) + } + }() + + ctx, key := fromContext(BackgroundContext()), "X-Magic-Ticket-Header" + if g, w := ctx.req.Header.Get(key), "my-app-id/default.20150612t184001.0"; g != w { + t.Errorf("%v = %q, want %q", key, g, w) + } + + // Check that using the background context doesn't panic. + req := &basepb.StringProto{ + Value: proto.String("Doctor Who"), + } + res := &basepb.StringProto{} + Call(BackgroundContext(), "actordb", "LookupActor", req, res) // expected to fail +} diff --git a/vendor/google.golang.org/appengine/internal/app_id_test.go b/vendor/google.golang.org/appengine/internal/app_id_test.go new file mode 100644 index 000000000..e69195cd4 --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/app_id_test.go @@ -0,0 +1,34 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package internal + +import ( + "testing" +) + +func TestAppIDParsing(t *testing.T) { + testCases := []struct { + in string + partition, domain, displayID string + }{ + {"simple-app-id", "", "", "simple-app-id"}, + {"domain.com:domain-app-id", "", "domain.com", "domain-app-id"}, + {"part~partition-app-id", "part", "", "partition-app-id"}, + {"part~domain.com:display", "part", "domain.com", "display"}, + } + + for _, tc := range testCases { + part, dom, dis := parseFullAppID(tc.in) + if part != tc.partition { + t.Errorf("partition of %q: got %q, want %q", tc.in, part, tc.partition) + } + if dom != tc.domain { + t.Errorf("domain of %q: got %q, want %q", tc.in, dom, tc.domain) + } + if dis != tc.displayID { + t.Errorf("displayID of %q: got %q, want %q", tc.in, dis, tc.displayID) + } + } +} diff --git a/vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto b/vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto new file mode 100644 index 000000000..19610ca5b --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto @@ -0,0 +1,64 @@ +syntax = "proto2"; +option go_package = "app_identity"; + +package appengine; + +message AppIdentityServiceError { + enum ErrorCode { + SUCCESS = 0; + UNKNOWN_SCOPE = 9; + BLOB_TOO_LARGE = 1000; + DEADLINE_EXCEEDED = 1001; + NOT_A_VALID_APP = 1002; + UNKNOWN_ERROR = 1003; + NOT_ALLOWED = 1005; + NOT_IMPLEMENTED = 1006; + } +} + +message SignForAppRequest { + optional bytes bytes_to_sign = 1; +} + +message SignForAppResponse { + optional string key_name = 1; + optional bytes signature_bytes = 2; +} + +message GetPublicCertificateForAppRequest { +} + +message PublicCertificate { + optional string key_name = 1; + optional string x509_certificate_pem = 2; +} + +message GetPublicCertificateForAppResponse { + repeated PublicCertificate public_certificate_list = 1; + optional int64 max_client_cache_time_in_second = 2; +} + +message GetServiceAccountNameRequest { +} + +message GetServiceAccountNameResponse { + optional string service_account_name = 1; +} + +message GetAccessTokenRequest { + repeated string scope = 1; + optional int64 service_account_id = 2; + optional string service_account_name = 3; +} + +message GetAccessTokenResponse { + optional string access_token = 1; + optional int64 expiration_time = 2; +} + +message GetDefaultGcsBucketNameRequest { +} + +message GetDefaultGcsBucketNameResponse { + optional string default_gcs_bucket_name = 1; +} diff --git a/vendor/google.golang.org/appengine/internal/base/api_base.proto b/vendor/google.golang.org/appengine/internal/base/api_base.proto new file mode 100644 index 000000000..56cd7a3ca --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/base/api_base.proto @@ -0,0 +1,33 @@ +// Built-in base types for API calls. Primarily useful as return types. + +syntax = "proto2"; +option go_package = "base"; + +package appengine.base; + +message StringProto { + required string value = 1; +} + +message Integer32Proto { + required int32 value = 1; +} + +message Integer64Proto { + required int64 value = 1; +} + +message BoolProto { + required bool value = 1; +} + +message DoubleProto { + required double value = 1; +} + +message BytesProto { + required bytes value = 1 [ctype=CORD]; +} + +message VoidProto { +} diff --git a/vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto b/vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto new file mode 100755 index 000000000..e76f126ff --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto @@ -0,0 +1,541 @@ +syntax = "proto2"; +option go_package = "datastore"; + +package appengine; + +message Action{} + +message PropertyValue { + optional int64 int64Value = 1; + optional bool booleanValue = 2; + optional string stringValue = 3; + optional double doubleValue = 4; + + optional group PointValue = 5 { + required double x = 6; + required double y = 7; + } + + optional group UserValue = 8 { + required string email = 9; + required string auth_domain = 10; + optional string nickname = 11; + optional string federated_identity = 21; + optional string federated_provider = 22; + } + + optional group ReferenceValue = 12 { + required string app = 13; + optional string name_space = 20; + repeated group PathElement = 14 { + required string type = 15; + optional int64 id = 16; + optional string name = 17; + } + } +} + +message Property { + enum Meaning { + NO_MEANING = 0; + BLOB = 14; + TEXT = 15; + BYTESTRING = 16; + + ATOM_CATEGORY = 1; + ATOM_LINK = 2; + ATOM_TITLE = 3; + ATOM_CONTENT = 4; + ATOM_SUMMARY = 5; + ATOM_AUTHOR = 6; + + GD_WHEN = 7; + GD_EMAIL = 8; + GEORSS_POINT = 9; + GD_IM = 10; + + GD_PHONENUMBER = 11; + GD_POSTALADDRESS = 12; + + GD_RATING = 13; + + BLOBKEY = 17; + ENTITY_PROTO = 19; + + INDEX_VALUE = 18; + }; + + optional Meaning meaning = 1 [default = NO_MEANING]; + optional string meaning_uri = 2; + + required string name = 3; + + required PropertyValue value = 5; + + required bool multiple = 4; + + optional bool searchable = 6 [default=false]; + + enum FtsTokenizationOption { + HTML = 1; + ATOM = 2; + } + + optional FtsTokenizationOption fts_tokenization_option = 8; + + optional string locale = 9 [default = "en"]; +} + +message Path { + repeated group Element = 1 { + required string type = 2; + optional int64 id = 3; + optional string name = 4; + } +} + +message Reference { + required string app = 13; + optional string name_space = 20; + required Path path = 14; +} + +message User { + required string email = 1; + required string auth_domain = 2; + optional string nickname = 3; + optional string federated_identity = 6; + optional string federated_provider = 7; +} + +message EntityProto { + required Reference key = 13; + required Path entity_group = 16; + optional User owner = 17; + + enum Kind { + GD_CONTACT = 1; + GD_EVENT = 2; + GD_MESSAGE = 3; + } + optional Kind kind = 4; + optional string kind_uri = 5; + + repeated Property property = 14; + repeated Property raw_property = 15; + + optional int32 rank = 18; +} + +message CompositeProperty { + required int64 index_id = 1; + repeated string value = 2; +} + +message Index { + required string entity_type = 1; + required bool ancestor = 5; + repeated group Property = 2 { + required string name = 3; + enum Direction { + ASCENDING = 1; + DESCENDING = 2; + } + optional Direction direction = 4 [default = ASCENDING]; + } +} + +message CompositeIndex { + required string app_id = 1; + required int64 id = 2; + required Index definition = 3; + + enum State { + WRITE_ONLY = 1; + READ_WRITE = 2; + DELETED = 3; + ERROR = 4; + } + required State state = 4; + + optional bool only_use_if_required = 6 [default = false]; +} + +message IndexPostfix { + message IndexValue { + required string property_name = 1; + required PropertyValue value = 2; + } + + repeated IndexValue index_value = 1; + + optional Reference key = 2; + + optional bool before = 3 [default=true]; +} + +message IndexPosition { + optional string key = 1; + + optional bool before = 2 [default=true]; +} + +message Snapshot { + enum Status { + INACTIVE = 0; + ACTIVE = 1; + } + + required int64 ts = 1; +} + +message InternalHeader { + optional string qos = 1; +} + +message Transaction { + optional InternalHeader header = 4; + required fixed64 handle = 1; + required string app = 2; + optional bool mark_changes = 3 [default = false]; +} + +message Query { + optional InternalHeader header = 39; + + required string app = 1; + optional string name_space = 29; + + optional string kind = 3; + optional Reference ancestor = 17; + + repeated group Filter = 4 { + enum Operator { + LESS_THAN = 1; + LESS_THAN_OR_EQUAL = 2; + GREATER_THAN = 3; + GREATER_THAN_OR_EQUAL = 4; + EQUAL = 5; + IN = 6; + EXISTS = 7; + } + + required Operator op = 6; + repeated Property property = 14; + } + + optional string search_query = 8; + + repeated group Order = 9 { + enum Direction { + ASCENDING = 1; + DESCENDING = 2; + } + + required string property = 10; + optional Direction direction = 11 [default = ASCENDING]; + } + + enum Hint { + ORDER_FIRST = 1; + ANCESTOR_FIRST = 2; + FILTER_FIRST = 3; + } + optional Hint hint = 18; + + optional int32 count = 23; + + optional int32 offset = 12 [default = 0]; + + optional int32 limit = 16; + + optional CompiledCursor compiled_cursor = 30; + optional CompiledCursor end_compiled_cursor = 31; + + repeated CompositeIndex composite_index = 19; + + optional bool require_perfect_plan = 20 [default = false]; + + optional bool keys_only = 21 [default = false]; + + optional Transaction transaction = 22; + + optional bool compile = 25 [default = false]; + + optional int64 failover_ms = 26; + + optional bool strong = 32; + + repeated string property_name = 33; + + repeated string group_by_property_name = 34; + + optional bool distinct = 24; + + optional int64 min_safe_time_seconds = 35; + + repeated string safe_replica_name = 36; + + optional bool persist_offset = 37 [default=false]; +} + +message CompiledQuery { + required group PrimaryScan = 1 { + optional string index_name = 2; + + optional string start_key = 3; + optional bool start_inclusive = 4; + optional string end_key = 5; + optional bool end_inclusive = 6; + + repeated string start_postfix_value = 22; + repeated string end_postfix_value = 23; + + optional int64 end_unapplied_log_timestamp_us = 19; + } + + repeated group MergeJoinScan = 7 { + required string index_name = 8; + + repeated string prefix_value = 9; + + optional bool value_prefix = 20 [default=false]; + } + + optional Index index_def = 21; + + optional int32 offset = 10 [default = 0]; + + optional int32 limit = 11; + + required bool keys_only = 12; + + repeated string property_name = 24; + + optional int32 distinct_infix_size = 25; + + optional group EntityFilter = 13 { + optional bool distinct = 14 [default=false]; + + optional string kind = 17; + optional Reference ancestor = 18; + } +} + +message CompiledCursor { + optional group Position = 2 { + optional string start_key = 27; + + repeated group IndexValue = 29 { + optional string property = 30; + required PropertyValue value = 31; + } + + optional Reference key = 32; + + optional bool start_inclusive = 28 [default=true]; + } +} + +message Cursor { + required fixed64 cursor = 1; + + optional string app = 2; +} + +message Error { + enum ErrorCode { + BAD_REQUEST = 1; + CONCURRENT_TRANSACTION = 2; + INTERNAL_ERROR = 3; + NEED_INDEX = 4; + TIMEOUT = 5; + PERMISSION_DENIED = 6; + BIGTABLE_ERROR = 7; + COMMITTED_BUT_STILL_APPLYING = 8; + CAPABILITY_DISABLED = 9; + TRY_ALTERNATE_BACKEND = 10; + SAFE_TIME_TOO_OLD = 11; + } +} + +message Cost { + optional int32 index_writes = 1; + optional int32 index_write_bytes = 2; + optional int32 entity_writes = 3; + optional int32 entity_write_bytes = 4; + optional group CommitCost = 5 { + optional int32 requested_entity_puts = 6; + optional int32 requested_entity_deletes = 7; + }; + optional int32 approximate_storage_delta = 8; + optional int32 id_sequence_updates = 9; +} + +message GetRequest { + optional InternalHeader header = 6; + + repeated Reference key = 1; + optional Transaction transaction = 2; + + optional int64 failover_ms = 3; + + optional bool strong = 4; + + optional bool allow_deferred = 5 [default=false]; +} + +message GetResponse { + repeated group Entity = 1 { + optional EntityProto entity = 2; + optional Reference key = 4; + + optional int64 version = 3; + } + + repeated Reference deferred = 5; + + optional bool in_order = 6 [default=true]; +} + +message PutRequest { + optional InternalHeader header = 11; + + repeated EntityProto entity = 1; + optional Transaction transaction = 2; + repeated CompositeIndex composite_index = 3; + + optional bool trusted = 4 [default = false]; + + optional bool force = 7 [default = false]; + + optional bool mark_changes = 8 [default = false]; + repeated Snapshot snapshot = 9; + + enum AutoIdPolicy { + CURRENT = 0; + SEQUENTIAL = 1; + } + optional AutoIdPolicy auto_id_policy = 10 [default = CURRENT]; +} + +message PutResponse { + repeated Reference key = 1; + optional Cost cost = 2; + repeated int64 version = 3; +} + +message TouchRequest { + optional InternalHeader header = 10; + + repeated Reference key = 1; + repeated CompositeIndex composite_index = 2; + optional bool force = 3 [default = false]; + repeated Snapshot snapshot = 9; +} + +message TouchResponse { + optional Cost cost = 1; +} + +message DeleteRequest { + optional InternalHeader header = 10; + + repeated Reference key = 6; + optional Transaction transaction = 5; + + optional bool trusted = 4 [default = false]; + + optional bool force = 7 [default = false]; + + optional bool mark_changes = 8 [default = false]; + repeated Snapshot snapshot = 9; +} + +message DeleteResponse { + optional Cost cost = 1; + repeated int64 version = 3; +} + +message NextRequest { + optional InternalHeader header = 5; + + required Cursor cursor = 1; + optional int32 count = 2; + + optional int32 offset = 4 [default = 0]; + + optional bool compile = 3 [default = false]; +} + +message QueryResult { + optional Cursor cursor = 1; + + repeated EntityProto result = 2; + + optional int32 skipped_results = 7; + + required bool more_results = 3; + + optional bool keys_only = 4; + + optional bool index_only = 9; + + optional bool small_ops = 10; + + optional CompiledQuery compiled_query = 5; + + optional CompiledCursor compiled_cursor = 6; + + repeated CompositeIndex index = 8; + + repeated int64 version = 11; +} + +message AllocateIdsRequest { + optional InternalHeader header = 4; + + optional Reference model_key = 1; + + optional int64 size = 2; + + optional int64 max = 3; + + repeated Reference reserve = 5; +} + +message AllocateIdsResponse { + required int64 start = 1; + required int64 end = 2; + optional Cost cost = 3; +} + +message CompositeIndices { + repeated CompositeIndex index = 1; +} + +message AddActionsRequest { + optional InternalHeader header = 3; + + required Transaction transaction = 1; + repeated Action action = 2; +} + +message AddActionsResponse { +} + +message BeginTransactionRequest { + optional InternalHeader header = 3; + + required string app = 1; + optional bool allow_multiple_eg = 2 [default = false]; +} + +message CommitResponse { + optional Cost cost = 1; + + repeated group Version = 3 { + required Reference root_entity_key = 4; + required int64 version = 5; + } +} diff --git a/vendor/google.golang.org/appengine/internal/internal_vm_test.go b/vendor/google.golang.org/appengine/internal/internal_vm_test.go new file mode 100644 index 000000000..f8097616b --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/internal_vm_test.go @@ -0,0 +1,60 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +// +build !appengine + +package internal + +import ( + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" +) + +func TestInstallingHealthChecker(t *testing.T) { + try := func(desc string, mux *http.ServeMux, wantCode int, wantBody string) { + installHealthChecker(mux) + srv := httptest.NewServer(mux) + defer srv.Close() + + resp, err := http.Get(srv.URL + "/_ah/health") + if err != nil { + t.Errorf("%s: http.Get: %v", desc, err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("%s: reading body: %v", desc, err) + return + } + + if resp.StatusCode != wantCode { + t.Errorf("%s: got HTTP %d, want %d", desc, resp.StatusCode, wantCode) + return + } + if wantBody != "" && string(body) != wantBody { + t.Errorf("%s: got HTTP body %q, want %q", desc, body, wantBody) + return + } + } + + // If there's no handlers, or only a root handler, a health checker should be installed. + try("empty mux", http.NewServeMux(), 200, "ok") + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, "root handler") + }) + try("mux with root handler", mux, 200, "ok") + + // If there's a custom health check handler, one should not be installed. + mux = http.NewServeMux() + mux.HandleFunc("/_ah/health", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(418) + io.WriteString(w, "I'm short and stout!") + }) + try("mux with custom health checker", mux, 418, "I'm short and stout!") +} diff --git a/vendor/google.golang.org/appengine/internal/log/log_service.proto b/vendor/google.golang.org/appengine/internal/log/log_service.proto new file mode 100644 index 000000000..8981dc475 --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/log/log_service.proto @@ -0,0 +1,150 @@ +syntax = "proto2"; +option go_package = "log"; + +package appengine; + +message LogServiceError { + enum ErrorCode { + OK = 0; + INVALID_REQUEST = 1; + STORAGE_ERROR = 2; + } +} + +message UserAppLogLine { + required int64 timestamp_usec = 1; + required int64 level = 2; + required string message = 3; +} + +message UserAppLogGroup { + repeated UserAppLogLine log_line = 2; +} + +message FlushRequest { + optional bytes logs = 1; +} + +message SetStatusRequest { + required string status = 1; +} + + +message LogOffset { + optional bytes request_id = 1; +} + +message LogLine { + required int64 time = 1; + required int32 level = 2; + required string log_message = 3; +} + +message RequestLog { + required string app_id = 1; + optional string module_id = 37 [default="default"]; + required string version_id = 2; + required bytes request_id = 3; + optional LogOffset offset = 35; + required string ip = 4; + optional string nickname = 5; + required int64 start_time = 6; + required int64 end_time = 7; + required int64 latency = 8; + required int64 mcycles = 9; + required string method = 10; + required string resource = 11; + required string http_version = 12; + required int32 status = 13; + required int64 response_size = 14; + optional string referrer = 15; + optional string user_agent = 16; + required string url_map_entry = 17; + required string combined = 18; + optional int64 api_mcycles = 19; + optional string host = 20; + optional double cost = 21; + + optional string task_queue_name = 22; + optional string task_name = 23; + + optional bool was_loading_request = 24; + optional int64 pending_time = 25; + optional int32 replica_index = 26 [default = -1]; + optional bool finished = 27 [default = true]; + optional bytes clone_key = 28; + + repeated LogLine line = 29; + + optional bool lines_incomplete = 36; + optional bytes app_engine_release = 38; + + optional int32 exit_reason = 30; + optional bool was_throttled_for_time = 31; + optional bool was_throttled_for_requests = 32; + optional int64 throttled_time = 33; + + optional bytes server_name = 34; +} + +message LogModuleVersion { + optional string module_id = 1 [default="default"]; + optional string version_id = 2; +} + +message LogReadRequest { + required string app_id = 1; + repeated string version_id = 2; + repeated LogModuleVersion module_version = 19; + + optional int64 start_time = 3; + optional int64 end_time = 4; + optional LogOffset offset = 5; + repeated bytes request_id = 6; + + optional int32 minimum_log_level = 7; + optional bool include_incomplete = 8; + optional int64 count = 9; + + optional string combined_log_regex = 14; + optional string host_regex = 15; + optional int32 replica_index = 16; + + optional bool include_app_logs = 10; + optional int32 app_logs_per_request = 17; + optional bool include_host = 11; + optional bool include_all = 12; + optional bool cache_iterator = 13; + optional int32 num_shards = 18; +} + +message LogReadResponse { + repeated RequestLog log = 1; + optional LogOffset offset = 2; + optional int64 last_end_time = 3; +} + +message LogUsageRecord { + optional string version_id = 1; + optional int32 start_time = 2; + optional int32 end_time = 3; + optional int64 count = 4; + optional int64 total_size = 5; + optional int32 records = 6; +} + +message LogUsageRequest { + required string app_id = 1; + repeated string version_id = 2; + optional int32 start_time = 3; + optional int32 end_time = 4; + optional uint32 resolution_hours = 5 [default = 1]; + optional bool combine_versions = 6; + optional int32 usage_version = 7; + optional bool versions_only = 8; +} + +message LogUsageResponse { + repeated LogUsageRecord usage = 1; + optional LogUsageRecord summary = 2; +} diff --git a/vendor/google.golang.org/appengine/internal/modules/modules_service.proto b/vendor/google.golang.org/appengine/internal/modules/modules_service.proto new file mode 100644 index 000000000..d29f0065a --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/modules/modules_service.proto @@ -0,0 +1,80 @@ +syntax = "proto2"; +option go_package = "modules"; + +package appengine; + +message ModulesServiceError { + enum ErrorCode { + OK = 0; + INVALID_MODULE = 1; + INVALID_VERSION = 2; + INVALID_INSTANCES = 3; + TRANSIENT_ERROR = 4; + UNEXPECTED_STATE = 5; + } +} + +message GetModulesRequest { +} + +message GetModulesResponse { + repeated string module = 1; +} + +message GetVersionsRequest { + optional string module = 1; +} + +message GetVersionsResponse { + repeated string version = 1; +} + +message GetDefaultVersionRequest { + optional string module = 1; +} + +message GetDefaultVersionResponse { + required string version = 1; +} + +message GetNumInstancesRequest { + optional string module = 1; + optional string version = 2; +} + +message GetNumInstancesResponse { + required int64 instances = 1; +} + +message SetNumInstancesRequest { + optional string module = 1; + optional string version = 2; + required int64 instances = 3; +} + +message SetNumInstancesResponse {} + +message StartModuleRequest { + required string module = 1; + required string version = 2; +} + +message StartModuleResponse {} + +message StopModuleRequest { + optional string module = 1; + optional string version = 2; +} + +message StopModuleResponse {} + +message GetHostnameRequest { + optional string module = 1; + optional string version = 2; + optional string instance = 3; +} + +message GetHostnameResponse { + required string hostname = 1; +} + diff --git a/vendor/google.golang.org/appengine/internal/net_test.go b/vendor/google.golang.org/appengine/internal/net_test.go new file mode 100644 index 000000000..24da8bb2b --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/net_test.go @@ -0,0 +1,58 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +// +build !appengine + +package internal + +import ( + "sync" + "testing" + "time" + + netcontext "golang.org/x/net/context" + + basepb "google.golang.org/appengine/internal/base" +) + +func TestDialLimit(t *testing.T) { + // Fill up semaphore with false acquisitions to permit only two TCP connections at a time. + // We don't replace limitSem because that results in a data race when net/http lazily closes connections. + nFake := cap(limitSem) - 2 + for i := 0; i < nFake; i++ { + limitSem <- 1 + } + defer func() { + for i := 0; i < nFake; i++ { + <-limitSem + } + }() + + f, c, cleanup := setup() // setup is in api_test.go + defer cleanup() + f.hang = make(chan int) + + // If we make two RunSlowly RPCs (which will wait for f.hang to be strobed), + // then the simple Non200 RPC should hang. + var wg sync.WaitGroup + wg.Add(2) + for i := 0; i < 2; i++ { + go func() { + defer wg.Done() + Call(toContext(c), "errors", "RunSlowly", &basepb.VoidProto{}, &basepb.VoidProto{}) + }() + } + time.Sleep(50 * time.Millisecond) // let those two RPCs start + + ctx, _ := netcontext.WithTimeout(toContext(c), 50*time.Millisecond) + err := Call(ctx, "errors", "Non200", &basepb.VoidProto{}, &basepb.VoidProto{}) + if err != errTimeout { + t.Errorf("Non200 RPC returned with err %v, want errTimeout", err) + } + + // Drain the two RunSlowly calls. + f.hang <- 1 + f.hang <- 1 + wg.Wait() +} diff --git a/vendor/google.golang.org/appengine/internal/regen.sh b/vendor/google.golang.org/appengine/internal/regen.sh new file mode 100755 index 000000000..2fdb546a6 --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/regen.sh @@ -0,0 +1,40 @@ +#!/bin/bash -e +# +# This script rebuilds the generated code for the protocol buffers. +# To run this you will need protoc and goprotobuf installed; +# see https://github.com/golang/protobuf for instructions. + +PKG=google.golang.org/appengine + +function die() { + echo 1>&2 $* + exit 1 +} + +# Sanity check that the right tools are accessible. +for tool in go protoc protoc-gen-go; do + q=$(which $tool) || die "didn't find $tool" + echo 1>&2 "$tool: $q" +done + +echo -n 1>&2 "finding package dir... " +pkgdir=$(go list -f '{{.Dir}}' $PKG) +echo 1>&2 $pkgdir +base=$(echo $pkgdir | sed "s,/$PKG\$,,") +echo 1>&2 "base: $base" +cd $base + +# Run protoc once per package. +for dir in $(find $PKG/internal -name '*.proto' | xargs dirname | sort | uniq); do + echo 1>&2 "* $dir" + protoc --go_out=. $dir/*.proto +done + +for f in $(find $PKG/internal -name '*.pb.go'); do + # Remove proto.RegisterEnum calls. + # These cause duplicate registration panics when these packages + # are used on classic App Engine. proto.RegisterEnum only affects + # parsing the text format; we don't care about that. + # https://code.google.com/p/googleappengine/issues/detail?id=11670#c17 + sed -i '/proto.RegisterEnum/d' $f +done diff --git a/vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto b/vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto new file mode 100644 index 000000000..f21763a4e --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto @@ -0,0 +1,44 @@ +syntax = "proto2"; +option go_package = "remote_api"; + +package remote_api; + +message Request { + required string service_name = 2; + required string method = 3; + required bytes request = 4; + optional string request_id = 5; +} + +message ApplicationError { + required int32 code = 1; + required string detail = 2; +} + +message RpcError { + enum ErrorCode { + UNKNOWN = 0; + CALL_NOT_FOUND = 1; + PARSE_ERROR = 2; + SECURITY_VIOLATION = 3; + OVER_QUOTA = 4; + REQUEST_TOO_LARGE = 5; + CAPABILITY_DISABLED = 6; + FEATURE_DISABLED = 7; + BAD_REQUEST = 8; + RESPONSE_TOO_LARGE = 9; + CANCELLED = 10; + REPLAY_ERROR = 11; + DEADLINE_EXCEEDED = 12; + } + required int32 code = 1; + optional string detail = 2; +} + +message Response { + optional bytes response = 1; + optional bytes exception = 2; + optional ApplicationError application_error = 3; + optional bytes java_exception = 4; + optional RpcError rpc_error = 5; +} diff --git a/vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto b/vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto new file mode 100644 index 000000000..f695edf6a --- /dev/null +++ b/vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto @@ -0,0 +1,64 @@ +syntax = "proto2"; +option go_package = "urlfetch"; + +package appengine; + +message URLFetchServiceError { + enum ErrorCode { + OK = 0; + INVALID_URL = 1; + FETCH_ERROR = 2; + UNSPECIFIED_ERROR = 3; + RESPONSE_TOO_LARGE = 4; + DEADLINE_EXCEEDED = 5; + SSL_CERTIFICATE_ERROR = 6; + DNS_ERROR = 7; + CLOSED = 8; + INTERNAL_TRANSIENT_ERROR = 9; + TOO_MANY_REDIRECTS = 10; + MALFORMED_REPLY = 11; + CONNECTION_ERROR = 12; + } +} + +message URLFetchRequest { + enum RequestMethod { + GET = 1; + POST = 2; + HEAD = 3; + PUT = 4; + DELETE = 5; + PATCH = 6; + } + required RequestMethod Method = 1; + required string Url = 2; + repeated group Header = 3 { + required string Key = 4; + required string Value = 5; + } + optional bytes Payload = 6 [ctype=CORD]; + + optional bool FollowRedirects = 7 [default=true]; + + optional double Deadline = 8; + + optional bool MustValidateServerCertificate = 9 [default=true]; +} + +message URLFetchResponse { + optional bytes Content = 1; + required int32 StatusCode = 2; + repeated group Header = 3 { + required string Key = 4; + required string Value = 5; + } + optional bool ContentWasTruncated = 6 [default=false]; + optional int64 ExternalBytesSent = 7; + optional int64 ExternalBytesReceived = 8; + + optional string FinalUrl = 9; + + optional int64 ApiCpuMilliseconds = 10 [default=0]; + optional int64 ApiBytesSent = 11 [default=0]; + optional int64 ApiBytesReceived = 12 [default=0]; +} diff --git a/vendor/google.golang.org/appengine/namespace_test.go b/vendor/google.golang.org/appengine/namespace_test.go new file mode 100644 index 000000000..847f640bd --- /dev/null +++ b/vendor/google.golang.org/appengine/namespace_test.go @@ -0,0 +1,39 @@ +// Copyright 2014 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package appengine + +import ( + "testing" + + "golang.org/x/net/context" +) + +func TestNamespaceValidity(t *testing.T) { + testCases := []struct { + namespace string + ok bool + }{ + // data from Python's namespace_manager_test.py + {"", true}, + {"__a.namespace.123__", true}, + {"-_A....NAMESPACE-_", true}, + {"-", true}, + {".", true}, + {".-", true}, + + {"?", false}, + {"+", false}, + {"!", false}, + {" ", false}, + } + for _, tc := range testCases { + _, err := Namespace(context.Background(), tc.namespace) + if err == nil && !tc.ok { + t.Errorf("Namespace %q should be rejected, but wasn't", tc.namespace) + } else if err != nil && tc.ok { + t.Errorf("Namespace %q should be accepted, but wasn't", tc.namespace) + } + } +} diff --git a/vendor/gopkg.in/inf.v0/benchmark_test.go b/vendor/gopkg.in/inf.v0/benchmark_test.go new file mode 100644 index 000000000..27071da0e --- /dev/null +++ b/vendor/gopkg.in/inf.v0/benchmark_test.go @@ -0,0 +1,210 @@ +package inf + +import ( + "fmt" + "math/big" + "math/rand" + "sync" + "testing" +) + +const maxcap = 1024 * 1024 +const bits = 256 +const maxscale = 32 + +var once sync.Once + +var decInput [][2]Dec +var intInput [][2]big.Int + +var initBench = func() { + decInput = make([][2]Dec, maxcap) + intInput = make([][2]big.Int, maxcap) + max := new(big.Int).Lsh(big.NewInt(1), bits) + r := rand.New(rand.NewSource(0)) + for i := 0; i < cap(decInput); i++ { + decInput[i][0].SetUnscaledBig(new(big.Int).Rand(r, max)). + SetScale(Scale(r.Int31n(int32(2*maxscale-1)) - int32(maxscale))) + decInput[i][1].SetUnscaledBig(new(big.Int).Rand(r, max)). + SetScale(Scale(r.Int31n(int32(2*maxscale-1)) - int32(maxscale))) + } + for i := 0; i < cap(intInput); i++ { + intInput[i][0].Rand(r, max) + intInput[i][1].Rand(r, max) + } +} + +func doBenchmarkDec1(b *testing.B, f func(z *Dec)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&decInput[i%maxcap][0]) + } +} + +func doBenchmarkDec2(b *testing.B, f func(x, y *Dec)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&decInput[i%maxcap][0], &decInput[i%maxcap][1]) + } +} + +func doBenchmarkInt1(b *testing.B, f func(z *big.Int)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&intInput[i%maxcap][0]) + } +} + +func doBenchmarkInt2(b *testing.B, f func(x, y *big.Int)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&intInput[i%maxcap][0], &intInput[i%maxcap][1]) + } +} + +func Benchmark_Dec_String(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + x.String() + }) +} + +func Benchmark_Dec_StringScan(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + s := x.String() + d := new(Dec) + fmt.Sscan(s, d) + }) +} + +func Benchmark_Dec_GobEncode(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + x.GobEncode() + }) +} + +func Benchmark_Dec_GobEnDecode(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + g, _ := x.GobEncode() + new(Dec).GobDecode(g) + }) +} + +func Benchmark_Dec_Add(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + ys := y.Scale() + y.SetScale(x.Scale()) + _ = new(Dec).Add(x, y) + y.SetScale(ys) + }) +} + +func Benchmark_Dec_AddMixed(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).Add(x, y) + }) +} + +func Benchmark_Dec_Sub(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + ys := y.Scale() + y.SetScale(x.Scale()) + _ = new(Dec).Sub(x, y) + y.SetScale(ys) + }) +} + +func Benchmark_Dec_SubMixed(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).Sub(x, y) + }) +} + +func Benchmark_Dec_Mul(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).Mul(x, y) + }) +} + +func Benchmark_Dec_Mul_QuoExact(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + v := new(Dec).Mul(x, y) + _ = new(Dec).QuoExact(v, y) + }) +} + +func Benchmark_Dec_QuoRound_Fixed_Down(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).QuoRound(x, y, 0, RoundDown) + }) +} + +func Benchmark_Dec_QuoRound_Fixed_HalfUp(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).QuoRound(x, y, 0, RoundHalfUp) + }) +} + +func Benchmark_Int_String(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + x.String() + }) +} + +func Benchmark_Int_StringScan(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + s := x.String() + d := new(big.Int) + fmt.Sscan(s, d) + }) +} + +func Benchmark_Int_GobEncode(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + x.GobEncode() + }) +} + +func Benchmark_Int_GobEnDecode(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + g, _ := x.GobEncode() + new(big.Int).GobDecode(g) + }) +} + +func Benchmark_Int_Add(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Add(x, y) + }) +} + +func Benchmark_Int_Sub(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Sub(x, y) + }) +} + +func Benchmark_Int_Mul(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Mul(x, y) + }) +} + +func Benchmark_Int_Quo(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Quo(x, y) + }) +} + +func Benchmark_Int_QuoRem(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _, _ = new(big.Int).QuoRem(x, y, new(big.Int)) + }) +} diff --git a/vendor/gopkg.in/inf.v0/dec_go1_2_test.go b/vendor/gopkg.in/inf.v0/dec_go1_2_test.go new file mode 100644 index 000000000..5df0f7b55 --- /dev/null +++ b/vendor/gopkg.in/inf.v0/dec_go1_2_test.go @@ -0,0 +1,33 @@ +// +build go1.2 + +package inf + +import ( + "encoding" + "encoding/json" + "testing" +) + +var _ encoding.TextMarshaler = new(Dec) +var _ encoding.TextUnmarshaler = new(Dec) + +type Obj struct { + Val *Dec +} + +func TestDecJsonMarshalUnmarshal(t *testing.T) { + o := Obj{Val: NewDec(123, 2)} + js, err := json.Marshal(o) + if err != nil { + t.Fatalf("json.Marshal(%v): got %v, want ok", o, err) + } + o2 := &Obj{} + err = json.Unmarshal(js, o2) + if err != nil { + t.Fatalf("json.Unmarshal(%#q): got %v, want ok", js, err) + } + if o.Val.Scale() != o2.Val.Scale() || + o.Val.UnscaledBig().Cmp(o2.Val.UnscaledBig()) != 0 { + t.Fatalf("json.Unmarshal(json.Marshal(%v)): want %v, got %v", o, o, o2) + } +} diff --git a/vendor/gopkg.in/inf.v0/dec_internal_test.go b/vendor/gopkg.in/inf.v0/dec_internal_test.go new file mode 100644 index 000000000..d4fbe3e5b --- /dev/null +++ b/vendor/gopkg.in/inf.v0/dec_internal_test.go @@ -0,0 +1,40 @@ +package inf + +import ( + "math/big" + "testing" +) + +var decQuoRemZZZ = []struct { + z, x, y *Dec + r *big.Rat + srA, srB int +}{ + // basic examples + {NewDec(1, 0), NewDec(2, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1}, + {NewDec(15, 1), NewDec(3, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1}, + {NewDec(1, 1), NewDec(1, 0), NewDec(10, 0), big.NewRat(0, 1), 0, 1}, + {NewDec(0, 0), NewDec(2, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1}, + {NewDec(0, 0), NewDec(2, 0), NewDec(6, 0), big.NewRat(1, 3), 1, 1}, + {NewDec(1, 1), NewDec(2, 0), NewDec(12, 0), big.NewRat(2, 3), 1, 1}, + + // examples from the Go Language Specification + {NewDec(1, 0), NewDec(5, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1}, + {NewDec(-1, 0), NewDec(-5, 0), NewDec(3, 0), big.NewRat(-2, 3), -1, 1}, + {NewDec(-1, 0), NewDec(5, 0), NewDec(-3, 0), big.NewRat(-2, 3), 1, -1}, + {NewDec(1, 0), NewDec(-5, 0), NewDec(-3, 0), big.NewRat(2, 3), -1, -1}, +} + +func TestDecQuoRem(t *testing.T) { + for i, a := range decQuoRemZZZ { + z, rA, rB := new(Dec), new(big.Int), new(big.Int) + s := scaleQuoExact{}.Scale(a.x, a.y) + z.quoRem(a.x, a.y, s, true, rA, rB) + if a.z.Cmp(z) != 0 || a.r.Cmp(new(big.Rat).SetFrac(rA, rB)) != 0 { + t.Errorf("#%d QuoRemZZZ got %v, %v, %v; expected %v, %v", i, z, rA, rB, a.z, a.r) + } + if a.srA != rA.Sign() || a.srB != rB.Sign() { + t.Errorf("#%d QuoRemZZZ wrong signs, got %v, %v; expected %v, %v", i, rA.Sign(), rB.Sign(), a.srA, a.srB) + } + } +} diff --git a/vendor/gopkg.in/inf.v0/dec_test.go b/vendor/gopkg.in/inf.v0/dec_test.go new file mode 100644 index 000000000..e4b09b3fd --- /dev/null +++ b/vendor/gopkg.in/inf.v0/dec_test.go @@ -0,0 +1,379 @@ +package inf_test + +import ( + "bytes" + "encoding/gob" + "fmt" + "math/big" + "strings" + "testing" + + "gopkg.in/inf.v0" +) + +type decFunZZ func(z, x, y *inf.Dec) *inf.Dec +type decArgZZ struct { + z, x, y *inf.Dec +} + +var decSumZZ = []decArgZZ{ + {inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)}, + {inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)}, + {inf.NewDec(1111111110, 0), inf.NewDec(123456789, 0), inf.NewDec(987654321, 0)}, + {inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(0, 0)}, + {inf.NewDec(864197532, 0), inf.NewDec(-123456789, 0), inf.NewDec(987654321, 0)}, + {inf.NewDec(-1111111110, 0), inf.NewDec(-123456789, 0), inf.NewDec(-987654321, 0)}, + {inf.NewDec(12, 2), inf.NewDec(1, 1), inf.NewDec(2, 2)}, +} + +var decProdZZ = []decArgZZ{ + {inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)}, + {inf.NewDec(0, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)}, + {inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(1, 0)}, + {inf.NewDec(-991*991, 0), inf.NewDec(991, 0), inf.NewDec(-991, 0)}, + {inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)}, + {inf.NewDec(2, -3), inf.NewDec(1, -1), inf.NewDec(2, -2)}, + {inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)}, +} + +func TestDecSignZ(t *testing.T) { + var zero inf.Dec + for _, a := range decSumZZ { + s := a.z.Sign() + e := a.z.Cmp(&zero) + if s != e { + t.Errorf("got %d; want %d for z = %v", s, e, a.z) + } + } +} + +func TestDecAbsZ(t *testing.T) { + var zero inf.Dec + for _, a := range decSumZZ { + var z inf.Dec + z.Abs(a.z) + var e inf.Dec + e.Set(a.z) + if e.Cmp(&zero) < 0 { + e.Sub(&zero, &e) + } + if z.Cmp(&e) != 0 { + t.Errorf("got z = %v; want %v", z, e) + } + } +} + +func testDecFunZZ(t *testing.T, msg string, f decFunZZ, a decArgZZ) { + var z inf.Dec + f(&z, a.x, a.y) + if (&z).Cmp(a.z) != 0 { + t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z) + } +} + +func TestDecSumZZ(t *testing.T) { + AddZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Add(x, y) } + SubZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Sub(x, y) } + for _, a := range decSumZZ { + arg := a + testDecFunZZ(t, "AddZZ", AddZZ, arg) + + arg = decArgZZ{a.z, a.y, a.x} + testDecFunZZ(t, "AddZZ symmetric", AddZZ, arg) + + arg = decArgZZ{a.x, a.z, a.y} + testDecFunZZ(t, "SubZZ", SubZZ, arg) + + arg = decArgZZ{a.y, a.z, a.x} + testDecFunZZ(t, "SubZZ symmetric", SubZZ, arg) + } +} + +func TestDecProdZZ(t *testing.T) { + MulZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Mul(x, y) } + for _, a := range decProdZZ { + arg := a + testDecFunZZ(t, "MulZZ", MulZZ, arg) + + arg = decArgZZ{a.z, a.y, a.x} + testDecFunZZ(t, "MulZZ symmetric", MulZZ, arg) + } +} + +var decUnscaledTests = []struct { + d *inf.Dec + u int64 // ignored when ok == false + ok bool +}{ + {new(inf.Dec), 0, true}, + {inf.NewDec(-1<<63, 0), -1 << 63, true}, + {inf.NewDec(-(-1<<63 + 1), 0), -(-1<<63 + 1), true}, + {new(inf.Dec).Neg(inf.NewDec(-1<<63, 0)), 0, false}, + {new(inf.Dec).Sub(inf.NewDec(-1<<63, 0), inf.NewDec(1, 0)), 0, false}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), 0, false}, +} + +func TestDecUnscaled(t *testing.T) { + for i, tt := range decUnscaledTests { + u, ok := tt.d.Unscaled() + if ok != tt.ok { + t.Errorf("#%d Unscaled: got %v, expected %v", i, ok, tt.ok) + } else if ok && u != tt.u { + t.Errorf("#%d Unscaled: got %v, expected %v", i, u, tt.u) + } + } +} + +var decRoundTests = [...]struct { + in *inf.Dec + s inf.Scale + r inf.Rounder + exp *inf.Dec +}{ + {inf.NewDec(123424999999999993, 15), 2, inf.RoundHalfUp, inf.NewDec(12342, 2)}, + {inf.NewDec(123425000000000001, 15), 2, inf.RoundHalfUp, inf.NewDec(12343, 2)}, + {inf.NewDec(123424999999999993, 15), 15, inf.RoundHalfUp, inf.NewDec(123424999999999993, 15)}, + {inf.NewDec(123424999999999993, 15), 16, inf.RoundHalfUp, inf.NewDec(1234249999999999930, 16)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -1, inf.RoundHalfUp, inf.NewDec(1844674407370955162, -1)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -2, inf.RoundHalfUp, inf.NewDec(184467440737095516, -2)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -3, inf.RoundHalfUp, inf.NewDec(18446744073709552, -3)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -4, inf.RoundHalfUp, inf.NewDec(1844674407370955, -4)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -5, inf.RoundHalfUp, inf.NewDec(184467440737096, -5)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -6, inf.RoundHalfUp, inf.NewDec(18446744073710, -6)}, +} + +func TestDecRound(t *testing.T) { + for i, tt := range decRoundTests { + z := new(inf.Dec).Round(tt.in, tt.s, tt.r) + if tt.exp.Cmp(z) != 0 { + t.Errorf("#%d Round got %v; expected %v", i, z, tt.exp) + } + } +} + +var decStringTests = []struct { + in string + out string + val int64 + scale inf.Scale // skip SetString if negative + ok bool + scanOk bool +}{ + {in: "", ok: false, scanOk: false}, + {in: "a", ok: false, scanOk: false}, + {in: "z", ok: false, scanOk: false}, + {in: "+", ok: false, scanOk: false}, + {in: "-", ok: false, scanOk: false}, + {in: "g", ok: false, scanOk: false}, + {in: ".", ok: false, scanOk: false}, + {in: ".-0", ok: false, scanOk: false}, + {in: ".+0", ok: false, scanOk: false}, + // Scannable but not SetStringable + {"0b", "ignored", 0, 0, false, true}, + {"0x", "ignored", 0, 0, false, true}, + {"0xg", "ignored", 0, 0, false, true}, + {"0.0g", "ignored", 0, 1, false, true}, + // examples from godoc for Dec + {"0", "0", 0, 0, true, true}, + {"0.00", "0.00", 0, 2, true, true}, + {"ignored", "0", 0, -2, true, false}, + {"1", "1", 1, 0, true, true}, + {"1.00", "1.00", 100, 2, true, true}, + {"10", "10", 10, 0, true, true}, + {"ignored", "10", 1, -1, true, false}, + // other tests + {"+0", "0", 0, 0, true, true}, + {"-0", "0", 0, 0, true, true}, + {"0.0", "0.0", 0, 1, true, true}, + {"0.1", "0.1", 1, 1, true, true}, + {"0.", "0", 0, 0, true, true}, + {"-10", "-10", -1, -1, true, true}, + {"-1", "-1", -1, 0, true, true}, + {"-0.1", "-0.1", -1, 1, true, true}, + {"-0.01", "-0.01", -1, 2, true, true}, + {"+0.", "0", 0, 0, true, true}, + {"-0.", "0", 0, 0, true, true}, + {".0", "0.0", 0, 1, true, true}, + {"+.0", "0.0", 0, 1, true, true}, + {"-.0", "0.0", 0, 1, true, true}, + {"0.0000000000", "0.0000000000", 0, 10, true, true}, + {"0.0000000001", "0.0000000001", 1, 10, true, true}, + {"-0.0000000000", "0.0000000000", 0, 10, true, true}, + {"-0.0000000001", "-0.0000000001", -1, 10, true, true}, + {"-10", "-10", -10, 0, true, true}, + {"+10", "10", 10, 0, true, true}, + {"00", "0", 0, 0, true, true}, + {"023", "23", 23, 0, true, true}, // decimal, not octal + {"-02.3", "-2.3", -23, 1, true, true}, // decimal, not octal +} + +func TestDecGetString(t *testing.T) { + z := new(inf.Dec) + for i, test := range decStringTests { + if !test.ok { + continue + } + z.SetUnscaled(test.val) + z.SetScale(test.scale) + + s := z.String() + if s != test.out { + t.Errorf("#%da got %s; want %s", i, s, test.out) + } + + s = fmt.Sprintf("%d", z) + if s != test.out { + t.Errorf("#%db got %s; want %s", i, s, test.out) + } + } +} + +func TestDecSetString(t *testing.T) { + tmp := new(inf.Dec) + for i, test := range decStringTests { + if test.scale < 0 { + // SetString only supports scale >= 0 + continue + } + // initialize to a non-zero value so that issues with parsing + // 0 are detected + tmp.Set(inf.NewDec(1234567890, 123)) + n1, ok1 := new(inf.Dec).SetString(test.in) + n2, ok2 := tmp.SetString(test.in) + expected := inf.NewDec(test.val, test.scale) + if ok1 != test.ok || ok2 != test.ok { + t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) + continue + } + if !ok1 { + if n1 != nil { + t.Errorf("#%d (input '%s') n1 != nil", i, test.in) + } + continue + } + if !ok2 { + if n2 != nil { + t.Errorf("#%d (input '%s') n2 != nil", i, test.in) + } + continue + } + + if n1.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) + } + if n2.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) + } + } +} + +func TestDecScan(t *testing.T) { + tmp := new(inf.Dec) + for i, test := range decStringTests { + if test.scale < 0 { + // SetString only supports scale >= 0 + continue + } + // initialize to a non-zero value so that issues with parsing + // 0 are detected + tmp.Set(inf.NewDec(1234567890, 123)) + n1, n2 := new(inf.Dec), tmp + nn1, err1 := fmt.Sscan(test.in, n1) + nn2, err2 := fmt.Sscan(test.in, n2) + if !test.scanOk { + if err1 == nil || err2 == nil { + t.Errorf("#%d (input '%s') ok incorrect, should be %t", i, test.in, test.scanOk) + } + continue + } + expected := inf.NewDec(test.val, test.scale) + if nn1 != 1 || err1 != nil || nn2 != 1 || err2 != nil { + t.Errorf("#%d (input '%s') error %d %v, %d %v", i, test.in, nn1, err1, nn2, err2) + continue + } + if n1.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) + } + if n2.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) + } + } +} + +var decScanNextTests = []struct { + in string + ok bool + next rune +}{ + {"", false, 0}, + {"a", false, 'a'}, + {"z", false, 'z'}, + {"+", false, 0}, + {"-", false, 0}, + {"g", false, 'g'}, + {".", false, 0}, + {".-0", false, '-'}, + {".+0", false, '+'}, + {"0b", true, 'b'}, + {"0x", true, 'x'}, + {"0xg", true, 'x'}, + {"0.0g", true, 'g'}, +} + +func TestDecScanNext(t *testing.T) { + for i, test := range decScanNextTests { + rdr := strings.NewReader(test.in) + n1 := new(inf.Dec) + nn1, _ := fmt.Fscan(rdr, n1) + if (test.ok && nn1 == 0) || (!test.ok && nn1 > 0) { + t.Errorf("#%d (input '%s') ok incorrect should be %t", i, test.in, test.ok) + continue + } + r := rune(0) + nn2, err := fmt.Fscanf(rdr, "%c", &r) + if test.next != r { + t.Errorf("#%d (input '%s') next incorrect, got %c should be %c, %d, %v", i, test.in, r, test.next, nn2, err) + } + } +} + +var decGobEncodingTests = []string{ + "0", + "1", + "2", + "10", + "42", + "1234567890", + "298472983472983471903246121093472394872319615612417471234712061", +} + +func TestDecGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for i, test := range decGobEncodingTests { + for j := 0; j < 2; j++ { + for k := inf.Scale(-5); k <= 5; k++ { + medium.Reset() // empty buffer for each test case (in case of failures) + stest := test + if j != 0 { + // negative numbers + stest = "-" + test + } + var tx inf.Dec + tx.SetString(stest) + tx.SetScale(k) // test with positive, negative, and zero scale + if err := enc.Encode(&tx); err != nil { + t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err) + } + var rx inf.Dec + if err := dec.Decode(&rx); err != nil { + t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err) + } + if rx.Cmp(&tx) != 0 { + t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx) + } + } + } + } +} diff --git a/vendor/gopkg.in/inf.v0/example_test.go b/vendor/gopkg.in/inf.v0/example_test.go new file mode 100644 index 000000000..fa1e54d16 --- /dev/null +++ b/vendor/gopkg.in/inf.v0/example_test.go @@ -0,0 +1,62 @@ +package inf_test + +import ( + "fmt" + "log" +) + +import "gopkg.in/inf.v0" + +func ExampleDec_SetString() { + d := new(inf.Dec) + d.SetString("012345.67890") // decimal; leading 0 ignored; trailing 0 kept + fmt.Println(d) + // Output: 12345.67890 +} + +func ExampleDec_Scan() { + // The Scan function is rarely used directly; + // the fmt package recognizes it as an implementation of fmt.Scanner. + d := new(inf.Dec) + _, err := fmt.Sscan("184467440.73709551617", d) + if err != nil { + log.Println("error scanning value:", err) + } else { + fmt.Println(d) + } + // Output: 184467440.73709551617 +} + +func ExampleDec_QuoRound_scale2RoundDown() { + // 10 / 3 is an infinite decimal; it has no exact Dec representation + x, y := inf.NewDec(10, 0), inf.NewDec(3, 0) + // use 2 digits beyond the decimal point, round towards 0 + z := new(inf.Dec).QuoRound(x, y, 2, inf.RoundDown) + fmt.Println(z) + // Output: 3.33 +} + +func ExampleDec_QuoRound_scale2RoundCeil() { + // -42 / 400 is an finite decimal with 3 digits beyond the decimal point + x, y := inf.NewDec(-42, 0), inf.NewDec(400, 0) + // use 2 digits beyond decimal point, round towards positive infinity + z := new(inf.Dec).QuoRound(x, y, 2, inf.RoundCeil) + fmt.Println(z) + // Output: -0.10 +} + +func ExampleDec_QuoExact_ok() { + // 1 / 25 is a finite decimal; it has exact Dec representation + x, y := inf.NewDec(1, 0), inf.NewDec(25, 0) + z := new(inf.Dec).QuoExact(x, y) + fmt.Println(z) + // Output: 0.04 +} + +func ExampleDec_QuoExact_fail() { + // 1 / 3 is an infinite decimal; it has no exact Dec representation + x, y := inf.NewDec(1, 0), inf.NewDec(3, 0) + z := new(inf.Dec).QuoExact(x, y) + fmt.Println(z) + // Output: <nil> +} diff --git a/vendor/gopkg.in/inf.v0/rounder_example_test.go b/vendor/gopkg.in/inf.v0/rounder_example_test.go new file mode 100644 index 000000000..4bf36af95 --- /dev/null +++ b/vendor/gopkg.in/inf.v0/rounder_example_test.go @@ -0,0 +1,73 @@ +package inf_test + +import ( + "fmt" + "os" + "text/tabwriter" + + "gopkg.in/inf.v0" +) + +// This example displays the results of Dec.Round with each of the Rounders. +// +func ExampleRounder() { + var vals = []struct { + x string + s inf.Scale + }{ + {"-0.18", 1}, {"-0.15", 1}, {"-0.12", 1}, {"-0.10", 1}, + {"-0.08", 1}, {"-0.05", 1}, {"-0.02", 1}, {"0.00", 1}, + {"0.02", 1}, {"0.05", 1}, {"0.08", 1}, {"0.10", 1}, + {"0.12", 1}, {"0.15", 1}, {"0.18", 1}, + } + + var rounders = []struct { + name string + rounder inf.Rounder + }{ + {"RoundDown", inf.RoundDown}, {"RoundUp", inf.RoundUp}, + {"RoundCeil", inf.RoundCeil}, {"RoundFloor", inf.RoundFloor}, + {"RoundHalfDown", inf.RoundHalfDown}, {"RoundHalfUp", inf.RoundHalfUp}, + {"RoundHalfEven", inf.RoundHalfEven}, {"RoundExact", inf.RoundExact}, + } + + fmt.Println("The results of new(inf.Dec).Round(x, s, inf.RoundXXX):") + fmt.Println() + w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight) + fmt.Fprint(w, "x\ts\t|\t") + for _, r := range rounders { + fmt.Fprintf(w, "%s\t", r.name[5:]) + } + fmt.Fprintln(w) + for _, v := range vals { + fmt.Fprintf(w, "%s\t%d\t|\t", v.x, v.s) + for _, r := range rounders { + x, _ := new(inf.Dec).SetString(v.x) + z := new(inf.Dec).Round(x, v.s, r.rounder) + fmt.Fprintf(w, "%d\t", z) + } + fmt.Fprintln(w) + } + w.Flush() + + // Output: + // The results of new(inf.Dec).Round(x, s, inf.RoundXXX): + // + // x s | Down Up Ceil Floor HalfDown HalfUp HalfEven Exact + // -0.18 1 | -0.1 -0.2 -0.1 -0.2 -0.2 -0.2 -0.2 <nil> + // -0.15 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.2 -0.2 <nil> + // -0.12 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.1 -0.1 <nil> + // -0.10 1 | -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 + // -0.08 1 | 0.0 -0.1 0.0 -0.1 -0.1 -0.1 -0.1 <nil> + // -0.05 1 | 0.0 -0.1 0.0 -0.1 0.0 -0.1 0.0 <nil> + // -0.02 1 | 0.0 -0.1 0.0 -0.1 0.0 0.0 0.0 <nil> + // 0.00 1 | 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + // 0.02 1 | 0.0 0.1 0.1 0.0 0.0 0.0 0.0 <nil> + // 0.05 1 | 0.0 0.1 0.1 0.0 0.0 0.1 0.0 <nil> + // 0.08 1 | 0.0 0.1 0.1 0.0 0.1 0.1 0.1 <nil> + // 0.10 1 | 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 + // 0.12 1 | 0.1 0.2 0.2 0.1 0.1 0.1 0.1 <nil> + // 0.15 1 | 0.1 0.2 0.2 0.1 0.1 0.2 0.2 <nil> + // 0.18 1 | 0.1 0.2 0.2 0.1 0.2 0.2 0.2 <nil> + +} diff --git a/vendor/gopkg.in/inf.v0/rounder_test.go b/vendor/gopkg.in/inf.v0/rounder_test.go new file mode 100644 index 000000000..d7e14c58c --- /dev/null +++ b/vendor/gopkg.in/inf.v0/rounder_test.go @@ -0,0 +1,109 @@ +package inf_test + +import ( + "math/big" + "testing" + + "gopkg.in/inf.v0" +) + +var decRounderInputs = [...]struct { + quo *inf.Dec + rA, rB *big.Int +}{ + // examples from go language spec + {inf.NewDec(1, 0), big.NewInt(2), big.NewInt(3)}, // 5 / 3 + {inf.NewDec(-1, 0), big.NewInt(-2), big.NewInt(3)}, // -5 / 3 + {inf.NewDec(-1, 0), big.NewInt(2), big.NewInt(-3)}, // 5 / -3 + {inf.NewDec(1, 0), big.NewInt(-2), big.NewInt(-3)}, // -5 / -3 + // examples from godoc + {inf.NewDec(-1, 1), big.NewInt(-8), big.NewInt(10)}, + {inf.NewDec(-1, 1), big.NewInt(-5), big.NewInt(10)}, + {inf.NewDec(-1, 1), big.NewInt(-2), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(-8), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(-5), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(-2), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(0), big.NewInt(1)}, + {inf.NewDec(0, 1), big.NewInt(2), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(5), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(8), big.NewInt(10)}, + {inf.NewDec(1, 1), big.NewInt(2), big.NewInt(10)}, + {inf.NewDec(1, 1), big.NewInt(5), big.NewInt(10)}, + {inf.NewDec(1, 1), big.NewInt(8), big.NewInt(10)}, +} + +var decRounderResults = [...]struct { + rounder inf.Rounder + results [len(decRounderInputs)]*inf.Dec +}{ + {inf.RoundExact, [...]*inf.Dec{nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, + inf.NewDec(0, 1), nil, nil, nil, nil, nil, nil}}, + {inf.RoundDown, [...]*inf.Dec{ + inf.NewDec(1, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(1, 0), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}}, + {inf.RoundUp, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1), + inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, + {inf.RoundHalfDown, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(2, 1)}}, + {inf.RoundHalfUp, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(1, 1), inf.NewDec(1, 1), + inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, + {inf.RoundHalfEven, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1), + inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1), + inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, + {inf.RoundFloor, [...]*inf.Dec{ + inf.NewDec(1, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(1, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}}, + {inf.RoundCeil, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(2, 0), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1), + inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, +} + +func TestDecRounders(t *testing.T) { + for i, a := range decRounderResults { + for j, input := range decRounderInputs { + q := new(inf.Dec).Set(input.quo) + rA, rB := new(big.Int).Set(input.rA), new(big.Int).Set(input.rB) + res := a.rounder.Round(new(inf.Dec), q, rA, rB) + if a.results[j] == nil && res == nil { + continue + } + if (a.results[j] == nil && res != nil) || + (a.results[j] != nil && res == nil) || + a.results[j].Cmp(res) != 0 { + t.Errorf("#%d,%d Rounder got %v; expected %v", i, j, res, a.results[j]) + } + } + } +} diff --git a/vendor/gopkg.in/yaml.v2/.travis.yml b/vendor/gopkg.in/yaml.v2/.travis.yml new file mode 100644 index 000000000..9f556934d --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/.travis.yml @@ -0,0 +1,12 @@ +language: go + +go: + - 1.4 + - 1.5 + - 1.6 + - 1.7 + - 1.8 + - 1.9 + - tip + +go_import_path: gopkg.in/yaml.v2 diff --git a/vendor/gopkg.in/yaml.v2/README.md b/vendor/gopkg.in/yaml.v2/README.md new file mode 100644 index 000000000..b50c6e877 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/README.md @@ -0,0 +1,133 @@ +# YAML support for the Go language + +Introduction +------------ + +The yaml package enables Go programs to comfortably encode and decode YAML +values. It was developed within [Canonical](https://www.canonical.com) as +part of the [juju](https://juju.ubuntu.com) project, and is based on a +pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) +C library to parse and generate YAML data quickly and reliably. + +Compatibility +------------- + +The yaml package supports most of YAML 1.1 and 1.2, including support for +anchors, tags, map merging, etc. Multi-document unmarshalling is not yet +implemented, and base-60 floats from YAML 1.1 are purposefully not +supported since they're a poor design and are gone in YAML 1.2. + +Installation and usage +---------------------- + +The import path for the package is *gopkg.in/yaml.v2*. + +To install it, run: + + go get gopkg.in/yaml.v2 + +API documentation +----------------- + +If opened in a browser, the import path itself leads to the API documentation: + + * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) + +API stability +------------- + +The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). + + +License +------- + +The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. + + +Example +------- + +```Go +package main + +import ( + "fmt" + "log" + + "gopkg.in/yaml.v2" +) + +var data = ` +a: Easy! +b: + c: 2 + d: [3, 4] +` + +// Note: struct fields must be public in order for unmarshal to +// correctly populate the data. +type T struct { + A string + B struct { + RenamedC int `yaml:"c"` + D []int `yaml:",flow"` + } +} + +func main() { + t := T{} + + err := yaml.Unmarshal([]byte(data), &t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t:\n%v\n\n", t) + + d, err := yaml.Marshal(&t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t dump:\n%s\n\n", string(d)) + + m := make(map[interface{}]interface{}) + + err = yaml.Unmarshal([]byte(data), &m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m:\n%v\n\n", m) + + d, err = yaml.Marshal(&m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m dump:\n%s\n\n", string(d)) +} +``` + +This example will generate the following output: + +``` +--- t: +{Easy! {2 [3 4]}} + +--- t dump: +a: Easy! +b: + c: 2 + d: [3, 4] + + +--- m: +map[a:Easy! b:map[c:2 d:[3 4]]] + +--- m dump: +a: Easy! +b: + c: 2 + d: + - 3 + - 4 +``` + diff --git a/vendor/gopkg.in/yaml.v2/decode_test.go b/vendor/gopkg.in/yaml.v2/decode_test.go new file mode 100644 index 000000000..9269f12b8 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/decode_test.go @@ -0,0 +1,1326 @@ +package yaml_test + +import ( + "errors" + "io" + "math" + "reflect" + "strings" + "time" + + . "gopkg.in/check.v1" + "gopkg.in/yaml.v2" +) + +var unmarshalIntTest = 123 + +var unmarshalTests = []struct { + data string + value interface{} +}{ + { + "", + (*struct{})(nil), + }, + { + "{}", &struct{}{}, + }, { + "v: hi", + map[string]string{"v": "hi"}, + }, { + "v: hi", map[string]interface{}{"v": "hi"}, + }, { + "v: true", + map[string]string{"v": "true"}, + }, { + "v: true", + map[string]interface{}{"v": true}, + }, { + "v: 10", + map[string]interface{}{"v": 10}, + }, { + "v: 0b10", + map[string]interface{}{"v": 2}, + }, { + "v: 0xA", + map[string]interface{}{"v": 10}, + }, { + "v: 4294967296", + map[string]int64{"v": 4294967296}, + }, { + "v: 0.1", + map[string]interface{}{"v": 0.1}, + }, { + "v: .1", + map[string]interface{}{"v": 0.1}, + }, { + "v: .Inf", + map[string]interface{}{"v": math.Inf(+1)}, + }, { + "v: -.Inf", + map[string]interface{}{"v": math.Inf(-1)}, + }, { + "v: -10", + map[string]interface{}{"v": -10}, + }, { + "v: -.1", + map[string]interface{}{"v": -0.1}, + }, + + // Simple values. + { + "123", + &unmarshalIntTest, + }, + + // Floats from spec + { + "canonical: 6.8523e+5", + map[string]interface{}{"canonical": 6.8523e+5}, + }, { + "expo: 685.230_15e+03", + map[string]interface{}{"expo": 685.23015e+03}, + }, { + "fixed: 685_230.15", + map[string]interface{}{"fixed": 685230.15}, + }, { + "neginf: -.inf", + map[string]interface{}{"neginf": math.Inf(-1)}, + }, { + "fixed: 685_230.15", + map[string]float64{"fixed": 685230.15}, + }, + //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported + //{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails. + + // Bools from spec + { + "canonical: y", + map[string]interface{}{"canonical": true}, + }, { + "answer: NO", + map[string]interface{}{"answer": false}, + }, { + "logical: True", + map[string]interface{}{"logical": true}, + }, { + "option: on", + map[string]interface{}{"option": true}, + }, { + "option: on", + map[string]bool{"option": true}, + }, + // Ints from spec + { + "canonical: 685230", + map[string]interface{}{"canonical": 685230}, + }, { + "decimal: +685_230", + map[string]interface{}{"decimal": 685230}, + }, { + "octal: 02472256", + map[string]interface{}{"octal": 685230}, + }, { + "hexa: 0x_0A_74_AE", + map[string]interface{}{"hexa": 685230}, + }, { + "bin: 0b1010_0111_0100_1010_1110", + map[string]interface{}{"bin": 685230}, + }, { + "bin: -0b101010", + map[string]interface{}{"bin": -42}, + }, { + "bin: -0b1000000000000000000000000000000000000000000000000000000000000000", + map[string]interface{}{"bin": -9223372036854775808}, + }, { + "decimal: +685_230", + map[string]int{"decimal": 685230}, + }, + + //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported + + // Nulls from spec + { + "empty:", + map[string]interface{}{"empty": nil}, + }, { + "canonical: ~", + map[string]interface{}{"canonical": nil}, + }, { + "english: null", + map[string]interface{}{"english": nil}, + }, { + "~: null key", + map[interface{}]string{nil: "null key"}, + }, { + "empty:", + map[string]*bool{"empty": nil}, + }, + + // Flow sequence + { + "seq: [A,B]", + map[string]interface{}{"seq": []interface{}{"A", "B"}}, + }, { + "seq: [A,B,C,]", + map[string][]string{"seq": []string{"A", "B", "C"}}, + }, { + "seq: [A,1,C]", + map[string][]string{"seq": []string{"A", "1", "C"}}, + }, { + "seq: [A,1,C]", + map[string][]int{"seq": []int{1}}, + }, { + "seq: [A,1,C]", + map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}, + }, + // Block sequence + { + "seq:\n - A\n - B", + map[string]interface{}{"seq": []interface{}{"A", "B"}}, + }, { + "seq:\n - A\n - B\n - C", + map[string][]string{"seq": []string{"A", "B", "C"}}, + }, { + "seq:\n - A\n - 1\n - C", + map[string][]string{"seq": []string{"A", "1", "C"}}, + }, { + "seq:\n - A\n - 1\n - C", + map[string][]int{"seq": []int{1}}, + }, { + "seq:\n - A\n - 1\n - C", + map[string]interface{}{"seq": []interface{}{"A", 1, "C"}}, + }, + + // Literal block scalar + { + "scalar: | # Comment\n\n literal\n\n \ttext\n\n", + map[string]string{"scalar": "\nliteral\n\n\ttext\n"}, + }, + + // Folded block scalar + { + "scalar: > # Comment\n\n folded\n line\n \n next\n line\n * one\n * two\n\n last\n line\n\n", + map[string]string{"scalar": "\nfolded line\nnext line\n * one\n * two\n\nlast line\n"}, + }, + + // Map inside interface with no type hints. + { + "a: {b: c}", + map[interface{}]interface{}{"a": map[interface{}]interface{}{"b": "c"}}, + }, + + // Structs and type conversions. + { + "hello: world", + &struct{ Hello string }{"world"}, + }, { + "a: {b: c}", + &struct{ A struct{ B string } }{struct{ B string }{"c"}}, + }, { + "a: {b: c}", + &struct{ A *struct{ B string } }{&struct{ B string }{"c"}}, + }, { + "a: {b: c}", + &struct{ A map[string]string }{map[string]string{"b": "c"}}, + }, { + "a: {b: c}", + &struct{ A *map[string]string }{&map[string]string{"b": "c"}}, + }, { + "a:", + &struct{ A map[string]string }{}, + }, { + "a: 1", + &struct{ A int }{1}, + }, { + "a: 1", + &struct{ A float64 }{1}, + }, { + "a: 1.0", + &struct{ A int }{1}, + }, { + "a: 1.0", + &struct{ A uint }{1}, + }, { + "a: [1, 2]", + &struct{ A []int }{[]int{1, 2}}, + }, { + "a: [1, 2]", + &struct{ A [2]int }{[2]int{1, 2}}, + }, { + "a: 1", + &struct{ B int }{0}, + }, { + "a: 1", + &struct { + B int "a" + }{1}, + }, { + "a: y", + &struct{ A bool }{true}, + }, + + // Some cross type conversions + { + "v: 42", + map[string]uint{"v": 42}, + }, { + "v: -42", + map[string]uint{}, + }, { + "v: 4294967296", + map[string]uint64{"v": 4294967296}, + }, { + "v: -4294967296", + map[string]uint64{}, + }, + + // int + { + "int_max: 2147483647", + map[string]int{"int_max": math.MaxInt32}, + }, + { + "int_min: -2147483648", + map[string]int{"int_min": math.MinInt32}, + }, + { + "int_overflow: 9223372036854775808", // math.MaxInt64 + 1 + map[string]int{}, + }, + + // int64 + { + "int64_max: 9223372036854775807", + map[string]int64{"int64_max": math.MaxInt64}, + }, + { + "int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111", + map[string]int64{"int64_max_base2": math.MaxInt64}, + }, + { + "int64_min: -9223372036854775808", + map[string]int64{"int64_min": math.MinInt64}, + }, + { + "int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111", + map[string]int64{"int64_neg_base2": -math.MaxInt64}, + }, + { + "int64_overflow: 9223372036854775808", // math.MaxInt64 + 1 + map[string]int64{}, + }, + + // uint + { + "uint_min: 0", + map[string]uint{"uint_min": 0}, + }, + { + "uint_max: 4294967295", + map[string]uint{"uint_max": math.MaxUint32}, + }, + { + "uint_underflow: -1", + map[string]uint{}, + }, + + // uint64 + { + "uint64_min: 0", + map[string]uint{"uint64_min": 0}, + }, + { + "uint64_max: 18446744073709551615", + map[string]uint64{"uint64_max": math.MaxUint64}, + }, + { + "uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111", + map[string]uint64{"uint64_max_base2": math.MaxUint64}, + }, + { + "uint64_maxint64: 9223372036854775807", + map[string]uint64{"uint64_maxint64": math.MaxInt64}, + }, + { + "uint64_underflow: -1", + map[string]uint64{}, + }, + + // float32 + { + "float32_max: 3.40282346638528859811704183484516925440e+38", + map[string]float32{"float32_max": math.MaxFloat32}, + }, + { + "float32_nonzero: 1.401298464324817070923729583289916131280e-45", + map[string]float32{"float32_nonzero": math.SmallestNonzeroFloat32}, + }, + { + "float32_maxuint64: 18446744073709551615", + map[string]float32{"float32_maxuint64": float32(math.MaxUint64)}, + }, + { + "float32_maxuint64+1: 18446744073709551616", + map[string]float32{"float32_maxuint64+1": float32(math.MaxUint64 + 1)}, + }, + + // float64 + { + "float64_max: 1.797693134862315708145274237317043567981e+308", + map[string]float64{"float64_max": math.MaxFloat64}, + }, + { + "float64_nonzero: 4.940656458412465441765687928682213723651e-324", + map[string]float64{"float64_nonzero": math.SmallestNonzeroFloat64}, + }, + { + "float64_maxuint64: 18446744073709551615", + map[string]float64{"float64_maxuint64": float64(math.MaxUint64)}, + }, + { + "float64_maxuint64+1: 18446744073709551616", + map[string]float64{"float64_maxuint64+1": float64(math.MaxUint64 + 1)}, + }, + + // Overflow cases. + { + "v: 4294967297", + map[string]int32{}, + }, { + "v: 128", + map[string]int8{}, + }, + + // Quoted values. + { + "'1': '\"2\"'", + map[interface{}]interface{}{"1": "\"2\""}, + }, { + "v:\n- A\n- 'B\n\n C'\n", + map[string][]string{"v": []string{"A", "B\nC"}}, + }, + + // Explicit tags. + { + "v: !!float '1.1'", + map[string]interface{}{"v": 1.1}, + }, { + "v: !!float 0", + map[string]interface{}{"v": float64(0)}, + }, { + "v: !!float -1", + map[string]interface{}{"v": float64(-1)}, + }, { + "v: !!null ''", + map[string]interface{}{"v": nil}, + }, { + "%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'", + map[string]interface{}{"v": 1}, + }, + + // Non-specific tag (Issue #75) + { + "v: ! test", + map[string]interface{}{"v": "test"}, + }, + + // Anchors and aliases. + { + "a: &x 1\nb: &y 2\nc: *x\nd: *y\n", + &struct{ A, B, C, D int }{1, 2, 1, 2}, + }, { + "a: &a {c: 1}\nb: *a", + &struct { + A, B struct { + C int + } + }{struct{ C int }{1}, struct{ C int }{1}}, + }, { + "a: &a [1, 2]\nb: *a", + &struct{ B []int }{[]int{1, 2}}, + }, + + // Bug #1133337 + { + "foo: ''", + map[string]*string{"foo": new(string)}, + }, { + "foo: null", + map[string]*string{"foo": nil}, + }, { + "foo: null", + map[string]string{"foo": ""}, + }, { + "foo: null", + map[string]interface{}{"foo": nil}, + }, + + // Support for ~ + { + "foo: ~", + map[string]*string{"foo": nil}, + }, { + "foo: ~", + map[string]string{"foo": ""}, + }, { + "foo: ~", + map[string]interface{}{"foo": nil}, + }, + + // Ignored field + { + "a: 1\nb: 2\n", + &struct { + A int + B int "-" + }{1, 0}, + }, + + // Bug #1191981 + { + "" + + "%YAML 1.1\n" + + "--- !!str\n" + + `"Generic line break (no glyph)\n\` + "\n" + + ` Generic line break (glyphed)\n\` + "\n" + + ` Line separator\u2028\` + "\n" + + ` Paragraph separator\u2029"` + "\n", + "" + + "Generic line break (no glyph)\n" + + "Generic line break (glyphed)\n" + + "Line separator\u2028Paragraph separator\u2029", + }, + + // Struct inlining + { + "a: 1\nb: 2\nc: 3\n", + &struct { + A int + C inlineB `yaml:",inline"` + }{1, inlineB{2, inlineC{3}}}, + }, + + // Map inlining + { + "a: 1\nb: 2\nc: 3\n", + &struct { + A int + C map[string]int `yaml:",inline"` + }{1, map[string]int{"b": 2, "c": 3}}, + }, + + // bug 1243827 + { + "a: -b_c", + map[string]interface{}{"a": "-b_c"}, + }, + { + "a: +b_c", + map[string]interface{}{"a": "+b_c"}, + }, + { + "a: 50cent_of_dollar", + map[string]interface{}{"a": "50cent_of_dollar"}, + }, + + // issue #295 (allow scalars with colons in flow mappings and sequences) + { + "a: {b: https://github.com/go-yaml/yaml}", + map[string]interface{}{"a": map[interface{}]interface{}{ + "b": "https://github.com/go-yaml/yaml", + }}, + }, + { + "a: [https://github.com/go-yaml/yaml]", + map[string]interface{}{"a": []interface{}{"https://github.com/go-yaml/yaml"}}, + }, + + // Duration + { + "a: 3s", + map[string]time.Duration{"a": 3 * time.Second}, + }, + + // Issue #24. + { + "a: <foo>", + map[string]string{"a": "<foo>"}, + }, + + // Base 60 floats are obsolete and unsupported. + { + "a: 1:1\n", + map[string]string{"a": "1:1"}, + }, + + // Binary data. + { + "a: !!binary gIGC\n", + map[string]string{"a": "\x80\x81\x82"}, + }, { + "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n", + map[string]string{"a": strings.Repeat("\x90", 54)}, + }, { + "a: !!binary |\n " + strings.Repeat("A", 70) + "\n ==\n", + map[string]string{"a": strings.Repeat("\x00", 52)}, + }, + + // Ordered maps. + { + "{b: 2, a: 1, d: 4, c: 3, sub: {e: 5}}", + &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}}, + }, + + // Issue #39. + { + "a:\n b:\n c: d\n", + map[string]struct{ B interface{} }{"a": {map[interface{}]interface{}{"c": "d"}}}, + }, + + // Custom map type. + { + "a: {b: c}", + M{"a": M{"b": "c"}}, + }, + + // Support encoding.TextUnmarshaler. + { + "a: 1.2.3.4\n", + map[string]textUnmarshaler{"a": textUnmarshaler{S: "1.2.3.4"}}, + }, + { + "a: 2015-02-24T18:19:39Z\n", + map[string]textUnmarshaler{"a": textUnmarshaler{"2015-02-24T18:19:39Z"}}, + }, + + // Timestamps + { + // Date only. + "a: 2015-01-01\n", + map[string]time.Time{"a": time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + { + // RFC3339 + "a: 2015-02-24T18:19:39.12Z\n", + map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, .12e9, time.UTC)}, + }, + { + // RFC3339 with short dates. + "a: 2015-2-3T3:4:5Z", + map[string]time.Time{"a": time.Date(2015, 2, 3, 3, 4, 5, 0, time.UTC)}, + }, + { + // ISO8601 lower case t + "a: 2015-02-24t18:19:39Z\n", + map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, 0, time.UTC)}, + }, + { + // space separate, no time zone + "a: 2015-02-24 18:19:39\n", + map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, 0, time.UTC)}, + }, + // Some cases not currently handled. Uncomment these when + // the code is fixed. + // { + // // space separated with time zone + // "a: 2001-12-14 21:59:43.10 -5", + // map[string]interface{}{"a": time.Date(2001, 12, 14, 21, 59, 43, .1e9, time.UTC)}, + // }, + // { + // // arbitrary whitespace between fields + // "a: 2001-12-14 \t\t \t21:59:43.10 \t Z", + // map[string]interface{}{"a": time.Date(2001, 12, 14, 21, 59, 43, .1e9, time.UTC)}, + // }, + { + // explicit string tag + "a: !!str 2015-01-01", + map[string]interface{}{"a": "2015-01-01"}, + }, + { + // explicit timestamp tag on quoted string + "a: !!timestamp \"2015-01-01\"", + map[string]time.Time{"a": time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + { + // explicit timestamp tag on unquoted string + "a: !!timestamp 2015-01-01", + map[string]time.Time{"a": time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, + { + // quoted string that's a valid timestamp + "a: \"2015-01-01\"", + map[string]interface{}{"a": "2015-01-01"}, + }, + { + // explicit timestamp tag into interface. + "a: !!timestamp \"2015-01-01\"", + map[string]interface{}{"a": "2015-01-01"}, + }, + { + // implicit timestamp tag into interface. + "a: 2015-01-01", + map[string]interface{}{"a": "2015-01-01"}, + }, + + // Encode empty lists as zero-length slices. + { + "a: []", + &struct{ A []int }{[]int{}}, + }, + + // UTF-16-LE + { + "\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n\x00", + M{"ñoño": "very yes"}, + }, + // UTF-16-LE with surrogate. + { + "\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \x00=\xd8\xd4\xdf\n\x00", + M{"ñoño": "very yes 🟔"}, + }, + + // UTF-16-BE + { + "\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n", + M{"ñoño": "very yes"}, + }, + // UTF-16-BE with surrogate. + { + "\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \xd8=\xdf\xd4\x00\n", + M{"ñoño": "very yes 🟔"}, + }, + + // YAML Float regex shouldn't match this + { + "a: 123456e1\n", + M{"a": "123456e1"}, + }, { + "a: 123456E1\n", + M{"a": "123456E1"}, + }, + // yaml-test-suite 3GZX: Spec Example 7.1. Alias Nodes + { + "First occurrence: &anchor Foo\nSecond occurrence: *anchor\nOverride anchor: &anchor Bar\nReuse anchor: *anchor\n", + map[interface{}]interface{}{ + "Reuse anchor": "Bar", + "First occurrence": "Foo", + "Second occurrence": "Foo", + "Override anchor": "Bar", + }, + }, + // Single document with garbage following it. + { + "---\nhello\n...\n}not yaml", + "hello", + }, +} + +type M map[interface{}]interface{} + +type inlineB struct { + B int + inlineC `yaml:",inline"` +} + +type inlineC struct { + C int +} + +func (s *S) TestUnmarshal(c *C) { + for i, item := range unmarshalTests { + c.Logf("test %d: %q", i, item.data) + t := reflect.ValueOf(item.value).Type() + value := reflect.New(t) + err := yaml.Unmarshal([]byte(item.data), value.Interface()) + if _, ok := err.(*yaml.TypeError); !ok { + c.Assert(err, IsNil) + } + c.Assert(value.Elem().Interface(), DeepEquals, item.value, Commentf("error: %v", err)) + } +} + +// TODO(v3): This test should also work when unmarshaling onto an interface{}. +func (s *S) TestUnmarshalFullTimestamp(c *C) { + // Full timestamp in same format as encoded. This is confirmed to be + // properly decoded by Python as a timestamp as well. + var str = "2015-02-24T18:19:39.123456789-03:00" + var t time.Time + err := yaml.Unmarshal([]byte(str), &t) + c.Assert(err, IsNil) + c.Assert(t, Equals, time.Date(2015, 2, 24, 18, 19, 39, 123456789, t.Location())) + c.Assert(t.In(time.UTC), Equals, time.Date(2015, 2, 24, 21, 19, 39, 123456789, time.UTC)) +} + +func (s *S) TestDecoderSingleDocument(c *C) { + // Test that Decoder.Decode works as expected on + // all the unmarshal tests. + for i, item := range unmarshalTests { + c.Logf("test %d: %q", i, item.data) + if item.data == "" { + // Behaviour differs when there's no YAML. + continue + } + t := reflect.ValueOf(item.value).Type() + value := reflect.New(t) + err := yaml.NewDecoder(strings.NewReader(item.data)).Decode(value.Interface()) + if _, ok := err.(*yaml.TypeError); !ok { + c.Assert(err, IsNil) + } + c.Assert(value.Elem().Interface(), DeepEquals, item.value) + } +} + +var decoderTests = []struct { + data string + values []interface{} +}{{ + "", + nil, +}, { + "a: b", + []interface{}{ + map[interface{}]interface{}{"a": "b"}, + }, +}, { + "---\na: b\n...\n", + []interface{}{ + map[interface{}]interface{}{"a": "b"}, + }, +}, { + "---\n'hello'\n...\n---\ngoodbye\n...\n", + []interface{}{ + "hello", + "goodbye", + }, +}} + +func (s *S) TestDecoder(c *C) { + for i, item := range decoderTests { + c.Logf("test %d: %q", i, item.data) + var values []interface{} + dec := yaml.NewDecoder(strings.NewReader(item.data)) + for { + var value interface{} + err := dec.Decode(&value) + if err == io.EOF { + break + } + c.Assert(err, IsNil) + values = append(values, value) + } + c.Assert(values, DeepEquals, item.values) + } +} + +type errReader struct{} + +func (errReader) Read([]byte) (int, error) { + return 0, errors.New("some read error") +} + +func (s *S) TestDecoderReadError(c *C) { + err := yaml.NewDecoder(errReader{}).Decode(&struct{}{}) + c.Assert(err, ErrorMatches, `yaml: input error: some read error`) +} + +func (s *S) TestUnmarshalNaN(c *C) { + value := map[string]interface{}{} + err := yaml.Unmarshal([]byte("notanum: .NaN"), &value) + c.Assert(err, IsNil) + c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true) +} + +var unmarshalErrorTests = []struct { + data, error string +}{ + {"v: !!float 'error'", "yaml: cannot decode !!str `error` as a !!float"}, + {"v: [A,", "yaml: line 1: did not find expected node content"}, + {"v:\n- [A,", "yaml: line 2: did not find expected node content"}, + {"a:\n- b: *,", "yaml: line 2: did not find expected alphabetic or numeric character"}, + {"a: *b\n", "yaml: unknown anchor 'b' referenced"}, + {"a: &a\n b: *a\n", "yaml: anchor 'a' value contains itself"}, + {"value: -", "yaml: block sequence entries are not allowed in this context"}, + {"a: !!binary ==", "yaml: !!binary value contains invalid base64 data"}, + {"{[.]}", `yaml: invalid map key: \[\]interface \{\}\{"\."\}`}, + {"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`}, + {"b: *a\na: &a {c: 1}", `yaml: unknown anchor 'a' referenced`}, + {"%TAG !%79! tag:yaml.org,2002:\n---\nv: !%79!int '1'", "yaml: did not find expected whitespace"}, +} + +func (s *S) TestUnmarshalErrors(c *C) { + for i, item := range unmarshalErrorTests { + c.Logf("test %d: %q", i, item.data) + var value interface{} + err := yaml.Unmarshal([]byte(item.data), &value) + c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value)) + } +} + +func (s *S) TestDecoderErrors(c *C) { + for _, item := range unmarshalErrorTests { + var value interface{} + err := yaml.NewDecoder(strings.NewReader(item.data)).Decode(&value) + c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value)) + } +} + +var unmarshalerTests = []struct { + data, tag string + value interface{} +}{ + {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}}, + {"_: [1,A]", "!!seq", []interface{}{1, "A"}}, + {"_: 10", "!!int", 10}, + {"_: null", "!!null", nil}, + {`_: BAR!`, "!!str", "BAR!"}, + {`_: "BAR!"`, "!!str", "BAR!"}, + {"_: !!foo 'BAR!'", "!!foo", "BAR!"}, + {`_: ""`, "!!str", ""}, +} + +var unmarshalerResult = map[int]error{} + +type unmarshalerType struct { + value interface{} +} + +func (o *unmarshalerType) UnmarshalYAML(unmarshal func(v interface{}) error) error { + if err := unmarshal(&o.value); err != nil { + return err + } + if i, ok := o.value.(int); ok { + if result, ok := unmarshalerResult[i]; ok { + return result + } + } + return nil +} + +type unmarshalerPointer struct { + Field *unmarshalerType "_" +} + +type unmarshalerValue struct { + Field unmarshalerType "_" +} + +func (s *S) TestUnmarshalerPointerField(c *C) { + for _, item := range unmarshalerTests { + obj := &unmarshalerPointer{} + err := yaml.Unmarshal([]byte(item.data), obj) + c.Assert(err, IsNil) + if item.value == nil { + c.Assert(obj.Field, IsNil) + } else { + c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value)) + c.Assert(obj.Field.value, DeepEquals, item.value) + } + } +} + +func (s *S) TestUnmarshalerValueField(c *C) { + for _, item := range unmarshalerTests { + obj := &unmarshalerValue{} + err := yaml.Unmarshal([]byte(item.data), obj) + c.Assert(err, IsNil) + c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value)) + c.Assert(obj.Field.value, DeepEquals, item.value) + } +} + +func (s *S) TestUnmarshalerWholeDocument(c *C) { + obj := &unmarshalerType{} + err := yaml.Unmarshal([]byte(unmarshalerTests[0].data), obj) + c.Assert(err, IsNil) + value, ok := obj.value.(map[interface{}]interface{}) + c.Assert(ok, Equals, true, Commentf("value: %#v", obj.value)) + c.Assert(value["_"], DeepEquals, unmarshalerTests[0].value) +} + +func (s *S) TestUnmarshalerTypeError(c *C) { + unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}} + unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}} + defer func() { + delete(unmarshalerResult, 2) + delete(unmarshalerResult, 4) + }() + + type T struct { + Before int + After int + M map[string]*unmarshalerType + } + var v T + data := `{before: A, m: {abc: 1, def: 2, ghi: 3, jkl: 4}, after: B}` + err := yaml.Unmarshal([]byte(data), &v) + c.Assert(err, ErrorMatches, ""+ + "yaml: unmarshal errors:\n"+ + " line 1: cannot unmarshal !!str `A` into int\n"+ + " foo\n"+ + " bar\n"+ + " line 1: cannot unmarshal !!str `B` into int") + c.Assert(v.M["abc"], NotNil) + c.Assert(v.M["def"], IsNil) + c.Assert(v.M["ghi"], NotNil) + c.Assert(v.M["jkl"], IsNil) + + c.Assert(v.M["abc"].value, Equals, 1) + c.Assert(v.M["ghi"].value, Equals, 3) +} + +type proxyTypeError struct{} + +func (v *proxyTypeError) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + var a int32 + var b int64 + if err := unmarshal(&s); err != nil { + panic(err) + } + if s == "a" { + if err := unmarshal(&b); err == nil { + panic("should have failed") + } + return unmarshal(&a) + } + if err := unmarshal(&a); err == nil { + panic("should have failed") + } + return unmarshal(&b) +} + +func (s *S) TestUnmarshalerTypeErrorProxying(c *C) { + type T struct { + Before int + After int + M map[string]*proxyTypeError + } + var v T + data := `{before: A, m: {abc: a, def: b}, after: B}` + err := yaml.Unmarshal([]byte(data), &v) + c.Assert(err, ErrorMatches, ""+ + "yaml: unmarshal errors:\n"+ + " line 1: cannot unmarshal !!str `A` into int\n"+ + " line 1: cannot unmarshal !!str `a` into int32\n"+ + " line 1: cannot unmarshal !!str `b` into int64\n"+ + " line 1: cannot unmarshal !!str `B` into int") +} + +type failingUnmarshaler struct{} + +var failingErr = errors.New("failingErr") + +func (ft *failingUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error { + return failingErr +} + +func (s *S) TestUnmarshalerError(c *C) { + err := yaml.Unmarshal([]byte("a: b"), &failingUnmarshaler{}) + c.Assert(err, Equals, failingErr) +} + +type sliceUnmarshaler []int + +func (su *sliceUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error { + var slice []int + err := unmarshal(&slice) + if err == nil { + *su = slice + return nil + } + + var intVal int + err = unmarshal(&intVal) + if err == nil { + *su = []int{intVal} + return nil + } + + return err +} + +func (s *S) TestUnmarshalerRetry(c *C) { + var su sliceUnmarshaler + err := yaml.Unmarshal([]byte("[1, 2, 3]"), &su) + c.Assert(err, IsNil) + c.Assert(su, DeepEquals, sliceUnmarshaler([]int{1, 2, 3})) + + err = yaml.Unmarshal([]byte("1"), &su) + c.Assert(err, IsNil) + c.Assert(su, DeepEquals, sliceUnmarshaler([]int{1})) +} + +// From http://yaml.org/type/merge.html +var mergeTests = ` +anchors: + list: + - &CENTER { "x": 1, "y": 2 } + - &LEFT { "x": 0, "y": 2 } + - &BIG { "r": 10 } + - &SMALL { "r": 1 } + +# All the following maps are equal: + +plain: + # Explicit keys + "x": 1 + "y": 2 + "r": 10 + label: center/big + +mergeOne: + # Merge one map + << : *CENTER + "r": 10 + label: center/big + +mergeMultiple: + # Merge multiple maps + << : [ *CENTER, *BIG ] + label: center/big + +override: + # Override + << : [ *BIG, *LEFT, *SMALL ] + "x": 1 + label: center/big + +shortTag: + # Explicit short merge tag + !!merge "<<" : [ *CENTER, *BIG ] + label: center/big + +longTag: + # Explicit merge long tag + !<tag:yaml.org,2002:merge> "<<" : [ *CENTER, *BIG ] + label: center/big + +inlineMap: + # Inlined map + << : {"x": 1, "y": 2, "r": 10} + label: center/big + +inlineSequenceMap: + # Inlined map in sequence + << : [ *CENTER, {"r": 10} ] + label: center/big +` + +func (s *S) TestMerge(c *C) { + var want = map[interface{}]interface{}{ + "x": 1, + "y": 2, + "r": 10, + "label": "center/big", + } + + var m map[interface{}]interface{} + err := yaml.Unmarshal([]byte(mergeTests), &m) + c.Assert(err, IsNil) + for name, test := range m { + if name == "anchors" { + continue + } + c.Assert(test, DeepEquals, want, Commentf("test %q failed", name)) + } +} + +func (s *S) TestMergeStruct(c *C) { + type Data struct { + X, Y, R int + Label string + } + want := Data{1, 2, 10, "center/big"} + + var m map[string]Data + err := yaml.Unmarshal([]byte(mergeTests), &m) + c.Assert(err, IsNil) + for name, test := range m { + if name == "anchors" { + continue + } + c.Assert(test, Equals, want, Commentf("test %q failed", name)) + } +} + +var unmarshalNullTests = []func() interface{}{ + func() interface{} { var v interface{}; v = "v"; return &v }, + func() interface{} { var s = "s"; return &s }, + func() interface{} { var s = "s"; sptr := &s; return &sptr }, + func() interface{} { var i = 1; return &i }, + func() interface{} { var i = 1; iptr := &i; return &iptr }, + func() interface{} { m := map[string]int{"s": 1}; return &m }, + func() interface{} { m := map[string]int{"s": 1}; return m }, +} + +func (s *S) TestUnmarshalNull(c *C) { + for _, test := range unmarshalNullTests { + item := test() + zero := reflect.Zero(reflect.TypeOf(item).Elem()).Interface() + err := yaml.Unmarshal([]byte("null"), item) + c.Assert(err, IsNil) + if reflect.TypeOf(item).Kind() == reflect.Map { + c.Assert(reflect.ValueOf(item).Interface(), DeepEquals, reflect.MakeMap(reflect.TypeOf(item)).Interface()) + } else { + c.Assert(reflect.ValueOf(item).Elem().Interface(), DeepEquals, zero) + } + } +} + +func (s *S) TestUnmarshalSliceOnPreset(c *C) { + // Issue #48. + v := struct{ A []int }{[]int{1}} + yaml.Unmarshal([]byte("a: [2]"), &v) + c.Assert(v.A, DeepEquals, []int{2}) +} + +var unmarshalStrictTests = []struct { + data string + value interface{} + error string +}{{ + data: "a: 1\nc: 2\n", + value: struct{ A, B int }{A: 1}, + error: `yaml: unmarshal errors:\n line 2: field c not found in type struct { A int; B int }`, +}, { + data: "a: 1\nb: 2\na: 3\n", + value: struct{ A, B int }{A: 3, B: 2}, + error: `yaml: unmarshal errors:\n line 3: field a already set in type struct { A int; B int }`, +}, { + data: "c: 3\na: 1\nb: 2\nc: 4\n", + value: struct { + A int + inlineB `yaml:",inline"` + }{ + A: 1, + inlineB: inlineB{ + B: 2, + inlineC: inlineC{ + C: 4, + }, + }, + }, + error: `yaml: unmarshal errors:\n line 4: field c already set in type struct { A int; yaml_test.inlineB "yaml:\\",inline\\"" }`, +}, { + data: "c: 0\na: 1\nb: 2\nc: 1\n", + value: struct { + A int + inlineB `yaml:",inline"` + }{ + A: 1, + inlineB: inlineB{ + B: 2, + inlineC: inlineC{ + C: 1, + }, + }, + }, + error: `yaml: unmarshal errors:\n line 4: field c already set in type struct { A int; yaml_test.inlineB "yaml:\\",inline\\"" }`, +}, { + data: "c: 1\na: 1\nb: 2\nc: 3\n", + value: struct { + A int + M map[string]interface{} `yaml:",inline"` + }{ + A: 1, + M: map[string]interface{}{ + "b": 2, + "c": 3, + }, + }, + error: `yaml: unmarshal errors:\n line 4: key "c" already set in map`, +}, { + data: "a: 1\n9: 2\nnull: 3\n9: 4", + value: map[interface{}]interface{}{ + "a": 1, + nil: 3, + 9: 4, + }, + error: `yaml: unmarshal errors:\n line 4: key 9 already set in map`, +}} + +func (s *S) TestUnmarshalStrict(c *C) { + for i, item := range unmarshalStrictTests { + c.Logf("test %d: %q", i, item.data) + // First test that normal Unmarshal unmarshals to the expected value. + t := reflect.ValueOf(item.value).Type() + value := reflect.New(t) + err := yaml.Unmarshal([]byte(item.data), value.Interface()) + c.Assert(err, Equals, nil) + c.Assert(value.Elem().Interface(), DeepEquals, item.value) + + // Then test that UnmarshalStrict fails on the same thing. + t = reflect.ValueOf(item.value).Type() + value = reflect.New(t) + err = yaml.UnmarshalStrict([]byte(item.data), value.Interface()) + c.Assert(err, ErrorMatches, item.error) + } +} + +type textUnmarshaler struct { + S string +} + +func (t *textUnmarshaler) UnmarshalText(s []byte) error { + t.S = string(s) + return nil +} + +func (s *S) TestFuzzCrashers(c *C) { + cases := []string{ + // runtime error: index out of range + "\"\\0\\\r\n", + + // should not happen + " 0: [\n] 0", + "? ? \"\n\" 0", + " - {\n000}0", + "0:\n 0: [0\n] 0", + " - \"\n000\"0", + " - \"\n000\"\"", + "0:\n - {\n000}0", + "0:\n - \"\n000\"0", + "0:\n - \"\n000\"\"", + + // runtime error: index out of range + " \ufeff\n", + "? \ufeff\n", + "? \ufeff:\n", + "0: \ufeff\n", + "? \ufeff: \ufeff\n", + } + for _, data := range cases { + var v interface{} + _ = yaml.Unmarshal([]byte(data), &v) + } +} + +//var data []byte +//func init() { +// var err error +// data, err = ioutil.ReadFile("/tmp/file.yaml") +// if err != nil { +// panic(err) +// } +//} +// +//func (s *S) BenchmarkUnmarshal(c *C) { +// var err error +// for i := 0; i < c.N; i++ { +// var v map[string]interface{} +// err = yaml.Unmarshal(data, &v) +// } +// if err != nil { +// panic(err) +// } +//} +// +//func (s *S) BenchmarkMarshal(c *C) { +// var v map[string]interface{} +// yaml.Unmarshal(data, &v) +// c.ResetTimer() +// for i := 0; i < c.N; i++ { +// yaml.Marshal(&v) +// } +//} diff --git a/vendor/gopkg.in/yaml.v2/encode_test.go b/vendor/gopkg.in/yaml.v2/encode_test.go new file mode 100644 index 000000000..f0911a76a --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/encode_test.go @@ -0,0 +1,595 @@ +package yaml_test + +import ( + "bytes" + "fmt" + "math" + "strconv" + "strings" + "time" + + "net" + "os" + + . "gopkg.in/check.v1" + "gopkg.in/yaml.v2" +) + +var marshalIntTest = 123 + +var marshalTests = []struct { + value interface{} + data string +}{ + { + nil, + "null\n", + }, { + (*marshalerType)(nil), + "null\n", + }, { + &struct{}{}, + "{}\n", + }, { + map[string]string{"v": "hi"}, + "v: hi\n", + }, { + map[string]interface{}{"v": "hi"}, + "v: hi\n", + }, { + map[string]string{"v": "true"}, + "v: \"true\"\n", + }, { + map[string]string{"v": "false"}, + "v: \"false\"\n", + }, { + map[string]interface{}{"v": true}, + "v: true\n", + }, { + map[string]interface{}{"v": false}, + "v: false\n", + }, { + map[string]interface{}{"v": 10}, + "v: 10\n", + }, { + map[string]interface{}{"v": -10}, + "v: -10\n", + }, { + map[string]uint{"v": 42}, + "v: 42\n", + }, { + map[string]interface{}{"v": int64(4294967296)}, + "v: 4294967296\n", + }, { + map[string]int64{"v": int64(4294967296)}, + "v: 4294967296\n", + }, { + map[string]uint64{"v": 4294967296}, + "v: 4294967296\n", + }, { + map[string]interface{}{"v": "10"}, + "v: \"10\"\n", + }, { + map[string]interface{}{"v": 0.1}, + "v: 0.1\n", + }, { + map[string]interface{}{"v": float64(0.1)}, + "v: 0.1\n", + }, { + map[string]interface{}{"v": float32(0.99)}, + "v: 0.99\n", + }, { + map[string]interface{}{"v": -0.1}, + "v: -0.1\n", + }, { + map[string]interface{}{"v": math.Inf(+1)}, + "v: .inf\n", + }, { + map[string]interface{}{"v": math.Inf(-1)}, + "v: -.inf\n", + }, { + map[string]interface{}{"v": math.NaN()}, + "v: .nan\n", + }, { + map[string]interface{}{"v": nil}, + "v: null\n", + }, { + map[string]interface{}{"v": ""}, + "v: \"\"\n", + }, { + map[string][]string{"v": []string{"A", "B"}}, + "v:\n- A\n- B\n", + }, { + map[string][]string{"v": []string{"A", "B\nC"}}, + "v:\n- A\n- |-\n B\n C\n", + }, { + map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}}, + "v:\n- A\n- 1\n- B:\n - 2\n - 3\n", + }, { + map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}}, + "a:\n b: c\n", + }, { + map[string]interface{}{"a": "-"}, + "a: '-'\n", + }, + + // Simple values. + { + &marshalIntTest, + "123\n", + }, + + // Structures + { + &struct{ Hello string }{"world"}, + "hello: world\n", + }, { + &struct { + A struct { + B string + } + }{struct{ B string }{"c"}}, + "a:\n b: c\n", + }, { + &struct { + A *struct { + B string + } + }{&struct{ B string }{"c"}}, + "a:\n b: c\n", + }, { + &struct { + A *struct { + B string + } + }{}, + "a: null\n", + }, { + &struct{ A int }{1}, + "a: 1\n", + }, { + &struct{ A []int }{[]int{1, 2}}, + "a:\n- 1\n- 2\n", + }, { + &struct{ A [2]int }{[2]int{1, 2}}, + "a:\n- 1\n- 2\n", + }, { + &struct { + B int "a" + }{1}, + "a: 1\n", + }, { + &struct{ A bool }{true}, + "a: true\n", + }, + + // Conditional flag + { + &struct { + A int "a,omitempty" + B int "b,omitempty" + }{1, 0}, + "a: 1\n", + }, { + &struct { + A int "a,omitempty" + B int "b,omitempty" + }{0, 0}, + "{}\n", + }, { + &struct { + A *struct{ X, y int } "a,omitempty,flow" + }{&struct{ X, y int }{1, 2}}, + "a: {x: 1}\n", + }, { + &struct { + A *struct{ X, y int } "a,omitempty,flow" + }{nil}, + "{}\n", + }, { + &struct { + A *struct{ X, y int } "a,omitempty,flow" + }{&struct{ X, y int }{}}, + "a: {x: 0}\n", + }, { + &struct { + A struct{ X, y int } "a,omitempty,flow" + }{struct{ X, y int }{1, 2}}, + "a: {x: 1}\n", + }, { + &struct { + A struct{ X, y int } "a,omitempty,flow" + }{struct{ X, y int }{0, 1}}, + "{}\n", + }, { + &struct { + A float64 "a,omitempty" + B float64 "b,omitempty" + }{1, 0}, + "a: 1\n", + }, + { + &struct { + T1 time.Time "t1,omitempty" + T2 time.Time "t2,omitempty" + T3 *time.Time "t3,omitempty" + T4 *time.Time "t4,omitempty" + }{ + T2: time.Date(2018, 1, 9, 10, 40, 47, 0, time.UTC), + T4: newTime(time.Date(2098, 1, 9, 10, 40, 47, 0, time.UTC)), + }, + "t2: 2018-01-09T10:40:47Z\nt4: 2098-01-09T10:40:47Z\n", + }, + // Nil interface that implements Marshaler. + { + map[string]yaml.Marshaler{ + "a": nil, + }, + "a: null\n", + }, + + // Flow flag + { + &struct { + A []int "a,flow" + }{[]int{1, 2}}, + "a: [1, 2]\n", + }, { + &struct { + A map[string]string "a,flow" + }{map[string]string{"b": "c", "d": "e"}}, + "a: {b: c, d: e}\n", + }, { + &struct { + A struct { + B, D string + } "a,flow" + }{struct{ B, D string }{"c", "e"}}, + "a: {b: c, d: e}\n", + }, + + // Unexported field + { + &struct { + u int + A int + }{0, 1}, + "a: 1\n", + }, + + // Ignored field + { + &struct { + A int + B int "-" + }{1, 2}, + "a: 1\n", + }, + + // Struct inlining + { + &struct { + A int + C inlineB `yaml:",inline"` + }{1, inlineB{2, inlineC{3}}}, + "a: 1\nb: 2\nc: 3\n", + }, + + // Map inlining + { + &struct { + A int + C map[string]int `yaml:",inline"` + }{1, map[string]int{"b": 2, "c": 3}}, + "a: 1\nb: 2\nc: 3\n", + }, + + // Duration + { + map[string]time.Duration{"a": 3 * time.Second}, + "a: 3s\n", + }, + + // Issue #24: bug in map merging logic. + { + map[string]string{"a": "<foo>"}, + "a: <foo>\n", + }, + + // Issue #34: marshal unsupported base 60 floats quoted for compatibility + // with old YAML 1.1 parsers. + { + map[string]string{"a": "1:1"}, + "a: \"1:1\"\n", + }, + + // Binary data. + { + map[string]string{"a": "\x00"}, + "a: \"\\0\"\n", + }, { + map[string]string{"a": "\x80\x81\x82"}, + "a: !!binary gIGC\n", + }, { + map[string]string{"a": strings.Repeat("\x90", 54)}, + "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n", + }, + + // Ordered maps. + { + &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}}, + "b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n", + }, + + // Encode unicode as utf-8 rather than in escaped form. + { + map[string]string{"a": "你好"}, + "a: 你好\n", + }, + + // Support encoding.TextMarshaler. + { + map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)}, + "a: 1.2.3.4\n", + }, + // time.Time gets a timestamp tag. + { + map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, 0, time.UTC)}, + "a: 2015-02-24T18:19:39Z\n", + }, + { + map[string]*time.Time{"a": newTime(time.Date(2015, 2, 24, 18, 19, 39, 0, time.UTC))}, + "a: 2015-02-24T18:19:39Z\n", + }, + { + // This is confirmed to be properly decoded in Python (libyaml) without a timestamp tag. + map[string]time.Time{"a": time.Date(2015, 2, 24, 18, 19, 39, 123456789, time.FixedZone("FOO", -3*60*60))}, + "a: 2015-02-24T18:19:39.123456789-03:00\n", + }, + // Ensure timestamp-like strings are quoted. + { + map[string]string{"a": "2015-02-24T18:19:39Z"}, + "a: \"2015-02-24T18:19:39Z\"\n", + }, + + // Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible). + { + map[string]string{"a": "b: c"}, + "a: 'b: c'\n", + }, + + // Containing hash mark ('#') in string should be quoted + { + map[string]string{"a": "Hello #comment"}, + "a: 'Hello #comment'\n", + }, + { + map[string]string{"a": "你好 #comment"}, + "a: '你好 #comment'\n", + }, +} + +func (s *S) TestMarshal(c *C) { + defer os.Setenv("TZ", os.Getenv("TZ")) + os.Setenv("TZ", "UTC") + for i, item := range marshalTests { + c.Logf("test %d: %q", i, item.data) + data, err := yaml.Marshal(item.value) + c.Assert(err, IsNil) + c.Assert(string(data), Equals, item.data) + } +} + +func (s *S) TestEncoderSingleDocument(c *C) { + for i, item := range marshalTests { + c.Logf("test %d. %q", i, item.data) + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + err := enc.Encode(item.value) + c.Assert(err, Equals, nil) + err = enc.Close() + c.Assert(err, Equals, nil) + c.Assert(buf.String(), Equals, item.data) + } +} + +func (s *S) TestEncoderMultipleDocuments(c *C) { + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + err := enc.Encode(map[string]string{"a": "b"}) + c.Assert(err, Equals, nil) + err = enc.Encode(map[string]string{"c": "d"}) + c.Assert(err, Equals, nil) + err = enc.Close() + c.Assert(err, Equals, nil) + c.Assert(buf.String(), Equals, "a: b\n---\nc: d\n") +} + +func (s *S) TestEncoderWriteError(c *C) { + enc := yaml.NewEncoder(errorWriter{}) + err := enc.Encode(map[string]string{"a": "b"}) + c.Assert(err, ErrorMatches, `yaml: write error: some write error`) // Data not flushed yet +} + +type errorWriter struct{} + +func (errorWriter) Write([]byte) (int, error) { + return 0, fmt.Errorf("some write error") +} + +var marshalErrorTests = []struct { + value interface{} + error string + panic string +}{{ + value: &struct { + B int + inlineB ",inline" + }{1, inlineB{2, inlineC{3}}}, + panic: `Duplicated key 'b' in struct struct \{ B int; .*`, +}, { + value: &struct { + A int + B map[string]int ",inline" + }{1, map[string]int{"a": 2}}, + panic: `Can't have key "a" in inlined map; conflicts with struct field`, +}} + +func (s *S) TestMarshalErrors(c *C) { + for _, item := range marshalErrorTests { + if item.panic != "" { + c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic) + } else { + _, err := yaml.Marshal(item.value) + c.Assert(err, ErrorMatches, item.error) + } + } +} + +func (s *S) TestMarshalTypeCache(c *C) { + var data []byte + var err error + func() { + type T struct{ A int } + data, err = yaml.Marshal(&T{}) + c.Assert(err, IsNil) + }() + func() { + type T struct{ B int } + data, err = yaml.Marshal(&T{}) + c.Assert(err, IsNil) + }() + c.Assert(string(data), Equals, "b: 0\n") +} + +var marshalerTests = []struct { + data string + value interface{} +}{ + {"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}}, + {"_:\n- 1\n- A\n", []interface{}{1, "A"}}, + {"_: 10\n", 10}, + {"_: null\n", nil}, + {"_: BAR!\n", "BAR!"}, +} + +type marshalerType struct { + value interface{} +} + +func (o marshalerType) MarshalText() ([]byte, error) { + panic("MarshalText called on type with MarshalYAML") +} + +func (o marshalerType) MarshalYAML() (interface{}, error) { + return o.value, nil +} + +type marshalerValue struct { + Field marshalerType "_" +} + +func (s *S) TestMarshaler(c *C) { + for _, item := range marshalerTests { + obj := &marshalerValue{} + obj.Field.value = item.value + data, err := yaml.Marshal(obj) + c.Assert(err, IsNil) + c.Assert(string(data), Equals, string(item.data)) + } +} + +func (s *S) TestMarshalerWholeDocument(c *C) { + obj := &marshalerType{} + obj.value = map[string]string{"hello": "world!"} + data, err := yaml.Marshal(obj) + c.Assert(err, IsNil) + c.Assert(string(data), Equals, "hello: world!\n") +} + +type failingMarshaler struct{} + +func (ft *failingMarshaler) MarshalYAML() (interface{}, error) { + return nil, failingErr +} + +func (s *S) TestMarshalerError(c *C) { + _, err := yaml.Marshal(&failingMarshaler{}) + c.Assert(err, Equals, failingErr) +} + +func (s *S) TestSortedOutput(c *C) { + order := []interface{}{ + false, + true, + 1, + uint(1), + 1.0, + 1.1, + 1.2, + 2, + uint(2), + 2.0, + 2.1, + "", + ".1", + ".2", + ".a", + "1", + "2", + "a!10", + "a/0001", + "a/002", + "a/3", + "a/10", + "a/11", + "a/0012", + "a/100", + "a~10", + "ab/1", + "b/1", + "b/01", + "b/2", + "b/02", + "b/3", + "b/03", + "b1", + "b01", + "b3", + "c2.10", + "c10.2", + "d1", + "d7", + "d7abc", + "d12", + "d12a", + } + m := make(map[interface{}]int) + for _, k := range order { + m[k] = 1 + } + data, err := yaml.Marshal(m) + c.Assert(err, IsNil) + out := "\n" + string(data) + last := 0 + for i, k := range order { + repr := fmt.Sprint(k) + if s, ok := k.(string); ok { + if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil { + repr = `"` + repr + `"` + } + } + index := strings.Index(out, "\n"+repr+":") + if index == -1 { + c.Fatalf("%#v is not in the output: %#v", k, out) + } + if index < last { + c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out) + } + last = index + } +} + +func newTime(t time.Time) *time.Time { + return &t +} diff --git a/vendor/gopkg.in/yaml.v2/example_embedded_test.go b/vendor/gopkg.in/yaml.v2/example_embedded_test.go new file mode 100644 index 000000000..171c0931a --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/example_embedded_test.go @@ -0,0 +1,41 @@ +package yaml_test + +import ( + "fmt" + "log" + + "gopkg.in/yaml.v2" +) + +// An example showing how to unmarshal embedded +// structs from YAML. + +type StructA struct { + A string `yaml:"a"` +} + +type StructB struct { + // Embedded structs are not treated as embedded in YAML by default. To do that, + // add the ",inline" annotation below + StructA `yaml:",inline"` + B string `yaml:"b"` +} + +var data = ` +a: a string from struct A +b: a string from struct B +` + +func ExampleUnmarshal_embedded() { + var b StructB + + err := yaml.Unmarshal([]byte(data), &b) + if err != nil { + log.Fatalf("cannot unmarshal data: %v", err) + } + fmt.Println(b.A) + fmt.Println(b.B) + // Output: + // a string from struct A + // a string from struct B +} diff --git a/vendor/gopkg.in/yaml.v2/go.mod b/vendor/gopkg.in/yaml.v2/go.mod new file mode 100644 index 000000000..1934e8769 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/go.mod @@ -0,0 +1,5 @@ +module "gopkg.in/yaml.v2" + +require ( + "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 +) diff --git a/vendor/gopkg.in/yaml.v2/suite_test.go b/vendor/gopkg.in/yaml.v2/suite_test.go new file mode 100644 index 000000000..c5cf1ed4f --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/suite_test.go @@ -0,0 +1,12 @@ +package yaml_test + +import ( + . "gopkg.in/check.v1" + "testing" +) + +func Test(t *testing.T) { TestingT(t) } + +type S struct{} + +var _ = Suite(&S{}) diff --git a/vendor/k8s.io/api/CONTRIBUTING.md b/vendor/k8s.io/api/CONTRIBUTING.md new file mode 100644 index 000000000..094efca3d --- /dev/null +++ b/vendor/k8s.io/api/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/api](https://git.k8s.io/kubernetes/staging/src/k8s.io/api) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/vendor/k8s.io/api/OWNERS b/vendor/k8s.io/api/OWNERS new file mode 100644 index 000000000..e79d5f1d4 --- /dev/null +++ b/vendor/k8s.io/api/OWNERS @@ -0,0 +1,52 @@ +approvers: +- erictune +- lavalamp +- smarterclayton +- thockin +- liggitt +# - bgrant0607 # manual escalations only +reviewers: +- brendandburns +- caesarxuchao +- davidopp +- dchen1107 +- deads2k +- derekwaynecarr +- dims +- eparis +- erictune +- errordeveloper +- feiskyer +- gmarek +- janetkuo +- jbeda +- jsafrane +- jszczepkowski +- justinsb +- krousey +- lavalamp +- liggitt +- luxas +- madhusudancs +- mikedanese +- mwielgus +- ncdc +- nikhiljindal +- piosz +- pmorie +- pwittrock +- roberthbailey +- rootfs +- saad-ali +- smarterclayton +- soltysh +- sttts +- tallclair +- thockin +- vishh +- wojtek-t +- yifan-gu +- yujuhong +- zmerlynn +labels: +- sig/architecture diff --git a/vendor/k8s.io/api/README.md b/vendor/k8s.io/api/README.md new file mode 100644 index 000000000..967543a45 --- /dev/null +++ b/vendor/k8s.io/api/README.md @@ -0,0 +1 @@ +This repo is still in the experimental stage. Shortly it will contain the schema of the API that are served by the Kubernetes apiserver. diff --git a/vendor/k8s.io/api/SECURITY_CONTACTS b/vendor/k8s.io/api/SECURITY_CONTACTS new file mode 100644 index 000000000..0648a8ebf --- /dev/null +++ b/vendor/k8s.io/api/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# 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/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/vendor/k8s.io/api/admissionregistration/v1alpha1/generated.proto b/vendor/k8s.io/api/admissionregistration/v1alpha1/generated.proto new file mode 100644 index 000000000..e17b55968 --- /dev/null +++ b/vendor/k8s.io/api/admissionregistration/v1alpha1/generated.proto @@ -0,0 +1,107 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.admissionregistration.v1alpha1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1alpha1"; + +// Initializer describes the name and the failure policy of an initializer, and +// what resources it applies to. +message Initializer { + // Name is the identifier of the initializer. It will be added to the + // object that needs to be initialized. + // Name should be fully qualified, e.g., alwayspullimages.kubernetes.io, where + // "alwayspullimages" is the name of the webhook, and kubernetes.io is the name + // of the organization. + // Required + optional string name = 1; + + // Rules describes what resources/subresources the initializer cares about. + // The initializer cares about an operation if it matches _any_ Rule. + // Rule.Resources must not include subresources. + repeated Rule rules = 2; +} + +// InitializerConfiguration describes the configuration of initializers. +message InitializerConfiguration { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Initializers is a list of resources and their default initializers + // Order-sensitive. + // When merging multiple InitializerConfigurations, we sort the initializers + // from different InitializerConfigurations by the name of the + // InitializerConfigurations; the order of the initializers from the same + // InitializerConfiguration is preserved. + // +patchMergeKey=name + // +patchStrategy=merge + // +optional + repeated Initializer initializers = 2; +} + +// InitializerConfigurationList is a list of InitializerConfiguration. +message InitializerConfigurationList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of InitializerConfiguration. + repeated InitializerConfiguration items = 2; +} + +// Rule is a tuple of APIGroups, APIVersion, and Resources.It is recommended +// to make sure that all the tuple expansions are valid. +message Rule { + // APIGroups is the API groups the resources belong to. '*' is all groups. + // If '*' is present, the length of the slice must be one. + // Required. + repeated string apiGroups = 1; + + // APIVersions is the API versions the resources belong to. '*' is all versions. + // If '*' is present, the length of the slice must be one. + // Required. + repeated string apiVersions = 2; + + // Resources is a list of resources this rule applies to. + // + // For example: + // 'pods' means pods. + // 'pods/log' means the log subresource of pods. + // '*' means all resources, but not subresources. + // 'pods/*' means all subresources of pods. + // '*/scale' means all scale subresources. + // '*/*' means all resources and their subresources. + // + // If wildcard is present, the validation rule will ensure resources do not + // overlap with each other. + // + // Depending on the enclosing object, subresources might not be allowed. + // Required. + repeated string resources = 3; +} + diff --git a/vendor/k8s.io/api/admissionregistration/v1beta1/generated.proto b/vendor/k8s.io/api/admissionregistration/v1beta1/generated.proto new file mode 100644 index 000000000..4d55ca878 --- /dev/null +++ b/vendor/k8s.io/api/admissionregistration/v1beta1/generated.proto @@ -0,0 +1,269 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.admissionregistration.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. +message MutatingWebhookConfiguration { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Webhooks is a list of webhooks and the affected resources and operations. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + repeated Webhook Webhooks = 2; +} + +// MutatingWebhookConfigurationList is a list of MutatingWebhookConfiguration. +message MutatingWebhookConfigurationList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of MutatingWebhookConfiguration. + repeated MutatingWebhookConfiguration items = 2; +} + +// Rule is a tuple of APIGroups, APIVersion, and Resources.It is recommended +// to make sure that all the tuple expansions are valid. +message Rule { + // APIGroups is the API groups the resources belong to. '*' is all groups. + // If '*' is present, the length of the slice must be one. + // Required. + repeated string apiGroups = 1; + + // APIVersions is the API versions the resources belong to. '*' is all versions. + // If '*' is present, the length of the slice must be one. + // Required. + repeated string apiVersions = 2; + + // Resources is a list of resources this rule applies to. + // + // For example: + // 'pods' means pods. + // 'pods/log' means the log subresource of pods. + // '*' means all resources, but not subresources. + // 'pods/*' means all subresources of pods. + // '*/scale' means all scale subresources. + // '*/*' means all resources and their subresources. + // + // If wildcard is present, the validation rule will ensure resources do not + // overlap with each other. + // + // Depending on the enclosing object, subresources might not be allowed. + // Required. + repeated string resources = 3; +} + +// RuleWithOperations is a tuple of Operations and Resources. It is recommended to make +// sure that all the tuple expansions are valid. +message RuleWithOperations { + // Operations is the operations the admission hook cares about - CREATE, UPDATE, or * + // for all operations. + // If '*' is present, the length of the slice must be one. + // Required. + repeated string operations = 1; + + // Rule is embedded, it describes other criteria of the rule, like + // APIGroups, APIVersions, Resources, etc. + optional Rule rule = 2; +} + +// ServiceReference holds a reference to Service.legacy.k8s.io +message ServiceReference { + // `namespace` is the namespace of the service. + // Required + optional string namespace = 1; + + // `name` is the name of the service. + // Required + optional string name = 2; + + // `path` is an optional URL path which will be sent in any request to + // this service. + // +optional + optional string path = 3; +} + +// ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. +message ValidatingWebhookConfiguration { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Webhooks is a list of webhooks and the affected resources and operations. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + repeated Webhook Webhooks = 2; +} + +// ValidatingWebhookConfigurationList is a list of ValidatingWebhookConfiguration. +message ValidatingWebhookConfigurationList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of ValidatingWebhookConfiguration. + repeated ValidatingWebhookConfiguration items = 2; +} + +// Webhook describes an admission webhook and the resources and operations it applies to. +message Webhook { + // The name of the admission webhook. + // Name should be fully qualified, e.g., imagepolicy.kubernetes.io, where + // "imagepolicy" is the name of the webhook, and kubernetes.io is the name + // of the organization. + // Required. + optional string name = 1; + + // ClientConfig defines how to communicate with the hook. + // Required + optional WebhookClientConfig clientConfig = 2; + + // Rules describes what operations on what resources/subresources the webhook cares about. + // The webhook cares about an operation if it matches _any_ Rule. + // However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks + // from putting the cluster in a state which cannot be recovered from without completely + // disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called + // on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects. + repeated RuleWithOperations rules = 3; + + // FailurePolicy defines how unrecognized errors from the admission endpoint are handled - + // allowed values are Ignore or Fail. Defaults to Ignore. + // +optional + optional string failurePolicy = 4; + + // NamespaceSelector decides whether to run the webhook on an object based + // on whether the namespace for that object matches the selector. If the + // object itself is a namespace, the matching is performed on + // object.metadata.labels. If the object is another cluster scoped resource, + // it never skips the webhook. + // + // For example, to run the webhook on any objects whose namespace is not + // associated with "runlevel" of "0" or "1"; you will set the selector as + // follows: + // "namespaceSelector": { + // "matchExpressions": [ + // { + // "key": "runlevel", + // "operator": "NotIn", + // "values": [ + // "0", + // "1" + // ] + // } + // ] + // } + // + // If instead you want to only run the webhook on any objects whose + // namespace is associated with the "environment" of "prod" or "staging"; + // you will set the selector as follows: + // "namespaceSelector": { + // "matchExpressions": [ + // { + // "key": "environment", + // "operator": "In", + // "values": [ + // "prod", + // "staging" + // ] + // } + // ] + // } + // + // See + // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + // for more examples of label selectors. + // + // Default to the empty LabelSelector, which matches everything. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector namespaceSelector = 5; + + // SideEffects states whether this webhookk has side effects. + // Acceptable values are: Unknown, None, Some, NoneOnDryRun + // Webhooks with side effects MUST implement a reconciliation system, since a request may be + // rejected by a future step in the admission change and the side effects therefore need to be undone. + // Requests with the dryRun attribute will be auto-rejected if they match a webhook with + // sideEffects == Unknown or Some. Defaults to Unknown. + // +optional + optional string sideEffects = 6; +} + +// WebhookClientConfig contains the information to make a TLS +// connection with the webhook +message WebhookClientConfig { + // `url` gives the location of the webhook, in standard URL form + // (`[scheme://]host:port/path`). Exactly one of `url` or `service` + // must be specified. + // + // The `host` should not refer to a service running in the cluster; use + // the `service` field instead. The host might be resolved via external + // DNS in some apiservers (e.g., `kube-apiserver` cannot resolve + // in-cluster DNS as that would be a layering violation). `host` may + // also be an IP address. + // + // Please note that using `localhost` or `127.0.0.1` as a `host` is + // risky unless you take great care to run this webhook on all hosts + // which run an apiserver which might need to make calls to this + // webhook. Such installs are likely to be non-portable, i.e., not easy + // to turn up in a new cluster. + // + // The scheme must be "https"; the URL must begin with "https://". + // + // A path is optional, and if present may be any string permissible in + // a URL. You may use the path to pass an arbitrary string to the + // webhook, for example, a cluster identifier. + // + // Attempting to use a user or basic auth e.g. "user:password@" is not + // allowed. Fragments ("#...") and query parameters ("?...") are not + // allowed, either. + // + // +optional + optional string url = 3; + + // `service` is a reference to the service for this webhook. Either + // `service` or `url` must be specified. + // + // If the webhook is running within the cluster, then you should use `service`. + // + // Port 443 will be used if it is open, otherwise it is an error. + // + // +optional + optional ServiceReference service = 1; + + // `caBundle` is a PEM encoded CA bundle which will be used to validate + // the webhook's server certificate. + // Required. + optional bytes caBundle = 2; +} + diff --git a/vendor/k8s.io/api/apps/OWNERS b/vendor/k8s.io/api/apps/OWNERS new file mode 100755 index 000000000..2f260571a --- /dev/null +++ b/vendor/k8s.io/api/apps/OWNERS @@ -0,0 +1,19 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- deads2k +- caesarxuchao +- pmorie +- sttts +- saad-ali +- ncdc +- tallclair +- dims +- errordeveloper +- mml +- m1093782566 +- mbohlool +- david-mcmahon +- kevin-wangzefeng +- jianhuiz diff --git a/vendor/k8s.io/api/apps/v1/generated.proto b/vendor/k8s.io/api/apps/v1/generated.proto new file mode 100644 index 000000000..c8a957ac6 --- /dev/null +++ b/vendor/k8s.io/api/apps/v1/generated.proto @@ -0,0 +1,700 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.apps.v1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// ControllerRevision implements an immutable snapshot of state data. Clients +// are responsible for serializing and deserializing the objects that contain +// their internal state. +// Once a ControllerRevision has been successfully created, it can not be updated. +// The API Server will fail validation of all requests that attempt to mutate +// the Data field. ControllerRevisions may, however, be deleted. Note that, due to its use by both +// the DaemonSet and StatefulSet controllers for update and rollback, this object is beta. However, +// it may be subject to name and representation changes in future releases, and clients should not +// depend on its stability. It is primarily for internal use by controllers. +message ControllerRevision { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Data is the serialized representation of the state. + optional k8s.io.apimachinery.pkg.runtime.RawExtension data = 2; + + // Revision indicates the revision of the state represented by Data. + optional int64 revision = 3; +} + +// ControllerRevisionList is a resource containing a list of ControllerRevision objects. +message ControllerRevisionList { + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of ControllerRevisions + repeated ControllerRevision items = 2; +} + +// DaemonSet represents the configuration of a daemon set. +message DaemonSet { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The desired behavior of this daemon set. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional DaemonSetSpec spec = 2; + + // The current status of this daemon set. This data may be + // out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional DaemonSetStatus status = 3; +} + +// DaemonSetCondition describes the state of a DaemonSet at a certain point. +message DaemonSetCondition { + // Type of DaemonSet condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// DaemonSetList is a collection of daemon sets. +message DaemonSetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // A list of daemon sets. + repeated DaemonSet items = 2; +} + +// DaemonSetSpec is the specification of a daemon set. +message DaemonSetSpec { + // A label query over pods that are managed by the daemon set. + // Must match in order to be controlled. + // It must match the pod template's labels. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 1; + + // An object that describes the pod that will be created. + // The DaemonSet will create exactly one copy of this pod on every node + // that matches the template's node selector (or on every node if no node + // selector is specified). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + optional k8s.io.api.core.v1.PodTemplateSpec template = 2; + + // An update strategy to replace existing DaemonSet pods with new pods. + // +optional + optional DaemonSetUpdateStrategy updateStrategy = 3; + + // The minimum number of seconds for which a newly created DaemonSet pod should + // be ready without any of its container crashing, for it to be considered + // available. Defaults to 0 (pod will be considered available as soon as it + // is ready). + // +optional + optional int32 minReadySeconds = 4; + + // The number of old history to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 10. + // +optional + optional int32 revisionHistoryLimit = 6; +} + +// DaemonSetStatus represents the current status of a daemon set. +message DaemonSetStatus { + // The number of nodes that are running at least 1 + // daemon pod and are supposed to run the daemon pod. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 currentNumberScheduled = 1; + + // The number of nodes that are running the daemon pod, but are + // not supposed to run the daemon pod. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 numberMisscheduled = 2; + + // The total number of nodes that should be running the daemon + // pod (including nodes correctly running the daemon pod). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 desiredNumberScheduled = 3; + + // The number of nodes that should be running the daemon pod and have one + // or more of the daemon pod running and ready. + optional int32 numberReady = 4; + + // The most recent generation observed by the daemon set controller. + // +optional + optional int64 observedGeneration = 5; + + // The total number of nodes that are running updated daemon pod + // +optional + optional int32 updatedNumberScheduled = 6; + + // The number of nodes that should be running the + // daemon pod and have one or more of the daemon pod running and + // available (ready for at least spec.minReadySeconds) + // +optional + optional int32 numberAvailable = 7; + + // The number of nodes that should be running the + // daemon pod and have none of the daemon pod running and available + // (ready for at least spec.minReadySeconds) + // +optional + optional int32 numberUnavailable = 8; + + // Count of hash collisions for the DaemonSet. The DaemonSet controller + // uses this field as a collision avoidance mechanism when it needs to + // create the name for the newest ControllerRevision. + // +optional + optional int32 collisionCount = 9; + + // Represents the latest available observations of a DaemonSet's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated DaemonSetCondition conditions = 10; +} + +// DaemonSetUpdateStrategy is a struct used to control the update strategy for a DaemonSet. +message DaemonSetUpdateStrategy { + // Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is RollingUpdate. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if type = "RollingUpdate". + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. Same as Deployment `strategy.rollingUpdate`. + // See https://github.com/kubernetes/kubernetes/issues/35345 + // +optional + optional RollingUpdateDaemonSet rollingUpdate = 2; +} + +// Deployment enables declarative updates for Pods and ReplicaSets. +message Deployment { + // Standard object metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the Deployment. + // +optional + optional DeploymentSpec spec = 2; + + // Most recently observed status of the Deployment. + // +optional + optional DeploymentStatus status = 3; +} + +// DeploymentCondition describes the state of a deployment at a certain point. +message DeploymentCondition { + // Type of deployment condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time this condition was updated. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastUpdateTime = 6; + + // Last time the condition transitioned from one status to another. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 7; + + // The reason for the condition's last transition. + optional string reason = 4; + + // A human readable message indicating details about the transition. + optional string message = 5; +} + +// DeploymentList is a list of Deployments. +message DeploymentList { + // Standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of Deployments. + repeated Deployment items = 2; +} + +// DeploymentSpec is the specification of the desired behavior of the Deployment. +message DeploymentSpec { + // Number of desired pods. This is a pointer to distinguish between explicit + // zero and not specified. Defaults to 1. + // +optional + optional int32 replicas = 1; + + // Label selector for pods. Existing ReplicaSets whose pods are + // selected by this will be the ones affected by this deployment. + // It must match the pod template's labels. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template describes the pods that will be created. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // The deployment strategy to use to replace existing pods with new ones. + // +optional + optional DeploymentStrategy strategy = 4; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 5; + + // The number of old ReplicaSets to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 10. + // +optional + optional int32 revisionHistoryLimit = 6; + + // Indicates that the deployment is paused. + // +optional + optional bool paused = 7; + + // The maximum time in seconds for a deployment to make progress before it + // is considered to be failed. The deployment controller will continue to + // process failed deployments and a condition with a ProgressDeadlineExceeded + // reason will be surfaced in the deployment status. Note that progress will + // not be estimated during the time a deployment is paused. Defaults to 600s. + optional int32 progressDeadlineSeconds = 9; +} + +// DeploymentStatus is the most recently observed status of the Deployment. +message DeploymentStatus { + // The generation observed by the deployment controller. + // +optional + optional int64 observedGeneration = 1; + + // Total number of non-terminated pods targeted by this deployment (their labels match the selector). + // +optional + optional int32 replicas = 2; + + // Total number of non-terminated pods targeted by this deployment that have the desired template spec. + // +optional + optional int32 updatedReplicas = 3; + + // Total number of ready pods targeted by this deployment. + // +optional + optional int32 readyReplicas = 7; + + // Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. + // +optional + optional int32 availableReplicas = 4; + + // Total number of unavailable pods targeted by this deployment. This is the total number of + // pods that are still required for the deployment to have 100% available capacity. They may + // either be pods that are running but not yet available or pods that still have not been created. + // +optional + optional int32 unavailableReplicas = 5; + + // Represents the latest available observations of a deployment's current state. + // +patchMergeKey=type + // +patchStrategy=merge + repeated DeploymentCondition conditions = 6; + + // Count of hash collisions for the Deployment. The Deployment controller uses this + // field as a collision avoidance mechanism when it needs to create the name for the + // newest ReplicaSet. + // +optional + optional int32 collisionCount = 8; +} + +// DeploymentStrategy describes how to replace existing pods with new ones. +message DeploymentStrategy { + // Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if DeploymentStrategyType = + // RollingUpdate. + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. + // +optional + optional RollingUpdateDeployment rollingUpdate = 2; +} + +// ReplicaSet ensures that a specified number of pod replicas are running at any given time. +message ReplicaSet { + // If the Labels of a ReplicaSet are empty, they are defaulted to + // be the same as the Pod(s) that the ReplicaSet manages. + // Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the specification of the desired behavior of the ReplicaSet. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicaSetSpec spec = 2; + + // Status is the most recently observed status of the ReplicaSet. + // This data may be out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicaSetStatus status = 3; +} + +// ReplicaSetCondition describes the state of a replica set at a certain point. +message ReplicaSetCondition { + // Type of replica set condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// ReplicaSetList is a collection of ReplicaSets. +message ReplicaSetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of ReplicaSets. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller + repeated ReplicaSet items = 2; +} + +// ReplicaSetSpec is the specification of a ReplicaSet. +message ReplicaSetSpec { + // Replicas is the number of desired replicas. + // This is a pointer to distinguish between explicit zero and unspecified. + // Defaults to 1. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller + // +optional + optional int32 replicas = 1; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 4; + + // Selector is a label query over pods that should match the replica count. + // Label keys and values that must match in order to be controlled by this replica set. + // It must match the pod template's labels. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + // +optional + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; +} + +// ReplicaSetStatus represents the current status of a ReplicaSet. +message ReplicaSetStatus { + // Replicas is the most recently oberved number of replicas. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller + optional int32 replicas = 1; + + // The number of pods that have labels matching the labels of the pod template of the replicaset. + // +optional + optional int32 fullyLabeledReplicas = 2; + + // The number of ready replicas for this replica set. + // +optional + optional int32 readyReplicas = 4; + + // The number of available replicas (ready for at least minReadySeconds) for this replica set. + // +optional + optional int32 availableReplicas = 5; + + // ObservedGeneration reflects the generation of the most recently observed ReplicaSet. + // +optional + optional int64 observedGeneration = 3; + + // Represents the latest available observations of a replica set's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated ReplicaSetCondition conditions = 6; +} + +// Spec to control the desired behavior of daemon set rolling update. +message RollingUpdateDaemonSet { + // The maximum number of DaemonSet pods that can be unavailable during the + // update. Value can be an absolute number (ex: 5) or a percentage of total + // number of DaemonSet pods at the start of the update (ex: 10%). Absolute + // number is calculated from percentage by rounding up. + // This cannot be 0. + // Default value is 1. + // Example: when this is set to 30%, at most 30% of the total number of nodes + // that should be running the daemon pod (i.e. status.desiredNumberScheduled) + // can have their pods stopped for an update at any given + // time. The update starts by stopping at most 30% of those DaemonSet pods + // and then brings up new DaemonSet pods in their place. Once the new pods + // are available, it then proceeds onto other DaemonSet pods, thus ensuring + // that at least 70% of original number of DaemonSet pods are available at + // all times during the update. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; +} + +// Spec to control the desired behavior of rolling update. +message RollingUpdateDeployment { + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding down. + // This can not be 0 if MaxSurge is 0. + // Defaults to 25%. + // Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods + // immediately when the rolling update starts. Once new pods are ready, old ReplicaSet + // can be scaled down further, followed by scaling up the new ReplicaSet, ensuring + // that the total number of pods available at all times during the update is at + // least 70% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; + + // The maximum number of pods that can be scheduled above the desired number of + // pods. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // This can not be 0 if MaxUnavailable is 0. + // Absolute number is calculated from percentage by rounding up. + // Defaults to 25%. + // Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when + // the rolling update starts, such that the total number of old and new pods do not exceed + // 130% of desired pods. Once old pods have been killed, + // new ReplicaSet can be scaled up further, ensuring that total number of pods running + // at any time during the update is at most 130% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxSurge = 2; +} + +// RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. +message RollingUpdateStatefulSetStrategy { + // Partition indicates the ordinal at which the StatefulSet should be + // partitioned. + // Default value is 0. + // +optional + optional int32 partition = 1; +} + +// StatefulSet represents a set of pods with consistent identities. +// Identities are defined as: +// - Network: A single stable DNS and hostname. +// - Storage: As many VolumeClaims as requested. +// The StatefulSet guarantees that a given network identity will always +// map to the same storage identity. +message StatefulSet { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the desired identities of pods in this set. + // +optional + optional StatefulSetSpec spec = 2; + + // Status is the current status of Pods in this StatefulSet. This data + // may be out of date by some window of time. + // +optional + optional StatefulSetStatus status = 3; +} + +// StatefulSetCondition describes the state of a statefulset at a certain point. +message StatefulSetCondition { + // Type of statefulset condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// StatefulSetList is a collection of StatefulSets. +message StatefulSetList { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + repeated StatefulSet items = 2; +} + +// A StatefulSetSpec is the specification of a StatefulSet. +message StatefulSetSpec { + // replicas is the desired number of replicas of the given Template. + // These are replicas in the sense that they are instantiations of the + // same Template, but individual replicas also have a consistent identity. + // If unspecified, defaults to 1. + // TODO: Consider a rename of this field. + // +optional + optional int32 replicas = 1; + + // selector is a label query over pods that should match the replica count. + // It must match the pod template's labels. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // template is the object that describes the pod that will be created if + // insufficient replicas are detected. Each pod stamped out by the StatefulSet + // will fulfill this Template, but have a unique identity from the rest + // of the StatefulSet. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // volumeClaimTemplates is a list of claims that pods are allowed to reference. + // The StatefulSet controller is responsible for mapping network identities to + // claims in a way that maintains the identity of a pod. Every claim in + // this list must have at least one matching (by name) volumeMount in one + // container in the template. A claim in this list takes precedence over + // any volumes in the template, with the same name. + // TODO: Define the behavior if a claim already exists with the same name. + // +optional + repeated k8s.io.api.core.v1.PersistentVolumeClaim volumeClaimTemplates = 4; + + // serviceName is the name of the service that governs this StatefulSet. + // This service must exist before the StatefulSet, and is responsible for + // the network identity of the set. Pods get DNS/hostnames that follow the + // pattern: pod-specific-string.serviceName.default.svc.cluster.local + // where "pod-specific-string" is managed by the StatefulSet controller. + optional string serviceName = 5; + + // podManagementPolicy controls how pods are created during initial scale up, + // when replacing pods on nodes, or when scaling down. The default policy is + // `OrderedReady`, where pods are created in increasing order (pod-0, then + // pod-1, etc) and the controller will wait until each pod is ready before + // continuing. When scaling down, the pods are removed in the opposite order. + // The alternative policy is `Parallel` which will create pods in parallel + // to match the desired scale without waiting, and on scale down will delete + // all pods at once. + // +optional + optional string podManagementPolicy = 6; + + // updateStrategy indicates the StatefulSetUpdateStrategy that will be + // employed to update Pods in the StatefulSet when a revision is made to + // Template. + optional StatefulSetUpdateStrategy updateStrategy = 7; + + // revisionHistoryLimit is the maximum number of revisions that will + // be maintained in the StatefulSet's revision history. The revision history + // consists of all revisions not represented by a currently applied + // StatefulSetSpec version. The default value is 10. + optional int32 revisionHistoryLimit = 8; +} + +// StatefulSetStatus represents the current state of a StatefulSet. +message StatefulSetStatus { + // observedGeneration is the most recent generation observed for this StatefulSet. It corresponds to the + // StatefulSet's generation, which is updated on mutation by the API Server. + // +optional + optional int64 observedGeneration = 1; + + // replicas is the number of Pods created by the StatefulSet controller. + optional int32 replicas = 2; + + // readyReplicas is the number of Pods created by the StatefulSet controller that have a Ready Condition. + optional int32 readyReplicas = 3; + + // currentReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by currentRevision. + optional int32 currentReplicas = 4; + + // updatedReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by updateRevision. + optional int32 updatedReplicas = 5; + + // currentRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the + // sequence [0,currentReplicas). + optional string currentRevision = 6; + + // updateRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the sequence + // [replicas-updatedReplicas,replicas) + optional string updateRevision = 7; + + // collisionCount is the count of hash collisions for the StatefulSet. The StatefulSet controller + // uses this field as a collision avoidance mechanism when it needs to create the name for the + // newest ControllerRevision. + // +optional + optional int32 collisionCount = 9; + + // Represents the latest available observations of a statefulset's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated StatefulSetCondition conditions = 10; +} + +// StatefulSetUpdateStrategy indicates the strategy that the StatefulSet +// controller will use to perform updates. It includes any additional parameters +// necessary to perform the update for the indicated strategy. +message StatefulSetUpdateStrategy { + // Type indicates the type of the StatefulSetUpdateStrategy. + // Default is RollingUpdate. + // +optional + optional string type = 1; + + // RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. + // +optional + optional RollingUpdateStatefulSetStrategy rollingUpdate = 2; +} + diff --git a/vendor/k8s.io/api/apps/v1beta1/generated.proto b/vendor/k8s.io/api/apps/v1beta1/generated.proto new file mode 100644 index 000000000..6f41f06bc --- /dev/null +++ b/vendor/k8s.io/api/apps/v1beta1/generated.proto @@ -0,0 +1,483 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.apps.v1beta1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// DEPRECATED - This group version of ControllerRevision is deprecated by apps/v1beta2/ControllerRevision. See the +// release notes for more information. +// ControllerRevision implements an immutable snapshot of state data. Clients +// are responsible for serializing and deserializing the objects that contain +// their internal state. +// Once a ControllerRevision has been successfully created, it can not be updated. +// The API Server will fail validation of all requests that attempt to mutate +// the Data field. ControllerRevisions may, however, be deleted. Note that, due to its use by both +// the DaemonSet and StatefulSet controllers for update and rollback, this object is beta. However, +// it may be subject to name and representation changes in future releases, and clients should not +// depend on its stability. It is primarily for internal use by controllers. +message ControllerRevision { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Data is the serialized representation of the state. + optional k8s.io.apimachinery.pkg.runtime.RawExtension data = 2; + + // Revision indicates the revision of the state represented by Data. + optional int64 revision = 3; +} + +// ControllerRevisionList is a resource containing a list of ControllerRevision objects. +message ControllerRevisionList { + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of ControllerRevisions + repeated ControllerRevision items = 2; +} + +// DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for +// more information. +// Deployment enables declarative updates for Pods and ReplicaSets. +message Deployment { + // Standard object metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the Deployment. + // +optional + optional DeploymentSpec spec = 2; + + // Most recently observed status of the Deployment. + // +optional + optional DeploymentStatus status = 3; +} + +// DeploymentCondition describes the state of a deployment at a certain point. +message DeploymentCondition { + // Type of deployment condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time this condition was updated. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastUpdateTime = 6; + + // Last time the condition transitioned from one status to another. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 7; + + // The reason for the condition's last transition. + optional string reason = 4; + + // A human readable message indicating details about the transition. + optional string message = 5; +} + +// DeploymentList is a list of Deployments. +message DeploymentList { + // Standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of Deployments. + repeated Deployment items = 2; +} + +// DEPRECATED. +// DeploymentRollback stores the information required to rollback a deployment. +message DeploymentRollback { + // Required: This must match the Name of a deployment. + optional string name = 1; + + // The annotations to be updated to a deployment + // +optional + map<string, string> updatedAnnotations = 2; + + // The config of this deployment rollback. + optional RollbackConfig rollbackTo = 3; +} + +// DeploymentSpec is the specification of the desired behavior of the Deployment. +message DeploymentSpec { + // Number of desired pods. This is a pointer to distinguish between explicit + // zero and not specified. Defaults to 1. + // +optional + optional int32 replicas = 1; + + // Label selector for pods. Existing ReplicaSets whose pods are + // selected by this will be the ones affected by this deployment. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template describes the pods that will be created. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // The deployment strategy to use to replace existing pods with new ones. + // +optional + optional DeploymentStrategy strategy = 4; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 5; + + // The number of old ReplicaSets to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 2. + // +optional + optional int32 revisionHistoryLimit = 6; + + // Indicates that the deployment is paused. + // +optional + optional bool paused = 7; + + // DEPRECATED. + // The config this deployment is rolling back to. Will be cleared after rollback is done. + // +optional + optional RollbackConfig rollbackTo = 8; + + // The maximum time in seconds for a deployment to make progress before it + // is considered to be failed. The deployment controller will continue to + // process failed deployments and a condition with a ProgressDeadlineExceeded + // reason will be surfaced in the deployment status. Note that progress will + // not be estimated during the time a deployment is paused. Defaults to 600s. + // +optional + optional int32 progressDeadlineSeconds = 9; +} + +// DeploymentStatus is the most recently observed status of the Deployment. +message DeploymentStatus { + // The generation observed by the deployment controller. + // +optional + optional int64 observedGeneration = 1; + + // Total number of non-terminated pods targeted by this deployment (their labels match the selector). + // +optional + optional int32 replicas = 2; + + // Total number of non-terminated pods targeted by this deployment that have the desired template spec. + // +optional + optional int32 updatedReplicas = 3; + + // Total number of ready pods targeted by this deployment. + // +optional + optional int32 readyReplicas = 7; + + // Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. + // +optional + optional int32 availableReplicas = 4; + + // Total number of unavailable pods targeted by this deployment. This is the total number of + // pods that are still required for the deployment to have 100% available capacity. They may + // either be pods that are running but not yet available or pods that still have not been created. + // +optional + optional int32 unavailableReplicas = 5; + + // Represents the latest available observations of a deployment's current state. + // +patchMergeKey=type + // +patchStrategy=merge + repeated DeploymentCondition conditions = 6; + + // Count of hash collisions for the Deployment. The Deployment controller uses this + // field as a collision avoidance mechanism when it needs to create the name for the + // newest ReplicaSet. + // +optional + optional int32 collisionCount = 8; +} + +// DeploymentStrategy describes how to replace existing pods with new ones. +message DeploymentStrategy { + // Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if DeploymentStrategyType = + // RollingUpdate. + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. + // +optional + optional RollingUpdateDeployment rollingUpdate = 2; +} + +// DEPRECATED. +message RollbackConfig { + // The revision to rollback to. If set to 0, rollback to the last revision. + // +optional + optional int64 revision = 1; +} + +// Spec to control the desired behavior of rolling update. +message RollingUpdateDeployment { + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding down. + // This can not be 0 if MaxSurge is 0. + // Defaults to 25%. + // Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods + // immediately when the rolling update starts. Once new pods are ready, old ReplicaSet + // can be scaled down further, followed by scaling up the new ReplicaSet, ensuring + // that the total number of pods available at all times during the update is at + // least 70% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; + + // The maximum number of pods that can be scheduled above the desired number of + // pods. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // This can not be 0 if MaxUnavailable is 0. + // Absolute number is calculated from percentage by rounding up. + // Defaults to 25%. + // Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when + // the rolling update starts, such that the total number of old and new pods do not exceed + // 130% of desired pods. Once old pods have been killed, + // new ReplicaSet can be scaled up further, ensuring that total number of pods running + // at any time during the update is atmost 130% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxSurge = 2; +} + +// RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. +message RollingUpdateStatefulSetStrategy { + // Partition indicates the ordinal at which the StatefulSet should be + // partitioned. + optional int32 partition = 1; +} + +// Scale represents a scaling request for a resource. +message Scale { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional ScaleSpec spec = 2; + + // current status of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. Read-only. + // +optional + optional ScaleStatus status = 3; +} + +// ScaleSpec describes the attributes of a scale subresource +message ScaleSpec { + // desired number of instances for the scaled object. + // +optional + optional int32 replicas = 1; +} + +// ScaleStatus represents the current status of a scale subresource. +message ScaleStatus { + // actual number of observed instances of the scaled object. + optional int32 replicas = 1; + + // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors + // +optional + map<string, string> selector = 2; + + // label selector for pods that should match the replicas count. This is a serializated + // version of both map-based and more expressive set-based selectors. This is done to + // avoid introspection in the clients. The string will be in the same format as the + // query-param syntax. If the target type only supports map-based selectors, both this + // field and map-based selector field are populated. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional string targetSelector = 3; +} + +// DEPRECATED - This group version of StatefulSet is deprecated by apps/v1beta2/StatefulSet. See the release notes for +// more information. +// StatefulSet represents a set of pods with consistent identities. +// Identities are defined as: +// - Network: A single stable DNS and hostname. +// - Storage: As many VolumeClaims as requested. +// The StatefulSet guarantees that a given network identity will always +// map to the same storage identity. +message StatefulSet { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the desired identities of pods in this set. + // +optional + optional StatefulSetSpec spec = 2; + + // Status is the current status of Pods in this StatefulSet. This data + // may be out of date by some window of time. + // +optional + optional StatefulSetStatus status = 3; +} + +// StatefulSetCondition describes the state of a statefulset at a certain point. +message StatefulSetCondition { + // Type of statefulset condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// StatefulSetList is a collection of StatefulSets. +message StatefulSetList { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + repeated StatefulSet items = 2; +} + +// A StatefulSetSpec is the specification of a StatefulSet. +message StatefulSetSpec { + // replicas is the desired number of replicas of the given Template. + // These are replicas in the sense that they are instantiations of the + // same Template, but individual replicas also have a consistent identity. + // If unspecified, defaults to 1. + // TODO: Consider a rename of this field. + // +optional + optional int32 replicas = 1; + + // selector is a label query over pods that should match the replica count. + // If empty, defaulted to labels on the pod template. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // template is the object that describes the pod that will be created if + // insufficient replicas are detected. Each pod stamped out by the StatefulSet + // will fulfill this Template, but have a unique identity from the rest + // of the StatefulSet. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // volumeClaimTemplates is a list of claims that pods are allowed to reference. + // The StatefulSet controller is responsible for mapping network identities to + // claims in a way that maintains the identity of a pod. Every claim in + // this list must have at least one matching (by name) volumeMount in one + // container in the template. A claim in this list takes precedence over + // any volumes in the template, with the same name. + // TODO: Define the behavior if a claim already exists with the same name. + // +optional + repeated k8s.io.api.core.v1.PersistentVolumeClaim volumeClaimTemplates = 4; + + // serviceName is the name of the service that governs this StatefulSet. + // This service must exist before the StatefulSet, and is responsible for + // the network identity of the set. Pods get DNS/hostnames that follow the + // pattern: pod-specific-string.serviceName.default.svc.cluster.local + // where "pod-specific-string" is managed by the StatefulSet controller. + optional string serviceName = 5; + + // podManagementPolicy controls how pods are created during initial scale up, + // when replacing pods on nodes, or when scaling down. The default policy is + // `OrderedReady`, where pods are created in increasing order (pod-0, then + // pod-1, etc) and the controller will wait until each pod is ready before + // continuing. When scaling down, the pods are removed in the opposite order. + // The alternative policy is `Parallel` which will create pods in parallel + // to match the desired scale without waiting, and on scale down will delete + // all pods at once. + // +optional + optional string podManagementPolicy = 6; + + // updateStrategy indicates the StatefulSetUpdateStrategy that will be + // employed to update Pods in the StatefulSet when a revision is made to + // Template. + optional StatefulSetUpdateStrategy updateStrategy = 7; + + // revisionHistoryLimit is the maximum number of revisions that will + // be maintained in the StatefulSet's revision history. The revision history + // consists of all revisions not represented by a currently applied + // StatefulSetSpec version. The default value is 10. + optional int32 revisionHistoryLimit = 8; +} + +// StatefulSetStatus represents the current state of a StatefulSet. +message StatefulSetStatus { + // observedGeneration is the most recent generation observed for this StatefulSet. It corresponds to the + // StatefulSet's generation, which is updated on mutation by the API Server. + // +optional + optional int64 observedGeneration = 1; + + // replicas is the number of Pods created by the StatefulSet controller. + optional int32 replicas = 2; + + // readyReplicas is the number of Pods created by the StatefulSet controller that have a Ready Condition. + optional int32 readyReplicas = 3; + + // currentReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by currentRevision. + optional int32 currentReplicas = 4; + + // updatedReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by updateRevision. + optional int32 updatedReplicas = 5; + + // currentRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the + // sequence [0,currentReplicas). + optional string currentRevision = 6; + + // updateRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the sequence + // [replicas-updatedReplicas,replicas) + optional string updateRevision = 7; + + // collisionCount is the count of hash collisions for the StatefulSet. The StatefulSet controller + // uses this field as a collision avoidance mechanism when it needs to create the name for the + // newest ControllerRevision. + // +optional + optional int32 collisionCount = 9; + + // Represents the latest available observations of a statefulset's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated StatefulSetCondition conditions = 10; +} + +// StatefulSetUpdateStrategy indicates the strategy that the StatefulSet +// controller will use to perform updates. It includes any additional parameters +// necessary to perform the update for the indicated strategy. +message StatefulSetUpdateStrategy { + // Type indicates the type of the StatefulSetUpdateStrategy. + optional string type = 1; + + // RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. + optional RollingUpdateStatefulSetStrategy rollingUpdate = 2; +} + diff --git a/vendor/k8s.io/api/apps/v1beta2/generated.proto b/vendor/k8s.io/api/apps/v1beta2/generated.proto new file mode 100644 index 000000000..cc3656d28 --- /dev/null +++ b/vendor/k8s.io/api/apps/v1beta2/generated.proto @@ -0,0 +1,751 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.apps.v1beta2; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta2"; + +// DEPRECATED - This group version of ControllerRevision is deprecated by apps/v1/ControllerRevision. See the +// release notes for more information. +// ControllerRevision implements an immutable snapshot of state data. Clients +// are responsible for serializing and deserializing the objects that contain +// their internal state. +// Once a ControllerRevision has been successfully created, it can not be updated. +// The API Server will fail validation of all requests that attempt to mutate +// the Data field. ControllerRevisions may, however, be deleted. Note that, due to its use by both +// the DaemonSet and StatefulSet controllers for update and rollback, this object is beta. However, +// it may be subject to name and representation changes in future releases, and clients should not +// depend on its stability. It is primarily for internal use by controllers. +message ControllerRevision { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Data is the serialized representation of the state. + optional k8s.io.apimachinery.pkg.runtime.RawExtension data = 2; + + // Revision indicates the revision of the state represented by Data. + optional int64 revision = 3; +} + +// ControllerRevisionList is a resource containing a list of ControllerRevision objects. +message ControllerRevisionList { + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of ControllerRevisions + repeated ControllerRevision items = 2; +} + +// DEPRECATED - This group version of DaemonSet is deprecated by apps/v1/DaemonSet. See the release notes for +// more information. +// DaemonSet represents the configuration of a daemon set. +message DaemonSet { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The desired behavior of this daemon set. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional DaemonSetSpec spec = 2; + + // The current status of this daemon set. This data may be + // out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional DaemonSetStatus status = 3; +} + +// DaemonSetCondition describes the state of a DaemonSet at a certain point. +message DaemonSetCondition { + // Type of DaemonSet condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// DaemonSetList is a collection of daemon sets. +message DaemonSetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // A list of daemon sets. + repeated DaemonSet items = 2; +} + +// DaemonSetSpec is the specification of a daemon set. +message DaemonSetSpec { + // A label query over pods that are managed by the daemon set. + // Must match in order to be controlled. + // It must match the pod template's labels. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 1; + + // An object that describes the pod that will be created. + // The DaemonSet will create exactly one copy of this pod on every node + // that matches the template's node selector (or on every node if no node + // selector is specified). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + optional k8s.io.api.core.v1.PodTemplateSpec template = 2; + + // An update strategy to replace existing DaemonSet pods with new pods. + // +optional + optional DaemonSetUpdateStrategy updateStrategy = 3; + + // The minimum number of seconds for which a newly created DaemonSet pod should + // be ready without any of its container crashing, for it to be considered + // available. Defaults to 0 (pod will be considered available as soon as it + // is ready). + // +optional + optional int32 minReadySeconds = 4; + + // The number of old history to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 10. + // +optional + optional int32 revisionHistoryLimit = 6; +} + +// DaemonSetStatus represents the current status of a daemon set. +message DaemonSetStatus { + // The number of nodes that are running at least 1 + // daemon pod and are supposed to run the daemon pod. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 currentNumberScheduled = 1; + + // The number of nodes that are running the daemon pod, but are + // not supposed to run the daemon pod. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 numberMisscheduled = 2; + + // The total number of nodes that should be running the daemon + // pod (including nodes correctly running the daemon pod). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 desiredNumberScheduled = 3; + + // The number of nodes that should be running the daemon pod and have one + // or more of the daemon pod running and ready. + optional int32 numberReady = 4; + + // The most recent generation observed by the daemon set controller. + // +optional + optional int64 observedGeneration = 5; + + // The total number of nodes that are running updated daemon pod + // +optional + optional int32 updatedNumberScheduled = 6; + + // The number of nodes that should be running the + // daemon pod and have one or more of the daemon pod running and + // available (ready for at least spec.minReadySeconds) + // +optional + optional int32 numberAvailable = 7; + + // The number of nodes that should be running the + // daemon pod and have none of the daemon pod running and available + // (ready for at least spec.minReadySeconds) + // +optional + optional int32 numberUnavailable = 8; + + // Count of hash collisions for the DaemonSet. The DaemonSet controller + // uses this field as a collision avoidance mechanism when it needs to + // create the name for the newest ControllerRevision. + // +optional + optional int32 collisionCount = 9; + + // Represents the latest available observations of a DaemonSet's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated DaemonSetCondition conditions = 10; +} + +// DaemonSetUpdateStrategy is a struct used to control the update strategy for a DaemonSet. +message DaemonSetUpdateStrategy { + // Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is RollingUpdate. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if type = "RollingUpdate". + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. Same as Deployment `strategy.rollingUpdate`. + // See https://github.com/kubernetes/kubernetes/issues/35345 + // +optional + optional RollingUpdateDaemonSet rollingUpdate = 2; +} + +// DEPRECATED - This group version of Deployment is deprecated by apps/v1/Deployment. See the release notes for +// more information. +// Deployment enables declarative updates for Pods and ReplicaSets. +message Deployment { + // Standard object metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the Deployment. + // +optional + optional DeploymentSpec spec = 2; + + // Most recently observed status of the Deployment. + // +optional + optional DeploymentStatus status = 3; +} + +// DeploymentCondition describes the state of a deployment at a certain point. +message DeploymentCondition { + // Type of deployment condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time this condition was updated. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastUpdateTime = 6; + + // Last time the condition transitioned from one status to another. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 7; + + // The reason for the condition's last transition. + optional string reason = 4; + + // A human readable message indicating details about the transition. + optional string message = 5; +} + +// DeploymentList is a list of Deployments. +message DeploymentList { + // Standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of Deployments. + repeated Deployment items = 2; +} + +// DeploymentSpec is the specification of the desired behavior of the Deployment. +message DeploymentSpec { + // Number of desired pods. This is a pointer to distinguish between explicit + // zero and not specified. Defaults to 1. + // +optional + optional int32 replicas = 1; + + // Label selector for pods. Existing ReplicaSets whose pods are + // selected by this will be the ones affected by this deployment. + // It must match the pod template's labels. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template describes the pods that will be created. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // The deployment strategy to use to replace existing pods with new ones. + // +optional + optional DeploymentStrategy strategy = 4; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 5; + + // The number of old ReplicaSets to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 10. + // +optional + optional int32 revisionHistoryLimit = 6; + + // Indicates that the deployment is paused. + // +optional + optional bool paused = 7; + + // The maximum time in seconds for a deployment to make progress before it + // is considered to be failed. The deployment controller will continue to + // process failed deployments and a condition with a ProgressDeadlineExceeded + // reason will be surfaced in the deployment status. Note that progress will + // not be estimated during the time a deployment is paused. Defaults to 600s. + optional int32 progressDeadlineSeconds = 9; +} + +// DeploymentStatus is the most recently observed status of the Deployment. +message DeploymentStatus { + // The generation observed by the deployment controller. + // +optional + optional int64 observedGeneration = 1; + + // Total number of non-terminated pods targeted by this deployment (their labels match the selector). + // +optional + optional int32 replicas = 2; + + // Total number of non-terminated pods targeted by this deployment that have the desired template spec. + // +optional + optional int32 updatedReplicas = 3; + + // Total number of ready pods targeted by this deployment. + // +optional + optional int32 readyReplicas = 7; + + // Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. + // +optional + optional int32 availableReplicas = 4; + + // Total number of unavailable pods targeted by this deployment. This is the total number of + // pods that are still required for the deployment to have 100% available capacity. They may + // either be pods that are running but not yet available or pods that still have not been created. + // +optional + optional int32 unavailableReplicas = 5; + + // Represents the latest available observations of a deployment's current state. + // +patchMergeKey=type + // +patchStrategy=merge + repeated DeploymentCondition conditions = 6; + + // Count of hash collisions for the Deployment. The Deployment controller uses this + // field as a collision avoidance mechanism when it needs to create the name for the + // newest ReplicaSet. + // +optional + optional int32 collisionCount = 8; +} + +// DeploymentStrategy describes how to replace existing pods with new ones. +message DeploymentStrategy { + // Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if DeploymentStrategyType = + // RollingUpdate. + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. + // +optional + optional RollingUpdateDeployment rollingUpdate = 2; +} + +// DEPRECATED - This group version of ReplicaSet is deprecated by apps/v1/ReplicaSet. See the release notes for +// more information. +// ReplicaSet ensures that a specified number of pod replicas are running at any given time. +message ReplicaSet { + // If the Labels of a ReplicaSet are empty, they are defaulted to + // be the same as the Pod(s) that the ReplicaSet manages. + // Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the specification of the desired behavior of the ReplicaSet. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicaSetSpec spec = 2; + + // Status is the most recently observed status of the ReplicaSet. + // This data may be out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicaSetStatus status = 3; +} + +// ReplicaSetCondition describes the state of a replica set at a certain point. +message ReplicaSetCondition { + // Type of replica set condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// ReplicaSetList is a collection of ReplicaSets. +message ReplicaSetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of ReplicaSets. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller + repeated ReplicaSet items = 2; +} + +// ReplicaSetSpec is the specification of a ReplicaSet. +message ReplicaSetSpec { + // Replicas is the number of desired replicas. + // This is a pointer to distinguish between explicit zero and unspecified. + // Defaults to 1. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller + // +optional + optional int32 replicas = 1; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 4; + + // Selector is a label query over pods that should match the replica count. + // Label keys and values that must match in order to be controlled by this replica set. + // It must match the pod template's labels. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + // +optional + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; +} + +// ReplicaSetStatus represents the current status of a ReplicaSet. +message ReplicaSetStatus { + // Replicas is the most recently oberved number of replicas. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller + optional int32 replicas = 1; + + // The number of pods that have labels matching the labels of the pod template of the replicaset. + // +optional + optional int32 fullyLabeledReplicas = 2; + + // The number of ready replicas for this replica set. + // +optional + optional int32 readyReplicas = 4; + + // The number of available replicas (ready for at least minReadySeconds) for this replica set. + // +optional + optional int32 availableReplicas = 5; + + // ObservedGeneration reflects the generation of the most recently observed ReplicaSet. + // +optional + optional int64 observedGeneration = 3; + + // Represents the latest available observations of a replica set's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated ReplicaSetCondition conditions = 6; +} + +// Spec to control the desired behavior of daemon set rolling update. +message RollingUpdateDaemonSet { + // The maximum number of DaemonSet pods that can be unavailable during the + // update. Value can be an absolute number (ex: 5) or a percentage of total + // number of DaemonSet pods at the start of the update (ex: 10%). Absolute + // number is calculated from percentage by rounding up. + // This cannot be 0. + // Default value is 1. + // Example: when this is set to 30%, at most 30% of the total number of nodes + // that should be running the daemon pod (i.e. status.desiredNumberScheduled) + // can have their pods stopped for an update at any given + // time. The update starts by stopping at most 30% of those DaemonSet pods + // and then brings up new DaemonSet pods in their place. Once the new pods + // are available, it then proceeds onto other DaemonSet pods, thus ensuring + // that at least 70% of original number of DaemonSet pods are available at + // all times during the update. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; +} + +// Spec to control the desired behavior of rolling update. +message RollingUpdateDeployment { + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding down. + // This can not be 0 if MaxSurge is 0. + // Defaults to 25%. + // Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods + // immediately when the rolling update starts. Once new pods are ready, old ReplicaSet + // can be scaled down further, followed by scaling up the new ReplicaSet, ensuring + // that the total number of pods available at all times during the update is at + // least 70% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; + + // The maximum number of pods that can be scheduled above the desired number of + // pods. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // This can not be 0 if MaxUnavailable is 0. + // Absolute number is calculated from percentage by rounding up. + // Defaults to 25%. + // Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when + // the rolling update starts, such that the total number of old and new pods do not exceed + // 130% of desired pods. Once old pods have been killed, + // new ReplicaSet can be scaled up further, ensuring that total number of pods running + // at any time during the update is atmost 130% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxSurge = 2; +} + +// RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. +message RollingUpdateStatefulSetStrategy { + // Partition indicates the ordinal at which the StatefulSet should be + // partitioned. + // Default value is 0. + // +optional + optional int32 partition = 1; +} + +// Scale represents a scaling request for a resource. +message Scale { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional ScaleSpec spec = 2; + + // current status of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. Read-only. + // +optional + optional ScaleStatus status = 3; +} + +// ScaleSpec describes the attributes of a scale subresource +message ScaleSpec { + // desired number of instances for the scaled object. + // +optional + optional int32 replicas = 1; +} + +// ScaleStatus represents the current status of a scale subresource. +message ScaleStatus { + // actual number of observed instances of the scaled object. + optional int32 replicas = 1; + + // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors + // +optional + map<string, string> selector = 2; + + // label selector for pods that should match the replicas count. This is a serializated + // version of both map-based and more expressive set-based selectors. This is done to + // avoid introspection in the clients. The string will be in the same format as the + // query-param syntax. If the target type only supports map-based selectors, both this + // field and map-based selector field are populated. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional string targetSelector = 3; +} + +// DEPRECATED - This group version of StatefulSet is deprecated by apps/v1/StatefulSet. See the release notes for +// more information. +// StatefulSet represents a set of pods with consistent identities. +// Identities are defined as: +// - Network: A single stable DNS and hostname. +// - Storage: As many VolumeClaims as requested. +// The StatefulSet guarantees that a given network identity will always +// map to the same storage identity. +message StatefulSet { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the desired identities of pods in this set. + // +optional + optional StatefulSetSpec spec = 2; + + // Status is the current status of Pods in this StatefulSet. This data + // may be out of date by some window of time. + // +optional + optional StatefulSetStatus status = 3; +} + +// StatefulSetCondition describes the state of a statefulset at a certain point. +message StatefulSetCondition { + // Type of statefulset condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// StatefulSetList is a collection of StatefulSets. +message StatefulSetList { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + repeated StatefulSet items = 2; +} + +// A StatefulSetSpec is the specification of a StatefulSet. +message StatefulSetSpec { + // replicas is the desired number of replicas of the given Template. + // These are replicas in the sense that they are instantiations of the + // same Template, but individual replicas also have a consistent identity. + // If unspecified, defaults to 1. + // TODO: Consider a rename of this field. + // +optional + optional int32 replicas = 1; + + // selector is a label query over pods that should match the replica count. + // It must match the pod template's labels. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // template is the object that describes the pod that will be created if + // insufficient replicas are detected. Each pod stamped out by the StatefulSet + // will fulfill this Template, but have a unique identity from the rest + // of the StatefulSet. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // volumeClaimTemplates is a list of claims that pods are allowed to reference. + // The StatefulSet controller is responsible for mapping network identities to + // claims in a way that maintains the identity of a pod. Every claim in + // this list must have at least one matching (by name) volumeMount in one + // container in the template. A claim in this list takes precedence over + // any volumes in the template, with the same name. + // TODO: Define the behavior if a claim already exists with the same name. + // +optional + repeated k8s.io.api.core.v1.PersistentVolumeClaim volumeClaimTemplates = 4; + + // serviceName is the name of the service that governs this StatefulSet. + // This service must exist before the StatefulSet, and is responsible for + // the network identity of the set. Pods get DNS/hostnames that follow the + // pattern: pod-specific-string.serviceName.default.svc.cluster.local + // where "pod-specific-string" is managed by the StatefulSet controller. + optional string serviceName = 5; + + // podManagementPolicy controls how pods are created during initial scale up, + // when replacing pods on nodes, or when scaling down. The default policy is + // `OrderedReady`, where pods are created in increasing order (pod-0, then + // pod-1, etc) and the controller will wait until each pod is ready before + // continuing. When scaling down, the pods are removed in the opposite order. + // The alternative policy is `Parallel` which will create pods in parallel + // to match the desired scale without waiting, and on scale down will delete + // all pods at once. + // +optional + optional string podManagementPolicy = 6; + + // updateStrategy indicates the StatefulSetUpdateStrategy that will be + // employed to update Pods in the StatefulSet when a revision is made to + // Template. + optional StatefulSetUpdateStrategy updateStrategy = 7; + + // revisionHistoryLimit is the maximum number of revisions that will + // be maintained in the StatefulSet's revision history. The revision history + // consists of all revisions not represented by a currently applied + // StatefulSetSpec version. The default value is 10. + optional int32 revisionHistoryLimit = 8; +} + +// StatefulSetStatus represents the current state of a StatefulSet. +message StatefulSetStatus { + // observedGeneration is the most recent generation observed for this StatefulSet. It corresponds to the + // StatefulSet's generation, which is updated on mutation by the API Server. + // +optional + optional int64 observedGeneration = 1; + + // replicas is the number of Pods created by the StatefulSet controller. + optional int32 replicas = 2; + + // readyReplicas is the number of Pods created by the StatefulSet controller that have a Ready Condition. + optional int32 readyReplicas = 3; + + // currentReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by currentRevision. + optional int32 currentReplicas = 4; + + // updatedReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version + // indicated by updateRevision. + optional int32 updatedReplicas = 5; + + // currentRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the + // sequence [0,currentReplicas). + optional string currentRevision = 6; + + // updateRevision, if not empty, indicates the version of the StatefulSet used to generate Pods in the sequence + // [replicas-updatedReplicas,replicas) + optional string updateRevision = 7; + + // collisionCount is the count of hash collisions for the StatefulSet. The StatefulSet controller + // uses this field as a collision avoidance mechanism when it needs to create the name for the + // newest ControllerRevision. + // +optional + optional int32 collisionCount = 9; + + // Represents the latest available observations of a statefulset's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated StatefulSetCondition conditions = 10; +} + +// StatefulSetUpdateStrategy indicates the strategy that the StatefulSet +// controller will use to perform updates. It includes any additional parameters +// necessary to perform the update for the indicated strategy. +message StatefulSetUpdateStrategy { + // Type indicates the type of the StatefulSetUpdateStrategy. + // Default is RollingUpdate. + // +optional + optional string type = 1; + + // RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType. + // +optional + optional RollingUpdateStatefulSetStrategy rollingUpdate = 2; +} + diff --git a/vendor/k8s.io/api/authentication/OWNERS b/vendor/k8s.io/api/authentication/OWNERS new file mode 100755 index 000000000..2bdfd0ce5 --- /dev/null +++ b/vendor/k8s.io/api/authentication/OWNERS @@ -0,0 +1,9 @@ +reviewers: +- liggitt +- lavalamp +- wojtek-t +- deads2k +- sttts +- mbohlool +- jianhuiz +- enj diff --git a/vendor/k8s.io/api/authentication/v1/generated.proto b/vendor/k8s.io/api/authentication/v1/generated.proto new file mode 100644 index 000000000..10c792171 --- /dev/null +++ b/vendor/k8s.io/api/authentication/v1/generated.proto @@ -0,0 +1,159 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.authentication.v1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// BoundObjectReference is a reference to an object that a token is bound to. +message BoundObjectReference { + // Kind of the referent. Valid kinds are 'Pod' and 'Secret'. + // +optional + optional string kind = 1; + + // API version of the referent. + // +optional + optional string aPIVersion = 2; + + // Name of the referent. + // +optional + optional string name = 3; + + // UID of the referent. + // +optional + optional string uID = 4; +} + +// ExtraValue masks the value so protobuf can generate +// +protobuf.nullable=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +message ExtraValue { + // items, if empty, will result in an empty slice + + repeated string items = 1; +} + +// TokenRequest requests a token for a given service account. +message TokenRequest { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + optional TokenRequestSpec spec = 2; + + // +optional + optional TokenRequestStatus status = 3; +} + +// TokenRequestSpec contains client provided parameters of a token request. +message TokenRequestSpec { + // Audiences are the intendend audiences of the token. A recipient of a + // token must identitfy themself with an identifier in the list of + // audiences of the token, and otherwise should reject the token. A + // token issued for multiple audiences may be used to authenticate + // against any of the audiences listed but implies a high degree of + // trust between the target audiences. + repeated string audiences = 1; + + // ExpirationSeconds is the requested duration of validity of the request. The + // token issuer may return a token with a different validity duration so a + // client needs to check the 'expiration' field in a response. + // +optional + optional int64 expirationSeconds = 4; + + // BoundObjectRef is a reference to an object that the token will be bound to. + // The token will only be valid for as long as the bound objet exists. + // +optional + optional BoundObjectReference boundObjectRef = 3; +} + +// TokenRequestStatus is the result of a token request. +message TokenRequestStatus { + // Token is the opaque bearer token. + optional string token = 1; + + // ExpirationTimestamp is the time of expiration of the returned token. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time expirationTimestamp = 2; +} + +// TokenReview attempts to authenticate a token to a known user. +// Note: TokenReview requests may be cached by the webhook token authenticator +// plugin in the kube-apiserver. +message TokenReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated + optional TokenReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request can be authenticated. + // +optional + optional TokenReviewStatus status = 3; +} + +// TokenReviewSpec is a description of the token authentication request. +message TokenReviewSpec { + // Token is the opaque bearer token. + // +optional + optional string token = 1; +} + +// TokenReviewStatus is the result of the token authentication request. +message TokenReviewStatus { + // Authenticated indicates that the token was associated with a known user. + // +optional + optional bool authenticated = 1; + + // User is the UserInfo associated with the provided token. + // +optional + optional UserInfo user = 2; + + // Error indicates that the token couldn't be checked + // +optional + optional string error = 3; +} + +// UserInfo holds the information about the user needed to implement the +// user.Info interface. +message UserInfo { + // The name that uniquely identifies this user among all active users. + // +optional + optional string username = 1; + + // A unique value that identifies this user across time. If this user is + // deleted and another user by the same name is added, they will have + // different UIDs. + // +optional + optional string uid = 2; + + // The names of groups this user is a part of. + // +optional + repeated string groups = 3; + + // Any additional information provided by the authenticator. + // +optional + map<string, ExtraValue> extra = 4; +} + diff --git a/vendor/k8s.io/api/authentication/v1beta1/generated.proto b/vendor/k8s.io/api/authentication/v1beta1/generated.proto new file mode 100644 index 000000000..a057bc591 --- /dev/null +++ b/vendor/k8s.io/api/authentication/v1beta1/generated.proto @@ -0,0 +1,98 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.authentication.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// ExtraValue masks the value so protobuf can generate +// +protobuf.nullable=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +message ExtraValue { + // items, if empty, will result in an empty slice + + repeated string items = 1; +} + +// TokenReview attempts to authenticate a token to a known user. +// Note: TokenReview requests may be cached by the webhook token authenticator +// plugin in the kube-apiserver. +message TokenReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated + optional TokenReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request can be authenticated. + // +optional + optional TokenReviewStatus status = 3; +} + +// TokenReviewSpec is a description of the token authentication request. +message TokenReviewSpec { + // Token is the opaque bearer token. + // +optional + optional string token = 1; +} + +// TokenReviewStatus is the result of the token authentication request. +message TokenReviewStatus { + // Authenticated indicates that the token was associated with a known user. + // +optional + optional bool authenticated = 1; + + // User is the UserInfo associated with the provided token. + // +optional + optional UserInfo user = 2; + + // Error indicates that the token couldn't be checked + // +optional + optional string error = 3; +} + +// UserInfo holds the information about the user needed to implement the +// user.Info interface. +message UserInfo { + // The name that uniquely identifies this user among all active users. + // +optional + optional string username = 1; + + // A unique value that identifies this user across time. If this user is + // deleted and another user by the same name is added, they will have + // different UIDs. + // +optional + optional string uid = 2; + + // The names of groups this user is a part of. + // +optional + repeated string groups = 3; + + // Any additional information provided by the authenticator. + // +optional + map<string, ExtraValue> extra = 4; +} + diff --git a/vendor/k8s.io/api/authorization/OWNERS b/vendor/k8s.io/api/authorization/OWNERS new file mode 100755 index 000000000..c1613fc2e --- /dev/null +++ b/vendor/k8s.io/api/authorization/OWNERS @@ -0,0 +1,17 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- liggitt +- nikhiljindal +- erictune +- sttts +- ncdc +- dims +- mml +- mbohlool +- david-mcmahon +- jianhuiz +- enj diff --git a/vendor/k8s.io/api/authorization/v1/generated.proto b/vendor/k8s.io/api/authorization/v1/generated.proto new file mode 100644 index 000000000..f68a04e49 --- /dev/null +++ b/vendor/k8s.io/api/authorization/v1/generated.proto @@ -0,0 +1,272 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.authorization.v1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// ExtraValue masks the value so protobuf can generate +// +protobuf.nullable=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +message ExtraValue { + // items, if empty, will result in an empty slice + + repeated string items = 1; +} + +// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. +// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions +// checking. +message LocalSubjectAccessReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace + // you made the request against. If empty, it is defaulted. + optional SubjectAccessReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request is allowed or not + // +optional + optional SubjectAccessReviewStatus status = 3; +} + +// NonResourceAttributes includes the authorization attributes available for non-resource requests to the Authorizer interface +message NonResourceAttributes { + // Path is the URL path of the request + // +optional + optional string path = 1; + + // Verb is the standard HTTP verb + // +optional + optional string verb = 2; +} + +// NonResourceRule holds information that describes a rule for the non-resource +message NonResourceRule { + // Verb is a list of kubernetes non-resource API verbs, like: get, post, put, delete, patch, head, options. "*" means all. + repeated string verbs = 1; + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, + // final step in the path. "*" means all. + // +optional + repeated string nonResourceURLs = 2; +} + +// ResourceAttributes includes the authorization attributes available for resource requests to the Authorizer interface +message ResourceAttributes { + // Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces + // "" (empty) is defaulted for LocalSubjectAccessReviews + // "" (empty) is empty for cluster-scoped resources + // "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview + // +optional + optional string namespace = 1; + + // Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy. "*" means all. + // +optional + optional string verb = 2; + + // Group is the API Group of the Resource. "*" means all. + // +optional + optional string group = 3; + + // Version is the API Version of the Resource. "*" means all. + // +optional + optional string version = 4; + + // Resource is one of the existing resource types. "*" means all. + // +optional + optional string resource = 5; + + // Subresource is one of the existing resource types. "" means none. + // +optional + optional string subresource = 6; + + // Name is the name of the resource being requested for a "get" or deleted for a "delete". "" (empty) means all. + // +optional + optional string name = 7; +} + +// ResourceRule is the list of actions the subject is allowed to perform on resources. The list ordering isn't significant, +// may contain duplicates, and possibly be incomplete. +message ResourceRule { + // Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. "*" means all. + repeated string verbs = 1; + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. "*" means all. + // +optional + repeated string apiGroups = 2; + + // Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups. + // "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups. + // +optional + repeated string resources = 3; + + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all. + // +optional + repeated string resourceNames = 4; +} + +// SelfSubjectAccessReview checks whether or the current user can perform an action. Not filling in a +// spec.namespace means "in all namespaces". Self is a special case, because users should always be able +// to check whether they can perform an action +message SelfSubjectAccessReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated. user and groups must be empty + optional SelfSubjectAccessReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request is allowed or not + // +optional + optional SubjectAccessReviewStatus status = 3; +} + +// SelfSubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes +// and NonResourceAuthorizationAttributes must be set +message SelfSubjectAccessReviewSpec { + // ResourceAuthorizationAttributes describes information for a resource access request + // +optional + optional ResourceAttributes resourceAttributes = 1; + + // NonResourceAttributes describes information for a non-resource access request + // +optional + optional NonResourceAttributes nonResourceAttributes = 2; +} + +// SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. +// The returned list of actions may be incomplete depending on the server's authorization mode, +// and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions, +// or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to +// drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns. +// SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server. +message SelfSubjectRulesReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated. + optional SelfSubjectRulesReviewSpec spec = 2; + + // Status is filled in by the server and indicates the set of actions a user can perform. + // +optional + optional SubjectRulesReviewStatus status = 3; +} + +message SelfSubjectRulesReviewSpec { + // Namespace to evaluate rules for. Required. + optional string namespace = 1; +} + +// SubjectAccessReview checks whether or not a user or group can perform an action. +message SubjectAccessReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated + optional SubjectAccessReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request is allowed or not + // +optional + optional SubjectAccessReviewStatus status = 3; +} + +// SubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes +// and NonResourceAuthorizationAttributes must be set +message SubjectAccessReviewSpec { + // ResourceAuthorizationAttributes describes information for a resource access request + // +optional + optional ResourceAttributes resourceAttributes = 1; + + // NonResourceAttributes describes information for a non-resource access request + // +optional + optional NonResourceAttributes nonResourceAttributes = 2; + + // User is the user you're testing for. + // If you specify "User" but not "Groups", then is it interpreted as "What if User were not a member of any groups + // +optional + optional string user = 3; + + // Groups is the groups you're testing for. + // +optional + repeated string groups = 4; + + // Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer + // it needs a reflection here. + // +optional + map<string, ExtraValue> extra = 5; + + // UID information about the requesting user. + // +optional + optional string uid = 6; +} + +// SubjectAccessReviewStatus +message SubjectAccessReviewStatus { + // Allowed is required. True if the action would be allowed, false otherwise. + optional bool allowed = 1; + + // Denied is optional. True if the action would be denied, otherwise + // false. If both allowed is false and denied is false, then the + // authorizer has no opinion on whether to authorize the action. Denied + // may not be true if Allowed is true. + // +optional + optional bool denied = 4; + + // Reason is optional. It indicates why a request was allowed or denied. + // +optional + optional string reason = 2; + + // EvaluationError is an indication that some error occurred during the authorization check. + // It is entirely possible to get an error and be able to continue determine authorization status in spite of it. + // For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request. + // +optional + optional string evaluationError = 3; +} + +// SubjectRulesReviewStatus contains the result of a rules check. This check can be incomplete depending on +// the set of authorizers the server is configured with and any errors experienced during evaluation. +// Because authorization rules are additive, if a rule appears in a list it's safe to assume the subject has that permission, +// even if that list is incomplete. +message SubjectRulesReviewStatus { + // ResourceRules is the list of actions the subject is allowed to perform on resources. + // The list ordering isn't significant, may contain duplicates, and possibly be incomplete. + repeated ResourceRule resourceRules = 1; + + // NonResourceRules is the list of actions the subject is allowed to perform on non-resources. + // The list ordering isn't significant, may contain duplicates, and possibly be incomplete. + repeated NonResourceRule nonResourceRules = 2; + + // Incomplete is true when the rules returned by this call are incomplete. This is most commonly + // encountered when an authorizer, such as an external authorizer, doesn't support rules evaluation. + optional bool incomplete = 3; + + // EvaluationError can appear in combination with Rules. It indicates an error occurred during + // rule evaluation, such as an authorizer that doesn't support rule evaluation, and that + // ResourceRules and/or NonResourceRules may be incomplete. + // +optional + optional string evaluationError = 4; +} + diff --git a/vendor/k8s.io/api/authorization/v1beta1/generated.proto b/vendor/k8s.io/api/authorization/v1beta1/generated.proto new file mode 100644 index 000000000..3876a3eeb --- /dev/null +++ b/vendor/k8s.io/api/authorization/v1beta1/generated.proto @@ -0,0 +1,272 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.authorization.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// ExtraValue masks the value so protobuf can generate +// +protobuf.nullable=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +message ExtraValue { + // items, if empty, will result in an empty slice + + repeated string items = 1; +} + +// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. +// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions +// checking. +message LocalSubjectAccessReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated. spec.namespace must be equal to the namespace + // you made the request against. If empty, it is defaulted. + optional SubjectAccessReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request is allowed or not + // +optional + optional SubjectAccessReviewStatus status = 3; +} + +// NonResourceAttributes includes the authorization attributes available for non-resource requests to the Authorizer interface +message NonResourceAttributes { + // Path is the URL path of the request + // +optional + optional string path = 1; + + // Verb is the standard HTTP verb + // +optional + optional string verb = 2; +} + +// NonResourceRule holds information that describes a rule for the non-resource +message NonResourceRule { + // Verb is a list of kubernetes non-resource API verbs, like: get, post, put, delete, patch, head, options. "*" means all. + repeated string verbs = 1; + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, + // final step in the path. "*" means all. + // +optional + repeated string nonResourceURLs = 2; +} + +// ResourceAttributes includes the authorization attributes available for resource requests to the Authorizer interface +message ResourceAttributes { + // Namespace is the namespace of the action being requested. Currently, there is no distinction between no namespace and all namespaces + // "" (empty) is defaulted for LocalSubjectAccessReviews + // "" (empty) is empty for cluster-scoped resources + // "" (empty) means "all" for namespace scoped resources from a SubjectAccessReview or SelfSubjectAccessReview + // +optional + optional string namespace = 1; + + // Verb is a kubernetes resource API verb, like: get, list, watch, create, update, delete, proxy. "*" means all. + // +optional + optional string verb = 2; + + // Group is the API Group of the Resource. "*" means all. + // +optional + optional string group = 3; + + // Version is the API Version of the Resource. "*" means all. + // +optional + optional string version = 4; + + // Resource is one of the existing resource types. "*" means all. + // +optional + optional string resource = 5; + + // Subresource is one of the existing resource types. "" means none. + // +optional + optional string subresource = 6; + + // Name is the name of the resource being requested for a "get" or deleted for a "delete". "" (empty) means all. + // +optional + optional string name = 7; +} + +// ResourceRule is the list of actions the subject is allowed to perform on resources. The list ordering isn't significant, +// may contain duplicates, and possibly be incomplete. +message ResourceRule { + // Verb is a list of kubernetes resource API verbs, like: get, list, watch, create, update, delete, proxy. "*" means all. + repeated string verbs = 1; + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. "*" means all. + // +optional + repeated string apiGroups = 2; + + // Resources is a list of resources this rule applies to. "*" means all in the specified apiGroups. + // "*/foo" represents the subresource 'foo' for all resources in the specified apiGroups. + // +optional + repeated string resources = 3; + + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. "*" means all. + // +optional + repeated string resourceNames = 4; +} + +// SelfSubjectAccessReview checks whether or the current user can perform an action. Not filling in a +// spec.namespace means "in all namespaces". Self is a special case, because users should always be able +// to check whether they can perform an action +message SelfSubjectAccessReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated. user and groups must be empty + optional SelfSubjectAccessReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request is allowed or not + // +optional + optional SubjectAccessReviewStatus status = 3; +} + +// SelfSubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes +// and NonResourceAuthorizationAttributes must be set +message SelfSubjectAccessReviewSpec { + // ResourceAuthorizationAttributes describes information for a resource access request + // +optional + optional ResourceAttributes resourceAttributes = 1; + + // NonResourceAttributes describes information for a non-resource access request + // +optional + optional NonResourceAttributes nonResourceAttributes = 2; +} + +// SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. +// The returned list of actions may be incomplete depending on the server's authorization mode, +// and any errors experienced during the evaluation. SelfSubjectRulesReview should be used by UIs to show/hide actions, +// or to quickly let an end user reason about their permissions. It should NOT Be used by external systems to +// drive authorization decisions as this raises confused deputy, cache lifetime/revocation, and correctness concerns. +// SubjectAccessReview, and LocalAccessReview are the correct way to defer authorization decisions to the API server. +message SelfSubjectRulesReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated. + optional SelfSubjectRulesReviewSpec spec = 2; + + // Status is filled in by the server and indicates the set of actions a user can perform. + // +optional + optional SubjectRulesReviewStatus status = 3; +} + +message SelfSubjectRulesReviewSpec { + // Namespace to evaluate rules for. Required. + optional string namespace = 1; +} + +// SubjectAccessReview checks whether or not a user or group can perform an action. +message SubjectAccessReview { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec holds information about the request being evaluated + optional SubjectAccessReviewSpec spec = 2; + + // Status is filled in by the server and indicates whether the request is allowed or not + // +optional + optional SubjectAccessReviewStatus status = 3; +} + +// SubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes +// and NonResourceAuthorizationAttributes must be set +message SubjectAccessReviewSpec { + // ResourceAuthorizationAttributes describes information for a resource access request + // +optional + optional ResourceAttributes resourceAttributes = 1; + + // NonResourceAttributes describes information for a non-resource access request + // +optional + optional NonResourceAttributes nonResourceAttributes = 2; + + // User is the user you're testing for. + // If you specify "User" but not "Group", then is it interpreted as "What if User were not a member of any groups + // +optional + optional string user = 3; + + // Groups is the groups you're testing for. + // +optional + repeated string group = 4; + + // Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer + // it needs a reflection here. + // +optional + map<string, ExtraValue> extra = 5; + + // UID information about the requesting user. + // +optional + optional string uid = 6; +} + +// SubjectAccessReviewStatus +message SubjectAccessReviewStatus { + // Allowed is required. True if the action would be allowed, false otherwise. + optional bool allowed = 1; + + // Denied is optional. True if the action would be denied, otherwise + // false. If both allowed is false and denied is false, then the + // authorizer has no opinion on whether to authorize the action. Denied + // may not be true if Allowed is true. + // +optional + optional bool denied = 4; + + // Reason is optional. It indicates why a request was allowed or denied. + // +optional + optional string reason = 2; + + // EvaluationError is an indication that some error occurred during the authorization check. + // It is entirely possible to get an error and be able to continue determine authorization status in spite of it. + // For instance, RBAC can be missing a role, but enough roles are still present and bound to reason about the request. + // +optional + optional string evaluationError = 3; +} + +// SubjectRulesReviewStatus contains the result of a rules check. This check can be incomplete depending on +// the set of authorizers the server is configured with and any errors experienced during evaluation. +// Because authorization rules are additive, if a rule appears in a list it's safe to assume the subject has that permission, +// even if that list is incomplete. +message SubjectRulesReviewStatus { + // ResourceRules is the list of actions the subject is allowed to perform on resources. + // The list ordering isn't significant, may contain duplicates, and possibly be incomplete. + repeated ResourceRule resourceRules = 1; + + // NonResourceRules is the list of actions the subject is allowed to perform on non-resources. + // The list ordering isn't significant, may contain duplicates, and possibly be incomplete. + repeated NonResourceRule nonResourceRules = 2; + + // Incomplete is true when the rules returned by this call are incomplete. This is most commonly + // encountered when an authorizer, such as an external authorizer, doesn't support rules evaluation. + optional bool incomplete = 3; + + // EvaluationError can appear in combination with Rules. It indicates an error occurred during + // rule evaluation, such as an authorizer that doesn't support rule evaluation, and that + // ResourceRules and/or NonResourceRules may be incomplete. + // +optional + optional string evaluationError = 4; +} + diff --git a/vendor/k8s.io/api/autoscaling/OWNERS b/vendor/k8s.io/api/autoscaling/OWNERS new file mode 100755 index 000000000..4a495ec25 --- /dev/null +++ b/vendor/k8s.io/api/autoscaling/OWNERS @@ -0,0 +1,19 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- caesarxuchao +- erictune +- sttts +- ncdc +- piosz +- dims +- errordeveloper +- madhusudancs +- mml +- mbohlool +- david-mcmahon +- jianhuiz +- directxman12 diff --git a/vendor/k8s.io/api/autoscaling/v1/generated.proto b/vendor/k8s.io/api/autoscaling/v1/generated.proto new file mode 100644 index 000000000..5b56b2ac8 --- /dev/null +++ b/vendor/k8s.io/api/autoscaling/v1/generated.proto @@ -0,0 +1,415 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.autoscaling.v1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/api/resource/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// CrossVersionObjectReference contains enough information to let you identify the referred resource. +message CrossVersionObjectReference { + // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds" + optional string kind = 1; + + // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names + optional string name = 2; + + // API version of the referent + // +optional + optional string apiVersion = 3; +} + +// ExternalMetricSource indicates how to scale on a metric not associated with +// any Kubernetes object (for example length of queue in cloud +// messaging service, or QPS from loadbalancer running outside of cluster). +message ExternalMetricSource { + // metricName is the name of the metric in question. + optional string metricName = 1; + + // metricSelector is used to identify a specific time series + // within a given metric. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector metricSelector = 2; + + // targetValue is the target value of the metric (as a quantity). + // Mutually exclusive with TargetAverageValue. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetValue = 3; + + // targetAverageValue is the target per-pod value of global metric (as a quantity). + // Mutually exclusive with TargetValue. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 4; +} + +// ExternalMetricStatus indicates the current value of a global metric +// not associated with any Kubernetes object. +message ExternalMetricStatus { + // metricName is the name of a metric used for autoscaling in + // metric system. + optional string metricName = 1; + + // metricSelector is used to identify a specific time series + // within a given metric. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector metricSelector = 2; + + // currentValue is the current value of the metric (as a quantity) + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentValue = 3; + + // currentAverageValue is the current value of metric averaged over autoscaled pods. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 4; +} + +// configuration of a horizontal pod autoscaler. +message HorizontalPodAutoscaler { + // Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // behaviour of autoscaler. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional HorizontalPodAutoscalerSpec spec = 2; + + // current information about the autoscaler. + // +optional + optional HorizontalPodAutoscalerStatus status = 3; +} + +// HorizontalPodAutoscalerCondition describes the state of +// a HorizontalPodAutoscaler at a certain point. +message HorizontalPodAutoscalerCondition { + // type describes the current condition + optional string type = 1; + + // status is the status of the condition (True, False, Unknown) + optional string status = 2; + + // lastTransitionTime is the last time the condition transitioned from + // one status to another + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // reason is the reason for the condition's last transition. + // +optional + optional string reason = 4; + + // message is a human-readable explanation containing details about + // the transition + // +optional + optional string message = 5; +} + +// list of horizontal pod autoscaler objects. +message HorizontalPodAutoscalerList { + // Standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // list of horizontal pod autoscaler objects. + repeated HorizontalPodAutoscaler items = 2; +} + +// specification of a horizontal pod autoscaler. +message HorizontalPodAutoscalerSpec { + // reference to scaled resource; horizontal pod autoscaler will learn the current resource consumption + // and will set the desired number of pods by using its Scale subresource. + optional CrossVersionObjectReference scaleTargetRef = 1; + + // lower limit for the number of pods that can be set by the autoscaler, default 1. + // +optional + optional int32 minReplicas = 2; + + // upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas. + optional int32 maxReplicas = 3; + + // target average CPU utilization (represented as a percentage of requested CPU) over all the pods; + // if not specified the default autoscaling policy will be used. + // +optional + optional int32 targetCPUUtilizationPercentage = 4; +} + +// current status of a horizontal pod autoscaler +message HorizontalPodAutoscalerStatus { + // most recent generation observed by this autoscaler. + // +optional + optional int64 observedGeneration = 1; + + // last time the HorizontalPodAutoscaler scaled the number of pods; + // used by the autoscaler to control how often the number of pods is changed. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastScaleTime = 2; + + // current number of replicas of pods managed by this autoscaler. + optional int32 currentReplicas = 3; + + // desired number of replicas of pods managed by this autoscaler. + optional int32 desiredReplicas = 4; + + // current average CPU utilization over all pods, represented as a percentage of requested CPU, + // e.g. 70 means that an average pod is using now 70% of its requested CPU. + // +optional + optional int32 currentCPUUtilizationPercentage = 5; +} + +// MetricSpec specifies how to scale based on a single metric +// (only `type` and one other matching field should be set at once). +message MetricSpec { + // type is the type of metric source. It should be one of "Object", + // "Pods" or "Resource", each mapping to a matching field in the object. + optional string type = 1; + + // object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + optional ObjectMetricSource object = 2; + + // pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + optional PodsMetricSource pods = 3; + + // resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ResourceMetricSource resource = 4; + + // external refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + optional ExternalMetricSource external = 5; +} + +// MetricStatus describes the last-read state of a single metric. +message MetricStatus { + // type is the type of metric source. It will be one of "Object", + // "Pods" or "Resource", each corresponds to a matching field in the object. + optional string type = 1; + + // object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + optional ObjectMetricStatus object = 2; + + // pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + optional PodsMetricStatus pods = 3; + + // resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ResourceMetricStatus resource = 4; + + // external refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + optional ExternalMetricStatus external = 5; +} + +// ObjectMetricSource indicates how to scale on a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +message ObjectMetricSource { + // target is the described Kubernetes object. + optional CrossVersionObjectReference target = 1; + + // metricName is the name of the metric in question. + optional string metricName = 2; + + // targetValue is the target value of the metric (as a quantity). + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetValue = 3; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric. + // When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 4; + + // averageValue is the target value of the average of the + // metric across all relevant pods (as a quantity) + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity averageValue = 5; +} + +// ObjectMetricStatus indicates the current value of a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +message ObjectMetricStatus { + // target is the described Kubernetes object. + optional CrossVersionObjectReference target = 1; + + // metricName is the name of the metric in question. + optional string metricName = 2; + + // currentValue is the current value of the metric (as a quantity). + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentValue = 3; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set in the ObjectMetricSource, it is passed as an additional parameter to the metrics server for more specific metrics scoping. + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 4; + + // averageValue is the current value of the average of the + // metric across all relevant pods (as a quantity) + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity averageValue = 5; +} + +// PodsMetricSource indicates how to scale on a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +// The values will be averaged together before being compared to the target +// value. +message PodsMetricSource { + // metricName is the name of the metric in question + optional string metricName = 1; + + // targetAverageValue is the target value of the average of the + // metric across all relevant pods (as a quantity) + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 2; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 3; +} + +// PodsMetricStatus indicates the current value of a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +message PodsMetricStatus { + // metricName is the name of the metric in question + optional string metricName = 1; + + // currentAverageValue is the current value of the average of the + // metric across all relevant pods (as a quantity) + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 2; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set in the PodsMetricSource, it is passed as an additional parameter to the metrics server for more specific metrics scoping. + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 3; +} + +// ResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +message ResourceMetricSource { + // name is the name of the resource in question. + optional string name = 1; + + // targetAverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + optional int32 targetAverageUtilization = 2; + + // targetAverageValue is the target value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 3; +} + +// ResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +message ResourceMetricStatus { + // name is the name of the resource in question. + optional string name = 1; + + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. It will only be + // present if `targetAverageValue` was set in the corresponding metric + // specification. + // +optional + optional int32 currentAverageUtilization = 2; + + // currentAverageValue is the current value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // It will always be set, regardless of the corresponding metric specification. + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 3; +} + +// Scale represents a scaling request for a resource. +message Scale { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional ScaleSpec spec = 2; + + // current status of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. Read-only. + // +optional + optional ScaleStatus status = 3; +} + +// ScaleSpec describes the attributes of a scale subresource. +message ScaleSpec { + // desired number of instances for the scaled object. + // +optional + optional int32 replicas = 1; +} + +// ScaleStatus represents the current status of a scale subresource. +message ScaleStatus { + // actual number of observed instances of the scaled object. + optional int32 replicas = 1; + + // label query over pods that should match the replicas count. This is same + // as the label selector but in the string format to avoid introspection + // by clients. The string will be in the same format as the query-param syntax. + // More info about label selectors: http://kubernetes.io/docs/user-guide/labels#label-selectors + // +optional + optional string selector = 2; +} + diff --git a/vendor/k8s.io/api/autoscaling/v2beta1/generated.proto b/vendor/k8s.io/api/autoscaling/v2beta1/generated.proto new file mode 100644 index 000000000..04bc0ed60 --- /dev/null +++ b/vendor/k8s.io/api/autoscaling/v2beta1/generated.proto @@ -0,0 +1,397 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.autoscaling.v2beta1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/api/resource/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v2beta1"; + +// CrossVersionObjectReference contains enough information to let you identify the referred resource. +message CrossVersionObjectReference { + // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds" + optional string kind = 1; + + // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names + optional string name = 2; + + // API version of the referent + // +optional + optional string apiVersion = 3; +} + +// ExternalMetricSource indicates how to scale on a metric not associated with +// any Kubernetes object (for example length of queue in cloud +// messaging service, or QPS from loadbalancer running outside of cluster). +// Exactly one "target" type should be set. +message ExternalMetricSource { + // metricName is the name of the metric in question. + optional string metricName = 1; + + // metricSelector is used to identify a specific time series + // within a given metric. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector metricSelector = 2; + + // targetValue is the target value of the metric (as a quantity). + // Mutually exclusive with TargetAverageValue. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetValue = 3; + + // targetAverageValue is the target per-pod value of global metric (as a quantity). + // Mutually exclusive with TargetValue. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 4; +} + +// ExternalMetricStatus indicates the current value of a global metric +// not associated with any Kubernetes object. +message ExternalMetricStatus { + // metricName is the name of a metric used for autoscaling in + // metric system. + optional string metricName = 1; + + // metricSelector is used to identify a specific time series + // within a given metric. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector metricSelector = 2; + + // currentValue is the current value of the metric (as a quantity) + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentValue = 3; + + // currentAverageValue is the current value of metric averaged over autoscaled pods. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 4; +} + +// HorizontalPodAutoscaler is the configuration for a horizontal pod +// autoscaler, which automatically manages the replica count of any resource +// implementing the scale subresource based on the metrics specified. +message HorizontalPodAutoscaler { + // metadata is the standard object metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // spec is the specification for the behaviour of the autoscaler. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional HorizontalPodAutoscalerSpec spec = 2; + + // status is the current information about the autoscaler. + // +optional + optional HorizontalPodAutoscalerStatus status = 3; +} + +// HorizontalPodAutoscalerCondition describes the state of +// a HorizontalPodAutoscaler at a certain point. +message HorizontalPodAutoscalerCondition { + // type describes the current condition + optional string type = 1; + + // status is the status of the condition (True, False, Unknown) + optional string status = 2; + + // lastTransitionTime is the last time the condition transitioned from + // one status to another + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // reason is the reason for the condition's last transition. + // +optional + optional string reason = 4; + + // message is a human-readable explanation containing details about + // the transition + // +optional + optional string message = 5; +} + +// HorizontalPodAutoscaler is a list of horizontal pod autoscaler objects. +message HorizontalPodAutoscalerList { + // metadata is the standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of horizontal pod autoscaler objects. + repeated HorizontalPodAutoscaler items = 2; +} + +// HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler. +message HorizontalPodAutoscalerSpec { + // scaleTargetRef points to the target resource to scale, and is used to the pods for which metrics + // should be collected, as well as to actually change the replica count. + optional CrossVersionObjectReference scaleTargetRef = 1; + + // minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. + // It defaults to 1 pod. + // +optional + optional int32 minReplicas = 2; + + // maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. + // It cannot be less that minReplicas. + optional int32 maxReplicas = 3; + + // metrics contains the specifications for which to use to calculate the + // desired replica count (the maximum replica count across all metrics will + // be used). The desired replica count is calculated multiplying the + // ratio between the target value and the current value by the current + // number of pods. Ergo, metrics used must decrease as the pod count is + // increased, and vice-versa. See the individual metric source types for + // more information about how each type of metric must respond. + // +optional + repeated MetricSpec metrics = 4; +} + +// HorizontalPodAutoscalerStatus describes the current status of a horizontal pod autoscaler. +message HorizontalPodAutoscalerStatus { + // observedGeneration is the most recent generation observed by this autoscaler. + // +optional + optional int64 observedGeneration = 1; + + // lastScaleTime is the last time the HorizontalPodAutoscaler scaled the number of pods, + // used by the autoscaler to control how often the number of pods is changed. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastScaleTime = 2; + + // currentReplicas is current number of replicas of pods managed by this autoscaler, + // as last seen by the autoscaler. + optional int32 currentReplicas = 3; + + // desiredReplicas is the desired number of replicas of pods managed by this autoscaler, + // as last calculated by the autoscaler. + optional int32 desiredReplicas = 4; + + // currentMetrics is the last read state of the metrics used by this autoscaler. + // +optional + repeated MetricStatus currentMetrics = 5; + + // conditions is the set of conditions required for this autoscaler to scale its target, + // and indicates whether or not those conditions are met. + repeated HorizontalPodAutoscalerCondition conditions = 6; +} + +// MetricSpec specifies how to scale based on a single metric +// (only `type` and one other matching field should be set at once). +message MetricSpec { + // type is the type of metric source. It should be one of "Object", + // "Pods" or "Resource", each mapping to a matching field in the object. + optional string type = 1; + + // object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + optional ObjectMetricSource object = 2; + + // pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + optional PodsMetricSource pods = 3; + + // resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ResourceMetricSource resource = 4; + + // external refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + optional ExternalMetricSource external = 5; +} + +// MetricStatus describes the last-read state of a single metric. +message MetricStatus { + // type is the type of metric source. It will be one of "Object", + // "Pods" or "Resource", each corresponds to a matching field in the object. + optional string type = 1; + + // object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + optional ObjectMetricStatus object = 2; + + // pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + optional PodsMetricStatus pods = 3; + + // resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ResourceMetricStatus resource = 4; + + // external refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + optional ExternalMetricStatus external = 5; +} + +// ObjectMetricSource indicates how to scale on a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +message ObjectMetricSource { + // target is the described Kubernetes object. + optional CrossVersionObjectReference target = 1; + + // metricName is the name of the metric in question. + optional string metricName = 2; + + // targetValue is the target value of the metric (as a quantity). + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetValue = 3; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 4; + + // averageValue is the target value of the average of the + // metric across all relevant pods (as a quantity) + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity averageValue = 5; +} + +// ObjectMetricStatus indicates the current value of a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +message ObjectMetricStatus { + // target is the described Kubernetes object. + optional CrossVersionObjectReference target = 1; + + // metricName is the name of the metric in question. + optional string metricName = 2; + + // currentValue is the current value of the metric (as a quantity). + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentValue = 3; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set in the ObjectMetricSource, it is passed as an additional parameter to the metrics server for more specific metrics scoping. + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 4; + + // averageValue is the current value of the average of the + // metric across all relevant pods (as a quantity) + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity averageValue = 5; +} + +// PodsMetricSource indicates how to scale on a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +// The values will be averaged together before being compared to the target +// value. +message PodsMetricSource { + // metricName is the name of the metric in question + optional string metricName = 1; + + // targetAverageValue is the target value of the average of the + // metric across all relevant pods (as a quantity) + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 2; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 3; +} + +// PodsMetricStatus indicates the current value of a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +message PodsMetricStatus { + // metricName is the name of the metric in question + optional string metricName = 1; + + // currentAverageValue is the current value of the average of the + // metric across all relevant pods (as a quantity) + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 2; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set in the PodsMetricSource, it is passed as an additional parameter to the metrics server for more specific metrics scoping. + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 3; +} + +// ResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +message ResourceMetricSource { + // name is the name of the resource in question. + optional string name = 1; + + // targetAverageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + optional int32 targetAverageUtilization = 2; + + // targetAverageValue is the target value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity targetAverageValue = 3; +} + +// ResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +message ResourceMetricStatus { + // name is the name of the resource in question. + optional string name = 1; + + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. It will only be + // present if `targetAverageValue` was set in the corresponding metric + // specification. + // +optional + optional int32 currentAverageUtilization = 2; + + // currentAverageValue is the current value of the average of the + // resource metric across all relevant pods, as a raw value (instead of as + // a percentage of the request), similar to the "pods" metric source type. + // It will always be set, regardless of the corresponding metric specification. + optional k8s.io.apimachinery.pkg.api.resource.Quantity currentAverageValue = 3; +} + diff --git a/vendor/k8s.io/api/autoscaling/v2beta2/generated.proto b/vendor/k8s.io/api/autoscaling/v2beta2/generated.proto new file mode 100644 index 000000000..b4e4c95a3 --- /dev/null +++ b/vendor/k8s.io/api/autoscaling/v2beta2/generated.proto @@ -0,0 +1,369 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.autoscaling.v2beta2; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/api/resource/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v2beta2"; + +// CrossVersionObjectReference contains enough information to let you identify the referred resource. +message CrossVersionObjectReference { + // Kind of the referent; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds" + optional string kind = 1; + + // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names + optional string name = 2; + + // API version of the referent + // +optional + optional string apiVersion = 3; +} + +// ExternalMetricSource indicates how to scale on a metric not associated with +// any Kubernetes object (for example length of queue in cloud +// messaging service, or QPS from loadbalancer running outside of cluster). +message ExternalMetricSource { + // metric identifies the target metric by name and selector + optional MetricIdentifier metric = 1; + + // target specifies the target value for the given metric + optional MetricTarget target = 2; +} + +// ExternalMetricStatus indicates the current value of a global metric +// not associated with any Kubernetes object. +message ExternalMetricStatus { + // metric identifies the target metric by name and selector + optional MetricIdentifier metric = 1; + + // current contains the current value for the given metric + optional MetricValueStatus current = 2; +} + +// HorizontalPodAutoscaler is the configuration for a horizontal pod +// autoscaler, which automatically manages the replica count of any resource +// implementing the scale subresource based on the metrics specified. +message HorizontalPodAutoscaler { + // metadata is the standard object metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // spec is the specification for the behaviour of the autoscaler. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional HorizontalPodAutoscalerSpec spec = 2; + + // status is the current information about the autoscaler. + // +optional + optional HorizontalPodAutoscalerStatus status = 3; +} + +// HorizontalPodAutoscalerCondition describes the state of +// a HorizontalPodAutoscaler at a certain point. +message HorizontalPodAutoscalerCondition { + // type describes the current condition + optional string type = 1; + + // status is the status of the condition (True, False, Unknown) + optional string status = 2; + + // lastTransitionTime is the last time the condition transitioned from + // one status to another + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // reason is the reason for the condition's last transition. + // +optional + optional string reason = 4; + + // message is a human-readable explanation containing details about + // the transition + // +optional + optional string message = 5; +} + +// HorizontalPodAutoscalerList is a list of horizontal pod autoscaler objects. +message HorizontalPodAutoscalerList { + // metadata is the standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of horizontal pod autoscaler objects. + repeated HorizontalPodAutoscaler items = 2; +} + +// HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler. +message HorizontalPodAutoscalerSpec { + // scaleTargetRef points to the target resource to scale, and is used to the pods for which metrics + // should be collected, as well as to actually change the replica count. + optional CrossVersionObjectReference scaleTargetRef = 1; + + // minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down. + // It defaults to 1 pod. + // +optional + optional int32 minReplicas = 2; + + // maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up. + // It cannot be less that minReplicas. + optional int32 maxReplicas = 3; + + // metrics contains the specifications for which to use to calculate the + // desired replica count (the maximum replica count across all metrics will + // be used). The desired replica count is calculated multiplying the + // ratio between the target value and the current value by the current + // number of pods. Ergo, metrics used must decrease as the pod count is + // increased, and vice-versa. See the individual metric source types for + // more information about how each type of metric must respond. + // If not set, the default metric will be set to 80% average CPU utilization. + // +optional + repeated MetricSpec metrics = 4; +} + +// HorizontalPodAutoscalerStatus describes the current status of a horizontal pod autoscaler. +message HorizontalPodAutoscalerStatus { + // observedGeneration is the most recent generation observed by this autoscaler. + // +optional + optional int64 observedGeneration = 1; + + // lastScaleTime is the last time the HorizontalPodAutoscaler scaled the number of pods, + // used by the autoscaler to control how often the number of pods is changed. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastScaleTime = 2; + + // currentReplicas is current number of replicas of pods managed by this autoscaler, + // as last seen by the autoscaler. + optional int32 currentReplicas = 3; + + // desiredReplicas is the desired number of replicas of pods managed by this autoscaler, + // as last calculated by the autoscaler. + optional int32 desiredReplicas = 4; + + // currentMetrics is the last read state of the metrics used by this autoscaler. + // +optional + repeated MetricStatus currentMetrics = 5; + + // conditions is the set of conditions required for this autoscaler to scale its target, + // and indicates whether or not those conditions are met. + repeated HorizontalPodAutoscalerCondition conditions = 6; +} + +// MetricIdentifier defines the name and optionally selector for a metric +message MetricIdentifier { + // name is the name of the given metric + optional string name = 1; + + // selector is the string-encoded form of a standard kubernetes label selector for the given metric + // When set, it is passed as an additional parameter to the metrics server for more specific metrics scoping. + // When unset, just the metricName will be used to gather metrics. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; +} + +// MetricSpec specifies how to scale based on a single metric +// (only `type` and one other matching field should be set at once). +message MetricSpec { + // type is the type of metric source. It should be one of "Object", + // "Pods" or "Resource", each mapping to a matching field in the object. + optional string type = 1; + + // object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + optional ObjectMetricSource object = 2; + + // pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + optional PodsMetricSource pods = 3; + + // resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ResourceMetricSource resource = 4; + + // external refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + optional ExternalMetricSource external = 5; +} + +// MetricStatus describes the last-read state of a single metric. +message MetricStatus { + // type is the type of metric source. It will be one of "Object", + // "Pods" or "Resource", each corresponds to a matching field in the object. + optional string type = 1; + + // object refers to a metric describing a single kubernetes object + // (for example, hits-per-second on an Ingress object). + // +optional + optional ObjectMetricStatus object = 2; + + // pods refers to a metric describing each pod in the current scale target + // (for example, transactions-processed-per-second). The values will be + // averaged together before being compared to the target value. + // +optional + optional PodsMetricStatus pods = 3; + + // resource refers to a resource metric (such as those specified in + // requests and limits) known to Kubernetes describing each pod in the + // current scale target (e.g. CPU or memory). Such metrics are built in to + // Kubernetes, and have special scaling options on top of those available + // to normal per-pod metrics using the "pods" source. + // +optional + optional ResourceMetricStatus resource = 4; + + // external refers to a global metric that is not associated + // with any Kubernetes object. It allows autoscaling based on information + // coming from components running outside of cluster + // (for example length of queue in cloud messaging service, or + // QPS from loadbalancer running outside of cluster). + // +optional + optional ExternalMetricStatus external = 5; +} + +// MetricTarget defines the target value, average value, or average utilization of a specific metric +message MetricTarget { + // type represents whether the metric type is Utilization, Value, or AverageValue + optional string type = 1; + + // value is the target value of the metric (as a quantity). + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity value = 2; + + // averageValue is the target value of the average of the + // metric across all relevant pods (as a quantity) + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity averageValue = 3; + + // averageUtilization is the target value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // Currently only valid for Resource metric source type + // +optional + optional int32 averageUtilization = 4; +} + +// MetricValueStatus holds the current value for a metric +message MetricValueStatus { + // value is the current value of the metric (as a quantity). + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity value = 1; + + // averageValue is the current value of the average of the + // metric across all relevant pods (as a quantity) + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity averageValue = 2; + + // currentAverageUtilization is the current value of the average of the + // resource metric across all relevant pods, represented as a percentage of + // the requested value of the resource for the pods. + // +optional + optional int32 averageUtilization = 3; +} + +// ObjectMetricSource indicates how to scale on a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +message ObjectMetricSource { + optional CrossVersionObjectReference describedObject = 1; + + // target specifies the target value for the given metric + optional MetricTarget target = 2; + + // metric identifies the target metric by name and selector + optional MetricIdentifier metric = 3; +} + +// ObjectMetricStatus indicates the current value of a metric describing a +// kubernetes object (for example, hits-per-second on an Ingress object). +message ObjectMetricStatus { + // metric identifies the target metric by name and selector + optional MetricIdentifier metric = 1; + + // current contains the current value for the given metric + optional MetricValueStatus current = 2; + + optional CrossVersionObjectReference describedObject = 3; +} + +// PodsMetricSource indicates how to scale on a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +// The values will be averaged together before being compared to the target +// value. +message PodsMetricSource { + // metric identifies the target metric by name and selector + optional MetricIdentifier metric = 1; + + // target specifies the target value for the given metric + optional MetricTarget target = 2; +} + +// PodsMetricStatus indicates the current value of a metric describing each pod in +// the current scale target (for example, transactions-processed-per-second). +message PodsMetricStatus { + // metric identifies the target metric by name and selector + optional MetricIdentifier metric = 1; + + // current contains the current value for the given metric + optional MetricValueStatus current = 2; +} + +// ResourceMetricSource indicates how to scale on a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). The values will be averaged +// together before being compared to the target. Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. Only one "target" type +// should be set. +message ResourceMetricSource { + // name is the name of the resource in question. + optional string name = 1; + + // target specifies the target value for the given metric + optional MetricTarget target = 2; +} + +// ResourceMetricStatus indicates the current value of a resource metric known to +// Kubernetes, as specified in requests and limits, describing each pod in the +// current scale target (e.g. CPU or memory). Such metrics are built in to +// Kubernetes, and have special scaling options on top of those available to +// normal per-pod metrics using the "pods" source. +message ResourceMetricStatus { + // Name is the name of the resource in question. + optional string name = 1; + + // current contains the current value for the given metric + optional MetricValueStatus current = 2; +} + diff --git a/vendor/k8s.io/api/batch/OWNERS b/vendor/k8s.io/api/batch/OWNERS new file mode 100755 index 000000000..38935ff16 --- /dev/null +++ b/vendor/k8s.io/api/batch/OWNERS @@ -0,0 +1,18 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- caesarxuchao +- erictune +- sttts +- saad-ali +- ncdc +- soltysh +- dims +- errordeveloper +- mml +- mbohlool +- david-mcmahon +- jianhuiz diff --git a/vendor/k8s.io/api/batch/v1/generated.proto b/vendor/k8s.io/api/batch/v1/generated.proto new file mode 100644 index 000000000..039149dab --- /dev/null +++ b/vendor/k8s.io/api/batch/v1/generated.proto @@ -0,0 +1,184 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.batch.v1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// Job represents the configuration of a single job. +message Job { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of a job. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional JobSpec spec = 2; + + // Current status of a job. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional JobStatus status = 3; +} + +// JobCondition describes current state of a job. +message JobCondition { + // Type of job condition, Complete or Failed. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition was checked. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastProbeTime = 3; + + // Last time the condition transit from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 4; + + // (brief) reason for the condition's last transition. + // +optional + optional string reason = 5; + + // Human readable message indicating details about last transition. + // +optional + optional string message = 6; +} + +// JobList is a collection of jobs. +message JobList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of Jobs. + repeated Job items = 2; +} + +// JobSpec describes how the job execution will look like. +message JobSpec { + // Specifies the maximum desired number of pods the job should + // run at any given time. The actual number of pods running in steady state will + // be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), + // i.e. when the work left to do is less than max parallelism. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + // +optional + optional int32 parallelism = 1; + + // Specifies the desired number of successfully finished pods the + // job should be run with. Setting to nil means that the success of any + // pod signals the success of all pods, and allows parallelism to have any positive + // value. Setting to 1 means that parallelism is limited to 1 and the success of that + // pod signals the success of the job. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + // +optional + optional int32 completions = 2; + + // Specifies the duration in seconds relative to the startTime that the job may be active + // before the system tries to terminate it; value must be positive integer + // +optional + optional int64 activeDeadlineSeconds = 3; + + // Specifies the number of retries before marking this job failed. + // Defaults to 6 + // +optional + optional int32 backoffLimit = 7; + + // A label query over pods that should match the pod count. + // Normally, the system sets this field for you. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 4; + + // manualSelector controls generation of pod labels and pod selectors. + // Leave `manualSelector` unset unless you are certain what you are doing. + // When false or unset, the system pick labels unique to this job + // and appends those labels to the pod template. When true, + // the user is responsible for picking unique labels and specifying + // the selector. Failure to pick a unique label may cause this + // and other jobs to not function correctly. However, You may see + // `manualSelector=true` in jobs that were created with the old `extensions/v1beta1` + // API. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector + // +optional + optional bool manualSelector = 5; + + // Describes the pod that will be created when executing a job. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + optional k8s.io.api.core.v1.PodTemplateSpec template = 6; + + // ttlSecondsAfterFinished limits the lifetime of a Job that has finished + // execution (either Complete or Failed). If this field is set, + // ttlSecondsAfterFinished after the Job finishes, it is eligible to be + // automatically deleted. When the Job is being deleted, its lifecycle + // guarantees (e.g. finalizers) will be honored. If this field is unset, + // the Job won't be automatically deleted. If this field is set to zero, + // the Job becomes eligible to be deleted immediately after it finishes. + // This field is alpha-level and is only honored by servers that enable the + // TTLAfterFinished feature. + // +optional + optional int32 ttlSecondsAfterFinished = 8; +} + +// JobStatus represents the current state of a Job. +message JobStatus { + // The latest available observations of an object's current state. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated JobCondition conditions = 1; + + // Represents time when the job was acknowledged by the job controller. + // It is not guaranteed to be set in happens-before order across separate operations. + // It is represented in RFC3339 form and is in UTC. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startTime = 2; + + // Represents time when the job was completed. It is not guaranteed to + // be set in happens-before order across separate operations. + // It is represented in RFC3339 form and is in UTC. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time completionTime = 3; + + // The number of actively running pods. + // +optional + optional int32 active = 4; + + // The number of pods which reached phase Succeeded. + // +optional + optional int32 succeeded = 5; + + // The number of pods which reached phase Failed. + // +optional + optional int32 failed = 6; +} + diff --git a/vendor/k8s.io/api/batch/v1beta1/generated.proto b/vendor/k8s.io/api/batch/v1beta1/generated.proto new file mode 100644 index 000000000..043b3551b --- /dev/null +++ b/vendor/k8s.io/api/batch/v1beta1/generated.proto @@ -0,0 +1,137 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.batch.v1beta1; + +import "k8s.io/api/batch/v1/generated.proto"; +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// CronJob represents the configuration of a single cron job. +message CronJob { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of a cron job, including the schedule. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional CronJobSpec spec = 2; + + // Current status of a cron job. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional CronJobStatus status = 3; +} + +// CronJobList is a collection of cron jobs. +message CronJobList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of CronJobs. + repeated CronJob items = 2; +} + +// CronJobSpec describes how the job execution will look like and when it will actually run. +message CronJobSpec { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + optional string schedule = 1; + + // Optional deadline in seconds for starting the job if it misses scheduled + // time for any reason. Missed jobs executions will be counted as failed ones. + // +optional + optional int64 startingDeadlineSeconds = 2; + + // Specifies how to treat concurrent executions of a Job. + // Valid values are: + // - "Allow" (default): allows CronJobs to run concurrently; + // - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; + // - "Replace": cancels currently running job and replaces it with a new one + // +optional + optional string concurrencyPolicy = 3; + + // This flag tells the controller to suspend subsequent executions, it does + // not apply to already started executions. Defaults to false. + // +optional + optional bool suspend = 4; + + // Specifies the job that will be created when executing a CronJob. + optional JobTemplateSpec jobTemplate = 5; + + // The number of successful finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 3. + // +optional + optional int32 successfulJobsHistoryLimit = 6; + + // The number of failed finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 1. + // +optional + optional int32 failedJobsHistoryLimit = 7; +} + +// CronJobStatus represents the current state of a cron job. +message CronJobStatus { + // A list of pointers to currently running jobs. + // +optional + repeated k8s.io.api.core.v1.ObjectReference active = 1; + + // Information when was the last time the job was successfully scheduled. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastScheduleTime = 4; +} + +// JobTemplate describes a template for creating copies of a predefined pod. +message JobTemplate { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Defines jobs that will be created from this template. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional JobTemplateSpec template = 2; +} + +// JobTemplateSpec describes the data a Job should have when created from a template +message JobTemplateSpec { + // Standard object's metadata of the jobs created from this template. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the job. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional k8s.io.api.batch.v1.JobSpec spec = 2; +} + diff --git a/vendor/k8s.io/api/batch/v2alpha1/generated.proto b/vendor/k8s.io/api/batch/v2alpha1/generated.proto new file mode 100644 index 000000000..4321c3361 --- /dev/null +++ b/vendor/k8s.io/api/batch/v2alpha1/generated.proto @@ -0,0 +1,135 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.batch.v2alpha1; + +import "k8s.io/api/batch/v1/generated.proto"; +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v2alpha1"; + +// CronJob represents the configuration of a single cron job. +message CronJob { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of a cron job, including the schedule. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional CronJobSpec spec = 2; + + // Current status of a cron job. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional CronJobStatus status = 3; +} + +// CronJobList is a collection of cron jobs. +message CronJobList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of CronJobs. + repeated CronJob items = 2; +} + +// CronJobSpec describes how the job execution will look like and when it will actually run. +message CronJobSpec { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + optional string schedule = 1; + + // Optional deadline in seconds for starting the job if it misses scheduled + // time for any reason. Missed jobs executions will be counted as failed ones. + // +optional + optional int64 startingDeadlineSeconds = 2; + + // Specifies how to treat concurrent executions of a Job. + // Valid values are: + // - "Allow" (default): allows CronJobs to run concurrently; + // - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; + // - "Replace": cancels currently running job and replaces it with a new one + // +optional + optional string concurrencyPolicy = 3; + + // This flag tells the controller to suspend subsequent executions, it does + // not apply to already started executions. Defaults to false. + // +optional + optional bool suspend = 4; + + // Specifies the job that will be created when executing a CronJob. + optional JobTemplateSpec jobTemplate = 5; + + // The number of successful finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + optional int32 successfulJobsHistoryLimit = 6; + + // The number of failed finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + optional int32 failedJobsHistoryLimit = 7; +} + +// CronJobStatus represents the current state of a cron job. +message CronJobStatus { + // A list of pointers to currently running jobs. + // +optional + repeated k8s.io.api.core.v1.ObjectReference active = 1; + + // Information when was the last time the job was successfully scheduled. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastScheduleTime = 4; +} + +// JobTemplate describes a template for creating copies of a predefined pod. +message JobTemplate { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Defines jobs that will be created from this template. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional JobTemplateSpec template = 2; +} + +// JobTemplateSpec describes the data a Job should have when created from a template +message JobTemplateSpec { + // Standard object's metadata of the jobs created from this template. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the job. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional k8s.io.api.batch.v1.JobSpec spec = 2; +} + diff --git a/vendor/k8s.io/api/certificates/OWNERS b/vendor/k8s.io/api/certificates/OWNERS new file mode 100755 index 000000000..1d1ab36e7 --- /dev/null +++ b/vendor/k8s.io/api/certificates/OWNERS @@ -0,0 +1,14 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- deads2k +- caesarxuchao +- liggitt +- sttts +- dims +- errordeveloper +- mbohlool +- david-mcmahon +- jianhuiz +- enj diff --git a/vendor/k8s.io/api/certificates/v1beta1/generated.proto b/vendor/k8s.io/api/certificates/v1beta1/generated.proto new file mode 100644 index 000000000..5200224a2 --- /dev/null +++ b/vendor/k8s.io/api/certificates/v1beta1/generated.proto @@ -0,0 +1,121 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.certificates.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// Describes a certificate signing request +message CertificateSigningRequest { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The certificate request itself and any additional information. + // +optional + optional CertificateSigningRequestSpec spec = 2; + + // Derived information about the request. + // +optional + optional CertificateSigningRequestStatus status = 3; +} + +message CertificateSigningRequestCondition { + // request approval state, currently Approved or Denied. + optional string type = 1; + + // brief reason for the request state + // +optional + optional string reason = 2; + + // human readable message with details about the request state + // +optional + optional string message = 3; + + // timestamp for the last update to this condition + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastUpdateTime = 4; +} + +message CertificateSigningRequestList { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + repeated CertificateSigningRequest items = 2; +} + +// This information is immutable after the request is created. Only the Request +// and Usages fields can be set on creation, other fields are derived by +// Kubernetes and cannot be modified by users. +message CertificateSigningRequestSpec { + // Base64-encoded PKCS#10 CSR data + optional bytes request = 1; + + // allowedUsages specifies a set of usage contexts the key will be + // valid for. + // See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3 + // https://tools.ietf.org/html/rfc5280#section-4.2.1.12 + repeated string usages = 5; + + // Information about the requesting user. + // See user.Info interface for details. + // +optional + optional string username = 2; + + // UID information about the requesting user. + // See user.Info interface for details. + // +optional + optional string uid = 3; + + // Group information about the requesting user. + // See user.Info interface for details. + // +optional + repeated string groups = 4; + + // Extra information about the requesting user. + // See user.Info interface for details. + // +optional + map<string, ExtraValue> extra = 6; +} + +message CertificateSigningRequestStatus { + // Conditions applied to the request, such as approval or denial. + // +optional + repeated CertificateSigningRequestCondition conditions = 1; + + // If request was approved, the controller will place the issued certificate here. + // +optional + optional bytes certificate = 2; +} + +// ExtraValue masks the value so protobuf can generate +// +protobuf.nullable=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +message ExtraValue { + // items, if empty, will result in an empty slice + + repeated string items = 1; +} + diff --git a/vendor/k8s.io/api/code-of-conduct.md b/vendor/k8s.io/api/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/api/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/k8s.io/api/coordination/v1beta1/generated.proto b/vendor/k8s.io/api/coordination/v1beta1/generated.proto new file mode 100644 index 000000000..918e0de1c --- /dev/null +++ b/vendor/k8s.io/api/coordination/v1beta1/generated.proto @@ -0,0 +1,80 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.coordination.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// Lease defines a lease concept. +message Lease { + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the Lease. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional LeaseSpec spec = 2; +} + +// LeaseList is a list of Lease objects. +message LeaseList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of schema objects. + repeated Lease items = 2; +} + +// LeaseSpec is a specification of a Lease. +message LeaseSpec { + // holderIdentity contains the identity of the holder of a current lease. + // +optional + optional string holderIdentity = 1; + + // leaseDurationSeconds is a duration that candidates for a lease need + // to wait to force acquire it. This is measure against time of last + // observed RenewTime. + // +optional + optional int32 leaseDurationSeconds = 2; + + // acquireTime is a time when the current lease was acquired. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.MicroTime acquireTime = 3; + + // renewTime is a time when the current holder of a lease has last + // updated the lease. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.MicroTime renewTime = 4; + + // leaseTransitions is the number of transitions of a lease between + // holders. + // +optional + optional int32 leaseTransitions = 5; +} + diff --git a/vendor/k8s.io/api/core/v1/generated.proto b/vendor/k8s.io/api/core/v1/generated.proto new file mode 100644 index 000000000..f76251d52 --- /dev/null +++ b/vendor/k8s.io/api/core/v1/generated.proto @@ -0,0 +1,4757 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.core.v1; + +import "k8s.io/apimachinery/pkg/api/resource/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// Represents a Persistent Disk resource in AWS. +// +// An AWS EBS disk must exist before mounting to a container. The disk +// must also be in the same AWS zone as the kubelet. An AWS EBS disk +// can only be mounted as read/write once. AWS EBS volumes support +// ownership management and SELinux relabeling. +message AWSElasticBlockStoreVolumeSource { + // Unique ID of the persistent disk resource in AWS (Amazon EBS volume). + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + optional string volumeID = 1; + + // Filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 2; + + // The partition in the volume that you want to mount. + // If omitted, the default is to mount by volume name. + // Examples: For volume /dev/sda1, you specify the partition as "1". + // Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + // +optional + optional int32 partition = 3; + + // Specify "true" to force and set the ReadOnly property in VolumeMounts to "true". + // If omitted, the default is "false". + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // +optional + optional bool readOnly = 4; +} + +// Affinity is a group of affinity scheduling rules. +message Affinity { + // Describes node affinity scheduling rules for the pod. + // +optional + optional NodeAffinity nodeAffinity = 1; + + // Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + // +optional + optional PodAffinity podAffinity = 2; + + // Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + // +optional + optional PodAntiAffinity podAntiAffinity = 3; +} + +// AttachedVolume describes a volume attached to a node +message AttachedVolume { + // Name of the attached volume + optional string name = 1; + + // DevicePath represents the device path where the volume should be available + optional string devicePath = 2; +} + +// AvoidPods describes pods that should avoid this node. This is the value for a +// Node annotation with key scheduler.alpha.kubernetes.io/preferAvoidPods and +// will eventually become a field of NodeStatus. +message AvoidPods { + // Bounded-sized list of signatures of pods that should avoid this node, sorted + // in timestamp order from oldest to newest. Size of the slice is unspecified. + // +optional + repeated PreferAvoidPodsEntry preferAvoidPods = 1; +} + +// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. +message AzureDiskVolumeSource { + // The Name of the data disk in the blob storage + optional string diskName = 1; + + // The URI the data disk in the blob storage + optional string diskURI = 2; + + // Host Caching mode: None, Read Only, Read Write. + // +optional + optional string cachingMode = 3; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + optional string fsType = 4; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 5; + + // Expected values Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared + optional string kind = 6; +} + +// AzureFile represents an Azure File Service mount on the host and bind mount to the pod. +message AzureFilePersistentVolumeSource { + // the name of secret that contains Azure Storage Account Name and Key + optional string secretName = 1; + + // Share Name + optional string shareName = 2; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 3; + + // the namespace of the secret that contains Azure Storage Account Name and Key + // default is the same as the Pod + // +optional + optional string secretNamespace = 4; +} + +// AzureFile represents an Azure File Service mount on the host and bind mount to the pod. +message AzureFileVolumeSource { + // the name of secret that contains Azure Storage Account Name and Key + optional string secretName = 1; + + // Share Name + optional string shareName = 2; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 3; +} + +// Binding ties one object to another; for example, a pod is bound to a node by a scheduler. +// Deprecated in 1.7, please use the bindings subresource of pods instead. +message Binding { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The target object that you want to bind to the standard object. + optional ObjectReference target = 2; +} + +// Represents storage that is managed by an external CSI volume driver (Beta feature) +message CSIPersistentVolumeSource { + // Driver is the name of the driver to use for this volume. + // Required. + optional string driver = 1; + + // VolumeHandle is the unique volume name returned by the CSI volume + // plugin’s CreateVolume to refer to the volume on all subsequent calls. + // Required. + optional string volumeHandle = 2; + + // Optional: The value to pass to ControllerPublishVolumeRequest. + // Defaults to false (read/write). + // +optional + optional bool readOnly = 3; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // +optional + optional string fsType = 4; + + // Attributes of the volume to publish. + // +optional + map<string, string> volumeAttributes = 5; + + // ControllerPublishSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // ControllerPublishVolume and ControllerUnpublishVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + optional SecretReference controllerPublishSecretRef = 6; + + // NodeStageSecretRef is a reference to the secret object containing sensitive + // information to pass to the CSI driver to complete the CSI NodeStageVolume + // and NodeStageVolume and NodeUnstageVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + optional SecretReference nodeStageSecretRef = 7; + + // NodePublishSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // NodePublishVolume and NodeUnpublishVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secrets are passed. + // +optional + optional SecretReference nodePublishSecretRef = 8; +} + +// Adds and removes POSIX capabilities from running containers. +message Capabilities { + // Added capabilities + // +optional + repeated string add = 1; + + // Removed capabilities + // +optional + repeated string drop = 2; +} + +// Represents a Ceph Filesystem mount that lasts the lifetime of a pod +// Cephfs volumes do not support ownership management or SELinux relabeling. +message CephFSPersistentVolumeSource { + // Required: Monitors is a collection of Ceph monitors + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + repeated string monitors = 1; + + // Optional: Used as the mounted root, rather than the full Ceph tree, default is / + // +optional + optional string path = 2; + + // Optional: User is the rados user name, default is admin + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional string user = 3; + + // Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional string secretFile = 4; + + // Optional: SecretRef is reference to the authentication secret for User, default is empty. + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional SecretReference secretRef = 5; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional bool readOnly = 6; +} + +// Represents a Ceph Filesystem mount that lasts the lifetime of a pod +// Cephfs volumes do not support ownership management or SELinux relabeling. +message CephFSVolumeSource { + // Required: Monitors is a collection of Ceph monitors + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + repeated string monitors = 1; + + // Optional: Used as the mounted root, rather than the full Ceph tree, default is / + // +optional + optional string path = 2; + + // Optional: User is the rados user name, default is admin + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional string user = 3; + + // Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional string secretFile = 4; + + // Optional: SecretRef is reference to the authentication secret for User, default is empty. + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional LocalObjectReference secretRef = 5; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // More info: https://releases.k8s.io/HEAD/examples/volumes/cephfs/README.md#how-to-use-it + // +optional + optional bool readOnly = 6; +} + +// Represents a cinder volume resource in Openstack. +// A Cinder volume must exist before mounting to a container. +// The volume must also be in the same region as the kubelet. +// Cinder volumes support ownership management and SELinux relabeling. +message CinderPersistentVolumeSource { + // volume id used to identify the volume in cinder + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + optional string volumeID = 1; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + // +optional + optional string fsType = 2; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + // +optional + optional bool readOnly = 3; + + // Optional: points to a secret object containing parameters used to connect + // to OpenStack. + // +optional + optional SecretReference secretRef = 4; +} + +// Represents a cinder volume resource in Openstack. +// A Cinder volume must exist before mounting to a container. +// The volume must also be in the same region as the kubelet. +// Cinder volumes support ownership management and SELinux relabeling. +message CinderVolumeSource { + // volume id used to identify the volume in cinder + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + optional string volumeID = 1; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + // +optional + optional string fsType = 2; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + // +optional + optional bool readOnly = 3; + + // Optional: points to a secret object containing parameters used to connect + // to OpenStack. + // +optional + optional LocalObjectReference secretRef = 4; +} + +// ClientIPConfig represents the configurations of Client IP based session affinity. +message ClientIPConfig { + // timeoutSeconds specifies the seconds of ClientIP type session sticky time. + // The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". + // Default value is 10800(for 3 hours). + // +optional + optional int32 timeoutSeconds = 1; +} + +// Information about the condition of a component. +message ComponentCondition { + // Type of condition for a component. + // Valid value: "Healthy" + optional string type = 1; + + // Status of the condition for a component. + // Valid values for "Healthy": "True", "False", or "Unknown". + optional string status = 2; + + // Message about the condition for a component. + // For example, information about a health check. + // +optional + optional string message = 3; + + // Condition error code for a component. + // For example, a health check error code. + // +optional + optional string error = 4; +} + +// ComponentStatus (and ComponentStatusList) holds the cluster validation info. +message ComponentStatus { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // List of component conditions observed + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated ComponentCondition conditions = 2; +} + +// Status of all the conditions for the component as a list of ComponentStatus objects. +message ComponentStatusList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of ComponentStatus objects. + repeated ComponentStatus items = 2; +} + +// ConfigMap holds configuration data for pods to consume. +message ConfigMap { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Data contains the configuration data. + // Each key must consist of alphanumeric characters, '-', '_' or '.'. + // Values with non-UTF-8 byte sequences must use the BinaryData field. + // The keys stored in Data must not overlap with the keys in + // the BinaryData field, this is enforced during validation process. + // +optional + map<string, string> data = 2; + + // BinaryData contains the binary data. + // Each key must consist of alphanumeric characters, '-', '_' or '.'. + // BinaryData can contain byte sequences that are not in the UTF-8 range. + // The keys stored in BinaryData must not overlap with the ones in + // the Data field, this is enforced during validation process. + // Using this field will require 1.10+ apiserver and + // kubelet. + // +optional + map<string, bytes> binaryData = 3; +} + +// ConfigMapEnvSource selects a ConfigMap to populate the environment +// variables with. +// +// The contents of the target ConfigMap's Data field will represent the +// key-value pairs as environment variables. +message ConfigMapEnvSource { + // The ConfigMap to select from. + optional LocalObjectReference localObjectReference = 1; + + // Specify whether the ConfigMap must be defined + // +optional + optional bool optional = 2; +} + +// Selects a key from a ConfigMap. +message ConfigMapKeySelector { + // The ConfigMap to select from. + optional LocalObjectReference localObjectReference = 1; + + // The key to select. + optional string key = 2; + + // Specify whether the ConfigMap or it's key must be defined + // +optional + optional bool optional = 3; +} + +// ConfigMapList is a resource containing a list of ConfigMap objects. +message ConfigMapList { + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of ConfigMaps. + repeated ConfigMap items = 2; +} + +// ConfigMapNodeConfigSource contains the information to reference a ConfigMap as a config source for the Node. +message ConfigMapNodeConfigSource { + // Namespace is the metadata.namespace of the referenced ConfigMap. + // This field is required in all cases. + optional string namespace = 1; + + // Name is the metadata.name of the referenced ConfigMap. + // This field is required in all cases. + optional string name = 2; + + // UID is the metadata.UID of the referenced ConfigMap. + // This field is forbidden in Node.Spec, and required in Node.Status. + // +optional + optional string uid = 3; + + // ResourceVersion is the metadata.ResourceVersion of the referenced ConfigMap. + // This field is forbidden in Node.Spec, and required in Node.Status. + // +optional + optional string resourceVersion = 4; + + // KubeletConfigKey declares which key of the referenced ConfigMap corresponds to the KubeletConfiguration structure + // This field is required in all cases. + optional string kubeletConfigKey = 5; +} + +// Adapts a ConfigMap into a projected volume. +// +// The contents of the target ConfigMap's Data field will be presented in a +// projected volume as files using the keys in the Data field as the file names, +// unless the items element is populated with specific mappings of keys to paths. +// Note that this is identical to a configmap volume source without the default +// mode. +message ConfigMapProjection { + optional LocalObjectReference localObjectReference = 1; + + // If unspecified, each key-value pair in the Data field of the referenced + // ConfigMap will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the ConfigMap, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + repeated KeyToPath items = 2; + + // Specify whether the ConfigMap or it's keys must be defined + // +optional + optional bool optional = 4; +} + +// Adapts a ConfigMap into a volume. +// +// The contents of the target ConfigMap's Data field will be presented in a +// volume as files using the keys in the Data field as the file names, unless +// the items element is populated with specific mappings of keys to paths. +// ConfigMap volumes support ownership management and SELinux relabeling. +message ConfigMapVolumeSource { + optional LocalObjectReference localObjectReference = 1; + + // If unspecified, each key-value pair in the Data field of the referenced + // ConfigMap will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the ConfigMap, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + repeated KeyToPath items = 2; + + // Optional: mode bits to use on created files by default. Must be a + // value between 0 and 0777. Defaults to 0644. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + optional int32 defaultMode = 3; + + // Specify whether the ConfigMap or it's keys must be defined + // +optional + optional bool optional = 4; +} + +// A single application container that you want to run within a pod. +message Container { + // Name of the container specified as a DNS_LABEL. + // Each container in a pod must have a unique name (DNS_LABEL). + // Cannot be updated. + optional string name = 1; + + // Docker image name. + // More info: https://kubernetes.io/docs/concepts/containers/images + // This field is optional to allow higher level config management to default or override + // container images in workload controllers like Deployments and StatefulSets. + // +optional + optional string image = 2; + + // Entrypoint array. Not executed within a shell. + // The docker image's ENTRYPOINT is used if this is not provided. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax + // can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, + // regardless of whether the variable exists or not. + // Cannot be updated. + // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + // +optional + repeated string command = 3; + + // Arguments to the entrypoint. + // The docker image's CMD is used if this is not provided. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax + // can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, + // regardless of whether the variable exists or not. + // Cannot be updated. + // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + // +optional + repeated string args = 4; + + // Container's working directory. + // If not specified, the container runtime's default will be used, which + // might be configured in the container image. + // Cannot be updated. + // +optional + optional string workingDir = 5; + + // List of ports to expose from the container. Exposing a port here gives + // the system additional information about the network connections a + // container uses, but is primarily informational. Not specifying a port here + // DOES NOT prevent that port from being exposed. Any port which is + // listening on the default "0.0.0.0" address inside a container will be + // accessible from the network. + // Cannot be updated. + // +optional + // +patchMergeKey=containerPort + // +patchStrategy=merge + repeated ContainerPort ports = 6; + + // List of sources to populate environment variables in the container. + // The keys defined within a source must be a C_IDENTIFIER. All invalid keys + // will be reported as an event when the container is starting. When a key exists in multiple + // sources, the value associated with the last source will take precedence. + // Values defined by an Env with a duplicate key will take precedence. + // Cannot be updated. + // +optional + repeated EnvFromSource envFrom = 19; + + // List of environment variables to set in the container. + // Cannot be updated. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + repeated EnvVar env = 7; + + // Compute Resources required by this container. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + // +optional + optional ResourceRequirements resources = 8; + + // Pod volumes to mount into the container's filesystem. + // Cannot be updated. + // +optional + // +patchMergeKey=mountPath + // +patchStrategy=merge + repeated VolumeMount volumeMounts = 9; + + // volumeDevices is the list of block devices to be used by the container. + // This is an alpha feature and may change in the future. + // +patchMergeKey=devicePath + // +patchStrategy=merge + // +optional + repeated VolumeDevice volumeDevices = 21; + + // Periodic probe of container liveness. + // Container will be restarted if the probe fails. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + optional Probe livenessProbe = 10; + + // Periodic probe of container service readiness. + // Container will be removed from service endpoints if the probe fails. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + optional Probe readinessProbe = 11; + + // Actions that the management system should take in response to container lifecycle events. + // Cannot be updated. + // +optional + optional Lifecycle lifecycle = 12; + + // Optional: Path at which the file to which the container's termination message + // will be written is mounted into the container's filesystem. + // Message written is intended to be brief final status, such as an assertion failure message. + // Will be truncated by the node if greater than 4096 bytes. The total message length across + // all containers will be limited to 12kb. + // Defaults to /dev/termination-log. + // Cannot be updated. + // +optional + optional string terminationMessagePath = 13; + + // Indicate how the termination message should be populated. File will use the contents of + // terminationMessagePath to populate the container status message on both success and failure. + // FallbackToLogsOnError will use the last chunk of container log output if the termination + // message file is empty and the container exited with an error. + // The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + // Defaults to File. + // Cannot be updated. + // +optional + optional string terminationMessagePolicy = 20; + + // Image pull policy. + // One of Always, Never, IfNotPresent. + // Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + // +optional + optional string imagePullPolicy = 14; + + // Security options the pod should run with. + // More info: https://kubernetes.io/docs/concepts/policy/security-context/ + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + // +optional + optional SecurityContext securityContext = 15; + + // Whether this container should allocate a buffer for stdin in the container runtime. If this + // is not set, reads from stdin in the container will always result in EOF. + // Default is false. + // +optional + optional bool stdin = 16; + + // Whether the container runtime should close the stdin channel after it has been opened by + // a single attach. When stdin is true the stdin stream will remain open across multiple attach + // sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + // first client attaches to stdin, and then remains open and accepts data until the client disconnects, + // at which time stdin is closed and remains closed until the container is restarted. If this + // flag is false, a container processes that reads from stdin will never receive an EOF. + // Default is false + // +optional + optional bool stdinOnce = 17; + + // Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + // Default is false. + // +optional + optional bool tty = 18; +} + +// Describe a container image +message ContainerImage { + // Names by which this image is known. + // e.g. ["k8s.gcr.io/hyperkube:v1.0.7", "dockerhub.io/google_containers/hyperkube:v1.0.7"] + repeated string names = 1; + + // The size of the image in bytes. + // +optional + optional int64 sizeBytes = 2; +} + +// ContainerPort represents a network port in a single container. +message ContainerPort { + // If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + // named port in a pod must have a unique name. Name for the port that can be + // referred to by services. + // +optional + optional string name = 1; + + // Number of port to expose on the host. + // If specified, this must be a valid port number, 0 < x < 65536. + // If HostNetwork is specified, this must match ContainerPort. + // Most containers do not need this. + // +optional + optional int32 hostPort = 2; + + // Number of port to expose on the pod's IP address. + // This must be a valid port number, 0 < x < 65536. + optional int32 containerPort = 3; + + // Protocol for port. Must be UDP, TCP, or SCTP. + // Defaults to "TCP". + // +optional + optional string protocol = 4; + + // What host IP to bind the external port to. + // +optional + optional string hostIP = 5; +} + +// ContainerState holds a possible state of container. +// Only one of its members may be specified. +// If none of them is specified, the default one is ContainerStateWaiting. +message ContainerState { + // Details about a waiting container + // +optional + optional ContainerStateWaiting waiting = 1; + + // Details about a running container + // +optional + optional ContainerStateRunning running = 2; + + // Details about a terminated container + // +optional + optional ContainerStateTerminated terminated = 3; +} + +// ContainerStateRunning is a running state of a container. +message ContainerStateRunning { + // Time at which the container was last (re-)started + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt = 1; +} + +// ContainerStateTerminated is a terminated state of a container. +message ContainerStateTerminated { + // Exit status from the last termination of the container + optional int32 exitCode = 1; + + // Signal from the last termination of the container + // +optional + optional int32 signal = 2; + + // (brief) reason from the last termination of the container + // +optional + optional string reason = 3; + + // Message regarding the last termination of the container + // +optional + optional string message = 4; + + // Time at which previous execution of the container started + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt = 5; + + // Time at which the container last terminated + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 6; + + // Container's ID in the format 'docker://<container_id>' + // +optional + optional string containerID = 7; +} + +// ContainerStateWaiting is a waiting state of a container. +message ContainerStateWaiting { + // (brief) reason the container is not yet running. + // +optional + optional string reason = 1; + + // Message regarding why the container is not yet running. + // +optional + optional string message = 2; +} + +// ContainerStatus contains details for the current status of this container. +message ContainerStatus { + // This must be a DNS_LABEL. Each container in a pod must have a unique name. + // Cannot be updated. + optional string name = 1; + + // Details about the container's current condition. + // +optional + optional ContainerState state = 2; + + // Details about the container's last termination condition. + // +optional + optional ContainerState lastState = 3; + + // Specifies whether the container has passed its readiness probe. + optional bool ready = 4; + + // The number of times the container has been restarted, currently based on + // the number of dead containers that have not yet been removed. + // Note that this is calculated from dead containers. But those containers are subject to + // garbage collection. This value will get capped at 5 by GC. + optional int32 restartCount = 5; + + // The image the container is running. + // More info: https://kubernetes.io/docs/concepts/containers/images + // TODO(dchen1107): Which image the container is running with? + optional string image = 6; + + // ImageID of the container's image. + optional string imageID = 7; + + // Container's ID in the format 'docker://<container_id>'. + // +optional + optional string containerID = 8; +} + +// DaemonEndpoint contains information about a single Daemon endpoint. +message DaemonEndpoint { + // Port number of the given endpoint. + optional int32 Port = 1; +} + +// Represents downward API info for projecting into a projected volume. +// Note that this is identical to a downwardAPI volume source without the default +// mode. +message DownwardAPIProjection { + // Items is a list of DownwardAPIVolume file + // +optional + repeated DownwardAPIVolumeFile items = 1; +} + +// DownwardAPIVolumeFile represents information to create the file containing the pod field +message DownwardAPIVolumeFile { + // Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' + optional string path = 1; + + // Required: Selects a field of the pod: only annotations, labels, name and namespace are supported. + // +optional + optional ObjectFieldSelector fieldRef = 2; + + // Selects a resource of the container: only resources limits and requests + // (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + // +optional + optional ResourceFieldSelector resourceFieldRef = 3; + + // Optional: mode bits to use on this file, must be a value between 0 + // and 0777. If not specified, the volume defaultMode will be used. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + optional int32 mode = 4; +} + +// DownwardAPIVolumeSource represents a volume containing downward API info. +// Downward API volumes support ownership management and SELinux relabeling. +message DownwardAPIVolumeSource { + // Items is a list of downward API volume file + // +optional + repeated DownwardAPIVolumeFile items = 1; + + // Optional: mode bits to use on created files by default. Must be a + // value between 0 and 0777. Defaults to 0644. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + optional int32 defaultMode = 2; +} + +// Represents an empty directory for a pod. +// Empty directory volumes support ownership management and SELinux relabeling. +message EmptyDirVolumeSource { + // What type of storage medium should back this directory. + // The default is "" which means to use the node's default medium. + // Must be an empty string (default) or Memory. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + // +optional + optional string medium = 1; + + // Total amount of local storage required for this EmptyDir volume. + // The size limit is also applicable for memory medium. + // The maximum usage on memory medium EmptyDir would be the minimum value between + // the SizeLimit specified here and the sum of memory limits of all containers in a pod. + // The default is nil which means that the limit is undefined. + // More info: http://kubernetes.io/docs/user-guide/volumes#emptydir + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity sizeLimit = 2; +} + +// EndpointAddress is a tuple that describes single IP address. +message EndpointAddress { + // The IP of this endpoint. + // May not be loopback (127.0.0.0/8), link-local (169.254.0.0/16), + // or link-local multicast ((224.0.0.0/24). + // IPv6 is also accepted but not fully supported on all platforms. Also, certain + // kubernetes components, like kube-proxy, are not IPv6 ready. + // TODO: This should allow hostname or IP, See #4447. + optional string ip = 1; + + // The Hostname of this endpoint + // +optional + optional string hostname = 3; + + // Optional: Node hosting this endpoint. This can be used to determine endpoints local to a node. + // +optional + optional string nodeName = 4; + + // Reference to object providing the endpoint. + // +optional + optional ObjectReference targetRef = 2; +} + +// EndpointPort is a tuple that describes a single port. +message EndpointPort { + // The name of this port (corresponds to ServicePort.Name). + // Must be a DNS_LABEL. + // Optional only if one port is defined. + // +optional + optional string name = 1; + + // The port number of the endpoint. + optional int32 port = 2; + + // The IP protocol for this port. + // Must be UDP, TCP, or SCTP. + // Default is TCP. + // +optional + optional string protocol = 3; +} + +// EndpointSubset is a group of addresses with a common set of ports. The +// expanded set of endpoints is the Cartesian product of Addresses x Ports. +// For example, given: +// { +// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], +// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] +// } +// The resulting set of endpoints can be viewed as: +// a: [ 10.10.1.1:8675, 10.10.2.2:8675 ], +// b: [ 10.10.1.1:309, 10.10.2.2:309 ] +message EndpointSubset { + // IP addresses which offer the related ports that are marked as ready. These endpoints + // should be considered safe for load balancers and clients to utilize. + // +optional + repeated EndpointAddress addresses = 1; + + // IP addresses which offer the related ports but are not currently marked as ready + // because they have not yet finished starting, have recently failed a readiness check, + // or have recently failed a liveness check. + // +optional + repeated EndpointAddress notReadyAddresses = 2; + + // Port numbers available on the related IP addresses. + // +optional + repeated EndpointPort ports = 3; +} + +// Endpoints is a collection of endpoints that implement the actual service. Example: +// Name: "mysvc", +// Subsets: [ +// { +// Addresses: [{"ip": "10.10.1.1"}, {"ip": "10.10.2.2"}], +// Ports: [{"name": "a", "port": 8675}, {"name": "b", "port": 309}] +// }, +// { +// Addresses: [{"ip": "10.10.3.3"}], +// Ports: [{"name": "a", "port": 93}, {"name": "b", "port": 76}] +// }, +// ] +message Endpoints { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The set of all endpoints is the union of all subsets. Addresses are placed into + // subsets according to the IPs they share. A single address with multiple ports, + // some of which are ready and some of which are not (because they come from + // different containers) will result in the address being displayed in different + // subsets for the different ports. No address will appear in both Addresses and + // NotReadyAddresses in the same subset. + // Sets of addresses and ports that comprise a service. + // +optional + repeated EndpointSubset subsets = 2; +} + +// EndpointsList is a list of endpoints. +message EndpointsList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of endpoints. + repeated Endpoints items = 2; +} + +// EnvFromSource represents the source of a set of ConfigMaps +message EnvFromSource { + // An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + // +optional + optional string prefix = 1; + + // The ConfigMap to select from + // +optional + optional ConfigMapEnvSource configMapRef = 2; + + // The Secret to select from + // +optional + optional SecretEnvSource secretRef = 3; +} + +// EnvVar represents an environment variable present in a Container. +message EnvVar { + // Name of the environment variable. Must be a C_IDENTIFIER. + optional string name = 1; + + // Variable references $(VAR_NAME) are expanded + // using the previous defined environment variables in the container and + // any service environment variables. If a variable cannot be resolved, + // the reference in the input string will be unchanged. The $(VAR_NAME) + // syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped + // references will never be expanded, regardless of whether the variable + // exists or not. + // Defaults to "". + // +optional + optional string value = 2; + + // Source for the environment variable's value. Cannot be used if value is not empty. + // +optional + optional EnvVarSource valueFrom = 3; +} + +// EnvVarSource represents a source for the value of an EnvVar. +message EnvVarSource { + // Selects a field of the pod: supports metadata.name, metadata.namespace, metadata.labels, metadata.annotations, + // spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP. + // +optional + optional ObjectFieldSelector fieldRef = 1; + + // Selects a resource of the container: only resources limits and requests + // (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + // +optional + optional ResourceFieldSelector resourceFieldRef = 2; + + // Selects a key of a ConfigMap. + // +optional + optional ConfigMapKeySelector configMapKeyRef = 3; + + // Selects a key of a secret in the pod's namespace + // +optional + optional SecretKeySelector secretKeyRef = 4; +} + +// Event is a report of an event somewhere in the cluster. +message Event { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The object that this event is about. + optional ObjectReference involvedObject = 2; + + // This should be a short, machine understandable string that gives the reason + // for the transition into the object's current status. + // TODO: provide exact specification for format. + // +optional + optional string reason = 3; + + // A human-readable description of the status of this operation. + // TODO: decide on maximum length. + // +optional + optional string message = 4; + + // The component reporting this event. Should be a short machine understandable string. + // +optional + optional EventSource source = 5; + + // The time at which the event was first recorded. (Time of server receipt is in TypeMeta.) + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time firstTimestamp = 6; + + // The time at which the most recent occurrence of this event was recorded. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTimestamp = 7; + + // The number of times this event has occurred. + // +optional + optional int32 count = 8; + + // Type of this event (Normal, Warning), new types could be added in the future + // +optional + optional string type = 9; + + // Time when this Event was first observed. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.MicroTime eventTime = 10; + + // Data about the Event series this event represents or nil if it's a singleton Event. + // +optional + optional EventSeries series = 11; + + // What action was taken/failed regarding to the Regarding object. + // +optional + optional string action = 12; + + // Optional secondary object for more complex actions. + // +optional + optional ObjectReference related = 13; + + // Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`. + // +optional + optional string reportingComponent = 14; + + // ID of the controller instance, e.g. `kubelet-xyzf`. + // +optional + optional string reportingInstance = 15; +} + +// EventList is a list of events. +message EventList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of events + repeated Event items = 2; +} + +// EventSeries contain information on series of events, i.e. thing that was/is happening +// continuously for some time. +message EventSeries { + // Number of occurrences in this series up to the last heartbeat time + optional int32 count = 1; + + // Time of the last occurrence observed + optional k8s.io.apimachinery.pkg.apis.meta.v1.MicroTime lastObservedTime = 2; + + // State of this Series: Ongoing or Finished + optional string state = 3; +} + +// EventSource contains information for an event. +message EventSource { + // Component from which the event is generated. + // +optional + optional string component = 1; + + // Node name on which the event is generated. + // +optional + optional string host = 2; +} + +// ExecAction describes a "run in container" action. +message ExecAction { + // Command is the command line to execute inside the container, the working directory for the + // command is root ('/') in the container's filesystem. The command is simply exec'd, it is + // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + // a shell, you need to explicitly call out to that shell. + // Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + // +optional + repeated string command = 1; +} + +// Represents a Fibre Channel volume. +// Fibre Channel volumes can only be mounted as read/write once. +// Fibre Channel volumes support ownership management and SELinux relabeling. +message FCVolumeSource { + // Optional: FC target worldwide names (WWNs) + // +optional + repeated string targetWWNs = 1; + + // Optional: FC target lun number + // +optional + optional int32 lun = 2; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 3; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 4; + + // Optional: FC volume world wide identifiers (wwids) + // Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + // +optional + repeated string wwids = 5; +} + +// FlexPersistentVolumeSource represents a generic persistent volume resource that is +// provisioned/attached using an exec based plugin. +message FlexPersistentVolumeSource { + // Driver is the name of the driver to use for this volume. + optional string driver = 1; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + // +optional + optional string fsType = 2; + + // Optional: SecretRef is reference to the secret object containing + // sensitive information to pass to the plugin scripts. This may be + // empty if no secret object is specified. If the secret object + // contains more than one secret, all secrets are passed to the plugin + // scripts. + // +optional + optional SecretReference secretRef = 3; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 4; + + // Optional: Extra command options if any. + // +optional + map<string, string> options = 5; +} + +// FlexVolume represents a generic volume resource that is +// provisioned/attached using an exec based plugin. +message FlexVolumeSource { + // Driver is the name of the driver to use for this volume. + optional string driver = 1; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + // +optional + optional string fsType = 2; + + // Optional: SecretRef is reference to the secret object containing + // sensitive information to pass to the plugin scripts. This may be + // empty if no secret object is specified. If the secret object + // contains more than one secret, all secrets are passed to the plugin + // scripts. + // +optional + optional LocalObjectReference secretRef = 3; + + // Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 4; + + // Optional: Extra command options if any. + // +optional + map<string, string> options = 5; +} + +// Represents a Flocker volume mounted by the Flocker agent. +// One and only one of datasetName and datasetUUID should be set. +// Flocker volumes do not support ownership management or SELinux relabeling. +message FlockerVolumeSource { + // Name of the dataset stored as metadata -> name on the dataset for Flocker + // should be considered as deprecated + // +optional + optional string datasetName = 1; + + // UUID of the dataset. This is unique identifier of a Flocker dataset + // +optional + optional string datasetUUID = 2; +} + +// Represents a Persistent Disk resource in Google Compute Engine. +// +// A GCE PD must exist before mounting to a container. The disk must +// also be in the same GCE project and zone as the kubelet. A GCE PD +// can only be mounted as read/write once or read-only many times. GCE +// PDs support ownership management and SELinux relabeling. +message GCEPersistentDiskVolumeSource { + // Unique name of the PD resource in GCE. Used to identify the disk in GCE. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + optional string pdName = 1; + + // Filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 2; + + // The partition in the volume that you want to mount. + // If omitted, the default is to mount by volume name. + // Examples: For volume /dev/sda1, you specify the partition as "1". + // Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + optional int32 partition = 3; + + // ReadOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + optional bool readOnly = 4; +} + +// Represents a volume that is populated with the contents of a git repository. +// Git repo volumes do not support ownership management. +// Git repo volumes support SELinux relabeling. +// +// DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an +// EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir +// into the Pod's container. +message GitRepoVolumeSource { + // Repository URL + optional string repository = 1; + + // Commit hash for the specified revision. + // +optional + optional string revision = 2; + + // Target directory name. + // Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + // git repository. Otherwise, if specified, the volume will contain the git repository in + // the subdirectory with the given name. + // +optional + optional string directory = 3; +} + +// Represents a Glusterfs mount that lasts the lifetime of a pod. +// Glusterfs volumes do not support ownership management or SELinux relabeling. +message GlusterfsVolumeSource { + // EndpointsName is the endpoint name that details Glusterfs topology. + // More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md#create-a-pod + optional string endpoints = 1; + + // Path is the Glusterfs volume path. + // More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md#create-a-pod + optional string path = 2; + + // ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. + // Defaults to false. + // More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md#create-a-pod + // +optional + optional bool readOnly = 3; +} + +// HTTPGetAction describes an action based on HTTP Get requests. +message HTTPGetAction { + // Path to access on the HTTP server. + // +optional + optional string path = 1; + + // Name or number of the port to access on the container. + // Number must be in the range 1 to 65535. + // Name must be an IANA_SVC_NAME. + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString port = 2; + + // Host name to connect to, defaults to the pod IP. You probably want to set + // "Host" in httpHeaders instead. + // +optional + optional string host = 3; + + // Scheme to use for connecting to the host. + // Defaults to HTTP. + // +optional + optional string scheme = 4; + + // Custom headers to set in the request. HTTP allows repeated headers. + // +optional + repeated HTTPHeader httpHeaders = 5; +} + +// HTTPHeader describes a custom header to be used in HTTP probes +message HTTPHeader { + // The header field name + optional string name = 1; + + // The header field value + optional string value = 2; +} + +// Handler defines a specific action that should be taken +// TODO: pass structured data to these actions, and document that data here. +message Handler { + // One and only one of the following should be specified. + // Exec specifies the action to take. + // +optional + optional ExecAction exec = 1; + + // HTTPGet specifies the http request to perform. + // +optional + optional HTTPGetAction httpGet = 2; + + // TCPSocket specifies an action involving a TCP port. + // TCP hooks not yet supported + // TODO: implement a realistic TCP lifecycle hook + // +optional + optional TCPSocketAction tcpSocket = 3; +} + +// HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the +// pod's hosts file. +message HostAlias { + // IP address of the host file entry. + optional string ip = 1; + + // Hostnames for the above IP address. + repeated string hostnames = 2; +} + +// Represents a host path mapped into a pod. +// Host path volumes do not support ownership management or SELinux relabeling. +message HostPathVolumeSource { + // Path of the directory on the host. + // If the path is a symlink, it will follow the link to the real path. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + optional string path = 1; + + // Type for HostPath Volume + // Defaults to "" + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + // +optional + optional string type = 2; +} + +// ISCSIPersistentVolumeSource represents an ISCSI disk. +// ISCSI volumes can only be mounted as read/write once. +// ISCSI volumes support ownership management and SELinux relabeling. +message ISCSIPersistentVolumeSource { + // iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + // is other than default (typically TCP ports 860 and 3260). + optional string targetPortal = 1; + + // Target iSCSI Qualified Name. + optional string iqn = 2; + + // iSCSI Target Lun number. + optional int32 lun = 3; + + // iSCSI Interface Name that uses an iSCSI transport. + // Defaults to 'default' (tcp). + // +optional + optional string iscsiInterface = 4; + + // Filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 5; + + // ReadOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // +optional + optional bool readOnly = 6; + + // iSCSI Target Portal List. The Portal is either an IP or ip_addr:port if the port + // is other than default (typically TCP ports 860 and 3260). + // +optional + repeated string portals = 7; + + // whether support iSCSI Discovery CHAP authentication + // +optional + optional bool chapAuthDiscovery = 8; + + // whether support iSCSI Session CHAP authentication + // +optional + optional bool chapAuthSession = 11; + + // CHAP Secret for iSCSI target and initiator authentication + // +optional + optional SecretReference secretRef = 10; + + // Custom iSCSI Initiator Name. + // If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + // <target portal>:<volume name> will be created for the connection. + // +optional + optional string initiatorName = 12; +} + +// Represents an ISCSI disk. +// ISCSI volumes can only be mounted as read/write once. +// ISCSI volumes support ownership management and SELinux relabeling. +message ISCSIVolumeSource { + // iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + // is other than default (typically TCP ports 860 and 3260). + optional string targetPortal = 1; + + // Target iSCSI Qualified Name. + optional string iqn = 2; + + // iSCSI Target Lun number. + optional int32 lun = 3; + + // iSCSI Interface Name that uses an iSCSI transport. + // Defaults to 'default' (tcp). + // +optional + optional string iscsiInterface = 4; + + // Filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 5; + + // ReadOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // +optional + optional bool readOnly = 6; + + // iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + // is other than default (typically TCP ports 860 and 3260). + // +optional + repeated string portals = 7; + + // whether support iSCSI Discovery CHAP authentication + // +optional + optional bool chapAuthDiscovery = 8; + + // whether support iSCSI Session CHAP authentication + // +optional + optional bool chapAuthSession = 11; + + // CHAP Secret for iSCSI target and initiator authentication + // +optional + optional LocalObjectReference secretRef = 10; + + // Custom iSCSI Initiator Name. + // If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + // <target portal>:<volume name> will be created for the connection. + // +optional + optional string initiatorName = 12; +} + +// Maps a string key to a path within a volume. +message KeyToPath { + // The key to project. + optional string key = 1; + + // The relative path of the file to map the key to. + // May not be an absolute path. + // May not contain the path element '..'. + // May not start with the string '..'. + optional string path = 2; + + // Optional: mode bits to use on this file, must be a value between 0 + // and 0777. If not specified, the volume defaultMode will be used. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + optional int32 mode = 3; +} + +// Lifecycle describes actions that the management system should take in response to container lifecycle +// events. For the PostStart and PreStop lifecycle handlers, management of the container blocks +// until the action is complete, unless the container process fails, in which case the handler is aborted. +message Lifecycle { + // PostStart is called immediately after a container is created. If the handler fails, + // the container is terminated and restarted according to its restart policy. + // Other management of the container blocks until the hook completes. + // More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + // +optional + optional Handler postStart = 1; + + // PreStop is called immediately before a container is terminated. + // The container is terminated after the handler completes. + // The reason for termination is passed to the handler. + // Regardless of the outcome of the handler, the container is eventually terminated. + // Other management of the container blocks until the hook completes. + // More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + // +optional + optional Handler preStop = 2; +} + +// LimitRange sets resource usage limits for each kind of resource in a Namespace. +message LimitRange { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the limits enforced. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional LimitRangeSpec spec = 2; +} + +// LimitRangeItem defines a min/max usage limit for any resource that matches on kind. +message LimitRangeItem { + // Type of resource that this limit applies to. + // +optional + optional string type = 1; + + // Max usage constraints on this kind by resource name. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> max = 2; + + // Min usage constraints on this kind by resource name. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> min = 3; + + // Default resource requirement limit value by resource name if resource limit is omitted. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> default = 4; + + // DefaultRequest is the default resource requirement request value by resource name if resource request is omitted. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> defaultRequest = 5; + + // MaxLimitRequestRatio if specified, the named resource must have a request and limit that are both non-zero where limit divided by request is less than or equal to the enumerated value; this represents the max burst for the named resource. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> maxLimitRequestRatio = 6; +} + +// LimitRangeList is a list of LimitRange items. +message LimitRangeList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of LimitRange objects. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + repeated LimitRange items = 2; +} + +// LimitRangeSpec defines a min/max usage limit for resources that match on kind. +message LimitRangeSpec { + // Limits is the list of LimitRangeItem objects that are enforced. + repeated LimitRangeItem limits = 1; +} + +// List holds a list of objects, which may not be known by the server. +message List { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of objects + repeated k8s.io.apimachinery.pkg.runtime.RawExtension items = 2; +} + +// LoadBalancerIngress represents the status of a load-balancer ingress point: +// traffic intended for the service should be sent to an ingress point. +message LoadBalancerIngress { + // IP is set for load-balancer ingress points that are IP based + // (typically GCE or OpenStack load-balancers) + // +optional + optional string ip = 1; + + // Hostname is set for load-balancer ingress points that are DNS based + // (typically AWS load-balancers) + // +optional + optional string hostname = 2; +} + +// LoadBalancerStatus represents the status of a load-balancer. +message LoadBalancerStatus { + // Ingress is a list containing ingress points for the load-balancer. + // Traffic intended for the service should be sent to these ingress points. + // +optional + repeated LoadBalancerIngress ingress = 1; +} + +// LocalObjectReference contains enough information to let you locate the +// referenced object inside the same namespace. +message LocalObjectReference { + // Name of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // TODO: Add other useful fields. apiVersion, kind, uid? + // +optional + optional string name = 1; +} + +// Local represents directly-attached storage with node affinity (Beta feature) +message LocalVolumeSource { + // The full path to the volume on the node. + // It can be either a directory or block device (disk, partition, ...). + optional string path = 1; + + // Filesystem type to mount. + // It applies only when the Path is a block device. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default value is to auto-select a fileystem if unspecified. + // +optional + optional string fsType = 2; +} + +// Represents an NFS mount that lasts the lifetime of a pod. +// NFS volumes do not support ownership management or SELinux relabeling. +message NFSVolumeSource { + // Server is the hostname or IP address of the NFS server. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + optional string server = 1; + + // Path that is exported by the NFS server. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + optional string path = 2; + + // ReadOnly here will force + // the NFS export to be mounted with read-only permissions. + // Defaults to false. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + // +optional + optional bool readOnly = 3; +} + +// Namespace provides a scope for Names. +// Use of multiple namespaces is optional. +message Namespace { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the behavior of the Namespace. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional NamespaceSpec spec = 2; + + // Status describes the current status of a Namespace. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional NamespaceStatus status = 3; +} + +// NamespaceList is a list of Namespaces. +message NamespaceList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of Namespace objects in the list. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + repeated Namespace items = 2; +} + +// NamespaceSpec describes the attributes on a Namespace. +message NamespaceSpec { + // Finalizers is an opaque list of values that must be empty to permanently remove object from storage. + // More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/ + // +optional + repeated string finalizers = 1; +} + +// NamespaceStatus is information about the current status of a Namespace. +message NamespaceStatus { + // Phase is the current lifecycle phase of the namespace. + // More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/ + // +optional + optional string phase = 1; +} + +// Node is a worker node in Kubernetes. +// Each node will have a unique identifier in the cache (i.e. in etcd). +message Node { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the behavior of a node. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional NodeSpec spec = 2; + + // Most recently observed status of the node. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional NodeStatus status = 3; +} + +// NodeAddress contains information for the node's address. +message NodeAddress { + // Node address type, one of Hostname, ExternalIP or InternalIP. + optional string type = 1; + + // The node address. + optional string address = 2; +} + +// Node affinity is a group of node affinity scheduling rules. +message NodeAffinity { + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to an update), the system + // may or may not try to eventually evict the pod from its node. + // +optional + optional NodeSelector requiredDuringSchedulingIgnoredDuringExecution = 1; + + // The scheduler will prefer to schedule pods to nodes that satisfy + // the affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node matches the corresponding matchExpressions; the + // node(s) with the highest sum are the most preferred. + // +optional + repeated PreferredSchedulingTerm preferredDuringSchedulingIgnoredDuringExecution = 2; +} + +// NodeCondition contains condition information for a node. +message NodeCondition { + // Type of node condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time we got an update on a given condition. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastHeartbeatTime = 3; + + // Last time the condition transit from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 4; + + // (brief) reason for the condition's last transition. + // +optional + optional string reason = 5; + + // Human readable message indicating details about last transition. + // +optional + optional string message = 6; +} + +// NodeConfigSource specifies a source of node configuration. Exactly one subfield (excluding metadata) must be non-nil. +message NodeConfigSource { + // ConfigMap is a reference to a Node's ConfigMap + optional ConfigMapNodeConfigSource configMap = 2; +} + +// NodeConfigStatus describes the status of the config assigned by Node.Spec.ConfigSource. +message NodeConfigStatus { + // Assigned reports the checkpointed config the node will try to use. + // When Node.Spec.ConfigSource is updated, the node checkpoints the associated + // config payload to local disk, along with a record indicating intended + // config. The node refers to this record to choose its config checkpoint, and + // reports this record in Assigned. Assigned only updates in the status after + // the record has been checkpointed to disk. When the Kubelet is restarted, + // it tries to make the Assigned config the Active config by loading and + // validating the checkpointed payload identified by Assigned. + // +optional + optional NodeConfigSource assigned = 1; + + // Active reports the checkpointed config the node is actively using. + // Active will represent either the current version of the Assigned config, + // or the current LastKnownGood config, depending on whether attempting to use the + // Assigned config results in an error. + // +optional + optional NodeConfigSource active = 2; + + // LastKnownGood reports the checkpointed config the node will fall back to + // when it encounters an error attempting to use the Assigned config. + // The Assigned config becomes the LastKnownGood config when the node determines + // that the Assigned config is stable and correct. + // This is currently implemented as a 10-minute soak period starting when the local + // record of Assigned config is updated. If the Assigned config is Active at the end + // of this period, it becomes the LastKnownGood. Note that if Spec.ConfigSource is + // reset to nil (use local defaults), the LastKnownGood is also immediately reset to nil, + // because the local default config is always assumed good. + // You should not make assumptions about the node's method of determining config stability + // and correctness, as this may change or become configurable in the future. + // +optional + optional NodeConfigSource lastKnownGood = 3; + + // Error describes any problems reconciling the Spec.ConfigSource to the Active config. + // Errors may occur, for example, attempting to checkpoint Spec.ConfigSource to the local Assigned + // record, attempting to checkpoint the payload associated with Spec.ConfigSource, attempting + // to load or validate the Assigned config, etc. + // Errors may occur at different points while syncing config. Earlier errors (e.g. download or + // checkpointing errors) will not result in a rollback to LastKnownGood, and may resolve across + // Kubelet retries. Later errors (e.g. loading or validating a checkpointed config) will result in + // a rollback to LastKnownGood. In the latter case, it is usually possible to resolve the error + // by fixing the config assigned in Spec.ConfigSource. + // You can find additional information for debugging by searching the error message in the Kubelet log. + // Error is a human-readable description of the error state; machines can check whether or not Error + // is empty, but should not rely on the stability of the Error text across Kubelet versions. + // +optional + optional string error = 4; +} + +// NodeDaemonEndpoints lists ports opened by daemons running on the Node. +message NodeDaemonEndpoints { + // Endpoint on which Kubelet is listening. + // +optional + optional DaemonEndpoint kubeletEndpoint = 1; +} + +// NodeList is the whole list of all Nodes which have been registered with master. +message NodeList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of nodes + repeated Node items = 2; +} + +// NodeProxyOptions is the query options to a Node's proxy call. +message NodeProxyOptions { + // Path is the URL path to use for the current proxy request to node. + // +optional + optional string path = 1; +} + +// NodeResources is an object for conveying resource information about a node. +// see http://releases.k8s.io/HEAD/docs/design/resources.md for more details. +message NodeResources { + // Capacity represents the available resources of a node + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> capacity = 1; +} + +// A node selector represents the union of the results of one or more label queries +// over a set of nodes; that is, it represents the OR of the selectors represented +// by the node selector terms. +message NodeSelector { + // Required. A list of node selector terms. The terms are ORed. + repeated NodeSelectorTerm nodeSelectorTerms = 1; +} + +// A node selector requirement is a selector that contains values, a key, and an operator +// that relates the key and values. +message NodeSelectorRequirement { + // The label key that the selector applies to. + optional string key = 1; + + // Represents a key's relationship to a set of values. + // Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + optional string operator = 2; + + // An array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. If the operator is Gt or Lt, the values + // array must have a single element, which will be interpreted as an integer. + // This array is replaced during a strategic merge patch. + // +optional + repeated string values = 3; +} + +// A null or empty node selector term matches no objects. The requirements of +// them are ANDed. +// The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. +message NodeSelectorTerm { + // A list of node selector requirements by node's labels. + // +optional + repeated NodeSelectorRequirement matchExpressions = 1; + + // A list of node selector requirements by node's fields. + // +optional + repeated NodeSelectorRequirement matchFields = 2; +} + +// NodeSpec describes the attributes that a node is created with. +message NodeSpec { + // PodCIDR represents the pod IP range assigned to the node. + // +optional + optional string podCIDR = 1; + + // ID of the node assigned by the cloud provider in the format: <ProviderName>://<ProviderSpecificNodeID> + // +optional + optional string providerID = 3; + + // Unschedulable controls node schedulability of new pods. By default, node is schedulable. + // More info: https://kubernetes.io/docs/concepts/nodes/node/#manual-node-administration + // +optional + optional bool unschedulable = 4; + + // If specified, the node's taints. + // +optional + repeated Taint taints = 5; + + // If specified, the source to get node configuration from + // The DynamicKubeletConfig feature gate must be enabled for the Kubelet to use this field + // +optional + optional NodeConfigSource configSource = 6; + + // Deprecated. Not all kubelets will set this field. Remove field after 1.13. + // see: https://issues.k8s.io/61966 + // +optional + optional string externalID = 2; +} + +// NodeStatus is information about the current status of a node. +message NodeStatus { + // Capacity represents the total resources of a node. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> capacity = 1; + + // Allocatable represents the resources of a node that are available for scheduling. + // Defaults to Capacity. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> allocatable = 2; + + // NodePhase is the recently observed lifecycle phase of the node. + // More info: https://kubernetes.io/docs/concepts/nodes/node/#phase + // The field is never populated, and now is deprecated. + // +optional + optional string phase = 3; + + // Conditions is an array of current observed node conditions. + // More info: https://kubernetes.io/docs/concepts/nodes/node/#condition + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated NodeCondition conditions = 4; + + // List of addresses reachable to the node. + // Queried from cloud provider, if available. + // More info: https://kubernetes.io/docs/concepts/nodes/node/#addresses + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated NodeAddress addresses = 5; + + // Endpoints of daemons running on the Node. + // +optional + optional NodeDaemonEndpoints daemonEndpoints = 6; + + // Set of ids/uuids to uniquely identify the node. + // More info: https://kubernetes.io/docs/concepts/nodes/node/#info + // +optional + optional NodeSystemInfo nodeInfo = 7; + + // List of container images on this node + // +optional + repeated ContainerImage images = 8; + + // List of attachable volumes in use (mounted) by the node. + // +optional + repeated string volumesInUse = 9; + + // List of volumes that are attached to the node. + // +optional + repeated AttachedVolume volumesAttached = 10; + + // Status of the config assigned to the node via the dynamic Kubelet config feature. + // +optional + optional NodeConfigStatus config = 11; +} + +// NodeSystemInfo is a set of ids/uuids to uniquely identify the node. +message NodeSystemInfo { + // MachineID reported by the node. For unique machine identification + // in the cluster this field is preferred. Learn more from man(5) + // machine-id: http://man7.org/linux/man-pages/man5/machine-id.5.html + optional string machineID = 1; + + // SystemUUID reported by the node. For unique machine identification + // MachineID is preferred. This field is specific to Red Hat hosts + // https://access.redhat.com/documentation/en-US/Red_Hat_Subscription_Management/1/html/RHSM/getting-system-uuid.html + optional string systemUUID = 2; + + // Boot ID reported by the node. + optional string bootID = 3; + + // Kernel Version reported by the node from 'uname -r' (e.g. 3.16.0-0.bpo.4-amd64). + optional string kernelVersion = 4; + + // OS Image reported by the node from /etc/os-release (e.g. Debian GNU/Linux 7 (wheezy)). + optional string osImage = 5; + + // ContainerRuntime Version reported by the node through runtime remote API (e.g. docker://1.5.0). + optional string containerRuntimeVersion = 6; + + // Kubelet Version reported by the node. + optional string kubeletVersion = 7; + + // KubeProxy Version reported by the node. + optional string kubeProxyVersion = 8; + + // The Operating System reported by the node + optional string operatingSystem = 9; + + // The Architecture reported by the node + optional string architecture = 10; +} + +// ObjectFieldSelector selects an APIVersioned field of an object. +message ObjectFieldSelector { + // Version of the schema the FieldPath is written in terms of, defaults to "v1". + // +optional + optional string apiVersion = 1; + + // Path of the field to select in the specified API version. + optional string fieldPath = 2; +} + +// ObjectReference contains enough information to let you inspect or modify the referred object. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +message ObjectReference { + // Kind of the referent. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional string kind = 1; + + // Namespace of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + // +optional + optional string namespace = 2; + + // Name of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + optional string name = 3; + + // UID of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + // +optional + optional string uid = 4; + + // API version of the referent. + // +optional + optional string apiVersion = 5; + + // Specific resourceVersion to which this reference is made, if any. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency + // +optional + optional string resourceVersion = 6; + + // If referring to a piece of an object instead of an entire object, this string + // should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + // For example, if the object reference is to a container within a pod, this would take on a value like: + // "spec.containers{name}" (where "name" refers to the name of the container that triggered + // the event) or if no container name is specified "spec.containers[2]" (container with + // index 2 in this pod). This syntax is chosen only to have some well-defined way of + // referencing a part of an object. + // TODO: this design is not final and this field is subject to change in the future. + // +optional + optional string fieldPath = 7; +} + +// PersistentVolume (PV) is a storage resource provisioned by an administrator. +// It is analogous to a node. +// More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes +message PersistentVolume { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines a specification of a persistent volume owned by the cluster. + // Provisioned by an administrator. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes + // +optional + optional PersistentVolumeSpec spec = 2; + + // Status represents the current information/status for the persistent volume. + // Populated by the system. + // Read-only. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistent-volumes + // +optional + optional PersistentVolumeStatus status = 3; +} + +// PersistentVolumeClaim is a user's request for and claim to a persistent volume +message PersistentVolumeClaim { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the desired characteristics of a volume requested by a pod author. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + optional PersistentVolumeClaimSpec spec = 2; + + // Status represents the current information/status of a persistent volume claim. + // Read-only. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + optional PersistentVolumeClaimStatus status = 3; +} + +// PersistentVolumeClaimCondition contails details about state of pvc +message PersistentVolumeClaimCondition { + optional string type = 1; + + optional string status = 2; + + // Last time we probed the condition. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastProbeTime = 3; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 4; + + // Unique, this should be a short, machine understandable string that gives the reason + // for condition's last transition. If it reports "ResizeStarted" that means the underlying + // persistent volume is being resized. + // +optional + optional string reason = 5; + + // Human-readable message indicating details about last transition. + // +optional + optional string message = 6; +} + +// PersistentVolumeClaimList is a list of PersistentVolumeClaim items. +message PersistentVolumeClaimList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // A list of persistent volume claims. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + repeated PersistentVolumeClaim items = 2; +} + +// PersistentVolumeClaimSpec describes the common attributes of storage devices +// and allows a Source for provider-specific attributes +message PersistentVolumeClaimSpec { + // AccessModes contains the desired access modes the volume should have. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + // +optional + repeated string accessModes = 1; + + // A label query over volumes to consider for binding. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 4; + + // Resources represents the minimum resources the volume should have. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + // +optional + optional ResourceRequirements resources = 2; + + // VolumeName is the binding reference to the PersistentVolume backing this claim. + // +optional + optional string volumeName = 3; + + // Name of the StorageClass required by the claim. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + // +optional + optional string storageClassName = 5; + + // volumeMode defines what type of volume is required by the claim. + // Value of Filesystem is implied when not included in claim spec. + // This is an alpha feature and may change in the future. + // +optional + optional string volumeMode = 6; + + // This field requires the VolumeSnapshotDataSource alpha feature gate to be + // enabled and currently VolumeSnapshot is the only supported data source. + // If the provisioner can support VolumeSnapshot data source, it will create + // a new volume and data will be restored to the volume at the same time. + // If the provisioner does not support VolumeSnapshot data source, volume will + // not be created and the failure will be reported as an event. + // In the future, we plan to support more data source types and the behavior + // of the provisioner may change. + // +optional + optional TypedLocalObjectReference dataSource = 7; +} + +// PersistentVolumeClaimStatus is the current status of a persistent volume claim. +message PersistentVolumeClaimStatus { + // Phase represents the current phase of PersistentVolumeClaim. + // +optional + optional string phase = 1; + + // AccessModes contains the actual access modes the volume backing the PVC has. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + // +optional + repeated string accessModes = 2; + + // Represents the actual resources of the underlying volume. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> capacity = 3; + + // Current Condition of persistent volume claim. If underlying persistent volume is being + // resized then the Condition will be set to 'ResizeStarted'. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated PersistentVolumeClaimCondition conditions = 4; +} + +// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace. +// This volume finds the bound PV and mounts that volume for the pod. A +// PersistentVolumeClaimVolumeSource is, essentially, a wrapper around another +// type of volume that is owned by someone else (the system). +message PersistentVolumeClaimVolumeSource { + // ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + optional string claimName = 1; + + // Will force the ReadOnly setting in VolumeMounts. + // Default false. + // +optional + optional bool readOnly = 2; +} + +// PersistentVolumeList is a list of PersistentVolume items. +message PersistentVolumeList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of persistent volumes. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes + repeated PersistentVolume items = 2; +} + +// PersistentVolumeSource is similar to VolumeSource but meant for the +// administrator who creates PVs. Exactly one of its members must be set. +message PersistentVolumeSource { + // GCEPersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. Provisioned by an admin. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + optional GCEPersistentDiskVolumeSource gcePersistentDisk = 1; + + // AWSElasticBlockStore represents an AWS Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // +optional + optional AWSElasticBlockStoreVolumeSource awsElasticBlockStore = 2; + + // HostPath represents a directory on the host. + // Provisioned by a developer or tester. + // This is useful for single-node development and testing only! + // On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + // +optional + optional HostPathVolumeSource hostPath = 3; + + // Glusterfs represents a Glusterfs volume that is attached to a host and + // exposed to the pod. Provisioned by an admin. + // More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md + // +optional + optional GlusterfsVolumeSource glusterfs = 4; + + // NFS represents an NFS mount on the host. Provisioned by an admin. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + // +optional + optional NFSVolumeSource nfs = 5; + + // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md + // +optional + optional RBDPersistentVolumeSource rbd = 6; + + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. Provisioned by an admin. + // +optional + optional ISCSIPersistentVolumeSource iscsi = 7; + + // Cinder represents a cinder volume attached and mounted on kubelets host machine + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + // +optional + optional CinderPersistentVolumeSource cinder = 8; + + // CephFS represents a Ceph FS mount on the host that shares a pod's lifetime + // +optional + optional CephFSPersistentVolumeSource cephfs = 9; + + // FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + // +optional + optional FCVolumeSource fc = 10; + + // Flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running + // +optional + optional FlockerVolumeSource flocker = 11; + + // FlexVolume represents a generic volume resource that is + // provisioned/attached using an exec based plugin. + // +optional + optional FlexPersistentVolumeSource flexVolume = 12; + + // AzureFile represents an Azure File Service mount on the host and bind mount to the pod. + // +optional + optional AzureFilePersistentVolumeSource azureFile = 13; + + // VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine + // +optional + optional VsphereVirtualDiskVolumeSource vsphereVolume = 14; + + // Quobyte represents a Quobyte mount on the host that shares a pod's lifetime + // +optional + optional QuobyteVolumeSource quobyte = 15; + + // AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + // +optional + optional AzureDiskVolumeSource azureDisk = 16; + + // PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine + optional PhotonPersistentDiskVolumeSource photonPersistentDisk = 17; + + // PortworxVolume represents a portworx volume attached and mounted on kubelets host machine + // +optional + optional PortworxVolumeSource portworxVolume = 18; + + // ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + // +optional + optional ScaleIOPersistentVolumeSource scaleIO = 19; + + // Local represents directly-attached storage with node affinity + // +optional + optional LocalVolumeSource local = 20; + + // StorageOS represents a StorageOS volume that is attached to the kubelet's host machine and mounted into the pod + // More info: https://releases.k8s.io/HEAD/examples/volumes/storageos/README.md + // +optional + optional StorageOSPersistentVolumeSource storageos = 21; + + // CSI represents storage that handled by an external CSI driver (Beta feature). + // +optional + optional CSIPersistentVolumeSource csi = 22; +} + +// PersistentVolumeSpec is the specification of a persistent volume. +message PersistentVolumeSpec { + // A description of the persistent volume's resources and capacity. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> capacity = 1; + + // The actual volume backing the persistent volume. + optional PersistentVolumeSource persistentVolumeSource = 2; + + // AccessModes contains all ways the volume can be mounted. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes + // +optional + repeated string accessModes = 3; + + // ClaimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. + // Expected to be non-nil when bound. + // claim.VolumeName is the authoritative bind between PV and PVC. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#binding + // +optional + optional ObjectReference claimRef = 4; + + // What happens to a persistent volume when released from its claim. + // Valid options are Retain (default for manually created PersistentVolumes), Delete (default + // for dynamically provisioned PersistentVolumes), and Recycle (deprecated). + // Recycle must be supported by the volume plugin underlying this PersistentVolume. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming + // +optional + optional string persistentVolumeReclaimPolicy = 5; + + // Name of StorageClass to which this persistent volume belongs. Empty value + // means that this volume does not belong to any StorageClass. + // +optional + optional string storageClassName = 6; + + // A list of mount options, e.g. ["ro", "soft"]. Not validated - mount will + // simply fail if one is invalid. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#mount-options + // +optional + repeated string mountOptions = 7; + + // volumeMode defines if a volume is intended to be used with a formatted filesystem + // or to remain in raw block state. Value of Filesystem is implied when not included in spec. + // This is an alpha feature and may change in the future. + // +optional + optional string volumeMode = 8; + + // NodeAffinity defines constraints that limit what nodes this volume can be accessed from. + // This field influences the scheduling of pods that use this volume. + // +optional + optional VolumeNodeAffinity nodeAffinity = 9; +} + +// PersistentVolumeStatus is the current status of a persistent volume. +message PersistentVolumeStatus { + // Phase indicates if a volume is available, bound to a claim, or released by a claim. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#phase + // +optional + optional string phase = 1; + + // A human-readable message indicating details about why the volume is in this state. + // +optional + optional string message = 2; + + // Reason is a brief CamelCase string that describes any failure and is meant + // for machine parsing and tidy display in the CLI. + // +optional + optional string reason = 3; +} + +// Represents a Photon Controller persistent disk resource. +message PhotonPersistentDiskVolumeSource { + // ID that identifies Photon Controller persistent disk + optional string pdID = 1; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + optional string fsType = 2; +} + +// Pod is a collection of containers that can run on a host. This resource is created +// by clients and scheduled onto hosts. +message Pod { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the pod. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional PodSpec spec = 2; + + // Most recently observed status of the pod. + // This data may not be up to date. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional PodStatus status = 3; +} + +// Pod affinity is a group of inter pod affinity scheduling rules. +message PodAffinity { + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system may or may not try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + repeated PodAffinityTerm requiredDuringSchedulingIgnoredDuringExecution = 1; + + // The scheduler will prefer to schedule pods to nodes that satisfy + // the affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + // node(s) with the highest sum are the most preferred. + // +optional + repeated WeightedPodAffinityTerm preferredDuringSchedulingIgnoredDuringExecution = 2; +} + +// Defines a set of pods (namely those matching the labelSelector +// relative to the given namespace(s)) that this pod should be +// co-located (affinity) or not co-located (anti-affinity) with, +// where co-located is defined as running on a node whose value of +// the label with key <topologyKey> matches that of any node on which +// a pod of the set of pods is running +message PodAffinityTerm { + // A label query over a set of resources, in this case pods. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector labelSelector = 1; + + // namespaces specifies which namespaces the labelSelector applies to (matches against); + // null or empty list means "this pod's namespace" + // +optional + repeated string namespaces = 2; + + // This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + // the labelSelector in the specified namespaces, where co-located is defined as running on a node + // whose value of the label with key topologyKey matches that of any node on which any of the + // selected pods is running. + // Empty topologyKey is not allowed. + optional string topologyKey = 3; +} + +// Pod anti affinity is a group of inter pod anti affinity scheduling rules. +message PodAntiAffinity { + // If the anti-affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the anti-affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system may or may not try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + repeated PodAffinityTerm requiredDuringSchedulingIgnoredDuringExecution = 1; + + // The scheduler will prefer to schedule pods to nodes that satisfy + // the anti-affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling anti-affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + // node(s) with the highest sum are the most preferred. + // +optional + repeated WeightedPodAffinityTerm preferredDuringSchedulingIgnoredDuringExecution = 2; +} + +// PodAttachOptions is the query options to a Pod's remote attach call. +// --- +// TODO: merge w/ PodExecOptions below for stdin, stdout, etc +// and also when we cut V2, we should export a "StreamOptions" or somesuch that contains Stdin, Stdout, Stder and TTY +message PodAttachOptions { + // Stdin if true, redirects the standard input stream of the pod for this call. + // Defaults to false. + // +optional + optional bool stdin = 1; + + // Stdout if true indicates that stdout is to be redirected for the attach call. + // Defaults to true. + // +optional + optional bool stdout = 2; + + // Stderr if true indicates that stderr is to be redirected for the attach call. + // Defaults to true. + // +optional + optional bool stderr = 3; + + // TTY if true indicates that a tty will be allocated for the attach call. + // This is passed through the container runtime so the tty + // is allocated on the worker node by the container runtime. + // Defaults to false. + // +optional + optional bool tty = 4; + + // The container in which to execute the command. + // Defaults to only container if there is only one container in the pod. + // +optional + optional string container = 5; +} + +// PodCondition contains details for the current condition of this pod. +message PodCondition { + // Type is the type of the condition. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + optional string type = 1; + + // Status is the status of the condition. + // Can be True, False, Unknown. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + optional string status = 2; + + // Last time we probed the condition. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastProbeTime = 3; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 4; + + // Unique, one-word, CamelCase reason for the condition's last transition. + // +optional + optional string reason = 5; + + // Human-readable message indicating details about last transition. + // +optional + optional string message = 6; +} + +// PodDNSConfig defines the DNS parameters of a pod in addition to +// those generated from DNSPolicy. +message PodDNSConfig { + // A list of DNS name server IP addresses. + // This will be appended to the base nameservers generated from DNSPolicy. + // Duplicated nameservers will be removed. + // +optional + repeated string nameservers = 1; + + // A list of DNS search domains for host-name lookup. + // This will be appended to the base search paths generated from DNSPolicy. + // Duplicated search paths will be removed. + // +optional + repeated string searches = 2; + + // A list of DNS resolver options. + // This will be merged with the base options generated from DNSPolicy. + // Duplicated entries will be removed. Resolution options given in Options + // will override those that appear in the base DNSPolicy. + // +optional + repeated PodDNSConfigOption options = 3; +} + +// PodDNSConfigOption defines DNS resolver options of a pod. +message PodDNSConfigOption { + // Required. + optional string name = 1; + + // +optional + optional string value = 2; +} + +// PodExecOptions is the query options to a Pod's remote exec call. +// --- +// TODO: This is largely identical to PodAttachOptions above, make sure they stay in sync and see about merging +// and also when we cut V2, we should export a "StreamOptions" or somesuch that contains Stdin, Stdout, Stder and TTY +message PodExecOptions { + // Redirect the standard input stream of the pod for this call. + // Defaults to false. + // +optional + optional bool stdin = 1; + + // Redirect the standard output stream of the pod for this call. + // Defaults to true. + // +optional + optional bool stdout = 2; + + // Redirect the standard error stream of the pod for this call. + // Defaults to true. + // +optional + optional bool stderr = 3; + + // TTY if true indicates that a tty will be allocated for the exec call. + // Defaults to false. + // +optional + optional bool tty = 4; + + // Container in which to execute the command. + // Defaults to only container if there is only one container in the pod. + // +optional + optional string container = 5; + + // Command is the remote command to execute. argv array. Not executed within a shell. + repeated string command = 6; +} + +// PodList is a list of Pods. +message PodList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of pods. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md + repeated Pod items = 2; +} + +// PodLogOptions is the query options for a Pod's logs REST call. +message PodLogOptions { + // The container for which to stream logs. Defaults to only container if there is one container in the pod. + // +optional + optional string container = 1; + + // Follow the log stream of the pod. Defaults to false. + // +optional + optional bool follow = 2; + + // Return previous terminated container logs. Defaults to false. + // +optional + optional bool previous = 3; + + // A relative time in seconds before the current time from which to show logs. If this value + // precedes the time a pod was started, only logs since the pod start will be returned. + // If this value is in the future, no logs will be returned. + // Only one of sinceSeconds or sinceTime may be specified. + // +optional + optional int64 sinceSeconds = 4; + + // An RFC3339 timestamp from which to show logs. If this value + // precedes the time a pod was started, only logs since the pod start will be returned. + // If this value is in the future, no logs will be returned. + // Only one of sinceSeconds or sinceTime may be specified. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time sinceTime = 5; + + // If true, add an RFC3339 or RFC3339Nano timestamp at the beginning of every line + // of log output. Defaults to false. + // +optional + optional bool timestamps = 6; + + // If set, the number of lines from the end of the logs to show. If not specified, + // logs are shown from the creation of the container or sinceSeconds or sinceTime + // +optional + optional int64 tailLines = 7; + + // If set, the number of bytes to read from the server before terminating the + // log output. This may not display a complete final line of logging, and may return + // slightly more or slightly less than the specified limit. + // +optional + optional int64 limitBytes = 8; +} + +// PodPortForwardOptions is the query options to a Pod's port forward call +// when using WebSockets. +// The `port` query parameter must specify the port or +// ports (comma separated) to forward over. +// Port forwarding over SPDY does not use these options. It requires the port +// to be passed in the `port` header as part of request. +message PodPortForwardOptions { + // List of ports to forward + // Required when using WebSockets + // +optional + repeated int32 ports = 1; +} + +// PodProxyOptions is the query options to a Pod's proxy call. +message PodProxyOptions { + // Path is the URL path to use for the current proxy request to pod. + // +optional + optional string path = 1; +} + +// PodReadinessGate contains the reference to a pod condition +message PodReadinessGate { + // ConditionType refers to a condition in the pod's condition list with matching type. + optional string conditionType = 1; +} + +// PodSecurityContext holds pod-level security attributes and common container settings. +// Some fields are also present in container.securityContext. Field values of +// container.securityContext take precedence over field values of PodSecurityContext. +message PodSecurityContext { + // The SELinux context to be applied to all containers. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container. May also be set in SecurityContext. If set in + // both SecurityContext and PodSecurityContext, the value specified in SecurityContext + // takes precedence for that container. + // +optional + optional SELinuxOptions seLinuxOptions = 1; + + // The UID to run the entrypoint of the container process. + // Defaults to user specified in image metadata if unspecified. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // +optional + optional int64 runAsUser = 2; + + // The GID to run the entrypoint of the container process. + // Uses runtime default if unset. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // +optional + optional int64 runAsGroup = 6; + + // Indicates that the container must run as a non-root user. + // If true, the Kubelet will validate the image at runtime to ensure that it + // does not run as UID 0 (root) and fail to start the container if it does. + // If unset or false, no such validation will be performed. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + optional bool runAsNonRoot = 3; + + // A list of groups applied to the first process run in each container, in addition + // to the container's primary GID. If unspecified, no groups will be added to + // any container. + // +optional + repeated int64 supplementalGroups = 4; + + // A special supplemental group that applies to all containers in a pod. + // Some volume types allow the Kubelet to change the ownership of that volume + // to be owned by the pod: + // + // 1. The owning GID will be the FSGroup + // 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + // 3. The permission bits are OR'd with rw-rw---- + // + // If unset, the Kubelet will not modify the ownership and permissions of any volume. + // +optional + optional int64 fsGroup = 5; + + // Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + // sysctls (by the container runtime) might fail to launch. + // +optional + repeated Sysctl sysctls = 7; +} + +// Describes the class of pods that should avoid this node. +// Exactly one field should be set. +message PodSignature { + // Reference to controller whose pods should avoid this node. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.OwnerReference podController = 1; +} + +// PodSpec is a description of a pod. +message PodSpec { + // List of volumes that can be mounted by containers belonging to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes + // +optional + // +patchMergeKey=name + // +patchStrategy=merge,retainKeys + repeated Volume volumes = 1; + + // List of initialization containers belonging to the pod. + // Init containers are executed in order prior to containers being started. If any + // init container fails, the pod is considered to have failed and is handled according + // to its restartPolicy. The name for an init container or normal container must be + // unique among all containers. + // Init containers may not have Lifecycle actions, Readiness probes, or Liveness probes. + // The resourceRequirements of an init container are taken into account during scheduling + // by finding the highest request/limit for each resource type, and then using the max of + // of that value or the sum of the normal containers. Limits are applied to init containers + // in a similar fashion. + // Init containers cannot currently be added or removed. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + // +patchMergeKey=name + // +patchStrategy=merge + repeated Container initContainers = 20; + + // List of containers belonging to the pod. + // Containers cannot currently be added or removed. + // There must be at least one container in a Pod. + // Cannot be updated. + // +patchMergeKey=name + // +patchStrategy=merge + repeated Container containers = 2; + + // Restart policy for all containers within the pod. + // One of Always, OnFailure, Never. + // Default to Always. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy + // +optional + optional string restartPolicy = 3; + + // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. + // Value must be non-negative integer. The value zero indicates delete immediately. + // If this value is nil, the default grace period will be used instead. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // Defaults to 30 seconds. + // +optional + optional int64 terminationGracePeriodSeconds = 4; + + // Optional duration in seconds the pod may be active on the node relative to + // StartTime before the system will actively try to mark it failed and kill associated containers. + // Value must be a positive integer. + // +optional + optional int64 activeDeadlineSeconds = 5; + + // Set DNS policy for the pod. + // Defaults to "ClusterFirst". + // Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. + // DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. + // To have DNS options set along with hostNetwork, you have to specify DNS policy + // explicitly to 'ClusterFirstWithHostNet'. + // +optional + optional string dnsPolicy = 6; + + // NodeSelector is a selector which must be true for the pod to fit on a node. + // Selector which must match a node's labels for the pod to be scheduled on that node. + // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + // +optional + map<string, string> nodeSelector = 7; + + // ServiceAccountName is the name of the ServiceAccount to use to run this pod. + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + // +optional + optional string serviceAccountName = 8; + + // DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. + // Deprecated: Use serviceAccountName instead. + // +k8s:conversion-gen=false + // +optional + optional string serviceAccount = 9; + + // AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. + // +optional + optional bool automountServiceAccountToken = 21; + + // NodeName is a request to schedule this pod onto a specific node. If it is non-empty, + // the scheduler simply schedules this pod onto that node, assuming that it fits resource + // requirements. + // +optional + optional string nodeName = 10; + + // Host networking requested for this pod. Use the host's network namespace. + // If this option is set, the ports that will be used must be specified. + // Default to false. + // +k8s:conversion-gen=false + // +optional + optional bool hostNetwork = 11; + + // Use the host's pid namespace. + // Optional: Default to false. + // +k8s:conversion-gen=false + // +optional + optional bool hostPID = 12; + + // Use the host's ipc namespace. + // Optional: Default to false. + // +k8s:conversion-gen=false + // +optional + optional bool hostIPC = 13; + + // Share a single process namespace between all of the containers in a pod. + // When this is set containers will be able to view and signal processes from other containers + // in the same pod, and the first process in each container will not be assigned PID 1. + // HostPID and ShareProcessNamespace cannot both be set. + // Optional: Default to false. + // This field is beta-level and may be disabled with the PodShareProcessNamespace feature. + // +k8s:conversion-gen=false + // +optional + optional bool shareProcessNamespace = 27; + + // SecurityContext holds pod-level security attributes and common container settings. + // Optional: Defaults to empty. See type description for default values of each field. + // +optional + optional PodSecurityContext securityContext = 14; + + // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. + // If specified, these secrets will be passed to individual puller implementations for them to use. For example, + // in the case of docker, only DockerConfig type secrets are honored. + // More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + repeated LocalObjectReference imagePullSecrets = 15; + + // Specifies the hostname of the Pod + // If not specified, the pod's hostname will be set to a system-defined value. + // +optional + optional string hostname = 16; + + // If specified, the fully qualified Pod hostname will be "<hostname>.<subdomain>.<pod namespace>.svc.<cluster domain>". + // If not specified, the pod will not have a domainname at all. + // +optional + optional string subdomain = 17; + + // If specified, the pod's scheduling constraints + // +optional + optional Affinity affinity = 18; + + // If specified, the pod will be dispatched by specified scheduler. + // If not specified, the pod will be dispatched by default scheduler. + // +optional + optional string schedulerName = 19; + + // If specified, the pod's tolerations. + // +optional + repeated Toleration tolerations = 22; + + // HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts + // file if specified. This is only valid for non-hostNetwork pods. + // +optional + // +patchMergeKey=ip + // +patchStrategy=merge + repeated HostAlias hostAliases = 23; + + // If specified, indicates the pod's priority. "system-node-critical" and + // "system-cluster-critical" are two special keywords which indicate the + // highest priorities with the former being the highest priority. Any other + // name must be defined by creating a PriorityClass object with that name. + // If not specified, the pod priority will be default or zero if there is no + // default. + // +optional + optional string priorityClassName = 24; + + // The priority value. Various system components use this field to find the + // priority of the pod. When Priority Admission Controller is enabled, it + // prevents users from setting this field. The admission controller populates + // this field from PriorityClassName. + // The higher the value, the higher the priority. + // +optional + optional int32 priority = 25; + + // Specifies the DNS parameters of a pod. + // Parameters specified here will be merged to the generated DNS + // configuration based on DNSPolicy. + // +optional + optional PodDNSConfig dnsConfig = 26; + + // If specified, all readiness gates will be evaluated for pod readiness. + // A pod is ready when all its containers are ready AND + // all conditions specified in the readiness gates have status equal to "True" + // More info: https://github.com/kubernetes/community/blob/master/keps/sig-network/0007-pod-ready%2B%2B.md + // +optional + repeated PodReadinessGate readinessGates = 28; + + // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used + // to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. + // If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an + // empty definition that uses the default runtime handler. + // More info: https://github.com/kubernetes/community/blob/master/keps/sig-node/0014-runtime-class.md + // This is an alpha feature and may change in the future. + // +optional + optional string runtimeClassName = 29; +} + +// PodStatus represents information about the status of a pod. Status may trail the actual +// state of a system, especially if the node that hosts the pod cannot contact the control +// plane. +message PodStatus { + // The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. + // The conditions array, the reason and message fields, and the individual container status + // arrays contain more detail about the pod's status. + // There are five possible phase values: + // + // Pending: The pod has been accepted by the Kubernetes system, but one or more of the + // container images has not been created. This includes time before being scheduled as + // well as time spent downloading images over the network, which could take a while. + // Running: The pod has been bound to a node, and all of the containers have been created. + // At least one container is still running, or is in the process of starting or restarting. + // Succeeded: All containers in the pod have terminated in success, and will not be restarted. + // Failed: All containers in the pod have terminated, and at least one container has + // terminated in failure. The container either exited with non-zero status or was terminated + // by the system. + // Unknown: For some reason the state of the pod could not be obtained, typically due to an + // error in communicating with the host of the pod. + // + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase + // +optional + optional string phase = 1; + + // Current service state of pod. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated PodCondition conditions = 2; + + // A human readable message indicating details about why the pod is in this condition. + // +optional + optional string message = 3; + + // A brief CamelCase message indicating details about why the pod is in this state. + // e.g. 'Evicted' + // +optional + optional string reason = 4; + + // nominatedNodeName is set only when this pod preempts other pods on the node, but it cannot be + // scheduled right away as preemption victims receive their graceful termination periods. + // This field does not guarantee that the pod will be scheduled on this node. Scheduler may decide + // to place the pod elsewhere if other nodes become available sooner. Scheduler may also decide to + // give the resources on this node to a higher priority pod that is created after preemption. + // As a result, this field may be different than PodSpec.nodeName when the pod is + // scheduled. + // +optional + optional string nominatedNodeName = 11; + + // IP address of the host to which the pod is assigned. Empty if not yet scheduled. + // +optional + optional string hostIP = 5; + + // IP address allocated to the pod. Routable at least within the cluster. + // Empty if not yet allocated. + // +optional + optional string podIP = 6; + + // RFC 3339 date and time at which the object was acknowledged by the Kubelet. + // This is before the Kubelet pulled the container image(s) for the pod. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startTime = 7; + + // The list has one entry per init container in the manifest. The most recent successful + // init container will have ready = true, the most recently started container will have + // startTime set. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status + repeated ContainerStatus initContainerStatuses = 10; + + // The list has one entry per container in the manifest. Each entry is currently the output + // of `docker inspect`. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status + // +optional + repeated ContainerStatus containerStatuses = 8; + + // The Quality of Service (QOS) classification assigned to the pod based on resource requirements + // See PodQOSClass type for available QOS classes + // More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md + // +optional + optional string qosClass = 9; +} + +// PodStatusResult is a wrapper for PodStatus returned by kubelet that can be encode/decoded +message PodStatusResult { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Most recently observed status of the pod. + // This data may not be up to date. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional PodStatus status = 2; +} + +// PodTemplate describes a template for creating copies of a predefined pod. +message PodTemplate { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Template defines the pods that will be created from this pod template. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional PodTemplateSpec template = 2; +} + +// PodTemplateList is a list of PodTemplates. +message PodTemplateList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of pod templates + repeated PodTemplate items = 2; +} + +// PodTemplateSpec describes the data a pod should have when created from a template +message PodTemplateSpec { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the pod. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional PodSpec spec = 2; +} + +// PortworxVolumeSource represents a Portworx volume resource. +message PortworxVolumeSource { + // VolumeID uniquely identifies a Portworx volume + optional string volumeID = 1; + + // FSType represents the filesystem type to mount + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + optional string fsType = 2; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 3; +} + +// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. +// +k8s:openapi-gen=false +message Preconditions { + // Specifies the target UID. + // +optional + optional string uid = 1; +} + +// Describes a class of pods that should avoid this node. +message PreferAvoidPodsEntry { + // The class of pods. + optional PodSignature podSignature = 1; + + // Time at which this entry was added to the list. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time evictionTime = 2; + + // (brief) reason why this entry was added to the list. + // +optional + optional string reason = 3; + + // Human readable message indicating why this entry was added to the list. + // +optional + optional string message = 4; +} + +// An empty preferred scheduling term matches all objects with implicit weight 0 +// (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). +message PreferredSchedulingTerm { + // Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + optional int32 weight = 1; + + // A node selector term, associated with the corresponding weight. + optional NodeSelectorTerm preference = 2; +} + +// Probe describes a health check to be performed against a container to determine whether it is +// alive or ready to receive traffic. +message Probe { + // The action taken to determine the health of a container + optional Handler handler = 1; + + // Number of seconds after the container has started before liveness probes are initiated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + optional int32 initialDelaySeconds = 2; + + // Number of seconds after which the probe times out. + // Defaults to 1 second. Minimum value is 1. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + optional int32 timeoutSeconds = 3; + + // How often (in seconds) to perform the probe. + // Default to 10 seconds. Minimum value is 1. + // +optional + optional int32 periodSeconds = 4; + + // Minimum consecutive successes for the probe to be considered successful after having failed. + // Defaults to 1. Must be 1 for liveness. Minimum value is 1. + // +optional + optional int32 successThreshold = 5; + + // Minimum consecutive failures for the probe to be considered failed after having succeeded. + // Defaults to 3. Minimum value is 1. + // +optional + optional int32 failureThreshold = 6; +} + +// Represents a projected volume source +message ProjectedVolumeSource { + // list of volume projections + repeated VolumeProjection sources = 1; + + // Mode bits to use on created files by default. Must be a value between + // 0 and 0777. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + optional int32 defaultMode = 2; +} + +// Represents a Quobyte mount that lasts the lifetime of a pod. +// Quobyte volumes do not support ownership management or SELinux relabeling. +message QuobyteVolumeSource { + // Registry represents a single or multiple Quobyte Registry services + // specified as a string as host:port pair (multiple entries are separated with commas) + // which acts as the central registry for volumes + optional string registry = 1; + + // Volume is a string that references an already created Quobyte volume by name. + optional string volume = 2; + + // ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. + // Defaults to false. + // +optional + optional bool readOnly = 3; + + // User to map volume access to + // Defaults to serivceaccount user + // +optional + optional string user = 4; + + // Group to map volume access to + // Default is no group + // +optional + optional string group = 5; +} + +// Represents a Rados Block Device mount that lasts the lifetime of a pod. +// RBD volumes support ownership management and SELinux relabeling. +message RBDPersistentVolumeSource { + // A collection of Ceph monitors. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + repeated string monitors = 1; + + // The rados image name. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + optional string image = 2; + + // Filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 3; + + // The rados pool name. + // Default is rbd. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional string pool = 4; + + // The rados user name. + // Default is admin. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional string user = 5; + + // Keyring is the path to key ring for RBDUser. + // Default is /etc/ceph/keyring. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional string keyring = 6; + + // SecretRef is name of the authentication secret for RBDUser. If provided + // overrides keyring. + // Default is nil. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional SecretReference secretRef = 7; + + // ReadOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional bool readOnly = 8; +} + +// Represents a Rados Block Device mount that lasts the lifetime of a pod. +// RBD volumes support ownership management and SELinux relabeling. +message RBDVolumeSource { + // A collection of Ceph monitors. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + repeated string monitors = 1; + + // The rados image name. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + optional string image = 2; + + // Filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + optional string fsType = 3; + + // The rados pool name. + // Default is rbd. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional string pool = 4; + + // The rados user name. + // Default is admin. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional string user = 5; + + // Keyring is the path to key ring for RBDUser. + // Default is /etc/ceph/keyring. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional string keyring = 6; + + // SecretRef is name of the authentication secret for RBDUser. If provided + // overrides keyring. + // Default is nil. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional LocalObjectReference secretRef = 7; + + // ReadOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it + // +optional + optional bool readOnly = 8; +} + +// RangeAllocation is not a public type. +message RangeAllocation { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Range is string that identifies the range represented by 'data'. + optional string range = 2; + + // Data is a bit array containing all allocated addresses in the previous segment. + optional bytes data = 3; +} + +// ReplicationController represents the configuration of a replication controller. +message ReplicationController { + // If the Labels of a ReplicationController are empty, they are defaulted to + // be the same as the Pod(s) that the replication controller manages. + // Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the specification of the desired behavior of the replication controller. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicationControllerSpec spec = 2; + + // Status is the most recently observed status of the replication controller. + // This data may be out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicationControllerStatus status = 3; +} + +// ReplicationControllerCondition describes the state of a replication controller at a certain point. +message ReplicationControllerCondition { + // Type of replication controller condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// ReplicationControllerList is a collection of replication controllers. +message ReplicationControllerList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of replication controllers. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller + repeated ReplicationController items = 2; +} + +// ReplicationControllerSpec is the specification of a replication controller. +message ReplicationControllerSpec { + // Replicas is the number of desired replicas. + // This is a pointer to distinguish between explicit zero and unspecified. + // Defaults to 1. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller + // +optional + optional int32 replicas = 1; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 4; + + // Selector is a label query over pods that should match the Replicas count. + // If Selector is empty, it is defaulted to the labels present on the Pod template. + // Label keys and values that must match in order to be controlled by this replication + // controller, if empty defaulted to labels on Pod template. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + map<string, string> selector = 2; + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. This takes precedence over a TemplateRef. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + // +optional + optional PodTemplateSpec template = 3; +} + +// ReplicationControllerStatus represents the current status of a replication +// controller. +message ReplicationControllerStatus { + // Replicas is the most recently oberved number of replicas. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller + optional int32 replicas = 1; + + // The number of pods that have labels matching the labels of the pod template of the replication controller. + // +optional + optional int32 fullyLabeledReplicas = 2; + + // The number of ready replicas for this replication controller. + // +optional + optional int32 readyReplicas = 4; + + // The number of available replicas (ready for at least minReadySeconds) for this replication controller. + // +optional + optional int32 availableReplicas = 5; + + // ObservedGeneration reflects the generation of the most recently observed replication controller. + // +optional + optional int64 observedGeneration = 3; + + // Represents the latest available observations of a replication controller's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated ReplicationControllerCondition conditions = 6; +} + +// ResourceFieldSelector represents container resources (cpu, memory) and their output format +message ResourceFieldSelector { + // Container name: required for volumes, optional for env vars + // +optional + optional string containerName = 1; + + // Required: resource to select + optional string resource = 2; + + // Specifies the output format of the exposed resources, defaults to "1" + // +optional + optional k8s.io.apimachinery.pkg.api.resource.Quantity divisor = 3; +} + +// ResourceQuota sets aggregate quota restrictions enforced per namespace +message ResourceQuota { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the desired quota. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ResourceQuotaSpec spec = 2; + + // Status defines the actual enforced quota and its current usage. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ResourceQuotaStatus status = 3; +} + +// ResourceQuotaList is a list of ResourceQuota items. +message ResourceQuotaList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ResourceQuota objects. + // More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ + repeated ResourceQuota items = 2; +} + +// ResourceQuotaSpec defines the desired hard limits to enforce for Quota. +message ResourceQuotaSpec { + // hard is the set of desired hard limits for each named resource. + // More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> hard = 1; + + // A collection of filters that must match each object tracked by a quota. + // If not specified, the quota matches all objects. + // +optional + repeated string scopes = 2; + + // scopeSelector is also a collection of filters like scopes that must match each object tracked by a quota + // but expressed using ScopeSelectorOperator in combination with possible values. + // For a resource to match, both scopes AND scopeSelector (if specified in spec), must be matched. + // +optional + optional ScopeSelector scopeSelector = 3; +} + +// ResourceQuotaStatus defines the enforced hard limits and observed use. +message ResourceQuotaStatus { + // Hard is the set of enforced hard limits for each named resource. + // More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/ + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> hard = 1; + + // Used is the current observed total usage of the resource in the namespace. + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> used = 2; +} + +// ResourceRequirements describes the compute resource requirements. +message ResourceRequirements { + // Limits describes the maximum amount of compute resources allowed. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> limits = 1; + + // Requests describes the minimum amount of compute resources required. + // If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + // otherwise to an implementation-defined value. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + // +optional + map<string, k8s.io.apimachinery.pkg.api.resource.Quantity> requests = 2; +} + +// SELinuxOptions are the labels to be applied to the container +message SELinuxOptions { + // User is a SELinux user label that applies to the container. + // +optional + optional string user = 1; + + // Role is a SELinux role label that applies to the container. + // +optional + optional string role = 2; + + // Type is a SELinux type label that applies to the container. + // +optional + optional string type = 3; + + // Level is SELinux level label that applies to the container. + // +optional + optional string level = 4; +} + +// ScaleIOPersistentVolumeSource represents a persistent ScaleIO volume +message ScaleIOPersistentVolumeSource { + // The host address of the ScaleIO API Gateway. + optional string gateway = 1; + + // The name of the storage system as configured in ScaleIO. + optional string system = 2; + + // SecretRef references to the secret for ScaleIO user and other + // sensitive information. If this is not provided, Login operation will fail. + optional SecretReference secretRef = 3; + + // Flag to enable/disable SSL communication with Gateway, default false + // +optional + optional bool sslEnabled = 4; + + // The name of the ScaleIO Protection Domain for the configured storage. + // +optional + optional string protectionDomain = 5; + + // The ScaleIO Storage Pool associated with the protection domain. + // +optional + optional string storagePool = 6; + + // Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + // Default is ThinProvisioned. + // +optional + optional string storageMode = 7; + + // The name of a volume already created in the ScaleIO system + // that is associated with this volume source. + optional string volumeName = 8; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // Default is "xfs" + // +optional + optional string fsType = 9; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 10; +} + +// ScaleIOVolumeSource represents a persistent ScaleIO volume +message ScaleIOVolumeSource { + // The host address of the ScaleIO API Gateway. + optional string gateway = 1; + + // The name of the storage system as configured in ScaleIO. + optional string system = 2; + + // SecretRef references to the secret for ScaleIO user and other + // sensitive information. If this is not provided, Login operation will fail. + optional LocalObjectReference secretRef = 3; + + // Flag to enable/disable SSL communication with Gateway, default false + // +optional + optional bool sslEnabled = 4; + + // The name of the ScaleIO Protection Domain for the configured storage. + // +optional + optional string protectionDomain = 5; + + // The ScaleIO Storage Pool associated with the protection domain. + // +optional + optional string storagePool = 6; + + // Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + // Default is ThinProvisioned. + // +optional + optional string storageMode = 7; + + // The name of a volume already created in the ScaleIO system + // that is associated with this volume source. + optional string volumeName = 8; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // Default is "xfs". + // +optional + optional string fsType = 9; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 10; +} + +// A scope selector represents the AND of the selectors represented +// by the scoped-resource selector requirements. +message ScopeSelector { + // A list of scope selector requirements by scope of the resources. + // +optional + repeated ScopedResourceSelectorRequirement matchExpressions = 1; +} + +// A scoped-resource selector requirement is a selector that contains values, a scope name, and an operator +// that relates the scope name and values. +message ScopedResourceSelectorRequirement { + // The name of the scope that the selector applies to. + optional string scopeName = 1; + + // Represents a scope's relationship to a set of values. + // Valid operators are In, NotIn, Exists, DoesNotExist. + optional string operator = 2; + + // An array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. + // This array is replaced during a strategic merge patch. + // +optional + repeated string values = 3; +} + +// Secret holds secret data of a certain type. The total bytes of the values in +// the Data field must be less than MaxSecretSize bytes. +message Secret { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Data contains the secret data. Each key must consist of alphanumeric + // characters, '-', '_' or '.'. The serialized form of the secret data is a + // base64 encoded string, representing the arbitrary (possibly non-string) + // data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 + // +optional + map<string, bytes> data = 2; + + // stringData allows specifying non-binary secret data in string form. + // It is provided as a write-only convenience method. + // All keys and values are merged into the data field on write, overwriting any existing values. + // It is never output when reading from the API. + // +k8s:conversion-gen=false + // +optional + map<string, string> stringData = 4; + + // Used to facilitate programmatic handling of secret data. + // +optional + optional string type = 3; +} + +// SecretEnvSource selects a Secret to populate the environment +// variables with. +// +// The contents of the target Secret's Data field will represent the +// key-value pairs as environment variables. +message SecretEnvSource { + // The Secret to select from. + optional LocalObjectReference localObjectReference = 1; + + // Specify whether the Secret must be defined + // +optional + optional bool optional = 2; +} + +// SecretKeySelector selects a key of a Secret. +message SecretKeySelector { + // The name of the secret in the pod's namespace to select from. + optional LocalObjectReference localObjectReference = 1; + + // The key of the secret to select from. Must be a valid secret key. + optional string key = 2; + + // Specify whether the Secret or it's key must be defined + // +optional + optional bool optional = 3; +} + +// SecretList is a list of Secret. +message SecretList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of secret objects. + // More info: https://kubernetes.io/docs/concepts/configuration/secret + repeated Secret items = 2; +} + +// Adapts a secret into a projected volume. +// +// The contents of the target Secret's Data field will be presented in a +// projected volume as files using the keys in the Data field as the file names. +// Note that this is identical to a secret volume source without the default +// mode. +message SecretProjection { + optional LocalObjectReference localObjectReference = 1; + + // If unspecified, each key-value pair in the Data field of the referenced + // Secret will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the Secret, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + repeated KeyToPath items = 2; + + // Specify whether the Secret or its key must be defined + // +optional + optional bool optional = 4; +} + +// SecretReference represents a Secret Reference. It has enough information to retrieve secret +// in any namespace +message SecretReference { + // Name is unique within a namespace to reference a secret resource. + // +optional + optional string name = 1; + + // Namespace defines the space within which the secret name must be unique. + // +optional + optional string namespace = 2; +} + +// Adapts a Secret into a volume. +// +// The contents of the target Secret's Data field will be presented in a volume +// as files using the keys in the Data field as the file names. +// Secret volumes support ownership management and SELinux relabeling. +message SecretVolumeSource { + // Name of the secret in the pod's namespace to use. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + // +optional + optional string secretName = 1; + + // If unspecified, each key-value pair in the Data field of the referenced + // Secret will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the Secret, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + repeated KeyToPath items = 2; + + // Optional: mode bits to use on created files by default. Must be a + // value between 0 and 0777. Defaults to 0644. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + optional int32 defaultMode = 3; + + // Specify whether the Secret or it's keys must be defined + // +optional + optional bool optional = 4; +} + +// SecurityContext holds security configuration that will be applied to a container. +// Some fields are present in both SecurityContext and PodSecurityContext. When both +// are set, the values in SecurityContext take precedence. +message SecurityContext { + // The capabilities to add/drop when running containers. + // Defaults to the default set of capabilities granted by the container runtime. + // +optional + optional Capabilities capabilities = 1; + + // Run container in privileged mode. + // Processes in privileged containers are essentially equivalent to root on the host. + // Defaults to false. + // +optional + optional bool privileged = 2; + + // The SELinux context to be applied to the container. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container. May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + optional SELinuxOptions seLinuxOptions = 3; + + // The UID to run the entrypoint of the container process. + // Defaults to user specified in image metadata if unspecified. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + optional int64 runAsUser = 4; + + // The GID to run the entrypoint of the container process. + // Uses runtime default if unset. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + optional int64 runAsGroup = 8; + + // Indicates that the container must run as a non-root user. + // If true, the Kubelet will validate the image at runtime to ensure that it + // does not run as UID 0 (root) and fail to start the container if it does. + // If unset or false, no such validation will be performed. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + optional bool runAsNonRoot = 5; + + // Whether this container has a read-only root filesystem. + // Default is false. + // +optional + optional bool readOnlyRootFilesystem = 6; + + // AllowPrivilegeEscalation controls whether a process can gain more + // privileges than its parent process. This bool directly controls if + // the no_new_privs flag will be set on the container process. + // AllowPrivilegeEscalation is true always when the container is: + // 1) run as Privileged + // 2) has CAP_SYS_ADMIN + // +optional + optional bool allowPrivilegeEscalation = 7; + + // procMount denotes the type of proc mount to use for the containers. + // The default is DefaultProcMount which uses the container runtime defaults for + // readonly paths and masked paths. + // This requires the ProcMountType feature flag to be enabled. + // +optional + optional string procMount = 9; +} + +// SerializedReference is a reference to serialized object. +message SerializedReference { + // The reference to an object in the system. + // +optional + optional ObjectReference reference = 1; +} + +// Service is a named abstraction of software service (for example, mysql) consisting of local port +// (for example 3306) that the proxy listens on, and the selector that determines which pods +// will answer requests sent through the proxy. +message Service { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the behavior of a service. + // https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ServiceSpec spec = 2; + + // Most recently observed status of the service. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ServiceStatus status = 3; +} + +// ServiceAccount binds together: +// * a name, understood by users, and perhaps by peripheral systems, for an identity +// * a principal that can be authenticated and authorized +// * a set of secrets +message ServiceAccount { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. + // More info: https://kubernetes.io/docs/concepts/configuration/secret + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + repeated ObjectReference secrets = 2; + + // ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images + // in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets + // can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. + // More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod + // +optional + repeated LocalObjectReference imagePullSecrets = 3; + + // AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. + // Can be overridden at the pod level. + // +optional + optional bool automountServiceAccountToken = 4; +} + +// ServiceAccountList is a list of ServiceAccount objects +message ServiceAccountList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of ServiceAccounts. + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + repeated ServiceAccount items = 2; +} + +// ServiceAccountTokenProjection represents a projected service account token +// volume. This projection can be used to insert a service account token into +// the pods runtime filesystem for use against APIs (Kubernetes API Server or +// otherwise). +message ServiceAccountTokenProjection { + // Audience is the intended audience of the token. A recipient of a token + // must identify itself with an identifier specified in the audience of the + // token, and otherwise should reject the token. The audience defaults to the + // identifier of the apiserver. + // +optional + optional string audience = 1; + + // ExpirationSeconds is the requested duration of validity of the service + // account token. As the token approaches expiration, the kubelet volume + // plugin will proactively rotate the service account token. The kubelet will + // start trying to rotate the token if the token is older than 80 percent of + // its time to live or if the token is older than 24 hours.Defaults to 1 hour + // and must be at least 10 minutes. + // +optional + optional int64 expirationSeconds = 2; + + // Path is the path relative to the mount point of the file to project the + // token into. + optional string path = 3; +} + +// ServiceList holds a list of services. +message ServiceList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of services + repeated Service items = 2; +} + +// ServicePort contains information on service's port. +message ServicePort { + // The name of this port within the service. This must be a DNS_LABEL. + // All ports within a ServiceSpec must have unique names. This maps to + // the 'Name' field in EndpointPort objects. + // Optional if only one ServicePort is defined on this service. + // +optional + optional string name = 1; + + // The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". + // Default is TCP. + // +optional + optional string protocol = 2; + + // The port that will be exposed by this service. + optional int32 port = 3; + + // Number or name of the port to access on the pods targeted by the service. + // Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + // If this is a string, it will be looked up as a named port in the + // target Pod's container ports. If this is not specified, the value + // of the 'port' field is used (an identity map). + // This field is ignored for services with clusterIP=None, and should be + // omitted or set equal to the 'port' field. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString targetPort = 4; + + // The port on each node on which this service is exposed when type=NodePort or LoadBalancer. + // Usually assigned by the system. If specified, it will be allocated to the service + // if unused or else creation of the service will fail. + // Default is to auto-allocate a port if the ServiceType of this Service requires one. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + // +optional + optional int32 nodePort = 5; +} + +// ServiceProxyOptions is the query options to a Service's proxy call. +message ServiceProxyOptions { + // Path is the part of URLs that include service endpoints, suffixes, + // and parameters to use for the current proxy request to service. + // For example, the whole request URL is + // http://localhost/api/v1/namespaces/kube-system/services/elasticsearch-logging/_search?q=user:kimchy. + // Path is _search?q=user:kimchy. + // +optional + optional string path = 1; +} + +// ServiceSpec describes the attributes that a user creates on a service. +message ServiceSpec { + // The list of ports that are exposed by this service. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + // +patchMergeKey=port + // +patchStrategy=merge + repeated ServicePort ports = 1; + + // Route service traffic to pods with label keys and values matching this + // selector. If empty or not present, the service is assumed to have an + // external process managing its endpoints, which Kubernetes will not + // modify. Only applies to types ClusterIP, NodePort, and LoadBalancer. + // Ignored if type is ExternalName. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/ + // +optional + map<string, string> selector = 2; + + // clusterIP is the IP address of the service and is usually assigned + // randomly by the master. If an address is specified manually and is not in + // use by others, it will be allocated to the service; otherwise, creation + // of the service will fail. This field can not be changed through updates. + // Valid values are "None", empty string (""), or a valid IP address. "None" + // can be specified for headless services when proxying is not required. + // Only applies to types ClusterIP, NodePort, and LoadBalancer. Ignored if + // type is ExternalName. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + // +optional + optional string clusterIP = 3; + + // type determines how the Service is exposed. Defaults to ClusterIP. Valid + // options are ExternalName, ClusterIP, NodePort, and LoadBalancer. + // "ExternalName" maps to the specified externalName. + // "ClusterIP" allocates a cluster-internal IP address for load-balancing to + // endpoints. Endpoints are determined by the selector or if that is not + // specified, by manual construction of an Endpoints object. If clusterIP is + // "None", no virtual IP is allocated and the endpoints are published as a + // set of endpoints rather than a stable IP. + // "NodePort" builds on ClusterIP and allocates a port on every node which + // routes to the clusterIP. + // "LoadBalancer" builds on NodePort and creates an + // external load-balancer (if supported in the current cloud) which routes + // to the clusterIP. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types + // +optional + optional string type = 4; + + // externalIPs is a list of IP addresses for which nodes in the cluster + // will also accept traffic for this service. These IPs are not managed by + // Kubernetes. The user is responsible for ensuring that traffic arrives + // at a node with this IP. A common example is external load-balancers + // that are not part of the Kubernetes system. + // +optional + repeated string externalIPs = 5; + + // Supports "ClientIP" and "None". Used to maintain session affinity. + // Enable client IP based session affinity. + // Must be ClientIP or None. + // Defaults to None. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies + // +optional + optional string sessionAffinity = 7; + + // Only applies to Service Type: LoadBalancer + // LoadBalancer will get created with the IP specified in this field. + // This feature depends on whether the underlying cloud-provider supports specifying + // the loadBalancerIP when a load balancer is created. + // This field will be ignored if the cloud-provider does not support the feature. + // +optional + optional string loadBalancerIP = 8; + + // If specified and supported by the platform, this will restrict traffic through the cloud-provider + // load-balancer will be restricted to the specified client IPs. This field will be ignored if the + // cloud-provider does not support the feature." + // More info: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/ + // +optional + repeated string loadBalancerSourceRanges = 9; + + // externalName is the external reference that kubedns or equivalent will + // return as a CNAME record for this service. No proxying will be involved. + // Must be a valid RFC-1123 hostname (https://tools.ietf.org/html/rfc1123) + // and requires Type to be ExternalName. + // +optional + optional string externalName = 10; + + // externalTrafficPolicy denotes if this Service desires to route external + // traffic to node-local or cluster-wide endpoints. "Local" preserves the + // client source IP and avoids a second hop for LoadBalancer and Nodeport + // type services, but risks potentially imbalanced traffic spreading. + // "Cluster" obscures the client source IP and may cause a second hop to + // another node, but should have good overall load-spreading. + // +optional + optional string externalTrafficPolicy = 11; + + // healthCheckNodePort specifies the healthcheck nodePort for the service. + // If not specified, HealthCheckNodePort is created by the service api + // backend with the allocated nodePort. Will use user-specified nodePort value + // if specified by the client. Only effects when Type is set to LoadBalancer + // and ExternalTrafficPolicy is set to Local. + // +optional + optional int32 healthCheckNodePort = 12; + + // publishNotReadyAddresses, when set to true, indicates that DNS implementations + // must publish the notReadyAddresses of subsets for the Endpoints associated with + // the Service. The default value is false. + // The primary use case for setting this field is to use a StatefulSet's Headless Service + // to propagate SRV records for its Pods without respect to their readiness for purpose + // of peer discovery. + // +optional + optional bool publishNotReadyAddresses = 13; + + // sessionAffinityConfig contains the configurations of session affinity. + // +optional + optional SessionAffinityConfig sessionAffinityConfig = 14; +} + +// ServiceStatus represents the current status of a service. +message ServiceStatus { + // LoadBalancer contains the current status of the load-balancer, + // if one is present. + // +optional + optional LoadBalancerStatus loadBalancer = 1; +} + +// SessionAffinityConfig represents the configurations of session affinity. +message SessionAffinityConfig { + // clientIP contains the configurations of Client IP based session affinity. + // +optional + optional ClientIPConfig clientIP = 1; +} + +// Represents a StorageOS persistent volume resource. +message StorageOSPersistentVolumeSource { + // VolumeName is the human-readable name of the StorageOS volume. Volume + // names are only unique within a namespace. + optional string volumeName = 1; + + // VolumeNamespace specifies the scope of the volume within StorageOS. If no + // namespace is specified then the Pod's namespace will be used. This allows the + // Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + // Set VolumeName to any name to override the default behaviour. + // Set to "default" if you are not using namespaces within StorageOS. + // Namespaces that do not pre-exist within StorageOS will be created. + // +optional + optional string volumeNamespace = 2; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + optional string fsType = 3; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 4; + + // SecretRef specifies the secret to use for obtaining the StorageOS API + // credentials. If not specified, default values will be attempted. + // +optional + optional ObjectReference secretRef = 5; +} + +// Represents a StorageOS persistent volume resource. +message StorageOSVolumeSource { + // VolumeName is the human-readable name of the StorageOS volume. Volume + // names are only unique within a namespace. + optional string volumeName = 1; + + // VolumeNamespace specifies the scope of the volume within StorageOS. If no + // namespace is specified then the Pod's namespace will be used. This allows the + // Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + // Set VolumeName to any name to override the default behaviour. + // Set to "default" if you are not using namespaces within StorageOS. + // Namespaces that do not pre-exist within StorageOS will be created. + // +optional + optional string volumeNamespace = 2; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + optional string fsType = 3; + + // Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + optional bool readOnly = 4; + + // SecretRef specifies the secret to use for obtaining the StorageOS API + // credentials. If not specified, default values will be attempted. + // +optional + optional LocalObjectReference secretRef = 5; +} + +// Sysctl defines a kernel parameter to be set +message Sysctl { + // Name of a property to set + optional string name = 1; + + // Value of a property to set + optional string value = 2; +} + +// TCPSocketAction describes an action based on opening a socket +message TCPSocketAction { + // Number or name of the port to access on the container. + // Number must be in the range 1 to 65535. + // Name must be an IANA_SVC_NAME. + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString port = 1; + + // Optional: Host name to connect to, defaults to the pod IP. + // +optional + optional string host = 2; +} + +// The node this Taint is attached to has the "effect" on +// any pod that does not tolerate the Taint. +message Taint { + // Required. The taint key to be applied to a node. + optional string key = 1; + + // Required. The taint value corresponding to the taint key. + // +optional + optional string value = 2; + + // Required. The effect of the taint on pods + // that do not tolerate the taint. + // Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + optional string effect = 3; + + // TimeAdded represents the time at which the taint was added. + // It is only written for NoExecute taints. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time timeAdded = 4; +} + +// The pod this Toleration is attached to tolerates any taint that matches +// the triple <key,value,effect> using the matching operator <operator>. +message Toleration { + // Key is the taint key that the toleration applies to. Empty means match all taint keys. + // If the key is empty, operator must be Exists; this combination means to match all values and all keys. + // +optional + optional string key = 1; + + // Operator represents a key's relationship to the value. + // Valid operators are Exists and Equal. Defaults to Equal. + // Exists is equivalent to wildcard for value, so that a pod can + // tolerate all taints of a particular category. + // +optional + optional string operator = 2; + + // Value is the taint value the toleration matches to. + // If the operator is Exists, the value should be empty, otherwise just a regular string. + // +optional + optional string value = 3; + + // Effect indicates the taint effect to match. Empty means match all taint effects. + // When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + // +optional + optional string effect = 4; + + // TolerationSeconds represents the period of time the toleration (which must be + // of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + // it is not set, which means tolerate the taint forever (do not evict). Zero and + // negative values will be treated as 0 (evict immediately) by the system. + // +optional + optional int64 tolerationSeconds = 5; +} + +// A topology selector requirement is a selector that matches given label. +// This is an alpha feature and may change in the future. +message TopologySelectorLabelRequirement { + // The label key that the selector applies to. + optional string key = 1; + + // An array of string values. One value must match the label to be selected. + // Each entry in Values is ORed. + repeated string values = 2; +} + +// A topology selector term represents the result of label queries. +// A null or empty topology selector term matches no objects. +// The requirements of them are ANDed. +// It provides a subset of functionality as NodeSelectorTerm. +// This is an alpha feature and may change in the future. +message TopologySelectorTerm { + // A list of topology selector requirements by labels. + // +optional + repeated TopologySelectorLabelRequirement matchLabelExpressions = 1; +} + +// TypedLocalObjectReference contains enough information to let you locate the +// typed referenced object inside the same namespace. +message TypedLocalObjectReference { + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + // +optional + optional string apiGroup = 1; + + // Kind is the type of resource being referenced + optional string kind = 2; + + // Name is the name of resource being referenced + optional string name = 3; +} + +// Volume represents a named volume in a pod that may be accessed by any container in the pod. +message Volume { + // Volume's name. + // Must be a DNS_LABEL and unique within the pod. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + optional string name = 1; + + // VolumeSource represents the location and type of the mounted volume. + // If not specified, the Volume is implied to be an EmptyDir. + // This implied behavior is deprecated and will be removed in a future version. + optional VolumeSource volumeSource = 2; +} + +// volumeDevice describes a mapping of a raw block device within a container. +message VolumeDevice { + // name must match the name of a persistentVolumeClaim in the pod + optional string name = 1; + + // devicePath is the path inside of the container that the device will be mapped to. + optional string devicePath = 2; +} + +// VolumeMount describes a mounting of a Volume within a container. +message VolumeMount { + // This must match the Name of a Volume. + optional string name = 1; + + // Mounted read-only if true, read-write otherwise (false or unspecified). + // Defaults to false. + // +optional + optional bool readOnly = 2; + + // Path within the container at which the volume should be mounted. Must + // not contain ':'. + optional string mountPath = 3; + + // Path within the volume from which the container's volume should be mounted. + // Defaults to "" (volume's root). + // +optional + optional string subPath = 4; + + // mountPropagation determines how mounts are propagated from the host + // to container and the other way around. + // When not set, MountPropagationNone is used. + // This field is beta in 1.10. + // +optional + optional string mountPropagation = 5; +} + +// VolumeNodeAffinity defines constraints that limit what nodes this volume can be accessed from. +message VolumeNodeAffinity { + // Required specifies hard node constraints that must be met. + optional NodeSelector required = 1; +} + +// Projection that may be projected along with other supported volume types +message VolumeProjection { + // information about the secret data to project + // +optional + optional SecretProjection secret = 1; + + // information about the downwardAPI data to project + // +optional + optional DownwardAPIProjection downwardAPI = 2; + + // information about the configMap data to project + // +optional + optional ConfigMapProjection configMap = 3; + + // information about the serviceAccountToken data to project + // +optional + optional ServiceAccountTokenProjection serviceAccountToken = 4; +} + +// Represents the source of a volume to mount. +// Only one of its members may be specified. +message VolumeSource { + // HostPath represents a pre-existing file or directory on the host + // machine that is directly exposed to the container. This is generally + // used for system agents or other privileged things that are allowed + // to see the host machine. Most containers will NOT need this. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + // --- + // TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + // mount host directories as read/write. + // +optional + optional HostPathVolumeSource hostPath = 1; + + // EmptyDir represents a temporary directory that shares a pod's lifetime. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + // +optional + optional EmptyDirVolumeSource emptyDir = 2; + + // GCEPersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + optional GCEPersistentDiskVolumeSource gcePersistentDisk = 3; + + // AWSElasticBlockStore represents an AWS Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // +optional + optional AWSElasticBlockStoreVolumeSource awsElasticBlockStore = 4; + + // GitRepo represents a git repository at a particular revision. + // DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + // EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + // into the Pod's container. + // +optional + optional GitRepoVolumeSource gitRepo = 5; + + // Secret represents a secret that should populate this volume. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + // +optional + optional SecretVolumeSource secret = 6; + + // NFS represents an NFS mount on the host that shares a pod's lifetime + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + // +optional + optional NFSVolumeSource nfs = 7; + + // ISCSI represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // More info: https://releases.k8s.io/HEAD/examples/volumes/iscsi/README.md + // +optional + optional ISCSIVolumeSource iscsi = 8; + + // Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + // More info: https://releases.k8s.io/HEAD/examples/volumes/glusterfs/README.md + // +optional + optional GlusterfsVolumeSource glusterfs = 9; + + // PersistentVolumeClaimVolumeSource represents a reference to a + // PersistentVolumeClaim in the same namespace. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + optional PersistentVolumeClaimVolumeSource persistentVolumeClaim = 10; + + // RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. + // More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md + // +optional + optional RBDVolumeSource rbd = 11; + + // FlexVolume represents a generic volume resource that is + // provisioned/attached using an exec based plugin. + // +optional + optional FlexVolumeSource flexVolume = 12; + + // Cinder represents a cinder volume attached and mounted on kubelets host machine + // More info: https://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md + // +optional + optional CinderVolumeSource cinder = 13; + + // CephFS represents a Ceph FS mount on the host that shares a pod's lifetime + // +optional + optional CephFSVolumeSource cephfs = 14; + + // Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running + // +optional + optional FlockerVolumeSource flocker = 15; + + // DownwardAPI represents downward API about the pod that should populate this volume + // +optional + optional DownwardAPIVolumeSource downwardAPI = 16; + + // FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + // +optional + optional FCVolumeSource fc = 17; + + // AzureFile represents an Azure File Service mount on the host and bind mount to the pod. + // +optional + optional AzureFileVolumeSource azureFile = 18; + + // ConfigMap represents a configMap that should populate this volume + // +optional + optional ConfigMapVolumeSource configMap = 19; + + // VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine + // +optional + optional VsphereVirtualDiskVolumeSource vsphereVolume = 20; + + // Quobyte represents a Quobyte mount on the host that shares a pod's lifetime + // +optional + optional QuobyteVolumeSource quobyte = 21; + + // AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + // +optional + optional AzureDiskVolumeSource azureDisk = 22; + + // PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine + optional PhotonPersistentDiskVolumeSource photonPersistentDisk = 23; + + // Items for all in one resources secrets, configmaps, and downward API + optional ProjectedVolumeSource projected = 26; + + // PortworxVolume represents a portworx volume attached and mounted on kubelets host machine + // +optional + optional PortworxVolumeSource portworxVolume = 24; + + // ScaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + // +optional + optional ScaleIOVolumeSource scaleIO = 25; + + // StorageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + // +optional + optional StorageOSVolumeSource storageos = 27; +} + +// Represents a vSphere volume resource. +message VsphereVirtualDiskVolumeSource { + // Path that identifies vSphere volume vmdk + optional string volumePath = 1; + + // Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + optional string fsType = 2; + + // Storage Policy Based Management (SPBM) profile name. + // +optional + optional string storagePolicyName = 3; + + // Storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + // +optional + optional string storagePolicyID = 4; +} + +// The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) +message WeightedPodAffinityTerm { + // weight associated with matching the corresponding podAffinityTerm, + // in the range 1-100. + optional int32 weight = 1; + + // Required. A pod affinity term, associated with the corresponding weight. + optional PodAffinityTerm podAffinityTerm = 2; +} + diff --git a/vendor/k8s.io/api/core/v1/taint_test.go b/vendor/k8s.io/api/core/v1/taint_test.go new file mode 100644 index 000000000..22c7f9c4f --- /dev/null +++ b/vendor/k8s.io/api/core/v1/taint_test.go @@ -0,0 +1,122 @@ +/* +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 v1 + +import ( + "testing" +) + +func TestTaintToString(t *testing.T) { + testCases := []struct { + taint *Taint + expectedString string + }{ + { + taint: &Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + expectedString: "foo=bar:NoSchedule", + }, + { + taint: &Taint{ + Key: "foo", + Effect: TaintEffectNoSchedule, + }, + expectedString: "foo:NoSchedule", + }, + } + + for i, tc := range testCases { + if tc.expectedString != tc.taint.ToString() { + t.Errorf("[%v] expected taint %v converted to %s, got %s", i, tc.taint, tc.expectedString, tc.taint.ToString()) + } + } +} + +func TestMatchTaint(t *testing.T) { + testCases := []struct { + description string + taint *Taint + taintToMatch Taint + expectMatch bool + }{ + { + description: "two taints with the same key,value,effect should match", + taint: &Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + taintToMatch: Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + expectMatch: true, + }, + { + description: "two taints with the same key,effect but different value should match", + taint: &Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + taintToMatch: Taint{ + Key: "foo", + Value: "different-value", + Effect: TaintEffectNoSchedule, + }, + expectMatch: true, + }, + { + description: "two taints with the different key cannot match", + taint: &Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + taintToMatch: Taint{ + Key: "different-key", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + expectMatch: false, + }, + { + description: "two taints with the different effect cannot match", + taint: &Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + taintToMatch: Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectPreferNoSchedule, + }, + expectMatch: false, + }, + } + + for _, tc := range testCases { + if tc.expectMatch != tc.taint.MatchTaint(&tc.taintToMatch) { + t.Errorf("[%s] expect taint %s match taint %s", tc.description, tc.taint.ToString(), tc.taintToMatch.ToString()) + } + } +} diff --git a/vendor/k8s.io/api/core/v1/toleration_test.go b/vendor/k8s.io/api/core/v1/toleration_test.go new file mode 100644 index 000000000..3dd48f087 --- /dev/null +++ b/vendor/k8s.io/api/core/v1/toleration_test.go @@ -0,0 +1,123 @@ +/* +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 v1 + +import ( + "testing" +) + +func TestTolerationToleratesTaint(t *testing.T) { + + testCases := []struct { + description string + toleration Toleration + taint Taint + expectTolerated bool + }{ + { + description: "toleration and taint have the same key and effect, and operator is Exists, and taint has no value, expect tolerated", + toleration: Toleration{ + Key: "foo", + Operator: TolerationOpExists, + Effect: TaintEffectNoSchedule, + }, + taint: Taint{ + Key: "foo", + Effect: TaintEffectNoSchedule, + }, + expectTolerated: true, + }, + { + description: "toleration and taint have the same key and effect, and operator is Exists, and taint has some value, expect tolerated", + toleration: Toleration{ + Key: "foo", + Operator: TolerationOpExists, + Effect: TaintEffectNoSchedule, + }, + taint: Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + expectTolerated: true, + }, + { + description: "toleration and taint have the same effect, toleration has empty key and operator is Exists, means match all taints, expect tolerated", + toleration: Toleration{ + Key: "", + Operator: TolerationOpExists, + Effect: TaintEffectNoSchedule, + }, + taint: Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + expectTolerated: true, + }, + { + description: "toleration and taint have the same key, effect and value, and operator is Equal, expect tolerated", + toleration: Toleration{ + Key: "foo", + Operator: TolerationOpEqual, + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + taint: Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + expectTolerated: true, + }, + { + description: "toleration and taint have the same key and effect, but different values, and operator is Equal, expect not tolerated", + toleration: Toleration{ + Key: "foo", + Operator: TolerationOpEqual, + Value: "value1", + Effect: TaintEffectNoSchedule, + }, + taint: Taint{ + Key: "foo", + Value: "value2", + Effect: TaintEffectNoSchedule, + }, + expectTolerated: false, + }, + { + description: "toleration and taint have the same key and value, but different effects, and operator is Equal, expect not tolerated", + toleration: Toleration{ + Key: "foo", + Operator: TolerationOpEqual, + Value: "bar", + Effect: TaintEffectNoSchedule, + }, + taint: Taint{ + Key: "foo", + Value: "bar", + Effect: TaintEffectNoExecute, + }, + expectTolerated: false, + }, + } + for _, tc := range testCases { + if tolerated := tc.toleration.ToleratesTaint(&tc.taint); tc.expectTolerated != tolerated { + t.Errorf("[%s] expect %v, got %v: toleration %+v, taint %s", tc.description, tc.expectTolerated, tolerated, tc.toleration, tc.taint.ToString()) + } + } +} diff --git a/vendor/k8s.io/api/events/OWNERS b/vendor/k8s.io/api/events/OWNERS new file mode 100644 index 000000000..d9ecd8856 --- /dev/null +++ b/vendor/k8s.io/api/events/OWNERS @@ -0,0 +1,8 @@ +reviewers: +- gmarek +- deads2k +- sttts +approvers: +- gmarek +- deads2k +- sttts diff --git a/vendor/k8s.io/api/events/v1beta1/generated.proto b/vendor/k8s.io/api/events/v1beta1/generated.proto new file mode 100644 index 000000000..b3e565e67 --- /dev/null +++ b/vendor/k8s.io/api/events/v1beta1/generated.proto @@ -0,0 +1,121 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.events.v1beta1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// Event is a report of an event somewhere in the cluster. It generally denotes some state change in the system. +message Event { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Required. Time when this Event was first observed. + optional k8s.io.apimachinery.pkg.apis.meta.v1.MicroTime eventTime = 2; + + // Data about the Event series this event represents or nil if it's a singleton Event. + // +optional + optional EventSeries series = 3; + + // Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`. + // +optional + optional string reportingController = 4; + + // ID of the controller instance, e.g. `kubelet-xyzf`. + // +optional + optional string reportingInstance = 5; + + // What action was taken/failed regarding to the regarding object. + // +optional + optional string action = 6; + + // Why the action was taken. + optional string reason = 7; + + // The object this Event is about. In most cases it's an Object reporting controller implements. + // E.g. ReplicaSetController implements ReplicaSets and this event is emitted because + // it acts on some changes in a ReplicaSet object. + // +optional + optional k8s.io.api.core.v1.ObjectReference regarding = 8; + + // Optional secondary object for more complex actions. E.g. when regarding object triggers + // a creation or deletion of related object. + // +optional + optional k8s.io.api.core.v1.ObjectReference related = 9; + + // Optional. A human-readable description of the status of this operation. + // Maximal length of the note is 1kB, but libraries should be prepared to + // handle values up to 64kB. + // +optional + optional string note = 10; + + // Type of this event (Normal, Warning), new types could be added in the + // future. + // +optional + optional string type = 11; + + // Deprecated field assuring backward compatibility with core.v1 Event type + // +optional + optional k8s.io.api.core.v1.EventSource deprecatedSource = 12; + + // Deprecated field assuring backward compatibility with core.v1 Event type + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time deprecatedFirstTimestamp = 13; + + // Deprecated field assuring backward compatibility with core.v1 Event type + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time deprecatedLastTimestamp = 14; + + // Deprecated field assuring backward compatibility with core.v1 Event type + // +optional + optional int32 deprecatedCount = 15; +} + +// EventList is a list of Event objects. +message EventList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of schema objects. + repeated Event items = 2; +} + +// EventSeries contain information on series of events, i.e. thing that was/is happening +// continuously for some time. +message EventSeries { + // Number of occurrences in this series up to the last heartbeat time + optional int32 count = 1; + + // Time when last Event from the series was seen before last heartbeat. + optional k8s.io.apimachinery.pkg.apis.meta.v1.MicroTime lastObservedTime = 2; + + // Information whether this series is ongoing or finished. + optional string state = 3; +} + diff --git a/vendor/k8s.io/api/extensions/OWNERS b/vendor/k8s.io/api/extensions/OWNERS new file mode 100755 index 000000000..cfac47110 --- /dev/null +++ b/vendor/k8s.io/api/extensions/OWNERS @@ -0,0 +1,38 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- brendandburns +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- nikhiljindal +- erictune +- pmorie +- sttts +- saad-ali +- janetkuo +- justinsb +- ncdc +- tallclair +- mwielgus +- soltysh +- piosz +- dims +- errordeveloper +- madhusudancs +- rootfs +- jszczepkowski +- mml +- resouer +- mbohlool +- david-mcmahon +- therc +- pweil- +- tmrts +- mqliang +- lukaszo +- jianhuiz diff --git a/vendor/k8s.io/api/extensions/v1beta1/generated.proto b/vendor/k8s.io/api/extensions/v1beta1/generated.proto new file mode 100644 index 000000000..1a9b7ebb1 --- /dev/null +++ b/vendor/k8s.io/api/extensions/v1beta1/generated.proto @@ -0,0 +1,1166 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.extensions.v1beta1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/api/resource/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// AllowedFlexVolume represents a single Flexvolume that is allowed to be used. +// Deprecated: use AllowedFlexVolume from policy API Group instead. +message AllowedFlexVolume { + // driver is the name of the Flexvolume driver. + optional string driver = 1; +} + +// AllowedHostPath defines the host volume conditions that will be enabled by a policy +// for pods to use. It requires the path prefix to be defined. +// Deprecated: use AllowedHostPath from policy API Group instead. +message AllowedHostPath { + // pathPrefix is the path prefix that the host volume must match. + // It does not support `*`. + // Trailing slashes are trimmed when validating the path prefix with a host path. + // + // Examples: + // `/foo` would allow `/foo`, `/foo/` and `/foo/bar` + // `/foo` would not allow `/food` or `/etc/foo` + optional string pathPrefix = 1; + + // when set to true, will allow host volumes matching the pathPrefix only if all volume mounts are readOnly. + // +optional + optional bool readOnly = 2; +} + +message CustomMetricCurrentStatus { + // Custom Metric name. + optional string name = 1; + + // Custom Metric value (average). + optional k8s.io.apimachinery.pkg.api.resource.Quantity value = 2; +} + +message CustomMetricCurrentStatusList { + repeated CustomMetricCurrentStatus items = 1; +} + +// Alpha-level support for Custom Metrics in HPA (as annotations). +message CustomMetricTarget { + // Custom Metric name. + optional string name = 1; + + // Custom Metric value (average). + optional k8s.io.apimachinery.pkg.api.resource.Quantity value = 2; +} + +message CustomMetricTargetList { + repeated CustomMetricTarget items = 1; +} + +// DEPRECATED - This group version of DaemonSet is deprecated by apps/v1beta2/DaemonSet. See the release notes for +// more information. +// DaemonSet represents the configuration of a daemon set. +message DaemonSet { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The desired behavior of this daemon set. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional DaemonSetSpec spec = 2; + + // The current status of this daemon set. This data may be + // out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional DaemonSetStatus status = 3; +} + +// DaemonSetCondition describes the state of a DaemonSet at a certain point. +message DaemonSetCondition { + // Type of DaemonSet condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // Last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// DaemonSetList is a collection of daemon sets. +message DaemonSetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // A list of daemon sets. + repeated DaemonSet items = 2; +} + +// DaemonSetSpec is the specification of a daemon set. +message DaemonSetSpec { + // A label query over pods that are managed by the daemon set. + // Must match in order to be controlled. + // If empty, defaulted to labels on Pod template. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 1; + + // An object that describes the pod that will be created. + // The DaemonSet will create exactly one copy of this pod on every node + // that matches the template's node selector (or on every node if no node + // selector is specified). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + optional k8s.io.api.core.v1.PodTemplateSpec template = 2; + + // An update strategy to replace existing DaemonSet pods with new pods. + // +optional + optional DaemonSetUpdateStrategy updateStrategy = 3; + + // The minimum number of seconds for which a newly created DaemonSet pod should + // be ready without any of its container crashing, for it to be considered + // available. Defaults to 0 (pod will be considered available as soon as it + // is ready). + // +optional + optional int32 minReadySeconds = 4; + + // DEPRECATED. + // A sequence number representing a specific generation of the template. + // Populated by the system. It can be set only during the creation. + // +optional + optional int64 templateGeneration = 5; + + // The number of old history to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // Defaults to 10. + // +optional + optional int32 revisionHistoryLimit = 6; +} + +// DaemonSetStatus represents the current status of a daemon set. +message DaemonSetStatus { + // The number of nodes that are running at least 1 + // daemon pod and are supposed to run the daemon pod. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 currentNumberScheduled = 1; + + // The number of nodes that are running the daemon pod, but are + // not supposed to run the daemon pod. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 numberMisscheduled = 2; + + // The total number of nodes that should be running the daemon + // pod (including nodes correctly running the daemon pod). + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/ + optional int32 desiredNumberScheduled = 3; + + // The number of nodes that should be running the daemon pod and have one + // or more of the daemon pod running and ready. + optional int32 numberReady = 4; + + // The most recent generation observed by the daemon set controller. + // +optional + optional int64 observedGeneration = 5; + + // The total number of nodes that are running updated daemon pod + // +optional + optional int32 updatedNumberScheduled = 6; + + // The number of nodes that should be running the + // daemon pod and have one or more of the daemon pod running and + // available (ready for at least spec.minReadySeconds) + // +optional + optional int32 numberAvailable = 7; + + // The number of nodes that should be running the + // daemon pod and have none of the daemon pod running and available + // (ready for at least spec.minReadySeconds) + // +optional + optional int32 numberUnavailable = 8; + + // Count of hash collisions for the DaemonSet. The DaemonSet controller + // uses this field as a collision avoidance mechanism when it needs to + // create the name for the newest ControllerRevision. + // +optional + optional int32 collisionCount = 9; + + // Represents the latest available observations of a DaemonSet's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated DaemonSetCondition conditions = 10; +} + +message DaemonSetUpdateStrategy { + // Type of daemon set update. Can be "RollingUpdate" or "OnDelete". + // Default is OnDelete. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if type = "RollingUpdate". + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. Same as Deployment `strategy.rollingUpdate`. + // See https://github.com/kubernetes/kubernetes/issues/35345 + // +optional + optional RollingUpdateDaemonSet rollingUpdate = 2; +} + +// DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for +// more information. +// Deployment enables declarative updates for Pods and ReplicaSets. +message Deployment { + // Standard object metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the Deployment. + // +optional + optional DeploymentSpec spec = 2; + + // Most recently observed status of the Deployment. + // +optional + optional DeploymentStatus status = 3; +} + +// DeploymentCondition describes the state of a deployment at a certain point. +message DeploymentCondition { + // Type of deployment condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time this condition was updated. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastUpdateTime = 6; + + // Last time the condition transitioned from one status to another. + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 7; + + // The reason for the condition's last transition. + optional string reason = 4; + + // A human readable message indicating details about the transition. + optional string message = 5; +} + +// DeploymentList is a list of Deployments. +message DeploymentList { + // Standard list metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of Deployments. + repeated Deployment items = 2; +} + +// DEPRECATED. +// DeploymentRollback stores the information required to rollback a deployment. +message DeploymentRollback { + // Required: This must match the Name of a deployment. + optional string name = 1; + + // The annotations to be updated to a deployment + // +optional + map<string, string> updatedAnnotations = 2; + + // The config of this deployment rollback. + optional RollbackConfig rollbackTo = 3; +} + +// DeploymentSpec is the specification of the desired behavior of the Deployment. +message DeploymentSpec { + // Number of desired pods. This is a pointer to distinguish between explicit + // zero and not specified. Defaults to 1. + // +optional + optional int32 replicas = 1; + + // Label selector for pods. Existing ReplicaSets whose pods are + // selected by this will be the ones affected by this deployment. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template describes the pods that will be created. + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; + + // The deployment strategy to use to replace existing pods with new ones. + // +optional + // +patchStrategy=retainKeys + optional DeploymentStrategy strategy = 4; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 5; + + // The number of old ReplicaSets to retain to allow rollback. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + optional int32 revisionHistoryLimit = 6; + + // Indicates that the deployment is paused and will not be processed by the + // deployment controller. + // +optional + optional bool paused = 7; + + // DEPRECATED. + // The config this deployment is rolling back to. Will be cleared after rollback is done. + // +optional + optional RollbackConfig rollbackTo = 8; + + // The maximum time in seconds for a deployment to make progress before it + // is considered to be failed. The deployment controller will continue to + // process failed deployments and a condition with a ProgressDeadlineExceeded + // reason will be surfaced in the deployment status. Note that progress will + // not be estimated during the time a deployment is paused. This is set to + // the max value of int32 (i.e. 2147483647) by default, which means "no deadline". + // +optional + optional int32 progressDeadlineSeconds = 9; +} + +// DeploymentStatus is the most recently observed status of the Deployment. +message DeploymentStatus { + // The generation observed by the deployment controller. + // +optional + optional int64 observedGeneration = 1; + + // Total number of non-terminated pods targeted by this deployment (their labels match the selector). + // +optional + optional int32 replicas = 2; + + // Total number of non-terminated pods targeted by this deployment that have the desired template spec. + // +optional + optional int32 updatedReplicas = 3; + + // Total number of ready pods targeted by this deployment. + // +optional + optional int32 readyReplicas = 7; + + // Total number of available pods (ready for at least minReadySeconds) targeted by this deployment. + // +optional + optional int32 availableReplicas = 4; + + // Total number of unavailable pods targeted by this deployment. This is the total number of + // pods that are still required for the deployment to have 100% available capacity. They may + // either be pods that are running but not yet available or pods that still have not been created. + // +optional + optional int32 unavailableReplicas = 5; + + // Represents the latest available observations of a deployment's current state. + // +patchMergeKey=type + // +patchStrategy=merge + repeated DeploymentCondition conditions = 6; + + // Count of hash collisions for the Deployment. The Deployment controller uses this + // field as a collision avoidance mechanism when it needs to create the name for the + // newest ReplicaSet. + // +optional + optional int32 collisionCount = 8; +} + +// DeploymentStrategy describes how to replace existing pods with new ones. +message DeploymentStrategy { + // Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + // +optional + optional string type = 1; + + // Rolling update config params. Present only if DeploymentStrategyType = + // RollingUpdate. + // --- + // TODO: Update this to follow our convention for oneOf, whatever we decide it + // to be. + // +optional + optional RollingUpdateDeployment rollingUpdate = 2; +} + +// FSGroupStrategyOptions defines the strategy type and options used to create the strategy. +// Deprecated: use FSGroupStrategyOptions from policy API Group instead. +message FSGroupStrategyOptions { + // rule is the strategy that will dictate what FSGroup is used in the SecurityContext. + // +optional + optional string rule = 1; + + // ranges are the allowed ranges of fs groups. If you would like to force a single + // fs group then supply a single range with the same start and end. Required for MustRunAs. + // +optional + repeated IDRange ranges = 2; +} + +// HTTPIngressPath associates a path regex with a backend. Incoming urls matching +// the path are forwarded to the backend. +message HTTPIngressPath { + // Path is an extended POSIX regex as defined by IEEE Std 1003.1, + // (i.e this follows the egrep/unix syntax, not the perl syntax) + // matched against the path of an incoming request. Currently it can + // contain characters disallowed from the conventional "path" + // part of a URL as defined by RFC 3986. Paths must begin with + // a '/'. If unspecified, the path defaults to a catch all sending + // traffic to the backend. + // +optional + optional string path = 1; + + // Backend defines the referenced service endpoint to which the traffic + // will be forwarded to. + optional IngressBackend backend = 2; +} + +// HTTPIngressRuleValue is a list of http selectors pointing to backends. +// In the example: http://<host>/<path>?<searchpart> -> backend where +// where parts of the url correspond to RFC 3986, this resource will be used +// to match against everything after the last '/' and before the first '?' +// or '#'. +message HTTPIngressRuleValue { + // A collection of paths that map requests to backends. + repeated HTTPIngressPath paths = 1; +} + +// HostPortRange defines a range of host ports that will be enabled by a policy +// for pods to use. It requires both the start and end to be defined. +// Deprecated: use HostPortRange from policy API Group instead. +message HostPortRange { + // min is the start of the range, inclusive. + optional int32 min = 1; + + // max is the end of the range, inclusive. + optional int32 max = 2; +} + +// IDRange provides a min/max of an allowed range of IDs. +// Deprecated: use IDRange from policy API Group instead. +message IDRange { + // min is the start of the range, inclusive. + optional int64 min = 1; + + // max is the end of the range, inclusive. + optional int64 max = 2; +} + +// DEPRECATED 1.9 - This group version of IPBlock is deprecated by networking/v1/IPBlock. +// IPBlock describes a particular CIDR (Ex. "192.168.1.1/24") that is allowed to the pods +// matched by a NetworkPolicySpec's podSelector. The except entry describes CIDRs that should +// not be included within this rule. +message IPBlock { + // CIDR is a string representing the IP Block + // Valid examples are "192.168.1.1/24" + optional string cidr = 1; + + // Except is a slice of CIDRs that should not be included within an IP Block + // Valid examples are "192.168.1.1/24" + // Except values will be rejected if they are outside the CIDR range + // +optional + repeated string except = 2; +} + +// Ingress is a collection of rules that allow inbound connections to reach the +// endpoints defined by a backend. An Ingress can be configured to give services +// externally-reachable urls, load balance traffic, terminate SSL, offer name +// based virtual hosting etc. +message Ingress { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec is the desired state of the Ingress. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional IngressSpec spec = 2; + + // Status is the current state of the Ingress. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional IngressStatus status = 3; +} + +// IngressBackend describes all endpoints for a given service and port. +message IngressBackend { + // Specifies the name of the referenced service. + optional string serviceName = 1; + + // Specifies the port of the referenced service. + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString servicePort = 2; +} + +// IngressList is a collection of Ingress. +message IngressList { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of Ingress. + repeated Ingress items = 2; +} + +// IngressRule represents the rules mapping the paths under a specified host to +// the related backend services. Incoming requests are first evaluated for a host +// match, then routed to the backend associated with the matching IngressRuleValue. +message IngressRule { + // Host is the fully qualified domain name of a network host, as defined + // by RFC 3986. Note the following deviations from the "host" part of the + // URI as defined in the RFC: + // 1. IPs are not allowed. Currently an IngressRuleValue can only apply to the + // IP in the Spec of the parent Ingress. + // 2. The `:` delimiter is not respected because ports are not allowed. + // Currently the port of an Ingress is implicitly :80 for http and + // :443 for https. + // Both these may change in the future. + // Incoming requests are matched against the host before the IngressRuleValue. + // If the host is unspecified, the Ingress routes all traffic based on the + // specified IngressRuleValue. + // +optional + optional string host = 1; + + // IngressRuleValue represents a rule to route requests for this IngressRule. + // If unspecified, the rule defaults to a http catch-all. Whether that sends + // just traffic matching the host to the default backend or all traffic to the + // default backend, is left to the controller fulfilling the Ingress. Http is + // currently the only supported IngressRuleValue. + // +optional + optional IngressRuleValue ingressRuleValue = 2; +} + +// IngressRuleValue represents a rule to apply against incoming requests. If the +// rule is satisfied, the request is routed to the specified backend. Currently +// mixing different types of rules in a single Ingress is disallowed, so exactly +// one of the following must be set. +message IngressRuleValue { + // +optional + optional HTTPIngressRuleValue http = 1; +} + +// IngressSpec describes the Ingress the user wishes to exist. +message IngressSpec { + // A default backend capable of servicing requests that don't match any + // rule. At least one of 'backend' or 'rules' must be specified. This field + // is optional to allow the loadbalancer controller or defaulting logic to + // specify a global default. + // +optional + optional IngressBackend backend = 1; + + // TLS configuration. Currently the Ingress only supports a single TLS + // port, 443. If multiple members of this list specify different hosts, they + // will be multiplexed on the same port according to the hostname specified + // through the SNI TLS extension, if the ingress controller fulfilling the + // ingress supports SNI. + // +optional + repeated IngressTLS tls = 2; + + // A list of host rules used to configure the Ingress. If unspecified, or + // no rule matches, all traffic is sent to the default backend. + // +optional + repeated IngressRule rules = 3; +} + +// IngressStatus describe the current state of the Ingress. +message IngressStatus { + // LoadBalancer contains the current status of the load-balancer. + // +optional + optional k8s.io.api.core.v1.LoadBalancerStatus loadBalancer = 1; +} + +// IngressTLS describes the transport layer security associated with an Ingress. +message IngressTLS { + // Hosts are a list of hosts included in the TLS certificate. The values in + // this list must match the name/s used in the tlsSecret. Defaults to the + // wildcard host setting for the loadbalancer controller fulfilling this + // Ingress, if left unspecified. + // +optional + repeated string hosts = 1; + + // SecretName is the name of the secret used to terminate SSL traffic on 443. + // Field is left optional to allow SSL routing based on SNI hostname alone. + // If the SNI host in a listener conflicts with the "Host" header field used + // by an IngressRule, the SNI host is used for termination and value of the + // Host header is used for routing. + // +optional + optional string secretName = 2; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicy is deprecated by networking/v1/NetworkPolicy. +// NetworkPolicy describes what network traffic is allowed for a set of Pods +message NetworkPolicy { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior for this NetworkPolicy. + // +optional + optional NetworkPolicySpec spec = 2; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicyEgressRule is deprecated by networking/v1/NetworkPolicyEgressRule. +// NetworkPolicyEgressRule describes a particular set of traffic that is allowed out of pods +// matched by a NetworkPolicySpec's podSelector. The traffic must match both ports and to. +// This type is beta-level in 1.8 +message NetworkPolicyEgressRule { + // List of destination ports for outgoing traffic. + // Each item in this list is combined using a logical OR. If this field is + // empty or missing, this rule matches all ports (traffic not restricted by port). + // If this field is present and contains at least one item, then this rule allows + // traffic only if the traffic matches at least one port in the list. + // +optional + repeated NetworkPolicyPort ports = 1; + + // List of destinations for outgoing traffic of pods selected for this rule. + // Items in this list are combined using a logical OR operation. If this field is + // empty or missing, this rule matches all destinations (traffic not restricted by + // destination). If this field is present and contains at least one item, this rule + // allows traffic only if the traffic matches at least one item in the to list. + // +optional + repeated NetworkPolicyPeer to = 2; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicyIngressRule is deprecated by networking/v1/NetworkPolicyIngressRule. +// This NetworkPolicyIngressRule matches traffic if and only if the traffic matches both ports AND from. +message NetworkPolicyIngressRule { + // List of ports which should be made accessible on the pods selected for this rule. + // Each item in this list is combined using a logical OR. + // If this field is empty or missing, this rule matches all ports (traffic not restricted by port). + // If this field is present and contains at least one item, then this rule allows traffic + // only if the traffic matches at least one port in the list. + // +optional + repeated NetworkPolicyPort ports = 1; + + // List of sources which should be able to access the pods selected for this rule. + // Items in this list are combined using a logical OR operation. + // If this field is empty or missing, this rule matches all sources (traffic not restricted by source). + // If this field is present and contains at least on item, this rule allows traffic only if the + // traffic matches at least one item in the from list. + // +optional + repeated NetworkPolicyPeer from = 2; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicyList is deprecated by networking/v1/NetworkPolicyList. +// Network Policy List is a list of NetworkPolicy objects. +message NetworkPolicyList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of schema objects. + repeated NetworkPolicy items = 2; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicyPeer is deprecated by networking/v1/NetworkPolicyPeer. +message NetworkPolicyPeer { + // This is a label selector which selects Pods. This field follows standard label + // selector semantics; if present but empty, it selects all pods. + // + // If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector podSelector = 1; + + // Selects Namespaces using cluster-scoped labels. This field follows standard label + // selector semantics; if present but empty, it selects all namespaces. + // + // If PodSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector namespaceSelector = 2; + + // IPBlock defines policy on a particular IPBlock. If this field is set then + // neither of the other fields can be. + // +optional + optional IPBlock ipBlock = 3; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicyPort is deprecated by networking/v1/NetworkPolicyPort. +message NetworkPolicyPort { + // Optional. The protocol (TCP, UDP, or SCTP) which traffic must match. + // If not specified, this field defaults to TCP. + // +optional + optional string protocol = 1; + + // If specified, the port on the given protocol. This can + // either be a numerical or named port on a pod. If this field is not provided, + // this matches all port names and numbers. + // If present, only traffic on the specified protocol AND port + // will be matched. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString port = 2; +} + +// DEPRECATED 1.9 - This group version of NetworkPolicySpec is deprecated by networking/v1/NetworkPolicySpec. +message NetworkPolicySpec { + // Selects the pods to which this NetworkPolicy object applies. The array of ingress rules + // is applied to any pods selected by this field. Multiple network policies can select the + // same set of pods. In this case, the ingress rules for each are combined additively. + // This field is NOT optional and follows standard label selector semantics. + // An empty podSelector matches all pods in this namespace. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector podSelector = 1; + + // List of ingress rules to be applied to the selected pods. + // Traffic is allowed to a pod if there are no NetworkPolicies selecting the pod + // OR if the traffic source is the pod's local node, + // OR if the traffic matches at least one ingress rule across all of the NetworkPolicy + // objects whose podSelector matches the pod. + // If this field is empty then this NetworkPolicy does not allow any traffic + // (and serves solely to ensure that the pods it selects are isolated by default). + // +optional + repeated NetworkPolicyIngressRule ingress = 2; + + // List of egress rules to be applied to the selected pods. Outgoing traffic is + // allowed if there are no NetworkPolicies selecting the pod (and cluster policy + // otherwise allows the traffic), OR if the traffic matches at least one egress rule + // across all of the NetworkPolicy objects whose podSelector matches the pod. If + // this field is empty then this NetworkPolicy limits all outgoing traffic (and serves + // solely to ensure that the pods it selects are isolated by default). + // This field is beta-level in 1.8 + // +optional + repeated NetworkPolicyEgressRule egress = 3; + + // List of rule types that the NetworkPolicy relates to. + // Valid options are Ingress, Egress, or Ingress,Egress. + // If this field is not specified, it will default based on the existence of Ingress or Egress rules; + // policies that contain an Egress section are assumed to affect Egress, and all policies + // (whether or not they contain an Ingress section) are assumed to affect Ingress. + // If you want to write an egress-only policy, you must explicitly specify policyTypes [ "Egress" ]. + // Likewise, if you want to write a policy that specifies that no egress is allowed, + // you must specify a policyTypes value that include "Egress" (since such a policy would not include + // an Egress section and would otherwise default to just [ "Ingress" ]). + // This field is beta-level in 1.8 + // +optional + repeated string policyTypes = 4; +} + +// PodSecurityPolicy governs the ability to make requests that affect the Security Context +// that will be applied to a pod and container. +// Deprecated: use PodSecurityPolicy from policy API Group instead. +message PodSecurityPolicy { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // spec defines the policy enforced. + // +optional + optional PodSecurityPolicySpec spec = 2; +} + +// PodSecurityPolicyList is a list of PodSecurityPolicy objects. +// Deprecated: use PodSecurityPolicyList from policy API Group instead. +message PodSecurityPolicyList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is a list of schema objects. + repeated PodSecurityPolicy items = 2; +} + +// PodSecurityPolicySpec defines the policy enforced. +// Deprecated: use PodSecurityPolicySpec from policy API Group instead. +message PodSecurityPolicySpec { + // privileged determines if a pod can request to be run as privileged. + // +optional + optional bool privileged = 1; + + // defaultAddCapabilities is the default set of capabilities that will be added to the container + // unless the pod spec specifically drops the capability. You may not list a capability in both + // defaultAddCapabilities and requiredDropCapabilities. Capabilities added here are implicitly + // allowed, and need not be included in the allowedCapabilities list. + // +optional + repeated string defaultAddCapabilities = 2; + + // requiredDropCapabilities are the capabilities that will be dropped from the container. These + // are required to be dropped and cannot be added. + // +optional + repeated string requiredDropCapabilities = 3; + + // allowedCapabilities is a list of capabilities that can be requested to add to the container. + // Capabilities in this field may be added at the pod author's discretion. + // You must not list a capability in both allowedCapabilities and requiredDropCapabilities. + // +optional + repeated string allowedCapabilities = 4; + + // volumes is a white list of allowed volume plugins. Empty indicates that + // no volumes may be used. To allow all volumes you may use '*'. + // +optional + repeated string volumes = 5; + + // hostNetwork determines if the policy allows the use of HostNetwork in the pod spec. + // +optional + optional bool hostNetwork = 6; + + // hostPorts determines which host port ranges are allowed to be exposed. + // +optional + repeated HostPortRange hostPorts = 7; + + // hostPID determines if the policy allows the use of HostPID in the pod spec. + // +optional + optional bool hostPID = 8; + + // hostIPC determines if the policy allows the use of HostIPC in the pod spec. + // +optional + optional bool hostIPC = 9; + + // seLinux is the strategy that will dictate the allowable labels that may be set. + optional SELinuxStrategyOptions seLinux = 10; + + // runAsUser is the strategy that will dictate the allowable RunAsUser values that may be set. + optional RunAsUserStrategyOptions runAsUser = 11; + + // supplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext. + optional SupplementalGroupsStrategyOptions supplementalGroups = 12; + + // fsGroup is the strategy that will dictate what fs group is used by the SecurityContext. + optional FSGroupStrategyOptions fsGroup = 13; + + // readOnlyRootFilesystem when set to true will force containers to run with a read only root file + // system. If the container specifically requests to run with a non-read only root file system + // the PSP should deny the pod. + // If set to false the container may run with a read only root file system if it wishes but it + // will not be forced to. + // +optional + optional bool readOnlyRootFilesystem = 14; + + // defaultAllowPrivilegeEscalation controls the default setting for whether a + // process can gain more privileges than its parent process. + // +optional + optional bool defaultAllowPrivilegeEscalation = 15; + + // allowPrivilegeEscalation determines if a pod can request to allow + // privilege escalation. If unspecified, defaults to true. + // +optional + optional bool allowPrivilegeEscalation = 16; + + // allowedHostPaths is a white list of allowed host paths. Empty indicates + // that all host paths may be used. + // +optional + repeated AllowedHostPath allowedHostPaths = 17; + + // allowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all + // Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes + // is allowed in the "volumes" field. + // +optional + repeated AllowedFlexVolume allowedFlexVolumes = 18; + + // allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none. + // Each entry is either a plain sysctl name or ends in "*" in which case it is considered + // as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed. + // Kubelet has to whitelist all allowed unsafe sysctls explicitly to avoid rejection. + // + // Examples: + // e.g. "foo/*" allows "foo/bar", "foo/baz", etc. + // e.g. "foo.*" allows "foo.bar", "foo.baz", etc. + // +optional + repeated string allowedUnsafeSysctls = 19; + + // forbiddenSysctls is a list of explicitly forbidden sysctls, defaults to none. + // Each entry is either a plain sysctl name or ends in "*" in which case it is considered + // as a prefix of forbidden sysctls. Single * means all sysctls are forbidden. + // + // Examples: + // e.g. "foo/*" forbids "foo/bar", "foo/baz", etc. + // e.g. "foo.*" forbids "foo.bar", "foo.baz", etc. + // +optional + repeated string forbiddenSysctls = 20; + + // AllowedProcMountTypes is a whitelist of allowed ProcMountTypes. + // Empty or nil indicates that only the DefaultProcMountType may be used. + // This requires the ProcMountType feature flag to be enabled. + // +optional + repeated string allowedProcMountTypes = 21; +} + +// DEPRECATED - This group version of ReplicaSet is deprecated by apps/v1beta2/ReplicaSet. See the release notes for +// more information. +// ReplicaSet ensures that a specified number of pod replicas are running at any given time. +message ReplicaSet { + // If the Labels of a ReplicaSet are empty, they are defaulted to + // be the same as the Pod(s) that the ReplicaSet manages. + // Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Spec defines the specification of the desired behavior of the ReplicaSet. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicaSetSpec spec = 2; + + // Status is the most recently observed status of the ReplicaSet. + // This data may be out of date by some window of time. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional ReplicaSetStatus status = 3; +} + +// ReplicaSetCondition describes the state of a replica set at a certain point. +message ReplicaSetCondition { + // Type of replica set condition. + optional string type = 1; + + // Status of the condition, one of True, False, Unknown. + optional string status = 2; + + // The last time the condition transitioned from one status to another. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3; + + // The reason for the condition's last transition. + // +optional + optional string reason = 4; + + // A human readable message indicating details about the transition. + // +optional + optional string message = 5; +} + +// ReplicaSetList is a collection of ReplicaSets. +message ReplicaSetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of ReplicaSets. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller + repeated ReplicaSet items = 2; +} + +// ReplicaSetSpec is the specification of a ReplicaSet. +message ReplicaSetSpec { + // Replicas is the number of desired replicas. + // This is a pointer to distinguish between explicit zero and unspecified. + // Defaults to 1. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller + // +optional + optional int32 replicas = 1; + + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing, for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + optional int32 minReadySeconds = 4; + + // Selector is a label query over pods that should match the replica count. + // If the selector is empty, it is defaulted to the labels present on the pod template. + // Label keys and values that must match in order to be controlled by this replica set. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // Template is the object that describes the pod that will be created if + // insufficient replicas are detected. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template + // +optional + optional k8s.io.api.core.v1.PodTemplateSpec template = 3; +} + +// ReplicaSetStatus represents the current status of a ReplicaSet. +message ReplicaSetStatus { + // Replicas is the most recently oberved number of replicas. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller + optional int32 replicas = 1; + + // The number of pods that have labels matching the labels of the pod template of the replicaset. + // +optional + optional int32 fullyLabeledReplicas = 2; + + // The number of ready replicas for this replica set. + // +optional + optional int32 readyReplicas = 4; + + // The number of available replicas (ready for at least minReadySeconds) for this replica set. + // +optional + optional int32 availableReplicas = 5; + + // ObservedGeneration reflects the generation of the most recently observed ReplicaSet. + // +optional + optional int64 observedGeneration = 3; + + // Represents the latest available observations of a replica set's current state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + repeated ReplicaSetCondition conditions = 6; +} + +// Dummy definition +message ReplicationControllerDummy { +} + +// DEPRECATED. +message RollbackConfig { + // The revision to rollback to. If set to 0, rollback to the last revision. + // +optional + optional int64 revision = 1; +} + +// Spec to control the desired behavior of daemon set rolling update. +message RollingUpdateDaemonSet { + // The maximum number of DaemonSet pods that can be unavailable during the + // update. Value can be an absolute number (ex: 5) or a percentage of total + // number of DaemonSet pods at the start of the update (ex: 10%). Absolute + // number is calculated from percentage by rounding up. + // This cannot be 0. + // Default value is 1. + // Example: when this is set to 30%, at most 30% of the total number of nodes + // that should be running the daemon pod (i.e. status.desiredNumberScheduled) + // can have their pods stopped for an update at any given + // time. The update starts by stopping at most 30% of those DaemonSet pods + // and then brings up new DaemonSet pods in their place. Once the new pods + // are available, it then proceeds onto other DaemonSet pods, thus ensuring + // that at least 70% of original number of DaemonSet pods are available at + // all times during the update. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; +} + +// Spec to control the desired behavior of rolling update. +message RollingUpdateDeployment { + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding down. + // This can not be 0 if MaxSurge is 0. + // By default, a fixed value of 1 is used. + // Example: when this is set to 30%, the old RC can be scaled down to 70% of desired pods + // immediately when the rolling update starts. Once new pods are ready, old RC + // can be scaled down further, followed by scaling up the new RC, ensuring + // that the total number of pods available at all times during the update is at + // least 70% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 1; + + // The maximum number of pods that can be scheduled above the desired number of + // pods. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // This can not be 0 if MaxUnavailable is 0. + // Absolute number is calculated from percentage by rounding up. + // By default, a value of 1 is used. + // Example: when this is set to 30%, the new RC can be scaled up immediately when + // the rolling update starts, such that the total number of old and new pods do not exceed + // 130% of desired pods. Once old pods have been killed, + // new RC can be scaled up further, ensuring that total number of pods running + // at any time during the update is atmost 130% of desired pods. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxSurge = 2; +} + +// RunAsUserStrategyOptions defines the strategy type and any options used to create the strategy. +// Deprecated: use RunAsUserStrategyOptions from policy API Group instead. +message RunAsUserStrategyOptions { + // rule is the strategy that will dictate the allowable RunAsUser values that may be set. + optional string rule = 1; + + // ranges are the allowed ranges of uids that may be used. If you would like to force a single uid + // then supply a single range with the same start and end. Required for MustRunAs. + // +optional + repeated IDRange ranges = 2; +} + +// SELinuxStrategyOptions defines the strategy type and any options used to create the strategy. +// Deprecated: use SELinuxStrategyOptions from policy API Group instead. +message SELinuxStrategyOptions { + // rule is the strategy that will dictate the allowable labels that may be set. + optional string rule = 1; + + // seLinuxOptions required to run as; required for MustRunAs + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + // +optional + optional k8s.io.api.core.v1.SELinuxOptions seLinuxOptions = 2; +} + +// represents a scaling request for a resource. +message Scale { + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // defines the behavior of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. + // +optional + optional ScaleSpec spec = 2; + + // current status of the scale. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status. Read-only. + // +optional + optional ScaleStatus status = 3; +} + +// describes the attributes of a scale subresource +message ScaleSpec { + // desired number of instances for the scaled object. + // +optional + optional int32 replicas = 1; +} + +// represents the current status of a scale subresource. +message ScaleStatus { + // actual number of observed instances of the scaled object. + optional int32 replicas = 1; + + // label query over pods that should match the replicas count. More info: http://kubernetes.io/docs/user-guide/labels#label-selectors + // +optional + map<string, string> selector = 2; + + // label selector for pods that should match the replicas count. This is a serializated + // version of both map-based and more expressive set-based selectors. This is done to + // avoid introspection in the clients. The string will be in the same format as the + // query-param syntax. If the target type only supports map-based selectors, both this + // field and map-based selector field are populated. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + optional string targetSelector = 3; +} + +// SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy. +// Deprecated: use SupplementalGroupsStrategyOptions from policy API Group instead. +message SupplementalGroupsStrategyOptions { + // rule is the strategy that will dictate what supplemental groups is used in the SecurityContext. + // +optional + optional string rule = 1; + + // ranges are the allowed ranges of supplemental groups. If you would like to force a single + // supplemental group then supply a single range with the same start and end. Required for MustRunAs. + // +optional + repeated IDRange ranges = 2; +} + diff --git a/vendor/k8s.io/api/networking/OWNERS b/vendor/k8s.io/api/networking/OWNERS new file mode 100755 index 000000000..0e696c0fb --- /dev/null +++ b/vendor/k8s.io/api/networking/OWNERS @@ -0,0 +1,5 @@ +reviewers: +- caseydavenport +- cmluciano +- danwinship +- thockin diff --git a/vendor/k8s.io/api/networking/v1/generated.proto b/vendor/k8s.io/api/networking/v1/generated.proto new file mode 100644 index 000000000..4e068d08f --- /dev/null +++ b/vendor/k8s.io/api/networking/v1/generated.proto @@ -0,0 +1,195 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.networking.v1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// IPBlock describes a particular CIDR (Ex. "192.168.1.1/24") that is allowed to the pods +// matched by a NetworkPolicySpec's podSelector. The except entry describes CIDRs that should +// not be included within this rule. +message IPBlock { + // CIDR is a string representing the IP Block + // Valid examples are "192.168.1.1/24" + optional string cidr = 1; + + // Except is a slice of CIDRs that should not be included within an IP Block + // Valid examples are "192.168.1.1/24" + // Except values will be rejected if they are outside the CIDR range + // +optional + repeated string except = 2; +} + +// NetworkPolicy describes what network traffic is allowed for a set of Pods +message NetworkPolicy { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior for this NetworkPolicy. + // +optional + optional NetworkPolicySpec spec = 2; +} + +// NetworkPolicyEgressRule describes a particular set of traffic that is allowed out of pods +// matched by a NetworkPolicySpec's podSelector. The traffic must match both ports and to. +// This type is beta-level in 1.8 +message NetworkPolicyEgressRule { + // List of destination ports for outgoing traffic. + // Each item in this list is combined using a logical OR. If this field is + // empty or missing, this rule matches all ports (traffic not restricted by port). + // If this field is present and contains at least one item, then this rule allows + // traffic only if the traffic matches at least one port in the list. + // +optional + repeated NetworkPolicyPort ports = 1; + + // List of destinations for outgoing traffic of pods selected for this rule. + // Items in this list are combined using a logical OR operation. If this field is + // empty or missing, this rule matches all destinations (traffic not restricted by + // destination). If this field is present and contains at least one item, this rule + // allows traffic only if the traffic matches at least one item in the to list. + // +optional + repeated NetworkPolicyPeer to = 2; +} + +// NetworkPolicyIngressRule describes a particular set of traffic that is allowed to the pods +// matched by a NetworkPolicySpec's podSelector. The traffic must match both ports and from. +message NetworkPolicyIngressRule { + // List of ports which should be made accessible on the pods selected for this + // rule. Each item in this list is combined using a logical OR. If this field is + // empty or missing, this rule matches all ports (traffic not restricted by port). + // If this field is present and contains at least one item, then this rule allows + // traffic only if the traffic matches at least one port in the list. + // +optional + repeated NetworkPolicyPort ports = 1; + + // List of sources which should be able to access the pods selected for this rule. + // Items in this list are combined using a logical OR operation. If this field is + // empty or missing, this rule matches all sources (traffic not restricted by + // source). If this field is present and contains at least on item, this rule + // allows traffic only if the traffic matches at least one item in the from list. + // +optional + repeated NetworkPolicyPeer from = 2; +} + +// NetworkPolicyList is a list of NetworkPolicy objects. +message NetworkPolicyList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of schema objects. + repeated NetworkPolicy items = 2; +} + +// NetworkPolicyPeer describes a peer to allow traffic from. Only certain combinations of +// fields are allowed +message NetworkPolicyPeer { + // This is a label selector which selects Pods. This field follows standard label + // selector semantics; if present but empty, it selects all pods. + // + // If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects the Pods matching PodSelector in the policy's own Namespace. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector podSelector = 1; + + // Selects Namespaces using cluster-scoped labels. This field follows standard label + // selector semantics; if present but empty, it selects all namespaces. + // + // If PodSelector is also set, then the NetworkPolicyPeer as a whole selects + // the Pods matching PodSelector in the Namespaces selected by NamespaceSelector. + // Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector namespaceSelector = 2; + + // IPBlock defines policy on a particular IPBlock. If this field is set then + // neither of the other fields can be. + // +optional + optional IPBlock ipBlock = 3; +} + +// NetworkPolicyPort describes a port to allow traffic on +message NetworkPolicyPort { + // The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this + // field defaults to TCP. + // +optional + optional string protocol = 1; + + // The port on the given protocol. This can either be a numerical or named port on + // a pod. If this field is not provided, this matches all port names and numbers. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString port = 2; +} + +// NetworkPolicySpec provides the specification of a NetworkPolicy +message NetworkPolicySpec { + // Selects the pods to which this NetworkPolicy object applies. The array of + // ingress rules is applied to any pods selected by this field. Multiple network + // policies can select the same set of pods. In this case, the ingress rules for + // each are combined additively. This field is NOT optional and follows standard + // label selector semantics. An empty podSelector matches all pods in this + // namespace. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector podSelector = 1; + + // List of ingress rules to be applied to the selected pods. Traffic is allowed to + // a pod if there are no NetworkPolicies selecting the pod + // (and cluster policy otherwise allows the traffic), OR if the traffic source is + // the pod's local node, OR if the traffic matches at least one ingress rule + // across all of the NetworkPolicy objects whose podSelector matches the pod. If + // this field is empty then this NetworkPolicy does not allow any traffic (and serves + // solely to ensure that the pods it selects are isolated by default) + // +optional + repeated NetworkPolicyIngressRule ingress = 2; + + // List of egress rules to be applied to the selected pods. Outgoing traffic is + // allowed if there are no NetworkPolicies selecting the pod (and cluster policy + // otherwise allows the traffic), OR if the traffic matches at least one egress rule + // across all of the NetworkPolicy objects whose podSelector matches the pod. If + // this field is empty then this NetworkPolicy limits all outgoing traffic (and serves + // solely to ensure that the pods it selects are isolated by default). + // This field is beta-level in 1.8 + // +optional + repeated NetworkPolicyEgressRule egress = 3; + + // List of rule types that the NetworkPolicy relates to. + // Valid options are Ingress, Egress, or Ingress,Egress. + // If this field is not specified, it will default based on the existence of Ingress or Egress rules; + // policies that contain an Egress section are assumed to affect Egress, and all policies + // (whether or not they contain an Ingress section) are assumed to affect Ingress. + // If you want to write an egress-only policy, you must explicitly specify policyTypes [ "Egress" ]. + // Likewise, if you want to write a policy that specifies that no egress is allowed, + // you must specify a policyTypes value that include "Egress" (since such a policy would not include + // an Egress section and would otherwise default to just [ "Ingress" ]). + // This field is beta-level in 1.8 + // +optional + repeated string policyTypes = 4; +} + diff --git a/vendor/k8s.io/api/policy/OWNERS b/vendor/k8s.io/api/policy/OWNERS new file mode 100755 index 000000000..a245fde35 --- /dev/null +++ b/vendor/k8s.io/api/policy/OWNERS @@ -0,0 +1,8 @@ +approvers: +- sig-apps-api-approvers +reviewers: +- sig-apps-reviewers +- pweil- +- liggitt +- tallclair +- php-coder diff --git a/vendor/k8s.io/api/policy/v1beta1/generated.proto b/vendor/k8s.io/api/policy/v1beta1/generated.proto new file mode 100644 index 000000000..aa37d948f --- /dev/null +++ b/vendor/k8s.io/api/policy/v1beta1/generated.proto @@ -0,0 +1,341 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.policy.v1beta1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; +import "k8s.io/apimachinery/pkg/util/intstr/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// AllowedFlexVolume represents a single Flexvolume that is allowed to be used. +message AllowedFlexVolume { + // driver is the name of the Flexvolume driver. + optional string driver = 1; +} + +// AllowedHostPath defines the host volume conditions that will be enabled by a policy +// for pods to use. It requires the path prefix to be defined. +message AllowedHostPath { + // pathPrefix is the path prefix that the host volume must match. + // It does not support `*`. + // Trailing slashes are trimmed when validating the path prefix with a host path. + // + // Examples: + // `/foo` would allow `/foo`, `/foo/` and `/foo/bar` + // `/foo` would not allow `/food` or `/etc/foo` + optional string pathPrefix = 1; + + // when set to true, will allow host volumes matching the pathPrefix only if all volume mounts are readOnly. + // +optional + optional bool readOnly = 2; +} + +// Eviction evicts a pod from its node subject to certain policies and safety constraints. +// This is a subresource of Pod. A request to cause such an eviction is +// created by POSTing to .../pods/<pod name>/evictions. +message Eviction { + // ObjectMeta describes the pod that is being evicted. + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // DeleteOptions may be provided + optional k8s.io.apimachinery.pkg.apis.meta.v1.DeleteOptions deleteOptions = 2; +} + +// FSGroupStrategyOptions defines the strategy type and options used to create the strategy. +message FSGroupStrategyOptions { + // rule is the strategy that will dictate what FSGroup is used in the SecurityContext. + // +optional + optional string rule = 1; + + // ranges are the allowed ranges of fs groups. If you would like to force a single + // fs group then supply a single range with the same start and end. Required for MustRunAs. + // +optional + repeated IDRange ranges = 2; +} + +// HostPortRange defines a range of host ports that will be enabled by a policy +// for pods to use. It requires both the start and end to be defined. +message HostPortRange { + // min is the start of the range, inclusive. + optional int32 min = 1; + + // max is the end of the range, inclusive. + optional int32 max = 2; +} + +// IDRange provides a min/max of an allowed range of IDs. +message IDRange { + // min is the start of the range, inclusive. + optional int64 min = 1; + + // max is the end of the range, inclusive. + optional int64 max = 2; +} + +// PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods +message PodDisruptionBudget { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired behavior of the PodDisruptionBudget. + optional PodDisruptionBudgetSpec spec = 2; + + // Most recently observed status of the PodDisruptionBudget. + optional PodDisruptionBudgetStatus status = 3; +} + +// PodDisruptionBudgetList is a collection of PodDisruptionBudgets. +message PodDisruptionBudgetList { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + repeated PodDisruptionBudget items = 2; +} + +// PodDisruptionBudgetSpec is a description of a PodDisruptionBudget. +message PodDisruptionBudgetSpec { + // An eviction is allowed if at least "minAvailable" pods selected by + // "selector" will still be available after the eviction, i.e. even in the + // absence of the evicted pod. So for example you can prevent all voluntary + // evictions by specifying "100%". + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString minAvailable = 1; + + // Label query over pods whose evictions are managed by the disruption + // budget. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2; + + // An eviction is allowed if at most "maxUnavailable" pods selected by + // "selector" are unavailable after the eviction, i.e. even in absence of + // the evicted pod. For example, one can prevent all voluntary evictions + // by specifying 0. This is a mutually exclusive setting with "minAvailable". + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 3; +} + +// PodDisruptionBudgetStatus represents information about the status of a +// PodDisruptionBudget. Status may trail the actual state of a system. +message PodDisruptionBudgetStatus { + // Most recent generation observed when updating this PDB status. PodDisruptionsAllowed and other + // status informatio is valid only if observedGeneration equals to PDB's object generation. + // +optional + optional int64 observedGeneration = 1; + + // DisruptedPods contains information about pods whose eviction was + // processed by the API server eviction subresource handler but has not + // yet been observed by the PodDisruptionBudget controller. + // A pod will be in this map from the time when the API server processed the + // eviction request to the time when the pod is seen by PDB controller + // as having been marked for deletion (or after a timeout). The key in the map is the name of the pod + // and the value is the time when the API server processed the eviction request. If + // the deletion didn't occur and a pod is still there it will be removed from + // the list automatically by PodDisruptionBudget controller after some time. + // If everything goes smooth this map should be empty for the most of the time. + // Large number of entries in the map may indicate problems with pod deletions. + // +optional + map<string, k8s.io.apimachinery.pkg.apis.meta.v1.Time> disruptedPods = 2; + + // Number of pod disruptions that are currently allowed. + optional int32 disruptionsAllowed = 3; + + // current number of healthy pods + optional int32 currentHealthy = 4; + + // minimum desired number of healthy pods + optional int32 desiredHealthy = 5; + + // total number of pods counted by this disruption budget + optional int32 expectedPods = 6; +} + +// PodSecurityPolicy governs the ability to make requests that affect the Security Context +// that will be applied to a pod and container. +message PodSecurityPolicy { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // spec defines the policy enforced. + // +optional + optional PodSecurityPolicySpec spec = 2; +} + +// PodSecurityPolicyList is a list of PodSecurityPolicy objects. +message PodSecurityPolicyList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is a list of schema objects. + repeated PodSecurityPolicy items = 2; +} + +// PodSecurityPolicySpec defines the policy enforced. +message PodSecurityPolicySpec { + // privileged determines if a pod can request to be run as privileged. + // +optional + optional bool privileged = 1; + + // defaultAddCapabilities is the default set of capabilities that will be added to the container + // unless the pod spec specifically drops the capability. You may not list a capability in both + // defaultAddCapabilities and requiredDropCapabilities. Capabilities added here are implicitly + // allowed, and need not be included in the allowedCapabilities list. + // +optional + repeated string defaultAddCapabilities = 2; + + // requiredDropCapabilities are the capabilities that will be dropped from the container. These + // are required to be dropped and cannot be added. + // +optional + repeated string requiredDropCapabilities = 3; + + // allowedCapabilities is a list of capabilities that can be requested to add to the container. + // Capabilities in this field may be added at the pod author's discretion. + // You must not list a capability in both allowedCapabilities and requiredDropCapabilities. + // +optional + repeated string allowedCapabilities = 4; + + // volumes is a white list of allowed volume plugins. Empty indicates that + // no volumes may be used. To allow all volumes you may use '*'. + // +optional + repeated string volumes = 5; + + // hostNetwork determines if the policy allows the use of HostNetwork in the pod spec. + // +optional + optional bool hostNetwork = 6; + + // hostPorts determines which host port ranges are allowed to be exposed. + // +optional + repeated HostPortRange hostPorts = 7; + + // hostPID determines if the policy allows the use of HostPID in the pod spec. + // +optional + optional bool hostPID = 8; + + // hostIPC determines if the policy allows the use of HostIPC in the pod spec. + // +optional + optional bool hostIPC = 9; + + // seLinux is the strategy that will dictate the allowable labels that may be set. + optional SELinuxStrategyOptions seLinux = 10; + + // runAsUser is the strategy that will dictate the allowable RunAsUser values that may be set. + optional RunAsUserStrategyOptions runAsUser = 11; + + // supplementalGroups is the strategy that will dictate what supplemental groups are used by the SecurityContext. + optional SupplementalGroupsStrategyOptions supplementalGroups = 12; + + // fsGroup is the strategy that will dictate what fs group is used by the SecurityContext. + optional FSGroupStrategyOptions fsGroup = 13; + + // readOnlyRootFilesystem when set to true will force containers to run with a read only root file + // system. If the container specifically requests to run with a non-read only root file system + // the PSP should deny the pod. + // If set to false the container may run with a read only root file system if it wishes but it + // will not be forced to. + // +optional + optional bool readOnlyRootFilesystem = 14; + + // defaultAllowPrivilegeEscalation controls the default setting for whether a + // process can gain more privileges than its parent process. + // +optional + optional bool defaultAllowPrivilegeEscalation = 15; + + // allowPrivilegeEscalation determines if a pod can request to allow + // privilege escalation. If unspecified, defaults to true. + // +optional + optional bool allowPrivilegeEscalation = 16; + + // allowedHostPaths is a white list of allowed host paths. Empty indicates + // that all host paths may be used. + // +optional + repeated AllowedHostPath allowedHostPaths = 17; + + // allowedFlexVolumes is a whitelist of allowed Flexvolumes. Empty or nil indicates that all + // Flexvolumes may be used. This parameter is effective only when the usage of the Flexvolumes + // is allowed in the "volumes" field. + // +optional + repeated AllowedFlexVolume allowedFlexVolumes = 18; + + // allowedUnsafeSysctls is a list of explicitly allowed unsafe sysctls, defaults to none. + // Each entry is either a plain sysctl name or ends in "*" in which case it is considered + // as a prefix of allowed sysctls. Single * means all unsafe sysctls are allowed. + // Kubelet has to whitelist all allowed unsafe sysctls explicitly to avoid rejection. + // + // Examples: + // e.g. "foo/*" allows "foo/bar", "foo/baz", etc. + // e.g. "foo.*" allows "foo.bar", "foo.baz", etc. + // +optional + repeated string allowedUnsafeSysctls = 19; + + // forbiddenSysctls is a list of explicitly forbidden sysctls, defaults to none. + // Each entry is either a plain sysctl name or ends in "*" in which case it is considered + // as a prefix of forbidden sysctls. Single * means all sysctls are forbidden. + // + // Examples: + // e.g. "foo/*" forbids "foo/bar", "foo/baz", etc. + // e.g. "foo.*" forbids "foo.bar", "foo.baz", etc. + // +optional + repeated string forbiddenSysctls = 20; + + // AllowedProcMountTypes is a whitelist of allowed ProcMountTypes. + // Empty or nil indicates that only the DefaultProcMountType may be used. + // This requires the ProcMountType feature flag to be enabled. + // +optional + repeated string allowedProcMountTypes = 21; +} + +// RunAsUserStrategyOptions defines the strategy type and any options used to create the strategy. +message RunAsUserStrategyOptions { + // rule is the strategy that will dictate the allowable RunAsUser values that may be set. + optional string rule = 1; + + // ranges are the allowed ranges of uids that may be used. If you would like to force a single uid + // then supply a single range with the same start and end. Required for MustRunAs. + // +optional + repeated IDRange ranges = 2; +} + +// SELinuxStrategyOptions defines the strategy type and any options used to create the strategy. +message SELinuxStrategyOptions { + // rule is the strategy that will dictate the allowable labels that may be set. + optional string rule = 1; + + // seLinuxOptions required to run as; required for MustRunAs + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + // +optional + optional k8s.io.api.core.v1.SELinuxOptions seLinuxOptions = 2; +} + +// SupplementalGroupsStrategyOptions defines the strategy type and options used to create the strategy. +message SupplementalGroupsStrategyOptions { + // rule is the strategy that will dictate what supplemental groups is used in the SecurityContext. + // +optional + optional string rule = 1; + + // ranges are the allowed ranges of supplemental groups. If you would like to force a single + // supplemental group then supply a single range with the same start and end. Required for MustRunAs. + // +optional + repeated IDRange ranges = 2; +} + diff --git a/vendor/k8s.io/api/rbac/OWNERS b/vendor/k8s.io/api/rbac/OWNERS new file mode 100755 index 000000000..1aefde049 --- /dev/null +++ b/vendor/k8s.io/api/rbac/OWNERS @@ -0,0 +1,17 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- deads2k +- sttts +- ncdc +- dims +- krousey +- mml +- mbohlool +- david-mcmahon +- ericchiang +- lixiaobing10051267 +- jianhuiz +- liggitt +- enj diff --git a/vendor/k8s.io/api/rbac/v1/generated.proto b/vendor/k8s.io/api/rbac/v1/generated.proto new file mode 100644 index 000000000..4b321a7c2 --- /dev/null +++ b/vendor/k8s.io/api/rbac/v1/generated.proto @@ -0,0 +1,197 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.rbac.v1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole +message AggregationRule { + // ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. + // If any of the selectors match, then the ClusterRole's permissions will be added + // +optional + repeated k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector clusterRoleSelectors = 1; +} + +// ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. +message ClusterRole { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Rules holds all the PolicyRules for this ClusterRole + repeated PolicyRule rules = 2; + + // AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. + // If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be + // stomped by the controller. + // +optional + optional AggregationRule aggregationRule = 3; +} + +// ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, +// and adds who information via Subject. +message ClusterRoleBinding { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Subjects holds references to the objects the role applies to. + // +optional + repeated Subject subjects = 2; + + // RoleRef can only reference a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + optional RoleRef roleRef = 3; +} + +// ClusterRoleBindingList is a collection of ClusterRoleBindings +message ClusterRoleBindingList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ClusterRoleBindings + repeated ClusterRoleBinding items = 2; +} + +// ClusterRoleList is a collection of ClusterRoles +message ClusterRoleList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ClusterRoles + repeated ClusterRole items = 2; +} + +// PolicyRule holds information that describes a policy rule, but does not contain information +// about who the rule applies to or which namespace the rule applies to. +message PolicyRule { + // Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds. + repeated string verbs = 1; + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. + // +optional + repeated string apiGroups = 2; + + // Resources is a list of resources this rule applies to. ResourceAll represents all resources. + // +optional + repeated string resources = 3; + + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +optional + repeated string resourceNames = 4; + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path + // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. + // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + // +optional + repeated string nonResourceURLs = 5; +} + +// Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. +message Role { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Rules holds all the PolicyRules for this Role + repeated PolicyRule rules = 2; +} + +// RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. +// It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given +// namespace only have effect in that namespace. +message RoleBinding { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Subjects holds references to the objects the role applies to. + // +optional + repeated Subject subjects = 2; + + // RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + optional RoleRef roleRef = 3; +} + +// RoleBindingList is a collection of RoleBindings +message RoleBindingList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of RoleBindings + repeated RoleBinding items = 2; +} + +// RoleList is a collection of Roles +message RoleList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of Roles + repeated Role items = 2; +} + +// RoleRef contains information that points to the role being used +message RoleRef { + // APIGroup is the group for the resource being referenced + optional string apiGroup = 1; + + // Kind is the type of resource being referenced + optional string kind = 2; + + // Name is the name of resource being referenced + optional string name = 3; +} + +// Subject contains a reference to the object or user identities a role binding applies to. This can either hold a direct API object reference, +// or a value for non-objects such as user and group names. +message Subject { + // Kind of object being referenced. Values defined by this API group are "User", "Group", and "ServiceAccount". + // If the Authorizer does not recognized the kind value, the Authorizer should report an error. + optional string kind = 1; + + // APIGroup holds the API group of the referenced subject. + // Defaults to "" for ServiceAccount subjects. + // Defaults to "rbac.authorization.k8s.io" for User and Group subjects. + // +optional + optional string apiGroup = 2; + + // Name of the object being referenced. + optional string name = 3; + + // Namespace of the referenced object. If the object kind is non-namespace, such as "User" or "Group", and this value is not empty + // the Authorizer should report an error. + // +optional + optional string namespace = 4; +} + diff --git a/vendor/k8s.io/api/rbac/v1alpha1/generated.proto b/vendor/k8s.io/api/rbac/v1alpha1/generated.proto new file mode 100644 index 000000000..cde3aaac9 --- /dev/null +++ b/vendor/k8s.io/api/rbac/v1alpha1/generated.proto @@ -0,0 +1,199 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.rbac.v1alpha1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1alpha1"; + +// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole +message AggregationRule { + // ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. + // If any of the selectors match, then the ClusterRole's permissions will be added + // +optional + repeated k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector clusterRoleSelectors = 1; +} + +// ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. +message ClusterRole { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Rules holds all the PolicyRules for this ClusterRole + repeated PolicyRule rules = 2; + + // AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. + // If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be + // stomped by the controller. + // +optional + optional AggregationRule aggregationRule = 3; +} + +// ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, +// and adds who information via Subject. +message ClusterRoleBinding { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Subjects holds references to the objects the role applies to. + // +optional + repeated Subject subjects = 2; + + // RoleRef can only reference a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + optional RoleRef roleRef = 3; +} + +// ClusterRoleBindingList is a collection of ClusterRoleBindings +message ClusterRoleBindingList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ClusterRoleBindings + repeated ClusterRoleBinding items = 2; +} + +// ClusterRoleList is a collection of ClusterRoles +message ClusterRoleList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ClusterRoles + repeated ClusterRole items = 2; +} + +// PolicyRule holds information that describes a policy rule, but does not contain information +// about who the rule applies to or which namespace the rule applies to. +message PolicyRule { + // Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds. + repeated string verbs = 1; + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. + // +optional + repeated string apiGroups = 3; + + // Resources is a list of resources this rule applies to. ResourceAll represents all resources. + // +optional + repeated string resources = 4; + + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +optional + repeated string resourceNames = 5; + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path + // This name is intentionally different than the internal type so that the DefaultConvert works nicely and because the ordering may be different. + // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. + // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + // +optional + repeated string nonResourceURLs = 6; +} + +// Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. +message Role { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Rules holds all the PolicyRules for this Role + repeated PolicyRule rules = 2; +} + +// RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. +// It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given +// namespace only have effect in that namespace. +message RoleBinding { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Subjects holds references to the objects the role applies to. + // +optional + repeated Subject subjects = 2; + + // RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + optional RoleRef roleRef = 3; +} + +// RoleBindingList is a collection of RoleBindings +message RoleBindingList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of RoleBindings + repeated RoleBinding items = 2; +} + +// RoleList is a collection of Roles +message RoleList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of Roles + repeated Role items = 2; +} + +// RoleRef contains information that points to the role being used +message RoleRef { + // APIGroup is the group for the resource being referenced + optional string apiGroup = 1; + + // Kind is the type of resource being referenced + optional string kind = 2; + + // Name is the name of resource being referenced + optional string name = 3; +} + +// Subject contains a reference to the object or user identities a role binding applies to. This can either hold a direct API object reference, +// or a value for non-objects such as user and group names. +message Subject { + // Kind of object being referenced. Values defined by this API group are "User", "Group", and "ServiceAccount". + // If the Authorizer does not recognized the kind value, the Authorizer should report an error. + optional string kind = 1; + + // APIVersion holds the API group and version of the referenced subject. + // Defaults to "v1" for ServiceAccount subjects. + // Defaults to "rbac.authorization.k8s.io/v1alpha1" for User and Group subjects. + // +k8s:conversion-gen=false + // +optional + optional string apiVersion = 2; + + // Name of the object being referenced. + optional string name = 3; + + // Namespace of the referenced object. If the object kind is non-namespace, such as "User" or "Group", and this value is not empty + // the Authorizer should report an error. + // +optional + optional string namespace = 4; +} + diff --git a/vendor/k8s.io/api/rbac/v1beta1/generated.proto b/vendor/k8s.io/api/rbac/v1beta1/generated.proto new file mode 100644 index 000000000..27bd30ce9 --- /dev/null +++ b/vendor/k8s.io/api/rbac/v1beta1/generated.proto @@ -0,0 +1,198 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.rbac.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole +message AggregationRule { + // ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules. + // If any of the selectors match, then the ClusterRole's permissions will be added + // +optional + repeated k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector clusterRoleSelectors = 1; +} + +// ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. +message ClusterRole { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Rules holds all the PolicyRules for this ClusterRole + repeated PolicyRule rules = 2; + + // AggregationRule is an optional field that describes how to build the Rules for this ClusterRole. + // If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be + // stomped by the controller. + // +optional + optional AggregationRule aggregationRule = 3; +} + +// ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, +// and adds who information via Subject. +message ClusterRoleBinding { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Subjects holds references to the objects the role applies to. + // +optional + repeated Subject subjects = 2; + + // RoleRef can only reference a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + optional RoleRef roleRef = 3; +} + +// ClusterRoleBindingList is a collection of ClusterRoleBindings +message ClusterRoleBindingList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ClusterRoleBindings + repeated ClusterRoleBinding items = 2; +} + +// ClusterRoleList is a collection of ClusterRoles +message ClusterRoleList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of ClusterRoles + repeated ClusterRole items = 2; +} + +// PolicyRule holds information that describes a policy rule, but does not contain information +// about who the rule applies to or which namespace the rule applies to. +message PolicyRule { + // Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds. + repeated string verbs = 1; + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. + // +optional + repeated string apiGroups = 2; + + // Resources is a list of resources this rule applies to. '*' represents all resources in the specified apiGroups. + // '*/foo' represents the subresource 'foo' for all resources in the specified apiGroups. + // +optional + repeated string resources = 3; + + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +optional + repeated string resourceNames = 4; + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path + // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. + // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + // +optional + repeated string nonResourceURLs = 5; +} + +// Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. +message Role { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Rules holds all the PolicyRules for this Role + repeated PolicyRule rules = 2; +} + +// RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. +// It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given +// namespace only have effect in that namespace. +message RoleBinding { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Subjects holds references to the objects the role applies to. + // +optional + repeated Subject subjects = 2; + + // RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + optional RoleRef roleRef = 3; +} + +// RoleBindingList is a collection of RoleBindings +message RoleBindingList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of RoleBindings + repeated RoleBinding items = 2; +} + +// RoleList is a collection of Roles +message RoleList { + // Standard object's metadata. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of Roles + repeated Role items = 2; +} + +// RoleRef contains information that points to the role being used +message RoleRef { + // APIGroup is the group for the resource being referenced + optional string apiGroup = 1; + + // Kind is the type of resource being referenced + optional string kind = 2; + + // Name is the name of resource being referenced + optional string name = 3; +} + +// Subject contains a reference to the object or user identities a role binding applies to. This can either hold a direct API object reference, +// or a value for non-objects such as user and group names. +message Subject { + // Kind of object being referenced. Values defined by this API group are "User", "Group", and "ServiceAccount". + // If the Authorizer does not recognized the kind value, the Authorizer should report an error. + optional string kind = 1; + + // APIGroup holds the API group of the referenced subject. + // Defaults to "" for ServiceAccount subjects. + // Defaults to "rbac.authorization.k8s.io" for User and Group subjects. + // +optional + optional string apiGroup = 2; + + // Name of the object being referenced. + optional string name = 3; + + // Namespace of the referenced object. If the object kind is non-namespace, such as "User" or "Group", and this value is not empty + // the Authorizer should report an error. + // +optional + optional string namespace = 4; +} + diff --git a/vendor/k8s.io/api/roundtrip_test.go b/vendor/k8s.io/api/roundtrip_test.go new file mode 100644 index 000000000..0c79c3eb4 --- /dev/null +++ b/vendor/k8s.io/api/roundtrip_test.go @@ -0,0 +1,151 @@ +/* +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. +*/ + +package testing + +import ( + "math/rand" + "testing" + + admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionregv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + admissionregv1beta1 "k8s.io/api/admissionregistration/v1beta1" + appsv1 "k8s.io/api/apps/v1" + appsv1beta1 "k8s.io/api/apps/v1beta1" + appsv1beta2 "k8s.io/api/apps/v1beta2" + authenticationv1 "k8s.io/api/authentication/v1" + authenticationv1beta1 "k8s.io/api/authentication/v1beta1" + authorizationv1 "k8s.io/api/authorization/v1" + authorizationv1beta1 "k8s.io/api/authorization/v1beta1" + autoscalingv1 "k8s.io/api/autoscaling/v1" + autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1" + batchv1 "k8s.io/api/batch/v1" + batchv1beta1 "k8s.io/api/batch/v1beta1" + batchv2alpha1 "k8s.io/api/batch/v2alpha1" + certificatesv1beta1 "k8s.io/api/certificates/v1beta1" + corev1 "k8s.io/api/core/v1" + eventsv1beta1 "k8s.io/api/events/v1beta1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + imagepolicyv1alpha1 "k8s.io/api/imagepolicy/v1alpha1" + networkingv1 "k8s.io/api/networking/v1" + policyv1beta1 "k8s.io/api/policy/v1beta1" + rbacv1 "k8s.io/api/rbac/v1" + rbacv1alpha1 "k8s.io/api/rbac/v1alpha1" + rbacv1beta1 "k8s.io/api/rbac/v1beta1" + schedulingv1alpha1 "k8s.io/api/scheduling/v1alpha1" + schedulingv1beta1 "k8s.io/api/scheduling/v1beta1" + settingsv1alpha1 "k8s.io/api/settings/v1alpha1" + storagev1 "k8s.io/api/storage/v1" + storagev1alpha1 "k8s.io/api/storage/v1alpha1" + storagev1beta1 "k8s.io/api/storage/v1beta1" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" + genericfuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" +) + +var groups = []runtime.SchemeBuilder{ + admissionv1beta1.SchemeBuilder, + admissionregv1alpha1.SchemeBuilder, + admissionregv1beta1.SchemeBuilder, + appsv1beta1.SchemeBuilder, + appsv1beta2.SchemeBuilder, + appsv1.SchemeBuilder, + authenticationv1beta1.SchemeBuilder, + authenticationv1.SchemeBuilder, + authorizationv1beta1.SchemeBuilder, + authorizationv1.SchemeBuilder, + autoscalingv1.SchemeBuilder, + autoscalingv2beta1.SchemeBuilder, + batchv2alpha1.SchemeBuilder, + batchv1beta1.SchemeBuilder, + batchv1.SchemeBuilder, + certificatesv1beta1.SchemeBuilder, + corev1.SchemeBuilder, + eventsv1beta1.SchemeBuilder, + extensionsv1beta1.SchemeBuilder, + imagepolicyv1alpha1.SchemeBuilder, + networkingv1.SchemeBuilder, + policyv1beta1.SchemeBuilder, + rbacv1alpha1.SchemeBuilder, + rbacv1beta1.SchemeBuilder, + rbacv1.SchemeBuilder, + schedulingv1alpha1.SchemeBuilder, + schedulingv1beta1.SchemeBuilder, + settingsv1alpha1.SchemeBuilder, + storagev1alpha1.SchemeBuilder, + storagev1beta1.SchemeBuilder, + storagev1.SchemeBuilder, +} + +func TestRoundTripExternalTypes(t *testing.T) { + for _, builder := range groups { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + + require.NoError(t, builder.AddToScheme(scheme)) + seed := rand.Int63() + // I'm only using the generic fuzzer funcs, but at some point in time we might need to + // switch to specialized. For now we're happy with the current serialization test. + fuzzer := fuzzer.FuzzerFor(genericfuzzer.Funcs, rand.NewSource(seed), codecs) + + roundtrip.RoundTripExternalTypes(t, scheme, codecs, fuzzer, nil) + } +} + +func TestFailRoundTrip(t *testing.T) { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + groupVersion := schema.GroupVersion{Group: "broken", Version: "v1"} + builder := runtime.NewSchemeBuilder(func(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(groupVersion, &BrokenType{}) + metav1.AddToGroupVersion(scheme, groupVersion) + return nil + }) + require.NoError(t, builder.AddToScheme(scheme)) + seed := rand.Int63() + fuzzer := fuzzer.FuzzerFor(genericfuzzer.Funcs, rand.NewSource(seed), codecs) + tmpT := new(testing.T) + roundtrip.RoundTripExternalTypes(tmpT, scheme, codecs, fuzzer, nil) + // It's very hacky way of making sure the DeepCopy is actually invoked inside RoundTripExternalTypes + // used in the other test. If for some reason this tests starts passing we need to fail b/c we're not testing + // the DeepCopy in the other method which we care so much about. + if !tmpT.Failed() { + t.Log("RoundTrip should've failed on DeepCopy but it did not!") + t.FailNow() + } +} + +type BrokenType struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Field1 string `json:"field1,omitempty"` + Field2 string `json:"field2,omitempty"` +} + +func (in *BrokenType) DeepCopy() *BrokenType { + return new(BrokenType) +} + +func (in *BrokenType) DeepCopyObject() runtime.Object { + return in.DeepCopy() +} diff --git a/vendor/k8s.io/api/scheduling/v1alpha1/generated.proto b/vendor/k8s.io/api/scheduling/v1alpha1/generated.proto new file mode 100644 index 000000000..5fb547211 --- /dev/null +++ b/vendor/k8s.io/api/scheduling/v1alpha1/generated.proto @@ -0,0 +1,67 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.scheduling.v1alpha1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1alpha1"; + +// PriorityClass defines mapping from a priority class name to the priority +// integer value. The value can be any valid integer. +message PriorityClass { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The value of this priority class. This is the actual priority that pods + // receive when they have the name of this class in their pod spec. + optional int32 value = 2; + + // globalDefault specifies whether this PriorityClass should be considered as + // the default priority for pods that do not have any priority class. + // Only one PriorityClass can be marked as `globalDefault`. However, if more than + // one PriorityClasses exists with their `globalDefault` field set to true, + // the smallest value of such global default PriorityClasses will be used as the default priority. + // +optional + optional bool globalDefault = 3; + + // description is an arbitrary string that usually provides guidelines on + // when this priority class should be used. + // +optional + optional string description = 4; +} + +// PriorityClassList is a collection of priority classes. +message PriorityClassList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of PriorityClasses + repeated PriorityClass items = 2; +} + diff --git a/vendor/k8s.io/api/scheduling/v1beta1/generated.proto b/vendor/k8s.io/api/scheduling/v1beta1/generated.proto new file mode 100644 index 000000000..0a9575503 --- /dev/null +++ b/vendor/k8s.io/api/scheduling/v1beta1/generated.proto @@ -0,0 +1,67 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.scheduling.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// PriorityClass defines mapping from a priority class name to the priority +// integer value. The value can be any valid integer. +message PriorityClass { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // The value of this priority class. This is the actual priority that pods + // receive when they have the name of this class in their pod spec. + optional int32 value = 2; + + // globalDefault specifies whether this PriorityClass should be considered as + // the default priority for pods that do not have any priority class. + // Only one PriorityClass can be marked as `globalDefault`. However, if more than + // one PriorityClasses exists with their `globalDefault` field set to true, + // the smallest value of such global default PriorityClasses will be used as the default priority. + // +optional + optional bool globalDefault = 3; + + // description is an arbitrary string that usually provides guidelines on + // when this priority class should be used. + // +optional + optional string description = 4; +} + +// PriorityClassList is a collection of priority classes. +message PriorityClassList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of PriorityClasses + repeated PriorityClass items = 2; +} + diff --git a/vendor/k8s.io/api/settings/v1alpha1/generated.proto b/vendor/k8s.io/api/settings/v1alpha1/generated.proto new file mode 100644 index 000000000..d5534c4de --- /dev/null +++ b/vendor/k8s.io/api/settings/v1alpha1/generated.proto @@ -0,0 +1,75 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.settings.v1alpha1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1alpha1"; + +// PodPreset is a policy resource that defines additional runtime +// requirements for a Pod. +message PodPreset { + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // +optional + optional PodPresetSpec spec = 2; +} + +// PodPresetList is a list of PodPreset objects. +message PodPresetList { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is a list of schema objects. + repeated PodPreset items = 2; +} + +// PodPresetSpec is a description of a pod preset. +message PodPresetSpec { + // Selector is a label query over a set of resources, in this case pods. + // Required. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 1; + + // Env defines the collection of EnvVar to inject into containers. + // +optional + repeated k8s.io.api.core.v1.EnvVar env = 2; + + // EnvFrom defines the collection of EnvFromSource to inject into containers. + // +optional + repeated k8s.io.api.core.v1.EnvFromSource envFrom = 3; + + // Volumes defines the collection of Volume to inject into the pod. + // +optional + repeated k8s.io.api.core.v1.Volume volumes = 4; + + // VolumeMounts defines the collection of VolumeMount to inject into containers. + // +optional + repeated k8s.io.api.core.v1.VolumeMount volumeMounts = 5; +} + diff --git a/vendor/k8s.io/api/storage/OWNERS b/vendor/k8s.io/api/storage/OWNERS new file mode 100755 index 000000000..d59ed6e1d --- /dev/null +++ b/vendor/k8s.io/api/storage/OWNERS @@ -0,0 +1,3 @@ +reviewers: +- deads2k +- mbohlool diff --git a/vendor/k8s.io/api/storage/v1/generated.proto b/vendor/k8s.io/api/storage/v1/generated.proto new file mode 100644 index 000000000..d1785659c --- /dev/null +++ b/vendor/k8s.io/api/storage/v1/generated.proto @@ -0,0 +1,90 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.storage.v1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// StorageClass describes the parameters for a class of storage for +// which PersistentVolumes can be dynamically provisioned. +// +// StorageClasses are non-namespaced; the name of the storage class +// according to etcd is in ObjectMeta.Name. +message StorageClass { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Provisioner indicates the type of the provisioner. + optional string provisioner = 2; + + // Parameters holds the parameters for the provisioner that should + // create volumes of this storage class. + // +optional + map<string, string> parameters = 3; + + // Dynamically provisioned PersistentVolumes of this storage class are + // created with this reclaimPolicy. Defaults to Delete. + // +optional + optional string reclaimPolicy = 4; + + // Dynamically provisioned PersistentVolumes of this storage class are + // created with these mountOptions, e.g. ["ro", "soft"]. Not validated - + // mount of the PVs will simply fail if one is invalid. + // +optional + repeated string mountOptions = 5; + + // AllowVolumeExpansion shows whether the storage class allow volume expand + // +optional + optional bool allowVolumeExpansion = 6; + + // VolumeBindingMode indicates how PersistentVolumeClaims should be + // provisioned and bound. When unset, VolumeBindingImmediate is used. + // This field is only honored by servers that enable the VolumeScheduling feature. + // +optional + optional string volumeBindingMode = 7; + + // Restrict the node topologies where volumes can be dynamically provisioned. + // Each volume plugin defines its own supported topology specifications. + // An empty TopologySelectorTerm list means there is no topology restriction. + // This field is only honored by servers that enable the VolumeScheduling feature. + // +optional + repeated k8s.io.api.core.v1.TopologySelectorTerm allowedTopologies = 8; +} + +// StorageClassList is a collection of storage classes. +message StorageClassList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of StorageClasses + repeated StorageClass items = 2; +} + diff --git a/vendor/k8s.io/api/storage/v1alpha1/generated.proto b/vendor/k8s.io/api/storage/v1alpha1/generated.proto new file mode 100644 index 000000000..ccb947540 --- /dev/null +++ b/vendor/k8s.io/api/storage/v1alpha1/generated.proto @@ -0,0 +1,126 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.storage.v1alpha1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1alpha1"; + +// VolumeAttachment captures the intent to attach or detach the specified volume +// to/from the specified node. +// +// VolumeAttachment objects are non-namespaced. +message VolumeAttachment { + // Standard object metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired attach/detach volume behavior. + // Populated by the Kubernetes system. + optional VolumeAttachmentSpec spec = 2; + + // Status of the VolumeAttachment request. + // Populated by the entity completing the attach or detach + // operation, i.e. the external-attacher. + // +optional + optional VolumeAttachmentStatus status = 3; +} + +// VolumeAttachmentList is a collection of VolumeAttachment objects. +message VolumeAttachmentList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of VolumeAttachments + repeated VolumeAttachment items = 2; +} + +// VolumeAttachmentSource represents a volume that should be attached. +// Right now only PersistenVolumes can be attached via external attacher, +// in future we may allow also inline volumes in pods. +// Exactly one member can be set. +message VolumeAttachmentSource { + // Name of the persistent volume to attach. + // +optional + optional string persistentVolumeName = 1; +} + +// VolumeAttachmentSpec is the specification of a VolumeAttachment request. +message VolumeAttachmentSpec { + // Attacher indicates the name of the volume driver that MUST handle this + // request. This is the name returned by GetPluginName(). + optional string attacher = 1; + + // Source represents the volume that should be attached. + optional VolumeAttachmentSource source = 2; + + // The node that the volume should be attached to. + optional string nodeName = 3; +} + +// VolumeAttachmentStatus is the status of a VolumeAttachment request. +message VolumeAttachmentStatus { + // Indicates the volume is successfully attached. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + optional bool attached = 1; + + // Upon successful attach, this field is populated with any + // information returned by the attach operation that must be passed + // into subsequent WaitForAttach or Mount calls. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + // +optional + map<string, string> attachmentMetadata = 2; + + // The last error encountered during attach operation, if any. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + // +optional + optional VolumeError attachError = 3; + + // The last error encountered during detach operation, if any. + // This field must only be set by the entity completing the detach + // operation, i.e. the external-attacher. + // +optional + optional VolumeError detachError = 4; +} + +// VolumeError captures an error encountered during a volume operation. +message VolumeError { + // Time the error was encountered. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time time = 1; + + // String detailing the error encountered during Attach or Detach operation. + // This string maybe logged, so it should not contain sensitive + // information. + // +optional + optional string message = 2; +} + diff --git a/vendor/k8s.io/api/storage/v1beta1/generated.proto b/vendor/k8s.io/api/storage/v1beta1/generated.proto new file mode 100644 index 000000000..ecf53bef6 --- /dev/null +++ b/vendor/k8s.io/api/storage/v1beta1/generated.proto @@ -0,0 +1,186 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.api.storage.v1beta1; + +import "k8s.io/api/core/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// StorageClass describes the parameters for a class of storage for +// which PersistentVolumes can be dynamically provisioned. +// +// StorageClasses are non-namespaced; the name of the storage class +// according to etcd is in ObjectMeta.Name. +message StorageClass { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Provisioner indicates the type of the provisioner. + optional string provisioner = 2; + + // Parameters holds the parameters for the provisioner that should + // create volumes of this storage class. + // +optional + map<string, string> parameters = 3; + + // Dynamically provisioned PersistentVolumes of this storage class are + // created with this reclaimPolicy. Defaults to Delete. + // +optional + optional string reclaimPolicy = 4; + + // Dynamically provisioned PersistentVolumes of this storage class are + // created with these mountOptions, e.g. ["ro", "soft"]. Not validated - + // mount of the PVs will simply fail if one is invalid. + // +optional + repeated string mountOptions = 5; + + // AllowVolumeExpansion shows whether the storage class allow volume expand + // +optional + optional bool allowVolumeExpansion = 6; + + // VolumeBindingMode indicates how PersistentVolumeClaims should be + // provisioned and bound. When unset, VolumeBindingImmediate is used. + // This field is only honored by servers that enable the VolumeScheduling feature. + // +optional + optional string volumeBindingMode = 7; + + // Restrict the node topologies where volumes can be dynamically provisioned. + // Each volume plugin defines its own supported topology specifications. + // An empty TopologySelectorTerm list means there is no topology restriction. + // This field is only honored by servers that enable the VolumeScheduling feature. + // +optional + repeated k8s.io.api.core.v1.TopologySelectorTerm allowedTopologies = 8; +} + +// StorageClassList is a collection of storage classes. +message StorageClassList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of StorageClasses + repeated StorageClass items = 2; +} + +// VolumeAttachment captures the intent to attach or detach the specified volume +// to/from the specified node. +// +// VolumeAttachment objects are non-namespaced. +message VolumeAttachment { + // Standard object metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the desired attach/detach volume behavior. + // Populated by the Kubernetes system. + optional VolumeAttachmentSpec spec = 2; + + // Status of the VolumeAttachment request. + // Populated by the entity completing the attach or detach + // operation, i.e. the external-attacher. + // +optional + optional VolumeAttachmentStatus status = 3; +} + +// VolumeAttachmentList is a collection of VolumeAttachment objects. +message VolumeAttachmentList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // Items is the list of VolumeAttachments + repeated VolumeAttachment items = 2; +} + +// VolumeAttachmentSource represents a volume that should be attached. +// Right now only PersistenVolumes can be attached via external attacher, +// in future we may allow also inline volumes in pods. +// Exactly one member can be set. +message VolumeAttachmentSource { + // Name of the persistent volume to attach. + // +optional + optional string persistentVolumeName = 1; +} + +// VolumeAttachmentSpec is the specification of a VolumeAttachment request. +message VolumeAttachmentSpec { + // Attacher indicates the name of the volume driver that MUST handle this + // request. This is the name returned by GetPluginName(). + optional string attacher = 1; + + // Source represents the volume that should be attached. + optional VolumeAttachmentSource source = 2; + + // The node that the volume should be attached to. + optional string nodeName = 3; +} + +// VolumeAttachmentStatus is the status of a VolumeAttachment request. +message VolumeAttachmentStatus { + // Indicates the volume is successfully attached. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + optional bool attached = 1; + + // Upon successful attach, this field is populated with any + // information returned by the attach operation that must be passed + // into subsequent WaitForAttach or Mount calls. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + // +optional + map<string, string> attachmentMetadata = 2; + + // The last error encountered during attach operation, if any. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + // +optional + optional VolumeError attachError = 3; + + // The last error encountered during detach operation, if any. + // This field must only be set by the entity completing the detach + // operation, i.e. the external-attacher. + // +optional + optional VolumeError detachError = 4; +} + +// VolumeError captures an error encountered during a volume operation. +message VolumeError { + // Time the error was encountered. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Time time = 1; + + // String detailing the error encountered during Attach or Detach operation. + // This string maybe logged, so it should not contain sensitive + // information. + // +optional + optional string message = 2; +} + diff --git a/vendor/k8s.io/apimachinery/CONTRIBUTING.md b/vendor/k8s.io/apimachinery/CONTRIBUTING.md new file mode 100644 index 000000000..6a50b5624 --- /dev/null +++ b/vendor/k8s.io/apimachinery/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/apimachinery](https://git.k8s.io/kubernetes/staging/src/k8s.io/apimachinery) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/vendor/k8s.io/apimachinery/OWNERS b/vendor/k8s.io/apimachinery/OWNERS new file mode 100644 index 000000000..3449af976 --- /dev/null +++ b/vendor/k8s.io/apimachinery/OWNERS @@ -0,0 +1,23 @@ +approvers: +- lavalamp +- smarterclayton +- deads2k +- sttts +- liggitt +- caesarxuchao +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- gmarek +- sttts +- ncdc +- tallclair +labels: +- sig/api-machinery diff --git a/vendor/k8s.io/apimachinery/README.md b/vendor/k8s.io/apimachinery/README.md new file mode 100644 index 000000000..258250ce2 --- /dev/null +++ b/vendor/k8s.io/apimachinery/README.md @@ -0,0 +1,29 @@ +# apimachinery + +Scheme, typing, encoding, decoding, and conversion packages for Kubernetes and Kubernetes-like API objects. + + +## Purpose + +This library is a shared dependency for servers and clients to work with Kubernetes API infrastructure without direct +type dependencies. Its first consumers are `k8s.io/kubernetes`, `k8s.io/client-go`, and `k8s.io/apiserver`. + + +## Compatibility + +There are *NO compatibility guarantees* for this repository. It is in direct support of Kubernetes, so branches +will track Kubernetes and be compatible with that repo. As we more cleanly separate the layers, we will review the +compatibility guarantee. + + +## Where does it come from? + +`apimachinery` is synced from https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery. +Code changes are made in that location, merged into `k8s.io/kubernetes` and later synced here. + + +## Things you should *NOT* do + + 1. Add API types to this repo. This is for the machinery, not for the types. + 2. Directly modify any files under `pkg` in this repo. Those are driven from `k8s.io/kubernetes/staging/src/k8s.io/apimachinery`. + 3. Expect compatibility. This repo is direct support of Kubernetes and the API isn't yet stable enough for API guarantees. diff --git a/vendor/k8s.io/apimachinery/SECURITY_CONTACTS b/vendor/k8s.io/apimachinery/SECURITY_CONTACTS new file mode 100644 index 000000000..0648a8ebf --- /dev/null +++ b/vendor/k8s.io/apimachinery/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# 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/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/vendor/k8s.io/apimachinery/code-of-conduct.md b/vendor/k8s.io/apimachinery/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/apimachinery/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/k8s.io/apimachinery/pkg/OWNERS b/vendor/k8s.io/apimachinery/pkg/OWNERS new file mode 100644 index 000000000..63bb7814f --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/OWNERS @@ -0,0 +1,6 @@ +approvers: +- caesarxuchao +- deads2k +- lavalamp +- smarterclayton +- liggitt diff --git a/vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS b/vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS new file mode 100755 index 000000000..dc6a4c724 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS @@ -0,0 +1,24 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- brendandburns +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- nikhiljindal +- gmarek +- erictune +- saad-ali +- janetkuo +- tallclair +- eparis +- dims +- hongchaodeng +- krousey +- cjcullen +- david-mcmahon +- goltermann diff --git a/vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go b/vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go new file mode 100644 index 000000000..303a9d3f4 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go @@ -0,0 +1,222 @@ +/* +Copyright 2014 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 errors + +import ( + "errors" + "fmt" + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func resource(resource string) schema.GroupResource { + return schema.GroupResource{Group: "", Resource: resource} +} +func kind(kind string) schema.GroupKind { + return schema.GroupKind{Group: "", Kind: kind} +} + +func TestErrorNew(t *testing.T) { + err := NewAlreadyExists(resource("tests"), "1") + if !IsAlreadyExists(err) { + t.Errorf("expected to be %s", metav1.StatusReasonAlreadyExists) + } + if IsConflict(err) { + t.Errorf("expected to not be %s", metav1.StatusReasonConflict) + } + if IsNotFound(err) { + t.Errorf(fmt.Sprintf("expected to not be %s", metav1.StatusReasonNotFound)) + } + if IsInvalid(err) { + t.Errorf("expected to not be %s", metav1.StatusReasonInvalid) + } + if IsBadRequest(err) { + t.Errorf("expected to not be %s", metav1.StatusReasonBadRequest) + } + if IsForbidden(err) { + t.Errorf("expected to not be %s", metav1.StatusReasonForbidden) + } + if IsServerTimeout(err) { + t.Errorf("expected to not be %s", metav1.StatusReasonServerTimeout) + } + if IsMethodNotSupported(err) { + t.Errorf("expected to not be %s", metav1.StatusReasonMethodNotAllowed) + } + + if !IsConflict(NewConflict(resource("tests"), "2", errors.New("message"))) { + t.Errorf("expected to be conflict") + } + if !IsNotFound(NewNotFound(resource("tests"), "3")) { + t.Errorf("expected to be %s", metav1.StatusReasonNotFound) + } + if !IsInvalid(NewInvalid(kind("Test"), "2", nil)) { + t.Errorf("expected to be %s", metav1.StatusReasonInvalid) + } + if !IsBadRequest(NewBadRequest("reason")) { + t.Errorf("expected to be %s", metav1.StatusReasonBadRequest) + } + if !IsForbidden(NewForbidden(resource("tests"), "2", errors.New("reason"))) { + t.Errorf("expected to be %s", metav1.StatusReasonForbidden) + } + if !IsUnauthorized(NewUnauthorized("reason")) { + t.Errorf("expected to be %s", metav1.StatusReasonUnauthorized) + } + if !IsServerTimeout(NewServerTimeout(resource("tests"), "reason", 0)) { + t.Errorf("expected to be %s", metav1.StatusReasonServerTimeout) + } + if !IsMethodNotSupported(NewMethodNotSupported(resource("foos"), "delete")) { + t.Errorf("expected to be %s", metav1.StatusReasonMethodNotAllowed) + } + + if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 10)); time != 10 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 0)); time != 0 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 10)); time != 10 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 1)); time != 1 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewGenericServerResponse(500, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok { + t.Errorf("unexpected %d", time) + } + if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 0, true)); time != 0 || ok { + t.Errorf("unexpected %d", time) + } +} + +func TestNewInvalid(t *testing.T) { + testCases := []struct { + Err *field.Error + Details *metav1.StatusDetails + }{ + { + field.Duplicate(field.NewPath("field[0].name"), "bar"), + &metav1.StatusDetails{ + Kind: "Kind", + Name: "name", + Causes: []metav1.StatusCause{{ + Type: metav1.CauseTypeFieldValueDuplicate, + Field: "field[0].name", + }}, + }, + }, + { + field.Invalid(field.NewPath("field[0].name"), "bar", "detail"), + &metav1.StatusDetails{ + Kind: "Kind", + Name: "name", + Causes: []metav1.StatusCause{{ + Type: metav1.CauseTypeFieldValueInvalid, + Field: "field[0].name", + }}, + }, + }, + { + field.NotFound(field.NewPath("field[0].name"), "bar"), + &metav1.StatusDetails{ + Kind: "Kind", + Name: "name", + Causes: []metav1.StatusCause{{ + Type: metav1.CauseTypeFieldValueNotFound, + Field: "field[0].name", + }}, + }, + }, + { + field.NotSupported(field.NewPath("field[0].name"), "bar", nil), + &metav1.StatusDetails{ + Kind: "Kind", + Name: "name", + Causes: []metav1.StatusCause{{ + Type: metav1.CauseTypeFieldValueNotSupported, + Field: "field[0].name", + }}, + }, + }, + { + field.Required(field.NewPath("field[0].name"), ""), + &metav1.StatusDetails{ + Kind: "Kind", + Name: "name", + Causes: []metav1.StatusCause{{ + Type: metav1.CauseTypeFieldValueRequired, + Field: "field[0].name", + }}, + }, + }, + } + for i, testCase := range testCases { + vErr, expected := testCase.Err, testCase.Details + expected.Causes[0].Message = vErr.ErrorBody() + err := NewInvalid(kind("Kind"), "name", field.ErrorList{vErr}) + status := err.ErrStatus + if status.Code != 422 || status.Reason != metav1.StatusReasonInvalid { + t.Errorf("%d: unexpected status: %#v", i, status) + } + if !reflect.DeepEqual(expected, status.Details) { + t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details) + } + } +} + +func TestReasonForError(t *testing.T) { + if e, a := metav1.StatusReasonUnknown, ReasonForError(nil); e != a { + t.Errorf("unexpected reason type: %#v", a) + } +} + +type TestType struct{} + +func (obj *TestType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (obj *TestType) DeepCopyObject() runtime.Object { + if obj == nil { + return nil + } + clone := *obj + return &clone +} + +func TestFromObject(t *testing.T) { + table := []struct { + obj runtime.Object + message string + }{ + {&metav1.Status{Message: "foobar"}, "foobar"}, + {&TestType{}, "unexpected object: &{}"}, + } + + for _, item := range table { + if e, a := item.message, FromObject(item.obj).Error(); e != a { + t.Errorf("Expected %v, got %v", e, a) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS b/vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS new file mode 100755 index 000000000..5f729ffe6 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS @@ -0,0 +1,25 @@ +reviewers: +- thockin +- smarterclayton +- wojtek-t +- deads2k +- brendandburns +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- nikhiljindal +- gmarek +- janetkuo +- ncdc +- eparis +- dims +- krousey +- markturansky +- fabioy +- resouer +- david-mcmahon +- mfojtik +- jianhuiz +- feihujiang +- ghodss diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go b/vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go new file mode 100644 index 000000000..4680bae9a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go @@ -0,0 +1,51 @@ +/* +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 meta + +import ( + "math/rand" + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" + "k8s.io/apimachinery/pkg/util/diff" + + fuzz "github.com/google/gofuzz" +) + +func TestAsPartialObjectMetadata(t *testing.T) { + f := fuzz.New().NilChance(.5).NumElements(0, 1).RandSource(rand.NewSource(1)) + + for i := 0; i < 100; i++ { + m := &metav1.ObjectMeta{} + f.Fuzz(m) + partial := AsPartialObjectMetadata(m) + if !reflect.DeepEqual(&partial.ObjectMeta, m) { + t.Fatalf("incomplete partial object metadata: %s", diff.ObjectReflectDiff(&partial.ObjectMeta, m)) + } + } + + for i := 0; i < 100; i++ { + m := &metav1beta1.PartialObjectMetadata{} + f.Fuzz(&m.ObjectMeta) + partial := AsPartialObjectMetadata(m) + if !reflect.DeepEqual(&partial.ObjectMeta, &m.ObjectMeta) { + t.Fatalf("incomplete partial object metadata: %s", diff.ObjectReflectDiff(&partial.ObjectMeta, &m.ObjectMeta)) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go b/vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go new file mode 100644 index 000000000..b71ca468d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go @@ -0,0 +1,391 @@ +/* +Copyright 2014 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 meta + +import ( + "errors" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestMultiRESTMapperResourceFor(t *testing.T) { + tcs := []struct { + name string + + mapper MultiRESTMapper + input schema.GroupVersionResource + result schema.GroupVersionResource + err error + }{ + { + name: "empty", + mapper: MultiRESTMapper{}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: schema.GroupVersionResource{}, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "ignore not found", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: schema.GroupVersionResource{}, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "accept first failure", + mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: schema.GroupVersionResource{}, + err: errors.New("fail on this"), + }, + } + + for _, tc := range tcs { + actualResult, actualErr := tc.mapper.ResourceFor(tc.input) + if e, a := tc.result, actualResult; e != a { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + switch { + case tc.err == nil && actualErr == nil: + case tc.err == nil: + t.Errorf("%s: unexpected error: %v", tc.name, actualErr) + case actualErr == nil: + t.Errorf("%s: expected error: %v got nil", tc.name, tc.err) + case tc.err.Error() != actualErr.Error(): + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestMultiRESTMapperResourcesFor(t *testing.T) { + tcs := []struct { + name string + + mapper MultiRESTMapper + input schema.GroupVersionResource + result []schema.GroupVersionResource + err error + }{ + { + name: "empty", + mapper: MultiRESTMapper{}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: nil, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "ignore not found", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: nil, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "accept first failure", + mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: nil, + err: errors.New("fail on this"), + }, + { + name: "union and dedup", + mapper: MultiRESTMapper{ + fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}}}, + fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "second"}}}, + }, + input: schema.GroupVersionResource{Resource: "foo"}, + result: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}, {Resource: "second"}}, + }, + { + name: "skip not and continue", + mapper: MultiRESTMapper{ + fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}, + fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}}}, + }, + input: schema.GroupVersionResource{Resource: "foo"}, + result: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}}, + }, + } + + for _, tc := range tcs { + actualResult, actualErr := tc.mapper.ResourcesFor(tc.input) + if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + switch { + case tc.err == nil && actualErr == nil: + case tc.err == nil: + t.Errorf("%s: unexpected error: %v", tc.name, actualErr) + case actualErr == nil: + t.Errorf("%s: expected error: %v got nil", tc.name, tc.err) + case tc.err.Error() != actualErr.Error(): + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestMultiRESTMapperKindsFor(t *testing.T) { + tcs := []struct { + name string + + mapper MultiRESTMapper + input schema.GroupVersionResource + result []schema.GroupVersionKind + err error + }{ + { + name: "empty", + mapper: MultiRESTMapper{}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: nil, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "ignore not found", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: nil, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "accept first failure", + mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: nil, + err: errors.New("fail on this"), + }, + { + name: "union and dedup", + mapper: MultiRESTMapper{ + fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}}}, + fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "second"}}}, + }, + input: schema.GroupVersionResource{Resource: "foo"}, + result: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}, {Kind: "second"}}, + }, + { + name: "skip not and continue", + mapper: MultiRESTMapper{ + fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}, + fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}}}, + }, + input: schema.GroupVersionResource{Resource: "foo"}, + result: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}}, + }, + } + + for _, tc := range tcs { + actualResult, actualErr := tc.mapper.KindsFor(tc.input) + if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + switch { + case tc.err == nil && actualErr == nil: + case tc.err == nil: + t.Errorf("%s: unexpected error: %v", tc.name, actualErr) + case actualErr == nil: + t.Errorf("%s: expected error: %v got nil", tc.name, tc.err) + case tc.err.Error() != actualErr.Error(): + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestMultiRESTMapperKindFor(t *testing.T) { + tcs := []struct { + name string + + mapper MultiRESTMapper + input schema.GroupVersionResource + result schema.GroupVersionKind + err error + }{ + { + name: "empty", + mapper: MultiRESTMapper{}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: schema.GroupVersionKind{}, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "ignore not found", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: schema.GroupVersionKind{}, + err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}}, + }, + { + name: "accept first failure", + mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}}, + input: schema.GroupVersionResource{Resource: "foo"}, + result: schema.GroupVersionKind{}, + err: errors.New("fail on this"), + }, + } + + for _, tc := range tcs { + actualResult, actualErr := tc.mapper.KindFor(tc.input) + if e, a := tc.result, actualResult; e != a { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + switch { + case tc.err == nil && actualErr == nil: + case tc.err == nil: + t.Errorf("%s: unexpected error: %v", tc.name, actualErr) + case actualErr == nil: + t.Errorf("%s: expected error: %v got nil", tc.name, tc.err) + case tc.err.Error() != actualErr.Error(): + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestMultiRESTMapperRESTMappings(t *testing.T) { + mapping1, mapping2 := &RESTMapping{}, &RESTMapping{} + tcs := []struct { + name string + + mapper MultiRESTMapper + groupKind schema.GroupKind + versions []string + result []*RESTMapping + err error + }{ + { + name: "empty with no versions", + mapper: MultiRESTMapper{}, + groupKind: schema.GroupKind{Kind: "Foo"}, + result: nil, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}}, + }, + { + name: "empty with one version", + mapper: MultiRESTMapper{}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: []string{"v1beta"}, + result: nil, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta"}}, + }, + { + name: "empty with multi(two) vesions", + mapper: MultiRESTMapper{}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: []string{"v1beta", "v2"}, + result: nil, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta", "v2"}}, + }, + { + name: "ignore not found with kind not exist", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "IGNORE_THIS"}}}}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: nil, + result: nil, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}}, + }, + { + name: "ignore not found with version not exist", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1"}}}}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: []string{"v1beta"}, + result: nil, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta"}}, + }, + { + name: "ignore not found with multi versions not exist", + mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1"}}}}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: []string{"v1beta", "v2"}, + result: nil, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}, SearchedVersions: []string{"v1beta", "v2"}}, + }, + { + name: "accept first failure", + mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: []string{"v1beta"}, + result: nil, + err: errors.New("fail on this"), + }, + { + name: "return both", + mapper: MultiRESTMapper{fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, fixedRESTMapper{mappings: []*RESTMapping{mapping2}}}, + groupKind: schema.GroupKind{Kind: "Foo"}, + versions: []string{"v1beta"}, + result: []*RESTMapping{mapping1, mapping2}, + }, + } + + for _, tc := range tcs { + actualResult, actualErr := tc.mapper.RESTMappings(tc.groupKind, tc.versions...) + if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + switch { + case tc.err == nil && actualErr == nil: + case tc.err == nil: + t.Errorf("%s: unexpected error: %v", tc.name, actualErr) + case actualErr == nil: + t.Errorf("%s: expected error: %v got nil", tc.name, tc.err) + case tc.err.Error() != actualErr.Error(): + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +type fixedRESTMapper struct { + resourcesFor []schema.GroupVersionResource + kindsFor []schema.GroupVersionKind + resourceFor schema.GroupVersionResource + kindFor schema.GroupVersionKind + mappings []*RESTMapping + + err error +} + +func (m fixedRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { + return "", m.err +} + +func (m fixedRESTMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { + return m.resourcesFor, m.err +} + +func (m fixedRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) { + return m.kindsFor, m.err +} + +func (m fixedRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) { + return m.resourceFor, m.err +} + +func (m fixedRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { + return m.kindFor, m.err +} + +func (m fixedRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) { + return nil, m.err +} + +func (m fixedRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (mappings []*RESTMapping, err error) { + return m.mappings, m.err +} + +func (m fixedRESTMapper) ResourceIsValid(resource schema.GroupVersionResource) bool { + return false +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go b/vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go new file mode 100644 index 000000000..fff1afd17 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go @@ -0,0 +1,409 @@ +/* +Copyright 2016 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 meta + +import ( + "errors" + "reflect" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestPriorityRESTMapperResourceForErrorHandling(t *testing.T) { + tcs := []struct { + name string + + delegate RESTMapper + resourcePatterns []schema.GroupVersionResource + result schema.GroupVersionResource + err string + }{ + { + name: "error", + delegate: fixedRESTMapper{err: errors.New("delegateError")}, + err: "delegateError", + }, + { + name: "single hit + error", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}, err: errors.New("delegateError")}, + result: schema.GroupVersionResource{Resource: "single-hit"}, + err: "delegateError", + }, + { + name: "group selection + error", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{ + {Group: "one", Version: "a", Resource: "first"}, + {Group: "two", Version: "b", Resource: "second"}, + }, err: errors.New("delegateError")}, + resourcePatterns: []schema.GroupVersionResource{ + {Group: "one", Version: AnyVersion, Resource: AnyResource}, + }, + result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"}, + err: "delegateError", + }, + + { + name: "single hit", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}}, + result: schema.GroupVersionResource{Resource: "single-hit"}, + }, + { + name: "ambiguous match", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{ + {Group: "one", Version: "a", Resource: "first"}, + {Group: "two", Version: "b", Resource: "second"}, + }}, + err: "matches multiple resources", + }, + { + name: "group selection", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{ + {Group: "one", Version: "a", Resource: "first"}, + {Group: "two", Version: "b", Resource: "second"}, + }}, + resourcePatterns: []schema.GroupVersionResource{ + {Group: "one", Version: AnyVersion, Resource: AnyResource}, + }, + result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"}, + }, + { + name: "empty match continues", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{ + {Group: "one", Version: "a", Resource: "first"}, + {Group: "two", Version: "b", Resource: "second"}, + }}, + resourcePatterns: []schema.GroupVersionResource{ + {Group: "fail", Version: AnyVersion, Resource: AnyResource}, + {Group: "one", Version: AnyVersion, Resource: AnyResource}, + }, + result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"}, + }, + { + name: "group followed by version selection", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{ + {Group: "one", Version: "a", Resource: "first"}, + {Group: "two", Version: "b", Resource: "second"}, + {Group: "one", Version: "c", Resource: "third"}, + }}, + resourcePatterns: []schema.GroupVersionResource{ + {Group: "one", Version: AnyVersion, Resource: AnyResource}, + {Group: AnyGroup, Version: "a", Resource: AnyResource}, + }, + result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"}, + }, + { + name: "resource selection", + delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{ + {Group: "one", Version: "a", Resource: "first"}, + {Group: "one", Version: "a", Resource: "second"}, + }}, + resourcePatterns: []schema.GroupVersionResource{ + {Group: AnyGroup, Version: AnyVersion, Resource: "second"}, + }, + result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "second"}, + }, + } + + for _, tc := range tcs { + mapper := PriorityRESTMapper{Delegate: tc.delegate, ResourcePriority: tc.resourcePatterns} + + actualResult, actualErr := mapper.ResourceFor(schema.GroupVersionResource{}) + if e, a := tc.result, actualResult; e != a { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + if len(tc.err) == 0 && actualErr == nil { + continue + } + if len(tc.err) == 0 && actualErr != nil { + t.Errorf("%s: unexpected err: %v", tc.name, actualErr) + continue + } + if len(tc.err) > 0 && actualErr == nil { + t.Errorf("%s: missing expected err: %v", tc.name, tc.err) + continue + } + if !strings.Contains(actualErr.Error(), tc.err) { + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestPriorityRESTMapperKindForErrorHandling(t *testing.T) { + tcs := []struct { + name string + + delegate RESTMapper + kindPatterns []schema.GroupVersionKind + result schema.GroupVersionKind + err string + }{ + { + name: "error", + delegate: fixedRESTMapper{err: errors.New("delegateErr")}, + err: "delegateErr", + }, + { + name: "single hit + error", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}, err: errors.New("delegateErr")}, + result: schema.GroupVersionKind{Kind: "single-hit"}, + err: "delegateErr", + }, + { + name: "group selection + error", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{ + {Group: "one", Version: "a", Kind: "first"}, + {Group: "two", Version: "b", Kind: "second"}, + }, err: errors.New("delegateErr")}, + kindPatterns: []schema.GroupVersionKind{ + {Group: "one", Version: AnyVersion, Kind: AnyKind}, + }, + result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"}, + err: "delegateErr", + }, + + { + name: "single hit", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}}, + result: schema.GroupVersionKind{Kind: "single-hit"}, + }, + { + name: "ambiguous match", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{ + {Group: "one", Version: "a", Kind: "first"}, + {Group: "two", Version: "b", Kind: "second"}, + }}, + err: "matches multiple kinds", + }, + { + name: "group selection", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{ + {Group: "one", Version: "a", Kind: "first"}, + {Group: "two", Version: "b", Kind: "second"}, + }}, + kindPatterns: []schema.GroupVersionKind{ + {Group: "one", Version: AnyVersion, Kind: AnyKind}, + }, + result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"}, + }, + { + name: "empty match continues", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{ + {Group: "one", Version: "a", Kind: "first"}, + {Group: "two", Version: "b", Kind: "second"}, + }}, + kindPatterns: []schema.GroupVersionKind{ + {Group: "fail", Version: AnyVersion, Kind: AnyKind}, + {Group: "one", Version: AnyVersion, Kind: AnyKind}, + }, + result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"}, + }, + { + name: "group followed by version selection", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{ + {Group: "one", Version: "a", Kind: "first"}, + {Group: "two", Version: "b", Kind: "second"}, + {Group: "one", Version: "c", Kind: "third"}, + }}, + kindPatterns: []schema.GroupVersionKind{ + {Group: "one", Version: AnyVersion, Kind: AnyKind}, + {Group: AnyGroup, Version: "a", Kind: AnyKind}, + }, + result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"}, + }, + { + name: "kind selection", + delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{ + {Group: "one", Version: "a", Kind: "first"}, + {Group: "one", Version: "a", Kind: "second"}, + }}, + kindPatterns: []schema.GroupVersionKind{ + {Group: AnyGroup, Version: AnyVersion, Kind: "second"}, + }, + result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "second"}, + }, + } + + for _, tc := range tcs { + mapper := PriorityRESTMapper{Delegate: tc.delegate, KindPriority: tc.kindPatterns} + + actualResult, actualErr := mapper.KindFor(schema.GroupVersionResource{}) + if e, a := tc.result, actualResult; e != a { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + if len(tc.err) == 0 && actualErr == nil { + continue + } + if len(tc.err) == 0 && actualErr != nil { + t.Errorf("%s: unexpected err: %v", tc.name, actualErr) + continue + } + if len(tc.err) > 0 && actualErr == nil { + t.Errorf("%s: missing expected err: %v", tc.name, tc.err) + continue + } + if !strings.Contains(actualErr.Error(), tc.err) { + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestPriorityRESTMapperRESTMapping(t *testing.T) { + mapping1 := &RESTMapping{ + GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1alpha1"}, + } + mapping2 := &RESTMapping{ + GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1"}, + } + mapping3 := &RESTMapping{ + GroupVersionKind: schema.GroupVersionKind{Group: "other", Kind: "Foo", Version: "v1"}, + } + allMappers := MultiRESTMapper{ + fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, + fixedRESTMapper{mappings: []*RESTMapping{mapping2}}, + fixedRESTMapper{mappings: []*RESTMapping{mapping3}}, + } + tcs := []struct { + name string + + mapper PriorityRESTMapper + input schema.GroupKind + result *RESTMapping + err error + }{ + { + name: "empty", + mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{}}, + input: schema.GroupKind{Kind: "Foo"}, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}}, + }, + { + name: "ignore not found", + mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "IGNORE_THIS"}}}}}, + input: schema.GroupKind{Kind: "Foo"}, + err: &NoKindMatchError{GroupKind: schema.GroupKind{Kind: "Foo"}}, + }, + { + name: "accept first failure", + mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}}}, + input: schema.GroupKind{Kind: "Foo"}, + err: errors.New("fail on this"), + }, + { + name: "result + error", + mapper: PriorityRESTMapper{Delegate: fixedRESTMapper{mappings: []*RESTMapping{mapping1}, err: errors.New("fail on this")}}, + input: schema.GroupKind{Kind: "Foo"}, + result: mapping1, + err: errors.New("fail on this"), + }, + { + name: "return error for ambiguous", + mapper: PriorityRESTMapper{ + Delegate: allMappers, + }, + input: schema.GroupKind{Kind: "Foo"}, + err: &AmbiguousKindError{ + PartialKind: schema.GroupVersionKind{Kind: "Foo"}, + MatchingKinds: []schema.GroupVersionKind{ + {Kind: "Foo", Version: "v1alpha1"}, + {Kind: "Foo", Version: "v1"}, + {Group: "other", Kind: "Foo", Version: "v1"}, + }, + }, + }, + { + name: "accept only item", + mapper: PriorityRESTMapper{ + Delegate: fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, + }, + input: schema.GroupKind{Kind: "Foo"}, + result: mapping1, + }, + { + name: "return single priority", + mapper: PriorityRESTMapper{ + Delegate: allMappers, + KindPriority: []schema.GroupVersionKind{{Version: "v1", Kind: AnyKind}, {Version: "v1alpha1", Kind: AnyKind}}, + }, + input: schema.GroupKind{Kind: "Foo"}, + result: mapping2, + }, + { + name: "return out of group match", + mapper: PriorityRESTMapper{ + Delegate: allMappers, + KindPriority: []schema.GroupVersionKind{{Group: AnyGroup, Version: "v1", Kind: AnyKind}, {Group: "other", Version: AnyVersion, Kind: AnyKind}}, + }, + input: schema.GroupKind{Kind: "Foo"}, + result: mapping3, + }, + } + + for _, tc := range tcs { + actualResult, actualErr := tc.mapper.RESTMapping(tc.input) + if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) { + t.Errorf("%s: expected %v, got %v", tc.name, e, a) + } + switch { + case tc.err == nil && actualErr == nil: + case tc.err == nil: + t.Errorf("%s: unexpected error: %v", tc.name, actualErr) + case actualErr == nil: + t.Errorf("%s: expected error: %v got nil", tc.name, tc.err) + case tc.err.Error() != actualErr.Error(): + t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr) + } + } +} + +func TestPriorityRESTMapperRESTMappingHonorsUserVersion(t *testing.T) { + mappingV2alpha1 := &RESTMapping{ + GroupVersionKind: schema.GroupVersionKind{Group: "Bar", Kind: "Foo", Version: "v2alpha1"}, + } + mappingV1 := &RESTMapping{ + GroupVersionKind: schema.GroupVersionKind{Group: "Bar", Kind: "Foo", Version: "v1"}, + } + + allMappers := MultiRESTMapper{ + fixedRESTMapper{mappings: []*RESTMapping{mappingV2alpha1}}, + fixedRESTMapper{mappings: []*RESTMapping{mappingV1}}, + } + + mapper := PriorityRESTMapper{ + Delegate: allMappers, + KindPriority: []schema.GroupVersionKind{{Group: "Bar", Version: "v2alpha1", Kind: AnyKind}, {Group: "Bar", Version: AnyVersion, Kind: AnyKind}}, + } + + outMapping1, err := mapper.RESTMapping(schema.GroupKind{Group: "Bar", Kind: "Foo"}, "v1") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if outMapping1 != mappingV1 { + t.Errorf("asked for version %v, expected mapping for %v, got mapping for %v", "v1", mappingV1.GroupVersionKind, outMapping1.GroupVersionKind) + } + + outMapping2, err := mapper.RESTMapping(schema.GroupKind{Group: "Bar", Kind: "Foo"}, "v2alpha1") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + if outMapping2 != mappingV2alpha1 { + t.Errorf("asked for version %v, expected mapping for %v, got mapping for %v", "v2alpha1", mappingV2alpha1.GroupVersionKind, outMapping2.GroupVersionKind) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go b/vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go new file mode 100644 index 000000000..853404ad6 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go @@ -0,0 +1,724 @@ +/* +Copyright 2014 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 meta + +import ( + "reflect" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestRESTMapperVersionAndKindForResource(t *testing.T) { + testGroup := "test.group" + testVersion := "test" + testGroupVersion := schema.GroupVersion{Group: testGroup, Version: testVersion} + + testCases := []struct { + Resource schema.GroupVersionResource + GroupVersionToRegister schema.GroupVersion + ExpectedGVK schema.GroupVersionKind + Err bool + }{ + {Resource: schema.GroupVersionResource{Resource: "internalobjec"}, Err: true}, + {Resource: schema.GroupVersionResource{Resource: "internalObjec"}, Err: true}, + + {Resource: schema.GroupVersionResource{Resource: "internalobject"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, + {Resource: schema.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")}, + } + for i, testCase := range testCases { + mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}) + if len(testCase.ExpectedGVK.Kind) != 0 { + mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace) + } + actualGVK, err := mapper.KindFor(testCase.Resource) + + hasErr := err != nil + if hasErr != testCase.Err { + t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err) + continue + } + if err != nil { + continue + } + + if actualGVK != testCase.ExpectedGVK { + t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK) + } + } +} + +func TestRESTMapperGroupForResource(t *testing.T) { + testCases := []struct { + Resource schema.GroupVersionResource + GroupVersionKind schema.GroupVersionKind + Err bool + }{ + {Resource: schema.GroupVersionResource{Resource: "myObject"}, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}}, + {Resource: schema.GroupVersionResource{Resource: "myobject"}, GroupVersionKind: schema.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}}, + {Resource: schema.GroupVersionResource{Resource: "myObje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}}, + {Resource: schema.GroupVersionResource{Resource: "myobje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}}, + } + for i, testCase := range testCases { + mapper := NewDefaultRESTMapper([]schema.GroupVersion{testCase.GroupVersionKind.GroupVersion()}) + mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace) + + actualGVK, err := mapper.KindFor(testCase.Resource) + if testCase.Err { + if err == nil { + t.Errorf("%d: expected error", i) + } + } else if err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + } else if actualGVK != testCase.GroupVersionKind { + t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersionKind, actualGVK) + } + } +} + +func TestRESTMapperKindsFor(t *testing.T) { + testCases := []struct { + Name string + PreferredOrder []schema.GroupVersion + KindsToRegister []schema.GroupVersionKind + PartialResourceToRequest schema.GroupVersionResource + + ExpectedKinds []schema.GroupVersionKind + ExpectedKindErr string + }{ + { + // exact matches are preferred + Name: "groups, with group exact", + PreferredOrder: []schema.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"}, + + ExpectedKinds: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + }, + + { + // group prefixes work + Name: "groups, with group prefix", + PreferredOrder: []schema.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + }, + PartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedKinds: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + }, + + { + // group prefixes can be ambiguous + Name: "groups, with ambiguous group prefix", + PreferredOrder: []schema.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedKinds: []schema.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + ExpectedKindErr: " matches multiple kinds ", + }, + + { + Name: "ambiguous groups, with preference order", + PreferredOrder: []schema.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "your-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "your-kind"}, + }, + PartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kinds"}, + + ExpectedKinds: []schema.GroupVersionKind{ + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + ExpectedKindErr: " matches multiple kinds ", + }, + + { + Name: "ambiguous groups, with explicit group match", + PreferredOrder: []schema.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "your-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "your-kind"}, + }, + PartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"}, + + ExpectedKinds: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + }, + + { + Name: "ambiguous groups, with ambiguous version match", + PreferredOrder: []schema.GroupVersion{ + {Group: "first-group", Version: "first-version"}, + {Group: "second-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "your-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "your-kind"}, + }, + PartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kinds"}, + + ExpectedKinds: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + }, + ExpectedKindErr: " matches multiple kinds ", + }, + } + for _, testCase := range testCases { + tcName := testCase.Name + mapper := NewDefaultRESTMapper(testCase.PreferredOrder) + for _, kind := range testCase.KindsToRegister { + mapper.Add(kind, RESTScopeNamespace) + } + + actualKinds, err := mapper.KindsFor(testCase.PartialResourceToRequest) + if err != nil { + t.Errorf("%s: unexpected error: %v", tcName, err) + continue + } + if !reflect.DeepEqual(testCase.ExpectedKinds, actualKinds) { + t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds, actualKinds) + } + + singleKind, err := mapper.KindFor(testCase.PartialResourceToRequest) + if err == nil && len(testCase.ExpectedKindErr) != 0 { + t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedKindErr) + continue + } + if err != nil { + if len(testCase.ExpectedKindErr) == 0 { + t.Errorf("%s: unexpected error: %v", tcName, err) + continue + } else { + if !strings.Contains(err.Error(), testCase.ExpectedKindErr) { + t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKindErr, err) + continue + } + } + + } else { + if testCase.ExpectedKinds[0] != singleKind { + t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds[0], singleKind) + } + + } + } +} + +func TestRESTMapperResourcesFor(t *testing.T) { + testCases := []struct { + Name string + PreferredOrder []schema.GroupVersion + KindsToRegister []schema.GroupVersionKind + PluralPartialResourceToRequest schema.GroupVersionResource + SingularPartialResourceToRequest schema.GroupVersionResource + + ExpectedResources []schema.GroupVersionResource + ExpectedResourceErr string + }{ + { + // exact matches are preferred + Name: "groups, with group exact", + PreferredOrder: []schema.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"}, + SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"}, + + ExpectedResources: []schema.GroupVersionResource{ + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + }, + + { + // group prefixes work + Name: "groups, with group prefix", + PreferredOrder: []schema.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + }, + PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kinds"}, + SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedResources: []schema.GroupVersionResource{ + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + }, + + { + // group prefixes can be ambiguous + Name: "groups, with ambiguous group prefix", + PreferredOrder: []schema.GroupVersion{ + {Group: "first-group-1", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group-1", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + }, + PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kinds"}, + SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"}, + + ExpectedResources: []schema.GroupVersionResource{ + {Group: "first-group-1", Version: "first-version", Resource: "my-kinds"}, + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + ExpectedResourceErr: " matches multiple resources ", + }, + + { + Name: "ambiguous groups, with preference order", + PreferredOrder: []schema.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "your-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "your-kind"}, + }, + PluralPartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kinds"}, + SingularPartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kind"}, + + ExpectedResources: []schema.GroupVersionResource{ + {Group: "second-group", Version: "first-version", Resource: "my-kinds"}, + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + ExpectedResourceErr: " matches multiple resources ", + }, + + { + Name: "ambiguous groups, with explicit group match", + PreferredOrder: []schema.GroupVersion{ + {Group: "second-group", Version: "first-version"}, + {Group: "first-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "your-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "your-kind"}, + }, + PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"}, + SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"}, + + ExpectedResources: []schema.GroupVersionResource{ + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + }, + }, + + { + Name: "ambiguous groups, with ambiguous version match", + PreferredOrder: []schema.GroupVersion{ + {Group: "first-group", Version: "first-version"}, + {Group: "second-group", Version: "first-version"}, + }, + KindsToRegister: []schema.GroupVersionKind{ + {Group: "first-group", Version: "first-version", Kind: "my-kind"}, + {Group: "first-group", Version: "first-version", Kind: "your-kind"}, + {Group: "second-group", Version: "first-version", Kind: "my-kind"}, + {Group: "second-group", Version: "first-version", Kind: "your-kind"}, + }, + PluralPartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kinds"}, + SingularPartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kind"}, + + ExpectedResources: []schema.GroupVersionResource{ + {Group: "first-group", Version: "first-version", Resource: "my-kinds"}, + {Group: "second-group", Version: "first-version", Resource: "my-kinds"}, + }, + ExpectedResourceErr: " matches multiple resources ", + }, + } + for _, testCase := range testCases { + tcName := testCase.Name + + for _, partialResource := range []schema.GroupVersionResource{testCase.PluralPartialResourceToRequest, testCase.SingularPartialResourceToRequest} { + mapper := NewDefaultRESTMapper(testCase.PreferredOrder) + for _, kind := range testCase.KindsToRegister { + mapper.Add(kind, RESTScopeNamespace) + } + + actualResources, err := mapper.ResourcesFor(partialResource) + if err != nil { + t.Errorf("%s: unexpected error: %v", tcName, err) + continue + } + if !reflect.DeepEqual(testCase.ExpectedResources, actualResources) { + t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources, actualResources) + } + + singleResource, err := mapper.ResourceFor(partialResource) + if err == nil && len(testCase.ExpectedResourceErr) != 0 { + t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedResourceErr) + continue + } + if err != nil { + if len(testCase.ExpectedResourceErr) == 0 { + t.Errorf("%s: unexpected error: %v", tcName, err) + continue + } else { + if !strings.Contains(err.Error(), testCase.ExpectedResourceErr) { + t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResourceErr, err) + continue + } + } + + } else { + if testCase.ExpectedResources[0] != singleResource { + t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources[0], singleResource) + } + + } + } + } +} + +func TestKindToResource(t *testing.T) { + testCases := []struct { + Kind string + Plural, Singular string + }{ + {Kind: "Pod", Plural: "pods", Singular: "pod"}, + + {Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"}, + + // Add "ies" when ending with "y" + {Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"}, + // Add "es" when ending with "s" + {Kind: "miss", Plural: "misses", Singular: "miss"}, + // Add "s" otherwise + {Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"}, + } + for i, testCase := range testCases { + version := schema.GroupVersion{} + + plural, singular := UnsafeGuessKindToResource(version.WithKind(testCase.Kind)) + if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) { + t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular) + } + } +} + +func TestRESTMapperResourceSingularizer(t *testing.T) { + testGroupVersion := schema.GroupVersion{Group: "tgroup", Version: "test"} + + testCases := []struct { + Kind string + Plural string + Singular string + }{ + {Kind: "Pod", Plural: "pods", Singular: "pod"}, + {Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"}, + {Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"}, + {Kind: "Status", Plural: "statuses", Singular: "status"}, + + {Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"}, + // TODO this test is broken. This updates to reflect actual behavior. Kinds are expected to be singular + // old (incorrect), comment: Don't add extra s if the original object is already plural + {Kind: "lowercases", Plural: "lowercaseses", Singular: "lowercases"}, + } + for i, testCase := range testCases { + mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}) + // create singular/plural mapping + mapper.Add(testGroupVersion.WithKind(testCase.Kind), RESTScopeNamespace) + + singular, err := mapper.ResourceSingularizer(testCase.Plural) + if err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + } + if singular != testCase.Singular { + t.Errorf("%d: mismatched singular: got %v, expected %v", i, singular, testCase.Singular) + } + } +} + +func TestRESTMapperRESTMapping(t *testing.T) { + testGroup := "tgroup" + testGroupVersion := schema.GroupVersion{Group: testGroup, Version: "test"} + internalGroupVersion := schema.GroupVersion{Group: testGroup, Version: "test"} + + testCases := []struct { + Kind string + APIGroupVersions []schema.GroupVersion + DefaultVersions []schema.GroupVersion + + Resource schema.GroupVersionResource + ExpectedGroupVersion *schema.GroupVersion + Err bool + }{ + {Kind: "Unknown", Err: true}, + {Kind: "InternalObject", Err: true}, + + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true}, + + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")}, + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")}, + + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")}, + + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{}, Resource: internalGroupVersion.WithResource("internalobjects"), ExpectedGroupVersion: &schema.GroupVersion{Group: testGroup, Version: "test"}}, + + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: testGroupVersion.WithResource("internalobjects")}, + + // TODO: add test for a resource that exists in one version but not another + } + for i, testCase := range testCases { + mapper := NewDefaultRESTMapper(testCase.DefaultVersions) + mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace) + + preferredVersions := []string{} + for _, gv := range testCase.APIGroupVersions { + preferredVersions = append(preferredVersions, gv.Version) + } + gk := schema.GroupKind{Group: testGroup, Kind: testCase.Kind} + + mapping, err := mapper.RESTMapping(gk, preferredVersions...) + hasErr := err != nil + if hasErr != testCase.Err { + t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err) + } + if hasErr { + continue + } + if mapping.Resource != testCase.Resource { + t.Errorf("%d: unexpected resource: %#v", i, mapping) + } + + groupVersion := testCase.ExpectedGroupVersion + if groupVersion == nil { + groupVersion = &testCase.APIGroupVersions[0] + } + if mapping.GroupVersionKind.GroupVersion() != *groupVersion { + t.Errorf("%d: unexpected version: %#v", i, mapping) + } + + } +} + +func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) { + expectedGroupVersion1 := schema.GroupVersion{Group: "tgroup", Version: "test1"} + expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"} + expectedGroupVersion3 := schema.GroupVersion{Group: "tgroup", Version: "test3"} + internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"} + otherObjectGK := schema.GroupKind{Group: "tgroup", Kind: "OtherObject"} + + mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}) + mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace) + mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace) + + // pick default matching object kind based on search order + mapping, err := mapper.RESTMapping(otherObjectGK) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if mapping.Resource != expectedGroupVersion2.WithResource("otherobjects") || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 { + t.Errorf("unexpected mapping: %#v", mapping) + } + + mapping, err = mapper.RESTMapping(internalObjectGK) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if mapping.Resource != expectedGroupVersion1.WithResource("internalobjects") || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 { + t.Errorf("unexpected mapping: %#v", mapping) + } + + // mismatch of version + mapping, err = mapper.RESTMapping(internalObjectGK, expectedGroupVersion2.Version) + if err == nil { + t.Errorf("unexpected non-error") + } + mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion1.Version) + if err == nil { + t.Errorf("unexpected non-error") + } + + // not in the search versions + mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version) + if err == nil { + t.Errorf("unexpected non-error") + } + + // explicit search order + mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion1.Version) + if err == nil { + t.Errorf("unexpected non-error") + } + + mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion2.Version) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if mapping.Resource != expectedGroupVersion2.WithResource("otherobjects") || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 { + t.Errorf("unexpected mapping: %#v", mapping) + } +} + +func TestRESTMapperRESTMappings(t *testing.T) { + testGroup := "tgroup" + testGroupVersion := schema.GroupVersion{Group: testGroup, Version: "v1"} + + testCases := []struct { + Kind string + APIGroupVersions []schema.GroupVersion + DefaultVersions []schema.GroupVersion + AddGroupVersionKind []schema.GroupVersionKind + + ExpectedRESTMappings []*RESTMapping + Err bool + }{ + {Kind: "Unknown", Err: true}, + {Kind: "InternalObject", Err: true}, + + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true}, + + // ask for specific version - not available - thus error + {DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}}, Err: true}, + + // ask for specific version - available - check ExpectedRESTMappings + { + DefaultVersions: []schema.GroupVersion{testGroupVersion}, + Kind: "InternalObject", + APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}}, + AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")}, + ExpectedRESTMappings: []*RESTMapping{{Resource: schema.GroupVersionResource{Group: testGroup, Version: "v2", Resource: "internalobjects"}, GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}}, + }, + + // ask for specific versions - only one available - check ExpectedRESTMappings + { + DefaultVersions: []schema.GroupVersion{testGroupVersion}, + Kind: "InternalObject", + APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v3"}, {Group: testGroup, Version: "v2"}}, + AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")}, + ExpectedRESTMappings: []*RESTMapping{{Resource: schema.GroupVersionResource{Group: testGroup, Version: "v2", Resource: "internalobjects"}, GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}}, + }, + + // do not ask for specific version - search through default versions - check ExpectedRESTMappings + { + DefaultVersions: []schema.GroupVersion{testGroupVersion, {Group: testGroup, Version: "v2"}}, + Kind: "InternalObject", + AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v1"}.WithKind("InternalObject"), schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")}, + ExpectedRESTMappings: []*RESTMapping{ + { + Resource: schema.GroupVersionResource{Group: testGroup, Version: "v1", Resource: "internalobjects"}, + GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v1", Kind: "InternalObject"}, + }, + { + Resource: schema.GroupVersionResource{Group: testGroup, Version: "v2", Resource: "internalobjects"}, + GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}, + }, + }, + }, + } + + for i, testCase := range testCases { + mapper := NewDefaultRESTMapper(testCase.DefaultVersions) + for _, gvk := range testCase.AddGroupVersionKind { + mapper.Add(gvk, RESTScopeNamespace) + } + + preferredVersions := []string{} + for _, gv := range testCase.APIGroupVersions { + preferredVersions = append(preferredVersions, gv.Version) + } + gk := schema.GroupKind{Group: testGroup, Kind: testCase.Kind} + + mappings, err := mapper.RESTMappings(gk, preferredVersions...) + hasErr := err != nil + if hasErr != testCase.Err { + t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err) + } + if hasErr { + continue + } + if len(mappings) != len(testCase.ExpectedRESTMappings) { + t.Errorf("%d: unexpected number = %d of rest mappings was returned, expected = %d", i, len(mappings), len(testCase.ExpectedRESTMappings)) + } + for j, mapping := range mappings { + exp := testCase.ExpectedRESTMappings[j] + if mapping.Resource != exp.Resource { + t.Errorf("%d - %d: unexpected resource: %#v", i, j, mapping) + } + if mapping.GroupVersionKind != exp.GroupVersionKind { + t.Errorf("%d - %d: unexpected GroupVersionKind: %#v", i, j, mapping) + } + } + } +} + +func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) { + expectedGroupVersion1 := schema.GroupVersion{Group: "tgroup", Version: "test1"} + expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"} + internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"} + + mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}) + mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace) + _, err := mapper.RESTMapping(internalObjectGK, "test3") + if err == nil { + t.Errorf("unexpected non-error") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS b/vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS new file mode 100755 index 000000000..c430067f3 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS @@ -0,0 +1,16 @@ +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- derekwaynecarr +- mikedanese +- saad-ali +- janetkuo +- tallclair +- eparis +- jbeda +- xiang90 +- mbohlool +- david-mcmahon +- goltermann diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go b/vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go new file mode 100644 index 000000000..8217cb139 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go @@ -0,0 +1,162 @@ +/* +Copyright 2014 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 resource + +import ( + "testing" +) + +func TestInt64AmountAsInt64(t *testing.T) { + for _, test := range []struct { + value int64 + scale Scale + result int64 + ok bool + }{ + {100, 0, 100, true}, + {100, 1, 1000, true}, + {100, -5, 0, false}, + {100, 100, 0, false}, + } { + r, ok := int64Amount{value: test.value, scale: test.scale}.AsInt64() + if r != test.result { + t.Errorf("%v: unexpected result: %d", test, r) + } + if ok != test.ok { + t.Errorf("%v: unexpected ok: %t", test, ok) + } + } +} + +func TestInt64AmountAdd(t *testing.T) { + for _, test := range []struct { + a, b, c int64Amount + ok bool + }{ + {int64Amount{value: 100, scale: 1}, int64Amount{value: 10, scale: 2}, int64Amount{value: 200, scale: 1}, true}, + {int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 2}, int64Amount{value: 110, scale: 1}, true}, + {int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 100}, int64Amount{value: 1, scale: 100}, false}, + {int64Amount{value: -5, scale: 2}, int64Amount{value: 50, scale: 1}, int64Amount{value: 0, scale: 1}, true}, + {int64Amount{value: -5, scale: 2}, int64Amount{value: 5, scale: 2}, int64Amount{value: 0, scale: 2}, true}, + + {int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 1, scale: -1}, int64Amount{value: 0, scale: -1}, false}, + {int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 0, scale: -1}, int64Amount{value: mostPositive, scale: -1}, true}, + {int64Amount{value: mostPositive / 10, scale: 1}, int64Amount{value: 10, scale: 0}, int64Amount{value: mostPositive, scale: -1}, false}, + } { + c := test.a + ok := c.Add(test.b) + if ok != test.ok { + t.Errorf("%v: unexpected ok: %t", test, ok) + } + if ok { + if c != test.c { + t.Errorf("%v: unexpected result: %d", test, c) + } + } else { + if c != test.a { + t.Errorf("%v: overflow addition mutated source: %d", test, c) + } + } + + // addition is commutative + c = test.b + if ok := c.Add(test.a); ok != test.ok { + t.Errorf("%v: unexpected ok: %t", test, ok) + } + if ok { + if c != test.c { + t.Errorf("%v: unexpected result: %d", test, c) + } + } else { + if c != test.b { + t.Errorf("%v: overflow addition mutated source: %d", test, c) + } + } + } +} +func TestInt64AsCanonicalString(t *testing.T) { + for _, test := range []struct { + value int64 + scale Scale + result string + exponent int32 + }{ + {100, 0, "100", 0}, + {100, 1, "1", 3}, + {100, -1, "10", 0}, + {10800, -10, "1080", -9}, + } { + r, exp := int64Amount{value: test.value, scale: test.scale}.AsCanonicalBytes(nil) + if string(r) != test.result { + t.Errorf("%v: unexpected result: %s", test, r) + } + if exp != test.exponent { + t.Errorf("%v: unexpected exponent: %d", test, exp) + } + } +} + +func TestAmountSign(t *testing.T) { + table := []struct { + i int64Amount + expect int + }{ + {int64Amount{value: -50, scale: 1}, -1}, + {int64Amount{value: 0, scale: 1}, 0}, + {int64Amount{value: 300, scale: 1}, 1}, + {int64Amount{value: -50, scale: -8}, -1}, + {int64Amount{value: 50, scale: -8}, 1}, + {int64Amount{value: 0, scale: -8}, 0}, + {int64Amount{value: -50, scale: 0}, -1}, + {int64Amount{value: 50, scale: 0}, 1}, + {int64Amount{value: 0, scale: 0}, 0}, + } + for _, testCase := range table { + if result := testCase.i.Sign(); result != testCase.expect { + t.Errorf("i: %v, Expected: %v, Actual: %v", testCase.i, testCase.expect, result) + } + } +} + +func TestInt64AmountAsScaledInt64(t *testing.T) { + for _, test := range []struct { + name string + i int64Amount + scaled Scale + result int64 + ok bool + }{ + {"test when i.scale < scaled ", int64Amount{value: 100, scale: 0}, 5, 1, true}, + {"test when i.scale = scaled", int64Amount{value: 100, scale: 1}, 1, 100, true}, + {"test when i.scale > scaled and result doesn't overflow", int64Amount{value: 100, scale: 5}, 2, 100000, true}, + {"test when i.scale > scaled and result overflows", int64Amount{value: 876, scale: 30}, 4, 0, false}, + {"test when i.scale < 0 and fraction exists", int64Amount{value: 93, scale: -1}, 0, 10, true}, + {"test when i.scale < 0 and fraction doesn't exist", int64Amount{value: 100, scale: -1}, 0, 10, true}, + {"test when i.value < 0 and fraction exists", int64Amount{value: -1932, scale: 2}, 4, -20, true}, + {"test when i.value < 0 and fraction doesn't exists", int64Amount{value: -1900, scale: 2}, 4, -19, true}, + } { + t.Run(test.name, func(t *testing.T) { + r, ok := test.i.AsScaledInt64(test.scaled) + if r != test.result { + t.Errorf("%v: expected result: %d, got result: %d", test.name, test.result, r) + } + if ok != test.ok { + t.Errorf("%v: expected ok: %t, got ok: %t", test.name, test.ok, ok) + } + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto b/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto new file mode 100644 index 000000000..2c615d51b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto @@ -0,0 +1,88 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.apimachinery.pkg.api.resource; + +// Package-wide variables from generator "generated". +option go_package = "resource"; + +// Quantity is a fixed-point representation of a number. +// It provides convenient marshaling/unmarshaling in JSON and YAML, +// in addition to String() and Int64() accessors. +// +// The serialization format is: +// +// <quantity> ::= <signedNumber><suffix> +// (Note that <suffix> may be empty, from the "" case in <decimalSI>.) +// <digit> ::= 0 | 1 | ... | 9 +// <digits> ::= <digit> | <digit><digits> +// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits> +// <sign> ::= "+" | "-" +// <signedNumber> ::= <number> | <sign><number> +// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI> +// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei +// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) +// <decimalSI> ::= m | "" | k | M | G | T | P | E +// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) +// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber> +// +// No matter which of the three exponent forms is used, no quantity may represent +// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal +// places. Numbers larger or more precise will be capped or rounded up. +// (E.g.: 0.1m will rounded up to 1m.) +// This may be extended in the future if we require larger or smaller quantities. +// +// When a Quantity is parsed from a string, it will remember the type of suffix +// it had, and will use the same type again when it is serialized. +// +// Before serializing, Quantity will be put in "canonical form". +// This means that Exponent/suffix will be adjusted up or down (with a +// corresponding increase or decrease in Mantissa) such that: +// a. No precision is lost +// b. No fractional digits will be emitted +// c. The exponent (or suffix) is as large as possible. +// The sign will be omitted unless the number is negative. +// +// Examples: +// 1.5 will be serialized as "1500m" +// 1.5Gi will be serialized as "1536Mi" +// +// Note that the quantity will NEVER be internally represented by a +// floating point number. That is the whole point of this exercise. +// +// Non-canonical values will still parse as long as they are well formed, +// but will be re-emitted in their canonical form. (So always use canonical +// form, or don't diff.) +// +// This format is intended to make it difficult to use these numbers without +// writing some sort of special handling code in the hopes that that will +// cause implementors to also use a fixed point implementation. +// +// +protobuf=true +// +protobuf.embed=string +// +protobuf.options.marshal=false +// +protobuf.options.(gogoproto.goproto_stringer)=false +// +k8s:deepcopy-gen=true +// +k8s:openapi-gen=true +message Quantity { + optional string string = 1; +} + diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go b/vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go new file mode 100644 index 000000000..070a0c237 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go @@ -0,0 +1,211 @@ +/* +Copyright 2014 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 resource + +import ( + "testing" +) + +func TestDetectOverflowAdd(t *testing.T) { + for _, test := range []struct { + a, b int64 + c int64 + ok bool + }{ + {0, 0, 0, true}, + {-1, 1, 0, true}, + {0, 1, 1, true}, + {2, 2, 4, true}, + {2, -2, 0, true}, + {-2, -2, -4, true}, + + {mostNegative, -1, 0, false}, + {mostNegative, 1, mostNegative + 1, true}, + {mostPositive, -1, mostPositive - 1, true}, + {mostPositive, 1, 0, false}, + + {mostNegative, mostPositive, -1, true}, + {mostPositive, mostNegative, -1, true}, + {mostPositive, mostPositive, 0, false}, + {mostNegative, mostNegative, 0, false}, + + {-mostPositive, mostNegative, 0, false}, + {mostNegative, -mostPositive, 0, false}, + {-mostPositive, -mostPositive, 0, false}, + } { + c, ok := int64Add(test.a, test.b) + if c != test.c { + t.Errorf("%v: unexpected result: %d", test, c) + } + if ok != test.ok { + t.Errorf("%v: unexpected overflow: %t", test, ok) + } + // addition is commutative + d, ok2 := int64Add(test.b, test.a) + if c != d || ok != ok2 { + t.Errorf("%v: not commutative: %d %t", test, d, ok2) + } + } +} + +func TestDetectOverflowMultiply(t *testing.T) { + for _, test := range []struct { + a, b int64 + c int64 + ok bool + }{ + {0, 0, 0, true}, + {-1, 1, -1, true}, + {-1, -1, 1, true}, + {1, 1, 1, true}, + {0, 1, 0, true}, + {1, 0, 0, true}, + {2, 2, 4, true}, + {2, -2, -4, true}, + {-2, -2, 4, true}, + + {mostNegative, -1, 0, false}, + {mostNegative, 1, mostNegative, true}, + {mostPositive, -1, -mostPositive, true}, + {mostPositive, 1, mostPositive, true}, + + {mostNegative, mostPositive, 0, false}, + {mostPositive, mostNegative, 0, false}, + {mostPositive, mostPositive, 1, false}, + {mostNegative, mostNegative, 0, false}, + + {-mostPositive, mostNegative, 0, false}, + {mostNegative, -mostPositive, 0, false}, + {-mostPositive, -mostPositive, 1, false}, + } { + c, ok := int64Multiply(test.a, test.b) + if c != test.c { + t.Errorf("%v: unexpected result: %d", test, c) + } + if ok != test.ok { + t.Errorf("%v: unexpected overflow: %t", test, ok) + } + // multiplication is commutative + d, ok2 := int64Multiply(test.b, test.a) + if c != d || ok != ok2 { + t.Errorf("%v: not commutative: %d %t", test, d, ok2) + } + } +} + +func TestDetectOverflowScale(t *testing.T) { + for _, a := range []int64{0, -1, 1, 10, -10, mostPositive, mostNegative, -mostPositive} { + for _, b := range []int64{1, 2, 10, 100, 1000, mostPositive} { + expect, expectOk := int64Multiply(a, b) + + c, ok := int64MultiplyScale(a, b) + if c != expect { + t.Errorf("%d*%d: unexpected result: %d", a, b, c) + } + if ok != expectOk { + t.Errorf("%d*%d: unexpected overflow: %t", a, b, ok) + } + } + for _, test := range []struct { + base int64 + fn func(a int64) (int64, bool) + }{ + {10, int64MultiplyScale10}, + {100, int64MultiplyScale100}, + {1000, int64MultiplyScale1000}, + } { + expect, expectOk := int64Multiply(a, test.base) + c, ok := test.fn(a) + if c != expect { + t.Errorf("%d*%d: unexpected result: %d", a, test.base, c) + } + if ok != expectOk { + t.Errorf("%d*%d: unexpected overflow: %t", a, test.base, ok) + } + } + } +} + +func TestRemoveInt64Factors(t *testing.T) { + for _, test := range []struct { + value int64 + max int64 + result int64 + scale int32 + }{ + {100, 10, 1, 2}, + {100, 10, 1, 2}, + {100, 100, 1, 1}, + {1, 10, 1, 0}, + } { + r, s := removeInt64Factors(test.value, test.max) + if r != test.result { + t.Errorf("%v: unexpected result: %d", test, r) + } + if s != test.scale { + t.Errorf("%v: unexpected scale: %d", test, s) + } + } +} + +func TestNegativeScaleInt64(t *testing.T) { + for _, test := range []struct { + base int64 + scale Scale + result int64 + exact bool + }{ + {1234567, 0, 1234567, true}, + {1234567, 1, 123457, false}, + {1234567, 2, 12346, false}, + {1234567, 3, 1235, false}, + {1234567, 4, 124, false}, + + {-1234567, 0, -1234567, true}, + {-1234567, 1, -123457, false}, + {-1234567, 2, -12346, false}, + {-1234567, 3, -1235, false}, + {-1234567, 4, -124, false}, + + {1000, 0, 1000, true}, + {1000, 1, 100, true}, + {1000, 2, 10, true}, + {1000, 3, 1, true}, + {1000, 4, 1, false}, + + {-1000, 0, -1000, true}, + {-1000, 1, -100, true}, + {-1000, 2, -10, true}, + {-1000, 3, -1, true}, + {-1000, 4, -1, false}, + + {0, 0, 0, true}, + {0, 1, 0, true}, + {0, 2, 0, true}, + + // negative scale is undefined behavior + {1000, -1, 1000, true}, + } { + result, exact := negativeScaleInt64(test.base, test.scale) + if result != test.result { + t.Errorf("%v: unexpected result: %d", test, result) + } + if exact != test.exact { + t.Errorf("%v: unexpected exact: %t", test, exact) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go b/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go new file mode 100644 index 000000000..56a7dbe0e --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go @@ -0,0 +1,59 @@ +/* +Copyright 2014 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 resource_test + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/resource" +) + +func ExampleFormat() { + memorySize := resource.NewQuantity(5*1024*1024*1024, resource.BinarySI) + fmt.Printf("memorySize = %v\n", memorySize) + + diskSize := resource.NewQuantity(5*1000*1000*1000, resource.DecimalSI) + fmt.Printf("diskSize = %v\n", diskSize) + + cores := resource.NewMilliQuantity(5300, resource.DecimalSI) + fmt.Printf("cores = %v\n", cores) + + // Output: + // memorySize = 5Gi + // diskSize = 5G + // cores = 5300m +} + +func ExampleMustParse() { + memorySize := resource.MustParse("5Gi") + fmt.Printf("memorySize = %v (%v)\n", memorySize.Value(), memorySize.Format) + + diskSize := resource.MustParse("5G") + fmt.Printf("diskSize = %v (%v)\n", diskSize.Value(), diskSize.Format) + + cores := resource.MustParse("5300m") + fmt.Printf("milliCores = %v (%v)\n", cores.MilliValue(), cores.Format) + + cores2 := resource.MustParse("5.4") + fmt.Printf("milliCores = %v (%v)\n", cores2.MilliValue(), cores2.Format) + + // Output: + // memorySize = 5368709120 (BinarySI) + // diskSize = 5000000000 (DecimalSI) + // milliCores = 5300 (DecimalSI) + // milliCores = 5400 (DecimalSI) +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go b/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go new file mode 100644 index 000000000..574a3cf5d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go @@ -0,0 +1,103 @@ +/* +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 resource + +import ( + "testing" + + inf "gopkg.in/inf.v0" +) + +func TestQuantityProtoMarshal(t *testing.T) { + // Test when d is nil + table := []struct { + quantity string + expect Quantity + }{ + {"0", Quantity{i: int64Amount{value: 0, scale: 0}, s: "0", Format: DecimalSI}}, + {"100m", Quantity{i: int64Amount{value: 100, scale: -3}, s: "100m", Format: DecimalSI}}, + {"50m", Quantity{i: int64Amount{value: 50, scale: -3}, s: "50m", Format: DecimalSI}}, + {"10000T", Quantity{i: int64Amount{value: 10000, scale: 12}, s: "10000T", Format: DecimalSI}}, + } + for _, testCase := range table { + q := MustParse(testCase.quantity) + // Won't currently get an error as MarshalTo can't return one + result, _ := q.Marshal() + q.MarshalTo(result) + if q.Cmp(testCase.expect) != 0 { + t.Errorf("Expected: %v, Actual: %v", testCase.expect, q) + } + } + // Test when i is {0,0} + table2 := []struct { + dec *inf.Dec + expect Quantity + }{ + {dec(0, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(0, 0).Dec}, s: "0", Format: DecimalSI}}, + {dec(10, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(10, 0).Dec}, s: "10", Format: DecimalSI}}, + {dec(-10, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(-10, 0).Dec}, s: "-10", Format: DecimalSI}}, + } + for _, testCase := range table2 { + q := Quantity{d: infDecAmount{testCase.dec}, Format: DecimalSI} + // Won't currently get an error as MarshalTo can't return one + result, _ := q.Marshal() + q.Unmarshal(result) + if q.Cmp(testCase.expect) != 0 { + t.Errorf("Expected: %v, Actual: %v", testCase.expect, q) + } + } +} + +func TestQuantityProtoUnmarshal(t *testing.T) { + // Test when d is nil + table := []struct { + input Quantity + expect string + }{ + {Quantity{i: int64Amount{value: 0, scale: 0}, s: "0", Format: DecimalSI}, "0"}, + {Quantity{i: int64Amount{value: 100, scale: -3}, s: "100m", Format: DecimalSI}, "100m"}, + {Quantity{i: int64Amount{value: 50, scale: -3}, s: "50m", Format: DecimalSI}, "50m"}, + {Quantity{i: int64Amount{value: 10000, scale: 12}, s: "10000T", Format: DecimalSI}, "10000T"}, + } + for _, testCase := range table { + var inputQ Quantity + expectQ := MustParse(testCase.expect) + inputByteArray, _ := testCase.input.Marshal() + inputQ.Unmarshal(inputByteArray) + if inputQ.Cmp(expectQ) != 0 { + t.Errorf("Expected: %v, Actual: %v", inputQ, expectQ) + } + } + // Test when i is {0,0} + table2 := []struct { + input Quantity + expect *inf.Dec + }{ + {Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(0, 0).Dec}, s: "0", Format: DecimalSI}, dec(0, 0).Dec}, + {Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(10, 0).Dec}, s: "10", Format: DecimalSI}, dec(10, 0).Dec}, + {Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(-10, 0).Dec}, s: "-10", Format: DecimalSI}, dec(-10, 0).Dec}, + } + for _, testCase := range table2 { + var inputQ Quantity + expectQ := Quantity{d: infDecAmount{testCase.expect}, Format: DecimalSI} + inputByteArray, _ := testCase.input.Marshal() + inputQ.Unmarshal(inputByteArray) + if inputQ.Cmp(expectQ) != 0 { + t.Errorf("Expected: %v, Actual: %v", inputQ, expectQ) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go b/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go new file mode 100644 index 000000000..915b2444e --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go @@ -0,0 +1,1352 @@ +/* +Copyright 2014 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 resource + +import ( + "encoding/json" + "math/rand" + "strings" + "testing" + "unicode" + + fuzz "github.com/google/gofuzz" + + inf "gopkg.in/inf.v0" +) + +func amount(i int64, exponent int) infDecAmount { + // See the below test-- scale is the negative of an exponent. + return infDecAmount{inf.NewDec(i, inf.Scale(-exponent))} +} + +func dec(i int64, exponent int) infDecAmount { + // See the below test-- scale is the negative of an exponent. + return infDecAmount{inf.NewDec(i, inf.Scale(-exponent))} +} + +func decQuantity(i int64, exponent int, format Format) Quantity { + return Quantity{d: dec(i, exponent), Format: format} +} + +func intQuantity(i int64, exponent Scale, format Format) Quantity { + return Quantity{i: int64Amount{value: i, scale: exponent}, Format: format} +} + +func TestDec(t *testing.T) { + table := []struct { + got infDecAmount + expect string + }{ + {dec(1, 0), "1"}, + {dec(1, 1), "10"}, + {dec(5, 2), "500"}, + {dec(8, 3), "8000"}, + {dec(2, 0), "2"}, + {dec(1, -1), "0.1"}, + {dec(3, -2), "0.03"}, + {dec(4, -3), "0.004"}, + } + + for _, item := range table { + if e, a := item.expect, item.got.Dec.String(); e != a { + t.Errorf("expected %v, got %v", e, a) + } + } +} + +// TestQuantityParseZero ensures that when a 0 quantity is passed, its string value is 0 +func TestQuantityParseZero(t *testing.T) { + zero := MustParse("0") + if expected, actual := "0", zero.String(); expected != actual { + t.Errorf("Expected %v, actual %v", expected, actual) + } +} + +// TestQuantityParseNonNumericPanic ensures that when a non-numeric string is parsed +// it panics +func TestQuantityParseNonNumericPanic(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("MustParse did not panic") + } + }() + _ = MustParse("Non-Numeric") +} + +// TestQuantityAddZeroPreservesSuffix verifies that a suffix is preserved +// independent of the order of operations when adding a zero and non-zero val +func TestQuantityAddZeroPreservesSuffix(t *testing.T) { + testValues := []string{"100m", "1Gi"} + zero := MustParse("0") + for _, testValue := range testValues { + value := MustParse(testValue) + v1 := *value.Copy() + // ensure non-zero + zero = non-zero (suffix preserved) + v1.Add(zero) + // ensure zero + non-zero = non-zero (suffix preserved) + v2 := *zero.Copy() + v2.Add(value) + + if v1.String() != testValue { + t.Errorf("Expected %v, actual %v", testValue, v1.String()) + continue + } + if v2.String() != testValue { + t.Errorf("Expected %v, actual %v", testValue, v2.String()) + } + } +} + +// TestQuantitySubZeroPreservesSuffix verifies that a suffix is preserved +// independent of the order of operations when subtracting a zero and non-zero val +func TestQuantitySubZeroPreservesSuffix(t *testing.T) { + testValues := []string{"100m", "1Gi"} + zero := MustParse("0") + for _, testValue := range testValues { + value := MustParse(testValue) + v1 := *value.Copy() + // ensure non-zero - zero = non-zero (suffix preserved) + v1.Sub(zero) + // ensure we preserved the input value + if v1.String() != testValue { + t.Errorf("Expected %v, actual %v", testValue, v1.String()) + } + + // ensure zero - non-zero = -non-zero (suffix preserved) + v2 := *zero.Copy() + v2.Sub(value) + negVal := *value.Copy() + negVal.Neg() + if v2.String() != negVal.String() { + t.Errorf("Expected %v, actual %v", negVal.String(), v2.String()) + } + } +} + +// TestQuantityCanocicalizeZero verifies that you get 0 as canonical value if internal value is 0, and not 0<suffix> +func TestQuantityCanocicalizeZero(t *testing.T) { + val := MustParse("1000m") + val.i.Sub(int64Amount{value: 1}) + zero := Quantity{i: val.i, Format: DecimalSI} + if expected, actual := "0", zero.String(); expected != actual { + t.Errorf("Expected %v, actual %v", expected, actual) + } +} + +func TestQuantityCmp(t *testing.T) { + // Test when d is nil + table := []struct { + x string + y string + expect int + }{ + {"0", "0", 0}, + {"100m", "50m", 1}, + {"50m", "100m", -1}, + {"10000T", "100Gi", 1}, + } + for _, testCase := range table { + q1 := MustParse(testCase.x) + q2 := MustParse(testCase.y) + if result := q1.Cmp(q2); result != testCase.expect { + t.Errorf("X: %v, Y: %v, Expected: %v, Actual: %v", testCase.x, testCase.y, testCase.expect, result) + } + } + // Test when i is {0,0} + table2 := []struct { + x *inf.Dec + y *inf.Dec + expect int + }{ + {dec(0, 0).Dec, dec(0, 0).Dec, 0}, + {nil, dec(0, 0).Dec, 0}, + {dec(0, 0).Dec, nil, 0}, + {nil, nil, 0}, + {nil, dec(10, 0).Dec, -1}, + {nil, dec(-10, 0).Dec, 1}, + {dec(10, 0).Dec, nil, 1}, + {dec(-10, 0).Dec, nil, -1}, + } + for _, testCase := range table2 { + q1 := Quantity{d: infDecAmount{testCase.x}, Format: DecimalSI} + q2 := Quantity{d: infDecAmount{testCase.y}, Format: DecimalSI} + if result := q1.Cmp(q2); result != testCase.expect { + t.Errorf("X: %v, Y: %v, Expected: %v, Actual: %v", testCase.x, testCase.y, testCase.expect, result) + } + } +} + +func TestParseQuantityString(t *testing.T) { + table := []struct { + input string + positive bool + value string + num, denom, suffix string + }{ + {"0.025Ti", true, "0.025", "0", "025", "Ti"}, + {"1.025Ti", true, "1.025", "1", "025", "Ti"}, + {"-1.025Ti", false, "-1.025", "1", "025", "Ti"}, + {".", true, ".", "0", "", ""}, + {"-.", false, "-.", "0", "", ""}, + {"1E-3", true, "1", "1", "", "E-3"}, + } + for _, test := range table { + positive, value, num, denom, suffix, err := parseQuantityString(test.input) + if err != nil { + t.Errorf("%s: error: %v", test.input, err) + continue + } + if positive != test.positive || value != test.value || num != test.num || denom != test.denom || suffix != test.suffix { + t.Errorf("%s: unmatched: %t %q %q %q %q", test.input, positive, value, num, denom, suffix) + } + } +} + +func TestQuantityParse(t *testing.T) { + if _, err := ParseQuantity(""); err == nil { + t.Errorf("expected empty string to return error") + } + + table := []struct { + input string + expect Quantity + }{ + {"0", decQuantity(0, 0, DecimalSI)}, + {"0n", decQuantity(0, 0, DecimalSI)}, + {"0u", decQuantity(0, 0, DecimalSI)}, + {"0m", decQuantity(0, 0, DecimalSI)}, + {"0Ki", decQuantity(0, 0, BinarySI)}, + {"0k", decQuantity(0, 0, DecimalSI)}, + {"0Mi", decQuantity(0, 0, BinarySI)}, + {"0M", decQuantity(0, 0, DecimalSI)}, + {"0Gi", decQuantity(0, 0, BinarySI)}, + {"0G", decQuantity(0, 0, DecimalSI)}, + {"0Ti", decQuantity(0, 0, BinarySI)}, + {"0T", decQuantity(0, 0, DecimalSI)}, + + // Quantity less numbers are allowed + {"1", decQuantity(1, 0, DecimalSI)}, + + // Binary suffixes + {"1Ki", decQuantity(1024, 0, BinarySI)}, + {"8Ki", decQuantity(8*1024, 0, BinarySI)}, + {"7Mi", decQuantity(7*1024*1024, 0, BinarySI)}, + {"6Gi", decQuantity(6*1024*1024*1024, 0, BinarySI)}, + {"5Ti", decQuantity(5*1024*1024*1024*1024, 0, BinarySI)}, + {"4Pi", decQuantity(4*1024*1024*1024*1024*1024, 0, BinarySI)}, + {"3Ei", decQuantity(3*1024*1024*1024*1024*1024*1024, 0, BinarySI)}, + + {"10Ti", decQuantity(10*1024*1024*1024*1024, 0, BinarySI)}, + {"100Ti", decQuantity(100*1024*1024*1024*1024, 0, BinarySI)}, + + // Decimal suffixes + {"5n", decQuantity(5, -9, DecimalSI)}, + {"4u", decQuantity(4, -6, DecimalSI)}, + {"3m", decQuantity(3, -3, DecimalSI)}, + {"9", decQuantity(9, 0, DecimalSI)}, + {"8k", decQuantity(8, 3, DecimalSI)}, + {"50k", decQuantity(5, 4, DecimalSI)}, + {"7M", decQuantity(7, 6, DecimalSI)}, + {"6G", decQuantity(6, 9, DecimalSI)}, + {"5T", decQuantity(5, 12, DecimalSI)}, + {"40T", decQuantity(4, 13, DecimalSI)}, + {"300T", decQuantity(3, 14, DecimalSI)}, + {"2P", decQuantity(2, 15, DecimalSI)}, + {"1E", decQuantity(1, 18, DecimalSI)}, + + // Decimal exponents + {"1E-3", decQuantity(1, -3, DecimalExponent)}, + {"1e3", decQuantity(1, 3, DecimalExponent)}, + {"1E6", decQuantity(1, 6, DecimalExponent)}, + {"1e9", decQuantity(1, 9, DecimalExponent)}, + {"1E12", decQuantity(1, 12, DecimalExponent)}, + {"1e15", decQuantity(1, 15, DecimalExponent)}, + {"1E18", decQuantity(1, 18, DecimalExponent)}, + + // Nonstandard but still parsable + {"1e14", decQuantity(1, 14, DecimalExponent)}, + {"1e13", decQuantity(1, 13, DecimalExponent)}, + {"1e3", decQuantity(1, 3, DecimalExponent)}, + {"100.035k", decQuantity(100035, 0, DecimalSI)}, + + // Things that look like floating point + {"0.001", decQuantity(1, -3, DecimalSI)}, + {"0.0005k", decQuantity(5, -1, DecimalSI)}, + {"0.005", decQuantity(5, -3, DecimalSI)}, + {"0.05", decQuantity(5, -2, DecimalSI)}, + {"0.5", decQuantity(5, -1, DecimalSI)}, + {"0.00050k", decQuantity(5, -1, DecimalSI)}, + {"0.00500", decQuantity(5, -3, DecimalSI)}, + {"0.05000", decQuantity(5, -2, DecimalSI)}, + {"0.50000", decQuantity(5, -1, DecimalSI)}, + {"0.5e0", decQuantity(5, -1, DecimalExponent)}, + {"0.5e-1", decQuantity(5, -2, DecimalExponent)}, + {"0.5e-2", decQuantity(5, -3, DecimalExponent)}, + {"0.5e0", decQuantity(5, -1, DecimalExponent)}, + {"10.035M", decQuantity(10035, 3, DecimalSI)}, + + {"1.2e3", decQuantity(12, 2, DecimalExponent)}, + {"1.3E+6", decQuantity(13, 5, DecimalExponent)}, + {"1.40e9", decQuantity(14, 8, DecimalExponent)}, + {"1.53E12", decQuantity(153, 10, DecimalExponent)}, + {"1.6e15", decQuantity(16, 14, DecimalExponent)}, + {"1.7E18", decQuantity(17, 17, DecimalExponent)}, + + {"9.01", decQuantity(901, -2, DecimalSI)}, + {"8.1k", decQuantity(81, 2, DecimalSI)}, + {"7.123456M", decQuantity(7123456, 0, DecimalSI)}, + {"6.987654321G", decQuantity(6987654321, 0, DecimalSI)}, + {"5.444T", decQuantity(5444, 9, DecimalSI)}, + {"40.1T", decQuantity(401, 11, DecimalSI)}, + {"300.2T", decQuantity(3002, 11, DecimalSI)}, + {"2.5P", decQuantity(25, 14, DecimalSI)}, + {"1.01E", decQuantity(101, 16, DecimalSI)}, + + // Things that saturate/round + {"3.001n", decQuantity(4, -9, DecimalSI)}, + {"1.1E-9", decQuantity(2, -9, DecimalExponent)}, + {"0.0000000001", decQuantity(1, -9, DecimalSI)}, + {"0.0000000005", decQuantity(1, -9, DecimalSI)}, + {"0.00000000050", decQuantity(1, -9, DecimalSI)}, + {"0.5e-9", decQuantity(1, -9, DecimalExponent)}, + {"0.9n", decQuantity(1, -9, DecimalSI)}, + {"0.00000012345", decQuantity(124, -9, DecimalSI)}, + {"0.00000012354", decQuantity(124, -9, DecimalSI)}, + {"9Ei", Quantity{d: maxAllowed, Format: BinarySI}}, + {"9223372036854775807Ki", Quantity{d: maxAllowed, Format: BinarySI}}, + {"12E", decQuantity(12, 18, DecimalSI)}, + + // We'll accept fractional binary stuff, too. + {"100.035Ki", decQuantity(10243584, -2, BinarySI)}, + {"0.5Mi", decQuantity(.5*1024*1024, 0, BinarySI)}, + {"0.05Gi", decQuantity(536870912, -1, BinarySI)}, + {"0.025Ti", decQuantity(274877906944, -1, BinarySI)}, + + // Things written by trolls + {"0.000000000001Ki", decQuantity(2, -9, DecimalSI)}, // rounds up, changes format + {".001", decQuantity(1, -3, DecimalSI)}, + {".0001k", decQuantity(100, -3, DecimalSI)}, + {"1.", decQuantity(1, 0, DecimalSI)}, + {"1.G", decQuantity(1, 9, DecimalSI)}, + } + + for _, asDec := range []bool{false, true} { + for _, item := range table { + got, err := ParseQuantity(item.input) + if err != nil { + t.Errorf("%v: unexpected error: %v", item.input, err) + continue + } + if asDec { + got.AsDec() + } + + if e, a := item.expect, got; e.Cmp(a) != 0 { + t.Errorf("%v: expected %v, got %v", item.input, e.String(), a.String()) + } + if e, a := item.expect.Format, got.Format; e != a { + t.Errorf("%v: expected %#v, got %#v", item.input, e, a) + } + + if asDec { + if i, ok := got.AsInt64(); i != 0 || ok { + t.Errorf("%v: expected inf.Dec to return false for AsInt64: %d", item.input, i) + } + continue + } + i, ok := item.expect.AsInt64() + if !ok { + continue + } + j, ok := got.AsInt64() + if !ok { + if got.d.Dec == nil && got.i.scale >= 0 { + t.Errorf("%v: is an int64Amount, but can't return AsInt64: %v", item.input, got) + } + continue + } + if i != j { + t.Errorf("%v: expected equivalent representation as int64: %d %d", item.input, i, j) + } + } + + for _, item := range table { + got, err := ParseQuantity(item.input) + if err != nil { + t.Errorf("%v: unexpected error: %v", item.input, err) + continue + } + + if asDec { + got.AsDec() + } + + // verify that we can decompose the input and get the same result by building up from the base. + positive, _, num, denom, suffix, err := parseQuantityString(item.input) + if err != nil { + t.Errorf("%v: unexpected error: %v", item.input, err) + continue + } + if got.Sign() >= 0 && !positive || got.Sign() < 0 && positive { + t.Errorf("%v: positive was incorrect: %t", item.input, positive) + continue + } + var value string + if !positive { + value = "-" + } + value += num + if len(denom) > 0 { + value += "." + denom + } + value += suffix + if len(value) == 0 { + t.Errorf("%v: did not parse correctly, %q %q %q", item.input, num, denom, suffix) + } + expected, err := ParseQuantity(value) + if err != nil { + t.Errorf("%v: unexpected error for %s: %v", item.input, value, err) + continue + } + if expected.Cmp(got) != 0 { + t.Errorf("%v: not the same as %s", item.input, value) + continue + } + } + + // Try the negative version of everything + desired := &inf.Dec{} + expect := Quantity{d: infDecAmount{Dec: desired}} + for _, item := range table { + got, err := ParseQuantity("-" + strings.TrimLeftFunc(item.input, unicode.IsSpace)) + if err != nil { + t.Errorf("-%v: unexpected error: %v", item.input, err) + continue + } + if asDec { + got.AsDec() + } + + expected := item.expect + desired.Neg(expected.AsDec()) + + if e, a := expect, got; e.Cmp(a) != 0 { + t.Errorf("%v: expected %s, got %s", item.input, e.String(), a.String()) + } + if e, a := expected.Format, got.Format; e != a { + t.Errorf("%v: expected %#v, got %#v", item.input, e, a) + } + } + + // Try everything with an explicit + + for _, item := range table { + got, err := ParseQuantity("+" + strings.TrimLeftFunc(item.input, unicode.IsSpace)) + if err != nil { + t.Errorf("-%v: unexpected error: %v", item.input, err) + continue + } + if asDec { + got.AsDec() + } + + if e, a := item.expect, got; e.Cmp(a) != 0 { + t.Errorf("%v(%t): expected %s, got %s", item.input, asDec, e.String(), a.String()) + } + if e, a := item.expect.Format, got.Format; e != a { + t.Errorf("%v: expected %#v, got %#v", item.input, e, a) + } + } + } + + invalid := []string{ + "1.1.M", + "1+1.0M", + "0.1mi", + "0.1am", + "aoeu", + ".5i", + "1i", + "-3.01i", + "-3.01e-", + + // trailing whitespace is forbidden + " 1", + "1 ", + } + for _, item := range invalid { + _, err := ParseQuantity(item) + if err == nil { + t.Errorf("%v parsed unexpectedly", item) + } + } +} + +func TestQuantityRoundUp(t *testing.T) { + table := []struct { + in string + scale Scale + expect Quantity + ok bool + }{ + {"9.01", -3, decQuantity(901, -2, DecimalSI), true}, + {"9.01", -2, decQuantity(901, -2, DecimalSI), true}, + {"9.01", -1, decQuantity(91, -1, DecimalSI), false}, + {"9.01", 0, decQuantity(10, 0, DecimalSI), false}, + {"9.01", 1, decQuantity(10, 0, DecimalSI), false}, + {"9.01", 2, decQuantity(100, 0, DecimalSI), false}, + + {"-9.01", -3, decQuantity(-901, -2, DecimalSI), true}, + {"-9.01", -2, decQuantity(-901, -2, DecimalSI), true}, + {"-9.01", -1, decQuantity(-91, -1, DecimalSI), false}, + {"-9.01", 0, decQuantity(-10, 0, DecimalSI), false}, + {"-9.01", 1, decQuantity(-10, 0, DecimalSI), false}, + {"-9.01", 2, decQuantity(-100, 0, DecimalSI), false}, + } + + for _, asDec := range []bool{false, true} { + for _, item := range table { + got, err := ParseQuantity(item.in) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expect := *item.expect.Copy() + if asDec { + got.AsDec() + } + if ok := got.RoundUp(item.scale); ok != item.ok { + t.Errorf("%s(%d,%t): unexpected ok: %t", item.in, item.scale, asDec, ok) + } + if got.Cmp(expect) != 0 { + t.Errorf("%s(%d,%t): unexpected round: %s vs %s", item.in, item.scale, asDec, got.String(), expect.String()) + } + } + } +} + +func TestQuantityCmpInt64AndDec(t *testing.T) { + table := []struct { + a, b Quantity + cmp int + }{ + {intQuantity(901, -2, DecimalSI), intQuantity(901, -2, DecimalSI), 0}, + {intQuantity(90, -1, DecimalSI), intQuantity(901, -2, DecimalSI), -1}, + {intQuantity(901, -2, DecimalSI), intQuantity(900, -2, DecimalSI), 1}, + {intQuantity(0, 0, DecimalSI), intQuantity(0, 0, DecimalSI), 0}, + {intQuantity(0, 1, DecimalSI), intQuantity(0, -1, DecimalSI), 0}, + {intQuantity(0, -1, DecimalSI), intQuantity(0, 1, DecimalSI), 0}, + {intQuantity(800, -3, DecimalSI), intQuantity(1, 0, DecimalSI), -1}, + {intQuantity(800, -3, DecimalSI), intQuantity(79, -2, DecimalSI), 1}, + + {intQuantity(mostPositive, 0, DecimalSI), intQuantity(1, -1, DecimalSI), 1}, + {intQuantity(mostPositive, 1, DecimalSI), intQuantity(1, 0, DecimalSI), 1}, + {intQuantity(mostPositive, 1, DecimalSI), intQuantity(1, 1, DecimalSI), 1}, + {intQuantity(mostPositive, 1, DecimalSI), intQuantity(0, 1, DecimalSI), 1}, + {intQuantity(mostPositive, -16, DecimalSI), intQuantity(1, 3, DecimalSI), -1}, + + {intQuantity(mostNegative, 0, DecimalSI), intQuantity(0, 0, DecimalSI), -1}, + {intQuantity(mostNegative, -18, DecimalSI), intQuantity(-1, 0, DecimalSI), -1}, + {intQuantity(mostNegative, -19, DecimalSI), intQuantity(-1, 0, DecimalSI), 1}, + + {intQuantity(1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(1, 1, DecimalSI), 0}, + {intQuantity(1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(-10, 0, DecimalSI), 1}, + {intQuantity(-1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(-10, 0, DecimalSI), 0}, + {intQuantity(1*1000000*1000000*1000000, -17, DecimalSI), intQuantity(1, 0, DecimalSI), 1}, + + {intQuantity(1*1000000*1000000*1000000+1, -17, DecimalSI), intQuantity(1, 1, DecimalSI), 1}, + {intQuantity(1*1000000*1000000*1000000-1, -17, DecimalSI), intQuantity(1, 1, DecimalSI), -1}, + } + + for _, item := range table { + if cmp := item.a.Cmp(item.b); cmp != item.cmp { + t.Errorf("%#v: unexpected Cmp: %d", item, cmp) + } + if cmp := item.b.Cmp(item.a); cmp != -item.cmp { + t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp) + } + } + + for _, item := range table { + a, b := *item.a.Copy(), *item.b.Copy() + a.AsDec() + if cmp := a.Cmp(b); cmp != item.cmp { + t.Errorf("%#v: unexpected Cmp: %d", item, cmp) + } + if cmp := b.Cmp(a); cmp != -item.cmp { + t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp) + } + } + + for _, item := range table { + a, b := *item.a.Copy(), *item.b.Copy() + b.AsDec() + if cmp := a.Cmp(b); cmp != item.cmp { + t.Errorf("%#v: unexpected Cmp: %d", item, cmp) + } + if cmp := b.Cmp(a); cmp != -item.cmp { + t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp) + } + } + + for _, item := range table { + a, b := *item.a.Copy(), *item.b.Copy() + a.AsDec() + b.AsDec() + if cmp := a.Cmp(b); cmp != item.cmp { + t.Errorf("%#v: unexpected Cmp: %d", item, cmp) + } + if cmp := b.Cmp(a); cmp != -item.cmp { + t.Errorf("%#v: unexpected inverted Cmp: %d", item, cmp) + } + } +} + +func TestQuantityNeg(t *testing.T) { + table := []struct { + a Quantity + out string + }{ + {intQuantity(901, -2, DecimalSI), "-9010m"}, + {decQuantity(901, -2, DecimalSI), "-9010m"}, + } + + for i, item := range table { + out := *item.a.Copy() + out.Neg() + if out.Cmp(item.a) == 0 { + t.Errorf("%d: negating an item should not mutate the source: %s", i, out.String()) + } + if out.String() != item.out { + t.Errorf("%d: negating did not equal exact value: %s", i, out.String()) + } + } +} + +func TestQuantityString(t *testing.T) { + table := []struct { + in Quantity + expect string + alternate string + }{ + {decQuantity(1024*1024*1024, 0, BinarySI), "1Gi", "1024Mi"}, + {decQuantity(300*1024*1024, 0, BinarySI), "300Mi", "307200Ki"}, + {decQuantity(6*1024, 0, BinarySI), "6Ki", ""}, + {decQuantity(1001*1024*1024*1024, 0, BinarySI), "1001Gi", "1025024Mi"}, + {decQuantity(1024*1024*1024*1024, 0, BinarySI), "1Ti", "1024Gi"}, + {decQuantity(5, 0, BinarySI), "5", "5000m"}, + {decQuantity(500, -3, BinarySI), "500m", "0.5"}, + {decQuantity(1, 9, DecimalSI), "1G", "1000M"}, + {decQuantity(1000, 6, DecimalSI), "1G", "0.001T"}, + {decQuantity(1000000, 3, DecimalSI), "1G", ""}, + {decQuantity(1000000000, 0, DecimalSI), "1G", ""}, + {decQuantity(1, -3, DecimalSI), "1m", "1000u"}, + {decQuantity(80, -3, DecimalSI), "80m", ""}, + {decQuantity(1080, -3, DecimalSI), "1080m", "1.08"}, + {decQuantity(108, -2, DecimalSI), "1080m", "1080000000n"}, + {decQuantity(10800, -4, DecimalSI), "1080m", ""}, + {decQuantity(300, 6, DecimalSI), "300M", ""}, + {decQuantity(1, 12, DecimalSI), "1T", ""}, + {decQuantity(1234567, 6, DecimalSI), "1234567M", ""}, + {decQuantity(1234567, -3, BinarySI), "1234567m", ""}, + {decQuantity(3, 3, DecimalSI), "3k", ""}, + {decQuantity(1025, 0, BinarySI), "1025", ""}, + {decQuantity(0, 0, DecimalSI), "0", ""}, + {decQuantity(0, 0, BinarySI), "0", ""}, + {decQuantity(1, 9, DecimalExponent), "1e9", ".001e12"}, + {decQuantity(1, -3, DecimalExponent), "1e-3", "0.001e0"}, + {decQuantity(1, -9, DecimalExponent), "1e-9", "1000e-12"}, + {decQuantity(80, -3, DecimalExponent), "80e-3", ""}, + {decQuantity(300, 6, DecimalExponent), "300e6", ""}, + {decQuantity(1, 12, DecimalExponent), "1e12", ""}, + {decQuantity(1, 3, DecimalExponent), "1e3", ""}, + {decQuantity(3, 3, DecimalExponent), "3e3", ""}, + {decQuantity(3, 3, DecimalSI), "3k", ""}, + {decQuantity(0, 0, DecimalExponent), "0", "00"}, + {decQuantity(1, -9, DecimalSI), "1n", ""}, + {decQuantity(80, -9, DecimalSI), "80n", ""}, + {decQuantity(1080, -9, DecimalSI), "1080n", ""}, + {decQuantity(108, -8, DecimalSI), "1080n", ""}, + {decQuantity(10800, -10, DecimalSI), "1080n", ""}, + {decQuantity(1, -6, DecimalSI), "1u", ""}, + {decQuantity(80, -6, DecimalSI), "80u", ""}, + {decQuantity(1080, -6, DecimalSI), "1080u", ""}, + } + for _, item := range table { + got := item.in.String() + if e, a := item.expect, got; e != a { + t.Errorf("%#v: expected %v, got %v", item.in, e, a) + } + q, err := ParseQuantity(item.expect) + if err != nil { + t.Errorf("%#v: unexpected error: %v", item.expect, err) + } + if len(q.s) == 0 || q.s != item.expect { + t.Errorf("%#v: did not copy canonical string on parse: %s", item.expect, q.s) + } + if len(item.alternate) == 0 { + continue + } + q, err = ParseQuantity(item.alternate) + if err != nil { + t.Errorf("%#v: unexpected error: %v", item.expect, err) + continue + } + if len(q.s) != 0 { + t.Errorf("%#v: unexpected nested string: %v", item.expect, q.s) + } + if q.String() != item.expect { + t.Errorf("%#v: unexpected alternate canonical: %v", item.expect, q.String()) + } + if len(q.s) == 0 || q.s != item.expect { + t.Errorf("%#v: did not set canonical string on ToString: %s", item.expect, q.s) + } + } + desired := &inf.Dec{} // Avoid modifying the values in the table. + for _, item := range table { + if item.in.Cmp(Quantity{}) == 0 { + // Don't expect it to print "-0" ever + continue + } + q := item.in + q.d = infDecAmount{desired.Neg(q.AsDec())} + if e, a := "-"+item.expect, q.String(); e != a { + t.Errorf("%#v: expected %v, got %v", item.in, e, a) + } + } +} + +func TestQuantityParseEmit(t *testing.T) { + table := []struct { + in string + expect string + }{ + {"1Ki", "1Ki"}, + {"1Mi", "1Mi"}, + {"1Gi", "1Gi"}, + {"1024Mi", "1Gi"}, + {"1000M", "1G"}, + {".001Ki", "1024m"}, + {".000001Ki", "1024u"}, + {".000000001Ki", "1024n"}, + {".000000000001Ki", "2n"}, + } + + for _, item := range table { + q, err := ParseQuantity(item.in) + if err != nil { + t.Errorf("Couldn't parse %v", item.in) + continue + } + if e, a := item.expect, q.String(); e != a { + t.Errorf("%#v: expected %v, got %v", item.in, e, a) + } + } + for _, item := range table { + q, err := ParseQuantity("-" + item.in) + if err != nil { + t.Errorf("Couldn't parse %v", item.in) + continue + } + if q.Cmp(Quantity{}) == 0 { + continue + } + if e, a := "-"+item.expect, q.String(); e != a { + t.Errorf("%#v: expected %v, got %v (%#v)", item.in, e, a, q.i) + } + } +} + +var fuzzer = fuzz.New().Funcs( + func(q *Quantity, c fuzz.Continue) { + q.i = Zero + if c.RandBool() { + q.Format = BinarySI + if c.RandBool() { + dec := &inf.Dec{} + q.d = infDecAmount{Dec: dec} + dec.SetScale(0) + dec.SetUnscaled(c.Int63()) + return + } + // Be sure to test cases like 1Mi + dec := &inf.Dec{} + q.d = infDecAmount{Dec: dec} + dec.SetScale(0) + dec.SetUnscaled(c.Int63n(1024) << uint(10*c.Intn(5))) + return + } + if c.RandBool() { + q.Format = DecimalSI + } else { + q.Format = DecimalExponent + } + if c.RandBool() { + dec := &inf.Dec{} + q.d = infDecAmount{Dec: dec} + dec.SetScale(inf.Scale(c.Intn(4))) + dec.SetUnscaled(c.Int63()) + return + } + // Be sure to test cases like 1M + dec := &inf.Dec{} + q.d = infDecAmount{Dec: dec} + dec.SetScale(inf.Scale(3 - c.Intn(15))) + dec.SetUnscaled(c.Int63n(1000)) + }, +) + +func TestQuantityDeepCopy(t *testing.T) { + // Test when d is nil + slice := []string{"0", "100m", "50m", "10000T"} + for _, testCase := range slice { + q := MustParse(testCase) + if result := q.DeepCopy(); result != q { + t.Errorf("Expected: %v, Actual: %v", q, result) + } + } + table := []*inf.Dec{ + dec(0, 0).Dec, + dec(10, 0).Dec, + dec(-10, 0).Dec, + } + // Test when i is {0,0} + for _, testCase := range table { + q := Quantity{d: infDecAmount{testCase}, Format: DecimalSI} + result := q.DeepCopy() + if q.d.Cmp(result.AsDec()) != 0 { + t.Errorf("Expected: %v, Actual: %v", q.String(), result.String()) + } + result = Quantity{d: infDecAmount{dec(2, 0).Dec}, Format: DecimalSI} + if q.d.Cmp(result.AsDec()) == 0 { + t.Errorf("Modifying result has affected q") + } + } +} + +func TestJSON(t *testing.T) { + for i := 0; i < 500; i++ { + q := &Quantity{} + fuzzer.Fuzz(q) + b, err := json.Marshal(q) + if err != nil { + t.Errorf("error encoding %v: %v", q, err) + continue + } + q2 := &Quantity{} + err = json.Unmarshal(b, q2) + if err != nil { + t.Logf("%d: %s", i, string(b)) + t.Errorf("%v: error decoding %v: %v", q, string(b), err) + } + if q2.Cmp(*q) != 0 { + t.Errorf("Expected equal: %v, %v (json was '%v')", q, q2, string(b)) + } + } +} + +func TestJSONWhitespace(t *testing.T) { + q := Quantity{} + testCases := []struct { + in string + expect string + }{ + {`" 1"`, "1"}, + {`"1 "`, "1"}, + {`1`, "1"}, + {` 1`, "1"}, + {`1 `, "1"}, + {`10`, "10"}, + {`-1`, "-1"}, + {` -1`, "-1"}, + } + for _, test := range testCases { + if err := json.Unmarshal([]byte(test.in), &q); err != nil { + t.Errorf("%q: %v", test.in, err) + } + if q.String() != test.expect { + t.Errorf("unexpected string: %q", q.String()) + } + } +} + +func TestMilliNewSet(t *testing.T) { + table := []struct { + value int64 + format Format + expect string + exact bool + }{ + {1, DecimalSI, "1m", true}, + {1000, DecimalSI, "1", true}, + {1234000, DecimalSI, "1234", true}, + {1024, BinarySI, "1024m", false}, // Format changes + {1000000, "invalidFormatDefaultsToExponent", "1e3", true}, + {1024 * 1024, BinarySI, "1048576m", false}, // Format changes + } + + for _, item := range table { + q := NewMilliQuantity(item.value, item.format) + if e, a := item.expect, q.String(); e != a { + t.Errorf("Expected %v, got %v; %#v", e, a, q) + } + if !item.exact { + continue + } + q2, err := ParseQuantity(q.String()) + if err != nil { + t.Errorf("Round trip failed on %v", q) + } + if e, a := item.value, q2.MilliValue(); e != a { + t.Errorf("Expected %v, got %v", e, a) + } + } + + for _, item := range table { + q := NewQuantity(0, item.format) + q.SetMilli(item.value) + if e, a := item.expect, q.String(); e != a { + t.Errorf("Set: Expected %v, got %v; %#v", e, a, q) + } + } +} + +func TestNewSet(t *testing.T) { + table := []struct { + value int64 + format Format + expect string + }{ + {1, DecimalSI, "1"}, + {1000, DecimalSI, "1k"}, + {1234000, DecimalSI, "1234k"}, + {1024, BinarySI, "1Ki"}, + {1000000, "invalidFormatDefaultsToExponent", "1e6"}, + {1024 * 1024, BinarySI, "1Mi"}, + } + + for _, asDec := range []bool{false, true} { + for _, item := range table { + q := NewQuantity(item.value, item.format) + if asDec { + q.ToDec() + } + if e, a := item.expect, q.String(); e != a { + t.Errorf("Expected %v, got %v; %#v", e, a, q) + } + q2, err := ParseQuantity(q.String()) + if err != nil { + t.Errorf("Round trip failed on %v", q) + } + if e, a := item.value, q2.Value(); e != a { + t.Errorf("Expected %v, got %v", e, a) + } + } + + for _, item := range table { + q := NewQuantity(0, item.format) + q.Set(item.value) + if asDec { + q.ToDec() + } + if e, a := item.expect, q.String(); e != a { + t.Errorf("Set: Expected %v, got %v; %#v", e, a, q) + } + } + } +} + +func TestNewScaledSet(t *testing.T) { + table := []struct { + value int64 + scale Scale + expect string + }{ + {1, Nano, "1n"}, + {1000, Nano, "1u"}, + {1, Micro, "1u"}, + {1000, Micro, "1m"}, + {1, Milli, "1m"}, + {1000, Milli, "1"}, + {1, 0, "1"}, + {0, Nano, "0"}, + {0, Micro, "0"}, + {0, Milli, "0"}, + {0, 0, "0"}, + } + + for _, item := range table { + q := NewScaledQuantity(item.value, item.scale) + if e, a := item.expect, q.String(); e != a { + t.Errorf("Expected %v, got %v; %#v", e, a, q) + } + q2, err := ParseQuantity(q.String()) + if err != nil { + t.Errorf("Round trip failed on %v", q) + } + if e, a := item.value, q2.ScaledValue(item.scale); e != a { + t.Errorf("Expected %v, got %v", e, a) + } + q3 := NewQuantity(0, DecimalSI) + q3.SetScaled(item.value, item.scale) + if q.Cmp(*q3) != 0 { + t.Errorf("Expected %v and %v to be equal", q, q3) + } + } +} + +func TestScaledValue(t *testing.T) { + table := []struct { + fromScale Scale + toScale Scale + expected int64 + }{ + {Nano, Nano, 1}, + {Nano, Micro, 1}, + {Nano, Milli, 1}, + {Nano, 0, 1}, + {Micro, Nano, 1000}, + {Micro, Micro, 1}, + {Micro, Milli, 1}, + {Micro, 0, 1}, + {Milli, Nano, 1000 * 1000}, + {Milli, Micro, 1000}, + {Milli, Milli, 1}, + {Milli, 0, 1}, + {0, Nano, 1000 * 1000 * 1000}, + {0, Micro, 1000 * 1000}, + {0, Milli, 1000}, + {0, 0, 1}, + } + + for _, item := range table { + q := NewScaledQuantity(1, item.fromScale) + if e, a := item.expected, q.ScaledValue(item.toScale); e != a { + t.Errorf("%v to %v: Expected %v, got %v", item.fromScale, item.toScale, e, a) + } + } +} + +func TestUninitializedNoCrash(t *testing.T) { + var q Quantity + + q.Value() + q.MilliValue() + q.Copy() + _ = q.String() + q.MarshalJSON() +} + +func TestCopy(t *testing.T) { + q := NewQuantity(5, DecimalSI) + c := q.Copy() + c.Set(6) + if q.Value() == 6 { + t.Errorf("Copy didn't") + } +} + +func TestSub(t *testing.T) { + tests := []struct { + a Quantity + b Quantity + expected Quantity + }{ + {decQuantity(10, 0, DecimalSI), decQuantity(1, 1, DecimalSI), decQuantity(0, 0, DecimalSI)}, + {decQuantity(10, 0, DecimalSI), decQuantity(1, 0, BinarySI), decQuantity(9, 0, DecimalSI)}, + {decQuantity(10, 0, BinarySI), decQuantity(1, 0, DecimalSI), decQuantity(9, 0, BinarySI)}, + {Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI), decQuantity(-50, 0, DecimalSI)}, + {decQuantity(50, 0, DecimalSI), Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI)}, + {Quantity{Format: DecimalSI}, Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)}, + } + + for i, test := range tests { + test.a.Sub(test.b) + if test.a.Cmp(test.expected) != 0 { + t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String()) + } + } +} + +func TestNeg(t *testing.T) { + tests := []struct { + a Quantity + b Quantity + expected Quantity + }{ + {a: intQuantity(0, 0, DecimalSI), expected: intQuantity(0, 0, DecimalSI)}, + {a: Quantity{}, expected: Quantity{}}, + {a: intQuantity(10, 0, BinarySI), expected: intQuantity(-10, 0, BinarySI)}, + {a: intQuantity(-10, 0, BinarySI), expected: intQuantity(10, 0, BinarySI)}, + {a: decQuantity(0, 0, DecimalSI), expected: intQuantity(0, 0, DecimalSI)}, + {a: decQuantity(10, 0, BinarySI), expected: intQuantity(-10, 0, BinarySI)}, + {a: decQuantity(-10, 0, BinarySI), expected: intQuantity(10, 0, BinarySI)}, + } + + for i, test := range tests { + a := test.a.Copy() + a.Neg() + // ensure value is same + if a.Cmp(test.expected) != 0 { + t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), a.String()) + } + } +} + +func TestAdd(t *testing.T) { + tests := []struct { + a Quantity + b Quantity + expected Quantity + }{ + {decQuantity(10, 0, DecimalSI), decQuantity(1, 1, DecimalSI), decQuantity(20, 0, DecimalSI)}, + {decQuantity(10, 0, DecimalSI), decQuantity(1, 0, BinarySI), decQuantity(11, 0, DecimalSI)}, + {decQuantity(10, 0, BinarySI), decQuantity(1, 0, DecimalSI), decQuantity(11, 0, BinarySI)}, + {Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI), decQuantity(50, 0, DecimalSI)}, + {decQuantity(50, 0, DecimalSI), Quantity{Format: DecimalSI}, decQuantity(50, 0, DecimalSI)}, + {Quantity{Format: DecimalSI}, Quantity{Format: DecimalSI}, decQuantity(0, 0, DecimalSI)}, + } + + for i, test := range tests { + test.a.Add(test.b) + if test.a.Cmp(test.expected) != 0 { + t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String()) + } + } +} + +func TestAddSubRoundTrip(t *testing.T) { + for k := -10; k <= 10; k++ { + q := Quantity{Format: DecimalSI} + var order []int64 + for i := 0; i < 100; i++ { + j := rand.Int63() + order = append(order, j) + q.Add(*NewScaledQuantity(j, Scale(k))) + } + for _, j := range order { + q.Sub(*NewScaledQuantity(j, Scale(k))) + } + if !q.IsZero() { + t.Errorf("addition and subtraction did not cancel: %s", &q) + } + } +} + +func TestAddSubRoundTripAcrossScales(t *testing.T) { + q := Quantity{Format: DecimalSI} + var order []int64 + for i := 0; i < 100; i++ { + j := rand.Int63() + order = append(order, j) + q.Add(*NewScaledQuantity(j, Scale(j%20-10))) + } + for _, j := range order { + q.Sub(*NewScaledQuantity(j, Scale(j%20-10))) + } + if !q.IsZero() { + t.Errorf("addition and subtraction did not cancel: %s", &q) + } +} + +func TestNegateRoundTrip(t *testing.T) { + for _, asDec := range []bool{false, true} { + for k := -10; k <= 10; k++ { + for i := 0; i < 100; i++ { + j := rand.Int63() + q := *NewScaledQuantity(j, Scale(k)) + if asDec { + q.AsDec() + } + + b := q.Copy() + b.Neg() + b.Neg() + if b.Cmp(q) != 0 { + t.Errorf("double negation did not cancel: %s", &q) + } + } + } + } +} +func benchmarkQuantities() []Quantity { + return []Quantity{ + intQuantity(1024*1024*1024, 0, BinarySI), + intQuantity(1024*1024*1024*1024, 0, BinarySI), + intQuantity(1000000, 3, DecimalSI), + intQuantity(1000000000, 0, DecimalSI), + intQuantity(1, -3, DecimalSI), + intQuantity(80, -3, DecimalSI), + intQuantity(1080, -3, DecimalSI), + intQuantity(0, 0, BinarySI), + intQuantity(1, 9, DecimalExponent), + intQuantity(1, -9, DecimalSI), + intQuantity(1000000, 10, DecimalSI), + } +} + +func BenchmarkQuantityString(b *testing.B) { + values := benchmarkQuantities() + b.ResetTimer() + var s string + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + q.s = "" + s = q.String() + } + b.StopTimer() + if len(s) == 0 { + b.Fatal(s) + } +} + +func BenchmarkQuantityStringPrecalc(b *testing.B) { + values := benchmarkQuantities() + for i := range values { + _ = values[i].String() + } + b.ResetTimer() + var s string + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + s = q.String() + } + b.StopTimer() + if len(s) == 0 { + b.Fatal(s) + } +} + +func BenchmarkQuantityStringBinarySI(b *testing.B) { + values := benchmarkQuantities() + for i := range values { + values[i].Format = BinarySI + } + b.ResetTimer() + var s string + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + q.s = "" + s = q.String() + } + b.StopTimer() + if len(s) == 0 { + b.Fatal(s) + } +} + +func BenchmarkQuantityMarshalJSON(b *testing.B) { + values := benchmarkQuantities() + b.ResetTimer() + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + q.s = "" + if _, err := q.MarshalJSON(); err != nil { + b.Fatal(err) + } + } + b.StopTimer() +} + +func BenchmarkQuantityUnmarshalJSON(b *testing.B) { + values := benchmarkQuantities() + var json [][]byte + for _, v := range values { + data, _ := v.MarshalJSON() + json = append(json, data) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + var q Quantity + if err := q.UnmarshalJSON(json[i%len(values)]); err != nil { + b.Fatal(err) + } + } + b.StopTimer() +} + +func BenchmarkParseQuantity(b *testing.B) { + values := benchmarkQuantities() + var strings []string + for _, v := range values { + strings = append(strings, v.String()) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + if _, err := ParseQuantity(strings[i%len(values)]); err != nil { + b.Fatal(err) + } + } + b.StopTimer() +} + +func BenchmarkCanonicalize(b *testing.B) { + values := benchmarkQuantities() + b.ResetTimer() + buffer := make([]byte, 0, 100) + for i := 0; i < b.N; i++ { + s, _ := values[i%len(values)].CanonicalizeBytes(buffer) + if len(s) == 0 { + b.Fatal(s) + } + } + b.StopTimer() +} + +func BenchmarkQuantityRoundUp(b *testing.B) { + values := benchmarkQuantities() + b.ResetTimer() + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + copied := q + copied.RoundUp(-3) + } + b.StopTimer() +} + +func BenchmarkQuantityCopy(b *testing.B) { + values := benchmarkQuantities() + b.ResetTimer() + for i := 0; i < b.N; i++ { + values[i%len(values)].Copy() + } + b.StopTimer() +} + +func BenchmarkQuantityAdd(b *testing.B) { + values := benchmarkQuantities() + base := &Quantity{} + b.ResetTimer() + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + base.d.Dec = nil + base.i = int64Amount{value: 100} + base.Add(q) + } + b.StopTimer() +} + +func BenchmarkQuantityCmp(b *testing.B) { + values := benchmarkQuantities() + b.ResetTimer() + for i := 0; i < b.N; i++ { + q := values[i%len(values)] + if q.Cmp(q) != 0 { + b.Fatal(q) + } + } + b.StopTimer() +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go b/vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go new file mode 100644 index 000000000..b150fa514 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go @@ -0,0 +1,85 @@ +/* +Copyright 2015 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 resource + +import ( + "math" + "math/big" + "testing" +) + +func TestScaledValueInternal(t *testing.T) { + tests := []struct { + unscaled *big.Int + scale int + newScale int + + want int64 + }{ + // remain scale + {big.NewInt(1000), 0, 0, 1000}, + + // scale down + {big.NewInt(1000), 0, -3, 1}, + {big.NewInt(1000), 3, 0, 1}, + {big.NewInt(0), 3, 0, 0}, + + // always round up + {big.NewInt(999), 3, 0, 1}, + {big.NewInt(500), 3, 0, 1}, + {big.NewInt(499), 3, 0, 1}, + {big.NewInt(1), 3, 0, 1}, + // large scaled value does not lose precision + {big.NewInt(0).Sub(maxInt64, bigOne), 1, 0, (math.MaxInt64-1)/10 + 1}, + // large intermediate result. + {big.NewInt(1).Exp(big.NewInt(10), big.NewInt(100), nil), 100, 0, 1}, + + // scale up + {big.NewInt(0), 0, 3, 0}, + {big.NewInt(1), 0, 3, 1000}, + {big.NewInt(1), -3, 0, 1000}, + {big.NewInt(1000), -3, 2, 100000000}, + {big.NewInt(0).Div(big.NewInt(math.MaxInt64), bigThousand), 0, 3, + (math.MaxInt64 / 1000) * 1000}, + } + + for i, tt := range tests { + old := (&big.Int{}).Set(tt.unscaled) + got := scaledValue(tt.unscaled, tt.scale, tt.newScale) + if got != tt.want { + t.Errorf("#%d: got = %v, want %v", i, got, tt.want) + } + if tt.unscaled.Cmp(old) != 0 { + t.Errorf("#%d: unscaled = %v, want %v", i, tt.unscaled, old) + } + } +} + +func BenchmarkScaledValueSmall(b *testing.B) { + s := big.NewInt(1000) + for i := 0; i < b.N; i++ { + scaledValue(s, 3, 0) + } +} + +func BenchmarkScaledValueLarge(b *testing.B) { + s := big.NewInt(math.MaxInt64) + s.Mul(s, big.NewInt(1000)) + for i := 0; i < b.N; i++ { + scaledValue(s, 10, 0) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go b/vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go new file mode 100644 index 000000000..ebd6c7e7c --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go @@ -0,0 +1,500 @@ +/* +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 validation + +import ( + "math/rand" + "reflect" + "strings" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +const ( + maxLengthErrMsg = "must be no more than" + namePartErrMsg = "name part must consist of" + nameErrMsg = "a qualified name must consist of" +) + +// Ensure custom name functions are allowed +func TestValidateObjectMetaCustomName(t *testing.T) { + errs := ValidateObjectMeta( + &metav1.ObjectMeta{Name: "test", GenerateName: "foo"}, + false, + func(s string, prefix bool) []string { + if s == "test" { + return nil + } + return []string{"name-gen"} + }, + field.NewPath("field")) + if len(errs) != 1 { + t.Fatalf("unexpected errors: %v", errs) + } + if !strings.Contains(errs[0].Error(), "name-gen") { + t.Errorf("unexpected error message: %v", errs) + } +} + +// Ensure namespace names follow dns label format +func TestValidateObjectMetaNamespaces(t *testing.T) { + errs := ValidateObjectMeta( + &metav1.ObjectMeta{Name: "test", Namespace: "foo.bar"}, + true, + func(s string, prefix bool) []string { + return nil + }, + field.NewPath("field")) + if len(errs) != 1 { + t.Fatalf("unexpected errors: %v", errs) + } + if !strings.Contains(errs[0].Error(), `Invalid value: "foo.bar"`) { + t.Errorf("unexpected error message: %v", errs) + } + maxLength := 63 + letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + b := make([]rune, maxLength+1) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + errs = ValidateObjectMeta( + &metav1.ObjectMeta{Name: "test", Namespace: string(b)}, + true, + func(s string, prefix bool) []string { + return nil + }, + field.NewPath("field")) + if len(errs) != 2 { + t.Fatalf("unexpected errors: %v", errs) + } + if !strings.Contains(errs[0].Error(), "Invalid value") || !strings.Contains(errs[1].Error(), "Invalid value") { + t.Errorf("unexpected error message: %v", errs) + } +} + +func TestValidateObjectMetaOwnerReferences(t *testing.T) { + trueVar := true + falseVar := false + testCases := []struct { + description string + ownerReferences []metav1.OwnerReference + expectError bool + expectedErrorMessage string + }{ + { + description: "simple success - third party extension.", + ownerReferences: []metav1.OwnerReference{ + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "1", + }, + }, + expectError: false, + expectedErrorMessage: "", + }, + { + description: "simple failures - event shouldn't be set as an owner", + ownerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Event", + Name: "name", + UID: "1", + }, + }, + expectError: true, + expectedErrorMessage: "is disallowed from being an owner", + }, + { + description: "simple controller ref success - one reference with Controller set", + ownerReferences: []metav1.OwnerReference{ + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "1", + Controller: &falseVar, + }, + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "2", + Controller: &trueVar, + }, + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "3", + Controller: &falseVar, + }, + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "4", + }, + }, + expectError: false, + expectedErrorMessage: "", + }, + { + description: "simple controller ref failure - two references with Controller set", + ownerReferences: []metav1.OwnerReference{ + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "1", + Controller: &falseVar, + }, + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "2", + Controller: &trueVar, + }, + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "3", + Controller: &trueVar, + }, + { + APIVersion: "customresourceVersion", + Kind: "customresourceKind", + Name: "name", + UID: "4", + }, + }, + expectError: true, + expectedErrorMessage: "Only one reference can have Controller set to true", + }, + } + + for _, tc := range testCases { + errs := ValidateObjectMeta( + &metav1.ObjectMeta{Name: "test", Namespace: "test", OwnerReferences: tc.ownerReferences}, + true, + func(s string, prefix bool) []string { + return nil + }, + field.NewPath("field")) + if len(errs) != 0 && !tc.expectError { + t.Errorf("unexpected error: %v in test case %v", errs, tc.description) + } + if len(errs) == 0 && tc.expectError { + t.Errorf("expect error in test case %v", tc.description) + } + if len(errs) != 0 && !strings.Contains(errs[0].Error(), tc.expectedErrorMessage) { + t.Errorf("unexpected error message: %v in test case %v", errs, tc.description) + } + } +} + +func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) { + if errs := ValidateObjectMetaUpdate( + &metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + &metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))}, + field.NewPath("field"), + ); len(errs) != 1 { + t.Fatalf("unexpected errors: %v", errs) + } + if errs := ValidateObjectMetaUpdate( + &metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))}, + &metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + field.NewPath("field"), + ); len(errs) != 1 { + t.Fatalf("unexpected errors: %v", errs) + } + if errs := ValidateObjectMetaUpdate( + &metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))}, + &metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(11, 0))}, + field.NewPath("field"), + ); len(errs) != 1 { + t.Fatalf("unexpected errors: %v", errs) + } +} + +func TestValidateFinalizersUpdate(t *testing.T) { + testcases := map[string]struct { + Old metav1.ObjectMeta + New metav1.ObjectMeta + ExpectedErr string + }{ + "invalid adding finalizers": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a", "y/b"}}, + ExpectedErr: "y/b", + }, + "invalid changing finalizers": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/b"}}, + ExpectedErr: "x/b", + }, + "valid removing finalizers": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a", "y/b"}}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}}, + ExpectedErr: "", + }, + "valid adding finalizers for objects not being deleted": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{"x/a"}}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{"x/a", "y/b"}}, + ExpectedErr: "", + }, + } + for name, tc := range testcases { + errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field")) + if len(errs) == 0 { + if len(tc.ExpectedErr) != 0 { + t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr) + } + } else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) { + t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a) + } + } +} + +func TestValidateFinalizersPreventConflictingFinalizers(t *testing.T) { + testcases := map[string]struct { + ObjectMeta metav1.ObjectMeta + ExpectedErr string + }{ + "conflicting finalizers": { + ObjectMeta: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents}}, + ExpectedErr: "cannot be both set", + }, + } + for name, tc := range testcases { + errs := ValidateObjectMeta(&tc.ObjectMeta, false, NameIsDNSSubdomain, field.NewPath("field")) + if len(errs) == 0 { + if len(tc.ExpectedErr) != 0 { + t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr) + } + } else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) { + t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a) + } + } +} + +func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) { + now := metav1.NewTime(time.Unix(1000, 0).UTC()) + later := metav1.NewTime(time.Unix(2000, 0).UTC()) + gracePeriodShort := int64(30) + gracePeriodLong := int64(40) + + testcases := map[string]struct { + Old metav1.ObjectMeta + New metav1.ObjectMeta + ExpectedNew metav1.ObjectMeta + ExpectedErrs []string + }{ + "valid without deletion fields": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + ExpectedErrs: []string{}, + }, + "valid with deletion fields": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort}, + ExpectedErrs: []string{}, + }, + + "invalid set deletionTimestamp": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now}, + ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:16:40 +0000 UTC: field is immutable"}, + }, + "invalid clear deletionTimestamp": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: \"null\": field is immutable"}, + }, + "invalid change deletionTimestamp": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &later}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &later}, + ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:33:20 +0000 UTC: field is immutable"}, + }, + + "invalid set deletionGracePeriodSeconds": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort}, + ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 30: field is immutable"}, + }, + "invalid clear deletionGracePeriodSeconds": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"}, + ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: \"null\": field is immutable"}, + }, + "invalid change deletionGracePeriodSeconds": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong}, + ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong}, + ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 40: field is immutable"}, + }, + } + + for k, tc := range testcases { + errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field")) + if len(errs) != len(tc.ExpectedErrs) { + t.Logf("%s: Expected: %#v", k, tc.ExpectedErrs) + t.Logf("%s: Got: %#v", k, errs) + t.Errorf("%s: expected %d errors, got %d", k, len(tc.ExpectedErrs), len(errs)) + continue + } + for i := range errs { + if errs[i].Error() != tc.ExpectedErrs[i] { + t.Errorf("%s: error #%d: expected %q, got %q", k, i, tc.ExpectedErrs[i], errs[i].Error()) + } + } + if !reflect.DeepEqual(tc.New, tc.ExpectedNew) { + t.Errorf("%s: Expected after validation:\n%#v\ngot\n%#v", k, tc.ExpectedNew, tc.New) + } + } +} + +func TestObjectMetaGenerationUpdate(t *testing.T) { + testcases := map[string]struct { + Old metav1.ObjectMeta + New metav1.ObjectMeta + ExpectedErrs []string + }{ + "invalid generation change - decremented": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 4}, + ExpectedErrs: []string{"field.generation: Invalid value: 4: must not be decremented"}, + }, + "valid generation change - incremented by one": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 1}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 2}, + ExpectedErrs: []string{}, + }, + "valid generation field - not updated": { + Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5}, + New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5}, + ExpectedErrs: []string{}, + }, + } + + for k, tc := range testcases { + errList := []string{} + errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field")) + if len(errs) != len(tc.ExpectedErrs) { + t.Logf("%s: Expected: %#v", k, tc.ExpectedErrs) + for _, err := range errs { + errList = append(errList, err.Error()) + } + t.Logf("%s: Got: %#v", k, errList) + t.Errorf("%s: expected %d errors, got %d", k, len(tc.ExpectedErrs), len(errs)) + continue + } + for i := range errList { + if errList[i] != tc.ExpectedErrs[i] { + t.Errorf("%s: error #%d: expected %q, got %q", k, i, tc.ExpectedErrs[i], errList[i]) + } + } + } +} + +// Ensure trailing slash is allowed in generate name +func TestValidateObjectMetaTrimsTrailingSlash(t *testing.T) { + errs := ValidateObjectMeta( + &metav1.ObjectMeta{Name: "test", GenerateName: "foo-"}, + false, + NameIsDNSSubdomain, + field.NewPath("field")) + if len(errs) != 0 { + t.Fatalf("unexpected errors: %v", errs) + } +} + +func TestValidateAnnotations(t *testing.T) { + successCases := []map[string]string{ + {"simple": "bar"}, + {"now-with-dashes": "bar"}, + {"1-starts-with-num": "bar"}, + {"1234": "bar"}, + {"simple/simple": "bar"}, + {"now-with-dashes/simple": "bar"}, + {"now-with-dashes/now-with-dashes": "bar"}, + {"now.with.dots/simple": "bar"}, + {"now-with.dashes-and.dots/simple": "bar"}, + {"1-num.2-num/3-num": "bar"}, + {"1234/5678": "bar"}, + {"1.2.3.4/5678": "bar"}, + {"UpperCase123": "bar"}, + {"a": strings.Repeat("b", totalAnnotationSizeLimitB-1)}, + { + "a": strings.Repeat("b", totalAnnotationSizeLimitB/2-1), + "c": strings.Repeat("d", totalAnnotationSizeLimitB/2-1), + }, + } + for i := range successCases { + errs := ValidateAnnotations(successCases[i], field.NewPath("field")) + if len(errs) != 0 { + t.Errorf("case[%d] expected success, got %#v", i, errs) + } + } + + nameErrorCases := []struct { + annotations map[string]string + expect string + }{ + {map[string]string{"nospecialchars^=@": "bar"}, namePartErrMsg}, + {map[string]string{"cantendwithadash-": "bar"}, namePartErrMsg}, + {map[string]string{"only/one/slash": "bar"}, nameErrMsg}, + {map[string]string{strings.Repeat("a", 254): "bar"}, maxLengthErrMsg}, + } + for i := range nameErrorCases { + errs := ValidateAnnotations(nameErrorCases[i].annotations, field.NewPath("field")) + if len(errs) != 1 { + t.Errorf("case[%d]: expected failure", i) + } else { + if !strings.Contains(errs[0].Detail, nameErrorCases[i].expect) { + t.Errorf("case[%d]: error details do not include %q: %q", i, nameErrorCases[i].expect, errs[0].Detail) + } + } + } + totalSizeErrorCases := []map[string]string{ + {"a": strings.Repeat("b", totalAnnotationSizeLimitB)}, + { + "a": strings.Repeat("b", totalAnnotationSizeLimitB/2), + "c": strings.Repeat("d", totalAnnotationSizeLimitB/2), + }, + } + for i := range totalSizeErrorCases { + errs := ValidateAnnotations(totalSizeErrorCases[i], field.NewPath("field")) + if len(errs) != 1 { + t.Errorf("case[%d] expected failure", i) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go new file mode 100644 index 000000000..8116f8074 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go @@ -0,0 +1,89 @@ +/* +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 internalversion + +import ( + "net/url" + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/diff" +) + +func TestListOptions(t *testing.T) { + // verify round trip conversion + ten := int64(10) + in := &metav1.ListOptions{ + LabelSelector: "a=1", + FieldSelector: "b=1", + ResourceVersion: "10", + TimeoutSeconds: &ten, + Watch: true, + } + out := &ListOptions{} + if err := scheme.Convert(in, out, nil); err != nil { + t.Fatal(err) + } + actual := &metav1.ListOptions{} + if err := scheme.Convert(out, actual, nil); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(in, actual) { + t.Errorf("unexpected: %s", diff.ObjectReflectDiff(in, actual)) + } + + // verify failing conversion + for i, failingObject := range []*metav1.ListOptions{ + {LabelSelector: "a!!!"}, + {FieldSelector: "a!!!"}, + } { + out = &ListOptions{} + if err := scheme.Convert(failingObject, out, nil); err == nil { + t.Errorf("%d: unexpected conversion: %#v", i, out) + } + } + + // verify kind registration + if gvks, unversioned, err := scheme.ObjectKinds(in); err != nil || unversioned || gvks[0] != metav1.SchemeGroupVersion.WithKind("ListOptions") { + t.Errorf("unexpected: %v %v %v", gvks[0], unversioned, err) + } + if gvks, unversioned, err := scheme.ObjectKinds(out); err != nil || unversioned || gvks[0] != SchemeGroupVersion.WithKind("ListOptions") { + t.Errorf("unexpected: %v %v %v", gvks[0], unversioned, err) + } + + actual = &metav1.ListOptions{} + if err := ParameterCodec.DecodeParameters(url.Values{"watch": []string{"1"}}, metav1.SchemeGroupVersion, actual); err != nil { + t.Fatal(err) + } + if !actual.Watch { + t.Errorf("unexpected watch decode: %#v", actual) + } + + // check ParameterCodec + query, err := ParameterCodec.EncodeParameters(in, metav1.SchemeGroupVersion) + if err != nil { + t.Fatal(err) + } + actual = &metav1.ListOptions{} + if err := ParameterCodec.DecodeParameters(query, metav1.SchemeGroupVersion, actual); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(in, actual) { + t.Errorf("unexpected: %s", diff.ObjectReflectDiff(in, actual)) + } +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go similarity index 68% rename from vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go rename to vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go index 50bdbd254..cca50eb4a 100644 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/generated_expansion.go +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go @@ -1,5 +1,5 @@ /* -Copyright The Kubernetes Authors. +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. @@ -14,8 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by client-gen. DO NOT EDIT. - package internalversion -type TestTypeExpansion interface{} +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" + "k8s.io/apimachinery/pkg/apis/meta/fuzzer" +) + +func TestRoundTrip(t *testing.T) { + roundtrip.RoundTripTestForScheme(t, scheme, fuzzer.Funcs) +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS new file mode 100755 index 000000000..cdb125a0d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS @@ -0,0 +1,31 @@ +reviewers: +- thockin +- smarterclayton +- wojtek-t +- deads2k +- brendandburns +- caesarxuchao +- liggitt +- nikhiljindal +- gmarek +- erictune +- davidopp +- sttts +- quinton-hoole +- luxas +- janetkuo +- justinsb +- ncdc +- soltysh +- dims +- madhusudancs +- hongchaodeng +- krousey +- mml +- mbohlool +- david-mcmahon +- therc +- mqliang +- kevin-wangzefeng +- jianhuiz +- feihujiang diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go new file mode 100644 index 000000000..add764a33 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go @@ -0,0 +1,133 @@ +/* +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 v1 + +import ( + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type metaObj struct { + ObjectMeta + TypeMeta +} + +func TestNewControllerRef(t *testing.T) { + gvk := schema.GroupVersionKind{ + Group: "group", + Version: "v1", + Kind: "Kind", + } + obj1 := &metaObj{ + ObjectMeta: ObjectMeta{ + Name: "name", + UID: "uid1", + }, + } + controllerRef := NewControllerRef(obj1, gvk) + if controllerRef.UID != obj1.UID { + t.Errorf("Incorrect UID: %s", controllerRef.UID) + } + if controllerRef.Controller == nil || *controllerRef.Controller != true { + t.Error("Controller must be set to true") + } + if controllerRef.BlockOwnerDeletion == nil || *controllerRef.BlockOwnerDeletion != true { + t.Error("BlockOwnerDeletion must be set to true") + } + if controllerRef.APIVersion == "" || + controllerRef.Kind == "" || + controllerRef.Name == "" { + t.Errorf("All controllerRef fields must be set: %v", controllerRef) + } +} + +func TestGetControllerOf(t *testing.T) { + gvk := schema.GroupVersionKind{ + Group: "group", + Version: "v1", + Kind: "Kind", + } + obj1 := &metaObj{ + ObjectMeta: ObjectMeta{ + UID: "uid1", + Name: "name1", + }, + } + controllerRef := NewControllerRef(obj1, gvk) + var falseRef = false + obj2 := &metaObj{ + ObjectMeta: ObjectMeta{ + UID: "uid2", + Name: "name1", + OwnerReferences: []OwnerReference{ + { + Name: "owner1", + Controller: &falseRef, + }, + *controllerRef, + { + Name: "owner2", + Controller: &falseRef, + }, + }, + }, + } + + if GetControllerOf(obj1) != nil { + t.Error("GetControllerOf must return null") + } + c := GetControllerOf(obj2) + if c.Name != controllerRef.Name || c.UID != controllerRef.UID { + t.Errorf("Incorrect result of GetControllerOf: %v", c) + } +} + +func TestIsControlledBy(t *testing.T) { + gvk := schema.GroupVersionKind{ + Group: "group", + Version: "v1", + Kind: "Kind", + } + obj1 := &metaObj{ + ObjectMeta: ObjectMeta{ + UID: "uid1", + }, + } + obj2 := &metaObj{ + ObjectMeta: ObjectMeta{ + UID: "uid2", + OwnerReferences: []OwnerReference{ + *NewControllerRef(obj1, gvk), + }, + }, + } + obj3 := &metaObj{ + ObjectMeta: ObjectMeta{ + UID: "uid3", + OwnerReferences: []OwnerReference{ + *NewControllerRef(obj2, gvk), + }, + }, + } + if !IsControlledBy(obj2, obj1) || !IsControlledBy(obj3, obj2) { + t.Error("Incorrect IsControlledBy result: false") + } + if IsControlledBy(obj3, obj1) { + t.Error("Incorrect IsControlledBy result: true") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion_test.go new file mode 100644 index 000000000..4c73d1d80 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion_test.go @@ -0,0 +1,84 @@ +/* +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 v1_test + +import ( + "testing" + + apiequality "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestMapToLabelSelectorRoundTrip(t *testing.T) { + // We should be able to round-trip a map-only selector through LabelSelector. + inputs := []map[string]string{ + nil, + {}, + {"one": "foo"}, + {"one": "foo", "two": "bar"}, + } + for _, in := range inputs { + ls := &v1.LabelSelector{} + if err := v1.Convert_Map_string_To_string_To_v1_LabelSelector(&in, ls, nil); err != nil { + t.Errorf("Convert_Map_string_To_string_To_v1_LabelSelector(%#v): %v", in, err) + continue + } + out := map[string]string{} + if err := v1.Convert_v1_LabelSelector_To_Map_string_To_string(ls, &out, nil); err != nil { + t.Errorf("Convert_v1_LabelSelector_To_Map_string_To_string(%#v): %v", ls, err) + continue + } + if !apiequality.Semantic.DeepEqual(in, out) { + t.Errorf("map-selector conversion round-trip failed: got %v; want %v", out, in) + } + } +} + +func TestConvertSliceStringToDeletionPropagation(t *testing.T) { + tcs := []struct { + Input []string + Output v1.DeletionPropagation + }{ + { + Input: nil, + Output: "", + }, + { + Input: []string{}, + Output: "", + }, + { + Input: []string{"foo"}, + Output: "foo", + }, + { + Input: []string{"bar", "foo"}, + Output: "bar", + }, + } + + for _, tc := range tcs { + var dp v1.DeletionPropagation + if err := v1.Convert_Slice_string_To_v1_DeletionPropagation(&tc.Input, &dp, nil); err != nil { + t.Errorf("Convert_Slice_string_To_v1_DeletionPropagation(%#v): %v", tc.Input, err) + continue + } + if !apiequality.Semantic.DeepEqual(dp, tc.Output) { + t.Errorf("slice string to DeletionPropagation conversion failed: got %v; want %v", dp, tc.Output) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go new file mode 100644 index 000000000..7230cb28a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go @@ -0,0 +1,153 @@ +/* +Copyright 2014 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 v1 + +import ( + "encoding/json" + "testing" + "time" + + "github.com/ghodss/yaml" +) + +type DurationHolder struct { + D Duration `json:"d"` +} + +func TestDurationMarshalYAML(t *testing.T) { + cases := []struct { + input Duration + result string + }{ + {Duration{5 * time.Second}, "d: 5s\n"}, + {Duration{2 * time.Minute}, "d: 2m0s\n"}, + {Duration{time.Hour + 3*time.Millisecond}, "d: 1h0m0.003s\n"}, + } + + for _, c := range cases { + input := DurationHolder{c.input} + result, err := yaml.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input: %q: %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result)) + } + } +} + +func TestDurationUnmarshalYAML(t *testing.T) { + cases := []struct { + input string + result Duration + }{ + {"d: 0s\n", Duration{}}, + {"d: 5s\n", Duration{5 * time.Second}}, + {"d: 2m0s\n", Duration{2 * time.Minute}}, + {"d: 1h0m0.003s\n", Duration{time.Hour + 3*time.Millisecond}}, + + // Units with zero values can optionally be dropped + {"d: 2m\n", Duration{2 * time.Minute}}, + {"d: 1h0.003s\n", Duration{time.Hour + 3*time.Millisecond}}, + } + + for _, c := range cases { + var result DurationHolder + if err := yaml.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input %q: %v", c.input, err) + } + if result.D != c.result { + t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result) + } + } +} + +func TestDurationMarshalJSON(t *testing.T) { + cases := []struct { + input Duration + result string + }{ + {Duration{5 * time.Second}, `{"d":"5s"}`}, + {Duration{2 * time.Minute}, `{"d":"2m0s"}`}, + {Duration{time.Hour + 3*time.Millisecond}, `{"d":"1h0m0.003s"}`}, + } + + for _, c := range cases { + input := DurationHolder{c.input} + result, err := json.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input: %q: %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result)) + } + } +} + +func TestDurationUnmarshalJSON(t *testing.T) { + cases := []struct { + input string + result Duration + }{ + {`{"d":"0s"}`, Duration{}}, + {`{"d":"5s"}`, Duration{5 * time.Second}}, + {`{"d":"2m0s"}`, Duration{2 * time.Minute}}, + {`{"d":"1h0m0.003s"}`, Duration{time.Hour + 3*time.Millisecond}}, + + // Units with zero values can optionally be dropped + {`{"d":"2m"}`, Duration{2 * time.Minute}}, + {`{"d":"1h0.003s"}`, Duration{time.Hour + 3*time.Millisecond}}, + } + + for _, c := range cases { + var result DurationHolder + if err := json.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input %q: %v", c.input, err) + } + if result.D != c.result { + t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result) + } + } +} + +func TestDurationMarshalJSONUnmarshalYAML(t *testing.T) { + cases := []struct { + input Duration + }{ + {Duration{}}, + {Duration{5 * time.Second}}, + {Duration{2 * time.Minute}}, + {Duration{time.Hour + 3*time.Millisecond}}, + } + + for i, c := range cases { + input := DurationHolder{c.input} + jsonMarshalled, err := json.Marshal(&input) + if err != nil { + t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err) + } + + var result DurationHolder + if err := yaml.Unmarshal(jsonMarshalled, &result); err != nil { + t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err) + } + + if input.D != result.D { + t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto new file mode 100644 index 000000000..eb3237f2b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto @@ -0,0 +1,879 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.apimachinery.pkg.apis.meta.v1; + +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1"; + +// APIGroup contains the name, the supported versions, and the preferred version +// of a group. +message APIGroup { + // name is the name of the group. + optional string name = 1; + + // versions are the versions supported in this group. + repeated GroupVersionForDiscovery versions = 2; + + // preferredVersion is the version preferred by the API server, which + // probably is the storage version. + // +optional + optional GroupVersionForDiscovery preferredVersion = 3; + + // a map of client CIDR to server address that is serving this group. + // This is to help clients reach servers in the most network-efficient way possible. + // Clients can use the appropriate server address as per the CIDR that they match. + // In case of multiple matches, clients should use the longest matching CIDR. + // The server returns only those CIDRs that it thinks that the client can match. + // For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. + // Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP. + // +optional + repeated ServerAddressByClientCIDR serverAddressByClientCIDRs = 4; +} + +// APIGroupList is a list of APIGroup, to allow clients to discover the API at +// /apis. +message APIGroupList { + // groups is a list of APIGroup. + repeated APIGroup groups = 1; +} + +// APIResource specifies the name of a resource and whether it is namespaced. +message APIResource { + // name is the plural name of the resource. + optional string name = 1; + + // singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. + // The singularName is more correct for reporting status on a single item and both singular and plural are allowed + // from the kubectl CLI interface. + optional string singularName = 6; + + // namespaced indicates if a resource is namespaced or not. + optional bool namespaced = 2; + + // group is the preferred group of the resource. Empty implies the group of the containing resource list. + // For subresources, this may have a different value, for example: Scale". + optional string group = 8; + + // version is the preferred version of the resource. Empty implies the version of the containing resource list + // For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". + optional string version = 9; + + // kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') + optional string kind = 3; + + // verbs is a list of supported kube verbs (this includes get, list, watch, create, + // update, patch, delete, deletecollection, and proxy) + optional Verbs verbs = 4; + + // shortNames is a list of suggested short names of the resource. + repeated string shortNames = 5; + + // categories is a list of the grouped resources this resource belongs to (e.g. 'all') + repeated string categories = 7; +} + +// APIResourceList is a list of APIResource, it is used to expose the name of the +// resources supported in a specific group and version, and if the resource +// is namespaced. +message APIResourceList { + // groupVersion is the group and version this APIResourceList is for. + optional string groupVersion = 1; + + // resources contains the name of the resources and if they are namespaced. + repeated APIResource resources = 2; +} + +// APIVersions lists the versions that are available, to allow clients to +// discover the API at /api, which is the root path of the legacy v1 API. +// +// +protobuf.options.(gogoproto.goproto_stringer)=false +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +message APIVersions { + // versions are the api versions that are available. + repeated string versions = 1; + + // a map of client CIDR to server address that is serving this group. + // This is to help clients reach servers in the most network-efficient way possible. + // Clients can use the appropriate server address as per the CIDR that they match. + // In case of multiple matches, clients should use the longest matching CIDR. + // The server returns only those CIDRs that it thinks that the client can match. + // For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. + // Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP. + repeated ServerAddressByClientCIDR serverAddressByClientCIDRs = 2; +} + +// CreateOptions may be provided when creating an API object. +message CreateOptions { + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + // +optional + repeated string dryRun = 1; + + // If IncludeUninitialized is specified, the object may be + // returned without completing initialization. + optional bool includeUninitialized = 2; +} + +// DeleteOptions may be provided when deleting an API object. +message DeleteOptions { + // The duration in seconds before the object should be deleted. Value must be non-negative integer. + // The value zero indicates delete immediately. If this value is nil, the default grace period for the + // specified type will be used. + // Defaults to a per object value if not specified. zero means delete immediately. + // +optional + optional int64 gracePeriodSeconds = 1; + + // Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be + // returned. + // +optional + optional Preconditions preconditions = 2; + + // Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. + // Should the dependent objects be orphaned. If true/false, the "orphan" + // finalizer will be added to/removed from the object's finalizers list. + // Either this field or PropagationPolicy may be set, but not both. + // +optional + optional bool orphanDependents = 3; + + // Whether and how garbage collection will be performed. + // Either this field or OrphanDependents may be set, but not both. + // The default policy is decided by the existing finalizer set in the + // metadata.finalizers and the resource-specific default policy. + // Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - + // allow the garbage collector to delete the dependents in the background; + // 'Foreground' - a cascading policy that deletes all dependents in the + // foreground. + // +optional + optional string propagationPolicy = 4; + + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + // +optional + repeated string dryRun = 5; +} + +// Duration is a wrapper around time.Duration which supports correct +// marshaling to YAML and JSON. In particular, it marshals into strings, which +// can be used as map keys in json. +message Duration { + optional int64 duration = 1; +} + +// ExportOptions is the query options to the standard REST get call. +message ExportOptions { + // Should this value be exported. Export strips fields that a user can not specify. + optional bool export = 1; + + // Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'. + optional bool exact = 2; +} + +// GetOptions is the standard query options to the standard REST get call. +message GetOptions { + // When specified: + // - if unset, then the result is returned from remote storage based on quorum-read flag; + // - if it's 0, then we simply return what we currently have in cache, no guarantee; + // - if set to non zero, then the result is at least as fresh as given rv. + optional string resourceVersion = 1; + + // If true, partially initialized resources are included in the response. + // +optional + optional bool includeUninitialized = 2; +} + +// GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying +// concepts during lookup stages without having partially valid types +// +// +protobuf.options.(gogoproto.goproto_stringer)=false +message GroupKind { + optional string group = 1; + + optional string kind = 2; +} + +// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying +// concepts during lookup stages without having partially valid types +// +// +protobuf.options.(gogoproto.goproto_stringer)=false +message GroupResource { + optional string group = 1; + + optional string resource = 2; +} + +// GroupVersion contains the "group" and the "version", which uniquely identifies the API. +// +// +protobuf.options.(gogoproto.goproto_stringer)=false +message GroupVersion { + optional string group = 1; + + optional string version = 2; +} + +// GroupVersion contains the "group/version" and "version" string of a version. +// It is made a struct to keep extensibility. +message GroupVersionForDiscovery { + // groupVersion specifies the API group and version in the form "group/version" + optional string groupVersion = 1; + + // version specifies the version in the form of "version". This is to save + // the clients the trouble of splitting the GroupVersion. + optional string version = 2; +} + +// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion +// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling +// +// +protobuf.options.(gogoproto.goproto_stringer)=false +message GroupVersionKind { + optional string group = 1; + + optional string version = 2; + + optional string kind = 3; +} + +// GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion +// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling +// +// +protobuf.options.(gogoproto.goproto_stringer)=false +message GroupVersionResource { + optional string group = 1; + + optional string version = 2; + + optional string resource = 3; +} + +// Initializer is information about an initializer that has not yet completed. +message Initializer { + // name of the process that is responsible for initializing this object. + optional string name = 1; +} + +// Initializers tracks the progress of initialization. +message Initializers { + // Pending is a list of initializers that must execute in order before this object is visible. + // When the last pending initializer is removed, and no failing result is set, the initializers + // struct will be set to nil and the object is considered as initialized and visible to all + // clients. + // +patchMergeKey=name + // +patchStrategy=merge + repeated Initializer pending = 1; + + // If result is set with the Failure field, the object will be persisted to storage and then deleted, + // ensuring that other clients can observe the deletion. + optional Status result = 2; +} + +// A label selector is a label query over a set of resources. The result of matchLabels and +// matchExpressions are ANDed. An empty label selector matches all objects. A null +// label selector matches no objects. +message LabelSelector { + // matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + // map is equivalent to an element of matchExpressions, whose key field is "key", the + // operator is "In", and the values array contains only "value". The requirements are ANDed. + // +optional + map<string, string> matchLabels = 1; + + // matchExpressions is a list of label selector requirements. The requirements are ANDed. + // +optional + repeated LabelSelectorRequirement matchExpressions = 2; +} + +// A label selector requirement is a selector that contains values, a key, and an operator that +// relates the key and values. +message LabelSelectorRequirement { + // key is the label key that the selector applies to. + // +patchMergeKey=key + // +patchStrategy=merge + optional string key = 1; + + // operator represents a key's relationship to a set of values. + // Valid operators are In, NotIn, Exists and DoesNotExist. + optional string operator = 2; + + // values is an array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. This array is replaced during a strategic + // merge patch. + // +optional + repeated string values = 3; +} + +// List holds a list of objects, which may not be known by the server. +message List { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional ListMeta metadata = 1; + + // List of objects + repeated k8s.io.apimachinery.pkg.runtime.RawExtension items = 2; +} + +// ListMeta describes metadata that synthetic resources must have, including lists and +// various status objects. A resource may have only one of {ObjectMeta, ListMeta}. +message ListMeta { + // selfLink is a URL representing this object. + // Populated by the system. + // Read-only. + // +optional + optional string selfLink = 1; + + // String that identifies the server's internal version of this object that + // can be used by clients to determine when objects have changed. + // Value must be treated as opaque by clients and passed unmodified back to the server. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency + // +optional + optional string resourceVersion = 2; + + // continue may be set if the user set a limit on the number of items returned, and indicates that + // the server has more data available. The value is opaque and may be used to issue another request + // to the endpoint that served this list to retrieve the next set of available objects. Continuing a + // consistent list may not be possible if the server configuration has changed or more than a few + // minutes have passed. The resourceVersion field returned when using this continue value will be + // identical to the value in the first response, unless you have received this token from an error + // message. + optional string continue = 3; +} + +// ListOptions is the query options to a standard REST list call. +message ListOptions { + // A selector to restrict the list of returned objects by their labels. + // Defaults to everything. + // +optional + optional string labelSelector = 1; + + // A selector to restrict the list of returned objects by their fields. + // Defaults to everything. + // +optional + optional string fieldSelector = 2; + + // If true, partially initialized resources are included in the response. + // +optional + optional bool includeUninitialized = 6; + + // Watch for changes to the described resources and return them as a stream of + // add, update, and remove notifications. Specify resourceVersion. + // +optional + optional bool watch = 3; + + // When specified with a watch call, shows changes that occur after that particular version of a resource. + // Defaults to changes from the beginning of history. + // When specified for list: + // - if unset, then the result is returned from remote storage based on quorum-read flag; + // - if it's 0, then we simply return what we currently have in cache, no guarantee; + // - if set to non zero, then the result is at least as fresh as given rv. + // +optional + optional string resourceVersion = 4; + + // Timeout for the list/watch call. + // This limits the duration of the call, regardless of any activity or inactivity. + // +optional + optional int64 timeoutSeconds = 5; + + // limit is a maximum number of responses to return for a list call. If more items exist, the + // server will set the `continue` field on the list metadata to a value that can be used with the + // same initial query to retrieve the next set of results. Setting a limit may return fewer than + // the requested amount of items (up to zero items) in the event all requested objects are + // filtered out and clients should only use the presence of the continue field to determine whether + // more results are available. Servers may choose not to support the limit argument and will return + // all of the available results. If limit is specified and the continue field is empty, clients may + // assume that no more results are available. This field is not supported if watch is true. + // + // The server guarantees that the objects returned when using continue will be identical to issuing + // a single list call without a limit - that is, no objects created, modified, or deleted after the + // first request is issued will be included in any subsequent continued requests. This is sometimes + // referred to as a consistent snapshot, and ensures that a client that is using limit to receive + // smaller chunks of a very large result can ensure they see all possible objects. If objects are + // updated during a chunked list the version of the object that was present at the time the first list + // result was calculated is returned. + optional int64 limit = 7; + + // The continue option should be set when retrieving more results from the server. Since this value is + // server defined, clients may only use the continue value from a previous query result with identical + // query parameters (except for the value of continue) and the server may reject a continue value it + // does not recognize. If the specified continue value is no longer valid whether due to expiration + // (generally five to fifteen minutes) or a configuration change on the server, the server will + // respond with a 410 ResourceExpired error together with a continue token. If the client needs a + // consistent list, it must restart their list without the continue field. Otherwise, the client may + // send another list request with the token received with the 410 error, the server will respond with + // a list starting from the next key, but from the latest snapshot, which is inconsistent from the + // previous list results - objects that are created, modified, or deleted after the first list request + // will be included in the response, as long as their keys are after the "next key". + // + // This field is not supported when watch is true. Clients may start a watch from the last + // resourceVersion value returned by the server and not miss any modifications. + optional string continue = 8; +} + +// MicroTime is version of Time with microsecond level precision. +// +// +protobuf.options.marshal=false +// +protobuf.as=Timestamp +// +protobuf.options.(gogoproto.goproto_stringer)=false +message MicroTime { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + optional int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. This field may be limited in precision depending on context. + optional int32 nanos = 2; +} + +// ObjectMeta is metadata that all persisted resources must have, which includes all objects +// users must create. +message ObjectMeta { + // Name must be unique within a namespace. Is required when creating resources, although + // some resources may allow a client to request the generation of an appropriate name + // automatically. Name is primarily intended for creation idempotence and configuration + // definition. + // Cannot be updated. + // More info: http://kubernetes.io/docs/user-guide/identifiers#names + // +optional + optional string name = 1; + + // GenerateName is an optional prefix, used by the server, to generate a unique + // name ONLY IF the Name field has not been provided. + // If this field is used, the name returned to the client will be different + // than the name passed. This value will also be combined with a unique suffix. + // The provided value has the same validation rules as the Name field, + // and may be truncated by the length of the suffix required to make the value + // unique on the server. + // + // If this field is specified and the generated name exists, the server will + // NOT return a 409 - instead, it will either return 201 Created or 500 with Reason + // ServerTimeout indicating a unique name could not be found in the time allotted, and the client + // should retry (optionally after the time indicated in the Retry-After header). + // + // Applied only if Name is not specified. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency + // +optional + optional string generateName = 2; + + // Namespace defines the space within each name must be unique. An empty namespace is + // equivalent to the "default" namespace, but "default" is the canonical representation. + // Not all objects are required to be scoped to a namespace - the value of this field for + // those objects will be empty. + // + // Must be a DNS_LABEL. + // Cannot be updated. + // More info: http://kubernetes.io/docs/user-guide/namespaces + // +optional + optional string namespace = 3; + + // SelfLink is a URL representing this object. + // Populated by the system. + // Read-only. + // +optional + optional string selfLink = 4; + + // UID is the unique in time and space value for this object. It is typically generated by + // the server on successful creation of a resource and is not allowed to change on PUT + // operations. + // + // Populated by the system. + // Read-only. + // More info: http://kubernetes.io/docs/user-guide/identifiers#uids + // +optional + optional string uid = 5; + + // An opaque value that represents the internal version of this object that can + // be used by clients to determine when objects have changed. May be used for optimistic + // concurrency, change detection, and the watch operation on a resource or set of resources. + // Clients must treat these values as opaque and passed unmodified back to the server. + // They may only be valid for a particular resource or set of resources. + // + // Populated by the system. + // Read-only. + // Value must be treated as opaque by clients and . + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency + // +optional + optional string resourceVersion = 6; + + // A sequence number representing a specific generation of the desired state. + // Populated by the system. Read-only. + // +optional + optional int64 generation = 7; + + // CreationTimestamp is a timestamp representing the server time when this object was + // created. It is not guaranteed to be set in happens-before order across separate operations. + // Clients may not set this value. It is represented in RFC3339 form and is in UTC. + // + // Populated by the system. + // Read-only. + // Null for lists. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional Time creationTimestamp = 8; + + // DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This + // field is set by the server when a graceful deletion is requested by the user, and is not + // directly settable by a client. The resource is expected to be deleted (no longer visible + // from resource lists, and not reachable by name) after the time in this field, once the + // finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. + // Once the deletionTimestamp is set, this value may not be unset or be set further into the + // future, although it may be shortened or the resource may be deleted prior to this time. + // For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react + // by sending a graceful termination signal to the containers in the pod. After that 30 seconds, + // the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, + // remove the pod from the API. In the presence of network partitions, this object may still + // exist after this timestamp, until an administrator or automated process can determine the + // resource is fully terminated. + // If not set, graceful deletion of the object has not been requested. + // + // Populated by the system when a graceful deletion is requested. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional Time deletionTimestamp = 9; + + // Number of seconds allowed for this object to gracefully terminate before + // it will be removed from the system. Only set when deletionTimestamp is also set. + // May only be shortened. + // Read-only. + // +optional + optional int64 deletionGracePeriodSeconds = 10; + + // Map of string keys and values that can be used to organize and categorize + // (scope and select) objects. May match selectors of replication controllers + // and services. + // More info: http://kubernetes.io/docs/user-guide/labels + // +optional + map<string, string> labels = 11; + + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: http://kubernetes.io/docs/user-guide/annotations + // +optional + map<string, string> annotations = 12; + + // List of objects depended by this object. If ALL objects in the list have + // been deleted, this object will be garbage collected. If this object is managed by a controller, + // then an entry in this list will point to this controller, with the controller field set to true. + // There cannot be more than one managing controller. + // +optional + // +patchMergeKey=uid + // +patchStrategy=merge + repeated OwnerReference ownerReferences = 13; + + // An initializer is a controller which enforces some system invariant at object creation time. + // This field is a list of initializers that have not yet acted on this object. If nil or empty, + // this object has been completely initialized. Otherwise, the object is considered uninitialized + // and is hidden (in list/watch and get calls) from clients that haven't explicitly asked to + // observe uninitialized objects. + // + // When an object is created, the system will populate this list with the current set of initializers. + // Only privileged users may set or modify this list. Once it is empty, it may not be modified further + // by any user. + optional Initializers initializers = 16; + + // Must be empty before the object is deleted from the registry. Each entry + // is an identifier for the responsible component that will remove the entry + // from the list. If the deletionTimestamp of the object is non-nil, entries + // in this list can only be removed. + // +optional + // +patchStrategy=merge + repeated string finalizers = 14; + + // The name of the cluster which the object belongs to. + // This is used to distinguish resources with same name and namespace in different clusters. + // This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request. + // +optional + optional string clusterName = 15; +} + +// OwnerReference contains enough information to let you identify an owning +// object. Currently, an owning object must be in the same namespace, so there +// is no namespace field. +message OwnerReference { + // API version of the referent. + optional string apiVersion = 5; + + // Kind of the referent. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + optional string kind = 1; + + // Name of the referent. + // More info: http://kubernetes.io/docs/user-guide/identifiers#names + optional string name = 3; + + // UID of the referent. + // More info: http://kubernetes.io/docs/user-guide/identifiers#uids + optional string uid = 4; + + // If true, this reference points to the managing controller. + // +optional + optional bool controller = 6; + + // If true, AND if the owner has the "foregroundDeletion" finalizer, then + // the owner cannot be deleted from the key-value store until this + // reference is removed. + // Defaults to false. + // To set this field, a user needs "delete" permission of the owner, + // otherwise 422 (Unprocessable Entity) will be returned. + // +optional + optional bool blockOwnerDeletion = 7; +} + +// Patch is provided to give a concrete name and type to the Kubernetes PATCH request body. +message Patch { +} + +// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out. +message Preconditions { + // Specifies the target UID. + // +optional + optional string uid = 1; +} + +// RootPaths lists the paths available at root. +// For example: "/healthz", "/apis". +message RootPaths { + // paths are the paths available at root. + repeated string paths = 1; +} + +// ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match. +message ServerAddressByClientCIDR { + // The CIDR with which clients can match their IP to figure out the server address that they should use. + optional string clientCIDR = 1; + + // Address of this server, suitable for a client that matches the above CIDR. + // This can be a hostname, hostname:port, IP or IP:port. + optional string serverAddress = 2; +} + +// Status is a return value for calls that don't return other objects. +message Status { + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional ListMeta metadata = 1; + + // Status of the operation. + // One of: "Success" or "Failure". + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status + // +optional + optional string status = 2; + + // A human-readable description of the status of this operation. + // +optional + optional string message = 3; + + // A machine-readable description of why this operation is in the + // "Failure" status. If this value is empty there + // is no information available. A Reason clarifies an HTTP status + // code but does not override it. + // +optional + optional string reason = 4; + + // Extended data associated with the reason. Each reason may define its + // own extended details. This field is optional and the data returned + // is not guaranteed to conform to any schema except that defined by + // the reason type. + // +optional + optional StatusDetails details = 5; + + // Suggested HTTP return code for this status, 0 if not set. + // +optional + optional int32 code = 6; +} + +// StatusCause provides more information about an api.Status failure, including +// cases when multiple errors are encountered. +message StatusCause { + // A machine-readable description of the cause of the error. If this value is + // empty there is no information available. + // +optional + optional string reason = 1; + + // A human-readable description of the cause of the error. This field may be + // presented as-is to a reader. + // +optional + optional string message = 2; + + // The field of the resource that has caused this error, as named by its JSON + // serialization. May include dot and postfix notation for nested attributes. + // Arrays are zero-indexed. Fields may appear more than once in an array of + // causes due to fields having multiple errors. + // Optional. + // + // Examples: + // "name" - the field "name" on the current resource + // "items[0].name" - the field "name" on the first array entry in "items" + // +optional + optional string field = 3; +} + +// StatusDetails is a set of additional properties that MAY be set by the +// server to provide additional information about a response. The Reason +// field of a Status object defines what attributes will be set. Clients +// must ignore fields that do not match the defined type of each attribute, +// and should assume that any attribute may be empty, invalid, or under +// defined. +message StatusDetails { + // The name attribute of the resource associated with the status StatusReason + // (when there is a single name which can be described). + // +optional + optional string name = 1; + + // The group attribute of the resource associated with the status StatusReason. + // +optional + optional string group = 2; + + // The kind attribute of the resource associated with the status StatusReason. + // On some operations may differ from the requested resource Kind. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional string kind = 3; + + // UID of the resource. + // (when there is a single resource which can be described). + // More info: http://kubernetes.io/docs/user-guide/identifiers#uids + // +optional + optional string uid = 6; + + // The Causes array includes more details associated with the StatusReason + // failure. Not all StatusReasons may provide detailed causes. + // +optional + repeated StatusCause causes = 4; + + // If specified, the time in seconds before the operation should be retried. Some errors may indicate + // the client must take an alternate action - for those errors this field may indicate how long to wait + // before taking the alternate action. + // +optional + optional int32 retryAfterSeconds = 5; +} + +// Time is a wrapper around time.Time which supports correct +// marshaling to YAML and JSON. Wrappers are provided for many +// of the factory methods that the time package offers. +// +// +protobuf.options.marshal=false +// +protobuf.as=Timestamp +// +protobuf.options.(gogoproto.goproto_stringer)=false +message Time { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + optional int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. This field may be limited in precision depending on context. + optional int32 nanos = 2; +} + +// Timestamp is a struct that is equivalent to Time, but intended for +// protobuf marshalling/unmarshalling. It is generated into a serialization +// that matches Time. Do not use in Go structs. +message Timestamp { + // Represents seconds of UTC time since Unix epoch + // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59Z inclusive. + optional int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. Negative + // second values with fractions must still have non-negative nanos values + // that count forward in time. Must be from 0 to 999,999,999 + // inclusive. This field may be limited in precision depending on context. + optional int32 nanos = 2; +} + +// TypeMeta describes an individual object in an API response or request +// with strings representing the type of the object and its API schema version. +// Structures that are versioned or persisted should inline TypeMeta. +// +// +k8s:deepcopy-gen=false +message TypeMeta { + // Kind is a string value representing the REST resource this object represents. + // Servers may infer this from the endpoint the client submits requests to. + // Cannot be updated. + // In CamelCase. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + // +optional + optional string kind = 1; + + // APIVersion defines the versioned schema of this representation of an object. + // Servers should convert recognized schemas to the latest internal value, and + // may reject unrecognized values. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources + // +optional + optional string apiVersion = 2; +} + +// UpdateOptions may be provided when updating an API object. +message UpdateOptions { + // When present, indicates that modifications should not be + // persisted. An invalid or unrecognized dryRun directive will + // result in an error response and no further processing of the + // request. Valid values are: + // - All: all dry run stages will be processed + // +optional + repeated string dryRun = 1; +} + +// Verbs masks the value so protobuf can generate +// +// +protobuf.nullable=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +message Verbs { + // items, if empty, will result in an empty slice + + repeated string items = 1; +} + +// Event represents a single event to a watched resource. +// +// +protobuf=true +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +message WatchEvent { + optional string type = 1; + + // Object is: + // * If Type is Added or Modified: the new state of the object. + // * If Type is Deleted: the state of the object immediately before deletion. + // * If Type is Error: *Status is recommended; other types may make sense + // depending on context. + optional k8s.io.apimachinery.pkg.runtime.RawExtension object = 2; +} + diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go new file mode 100644 index 000000000..5250e33cb --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2015 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 v1 + +import ( + gojson "encoding/json" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime/serializer/json" +) + +type GroupVersionHolder struct { + GV GroupVersion `json:"val"` +} + +func TestGroupVersionUnmarshalJSON(t *testing.T) { + cases := []struct { + input []byte + expect GroupVersion + }{ + {[]byte(`{"val": "v1"}`), GroupVersion{"", "v1"}}, + {[]byte(`{"val": "extensions/v1beta1"}`), GroupVersion{"extensions", "v1beta1"}}, + } + + for _, c := range cases { + var result GroupVersionHolder + // test golang lib's JSON codec + if err := gojson.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("JSON codec failed to unmarshal input '%v': %v", c.input, err) + } + if !reflect.DeepEqual(result.GV, c.expect) { + t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV) + } + // test the json-iterator codec + iter := json.CaseSensitiveJsonIterator() + if err := iter.Unmarshal(c.input, &result); err != nil { + t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err) + } + if !reflect.DeepEqual(result.GV, c.expect) { + t.Errorf("json-iterator codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV) + } + } +} + +func TestGroupVersionMarshalJSON(t *testing.T) { + cases := []struct { + input GroupVersion + expect []byte + }{ + {GroupVersion{"", "v1"}, []byte(`{"val":"v1"}`)}, + {GroupVersion{"extensions", "v1beta1"}, []byte(`{"val":"extensions/v1beta1"}`)}, + } + + for _, c := range cases { + input := GroupVersionHolder{c.input} + result, err := gojson.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input '%v': %v", input, err) + } + if !reflect.DeepEqual(result, c.expect) { + t.Errorf("Failed to marshal input '%+v': expected: %s, got: %s", input, c.expect, result) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go new file mode 100644 index 000000000..fa4249300 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go @@ -0,0 +1,161 @@ +/* +Copyright 2016 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 v1 + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/labels" +) + +func TestLabelSelectorAsSelector(t *testing.T) { + matchLabels := map[string]string{"foo": "bar"} + matchExpressions := []LabelSelectorRequirement{{ + Key: "baz", + Operator: LabelSelectorOpIn, + Values: []string{"qux", "norf"}, + }} + mustParse := func(s string) labels.Selector { + out, e := labels.Parse(s) + if e != nil { + panic(e) + } + return out + } + tc := []struct { + in *LabelSelector + out labels.Selector + expectErr bool + }{ + {in: nil, out: labels.Nothing()}, + {in: &LabelSelector{}, out: labels.Everything()}, + { + in: &LabelSelector{MatchLabels: matchLabels}, + out: mustParse("foo=bar"), + }, + { + in: &LabelSelector{MatchExpressions: matchExpressions}, + out: mustParse("baz in (norf,qux)"), + }, + { + in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions}, + out: mustParse("baz in (norf,qux),foo=bar"), + }, + { + in: &LabelSelector{ + MatchExpressions: []LabelSelectorRequirement{{ + Key: "baz", + Operator: LabelSelectorOpExists, + Values: []string{"qux", "norf"}, + }}, + }, + expectErr: true, + }, + } + + for i, tc := range tc { + inCopy := tc.in.DeepCopy() + out, err := LabelSelectorAsSelector(tc.in) + // after calling LabelSelectorAsSelector, tc.in shouldn't be modified + if !reflect.DeepEqual(inCopy, tc.in) { + t.Errorf("[%v]expected:\n\t%#v\nbut got:\n\t%#v", i, inCopy, tc.in) + } + if err == nil && tc.expectErr { + t.Errorf("[%v]expected error but got none.", i) + } + if err != nil && !tc.expectErr { + t.Errorf("[%v]did not expect error but got: %v", i, err) + } + // fmt.Sprint() over String() as nil.String() will panic + if fmt.Sprint(out) != fmt.Sprint(tc.out) { + t.Errorf("[%v]expected:\n\t%s\nbut got:\n\t%s", i, fmt.Sprint(tc.out), fmt.Sprint(out)) + } + } +} + +func TestLabelSelectorAsMap(t *testing.T) { + matchLabels := map[string]string{"foo": "bar"} + matchExpressions := func(operator LabelSelectorOperator, values []string) []LabelSelectorRequirement { + return []LabelSelectorRequirement{{ + Key: "baz", + Operator: operator, + Values: values, + }} + } + + tests := []struct { + in *LabelSelector + out map[string]string + errString string + }{ + {in: nil, out: nil}, + { + in: &LabelSelector{MatchLabels: matchLabels}, + out: map[string]string{"foo": "bar"}, + }, + { + in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})}, + out: map[string]string{"foo": "bar", "baz": "norf"}, + }, + { + in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})}, + out: map[string]string{"baz": "norf"}, + }, + { + in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf", "qux"})}, + out: map[string]string{"foo": "bar"}, + errString: "without a single value cannot be converted", + }, + { + in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpNotIn, []string{"norf", "qux"})}, + out: map[string]string{}, + errString: "cannot be converted", + }, + { + in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpExists, []string{})}, + out: map[string]string{"foo": "bar"}, + errString: "cannot be converted", + }, + { + in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpDoesNotExist, []string{})}, + out: map[string]string{}, + errString: "cannot be converted", + }, + } + + for i, tc := range tests { + out, err := LabelSelectorAsMap(tc.in) + if err == nil && len(tc.errString) > 0 { + t.Errorf("[%v]expected error but got none.", i) + continue + } + if err != nil && len(tc.errString) == 0 { + t.Errorf("[%v]did not expect error but got: %v", i, err) + continue + } + if err != nil && len(tc.errString) > 0 && !strings.Contains(err.Error(), tc.errString) { + t.Errorf("[%v]expected error with %q but got: %v", i, tc.errString, err) + continue + } + if !reflect.DeepEqual(out, tc.out) { + t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go new file mode 100644 index 000000000..918b1a294 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go @@ -0,0 +1,123 @@ +/* +Copyright 2016 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 v1 + +import ( + "reflect" + "testing" +) + +func TestCloneSelectorAndAddLabel(t *testing.T) { + labels := map[string]string{ + "foo1": "bar1", + "foo2": "bar2", + "foo3": "bar3", + } + matchExpressions := []LabelSelectorRequirement{ + {Key: "foo", Operator: LabelSelectorOpIn, Values: []string{"foo"}}, + } + + cases := []struct { + labels map[string]string + labelKey string + labelValue string + want map[string]string + }{ + { + labels: labels, + want: labels, + }, + { + labels: labels, + labelKey: "foo4", + labelValue: "89", + want: map[string]string{ + "foo1": "bar1", + "foo2": "bar2", + "foo3": "bar3", + "foo4": "89", + }, + }, + { + labels: nil, + labelKey: "foo4", + labelValue: "12", + want: map[string]string{ + "foo4": "12", + }, + }, + } + + for _, tc := range cases { + ls_in := LabelSelector{MatchLabels: tc.labels, MatchExpressions: matchExpressions} + ls_out := LabelSelector{MatchLabels: tc.want, MatchExpressions: matchExpressions} + + got := CloneSelectorAndAddLabel(&ls_in, tc.labelKey, tc.labelValue) + if !reflect.DeepEqual(got, &ls_out) { + t.Errorf("got %v, want %v", got, tc.want) + } + } +} + +func TestAddLabelToSelector(t *testing.T) { + labels := map[string]string{ + "foo1": "bar1", + "foo2": "bar2", + "foo3": "bar3", + } + + cases := []struct { + labels map[string]string + labelKey string + labelValue string + want map[string]string + }{ + { + labels: labels, + want: labels, + }, + { + labels: labels, + labelKey: "foo4", + labelValue: "89", + want: map[string]string{ + "foo1": "bar1", + "foo2": "bar2", + "foo3": "bar3", + "foo4": "89", + }, + }, + { + labels: nil, + labelKey: "foo4", + labelValue: "12", + want: map[string]string{ + "foo4": "12", + }, + }, + } + + for _, tc := range cases { + ls_in := LabelSelector{MatchLabels: tc.labels} + ls_out := LabelSelector{MatchLabels: tc.want} + + got := AddLabelToSelector(&ls_in, tc.labelKey, tc.labelValue) + if !reflect.DeepEqual(got, &ls_out) { + t.Errorf("got %v, want %v", got, tc.want) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_test.go new file mode 100644 index 000000000..339610aeb --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_test.go @@ -0,0 +1,139 @@ +/* +Copyright 2016 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 v1 + +import ( + "encoding/json" + "reflect" + "testing" + "time" + + "github.com/ghodss/yaml" +) + +type MicroTimeHolder struct { + T MicroTime `json:"t"` +} + +func TestMicroTimeMarshalYAML(t *testing.T) { + cases := []struct { + input MicroTime + result string + }{ + {MicroTime{}, "t: null\n"}, + {DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05.000000Z\n"}, + {DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05.000000Z\n"}, + } + + for _, c := range cases { + input := MicroTimeHolder{c.input} + result, err := yaml.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input: '%v': %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result)) + } + } +} + +func TestMicroTimeUnmarshalYAML(t *testing.T) { + cases := []struct { + input string + result MicroTime + }{ + {"t: null\n", MicroTime{}}, + {"t: 1998-05-05T05:05:05.000000Z\n", MicroTime{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}}, + } + + for _, c := range cases { + var result MicroTimeHolder + if err := yaml.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input '%v': %v", c.input, err) + } + if result.T != c.result { + t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result) + } + } +} + +func TestMicroTimeMarshalJSON(t *testing.T) { + cases := []struct { + input MicroTime + result string + }{ + {MicroTime{}, "{\"t\":null}"}, + {DateMicro(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "{\"t\":\"1998-05-05T05:05:05.000000Z\"}"}, + {DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "{\"t\":\"1998-05-05T05:05:05.000000Z\"}"}, + } + + for _, c := range cases { + input := MicroTimeHolder{c.input} + result, err := json.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input: '%v': %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result)) + } + } +} + +func TestMicroTimeUnmarshalJSON(t *testing.T) { + cases := []struct { + input string + result MicroTime + }{ + {"{\"t\":null}", MicroTime{}}, + {"{\"t\":\"1998-05-05T05:05:05.000000Z\"}", MicroTime{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}}, + } + + for _, c := range cases { + var result MicroTimeHolder + if err := json.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input '%v': %v", c.input, err) + } + if result.T != c.result { + t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result) + } + } +} + +func TestMicroTimeProto(t *testing.T) { + cases := []struct { + input MicroTime + }{ + {MicroTime{}}, + {DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.Local)}, + {DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.Local)}, + } + + for _, c := range cases { + input := c.input + data, err := input.Marshal() + if err != nil { + t.Fatalf("Failed to marshal input: '%v': %v", input, err) + } + time := MicroTime{} + if err := time.Unmarshal(data); err != nil { + t.Fatalf("Failed to unmarshal output: '%v': %v", input, err) + } + if !reflect.DeepEqual(input, time) { + t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, time) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_test.go new file mode 100644 index 000000000..9923958ee --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/time_test.go @@ -0,0 +1,197 @@ +/* +Copyright 2014 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 v1 + +import ( + "encoding/json" + "reflect" + "testing" + "time" + + "github.com/ghodss/yaml" +) + +type TimeHolder struct { + T Time `json:"t"` +} + +func TestTimeMarshalYAML(t *testing.T) { + cases := []struct { + input Time + result string + }{ + {Time{}, "t: null\n"}, + {Date(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05Z\n"}, + {Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"}, + } + + for _, c := range cases { + input := TimeHolder{c.input} + result, err := yaml.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input: '%v': %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result)) + } + } +} + +func TestTimeUnmarshalYAML(t *testing.T) { + cases := []struct { + input string + result Time + }{ + {"t: null\n", Time{}}, + {"t: 1998-05-05T05:05:05Z\n", Time{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}}, + } + + for _, c := range cases { + var result TimeHolder + if err := yaml.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input '%v': %v", c.input, err) + } + if result.T != c.result { + t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result) + } + } +} + +func TestTimeMarshalJSON(t *testing.T) { + cases := []struct { + input Time + result string + }{ + {Time{}, "{\"t\":null}"}, + {Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"}, + {Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"}, + } + + for _, c := range cases { + input := TimeHolder{c.input} + result, err := json.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input: '%v': %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result)) + } + } +} + +func TestTimeUnmarshalJSON(t *testing.T) { + cases := []struct { + input string + result Time + }{ + {"{\"t\":null}", Time{}}, + {"{\"t\":\"1998-05-05T05:05:05Z\"}", Time{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}}, + } + + for _, c := range cases { + var result TimeHolder + if err := json.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input '%v': %v", c.input, err) + } + if result.T != c.result { + t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result) + } + } +} + +func TestTimeMarshalJSONUnmarshalYAML(t *testing.T) { + cases := []struct { + input Time + }{ + {Time{}}, + {Date(1998, time.May, 5, 5, 5, 5, 50, time.Local).Rfc3339Copy()}, + {Date(1998, time.May, 5, 5, 5, 5, 0, time.Local).Rfc3339Copy()}, + } + + for i, c := range cases { + input := TimeHolder{c.input} + jsonMarshalled, err := json.Marshal(&input) + if err != nil { + t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err) + } + + var result TimeHolder + err = yaml.Unmarshal(jsonMarshalled, &result) + if err != nil { + t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err) + } + + iN, iO := input.T.Zone() + oN, oO := result.T.Zone() + if iN != oN || iO != oO { + t.Errorf("%d-3: Time zones differ before and after serialization %s:%d %s:%d", i, iN, iO, oN, oO) + } + + if input.T.UnixNano() != result.T.UnixNano() { + t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result) + } + } +} + +func TestTimeProto(t *testing.T) { + cases := []struct { + input Time + }{ + {Time{}}, + {Date(1998, time.May, 5, 1, 5, 5, 0, time.Local)}, + {Date(1998, time.May, 5, 5, 5, 5, 0, time.Local)}, + } + + for _, c := range cases { + input := c.input + data, err := input.Marshal() + if err != nil { + t.Fatalf("Failed to marshal input: '%v': %v", input, err) + } + time := Time{} + if err := time.Unmarshal(data); err != nil { + t.Fatalf("Failed to unmarshal output: '%v': %v", input, err) + } + if !reflect.DeepEqual(input, time) { + t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, time) + } + } +} + +func TestTimeEqual(t *testing.T) { + t1 := NewTime(time.Now()) + cases := []struct { + name string + x *Time + y *Time + result bool + }{ + {"nil =? nil", nil, nil, true}, + {"!nil =? !nil", &t1, &t1, true}, + {"nil =? !nil", nil, &t1, false}, + {"!nil =? nil", &t1, nil, false}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + result := c.x.Equal(c.y) + if result != c.result { + t.Errorf("Failed equality test for '%v', '%v': expected %+v, got %+v", c.x, c.y, c.result, result) + } + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go new file mode 100644 index 000000000..4c55198ee --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/types_test.go @@ -0,0 +1,135 @@ +/* +Copyright 2016 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 v1 + +import ( + gojson "encoding/json" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime/serializer/json" +) + +func TestVerbsMarshalJSON(t *testing.T) { + cases := []struct { + input APIResource + result string + }{ + {APIResource{}, `{"name":"","singularName":"","namespaced":false,"kind":"","verbs":null}`}, + {APIResource{Verbs: Verbs([]string{})}, `{"name":"","singularName":"","namespaced":false,"kind":"","verbs":[]}`}, + {APIResource{Verbs: Verbs([]string{"delete"})}, `{"name":"","singularName":"","namespaced":false,"kind":"","verbs":["delete"]}`}, + } + + for i, c := range cases { + result, err := gojson.Marshal(&c.input) + if err != nil { + t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err) + } + if string(result) != c.result { + t.Errorf("[%d] Failed to marshal input: '%v': expected '%v', got '%v'", i, c.input, c.result, string(result)) + } + } +} + +func TestVerbsJsonIterUnmarshalJSON(t *testing.T) { + cases := []struct { + input string + result APIResource + }{ + {`{}`, APIResource{}}, + {`{"verbs":null}`, APIResource{}}, + {`{"verbs":[]}`, APIResource{Verbs: Verbs([]string{})}}, + {`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}}, + } + + iter := json.CaseSensitiveJsonIterator() + for i, c := range cases { + var result APIResource + if err := iter.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err) + } + if !reflect.DeepEqual(result, c.result) { + t.Errorf("[%d] Failed to unmarshal input '%v': expected %+v, got %+v", i, c.input, c.result, result) + } + } +} + +// TestMarshalJSONWithOmit tests that we don't have regressions regarding nil and empty slices with "omit" +func TestMarshalJSONWithOmit(t *testing.T) { + cases := []struct { + input LabelSelector + result string + }{ + {LabelSelector{}, `{}`}, + {LabelSelector{MatchExpressions: []LabelSelectorRequirement{}}, `{}`}, + {LabelSelector{MatchExpressions: []LabelSelectorRequirement{{}}}, `{"matchExpressions":[{"key":"","operator":""}]}`}, + } + + for i, c := range cases { + result, err := gojson.Marshal(&c.input) + if err != nil { + t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err) + } + if string(result) != c.result { + t.Errorf("[%d] Failed to marshal input: '%v': expected '%v', got '%v'", i, c.input, c.result, string(result)) + } + } +} + +func TestVerbsUnmarshalJSON(t *testing.T) { + cases := []struct { + input string + result APIResource + }{ + {`{}`, APIResource{}}, + {`{"verbs":null}`, APIResource{}}, + {`{"verbs":[]}`, APIResource{Verbs: Verbs([]string{})}}, + {`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}}, + } + + for i, c := range cases { + var result APIResource + if err := gojson.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err) + } + if !reflect.DeepEqual(result, c.result) { + t.Errorf("[%d] Failed to unmarshal input '%v': expected %+v, got %+v", i, c.input, c.result, result) + } + } +} + +func TestVerbsProto(t *testing.T) { + cases := []APIResource{ + {}, + {Verbs: Verbs([]string{})}, + {Verbs: Verbs([]string{"delete"})}, + } + + for _, input := range cases { + data, err := input.Marshal() + if err != nil { + t.Fatalf("Failed to marshal input: '%v': %v", input, err) + } + resource := APIResource{} + if err := resource.Unmarshal(data); err != nil { + t.Fatalf("Failed to unmarshal output: '%v': %v", input, err) + } + if !reflect.DeepEqual(input, resource) { + t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, resource) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers_test.go new file mode 100644 index 000000000..d97996211 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers_test.go @@ -0,0 +1,136 @@ +/* +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 unstructured + +import ( + "io/ioutil" + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestCodecOfUnstructuredList tests that there are no data races in Encode(). +// i.e. that it does not mutate the object being encoded. +func TestCodecOfUnstructuredList(t *testing.T) { + var wg sync.WaitGroup + concurrency := 10 + list := UnstructuredList{ + Object: map[string]interface{}{}, + } + wg.Add(concurrency) + for i := 0; i < concurrency; i++ { + go func() { + defer wg.Done() + assert.NoError(t, UnstructuredJSONScheme.Encode(&list, ioutil.Discard)) + }() + } + wg.Wait() +} + +func TestRemoveNestedField(t *testing.T) { + obj := map[string]interface{}{ + "x": map[string]interface{}{ + "y": 1, + "a": "foo", + }, + } + RemoveNestedField(obj, "x", "a") + assert.Len(t, obj["x"], 1) + RemoveNestedField(obj, "x", "y") + assert.Empty(t, obj["x"]) + RemoveNestedField(obj, "x") + assert.Empty(t, obj) + RemoveNestedField(obj, "x") // Remove of a non-existent field + assert.Empty(t, obj) +} + +func TestNestedFieldNoCopy(t *testing.T) { + target := map[string]interface{}{"foo": "bar"} + + obj := map[string]interface{}{ + "a": map[string]interface{}{ + "b": target, + "c": nil, + "d": []interface{}{"foo"}, + }, + } + + // case 1: field exists and is non-nil + res, exists, err := NestedFieldNoCopy(obj, "a", "b") + assert.True(t, exists) + assert.Nil(t, err) + assert.Equal(t, target, res) + target["foo"] = "baz" + assert.Equal(t, target["foo"], res.(map[string]interface{})["foo"], "result should be a reference to the expected item") + + // case 2: field exists and is nil + res, exists, err = NestedFieldNoCopy(obj, "a", "c") + assert.True(t, exists) + assert.Nil(t, err) + assert.Nil(t, res) + + // case 3: error traversing obj + res, exists, err = NestedFieldNoCopy(obj, "a", "d", "foo") + assert.False(t, exists) + assert.NotNil(t, err) + assert.Nil(t, res) + + // case 4: field does not exist + res, exists, err = NestedFieldNoCopy(obj, "a", "e") + assert.False(t, exists) + assert.Nil(t, err) + assert.Nil(t, res) +} + +func TestNestedFieldCopy(t *testing.T) { + target := map[string]interface{}{"foo": "bar"} + + obj := map[string]interface{}{ + "a": map[string]interface{}{ + "b": target, + "c": nil, + "d": []interface{}{"foo"}, + }, + } + + // case 1: field exists and is non-nil + res, exists, err := NestedFieldCopy(obj, "a", "b") + assert.True(t, exists) + assert.Nil(t, err) + assert.Equal(t, target, res) + target["foo"] = "baz" + assert.NotEqual(t, target["foo"], res.(map[string]interface{})["foo"], "result should be a copy of the expected item") + + // case 2: field exists and is nil + res, exists, err = NestedFieldCopy(obj, "a", "c") + assert.True(t, exists) + assert.Nil(t, err) + assert.Nil(t, res) + + // case 3: error traversing obj + res, exists, err = NestedFieldCopy(obj, "a", "d", "foo") + assert.False(t, exists) + assert.NotNil(t, err) + assert.Nil(t, res) + + // case 4: field does not exist + res, exists, err = NestedFieldCopy(obj, "a", "e") + assert.False(t, exists) + assert.Nil(t, err) + assert.Nil(t, res) +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list_test.go new file mode 100644 index 000000000..04ada449b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_list_test.go @@ -0,0 +1,86 @@ +/* +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 unstructured + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUnstructuredList(t *testing.T) { + list := &UnstructuredList{ + Object: map[string]interface{}{"kind": "List", "apiVersion": "v1"}, + Items: []Unstructured{ + {Object: map[string]interface{}{"kind": "Pod", "apiVersion": "v1", "metadata": map[string]interface{}{"name": "test"}}}, + }, + } + content := list.UnstructuredContent() + items := content["items"].([]interface{}) + require.Len(t, items, 1) + val, found, err := NestedFieldCopy(items[0].(map[string]interface{}), "metadata", "name") + require.True(t, found) + require.NoError(t, err) + assert.Equal(t, "test", val) +} + +func TestNilDeletionTimestamp(t *testing.T) { + var u Unstructured + del := u.GetDeletionTimestamp() + if del != nil { + t.Errorf("unexpected non-nil deletion timestamp: %v", del) + } + u.SetDeletionTimestamp(u.GetDeletionTimestamp()) + del = u.GetDeletionTimestamp() + if del != nil { + t.Errorf("unexpected non-nil deletion timestamp: %v", del) + } + _, ok := u.Object["metadata"] + assert.False(t, ok) + + now := metav1.Now() + u.SetDeletionTimestamp(&now) + assert.Equal(t, now.Unix(), u.GetDeletionTimestamp().Unix()) + u.SetDeletionTimestamp(nil) + metadata := u.Object["metadata"].(map[string]interface{}) + _, ok = metadata["deletionTimestamp"] + assert.False(t, ok) +} + +func TestEmptyCreationTimestampIsOmitted(t *testing.T) { + var u Unstructured + now := metav1.Now() + + // set an initial creationTimestamp and ensure the field exists + u.SetCreationTimestamp(now) + metadata := u.Object["metadata"].(map[string]interface{}) + creationTimestamp, exists := metadata["creationTimestamp"] + if !exists { + t.Fatalf("unexpected missing creationTimestamp") + } + + // set an empty timestamp and ensure the field no longer exists + u.SetCreationTimestamp(metav1.Time{}) + metadata = u.Object["metadata"].(map[string]interface{}) + creationTimestamp, exists = metadata["creationTimestamp"] + if exists { + t.Errorf("unexpected creation timestamp field: %q", creationTimestamp) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go new file mode 100644 index 000000000..4a03fff65 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go @@ -0,0 +1,162 @@ +/* +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. +*/ + +package unstructured_test + +import ( + "math/rand" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + + "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" + "k8s.io/apimachinery/pkg/api/equality" + metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/util/diff" +) + +func TestNilUnstructuredContent(t *testing.T) { + var u unstructured.Unstructured + uCopy := u.DeepCopy() + content := u.UnstructuredContent() + expContent := make(map[string]interface{}) + assert.EqualValues(t, expContent, content) + assert.Equal(t, uCopy, &u) +} + +// TestUnstructuredMetadataRoundTrip checks that metadata accessors +// correctly set the metadata for unstructured objects. +// First, it fuzzes an empty ObjectMeta and sets this value as the metadata for an unstructured object. +// Next, it uses metadata accessor methods to set these fuzzed values to another unstructured object. +// Finally, it checks that both the unstructured objects are equal. +func TestUnstructuredMetadataRoundTrip(t *testing.T) { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + seed := rand.Int63() + fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(seed), codecs) + + N := 1000 + for i := 0; i < N; i++ { + u := &unstructured.Unstructured{Object: map[string]interface{}{}} + uCopy := u.DeepCopy() + metadata := &metav1.ObjectMeta{} + fuzzer.Fuzz(metadata) + + if err := setObjectMeta(u, metadata); err != nil { + t.Fatalf("unexpected error setting fuzzed ObjectMeta: %v", err) + } + setObjectMetaUsingAccessors(u, uCopy) + + // TODO: remove this special casing when creationTimestamp becomes a pointer. + // Right now, creationTimestamp is a struct (metav1.Time) so omitempty holds no meaning for it. + // However, the current behaviour is to remove the field if it holds an empty struct. + // This special casing exists here because custom marshallers for metav1.Time marshal + // an empty value to "null", which gets converted to nil when converting to an unstructured map by "ToUnstructured". + if err := unstructured.SetNestedField(uCopy.UnstructuredContent(), nil, "metadata", "creationTimestamp"); err != nil { + t.Fatalf("unexpected error setting creationTimestamp as nil: %v", err) + } + + if !equality.Semantic.DeepEqual(u, uCopy) { + t.Errorf("diff: %v", diff.ObjectReflectDiff(u, uCopy)) + } + } +} + +// TestUnstructuredMetadataOmitempty checks that ObjectMeta omitempty +// semantics are enforced for unstructured objects. +// The fuzzing test above should catch these cases but this is here just to be safe. +// Example: the metadata.clusterName field has the omitempty json tag +// so if it is set to it's zero value (""), it should be removed from the metadata map. +func TestUnstructuredMetadataOmitempty(t *testing.T) { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + seed := rand.Int63() + fuzzer := fuzzer.FuzzerFor(metafuzzer.Funcs, rand.NewSource(seed), codecs) + + // fuzz to make sure we don't miss any function calls below + u := &unstructured.Unstructured{Object: map[string]interface{}{}} + metadata := &metav1.ObjectMeta{} + fuzzer.Fuzz(metadata) + if err := setObjectMeta(u, metadata); err != nil { + t.Fatalf("unexpected error setting fuzzed ObjectMeta: %v", err) + } + + // set zero values for all fields in metadata explicitly + // to check that omitempty fields having zero values are never set + u.SetName("") + u.SetGenerateName("") + u.SetNamespace("") + u.SetSelfLink("") + u.SetUID("") + u.SetResourceVersion("") + u.SetGeneration(0) + u.SetCreationTimestamp(metav1.Time{}) + u.SetDeletionTimestamp(nil) + u.SetDeletionGracePeriodSeconds(nil) + u.SetLabels(nil) + u.SetAnnotations(nil) + u.SetOwnerReferences(nil) + u.SetInitializers(nil) + u.SetFinalizers(nil) + u.SetClusterName("") + + gotMetadata, _, err := unstructured.NestedFieldNoCopy(u.UnstructuredContent(), "metadata") + if err != nil { + t.Error(err) + } + emptyMetadata := make(map[string]interface{}) + + if !reflect.DeepEqual(gotMetadata, emptyMetadata) { + t.Errorf("expected %v, got %v", emptyMetadata, gotMetadata) + } +} + +func setObjectMeta(u *unstructured.Unstructured, objectMeta *metav1.ObjectMeta) error { + if objectMeta == nil { + unstructured.RemoveNestedField(u.UnstructuredContent(), "metadata") + return nil + } + metadata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(objectMeta) + if err != nil { + return err + } + u.UnstructuredContent()["metadata"] = metadata + return nil +} + +func setObjectMetaUsingAccessors(u, uCopy *unstructured.Unstructured) { + uCopy.SetName(u.GetName()) + uCopy.SetGenerateName(u.GetGenerateName()) + uCopy.SetNamespace(u.GetNamespace()) + uCopy.SetSelfLink(u.GetSelfLink()) + uCopy.SetUID(u.GetUID()) + uCopy.SetResourceVersion(u.GetResourceVersion()) + uCopy.SetGeneration(u.GetGeneration()) + uCopy.SetCreationTimestamp(u.GetCreationTimestamp()) + uCopy.SetDeletionTimestamp(u.GetDeletionTimestamp()) + uCopy.SetDeletionGracePeriodSeconds(u.GetDeletionGracePeriodSeconds()) + uCopy.SetLabels(u.GetLabels()) + uCopy.SetAnnotations(u.GetAnnotations()) + uCopy.SetOwnerReferences(u.GetOwnerReferences()) + uCopy.SetInitializers(u.GetInitializers()) + uCopy.SetFinalizers(u.GetFinalizers()) + uCopy.SetClusterName(u.GetClusterName()) +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation/validation_test.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation/validation_test.go new file mode 100644 index 000000000..a7046a548 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation/validation_test.go @@ -0,0 +1,127 @@ +/* +Copyright 2016 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 validation + +import ( + "fmt" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func TestValidateLabels(t *testing.T) { + successCases := []map[string]string{ + {"simple": "bar"}, + {"now-with-dashes": "bar"}, + {"1-starts-with-num": "bar"}, + {"1234": "bar"}, + {"simple/simple": "bar"}, + {"now-with-dashes/simple": "bar"}, + {"now-with-dashes/now-with-dashes": "bar"}, + {"now.with.dots/simple": "bar"}, + {"now-with.dashes-and.dots/simple": "bar"}, + {"1-num.2-num/3-num": "bar"}, + {"1234/5678": "bar"}, + {"1.2.3.4/5678": "bar"}, + {"UpperCaseAreOK123": "bar"}, + {"goodvalue": "123_-.BaR"}, + } + for i := range successCases { + errs := ValidateLabels(successCases[i], field.NewPath("field")) + if len(errs) != 0 { + t.Errorf("case[%d] expected success, got %#v", i, errs) + } + } + + namePartErrMsg := "name part must consist of" + nameErrMsg := "a qualified name must consist of" + labelErrMsg := "a valid label must be an empty string or consist of" + maxLengthErrMsg := "must be no more than" + + labelNameErrorCases := []struct { + labels map[string]string + expect string + }{ + {map[string]string{"nospecialchars^=@": "bar"}, namePartErrMsg}, + {map[string]string{"cantendwithadash-": "bar"}, namePartErrMsg}, + {map[string]string{"only/one/slash": "bar"}, nameErrMsg}, + {map[string]string{strings.Repeat("a", 254): "bar"}, maxLengthErrMsg}, + } + for i := range labelNameErrorCases { + errs := ValidateLabels(labelNameErrorCases[i].labels, field.NewPath("field")) + if len(errs) != 1 { + t.Errorf("case[%d]: expected failure", i) + } else { + if !strings.Contains(errs[0].Detail, labelNameErrorCases[i].expect) { + t.Errorf("case[%d]: error details do not include %q: %q", i, labelNameErrorCases[i].expect, errs[0].Detail) + } + } + } + + labelValueErrorCases := []struct { + labels map[string]string + expect string + }{ + {map[string]string{"toolongvalue": strings.Repeat("a", 64)}, maxLengthErrMsg}, + {map[string]string{"backslashesinvalue": "some\\bad\\value"}, labelErrMsg}, + {map[string]string{"nocommasallowed": "bad,value"}, labelErrMsg}, + {map[string]string{"strangecharsinvalue": "?#$notsogood"}, labelErrMsg}, + } + for i := range labelValueErrorCases { + errs := ValidateLabels(labelValueErrorCases[i].labels, field.NewPath("field")) + if len(errs) != 1 { + t.Errorf("case[%d]: expected failure", i) + } else { + if !strings.Contains(errs[0].Detail, labelValueErrorCases[i].expect) { + t.Errorf("case[%d]: error details do not include %q: %q", i, labelValueErrorCases[i].expect, errs[0].Detail) + } + } + } +} + +func TestValidDryRun(t *testing.T) { + tests := [][]string{ + {}, + {"All"}, + {"All", "All"}, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { + if errs := validateDryRun(field.NewPath("dryRun"), test); len(errs) != 0 { + t.Errorf("%v should be a valid dry-run value: %v", test, errs) + } + }) + } +} + +func TestInvalidDryRun(t *testing.T) { + tests := [][]string{ + {"False"}, + {"All", "False"}, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { + if len(validateDryRun(field.NewPath("dryRun"), test)) == 0 { + t.Errorf("%v shouldn't be a valid dry-run value", test) + } + }) + } + +} diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1/generated.proto b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1/generated.proto new file mode 100644 index 000000000..83be99790 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1beta1/generated.proto @@ -0,0 +1,57 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.apimachinery.pkg.apis.meta.v1beta1; + +import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/generated.proto"; +import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; + +// Package-wide variables from generator "generated". +option go_package = "v1beta1"; + +// PartialObjectMetadata is a generic representation of any object with ObjectMeta. It allows clients +// to get access to a particular ObjectMeta schema without knowing the details of the version. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +message PartialObjectMetadata { + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; +} + +// PartialObjectMetadataList contains a list of objects containing only their metadata +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +message PartialObjectMetadataList { + // items contains each of the included items. + repeated PartialObjectMetadata items = 1; +} + +// TableOptions are used when a Table is requested by the caller. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +message TableOptions { + // includeObject decides whether to include each object along with its columnar information. + // Specifying "None" will return no object, specifying "Object" will return the full object contents, and + // specifying "Metadata" (the default) will return the object's metadata in the PartialObjectMetadata kind + // in version v1beta1 of the meta.k8s.io API group. + optional string includeObject = 1; +} + diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/converter_test.go b/vendor/k8s.io/apimachinery/pkg/conversion/converter_test.go new file mode 100644 index 000000000..924f69913 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/conversion/converter_test.go @@ -0,0 +1,734 @@ +/* +Copyright 2014 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 conversion + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "testing" + + "github.com/google/gofuzz" + flag "github.com/spf13/pflag" + + "k8s.io/apimachinery/pkg/util/diff" +) + +var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.") + +// Test a weird version/kind embedding format. +type MyWeirdCustomEmbeddedVersionKindField struct { + ID string `json:"ID,omitempty"` + APIVersion string `json:"myVersionKey,omitempty"` + ObjectKind string `json:"myKindKey,omitempty"` + Z string `json:"Z,omitempty"` + Y uint64 `json:"Y,omitempty"` +} + +type TestType1 struct { + MyWeirdCustomEmbeddedVersionKindField `json:",inline"` + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` + C int8 `json:"C,omitempty"` + D int16 `json:"D,omitempty"` + E int32 `json:"E,omitempty"` + F int64 `json:"F,omitempty"` + G uint `json:"G,omitempty"` + H uint8 `json:"H,omitempty"` + I uint16 `json:"I,omitempty"` + J uint32 `json:"J,omitempty"` + K uint64 `json:"K,omitempty"` + L bool `json:"L,omitempty"` + M map[string]int `json:"M,omitempty"` + N map[string]TestType2 `json:"N,omitempty"` + O *TestType2 `json:"O,omitempty"` + P []TestType2 `json:"Q,omitempty"` +} + +type TestType2 struct { + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` +} + +type ExternalTestType2 struct { + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` +} +type ExternalTestType1 struct { + MyWeirdCustomEmbeddedVersionKindField `json:",inline"` + A string `json:"A,omitempty"` + B int `json:"B,omitempty"` + C int8 `json:"C,omitempty"` + D int16 `json:"D,omitempty"` + E int32 `json:"E,omitempty"` + F int64 `json:"F,omitempty"` + G uint `json:"G,omitempty"` + H uint8 `json:"H,omitempty"` + I uint16 `json:"I,omitempty"` + J uint32 `json:"J,omitempty"` + K uint64 `json:"K,omitempty"` + L bool `json:"L,omitempty"` + M map[string]int `json:"M,omitempty"` + N map[string]ExternalTestType2 `json:"N,omitempty"` + O *ExternalTestType2 `json:"O,omitempty"` + P []ExternalTestType2 `json:"Q,omitempty"` +} + +func testLogger(t *testing.T) DebugLogger { + // We don't set logger to eliminate rubbish logs in tests. + // If you want to switch it, simply switch it to: "return t" + return nil +} + +func TestConverter_byteSlice(t *testing.T) { + c := NewConverter(DefaultNameFunc) + src := []byte{1, 2, 3} + dest := []byte{} + err := c.Convert(&src, &dest, 0, nil) + if err != nil { + t.Fatalf("expected no error") + } + if e, a := src, dest; !reflect.DeepEqual(e, a) { + t.Errorf("expected %#v, got %#v", e, a) + } +} + +func TestConverter_MismatchedTypes(t *testing.T) { + c := NewConverter(DefaultNameFunc) + + err := c.RegisterConversionFunc( + func(in *[]string, out *int, s Scope) error { + if str, err := strconv.Atoi((*in)[0]); err != nil { + return err + } else { + *out = str + return nil + } + }, + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + src := []string{"5"} + var dest *int + err = c.Convert(&src, &dest, 0, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if e, a := 5, *dest; e != a { + t.Errorf("expected %#v, got %#v", e, a) + } +} + +func TestConverter_DefaultConvert(t *testing.T) { + type A struct { + Foo string + Baz int + } + type B struct { + Bar string + Baz int + } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + c.nameFunc = func(t reflect.Type) string { return "MyType" } + + // Ensure conversion funcs can call DefaultConvert to get default behavior, + // then fixup remaining fields manually + err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { + if err := s.DefaultConvert(in, out, IgnoreMissingFields); err != nil { + return err + } + out.Bar = in.Foo + return nil + }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + x := A{"hello, intrepid test reader!", 3} + y := B{} + + err = c.Convert(&x, &y, 0, nil) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + if e, a := x.Foo, y.Bar; e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := x.Baz, y.Baz; e != a { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestConverter_DeepCopy(t *testing.T) { + type A struct { + Foo *string + Bar []string + Baz interface{} + Qux map[string]string + } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + + foo, baz := "foo", "baz" + x := A{ + Foo: &foo, + Bar: []string{"bar"}, + Baz: &baz, + Qux: map[string]string{"qux": "qux"}, + } + y := A{} + + if err := c.Convert(&x, &y, 0, nil); err != nil { + t.Fatalf("unexpected error %v", err) + } + *x.Foo = "foo2" + x.Bar[0] = "bar2" + *x.Baz.(*string) = "baz2" + x.Qux["qux"] = "qux2" + if e, a := *x.Foo, *y.Foo; e == a { + t.Errorf("expected difference between %v and %v", e, a) + } + if e, a := x.Bar, y.Bar; reflect.DeepEqual(e, a) { + t.Errorf("expected difference between %v and %v", e, a) + } + if e, a := *x.Baz.(*string), *y.Baz.(*string); e == a { + t.Errorf("expected difference between %v and %v", e, a) + } + if e, a := x.Qux, y.Qux; reflect.DeepEqual(e, a) { + t.Errorf("expected difference between %v and %v", e, a) + } +} + +func TestConverter_CallsRegisteredFunctions(t *testing.T) { + type A struct { + Foo string + Baz int + } + type B struct { + Bar string + Baz int + } + type C struct{} + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { + out.Bar = in.Foo + return s.Convert(&in.Baz, &out.Baz, 0) + }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = c.RegisterConversionFunc(func(in *B, out *A, s Scope) error { + out.Foo = in.Bar + return s.Convert(&in.Baz, &out.Baz, 0) + }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + x := A{"hello, intrepid test reader!", 3} + y := B{} + + err = c.Convert(&x, &y, 0, nil) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + if e, a := x.Foo, y.Bar; e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := x.Baz, y.Baz; e != a { + t.Errorf("expected %v, got %v", e, a) + } + + z := B{"all your test are belong to us", 42} + w := A{} + + err = c.Convert(&z, &w, 0, nil) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + if e, a := z.Bar, w.Foo; e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := z.Baz, w.Baz; e != a { + t.Errorf("expected %v, got %v", e, a) + } + + err = c.RegisterConversionFunc(func(in *A, out *C, s Scope) error { + return fmt.Errorf("C can't store an A, silly") + }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = c.Convert(&A{}, &C{}, 0, nil) + if err == nil { + t.Errorf("unexpected non-error") + } +} + +func TestConverter_IgnoredConversion(t *testing.T) { + type A struct{} + type B struct{} + + count := 0 + c := NewConverter(DefaultNameFunc) + if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { + count++ + return nil + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + if err := c.RegisterIgnoredConversion(&A{}, &B{}); err != nil { + t.Fatal(err) + } + a := A{} + b := B{} + if err := c.Convert(&a, &b, 0, nil); err != nil { + t.Errorf("%v", err) + } + if count != 0 { + t.Errorf("unexpected number of conversion invocations") + } +} + +func TestConverter_IgnoredConversionNested(t *testing.T) { + type C string + type A struct { + C C + } + type B struct { + C C + } + + c := NewConverter(DefaultNameFunc) + typed := C("") + if err := c.RegisterIgnoredConversion(&typed, &typed); err != nil { + t.Fatal(err) + } + a := A{C: C("test")} + b := B{C: C("other")} + if err := c.Convert(&a, &b, AllowDifferentFieldTypeNames, nil); err != nil { + t.Errorf("%v", err) + } + if b.C != C("other") { + t.Errorf("expected no conversion of field C: %#v", b) + } +} + +func TestConverter_GeneratedConversionOverriden(t *testing.T) { + type A struct{} + type B struct{} + c := NewConverter(DefaultNameFunc) + if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { + return nil + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error { + return fmt.Errorf("generated function should be overridden") + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + + a := A{} + b := B{} + if err := c.Convert(&a, &b, 0, nil); err != nil { + t.Errorf("%v", err) + } +} + +func TestConverter_WithConversionOverriden(t *testing.T) { + type A struct{} + type B struct{} + c := NewConverter(DefaultNameFunc) + if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error { + return fmt.Errorf("conversion function should be overridden") + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error { + return fmt.Errorf("generated function should be overridden") + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + + ext := NewConversionFuncs() + ext.Add(func(in *A, out *B, s Scope) error { + return nil + }) + newc := c.WithConversions(ext) + + a := A{} + b := B{} + if err := c.Convert(&a, &b, 0, nil); err == nil || err.Error() != "conversion function should be overridden" { + t.Errorf("unexpected error: %v", err) + } + if err := newc.Convert(&a, &b, 0, nil); err != nil { + t.Errorf("%v", err) + } +} + +func TestConverter_MapsStringArrays(t *testing.T) { + type A struct { + Foo string + Baz int + Other string + } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error { + if len(*input) == 0 { + *out = "" + } + *out = (*input)[0] + return nil + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + + x := map[string][]string{ + "Foo": {"bar"}, + "Baz": {"1"}, + "Other": {"", "test"}, + "other": {"wrong"}, + } + y := A{"test", 2, "something"} + + if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames, nil); err == nil { + t.Error("unexpected non-error") + } + + if err := c.RegisterConversionFunc(func(input *[]string, out *int, s Scope) error { + if len(*input) == 0 { + *out = 0 + } + str := (*input)[0] + i, err := strconv.Atoi(str) + if err != nil { + return err + } + *out = i + return nil + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + + if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames, nil); err != nil { + t.Fatalf("unexpected error %v", err) + } + if !reflect.DeepEqual(y, A{"bar", 1, ""}) { + t.Errorf("unexpected result: %#v", y) + } +} + +func TestConverter_MapsStringArraysWithMappingKey(t *testing.T) { + type A struct { + Foo string `json:"test"` + Baz int + Other string + } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error { + if len(*input) == 0 { + *out = "" + } + *out = (*input)[0] + return nil + }); err != nil { + t.Fatalf("unexpected error %v", err) + } + + x := map[string][]string{ + "Foo": {"bar"}, + "test": {"baz"}, + } + y := A{"", 0, ""} + + if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames|IgnoreMissingFields, &Meta{}); err != nil { + t.Fatalf("unexpected error %v", err) + } + if !reflect.DeepEqual(y, A{"bar", 0, ""}) { + t.Errorf("unexpected result: %#v", y) + } + + mapping := func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string) { + if s := destTag.Get("json"); len(s) > 0 { + return strings.SplitN(s, ",", 2)[0], key + } + return key, key + } + + if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames|IgnoreMissingFields, &Meta{KeyNameMapping: mapping}); err != nil { + t.Fatalf("unexpected error %v", err) + } + if !reflect.DeepEqual(y, A{"baz", 0, ""}) { + t.Errorf("unexpected result: %#v", y) + } +} + +func TestConverter_fuzz(t *testing.T) { + // Use the same types from the scheme test. + table := []struct { + from, to, check interface{} + }{ + {&TestType1{}, &ExternalTestType1{}, &TestType1{}}, + {&ExternalTestType1{}, &TestType1{}, &ExternalTestType1{}}, + } + + f := fuzz.New().NilChance(.5).NumElements(0, 100) + c := NewConverter(DefaultNameFunc) + c.nameFunc = func(t reflect.Type) string { + // Hide the fact that we don't have separate packages for these things. + return map[reflect.Type]string{ + reflect.TypeOf(TestType1{}): "TestType1", + reflect.TypeOf(ExternalTestType1{}): "TestType1", + reflect.TypeOf(TestType2{}): "TestType2", + reflect.TypeOf(ExternalTestType2{}): "TestType2", + }[t] + } + c.Debug = testLogger(t) + + for i, item := range table { + for j := 0; j < *fuzzIters; j++ { + f.Fuzz(item.from) + err := c.Convert(item.from, item.to, 0, nil) + if err != nil { + t.Errorf("(%v, %v): unexpected error: %v", i, j, err) + continue + } + err = c.Convert(item.to, item.check, 0, nil) + if err != nil { + t.Errorf("(%v, %v): unexpected error: %v", i, j, err) + continue + } + if e, a := item.from, item.check; !reflect.DeepEqual(e, a) { + t.Errorf("(%v, %v): unexpected diff: %v", i, j, diff.ObjectDiff(e, a)) + } + } + } +} + +func TestConverter_MapElemAddr(t *testing.T) { + type Foo struct { + A map[int]int + } + type Bar struct { + A map[string]string + } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + err := c.RegisterConversionFunc( + func(in *int, out *string, s Scope) error { + *out = fmt.Sprintf("%v", *in) + return nil + }, + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + err = c.RegisterConversionFunc( + func(in *string, out *int, s Scope) error { + if str, err := strconv.Atoi(*in); err != nil { + return err + } else { + *out = str + return nil + } + }, + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + f := fuzz.New().NilChance(0).NumElements(3, 3) + first := Foo{} + second := Bar{} + f.Fuzz(&first) + err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + third := Foo{} + err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil) + if e, a := first, third; !reflect.DeepEqual(e, a) { + t.Errorf("Unexpected diff: %v", diff.ObjectDiff(e, a)) + } +} + +func TestConverter_tags(t *testing.T) { + type Foo struct { + A string `test:"foo"` + } + type Bar struct { + A string `test:"bar"` + } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + err := c.RegisterConversionFunc( + func(in *string, out *string, s Scope) error { + if e, a := "foo", s.SrcTag().Get("test"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := "bar", s.DestTag().Get("test"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + return nil + }, + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + err = c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestConverter_meta(t *testing.T) { + type Foo struct{ A string } + type Bar struct{ A string } + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + checks := 0 + err := c.RegisterConversionFunc( + func(in *Foo, out *Bar, s Scope) error { + if s.Meta() == nil { + t.Errorf("Meta did not get passed!") + } + checks++ + s.Convert(&in.A, &out.A, 0) + return nil + }, + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + err = c.RegisterConversionFunc( + func(in *string, out *string, s Scope) error { + if s.Meta() == nil { + t.Errorf("Meta did not get passed a second time!") + } + checks++ + return nil + }, + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if checks != 2 { + t.Errorf("Registered functions did not get called.") + } +} + +func TestConverter_flags(t *testing.T) { + type Foo struct{ A string } + type Bar struct{ A string } + table := []struct { + from, to interface{} + flags FieldMatchingFlags + shouldSucceed bool + }{ + // Check that DestFromSource allows extra fields only in source. + { + from: &struct{ A string }{}, + to: &struct{ A, B string }{}, + flags: DestFromSource, + shouldSucceed: false, + }, { + from: &struct{ A, B string }{}, + to: &struct{ A string }{}, + flags: DestFromSource, + shouldSucceed: true, + }, + + // Check that SourceToDest allows for extra fields only in dest. + { + from: &struct{ A string }{}, + to: &struct{ A, B string }{}, + flags: SourceToDest, + shouldSucceed: true, + }, { + from: &struct{ A, B string }{}, + to: &struct{ A string }{}, + flags: SourceToDest, + shouldSucceed: false, + }, + + // Check that IgnoreMissingFields makes the above failure cases pass. + { + from: &struct{ A string }{}, + to: &struct{ A, B string }{}, + flags: DestFromSource | IgnoreMissingFields, + shouldSucceed: true, + }, { + from: &struct{ A, B string }{}, + to: &struct{ A string }{}, + flags: SourceToDest | IgnoreMissingFields, + shouldSucceed: true, + }, + + // Check that the field type name must match unless + // AllowDifferentFieldTypeNames is specified. + { + from: &struct{ A, B Foo }{}, + to: &struct{ A Bar }{}, + flags: DestFromSource, + shouldSucceed: false, + }, { + from: &struct{ A Foo }{}, + to: &struct{ A, B Bar }{}, + flags: SourceToDest, + shouldSucceed: false, + }, { + from: &struct{ A, B Foo }{}, + to: &struct{ A Bar }{}, + flags: DestFromSource | AllowDifferentFieldTypeNames, + shouldSucceed: true, + }, { + from: &struct{ A Foo }{}, + to: &struct{ A, B Bar }{}, + flags: SourceToDest | AllowDifferentFieldTypeNames, + shouldSucceed: true, + }, + } + f := fuzz.New().NilChance(.5).NumElements(0, 100) + c := NewConverter(DefaultNameFunc) + c.Debug = testLogger(t) + + for i, item := range table { + for j := 0; j < *fuzzIters; j++ { + f.Fuzz(item.from) + err := c.Convert(item.from, item.to, item.flags, nil) + if item.shouldSucceed && err != nil { + t.Errorf("(%v, %v): unexpected error: %v", i, j, err) + continue + } + if !item.shouldSucceed && err == nil { + t.Errorf("(%v, %v): unexpected non-error", i, j) + continue + } + } + } +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go b/vendor/k8s.io/apimachinery/pkg/conversion/helper_test.go similarity index 54% rename from vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go rename to vendor/k8s.io/apimachinery/pkg/conversion/helper_test.go index cce2e603a..8c61a30a8 100644 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.defaults.go +++ b/vendor/k8s.io/apimachinery/pkg/conversion/helper_test.go @@ -1,7 +1,5 @@ -// +build !ignore_autogenerated - /* -Copyright The Kubernetes Authors. +Copyright 2014 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. @@ -16,17 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by defaulter-gen. DO NOT EDIT. +package conversion -package v1 +import "testing" -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) +func TestInvalidPtrValueKind(t *testing.T) { + var simple interface{} + switch obj := simple.(type) { + default: + _, err := EnforcePtr(obj) + if err == nil { + t.Errorf("Expected error on invalid kind") + } + } +} -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil +func TestEnforceNilPtr(t *testing.T) { + var nilPtr *struct{} + _, err := EnforcePtr(nilPtr) + if err == nil { + t.Errorf("Expected error on nil pointer") + } } diff --git a/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert_test.go b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert_test.go new file mode 100644 index 000000000..1eed5e1fe --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/conversion/queryparams/convert_test.go @@ -0,0 +1,219 @@ +/* +Copyright 2014 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 queryparams_test + +import ( + "net/url" + "reflect" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion/queryparams" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type namedString string +type namedBool bool + +type bar struct { + Float1 float32 `json:"float1"` + Float2 float64 `json:"float2"` + Int1 int64 `json:"int1,omitempty"` + Int2 int32 `json:"int2,omitempty"` + Int3 int16 `json:"int3,omitempty"` + Str1 string `json:"str1,omitempty"` + Ignored int + Ignored2 string +} + +func (obj *bar) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } + +type foo struct { + Str string `json:"str"` + Integer int `json:"integer,omitempty"` + Slice []string `json:"slice,omitempty"` + Boolean bool `json:"boolean,omitempty"` + NamedStr namedString `json:"namedStr,omitempty"` + NamedBool namedBool `json:"namedBool,omitempty"` + Foobar bar `json:"foobar,omitempty"` + Testmap map[string]string `json:"testmap,omitempty"` +} + +func (obj *foo) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } + +type baz struct { + Ptr *int `json:"ptr"` + Bptr *bool `json:"bptr,omitempty"` +} + +func (obj *baz) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } + +// childStructs tests some of the types we serialize to query params for log API calls +// notably, the nested time struct +type childStructs struct { + Container string `json:"container,omitempty"` + Follow bool `json:"follow,omitempty"` + Previous bool `json:"previous,omitempty"` + SinceSeconds *int64 `json:"sinceSeconds,omitempty"` + TailLines *int64 `json:"tailLines,omitempty"` + SinceTime *metav1.Time `json:"sinceTime,omitempty"` + EmptyTime *metav1.Time `json:"emptyTime"` + NonPointerTime metav1.Time `json:"nonPointerTime"` +} + +func (obj *childStructs) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } + +func validateResult(t *testing.T, input interface{}, actual, expected url.Values) { + local := url.Values{} + for k, v := range expected { + local[k] = v + } + for k, v := range actual { + if ev, ok := local[k]; !ok || !reflect.DeepEqual(ev, v) { + if !ok { + t.Errorf("%#v: actual value key %s not found in expected map", input, k) + } else { + t.Errorf("%#v: values don't match: actual: %#v, expected: %#v", input, v, ev) + } + } + delete(local, k) + } + if len(local) > 0 { + t.Errorf("%#v: expected map has keys that were not found in actual map: %#v", input, local) + } +} + +func TestConvert(t *testing.T) { + sinceSeconds := int64(123) + tailLines := int64(0) + sinceTime := metav1.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC) + + tests := []struct { + input interface{} + expected url.Values + }{ + { + input: &foo{ + Str: "hello", + }, + expected: url.Values{"str": {"hello"}}, + }, + { + input: &foo{ + Str: "test string", + Slice: []string{"one", "two", "three"}, + Integer: 234, + Boolean: true, + }, + expected: url.Values{"str": {"test string"}, "slice": {"one", "two", "three"}, "integer": {"234"}, "boolean": {"true"}}, + }, + { + input: &foo{ + Str: "named types", + NamedStr: "value1", + NamedBool: true, + }, + expected: url.Values{"str": {"named types"}, "namedStr": {"value1"}, "namedBool": {"true"}}, + }, + { + input: &foo{ + Str: "don't ignore embedded struct", + Foobar: bar{ + Float1: 5.0, + }, + }, + expected: url.Values{"str": {"don't ignore embedded struct"}, "float1": {"5"}, "float2": {"0"}}, + }, + { + // Ignore untagged fields + input: &bar{ + Float1: 23.5, + Float2: 100.7, + Int1: 1, + Int2: 2, + Int3: 3, + Ignored: 1, + Ignored2: "ignored", + }, + expected: url.Values{"float1": {"23.5"}, "float2": {"100.7"}, "int1": {"1"}, "int2": {"2"}, "int3": {"3"}}, + }, + { + // include fields that are not tagged omitempty + input: &foo{ + NamedStr: "named str", + }, + expected: url.Values{"str": {""}, "namedStr": {"named str"}}, + }, + { + input: &baz{ + Ptr: intp(5), + Bptr: boolp(true), + }, + expected: url.Values{"ptr": {"5"}, "bptr": {"true"}}, + }, + { + input: &baz{ + Bptr: boolp(true), + }, + expected: url.Values{"ptr": {""}, "bptr": {"true"}}, + }, + { + input: &baz{ + Ptr: intp(5), + }, + expected: url.Values{"ptr": {"5"}}, + }, + { + input: &childStructs{ + Container: "mycontainer", + Follow: true, + Previous: true, + SinceSeconds: &sinceSeconds, + TailLines: nil, + SinceTime: &sinceTime, // test a custom marshaller + EmptyTime: nil, // test a nil custom marshaller without omitempty + NonPointerTime: sinceTime, + }, + expected: url.Values{"container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"123"}, "sinceTime": {"2000-01-01T12:34:56Z"}, "emptyTime": {""}, "nonPointerTime": {"2000-01-01T12:34:56Z"}}, + }, + { + input: &childStructs{ + Container: "mycontainer", + Follow: true, + Previous: true, + SinceSeconds: &sinceSeconds, + TailLines: &tailLines, + SinceTime: nil, // test a nil custom marshaller with omitempty + NonPointerTime: sinceTime, + }, + expected: url.Values{"container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"123"}, "tailLines": {"0"}, "emptyTime": {""}, "nonPointerTime": {"2000-01-01T12:34:56Z"}}, + }, + } + + for _, test := range tests { + result, err := queryparams.Convert(test.input) + if err != nil { + t.Errorf("Unexpected error while converting %#v: %v", test.input, err) + } + validateResult(t, test.input, result, test.expected) + } +} + +func intp(n int) *int { return &n } + +func boolp(b bool) *bool { return &b } diff --git a/vendor/k8s.io/apimachinery/pkg/fields/fields_test.go b/vendor/k8s.io/apimachinery/pkg/fields/fields_test.go new file mode 100644 index 000000000..6965be687 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/fields/fields_test.go @@ -0,0 +1,57 @@ +/* +Copyright 2015 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 fields + +import ( + "testing" +) + +func matches(t *testing.T, ls Set, want string) { + if ls.String() != want { + t.Errorf("Expected '%s', but got '%s'", want, ls.String()) + } +} + +func TestSetString(t *testing.T) { + matches(t, Set{"x": "y"}, "x=y") + matches(t, Set{"foo": "bar"}, "foo=bar") + matches(t, Set{"foo": "bar", "baz": "qup"}, "baz=qup,foo=bar") +} + +func TestFieldHas(t *testing.T) { + fieldHasTests := []struct { + Ls Fields + Key string + Has bool + }{ + {Set{"x": "y"}, "x", true}, + {Set{"x": ""}, "x", true}, + {Set{"x": "y"}, "foo", false}, + } + for _, lh := range fieldHasTests { + if has := lh.Ls.Has(lh.Key); has != lh.Has { + t.Errorf("%#v.Has(%#v) => %v, expected %v", lh.Ls, lh.Key, has, lh.Has) + } + } +} + +func TestFieldGet(t *testing.T) { + ls := Set{"x": "y"} + if ls.Get("x") != "y" { + t.Errorf("Set.Get is broken") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/fields/selector_test.go b/vendor/k8s.io/apimachinery/pkg/fields/selector_test.go new file mode 100644 index 000000000..0aa66935c --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/fields/selector_test.go @@ -0,0 +1,397 @@ +/* +Copyright 2015 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 fields + +import ( + "reflect" + "testing" +) + +func TestSplitTerms(t *testing.T) { + testcases := map[string][]string{ + // Simple selectors + `a`: {`a`}, + `a=avalue`: {`a=avalue`}, + `a=avalue,b=bvalue`: {`a=avalue`, `b=bvalue`}, + `a=avalue,b==bvalue,c!=cvalue`: {`a=avalue`, `b==bvalue`, `c!=cvalue`}, + + // Empty terms + ``: nil, + `a=a,`: {`a=a`, ``}, + `,a=a`: {``, `a=a`}, + + // Escaped values + `k=\,,k2=v2`: {`k=\,`, `k2=v2`}, // escaped comma in value + `k=\\,k2=v2`: {`k=\\`, `k2=v2`}, // escaped backslash, unescaped comma + `k=\\\,,k2=v2`: {`k=\\\,`, `k2=v2`}, // escaped backslash and comma + `k=\a\b\`: {`k=\a\b\`}, // non-escape sequences + `k=\`: {`k=\`}, // orphan backslash + + // Multi-byte + `함=수,목=록`: {`함=수`, `목=록`}, + } + + for selector, expectedTerms := range testcases { + if terms := splitTerms(selector); !reflect.DeepEqual(terms, expectedTerms) { + t.Errorf("splitSelectors(`%s`): Expected\n%#v\ngot\n%#v", selector, expectedTerms, terms) + } + } +} + +func TestSplitTerm(t *testing.T) { + testcases := map[string]struct { + lhs string + op string + rhs string + ok bool + }{ + // Simple terms + `a=value`: {lhs: `a`, op: `=`, rhs: `value`, ok: true}, + `b==value`: {lhs: `b`, op: `==`, rhs: `value`, ok: true}, + `c!=value`: {lhs: `c`, op: `!=`, rhs: `value`, ok: true}, + + // Empty or invalid terms + ``: {lhs: ``, op: ``, rhs: ``, ok: false}, + `a`: {lhs: ``, op: ``, rhs: ``, ok: false}, + + // Escaped values + `k=\,`: {lhs: `k`, op: `=`, rhs: `\,`, ok: true}, + `k=\=`: {lhs: `k`, op: `=`, rhs: `\=`, ok: true}, + `k=\\\a\b\=\,\`: {lhs: `k`, op: `=`, rhs: `\\\a\b\=\,\`, ok: true}, + + // Multi-byte + `함=수`: {lhs: `함`, op: `=`, rhs: `수`, ok: true}, + } + + for term, expected := range testcases { + lhs, op, rhs, ok := splitTerm(term) + if lhs != expected.lhs || op != expected.op || rhs != expected.rhs || ok != expected.ok { + t.Errorf( + "splitTerm(`%s`): Expected\n%s,%s,%s,%v\nGot\n%s,%s,%s,%v", + term, + expected.lhs, expected.op, expected.rhs, expected.ok, + lhs, op, rhs, ok, + ) + } + } +} + +func TestEscapeValue(t *testing.T) { + // map values to their normalized escaped values + testcases := map[string]string{ + ``: ``, + `a`: `a`, + `=`: `\=`, + `,`: `\,`, + `\`: `\\`, + `\=\,\`: `\\\=\\\,\\`, + } + + for unescapedValue, escapedValue := range testcases { + actualEscaped := EscapeValue(unescapedValue) + if actualEscaped != escapedValue { + t.Errorf("EscapeValue(%s): expected %s, got %s", unescapedValue, escapedValue, actualEscaped) + } + + actualUnescaped, err := UnescapeValue(escapedValue) + if err != nil { + t.Errorf("UnescapeValue(%s): unexpected error %v", escapedValue, err) + } + if actualUnescaped != unescapedValue { + t.Errorf("UnescapeValue(%s): expected %s, got %s", escapedValue, unescapedValue, actualUnescaped) + } + } + + // test invalid escape sequences + invalidTestcases := []string{ + `\`, // orphan slash is invalid + `\\\`, // orphan slash is invalid + `\a`, // unrecognized escape sequence is invalid + } + for _, invalidValue := range invalidTestcases { + _, err := UnescapeValue(invalidValue) + if _, ok := err.(InvalidEscapeSequence); !ok || err == nil { + t.Errorf("UnescapeValue(%s): expected invalid escape sequence error, got %#v", invalidValue, err) + } + } +} + +func TestSelectorParse(t *testing.T) { + testGoodStrings := []string{ + "x=a,y=b,z=c", + "", + "x!=a,y=b", + `x=a||y\=b`, + `x=a\=\=b`, + } + testBadStrings := []string{ + "x=a||y=b", + "x==a==b", + "x=a,b", + "x in (a)", + "x in (a,b,c)", + "x", + } + for _, test := range testGoodStrings { + lq, err := ParseSelector(test) + if err != nil { + t.Errorf("%v: error %v (%#v)\n", test, err, err) + } + if test != lq.String() { + t.Errorf("%v restring gave: %v\n", test, lq.String()) + } + } + for _, test := range testBadStrings { + _, err := ParseSelector(test) + if err == nil { + t.Errorf("%v: did not get expected error\n", test) + } + } +} + +func TestDeterministicParse(t *testing.T) { + s1, err := ParseSelector("x=a,a=x") + s2, err2 := ParseSelector("a=x,x=a") + if err != nil || err2 != nil { + t.Errorf("Unexpected parse error") + } + if s1.String() != s2.String() { + t.Errorf("Non-deterministic parse") + } +} + +func expectMatch(t *testing.T, selector string, ls Set) { + lq, err := ParseSelector(selector) + if err != nil { + t.Errorf("Unable to parse %v as a selector\n", selector) + return + } + if !lq.Matches(ls) { + t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) + } +} + +func expectNoMatch(t *testing.T, selector string, ls Set) { + lq, err := ParseSelector(selector) + if err != nil { + t.Errorf("Unable to parse %v as a selector\n", selector) + return + } + if lq.Matches(ls) { + t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) + } +} + +func TestEverything(t *testing.T) { + if !Everything().Matches(Set{"x": "y"}) { + t.Errorf("Nil selector didn't match") + } + if !Everything().Empty() { + t.Errorf("Everything was not empty") + } +} + +func TestSelectorMatches(t *testing.T) { + expectMatch(t, "", Set{"x": "y"}) + expectMatch(t, "x=y", Set{"x": "y"}) + expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"}) + expectMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "a"}) + expectMatch(t, "notin=in", Set{"notin": "in"}) // in and notin in exactMatch + expectNoMatch(t, "x=y", Set{"x": "z"}) + expectNoMatch(t, "x=y,z=w", Set{"x": "w", "z": "w"}) + expectNoMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "w"}) + + fieldset := Set{ + "foo": "bar", + "baz": "blah", + "complex": `=value\,\`, + } + expectMatch(t, "foo=bar", fieldset) + expectMatch(t, "baz=blah", fieldset) + expectMatch(t, "foo=bar,baz=blah", fieldset) + expectMatch(t, `foo=bar,baz=blah,complex=\=value\\\,\\`, fieldset) + expectNoMatch(t, "foo=blah", fieldset) + expectNoMatch(t, "baz=bar", fieldset) + expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", fieldset) +} + +func TestOneTermEqualSelector(t *testing.T) { + if !OneTermEqualSelector("x", "y").Matches(Set{"x": "y"}) { + t.Errorf("No match when match expected.") + } + if OneTermEqualSelector("x", "y").Matches(Set{"x": "z"}) { + t.Errorf("Match when none expected.") + } +} + +func expectMatchDirect(t *testing.T, selector, ls Set) { + if !SelectorFromSet(selector).Matches(ls) { + t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) + } +} + +func expectNoMatchDirect(t *testing.T, selector, ls Set) { + if SelectorFromSet(selector).Matches(ls) { + t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) + } +} + +func TestSetMatches(t *testing.T) { + labelset := Set{ + "foo": "bar", + "baz": "blah", + } + expectMatchDirect(t, Set{}, labelset) + expectMatchDirect(t, Set{"foo": "bar"}, labelset) + expectMatchDirect(t, Set{"baz": "blah"}, labelset) + expectMatchDirect(t, Set{"foo": "bar", "baz": "blah"}, labelset) + expectNoMatchDirect(t, Set{"foo": "=blah"}, labelset) + expectNoMatchDirect(t, Set{"baz": "=bar"}, labelset) + expectNoMatchDirect(t, Set{"foo": "=bar", "foobar": "bar", "baz": "blah"}, labelset) +} + +func TestNilMapIsValid(t *testing.T) { + selector := Set(nil).AsSelector() + if selector == nil { + t.Errorf("Selector for nil set should be Everything") + } + if !selector.Empty() { + t.Errorf("Selector for nil set should be Empty") + } +} + +func TestSetIsEmpty(t *testing.T) { + if !(Set{}).AsSelector().Empty() { + t.Errorf("Empty set should be empty") + } + if !(andTerm(nil)).Empty() { + t.Errorf("Nil andTerm should be empty") + } + if (&hasTerm{}).Empty() { + t.Errorf("hasTerm should not be empty") + } + if (&notHasTerm{}).Empty() { + t.Errorf("notHasTerm should not be empty") + } + if !(andTerm{andTerm{}}).Empty() { + t.Errorf("Nested andTerm should be empty") + } + if (andTerm{&hasTerm{"a", "b"}}).Empty() { + t.Errorf("Nested andTerm should not be empty") + } +} + +func TestRequiresExactMatch(t *testing.T) { + testCases := map[string]struct { + S Selector + Label string + Value string + Found bool + }{ + "empty set": {Set{}.AsSelector(), "test", "", false}, + "empty hasTerm": {&hasTerm{}, "test", "", false}, + "skipped hasTerm": {&hasTerm{"a", "b"}, "test", "", false}, + "valid hasTerm": {&hasTerm{"test", "b"}, "test", "b", true}, + "valid hasTerm no value": {&hasTerm{"test", ""}, "test", "", true}, + "valid notHasTerm": {&notHasTerm{"test", "b"}, "test", "", false}, + "valid notHasTerm no value": {&notHasTerm{"test", ""}, "test", "", false}, + "nil andTerm": {andTerm(nil), "test", "", false}, + "empty andTerm": {andTerm{}, "test", "", false}, + "nested andTerm": {andTerm{andTerm{}}, "test", "", false}, + "nested andTerm matches": {andTerm{&hasTerm{"test", "b"}}, "test", "b", true}, + "andTerm with non-match": {andTerm{&hasTerm{}, &hasTerm{"test", "b"}}, "test", "b", true}, + } + for k, v := range testCases { + value, found := v.S.RequiresExactMatch(v.Label) + if value != v.Value { + t.Errorf("%s: expected value %s, got %s", k, v.Value, value) + } + if found != v.Found { + t.Errorf("%s: expected found %t, got %t", k, v.Found, found) + } + } +} + +func TestTransform(t *testing.T) { + testCases := []struct { + name string + selector string + transform func(field, value string) (string, string, error) + result string + isEmpty bool + }{ + { + name: "empty selector", + selector: "", + transform: func(field, value string) (string, string, error) { return field, value, nil }, + result: "", + isEmpty: true, + }, + { + name: "no-op transform", + selector: "a=b,c=d", + transform: func(field, value string) (string, string, error) { return field, value, nil }, + result: "a=b,c=d", + isEmpty: false, + }, + { + name: "transform one field", + selector: "a=b,c=d", + transform: func(field, value string) (string, string, error) { + if field == "a" { + return "e", "f", nil + } + return field, value, nil + }, + result: "e=f,c=d", + isEmpty: false, + }, + { + name: "remove field to make empty", + selector: "a=b", + transform: func(field, value string) (string, string, error) { return "", "", nil }, + result: "", + isEmpty: true, + }, + { + name: "remove only one field", + selector: "a=b,c=d,e=f", + transform: func(field, value string) (string, string, error) { + if field == "c" { + return "", "", nil + } + return field, value, nil + }, + result: "a=b,e=f", + isEmpty: false, + }, + } + + for i, tc := range testCases { + result, err := ParseAndTransformSelector(tc.selector, tc.transform) + if err != nil { + t.Errorf("[%d] unexpected error during Transform: %v", i, err) + } + if result.Empty() != tc.isEmpty { + t.Errorf("[%d] expected empty: %t, got: %t", i, tc.isEmpty, result.Empty()) + } + if result.String() != tc.result { + t.Errorf("[%d] unexpected result: %s", i, result.String()) + } + } + +} diff --git a/vendor/k8s.io/apimachinery/pkg/labels/labels_test.go b/vendor/k8s.io/apimachinery/pkg/labels/labels_test.go new file mode 100644 index 000000000..2d4d761bc --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/labels/labels_test.go @@ -0,0 +1,231 @@ +/* +Copyright 2014 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 labels + +import ( + "testing" +) + +func matches(t *testing.T, ls Set, want string) { + if ls.String() != want { + t.Errorf("Expected '%s', but got '%s'", want, ls.String()) + } +} + +func TestSetString(t *testing.T) { + matches(t, Set{"x": "y"}, "x=y") + matches(t, Set{"foo": "bar"}, "foo=bar") + matches(t, Set{"foo": "bar", "baz": "qup"}, "baz=qup,foo=bar") + + // TODO: Make our label representation robust enough to handle labels + // with ",=!" characters in their names. +} + +func TestLabelHas(t *testing.T) { + labelHasTests := []struct { + Ls Labels + Key string + Has bool + }{ + {Set{"x": "y"}, "x", true}, + {Set{"x": ""}, "x", true}, + {Set{"x": "y"}, "foo", false}, + } + for _, lh := range labelHasTests { + if has := lh.Ls.Has(lh.Key); has != lh.Has { + t.Errorf("%#v.Has(%#v) => %v, expected %v", lh.Ls, lh.Key, has, lh.Has) + } + } +} + +func TestLabelGet(t *testing.T) { + ls := Set{"x": "y"} + if ls.Get("x") != "y" { + t.Errorf("Set.Get is broken") + } +} + +func TestLabelConflict(t *testing.T) { + tests := []struct { + labels1 map[string]string + labels2 map[string]string + conflict bool + }{ + { + labels1: map[string]string{}, + labels2: map[string]string{}, + conflict: false, + }, + { + labels1: map[string]string{"env": "test"}, + labels2: map[string]string{"infra": "true"}, + conflict: false, + }, + { + labels1: map[string]string{"env": "test"}, + labels2: map[string]string{"infra": "true", "env": "test"}, + conflict: false, + }, + { + labels1: map[string]string{"env": "test"}, + labels2: map[string]string{"env": "dev"}, + conflict: true, + }, + { + labels1: map[string]string{"env": "test", "infra": "false"}, + labels2: map[string]string{"infra": "true", "color": "blue"}, + conflict: true, + }, + } + for _, test := range tests { + conflict := Conflicts(Set(test.labels1), Set(test.labels2)) + if conflict != test.conflict { + t.Errorf("expected: %v but got: %v", test.conflict, conflict) + } + } +} + +func TestLabelMerge(t *testing.T) { + tests := []struct { + labels1 map[string]string + labels2 map[string]string + mergedLabels map[string]string + }{ + { + labels1: map[string]string{}, + labels2: map[string]string{}, + mergedLabels: map[string]string{}, + }, + { + labels1: map[string]string{"infra": "true"}, + labels2: map[string]string{}, + mergedLabels: map[string]string{"infra": "true"}, + }, + { + labels1: map[string]string{"infra": "true"}, + labels2: map[string]string{"env": "test", "color": "blue"}, + mergedLabels: map[string]string{"infra": "true", "env": "test", "color": "blue"}, + }, + } + for _, test := range tests { + mergedLabels := Merge(Set(test.labels1), Set(test.labels2)) + if !Equals(mergedLabels, test.mergedLabels) { + t.Errorf("expected: %v but got: %v", test.mergedLabels, mergedLabels) + } + } +} + +func TestLabelSelectorParse(t *testing.T) { + tests := []struct { + selector string + labels map[string]string + valid bool + }{ + { + selector: "", + labels: map[string]string{}, + valid: true, + }, + { + selector: "x=a", + labels: map[string]string{"x": "a"}, + valid: true, + }, + { + selector: "x=a,y=b,z=c", + labels: map[string]string{"x": "a", "y": "b", "z": "c"}, + valid: true, + }, + { + selector: " x = a , y = b , z = c ", + labels: map[string]string{"x": "a", "y": "b", "z": "c"}, + valid: true, + }, + { + selector: "color=green,env=test,service=front", + labels: map[string]string{"color": "green", "env": "test", "service": "front"}, + valid: true, + }, + { + selector: "color=green, env=test, service=front", + labels: map[string]string{"color": "green", "env": "test", "service": "front"}, + valid: true, + }, + { + selector: ",", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x,y", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x=$y", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x!=y", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x==y", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x=a||y=b", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x in (y)", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x notin (y)", + labels: map[string]string{}, + valid: false, + }, + { + selector: "x y", + labels: map[string]string{}, + valid: false, + }, + } + for _, test := range tests { + labels, err := ConvertSelectorToLabelsMap(test.selector) + if test.valid && err != nil { + t.Errorf("selector: %s, expected no error but got: %s", test.selector, err) + } else if !test.valid && err == nil { + t.Errorf("selector: %s, expected an error", test.selector) + } + + if !Equals(Set(labels), test.labels) { + t.Errorf("expected: %s but got: %s", test.labels, labels) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/labels/selector_test.go b/vendor/k8s.io/apimachinery/pkg/labels/selector_test.go new file mode 100644 index 000000000..a2702989b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/labels/selector_test.go @@ -0,0 +1,619 @@ +/* +Copyright 2014 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 labels + +import ( + "reflect" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/sets" +) + +func TestSelectorParse(t *testing.T) { + testGoodStrings := []string{ + "x=a,y=b,z=c", + "", + "x!=a,y=b", + "x=", + "x= ", + "x=,z= ", + "x= ,z= ", + "!x", + "x>1", + "x>1,z<5", + } + testBadStrings := []string{ + "x=a||y=b", + "x==a==b", + "!x=a", + "x<a", + } + for _, test := range testGoodStrings { + lq, err := Parse(test) + if err != nil { + t.Errorf("%v: error %v (%#v)\n", test, err, err) + } + if strings.Replace(test, " ", "", -1) != lq.String() { + t.Errorf("%v restring gave: %v\n", test, lq.String()) + } + } + for _, test := range testBadStrings { + _, err := Parse(test) + if err == nil { + t.Errorf("%v: did not get expected error\n", test) + } + } +} + +func TestDeterministicParse(t *testing.T) { + s1, err := Parse("x=a,a=x") + s2, err2 := Parse("a=x,x=a") + if err != nil || err2 != nil { + t.Errorf("Unexpected parse error") + } + if s1.String() != s2.String() { + t.Errorf("Non-deterministic parse") + } +} + +func expectMatch(t *testing.T, selector string, ls Set) { + lq, err := Parse(selector) + if err != nil { + t.Errorf("Unable to parse %v as a selector\n", selector) + return + } + if !lq.Matches(ls) { + t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) + } +} + +func expectNoMatch(t *testing.T, selector string, ls Set) { + lq, err := Parse(selector) + if err != nil { + t.Errorf("Unable to parse %v as a selector\n", selector) + return + } + if lq.Matches(ls) { + t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) + } +} + +func TestEverything(t *testing.T) { + if !Everything().Matches(Set{"x": "y"}) { + t.Errorf("Nil selector didn't match") + } + if !Everything().Empty() { + t.Errorf("Everything was not empty") + } +} + +func TestSelectorMatches(t *testing.T) { + expectMatch(t, "", Set{"x": "y"}) + expectMatch(t, "x=y", Set{"x": "y"}) + expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"}) + expectMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "a"}) + expectMatch(t, "notin=in", Set{"notin": "in"}) // in and notin in exactMatch + expectMatch(t, "x", Set{"x": "z"}) + expectMatch(t, "!x", Set{"y": "z"}) + expectMatch(t, "x>1", Set{"x": "2"}) + expectMatch(t, "x<1", Set{"x": "0"}) + expectNoMatch(t, "x=z", Set{}) + expectNoMatch(t, "x=y", Set{"x": "z"}) + expectNoMatch(t, "x=y,z=w", Set{"x": "w", "z": "w"}) + expectNoMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "w"}) + expectNoMatch(t, "x", Set{"y": "z"}) + expectNoMatch(t, "!x", Set{"x": "z"}) + expectNoMatch(t, "x>1", Set{"x": "0"}) + expectNoMatch(t, "x<1", Set{"x": "2"}) + + labelset := Set{ + "foo": "bar", + "baz": "blah", + } + expectMatch(t, "foo=bar", labelset) + expectMatch(t, "baz=blah", labelset) + expectMatch(t, "foo=bar,baz=blah", labelset) + expectNoMatch(t, "foo=blah", labelset) + expectNoMatch(t, "baz=bar", labelset) + expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", labelset) +} + +func expectMatchDirect(t *testing.T, selector, ls Set) { + if !SelectorFromSet(selector).Matches(ls) { + t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) + } +} + +func expectNoMatchDirect(t *testing.T, selector, ls Set) { + if SelectorFromSet(selector).Matches(ls) { + t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) + } +} + +func TestSetMatches(t *testing.T) { + labelset := Set{ + "foo": "bar", + "baz": "blah", + } + expectMatchDirect(t, Set{}, labelset) + expectMatchDirect(t, Set{"foo": "bar"}, labelset) + expectMatchDirect(t, Set{"baz": "blah"}, labelset) + expectMatchDirect(t, Set{"foo": "bar", "baz": "blah"}, labelset) + + //TODO: bad values not handled for the moment in SelectorFromSet + //expectNoMatchDirect(t, Set{"foo": "=blah"}, labelset) + //expectNoMatchDirect(t, Set{"baz": "=bar"}, labelset) + //expectNoMatchDirect(t, Set{"foo": "=bar", "foobar": "bar", "baz": "blah"}, labelset) +} + +func TestNilMapIsValid(t *testing.T) { + selector := Set(nil).AsSelector() + if selector == nil { + t.Errorf("Selector for nil set should be Everything") + } + if !selector.Empty() { + t.Errorf("Selector for nil set should be Empty") + } +} + +func TestSetIsEmpty(t *testing.T) { + if !(Set{}).AsSelector().Empty() { + t.Errorf("Empty set should be empty") + } + if !(NewSelector()).Empty() { + t.Errorf("Nil Selector should be empty") + } +} + +func TestLexer(t *testing.T) { + testcases := []struct { + s string + t Token + }{ + {"", EndOfStringToken}, + {",", CommaToken}, + {"notin", NotInToken}, + {"in", InToken}, + {"=", EqualsToken}, + {"==", DoubleEqualsToken}, + {">", GreaterThanToken}, + {"<", LessThanToken}, + //Note that Lex returns the longest valid token found + {"!", DoesNotExistToken}, + {"!=", NotEqualsToken}, + {"(", OpenParToken}, + {")", ClosedParToken}, + //Non-"special" characters are considered part of an identifier + {"~", IdentifierToken}, + {"||", IdentifierToken}, + } + for _, v := range testcases { + l := &Lexer{s: v.s, pos: 0} + token, lit := l.Lex() + if token != v.t { + t.Errorf("Got %d it should be %d for '%s'", token, v.t, v.s) + } + if v.t != ErrorToken && lit != v.s { + t.Errorf("Got '%s' it should be '%s'", lit, v.s) + } + } +} + +func min(l, r int) (m int) { + m = r + if l < r { + m = l + } + return m +} + +func TestLexerSequence(t *testing.T) { + testcases := []struct { + s string + t []Token + }{ + {"key in ( value )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, ClosedParToken}}, + {"key notin ( value )", []Token{IdentifierToken, NotInToken, OpenParToken, IdentifierToken, ClosedParToken}}, + {"key in ( value1, value2 )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, CommaToken, IdentifierToken, ClosedParToken}}, + {"key", []Token{IdentifierToken}}, + {"!key", []Token{DoesNotExistToken, IdentifierToken}}, + {"()", []Token{OpenParToken, ClosedParToken}}, + {"x in (),y", []Token{IdentifierToken, InToken, OpenParToken, ClosedParToken, CommaToken, IdentifierToken}}, + {"== != (), = notin", []Token{DoubleEqualsToken, NotEqualsToken, OpenParToken, ClosedParToken, CommaToken, EqualsToken, NotInToken}}, + {"key>2", []Token{IdentifierToken, GreaterThanToken, IdentifierToken}}, + {"key<1", []Token{IdentifierToken, LessThanToken, IdentifierToken}}, + } + for _, v := range testcases { + var literals []string + var tokens []Token + l := &Lexer{s: v.s, pos: 0} + for { + token, lit := l.Lex() + if token == EndOfStringToken { + break + } + tokens = append(tokens, token) + literals = append(literals, lit) + } + if len(tokens) != len(v.t) { + t.Errorf("Bad number of tokens for '%s %d, %d", v.s, len(tokens), len(v.t)) + } + for i := 0; i < min(len(tokens), len(v.t)); i++ { + if tokens[i] != v.t[i] { + t.Errorf("Test '%s': Mismatching in token type found '%v' it should be '%v'", v.s, tokens[i], v.t[i]) + } + } + } +} +func TestParserLookahead(t *testing.T) { + testcases := []struct { + s string + t []Token + }{ + {"key in ( value )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, ClosedParToken, EndOfStringToken}}, + {"key notin ( value )", []Token{IdentifierToken, NotInToken, OpenParToken, IdentifierToken, ClosedParToken, EndOfStringToken}}, + {"key in ( value1, value2 )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, CommaToken, IdentifierToken, ClosedParToken, EndOfStringToken}}, + {"key", []Token{IdentifierToken, EndOfStringToken}}, + {"!key", []Token{DoesNotExistToken, IdentifierToken, EndOfStringToken}}, + {"()", []Token{OpenParToken, ClosedParToken, EndOfStringToken}}, + {"", []Token{EndOfStringToken}}, + {"x in (),y", []Token{IdentifierToken, InToken, OpenParToken, ClosedParToken, CommaToken, IdentifierToken, EndOfStringToken}}, + {"== != (), = notin", []Token{DoubleEqualsToken, NotEqualsToken, OpenParToken, ClosedParToken, CommaToken, EqualsToken, NotInToken, EndOfStringToken}}, + {"key>2", []Token{IdentifierToken, GreaterThanToken, IdentifierToken, EndOfStringToken}}, + {"key<1", []Token{IdentifierToken, LessThanToken, IdentifierToken, EndOfStringToken}}, + } + for _, v := range testcases { + p := &Parser{l: &Lexer{s: v.s, pos: 0}, position: 0} + p.scan() + if len(p.scannedItems) != len(v.t) { + t.Errorf("Expected %d items found %d", len(v.t), len(p.scannedItems)) + } + for { + token, lit := p.lookahead(KeyAndOperator) + + token2, lit2 := p.consume(KeyAndOperator) + if token == EndOfStringToken { + break + } + if token != token2 || lit != lit2 { + t.Errorf("Bad values") + } + } + } +} + +func TestRequirementConstructor(t *testing.T) { + requirementConstructorTests := []struct { + Key string + Op selection.Operator + Vals sets.String + Success bool + }{ + {"x", selection.In, nil, false}, + {"x", selection.NotIn, sets.NewString(), false}, + {"x", selection.In, sets.NewString("foo"), true}, + {"x", selection.NotIn, sets.NewString("foo"), true}, + {"x", selection.Exists, nil, true}, + {"x", selection.DoesNotExist, nil, true}, + {"1foo", selection.In, sets.NewString("bar"), true}, + {"1234", selection.In, sets.NewString("bar"), true}, + {"y", selection.GreaterThan, sets.NewString("1"), true}, + {"z", selection.LessThan, sets.NewString("6"), true}, + {"foo", selection.GreaterThan, sets.NewString("bar"), false}, + {"barz", selection.LessThan, sets.NewString("blah"), false}, + {strings.Repeat("a", 254), selection.Exists, nil, false}, //breaks DNS rule that len(key) <= 253 + } + for _, rc := range requirementConstructorTests { + if _, err := NewRequirement(rc.Key, rc.Op, rc.Vals.List()); err == nil && !rc.Success { + t.Errorf("expected error with key:%#v op:%v vals:%v, got no error", rc.Key, rc.Op, rc.Vals) + } else if err != nil && rc.Success { + t.Errorf("expected no error with key:%#v op:%v vals:%v, got:%v", rc.Key, rc.Op, rc.Vals, err) + } + } +} + +func TestToString(t *testing.T) { + var req Requirement + toStringTests := []struct { + In *internalSelector + Out string + Valid bool + }{ + + {&internalSelector{ + getRequirement("x", selection.In, sets.NewString("abc", "def"), t), + getRequirement("y", selection.NotIn, sets.NewString("jkl"), t), + getRequirement("z", selection.Exists, nil, t)}, + "x in (abc,def),y notin (jkl),z", true}, + {&internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t), + getRequirement("y", selection.NotEquals, sets.NewString("jkl"), t), + getRequirement("z", selection.DoesNotExist, nil, t)}, + "x notin (abc,def),y!=jkl,!z", true}, + {&internalSelector{ + getRequirement("x", selection.In, sets.NewString("abc", "def"), t), + req}, // adding empty req for the trailing ',' + "x in (abc,def),", false}, + {&internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString("abc"), t), + getRequirement("y", selection.In, sets.NewString("jkl", "mno"), t), + getRequirement("z", selection.NotIn, sets.NewString(""), t)}, + "x notin (abc),y in (jkl,mno),z notin ()", true}, + {&internalSelector{ + getRequirement("x", selection.Equals, sets.NewString("abc"), t), + getRequirement("y", selection.DoubleEquals, sets.NewString("jkl"), t), + getRequirement("z", selection.NotEquals, sets.NewString("a"), t), + getRequirement("z", selection.Exists, nil, t)}, + "x=abc,y==jkl,z!=a,z", true}, + {&internalSelector{ + getRequirement("x", selection.GreaterThan, sets.NewString("2"), t), + getRequirement("y", selection.LessThan, sets.NewString("8"), t), + getRequirement("z", selection.Exists, nil, t)}, + "x>2,y<8,z", true}, + } + for _, ts := range toStringTests { + if out := ts.In.String(); out == "" && ts.Valid { + t.Errorf("%#v.String() => '%v' expected no error", ts.In, out) + } else if out != ts.Out { + t.Errorf("%#v.String() => '%v' want '%v'", ts.In, out, ts.Out) + } + } +} + +func TestRequirementSelectorMatching(t *testing.T) { + var req Requirement + labelSelectorMatchingTests := []struct { + Set Set + Sel Selector + Match bool + }{ + {Set{"x": "foo", "y": "baz"}, &internalSelector{ + req, + }, false}, + {Set{"x": "foo", "y": "baz"}, &internalSelector{ + getRequirement("x", selection.In, sets.NewString("foo"), t), + getRequirement("y", selection.NotIn, sets.NewString("alpha"), t), + }, true}, + {Set{"x": "foo", "y": "baz"}, &internalSelector{ + getRequirement("x", selection.In, sets.NewString("foo"), t), + getRequirement("y", selection.In, sets.NewString("alpha"), t), + }, false}, + {Set{"y": ""}, &internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString(""), t), + getRequirement("y", selection.Exists, nil, t), + }, true}, + {Set{"y": ""}, &internalSelector{ + getRequirement("x", selection.DoesNotExist, nil, t), + getRequirement("y", selection.Exists, nil, t), + }, true}, + {Set{"y": ""}, &internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString(""), t), + getRequirement("y", selection.DoesNotExist, nil, t), + }, false}, + {Set{"y": "baz"}, &internalSelector{ + getRequirement("x", selection.In, sets.NewString(""), t), + }, false}, + {Set{"z": "2"}, &internalSelector{ + getRequirement("z", selection.GreaterThan, sets.NewString("1"), t), + }, true}, + {Set{"z": "v2"}, &internalSelector{ + getRequirement("z", selection.GreaterThan, sets.NewString("1"), t), + }, false}, + } + for _, lsm := range labelSelectorMatchingTests { + if match := lsm.Sel.Matches(lsm.Set); match != lsm.Match { + t.Errorf("%+v.Matches(%#v) => %v, want %v", lsm.Sel, lsm.Set, match, lsm.Match) + } + } +} + +func TestSetSelectorParser(t *testing.T) { + setSelectorParserTests := []struct { + In string + Out Selector + Match bool + Valid bool + }{ + {"", NewSelector(), true, true}, + {"\rx", internalSelector{ + getRequirement("x", selection.Exists, nil, t), + }, true, true}, + {"this-is-a-dns.domain.com/key-with-dash", internalSelector{ + getRequirement("this-is-a-dns.domain.com/key-with-dash", selection.Exists, nil, t), + }, true, true}, + {"this-is-another-dns.domain.com/key-with-dash in (so,what)", internalSelector{ + getRequirement("this-is-another-dns.domain.com/key-with-dash", selection.In, sets.NewString("so", "what"), t), + }, true, true}, + {"0.1.2.domain/99 notin (10.10.100.1, tick.tack.clock)", internalSelector{ + getRequirement("0.1.2.domain/99", selection.NotIn, sets.NewString("10.10.100.1", "tick.tack.clock"), t), + }, true, true}, + {"foo in (abc)", internalSelector{ + getRequirement("foo", selection.In, sets.NewString("abc"), t), + }, true, true}, + {"x notin\n (abc)", internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString("abc"), t), + }, true, true}, + {"x notin \t (abc,def)", internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t), + }, true, true}, + {"x in (abc,def)", internalSelector{ + getRequirement("x", selection.In, sets.NewString("abc", "def"), t), + }, true, true}, + {"x in (abc,)", internalSelector{ + getRequirement("x", selection.In, sets.NewString("abc", ""), t), + }, true, true}, + {"x in ()", internalSelector{ + getRequirement("x", selection.In, sets.NewString(""), t), + }, true, true}, + {"x notin (abc,,def),bar,z in (),w", internalSelector{ + getRequirement("bar", selection.Exists, nil, t), + getRequirement("w", selection.Exists, nil, t), + getRequirement("x", selection.NotIn, sets.NewString("abc", "", "def"), t), + getRequirement("z", selection.In, sets.NewString(""), t), + }, true, true}, + {"x,y in (a)", internalSelector{ + getRequirement("y", selection.In, sets.NewString("a"), t), + getRequirement("x", selection.Exists, nil, t), + }, false, true}, + {"x=a", internalSelector{ + getRequirement("x", selection.Equals, sets.NewString("a"), t), + }, true, true}, + {"x>1", internalSelector{ + getRequirement("x", selection.GreaterThan, sets.NewString("1"), t), + }, true, true}, + {"x<7", internalSelector{ + getRequirement("x", selection.LessThan, sets.NewString("7"), t), + }, true, true}, + {"x=a,y!=b", internalSelector{ + getRequirement("x", selection.Equals, sets.NewString("a"), t), + getRequirement("y", selection.NotEquals, sets.NewString("b"), t), + }, true, true}, + {"x=a,y!=b,z in (h,i,j)", internalSelector{ + getRequirement("x", selection.Equals, sets.NewString("a"), t), + getRequirement("y", selection.NotEquals, sets.NewString("b"), t), + getRequirement("z", selection.In, sets.NewString("h", "i", "j"), t), + }, true, true}, + {"x=a||y=b", internalSelector{}, false, false}, + {"x,,y", nil, true, false}, + {",x,y", nil, true, false}, + {"x nott in (y)", nil, true, false}, + {"x notin ( )", internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString(""), t), + }, true, true}, + {"x notin (, a)", internalSelector{ + getRequirement("x", selection.NotIn, sets.NewString("", "a"), t), + }, true, true}, + {"a in (xyz),", nil, true, false}, + {"a in (xyz)b notin ()", nil, true, false}, + {"a ", internalSelector{ + getRequirement("a", selection.Exists, nil, t), + }, true, true}, + {"a in (x,y,notin, z,in)", internalSelector{ + getRequirement("a", selection.In, sets.NewString("in", "notin", "x", "y", "z"), t), + }, true, true}, // operator 'in' inside list of identifiers + {"a in (xyz abc)", nil, false, false}, // no comma + {"a notin(", nil, true, false}, // bad formed + {"a (", nil, false, false}, // cpar + {"(", nil, false, false}, // opar + } + + for _, ssp := range setSelectorParserTests { + if sel, err := Parse(ssp.In); err != nil && ssp.Valid { + t.Errorf("Parse(%s) => %v expected no error", ssp.In, err) + } else if err == nil && !ssp.Valid { + t.Errorf("Parse(%s) => %+v expected error", ssp.In, sel) + } else if ssp.Match && !reflect.DeepEqual(sel, ssp.Out) { + t.Errorf("Parse(%s) => parse output '%#v' doesn't match '%#v' expected match", ssp.In, sel, ssp.Out) + } + } +} + +func getRequirement(key string, op selection.Operator, vals sets.String, t *testing.T) Requirement { + req, err := NewRequirement(key, op, vals.List()) + if err != nil { + t.Errorf("NewRequirement(%v, %v, %v) resulted in error:%v", key, op, vals, err) + return Requirement{} + } + return *req +} + +func TestAdd(t *testing.T) { + testCases := []struct { + name string + sel Selector + key string + operator selection.Operator + values []string + refSelector Selector + }{ + { + "keyInOperator", + internalSelector{}, + "key", + selection.In, + []string{"value"}, + internalSelector{Requirement{"key", selection.In, []string{"value"}}}, + }, + { + "keyEqualsOperator", + internalSelector{Requirement{"key", selection.In, []string{"value"}}}, + "key2", + selection.Equals, + []string{"value2"}, + internalSelector{ + Requirement{"key", selection.In, []string{"value"}}, + Requirement{"key2", selection.Equals, []string{"value2"}}, + }, + }, + } + for _, ts := range testCases { + req, err := NewRequirement(ts.key, ts.operator, ts.values) + if err != nil { + t.Errorf("%s - Unable to create labels.Requirement", ts.name) + } + ts.sel = ts.sel.Add(*req) + if !reflect.DeepEqual(ts.sel, ts.refSelector) { + t.Errorf("%s - Expected %v found %v", ts.name, ts.refSelector, ts.sel) + } + } +} + +func TestSafeSort(t *testing.T) { + tests := []struct { + name string + in []string + inCopy []string + want []string + }{ + { + name: "nil strings", + in: nil, + inCopy: nil, + want: nil, + }, + { + name: "ordered strings", + in: []string{"bar", "foo"}, + inCopy: []string{"bar", "foo"}, + want: []string{"bar", "foo"}, + }, + { + name: "unordered strings", + in: []string{"foo", "bar"}, + inCopy: []string{"foo", "bar"}, + want: []string{"bar", "foo"}, + }, + { + name: "duplicated strings", + in: []string{"foo", "bar", "foo", "bar"}, + inCopy: []string{"foo", "bar", "foo", "bar"}, + want: []string{"bar", "bar", "foo", "foo"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := safeSort(tt.in); !reflect.DeepEqual(got, tt.want) { + t.Errorf("safeSort() = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(tt.in, tt.inCopy) { + t.Errorf("after safeSort(), input = %v, want %v", tt.in, tt.inCopy) + } + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/conversion_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/conversion_test.go new file mode 100644 index 000000000..33670415b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/conversion_test.go @@ -0,0 +1,115 @@ +/* +Copyright 2014 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 runtime_test + +import ( + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + runtimetesting "k8s.io/apimachinery/pkg/runtime/testing" +) + +func TestStringMapConversion(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "external"} + + scheme := runtime.NewScheme() + scheme.Log(t) + scheme.AddKnownTypeWithName(internalGV.WithKind("Complex"), &runtimetesting.InternalComplex{}) + scheme.AddKnownTypeWithName(externalGV.WithKind("Complex"), &runtimetesting.ExternalComplex{}) + + testCases := map[string]struct { + input map[string][]string + errFn func(error) bool + expected runtime.Object + }{ + "ignores omitempty": { + input: map[string][]string{ + "String": {"not_used"}, + "string": {"value"}, + "int": {"1"}, + "Integer64": {"2"}, + }, + expected: &runtimetesting.ExternalComplex{String: "value", Integer: 1}, + }, + "returns error on bad int": { + input: map[string][]string{ + "int": {"a"}, + }, + errFn: func(err error) bool { return err != nil }, + expected: &runtimetesting.ExternalComplex{}, + }, + "parses int64": { + input: map[string][]string{ + "Int64": {"-1"}, + }, + expected: &runtimetesting.ExternalComplex{Int64: -1}, + }, + "returns error on bad int64": { + input: map[string][]string{ + "Int64": {"a"}, + }, + errFn: func(err error) bool { return err != nil }, + expected: &runtimetesting.ExternalComplex{}, + }, + "parses boolean true": { + input: map[string][]string{ + "bool": {"true"}, + }, + expected: &runtimetesting.ExternalComplex{Bool: true}, + }, + "parses boolean any value": { + input: map[string][]string{ + "bool": {"foo"}, + }, + expected: &runtimetesting.ExternalComplex{Bool: true}, + }, + "parses boolean false": { + input: map[string][]string{ + "bool": {"false"}, + }, + expected: &runtimetesting.ExternalComplex{Bool: false}, + }, + "parses boolean empty value": { + input: map[string][]string{ + "bool": {""}, + }, + expected: &runtimetesting.ExternalComplex{Bool: true}, + }, + "parses boolean no value": { + input: map[string][]string{ + "bool": {}, + }, + expected: &runtimetesting.ExternalComplex{Bool: false}, + }, + } + + for k, tc := range testCases { + out := &runtimetesting.ExternalComplex{} + if err := scheme.Convert(&tc.input, out, nil); (tc.errFn == nil && err != nil) || (tc.errFn != nil && !tc.errFn(err)) { + t.Errorf("%s: unexpected error: %v", k, err) + continue + } else if err != nil { + continue + } + if !reflect.DeepEqual(out, tc.expected) { + t.Errorf("%s: unexpected output: %#v", k, out) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/converter_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/converter_test.go new file mode 100644 index 000000000..7820b8cef --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/converter_test.go @@ -0,0 +1,597 @@ +/* +Copyright 2015 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. +*/ + +// These tests are in a separate package to break cyclic dependency in tests. +// Unstructured type depends on unstructured converter package but we want to test how the converter handles +// the Unstructured type so we need to import both. + +package runtime_test + +import ( + encodingjson "encoding/json" + "fmt" + "reflect" + "strconv" + "testing" + "time" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/apimachinery/pkg/util/json" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var simpleEquality = conversion.EqualitiesOrDie( + func(a, b time.Time) bool { + return a.UTC() == b.UTC() + }, +) + +// Definte a number of test types. +type A struct { + A int `json:"aa,omitempty"` + B string `json:"ab,omitempty"` + C bool `json:"ac,omitempty"` +} + +type B struct { + A A `json:"ba"` + B string `json:"bb"` + C map[string]string `json:"bc"` + D []string `json:"bd"` +} + +type C struct { + A []A `json:"ca"` + B `json:",inline"` + C string `json:"cc"` + D *int64 `json:"cd"` + E map[string]int `json:"ce"` + F []bool `json:"cf"` + G []int `json:"cg"` + H float32 `json:"ch"` + I []interface{} `json:"ci"` +} + +type D struct { + A []interface{} `json:"da"` +} + +type E struct { + A interface{} `json:"ea"` +} + +type F struct { + A string `json:"fa"` + B map[string]string `json:"fb"` + C []A `json:"fc"` + D int `json:"fd"` + E float32 `json:"fe"` + F []string `json:"ff"` + G []int `json:"fg"` + H []bool `json:"fh"` + I []float32 `json:"fi"` +} + +type G struct { + CustomValue1 CustomValue `json:"customValue1"` + CustomValue2 *CustomValue `json:"customValue2"` + CustomPointer1 CustomPointer `json:"customPointer1"` + CustomPointer2 *CustomPointer `json:"customPointer2"` +} + +type CustomValue struct { + data []byte +} + +// MarshalJSON has a value receiver on this type. +func (c CustomValue) MarshalJSON() ([]byte, error) { + return c.data, nil +} + +type CustomPointer struct { + data []byte +} + +// MarshalJSON has a pointer receiver on this type. +func (c *CustomPointer) MarshalJSON() ([]byte, error) { + return c.data, nil +} + +func doRoundTrip(t *testing.T, item interface{}) { + data, err := json.Marshal(item) + if err != nil { + t.Errorf("Error when marshaling object: %v", err) + return + } + + unstr := make(map[string]interface{}) + err = json.Unmarshal(data, &unstr) + if err != nil { + t.Errorf("Error when unmarshaling to unstructured: %v", err) + return + } + + data, err = json.Marshal(unstr) + if err != nil { + t.Errorf("Error when marshaling unstructured: %v", err) + return + } + unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface() + err = json.Unmarshal(data, unmarshalledObj) + if err != nil { + t.Errorf("Error when unmarshaling to object: %v", err) + return + } + if !reflect.DeepEqual(item, unmarshalledObj) { + t.Errorf("Object changed during JSON operations, diff: %v", diff.ObjectReflectDiff(item, unmarshalledObj)) + return + } + + // TODO: should be using mismatch detection but fails due to another error + newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(item) + if err != nil { + t.Errorf("ToUnstructured failed: %v", err) + return + } + + newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface() + err = runtime.NewTestUnstructuredConverter(simpleEquality).FromUnstructured(newUnstr, newObj) + if err != nil { + t.Errorf("FromUnstructured failed: %v", err) + return + } + + if !reflect.DeepEqual(item, newObj) { + t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(item, newObj)) + } +} + +func TestRoundTrip(t *testing.T) { + intVal := int64(42) + testCases := []struct { + obj interface{} + }{ + { + obj: &unstructured.UnstructuredList{ + Object: map[string]interface{}{ + "kind": "List", + }, + // Not testing a list with nil Items because items is a non-optional field and hence + // is always marshaled into an empty array which is not equal to nil when unmarshalled and will fail. + // That is expected. + Items: []unstructured.Unstructured{}, + }, + }, + { + obj: &unstructured.UnstructuredList{ + Object: map[string]interface{}{ + "kind": "List", + }, + Items: []unstructured.Unstructured{ + { + Object: map[string]interface{}{ + "kind": "Pod", + }, + }, + }, + }, + }, + { + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "kind": "Pod", + }, + }, + }, + { + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "Foo", + "metadata": map[string]interface{}{ + "name": "foo1", + }, + }, + }, + }, + { + // This (among others) tests nil map, slice and pointer. + obj: &C{ + C: "ccc", + }, + }, + { + // This (among others) tests empty map and slice. + obj: &C{ + A: []A{}, + C: "ccc", + E: map[string]int{}, + I: []interface{}{}, + }, + }, + { + obj: &C{ + A: []A{ + { + A: 1, + B: "11", + C: true, + }, + { + A: 2, + B: "22", + C: false, + }, + }, + B: B{ + A: A{ + A: 3, + B: "33", + }, + B: "bbb", + C: map[string]string{ + "k1": "v1", + "k2": "v2", + }, + D: []string{"s1", "s2"}, + }, + C: "ccc", + D: &intVal, + E: map[string]int{ + "k1": 1, + "k2": 2, + }, + F: []bool{true, false, false}, + G: []int{1, 2, 5}, + H: 3.3, + I: []interface{}{nil, nil, nil}, + }, + }, + { + // Test slice of interface{} with empty slices. + obj: &D{ + A: []interface{}{[]interface{}{}, []interface{}{}}, + }, + }, + { + // Test slice of interface{} with different values. + obj: &D{ + A: []interface{}{3.0, "3.0", nil}, + }, + }, + } + + for i := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + doRoundTrip(t, testCases[i].obj) + }) + } +} + +// Verifies that: +// 1) serialized json -> object +// 2) serialized json -> map[string]interface{} -> object +// produces the same object. +func doUnrecognized(t *testing.T, jsonData string, item interface{}, expectedErr error) { + unmarshalledObj := reflect.New(reflect.TypeOf(item).Elem()).Interface() + err := json.Unmarshal([]byte(jsonData), unmarshalledObj) + if (err != nil) != (expectedErr != nil) { + t.Errorf("Unexpected error when unmarshaling to object: %v, expected: %v", err, expectedErr) + return + } + + unstr := make(map[string]interface{}) + err = json.Unmarshal([]byte(jsonData), &unstr) + if err != nil { + t.Errorf("Error when unmarshaling to unstructured: %v", err) + return + } + newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface() + err = runtime.NewTestUnstructuredConverter(simpleEquality).FromUnstructured(unstr, newObj) + if (err != nil) != (expectedErr != nil) { + t.Errorf("Unexpected error in FromUnstructured: %v, expected: %v", err, expectedErr) + } + + if expectedErr == nil && !reflect.DeepEqual(unmarshalledObj, newObj) { + t.Errorf("Object changed, diff: %v", diff.ObjectReflectDiff(unmarshalledObj, newObj)) + } +} + +func TestUnrecognized(t *testing.T) { + testCases := []struct { + data string + obj interface{} + err error + }{ + { + data: "{\"da\":[3.0,\"3.0\",null]}", + obj: &D{}, + }, + { + data: "{\"ea\":[3.0,\"3.0\",null]}", + obj: &E{}, + }, + { + data: "{\"ea\":[null,null,null]}", + obj: &E{}, + }, + { + data: "{\"ea\":[[],[null]]}", + obj: &E{}, + }, + { + data: "{\"ea\":{\"a\":[],\"b\":null}}", + obj: &E{}, + }, + { + data: "{\"fa\":\"fa\",\"fb\":{\"a\":\"a\"}}", + obj: &F{}, + }, + { + data: "{\"fa\":\"fa\",\"fb\":{\"a\":null}}", + obj: &F{}, + }, + { + data: "{\"fc\":[null]}", + obj: &F{}, + }, + { + data: "{\"fc\":[{\"aa\":123,\"ab\":\"bbb\"}]}", + obj: &F{}, + }, + { + // Only unknown fields + data: "{\"fx\":[{\"aa\":123,\"ab\":\"bbb\"}],\"fz\":123}", + obj: &F{}, + }, + { + data: "{\"fc\":[{\"aa\":\"aaa\",\"ab\":\"bbb\"}]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type int"), + }, + { + data: "{\"fd\":123,\"fe\":3.5}", + obj: &F{}, + }, + { + data: "{\"ff\":[\"abc\"],\"fg\":[123],\"fh\":[true,false]}", + obj: &F{}, + }, + { + // Invalid string data + data: "{\"fa\":123}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"), + }, + { + // Invalid string data + data: "{\"fa\":13.5}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"), + }, + { + // Invalid string data + data: "{\"fa\":true}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal bool into Go value of type string"), + }, + { + // Invalid []string data + data: "{\"ff\":123}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type []string"), + }, + { + // Invalid []string data + data: "{\"ff\":3.5}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type []string"), + }, + { + // Invalid []string data + data: "{\"ff\":[123,345]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type string"), + }, + { + // Invalid []int data + data: "{\"fg\":123}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type []int"), + }, + { + // Invalid []int data + data: "{\"fg\":\"abc\"}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type []int"), + }, + { + // Invalid []int data + data: "{\"fg\":[\"abc\"]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type int"), + }, + { + // Invalid []int data + data: "{\"fg\":[3.5]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number 3.5 into Go value of type int"), + }, + { + // Invalid []int data + data: "{\"fg\":[true,false]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number 3.5 into Go value of type int"), + }, + { + // Invalid []bool data + data: "{\"fh\":123}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type []bool"), + }, + { + // Invalid []bool data + data: "{\"fh\":\"abc\"}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type []bool"), + }, + { + // Invalid []bool data + data: "{\"fh\":[\"abc\"]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type bool"), + }, + { + // Invalid []bool data + data: "{\"fh\":[3.5]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type bool"), + }, + { + // Invalid []bool data + data: "{\"fh\":[123]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type bool"), + }, + { + // Invalid []float data + data: "{\"fi\":123}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal number into Go value of type []float32"), + }, + { + // Invalid []float data + data: "{\"fi\":\"abc\"}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type []float32"), + }, + { + // Invalid []float data + data: "{\"fi\":[\"abc\"]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal string into Go value of type float32"), + }, + { + // Invalid []float data + data: "{\"fi\":[true]}", + obj: &F{}, + err: fmt.Errorf("json: cannot unmarshal bool into Go value of type float32"), + }, + } + + for _, tc := range testCases { + t.Run(tc.data, func(t *testing.T) { + doUnrecognized(t, tc.data, tc.obj, tc.err) + }) + } +} + +func TestDeepCopyJSON(t *testing.T) { + src := map[string]interface{}{ + "a": nil, + "b": int64(123), + "c": map[string]interface{}{ + "a": "b", + }, + "d": []interface{}{ + int64(1), int64(2), + }, + "e": "estr", + "f": true, + "g": encodingjson.Number("123"), + } + deepCopy := runtime.DeepCopyJSON(src) + assert.Equal(t, src, deepCopy) +} + +func TestFloatIntConversion(t *testing.T) { + unstr := map[string]interface{}{"fd": float64(3)} + + var obj F + if err := runtime.NewTestUnstructuredConverter(simpleEquality).FromUnstructured(unstr, &obj); err != nil { + t.Errorf("Unexpected error in FromUnstructured: %v", err) + } + + data, err := json.Marshal(unstr) + if err != nil { + t.Fatalf("Error when marshaling unstructured: %v", err) + } + var unmarshalled F + if err := json.Unmarshal(data, &unmarshalled); err != nil { + t.Fatalf("Error when unmarshaling to object: %v", err) + } + + if !reflect.DeepEqual(obj, unmarshalled) { + t.Errorf("Incorrect conversion, diff: %v", diff.ObjectReflectDiff(obj, unmarshalled)) + } +} + +func TestCustomToUnstructured(t *testing.T) { + testcases := []struct { + Data string + Expected interface{} + }{ + {Data: `null`, Expected: nil}, + {Data: `true`, Expected: true}, + {Data: `false`, Expected: false}, + {Data: `[]`, Expected: []interface{}{}}, + {Data: `[1]`, Expected: []interface{}{int64(1)}}, + {Data: `{}`, Expected: map[string]interface{}{}}, + {Data: `{"a":1}`, Expected: map[string]interface{}{"a": int64(1)}}, + {Data: `0`, Expected: int64(0)}, + {Data: `0.0`, Expected: float64(0)}, + } + + for _, tc := range testcases { + tc := tc + t.Run(tc.Data, func(t *testing.T) { + t.Parallel() + result, err := runtime.NewTestUnstructuredConverter(simpleEquality).ToUnstructured(&G{ + CustomValue1: CustomValue{data: []byte(tc.Data)}, + CustomValue2: &CustomValue{data: []byte(tc.Data)}, + CustomPointer1: CustomPointer{data: []byte(tc.Data)}, + CustomPointer2: &CustomPointer{data: []byte(tc.Data)}, + }) + require.NoError(t, err) + for field, fieldResult := range result { + assert.Equal(t, tc.Expected, fieldResult, field) + } + }) + } +} + +func TestCustomToUnstructuredTopLevel(t *testing.T) { + // Only objects are supported at the top level + topLevelCases := []interface{}{ + &CustomValue{data: []byte(`{"a":1}`)}, + &CustomPointer{data: []byte(`{"a":1}`)}, + } + expected := map[string]interface{}{"a": int64(1)} + for i, obj := range topLevelCases { + obj := obj + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() + result, err := runtime.NewTestUnstructuredConverter(simpleEquality).ToUnstructured(obj) + require.NoError(t, err) + assert.Equal(t, expected, result) + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/embedded_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/embedded_test.go new file mode 100644 index 000000000..606e0e96a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/embedded_test.go @@ -0,0 +1,256 @@ +/* +Copyright 2014 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 runtime_test + +import ( + "encoding/json" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + runtimetesting "k8s.io/apimachinery/pkg/runtime/testing" + "k8s.io/apimachinery/pkg/util/diff" +) + +func TestDecodeEmptyRawExtensionAsObject(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"} + externalGVK := externalGV.WithKind("ObjectTest") + + s := runtime.NewScheme() + s.AddKnownTypes(internalGV, &runtimetesting.ObjectTest{}) + s.AddKnownTypeWithName(externalGVK, &runtimetesting.ObjectTestExternal{}) + + codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) + + obj, gvk, err := codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{}]}`), nil, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + test := obj.(*runtimetesting.ObjectTest) + if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != "{}" || unk.ContentType != runtime.ContentTypeJSON { + t.Fatalf("unexpected object: %#v", test.Items[0]) + } + if *gvk != externalGVK { + t.Fatalf("unexpected kind: %#v", gvk) + } + + obj, gvk, err = codec.Decode([]byte(`{"kind":"`+externalGVK.Kind+`","apiVersion":"`+externalGV.String()+`","items":[{"kind":"Other","apiVersion":"v1"}]}`), nil, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + test = obj.(*runtimetesting.ObjectTest) + if unk, ok := test.Items[0].(*runtime.Unknown); !ok || unk.Kind != "" || unk.APIVersion != "" || string(unk.Raw) != `{"kind":"Other","apiVersion":"v1"}` || unk.ContentType != runtime.ContentTypeJSON { + t.Fatalf("unexpected object: %#v", test.Items[0]) + } + if *gvk != externalGVK { + t.Fatalf("unexpected kind: %#v", gvk) + } +} + +func TestArrayOfRuntimeObject(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"} + + s := runtime.NewScheme() + s.AddKnownTypes(internalGV, &runtimetesting.EmbeddedTest{}) + s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &runtimetesting.EmbeddedTestExternal{}) + s.AddKnownTypes(internalGV, &runtimetesting.ObjectTest{}) + s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &runtimetesting.ObjectTestExternal{}) + + codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) + + innerItems := []runtime.Object{ + &runtimetesting.EmbeddedTest{ID: "baz"}, + } + items := []runtime.Object{ + &runtimetesting.EmbeddedTest{ID: "foo"}, + &runtimetesting.EmbeddedTest{ID: "bar"}, + // TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization + &runtime.Unknown{ + Raw: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`), + ContentType: runtime.ContentTypeJSON, + }, + &runtimetesting.ObjectTest{ + Items: runtime.NewEncodableList(codec, innerItems), + }, + } + internal := &runtimetesting.ObjectTest{ + Items: runtime.NewEncodableList(codec, items), + } + wire, err := runtime.Encode(codec, internal) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + t.Logf("Wire format is:\n%s\n", string(wire)) + + obj := &runtimetesting.ObjectTestExternal{} + if err := json.Unmarshal(wire, obj); err != nil { + t.Fatalf("unexpected error: %v", err) + } + t.Logf("exact wire is: %s", string(obj.Items[0].Raw)) + + items[3] = &runtimetesting.ObjectTest{Items: innerItems} + internal.Items = items + + decoded, err := runtime.Decode(codec, wire) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + list, err := meta.ExtractList(decoded) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if errs := runtime.DecodeList(list, codec); len(errs) > 0 { + t.Fatalf("unexpected error: %v", errs) + } + + list2, err := meta.ExtractList(list[3]) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if errs := runtime.DecodeList(list2, codec); len(errs) > 0 { + t.Fatalf("unexpected error: %v", errs) + } + if err := meta.SetList(list[3], list2); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // we want DecodeList to set type meta if possible, even on runtime.Unknown objects + internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"} + if e, a := internal.Items, list; !reflect.DeepEqual(e, a) { + t.Errorf("mismatched decoded: %s", diff.ObjectGoPrintSideBySide(e, a)) + } +} + +func TestNestedObject(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"} + embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest") + + s := runtime.NewScheme() + s.AddKnownTypes(internalGV, &runtimetesting.EmbeddedTest{}) + s.AddKnownTypeWithName(embeddedTestExternalGVK, &runtimetesting.EmbeddedTestExternal{}) + + codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) + + inner := &runtimetesting.EmbeddedTest{ + ID: "inner", + } + outer := &runtimetesting.EmbeddedTest{ + ID: "outer", + Object: runtime.NewEncodable(codec, inner), + } + + wire, err := runtime.Encode(codec, outer) + if err != nil { + t.Fatalf("Unexpected encode error '%v'", err) + } + + t.Logf("Wire format is:\n%v\n", string(wire)) + + decoded, err := runtime.Decode(codec, wire) + if err != nil { + t.Fatalf("Unexpected decode error %v", err) + } + + // for later tests + outer.Object = inner + + if e, a := outer, decoded; reflect.DeepEqual(e, a) { + t.Errorf("Expected unequal %#v %#v", e, a) + } + + obj, err := runtime.Decode(codec, decoded.(*runtimetesting.EmbeddedTest).Object.(*runtime.Unknown).Raw) + if err != nil { + t.Fatal(err) + } + decoded.(*runtimetesting.EmbeddedTest).Object = obj + if e, a := outer, decoded; !reflect.DeepEqual(e, a) { + t.Errorf("Expected equal %#v %#v", e, a) + } + + // test JSON decoding of the external object, which should preserve + // raw bytes + var externalViaJSON runtimetesting.EmbeddedTestExternal + err = json.Unmarshal(wire, &externalViaJSON) + if err != nil { + t.Fatalf("Unexpected decode error %v", err) + } + if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.ID != "outer" { + t.Errorf("Expected objects to have type info set, got %#v", externalViaJSON) + } + if len(externalViaJSON.EmptyObject.Raw) > 0 { + t.Errorf("Expected deserialization of empty nested objects into empty bytes, got %#v", externalViaJSON) + } + + // test JSON decoding, too, since Decode uses yaml unmarshalling. + // Generic Unmarshalling of JSON cannot load the nested objects because there is + // no default schema set. Consumers wishing to get direct JSON decoding must use + // the external representation + var decodedViaJSON runtimetesting.EmbeddedTest + err = json.Unmarshal(wire, &decodedViaJSON) + if err == nil { + t.Fatal("Expeceted decode error") + } + if _, ok := err.(*json.UnmarshalTypeError); !ok { + t.Fatalf("Unexpected decode error: %v", err) + } + if a := decodedViaJSON; a.Object != nil || a.EmptyObject != nil { + t.Errorf("Expected embedded objects to be nil: %#v", a) + } +} + +// TestDeepCopyOfRuntimeObject checks to make sure that runtime.Objects's can be passed through DeepCopy with fidelity +func TestDeepCopyOfRuntimeObject(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "v1test"} + embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest") + + s := runtime.NewScheme() + s.AddKnownTypes(internalGV, &runtimetesting.EmbeddedTest{}) + s.AddKnownTypeWithName(embeddedTestExternalGVK, &runtimetesting.EmbeddedTestExternal{}) + + original := &runtimetesting.EmbeddedTest{ + ID: "outer", + Object: &runtimetesting.EmbeddedTest{ + ID: "inner", + }, + } + + codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) + + originalData, err := runtime.Encode(codec, original) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + t.Logf("originalRole = %v\n", string(originalData)) + + copyOfOriginal := original.DeepCopy() + copiedData, err := runtime.Encode(codec, copyOfOriginal) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + t.Logf("copyOfRole = %v\n", string(copiedData)) + + if !reflect.DeepEqual(original, copyOfOriginal) { + t.Errorf("expected \n%v\n, got \n%v", string(originalData), string(copiedData)) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/extension_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/extension_test.go new file mode 100644 index 000000000..5f9154ea6 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/extension_test.go @@ -0,0 +1,113 @@ +/* +Copyright 2014 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 runtime_test + +import ( + "bytes" + "encoding/json" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" +) + +func TestEmbeddedRawExtensionMarshal(t *testing.T) { + type test struct { + Ext runtime.RawExtension + } + + extension := test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}} + data, err := json.Marshal(extension) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if string(data) != `{"Ext":{"foo":"bar"}}` { + t.Errorf("unexpected data: %s", string(data)) + } +} +func TestEmbeddedRawExtensionUnmarshal(t *testing.T) { + type test struct { + Ext runtime.RawExtension + } + + testCases := map[string]struct { + orig test + }{ + "non-empty object": { + orig: test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}}, + }, + "empty object": { + orig: test{Ext: runtime.RawExtension{}}, + }, + } + + for k, tc := range testCases { + new := test{} + data, _ := json.Marshal(tc.orig) + if err := json.Unmarshal(data, &new); err != nil { + t.Errorf("%s: umarshal error: %v", k, err) + } + if !reflect.DeepEqual(tc.orig, new) { + t.Errorf("%s: unmarshaled struct differs from original: %v %v", k, tc.orig, new) + } + } +} + +func TestEmbeddedRawExtensionRoundTrip(t *testing.T) { + type test struct { + Ext runtime.RawExtension + } + + testCases := map[string]struct { + orig test + }{ + "non-empty object": { + orig: test{Ext: runtime.RawExtension{Raw: []byte(`{"foo":"bar"}`)}}, + }, + "empty object": { + orig: test{Ext: runtime.RawExtension{}}, + }, + } + + for k, tc := range testCases { + new1 := test{} + new2 := test{} + data, err := json.Marshal(tc.orig) + if err != nil { + t.Errorf("1st marshal error: %v", err) + } + if err = json.Unmarshal(data, &new1); err != nil { + t.Errorf("1st unmarshal error: %v", err) + } + newData, err := json.Marshal(new1) + if err != nil { + t.Errorf("2st marshal error: %v", err) + } + if err = json.Unmarshal(newData, &new2); err != nil { + t.Errorf("2nd unmarshal error: %v", err) + } + if !bytes.Equal(data, newData) { + t.Errorf("%s: re-marshaled data differs from original: %v %v", k, data, newData) + } + if !reflect.DeepEqual(tc.orig, new1) { + t.Errorf("%s: unmarshaled struct differs from original: %v %v", k, tc.orig, new1) + } + if !reflect.DeepEqual(new1, new2) { + t.Errorf("%s: re-unmarshaled struct differs from original: %v %v", k, new1, new2) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/generated.proto b/vendor/k8s.io/apimachinery/pkg/runtime/generated.proto new file mode 100644 index 000000000..fb61ac96a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/generated.proto @@ -0,0 +1,127 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.apimachinery.pkg.runtime; + +// Package-wide variables from generator "generated". +option go_package = "runtime"; + +// RawExtension is used to hold extensions in external versions. +// +// To use this, make a field which has RawExtension as its type in your external, versioned +// struct, and Object in your internal struct. You also need to register your +// various plugin types. +// +// // Internal package: +// type MyAPIObject struct { +// runtime.TypeMeta `json:",inline"` +// MyPlugin runtime.Object `json:"myPlugin"` +// } +// type PluginA struct { +// AOption string `json:"aOption"` +// } +// +// // External package: +// type MyAPIObject struct { +// runtime.TypeMeta `json:",inline"` +// MyPlugin runtime.RawExtension `json:"myPlugin"` +// } +// type PluginA struct { +// AOption string `json:"aOption"` +// } +// +// // On the wire, the JSON will look something like this: +// { +// "kind":"MyAPIObject", +// "apiVersion":"v1", +// "myPlugin": { +// "kind":"PluginA", +// "aOption":"foo", +// }, +// } +// +// So what happens? Decode first uses json or yaml to unmarshal the serialized data into +// your external MyAPIObject. That causes the raw JSON to be stored, but not unpacked. +// The next step is to copy (using pkg/conversion) into the internal struct. The runtime +// package's DefaultScheme has conversion functions installed which will unpack the +// JSON stored in RawExtension, turning it into the correct object type, and storing it +// in the Object. (TODO: In the case where the object is of an unknown type, a +// runtime.Unknown object will be created and stored.) +// +// +k8s:deepcopy-gen=true +// +protobuf=true +// +k8s:openapi-gen=true +message RawExtension { + // Raw is the underlying serialization of this object. + // + // TODO: Determine how to detect ContentType and ContentEncoding of 'Raw' data. + optional bytes raw = 1; +} + +// TypeMeta is shared by all top level objects. The proper way to use it is to inline it in your type, +// like this: +// type MyAwesomeAPIObject struct { +// runtime.TypeMeta `json:",inline"` +// ... // other fields +// } +// func (obj *MyAwesomeAPIObject) SetGroupVersionKind(gvk *metav1.GroupVersionKind) { metav1.UpdateTypeMeta(obj,gvk) }; GroupVersionKind() *GroupVersionKind +// +// TypeMeta is provided here for convenience. You may use it directly from this package or define +// your own with the same fields. +// +// +k8s:deepcopy-gen=false +// +protobuf=true +// +k8s:openapi-gen=true +message TypeMeta { + // +optional + optional string apiVersion = 1; + + // +optional + optional string kind = 2; +} + +// Unknown allows api objects with unknown types to be passed-through. This can be used +// to deal with the API objects from a plug-in. Unknown objects still have functioning +// TypeMeta features-- kind, version, etc. +// TODO: Make this object have easy access to field based accessors and settors for +// metadata and field mutatation. +// +// +k8s:deepcopy-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +protobuf=true +// +k8s:openapi-gen=true +message Unknown { + optional TypeMeta typeMeta = 1; + + // Raw will hold the complete serialized object which couldn't be matched + // with a registered type. Most likely, nothing should be done with this + // except for passing it through the system. + optional bytes raw = 2; + + // ContentEncoding is encoding used to encode 'Raw' data. + // Unspecified means no encoding. + optional string contentEncoding = 3; + + // ContentType is serialization method used to serialize 'Raw'. + // Unspecified means ContentTypeJSON. + optional string contentType = 4; +} + diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/local_scheme_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/local_scheme_test.go new file mode 100644 index 000000000..45a0dde5e --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/local_scheme_test.go @@ -0,0 +1,150 @@ +/* +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. +*/ + +package runtime + +import ( + "testing" + + "reflect" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" +) + +func TestPreferredVersionsAllGroups(t *testing.T) { + tests := []struct { + name string + versionPriority map[string][]string + observedVersions []schema.GroupVersion + expectedPrioritized map[string][]schema.GroupVersion + expectedPreferred map[schema.GroupVersion]bool + }{ + { + name: "observedOnly", + observedVersions: []schema.GroupVersion{ + {Group: "", Version: "v3"}, + {Group: "foo", Version: "v1"}, + {Group: "foo", Version: "v2"}, + {Group: "", Version: "v1"}, + }, + expectedPrioritized: map[string][]schema.GroupVersion{ + "": { + {Group: "", Version: "v3"}, + {Group: "", Version: "v1"}, + }, + "foo": { + {Group: "foo", Version: "v1"}, + {Group: "foo", Version: "v2"}, + }, + }, + expectedPreferred: map[schema.GroupVersion]bool{ + {Group: "", Version: "v3"}: true, + {Group: "foo", Version: "v1"}: true, + }, + }, + { + name: "specifiedOnly", + versionPriority: map[string][]string{ + "": {"v3", "v1"}, + "foo": {"v1", "v2"}, + }, + expectedPrioritized: map[string][]schema.GroupVersion{ + "": { + {Group: "", Version: "v3"}, + {Group: "", Version: "v1"}, + }, + "foo": { + {Group: "foo", Version: "v1"}, + {Group: "foo", Version: "v2"}, + }, + }, + expectedPreferred: map[schema.GroupVersion]bool{ + {Group: "", Version: "v3"}: true, + {Group: "foo", Version: "v1"}: true, + }, + }, + { + name: "both", + versionPriority: map[string][]string{ + "": {"v3", "v1"}, + "foo": {"v1", "v2"}, + }, + observedVersions: []schema.GroupVersion{ + {Group: "", Version: "v1"}, + {Group: "", Version: "v3"}, + {Group: "", Version: "v4"}, + {Group: "", Version: "v5"}, + {Group: "bar", Version: "v1"}, + {Group: "bar", Version: "v2"}, + }, + expectedPrioritized: map[string][]schema.GroupVersion{ + "": { + {Group: "", Version: "v3"}, + {Group: "", Version: "v1"}, + {Group: "", Version: "v4"}, + {Group: "", Version: "v5"}, + }, + "foo": { + {Group: "foo", Version: "v1"}, + {Group: "foo", Version: "v2"}, + }, + "bar": { + {Group: "bar", Version: "v1"}, + {Group: "bar", Version: "v2"}, + }, + }, + expectedPreferred: map[schema.GroupVersion]bool{ + {Group: "", Version: "v3"}: true, + {Group: "foo", Version: "v1"}: true, + {Group: "bar", Version: "v1"}: true, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + scheme := NewScheme() + scheme.versionPriority = test.versionPriority + scheme.observedVersions = test.observedVersions + + for group, expected := range test.expectedPrioritized { + actual := scheme.PrioritizedVersionsForGroup(group) + if !reflect.DeepEqual(expected, actual) { + t.Error(diff.ObjectDiff(expected, actual)) + } + } + + prioritizedAll := scheme.PrioritizedVersionsAllGroups() + actualPrioritizedAll := map[string][]schema.GroupVersion{} + for _, actual := range prioritizedAll { + actualPrioritizedAll[actual.Group] = append(actualPrioritizedAll[actual.Group], actual) + } + if !reflect.DeepEqual(test.expectedPrioritized, actualPrioritizedAll) { + t.Error(diff.ObjectDiff(test.expectedPrioritized, actualPrioritizedAll)) + } + + preferredAll := scheme.PreferredVersionAllGroups() + actualPreferredAll := map[schema.GroupVersion]bool{} + for _, actual := range preferredAll { + actualPreferredAll[actual] = true + } + if !reflect.DeepEqual(test.expectedPreferred, actualPreferredAll) { + t.Error(diff.ObjectDiff(test.expectedPreferred, actualPreferredAll)) + } + }) + } +} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go b/vendor/k8s.io/apimachinery/pkg/runtime/schema/generated.proto similarity index 71% rename from vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go rename to vendor/k8s.io/apimachinery/pkg/runtime/schema/generated.proto index 3059734a9..5aeeaa100 100644 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/schema/generated.proto @@ -14,10 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by client-gen. DO NOT EDIT. -package v1 +// This file was autogenerated by go-to-protobuf. Do not edit it manually! -type ClusterTestTypeExpansion interface{} +syntax = 'proto2'; + +package k8s.io.apimachinery.pkg.runtime.schema; + +// Package-wide variables from generator "generated". +option go_package = "schema"; -type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version_test.go new file mode 100644 index 000000000..3934bc45a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/schema/group_version_test.go @@ -0,0 +1,180 @@ +/* +Copyright 2015 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 schema + +import ( + "testing" +) + +func TestGroupVersionParse(t *testing.T) { + tests := []struct { + input string + out GroupVersion + err func(error) bool + }{ + {input: "v1", out: GroupVersion{Version: "v1"}}, + {input: "v2", out: GroupVersion{Version: "v2"}}, + {input: "/v1", out: GroupVersion{Version: "v1"}}, + {input: "v1/", out: GroupVersion{Group: "v1"}}, + {input: "/v1/", err: func(err error) bool { return err.Error() == "unexpected GroupVersion string: /v1/" }}, + {input: "v1/a", out: GroupVersion{Group: "v1", Version: "a"}}, + } + for i, test := range tests { + out, err := ParseGroupVersion(test.input) + if test.err == nil && err != nil || err == nil && test.err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + continue + } + if test.err != nil && !test.err(err) { + t.Errorf("%d: unexpected error: %v", i, err) + continue + } + if out != test.out { + t.Errorf("%d: unexpected output: %#v", i, out) + } + } +} + +func TestGroupResourceParse(t *testing.T) { + tests := []struct { + input string + out GroupResource + }{ + {input: "v1", out: GroupResource{Resource: "v1"}}, + {input: ".v1", out: GroupResource{Group: "v1"}}, + {input: "v1.", out: GroupResource{Resource: "v1"}}, + {input: "v1.a", out: GroupResource{Group: "a", Resource: "v1"}}, + {input: "b.v1.a", out: GroupResource{Group: "v1.a", Resource: "b"}}, + } + for i, test := range tests { + out := ParseGroupResource(test.input) + if out != test.out { + t.Errorf("%d: unexpected output: %#v", i, out) + } + } +} + +func TestParseResourceArg(t *testing.T) { + tests := []struct { + input string + gvr *GroupVersionResource + gr GroupResource + }{ + {input: "v1", gr: GroupResource{Resource: "v1"}}, + {input: ".v1", gr: GroupResource{Group: "v1"}}, + {input: "v1.", gr: GroupResource{Resource: "v1"}}, + {input: "v1.a", gr: GroupResource{Group: "a", Resource: "v1"}}, + {input: "b.v1.a", gvr: &GroupVersionResource{Group: "a", Version: "v1", Resource: "b"}, gr: GroupResource{Group: "v1.a", Resource: "b"}}, + } + for i, test := range tests { + gvr, gr := ParseResourceArg(test.input) + if (gvr != nil && test.gvr == nil) || (gvr == nil && test.gvr != nil) || (test.gvr != nil && *gvr != *test.gvr) { + t.Errorf("%d: unexpected output: %#v", i, gvr) + } + if gr != test.gr { + t.Errorf("%d: unexpected output: %#v", i, gr) + } + } +} + +func TestKindForGroupVersionKinds(t *testing.T) { + gvks := GroupVersions{ + GroupVersion{Group: "batch", Version: "v1"}, + GroupVersion{Group: "batch", Version: "v2alpha1"}, + GroupVersion{Group: "policy", Version: "v1beta1"}, + } + cases := []struct { + input []GroupVersionKind + target GroupVersionKind + ok bool + }{ + { + input: []GroupVersionKind{{Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}}, + target: GroupVersionKind{Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}, + ok: true, + }, + { + input: []GroupVersionKind{{Group: "batch", Version: "v3alpha1", Kind: "CronJob"}}, + target: GroupVersionKind{Group: "batch", Version: "v1", Kind: "CronJob"}, + ok: true, + }, + { + input: []GroupVersionKind{{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"}}, + target: GroupVersionKind{Group: "policy", Version: "v1beta1", Kind: "PodDisruptionBudget"}, + ok: true, + }, + { + input: []GroupVersionKind{{Group: "apps", Version: "v1alpha1", Kind: "StatefulSet"}}, + target: GroupVersionKind{}, + ok: false, + }, + } + + for i, c := range cases { + target, ok := gvks.KindForGroupVersionKinds(c.input) + if c.target != target { + t.Errorf("%d: unexpected target: %v, expected %v", i, target, c.target) + } + if c.ok != ok { + t.Errorf("%d: unexpected ok: %v, expected %v", i, ok, c.ok) + } + } +} + +func TestParseKindArg(t *testing.T) { + tests := []struct { + input string + gvk *GroupVersionKind + gk GroupKind + }{ + {input: "Pod", gk: GroupKind{Kind: "Pod"}}, + {input: ".apps", gk: GroupKind{Group: "apps"}}, + {input: "Pod.", gk: GroupKind{Kind: "Pod"}}, + {input: "StatefulSet.apps", gk: GroupKind{Group: "apps", Kind: "StatefulSet"}}, + {input: "StatefulSet.v1.apps", gvk: &GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}, gk: GroupKind{Group: "v1.apps", Kind: "StatefulSet"}}, + } + for i, test := range tests { + t.Run(test.input, func(t *testing.T) { + gvk, gk := ParseKindArg(test.input) + if (gvk != nil && test.gvk == nil) || (gvk == nil && test.gvk != nil) || (test.gvk != nil && *gvk != *test.gvk) { + t.Errorf("%d: expected output: %#v, got: %#v", i, test.gvk, gvk) + } + if gk != test.gk { + t.Errorf("%d: expected output: %#v, got: %#v", i, test.gk, gk) + } + }) + } +} + +func TestParseGroupKind(t *testing.T) { + tests := []struct { + input string + out GroupKind + }{ + {input: "Pod", out: GroupKind{Kind: "Pod"}}, + {input: ".StatefulSet", out: GroupKind{Group: "StatefulSet"}}, + {input: "StatefulSet.apps", out: GroupKind{Group: "apps", Kind: "StatefulSet"}}, + } + for i, test := range tests { + t.Run(test.input, func(t *testing.T) { + out := ParseGroupKind(test.input) + if out != test.out { + t.Errorf("%d: expected output: %#v, got: %#v", i, test.out, out) + } + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/scheme_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/scheme_test.go new file mode 100644 index 000000000..66f652faa --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/scheme_test.go @@ -0,0 +1,1021 @@ +/* +Copyright 2014 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 runtime_test + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + runtimetesting "k8s.io/apimachinery/pkg/runtime/testing" + "k8s.io/apimachinery/pkg/util/diff" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +func TestScheme(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + internalGVK := internalGV.WithKind("Simple") + externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} + externalGVK := externalGV.WithKind("Simple") + + scheme := runtime.NewScheme() + scheme.AddKnownTypeWithName(internalGVK, &runtimetesting.InternalSimple{}) + scheme.AddKnownTypeWithName(externalGVK, &runtimetesting.ExternalSimple{}) + + // If set, would clear TypeMeta during conversion. + //scheme.AddIgnoredConversionType(&TypeMeta{}, &TypeMeta{}) + + // test that scheme is an ObjectTyper + var _ runtime.ObjectTyper = scheme + + internalToExternalCalls := 0 + externalToInternalCalls := 0 + + // Register functions to verify that scope.Meta() gets set correctly. + err := scheme.AddConversionFuncs( + func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error { + err := scope.Convert(&in.TypeMeta, &out.TypeMeta, 0) + if err != nil { + return err + } + err = scope.Convert(&in.TestString, &out.TestString, 0) + if err != nil { + return err + } + internalToExternalCalls++ + return nil + }, + func(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error { + err := scope.Convert(&in.TypeMeta, &out.TypeMeta, 0) + if err != nil { + return err + } + err = scope.Convert(&in.TestString, &out.TestString, 0) + if err != nil { + return err + } + externalToInternalCalls++ + return nil + }, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + t.Run("Encode, Decode, DecodeInto, and DecodeToVersion", func(t *testing.T) { + simple := &runtimetesting.InternalSimple{ + TestString: "foo", + } + + codecs := serializer.NewCodecFactory(scheme) + codec := codecs.LegacyCodec(externalGV) + info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON) + jsonserializer := info.Serializer + + obj := runtime.Object(simple) + data, err := runtime.Encode(codec, obj) + if err != nil { + t.Fatal(err) + } + + obj2, err := runtime.Decode(codec, data) + if err != nil { + t.Fatal(err) + } + if _, ok := obj2.(*runtimetesting.InternalSimple); !ok { + t.Fatalf("Got wrong type") + } + if e, a := simple, obj2; !reflect.DeepEqual(e, a) { + t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) + } + + obj3 := &runtimetesting.InternalSimple{} + if err := runtime.DecodeInto(codec, data, obj3); err != nil { + t.Fatal(err) + } + // clearing TypeMeta is a function of the scheme, which we do not test here (ConvertToVersion + // does not automatically clear TypeMeta anymore). + simple.TypeMeta = runtime.TypeMeta{Kind: "Simple", APIVersion: externalGV.String()} + if e, a := simple, obj3; !reflect.DeepEqual(e, a) { + t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) + } + + obj4, err := runtime.Decode(jsonserializer, data) + if err != nil { + t.Fatal(err) + } + if _, ok := obj4.(*runtimetesting.ExternalSimple); !ok { + t.Fatalf("Got wrong type") + } + }) + t.Run("Convert", func(t *testing.T) { + simple := &runtimetesting.InternalSimple{ + TestString: "foo", + } + + external := &runtimetesting.ExternalSimple{} + err = scheme.Convert(simple, external, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if e, a := simple.TestString, external.TestString; e != a { + t.Errorf("Expected %q, got %q", e, a) + } + }) + t.Run("Convert internal to unstructured", func(t *testing.T) { + simple := &runtimetesting.InternalSimple{ + TestString: "foo", + } + + unstructuredObj := &runtimetesting.Unstructured{} + err = scheme.Convert(simple, unstructuredObj, nil) + if err == nil || !strings.Contains(err.Error(), "to Unstructured without providing a preferred version to convert to") { + t.Fatalf("Unexpected non-error: %v", err) + } + err = scheme.Convert(simple, unstructuredObj, externalGV) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if e, a := simple.TestString, unstructuredObj.Object["testString"].(string); e != a { + t.Errorf("Expected %q, got %q", e, a) + } + if e := unstructuredObj.GetObjectKind().GroupVersionKind(); e != externalGVK { + t.Errorf("Unexpected object kind: %#v", e) + } + if gvks, unversioned, err := scheme.ObjectKinds(unstructuredObj); err != nil || gvks[0] != externalGVK || unversioned { + t.Errorf("Scheme did not recognize unversioned: %v, %#v %t", err, gvks, unversioned) + } + }) + t.Run("Convert external to unstructured", func(t *testing.T) { + unstructuredObj := &runtimetesting.Unstructured{} + external := &runtimetesting.ExternalSimple{ + TestString: "foo", + } + + err = scheme.Convert(external, unstructuredObj, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if e, a := external.TestString, unstructuredObj.Object["testString"].(string); e != a { + t.Errorf("Expected %q, got %q", e, a) + } + if e := unstructuredObj.GetObjectKind().GroupVersionKind(); e != externalGVK { + t.Errorf("Unexpected object kind: %#v", e) + } + }) + t.Run("Convert unstructured to unstructured", func(t *testing.T) { + uIn := &runtimetesting.Unstructured{Object: map[string]interface{}{ + "test": []interface{}{"other", "test"}, + }} + uOut := &runtimetesting.Unstructured{} + err = scheme.Convert(uIn, uOut, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(uIn.Object, uOut.Object) { + t.Errorf("Unexpected object contents: %#v", uOut.Object) + } + }) + t.Run("Convert unstructured to structured", func(t *testing.T) { + unstructuredObj := &runtimetesting.Unstructured{ + Object: map[string]interface{}{ + "testString": "bla", + }, + } + unstructuredObj.SetGroupVersionKind(externalGV.WithKind("Simple")) + externalOut := &runtimetesting.ExternalSimple{} + err = scheme.Convert(unstructuredObj, externalOut, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if externalOut.TestString != "bla" { + t.Errorf("Unexpected object contents: %#v", externalOut) + } + }) + t.Run("Encode and Convert should each have caused an increment", func(t *testing.T) { + if e, a := 3, internalToExternalCalls; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + }) + t.Run("DecodeInto and Decode should each have caused an increment because of a conversion", func(t *testing.T) { + if e, a := 2, externalToInternalCalls; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + }) + t.Run("Verify that unstructured types must have V and K set", func(t *testing.T) { + emptyObj := &runtimetesting.Unstructured{Object: make(map[string]interface{})} + if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingKind(err) { + t.Errorf("unexpected error: %v", err) + } + emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test"}) + if _, _, err := scheme.ObjectKinds(emptyObj); !runtime.IsMissingVersion(err) { + t.Errorf("unexpected error: %v", err) + } + emptyObj.SetGroupVersionKind(schema.GroupVersionKind{Kind: "Test", Version: "v1"}) + if _, _, err := scheme.ObjectKinds(emptyObj); err != nil { + t.Errorf("unexpected error: %v", err) + } + }) +} + +func TestBadJSONRejection(t *testing.T) { + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + info, _ := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), runtime.ContentTypeJSON) + jsonserializer := info.Serializer + + badJSONMissingKind := []byte(`{ }`) + if _, err := runtime.Decode(jsonserializer, badJSONMissingKind); err == nil { + t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind) + } + badJSONUnknownType := []byte(`{"kind": "bar"}`) + if _, err1 := runtime.Decode(jsonserializer, badJSONUnknownType); err1 == nil { + t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType) + } + /*badJSONKindMismatch := []byte(`{"kind": "Pod"}`) + if err2 := DecodeInto(badJSONKindMismatch, &Node{}); err2 == nil { + t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch) + }*/ +} + +func TestExternalToInternalMapping(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} + + scheme := runtime.NewScheme() + scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &runtimetesting.InternalOptionalExtensionType{}) + scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &runtimetesting.ExternalOptionalExtensionType{}) + + codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) + + table := []struct { + obj runtime.Object + encoded string + }{ + { + &runtimetesting.InternalOptionalExtensionType{Extension: nil}, + `{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`, + }, + } + + for i, item := range table { + gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) + if err != nil { + t.Errorf("unexpected error '%v' (%v)", err, item.encoded) + } else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) { + t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a)) + } + } +} + +func TestExtensionMapping(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} + + scheme := runtime.NewScheme() + scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &runtimetesting.InternalExtensionType{}) + scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &runtimetesting.InternalOptionalExtensionType{}) + scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &runtimetesting.ExternalExtensionType{}) + scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &runtimetesting.ExternalOptionalExtensionType{}) + + // register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the + // external version. + scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &runtimetesting.ExtensionA{}) + scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &runtimetesting.ExtensionB{}) + scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &runtimetesting.ExtensionA{}) + scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &runtimetesting.ExtensionB{}) + + codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) + + table := []struct { + obj runtime.Object + expected runtime.Object + encoded string + }{ + { + &runtimetesting.InternalExtensionType{ + Extension: runtime.NewEncodable(codec, &runtimetesting.ExtensionA{TestString: "foo"}), + }, + &runtimetesting.InternalExtensionType{ + Extension: &runtime.Unknown{ + Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}`), + ContentType: runtime.ContentTypeJSON, + }, + }, + // apiVersion is set in the serialized object for easier consumption by clients + `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}} +`, + }, { + &runtimetesting.InternalExtensionType{Extension: runtime.NewEncodable(codec, &runtimetesting.ExtensionB{TestString: "bar"})}, + &runtimetesting.InternalExtensionType{ + Extension: &runtime.Unknown{ + Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}`), + ContentType: runtime.ContentTypeJSON, + }, + }, + // apiVersion is set in the serialized object for easier consumption by clients + `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}} +`, + }, { + &runtimetesting.InternalExtensionType{Extension: nil}, + &runtimetesting.InternalExtensionType{ + Extension: nil, + }, + `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":null} +`, + }, + } + + for i, item := range table { + gotEncoded, err := runtime.Encode(codec, item.obj) + if err != nil { + t.Errorf("unexpected error '%v' (%#v)", err, item.obj) + } else if e, a := item.encoded, string(gotEncoded); e != a { + t.Errorf("expected\n%#v\ngot\n%#v\n", e, a) + } + + gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) + if err != nil { + t.Errorf("unexpected error '%v' (%v)", err, item.encoded) + } else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) { + t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a)) + } + } +} + +func TestEncode(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + internalGVK := internalGV.WithKind("Simple") + externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} + externalGVK := externalGV.WithKind("Simple") + + scheme := runtime.NewScheme() + scheme.AddKnownTypeWithName(internalGVK, &runtimetesting.InternalSimple{}) + scheme.AddKnownTypeWithName(externalGVK, &runtimetesting.ExternalSimple{}) + + codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) + + test := &runtimetesting.InternalSimple{ + TestString: "I'm the same", + } + obj := runtime.Object(test) + data, err := runtime.Encode(codec, obj) + obj2, gvk, err2 := codec.Decode(data, nil, nil) + if err != nil || err2 != nil { + t.Fatalf("Failure: '%v' '%v'", err, err2) + } + if _, ok := obj2.(*runtimetesting.InternalSimple); !ok { + t.Fatalf("Got wrong type") + } + if !reflect.DeepEqual(obj2, test) { + t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2) + } + if *gvk != externalGVK { + t.Errorf("unexpected gvk returned by decode: %#v", *gvk) + } +} + +func TestUnversionedTypes(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + internalGVK := internalGV.WithKind("Simple") + externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} + externalGVK := externalGV.WithKind("Simple") + otherGV := schema.GroupVersion{Group: "group", Version: "other"} + + scheme := runtime.NewScheme() + scheme.AddUnversionedTypes(externalGV, &runtimetesting.InternalSimple{}) + scheme.AddKnownTypeWithName(internalGVK, &runtimetesting.InternalSimple{}) + scheme.AddKnownTypeWithName(externalGVK, &runtimetesting.ExternalSimple{}) + scheme.AddKnownTypeWithName(otherGV.WithKind("Simple"), &runtimetesting.ExternalSimple{}) + + codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) + + if unv, ok := scheme.IsUnversioned(&runtimetesting.InternalSimple{}); !unv || !ok { + t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok) + } + + kinds, _, err := scheme.ObjectKinds(&runtimetesting.InternalSimple{}) + if err != nil { + t.Fatal(err) + } + kind := kinds[0] + if kind != externalGV.WithKind("InternalSimple") { + t.Fatalf("unexpected: %#v", kind) + } + + test := &runtimetesting.InternalSimple{ + TestString: "I'm the same", + } + obj := runtime.Object(test) + data, err := runtime.Encode(codec, obj) + if err != nil { + t.Fatal(err) + } + obj2, gvk, err := codec.Decode(data, nil, nil) + if err != nil { + t.Fatal(err) + } + if _, ok := obj2.(*runtimetesting.InternalSimple); !ok { + t.Fatalf("Got wrong type") + } + if !reflect.DeepEqual(obj2, test) { + t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2) + } + // object is serialized as an unversioned object (in the group and version it was defined in) + if *gvk != externalGV.WithKind("InternalSimple") { + t.Errorf("unexpected gvk returned by decode: %#v", *gvk) + } + + // when serialized to a different group, the object is kept in its preferred name + codec = serializer.NewCodecFactory(scheme).LegacyCodec(otherGV) + data, err = runtime.Encode(codec, obj) + if err != nil { + t.Fatal(err) + } + if string(data) != `{"apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"}`+"\n" { + t.Errorf("unexpected data: %s", data) + } +} + +// Returns a new Scheme set up with the test objects. +func GetTestScheme() *runtime.Scheme { + internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Version: "v1"} + alternateExternalGV := schema.GroupVersion{Group: "custom", Version: "v1"} + alternateInternalGV := schema.GroupVersion{Group: "custom", Version: runtime.APIVersionInternal} + differentExternalGV := schema.GroupVersion{Group: "other", Version: "v2"} + + s := runtime.NewScheme() + // Ordinarily, we wouldn't add TestType2, but because this is a test and + // both types are from the same package, we need to get it into the system + // so that converter will match it with ExternalType2. + s.AddKnownTypes(internalGV, &runtimetesting.TestType1{}, &runtimetesting.TestType2{}, &runtimetesting.ExternalInternalSame{}) + s.AddKnownTypes(externalGV, &runtimetesting.ExternalInternalSame{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &runtimetesting.ExternalTestType2{}) + s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &runtimetesting.TestType1{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType4"), &runtimetesting.ExternalTestType1{}) + s.AddKnownTypeWithName(alternateInternalGV.WithKind("TestType3"), &runtimetesting.TestType1{}) + s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType3"), &runtimetesting.ExternalTestType1{}) + s.AddKnownTypeWithName(alternateExternalGV.WithKind("TestType5"), &runtimetesting.ExternalTestType1{}) + s.AddKnownTypeWithName(differentExternalGV.WithKind("TestType1"), &runtimetesting.ExternalTestType1{}) + s.AddUnversionedTypes(externalGV, &runtimetesting.UnversionedType{}) + + utilruntime.Must(s.AddConversionFuncs(func(in *runtimetesting.TestType1, out *runtimetesting.ExternalTestType1, s conversion.Scope) error { + out.A = in.A + return nil + })) + return s +} + +func TestKnownTypes(t *testing.T) { + s := GetTestScheme() + if len(s.KnownTypes(schema.GroupVersion{Group: "group", Version: "v2"})) != 0 { + t.Errorf("should have no known types for v2") + } + + types := s.KnownTypes(schema.GroupVersion{Version: "v1"}) + for _, s := range []string{"TestType1", "TestType2", "TestType3", "ExternalInternalSame"} { + if _, ok := types[s]; !ok { + t.Errorf("missing type %q", s) + } + } +} + +func TestAddKnownTypesIdemPotent(t *testing.T) { + s := runtime.NewScheme() + + gv := schema.GroupVersion{Group: "foo", Version: "v1"} + s.AddKnownTypes(gv, &runtimetesting.InternalSimple{}) + s.AddKnownTypes(gv, &runtimetesting.InternalSimple{}) + if len(s.KnownTypes(gv)) != 1 { + t.Errorf("expected only one %v type after double registration", gv) + } + if len(s.AllKnownTypes()) != 1 { + t.Errorf("expected only one type after double registration") + } + + s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{}) + s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{}) + if len(s.KnownTypes(gv)) != 1 { + t.Errorf("expected only one %v type after double registration with custom name", gv) + } + if len(s.AllKnownTypes()) != 1 { + t.Errorf("expected only one type after double registration with custom name") + } + + s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{}) + s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{}) + if len(s.KnownTypes(gv)) != 1 { + t.Errorf("expected only one %v type after double registration with custom name", gv) + } + if len(s.AllKnownTypes()) != 1 { + t.Errorf("expected only one type after double registration with custom name") + } + + kinds, _, err := s.ObjectKinds(&runtimetesting.InternalSimple{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(kinds) != 1 { + t.Errorf("expected only one kind for InternalSimple after double registration") + } +} + +// redefine InternalSimple with the same name, but obviously as a different type than in runtimetesting +type InternalSimple struct { + runtime.TypeMeta `json:",inline"` + TestString string `json:"testString"` +} + +func (s *InternalSimple) DeepCopyObject() runtime.Object { return nil } + +func TestConflictingAddKnownTypes(t *testing.T) { + s := runtime.NewScheme() + gv := schema.GroupVersion{Group: "foo", Version: "v1"} + + panicked := make(chan bool) + go func() { + defer func() { + if recover() != nil { + panicked <- true + } + }() + s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.InternalSimple{}) + s.AddKnownTypeWithName(gv.WithKind("InternalSimple"), &runtimetesting.ExternalSimple{}) + panicked <- false + }() + if !<-panicked { + t.Errorf("Expected AddKnownTypesWithName to panic with conflicting type registrations") + } + + go func() { + defer func() { + if recover() != nil { + panicked <- true + } + }() + + s.AddUnversionedTypes(gv, &runtimetesting.InternalSimple{}) + s.AddUnversionedTypes(gv, &InternalSimple{}) + panicked <- false + }() + if !<-panicked { + t.Errorf("Expected AddUnversionedTypes to panic with conflicting type registrations") + } +} + +func TestConvertToVersionBasic(t *testing.T) { + s := GetTestScheme() + tt := &runtimetesting.TestType1{A: "I'm not a pointer object"} + other, err := s.ConvertToVersion(tt, schema.GroupVersion{Version: "v1"}) + if err != nil { + t.Fatalf("Failure: %v", err) + } + converted, ok := other.(*runtimetesting.ExternalTestType1) + if !ok { + t.Fatalf("Got wrong type: %T", other) + } + if tt.A != converted.A { + t.Fatalf("Failed to convert object correctly: %#v", converted) + } +} + +type testGroupVersioner struct { + target schema.GroupVersionKind + ok bool +} + +func (m testGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (schema.GroupVersionKind, bool) { + return m.target, m.ok +} + +func TestConvertToVersion(t *testing.T) { + testCases := []struct { + scheme *runtime.Scheme + in runtime.Object + gv runtime.GroupVersioner + same bool + out runtime.Object + errFn func(error) bool + }{ + // errors if the type is not registered in the scheme + { + scheme: GetTestScheme(), + in: &runtimetesting.UnknownType{}, + errFn: func(err error) bool { return err != nil && runtime.IsNotRegisteredError(err) }, + }, + // errors if the group versioner returns no target + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: testGroupVersioner{}, + errFn: func(err error) bool { + return err != nil && strings.Contains(err.Error(), "is not suitable for converting") + }, + }, + // converts to internal + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: schema.GroupVersion{Version: runtime.APIVersionInternal}, + out: &runtimetesting.TestType1{A: "test"}, + }, + // converts from unstructured to internal + { + scheme: GetTestScheme(), + in: &runtimetesting.Unstructured{Object: map[string]interface{}{ + "apiVersion": "custom/v1", + "kind": "TestType3", + "A": "test", + }}, + gv: schema.GroupVersion{Version: runtime.APIVersionInternal}, + out: &runtimetesting.TestType1{A: "test"}, + }, + // converts from unstructured to external + { + scheme: GetTestScheme(), + in: &runtimetesting.Unstructured{Object: map[string]interface{}{ + "apiVersion": "custom/v1", + "kind": "TestType3", + "A": "test", + }}, + gv: schema.GroupVersion{Group: "custom", Version: "v1"}, + out: &runtimetesting.ExternalTestType1{MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"}, A: "test"}, + }, + // prefers the best match + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: schema.GroupVersions{{Version: runtime.APIVersionInternal}, {Version: "v1"}}, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // unversioned type returned as-is + { + scheme: GetTestScheme(), + in: &runtimetesting.UnversionedType{A: "test"}, + gv: schema.GroupVersions{{Version: "v1"}}, + same: true, + out: &runtimetesting.UnversionedType{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"}, + A: "test", + }, + }, + // unversioned type returned when not included in the target types + { + scheme: GetTestScheme(), + in: &runtimetesting.UnversionedType{A: "test"}, + gv: schema.GroupVersions{{Group: "other", Version: "v2"}}, + same: true, + out: &runtimetesting.UnversionedType{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "UnversionedType"}, + A: "test", + }, + }, + // detected as already being in the target version + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: schema.GroupVersions{{Version: "v1"}}, + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // detected as already being in the first target version + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: schema.GroupVersions{{Version: "v1"}, {Version: runtime.APIVersionInternal}}, + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // detected as already being in the first target version + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: schema.GroupVersions{{Version: "v1"}, {Version: runtime.APIVersionInternal}}, + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (1/3): different kind + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Version: "v1"}}, + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"}, + A: "test", + }, + }, + // the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (2/3): different gv + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType3", Group: "custom", Version: "v1"}}, + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType3"}, + A: "test", + }, + }, + // the external type is registered in multiple groups, versions, and kinds, and can be targeted to all of them (3/3): different gvk + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Group: "custom", Version: "v1", Kind: "TestType5"}}, + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"}, + A: "test", + }, + }, + // multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}), + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // multi group versioner recognizes multiple groups and forces the output to a particular version, copies because version differs + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "other", Version: "v2"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}), + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "other/v2", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // multi group versioner is unable to find a match when kind AND group don't match (there is no TestType1 kind in group "other", and no kind "TestType5" in the default group) + { + scheme: GetTestScheme(), + in: &runtimetesting.TestType1{A: "test"}, + gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "custom", Version: "v1"}, schema.GroupKind{Group: "other"}, schema.GroupKind{Kind: "TestType5"}), + errFn: func(err error) bool { + return err != nil && strings.Contains(err.Error(), "is not suitable for converting") + }, + }, + // multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}, schema.GroupKind{Kind: "TestType1"}), + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // multi group versioner recognizes multiple groups and forces the output to a particular version, performs no copy + { + scheme: GetTestScheme(), + in: &runtimetesting.ExternalTestType1{A: "test"}, + gv: runtime.NewMultiGroupVersioner(schema.GroupVersion{Group: "", Version: "v1"}, schema.GroupKind{Kind: "TestType1"}, schema.GroupKind{Group: "custom", Kind: "TestType3"}), + same: true, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType1"}, + A: "test", + }, + }, + // group versioner can choose a particular target kind for a given input when kind is the same across group versions + { + scheme: GetTestScheme(), + in: &runtimetesting.TestType1{A: "test"}, + gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Version: "v1", Kind: "TestType3"}}, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "v1", ObjectKind: "TestType3"}, + A: "test", + }, + }, + // group versioner can choose a different kind + { + scheme: GetTestScheme(), + in: &runtimetesting.TestType1{A: "test"}, + gv: testGroupVersioner{ok: true, target: schema.GroupVersionKind{Kind: "TestType5", Group: "custom", Version: "v1"}}, + out: &runtimetesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: runtimetesting.MyWeirdCustomEmbeddedVersionKindField{APIVersion: "custom/v1", ObjectKind: "TestType5"}, + A: "test", + }, + }, + } + for i, test := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + original := test.in.DeepCopyObject() + out, err := test.scheme.ConvertToVersion(test.in, test.gv) + switch { + case test.errFn != nil: + if !test.errFn(err) { + t.Fatalf("unexpected error: %v", err) + } + return + case err != nil: + t.Fatalf("unexpected error: %v", err) + } + if out == test.in { + t.Fatalf("ConvertToVersion should always copy out: %#v", out) + } + + if test.same { + if !reflect.DeepEqual(original, test.in) { + t.Fatalf("unexpected mutation of input: %s", diff.ObjectReflectDiff(original, test.in)) + } + if !reflect.DeepEqual(out, test.out) { + t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(out, test.out)) + } + unsafe, err := test.scheme.UnsafeConvertToVersion(test.in, test.gv) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(unsafe, test.out) { + t.Fatalf("unexpected unsafe: %s", diff.ObjectReflectDiff(unsafe, test.out)) + } + if unsafe != test.in { + t.Fatalf("UnsafeConvertToVersion should return same object: %#v", unsafe) + } + return + } + if !reflect.DeepEqual(out, test.out) { + t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(out, test.out)) + } + }) + } +} + +func TestConvert(t *testing.T) { + testCases := []struct { + scheme *runtime.Scheme + in runtime.Object + into runtime.Object + gv runtime.GroupVersioner + out runtime.Object + errFn func(error) bool + }{ + // converts from internal to unstructured, given a target version + { + scheme: GetTestScheme(), + in: &runtimetesting.TestType1{A: "test"}, + into: &runtimetesting.Unstructured{}, + out: &runtimetesting.Unstructured{Object: map[string]interface{}{ + "myVersionKey": "custom/v1", + "myKindKey": "TestType3", + "A": "test", + }}, + gv: schema.GroupVersion{Group: "custom", Version: "v1"}, + }, + } + for i, test := range testCases { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + err := test.scheme.Convert(test.in, test.into, test.gv) + switch { + case test.errFn != nil: + if !test.errFn(err) { + t.Fatalf("unexpected error: %v", err) + } + return + case err != nil: + t.Fatalf("unexpected error: %v", err) + return + } + + if !reflect.DeepEqual(test.into, test.out) { + t.Fatalf("unexpected out: %s", diff.ObjectReflectDiff(test.into, test.out)) + } + }) + } +} + +func TestMetaValues(t *testing.T) { + internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Group: "test.group", Version: "externalVersion"} + + s := runtime.NewScheme() + s.AddKnownTypeWithName(internalGV.WithKind("Simple"), &runtimetesting.InternalSimple{}) + s.AddKnownTypeWithName(externalGV.WithKind("Simple"), &runtimetesting.ExternalSimple{}) + + internalToExternalCalls := 0 + externalToInternalCalls := 0 + + // Register functions to verify that scope.Meta() gets set correctly. + err := s.AddConversionFuncs( + func(in *runtimetesting.InternalSimple, out *runtimetesting.ExternalSimple, scope conversion.Scope) error { + t.Logf("internal -> external") + scope.Convert(&in.TestString, &out.TestString, 0) + internalToExternalCalls++ + return nil + }, + func(in *runtimetesting.ExternalSimple, out *runtimetesting.InternalSimple, scope conversion.Scope) error { + t.Logf("external -> internal") + scope.Convert(&in.TestString, &out.TestString, 0) + externalToInternalCalls++ + return nil + }, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + simple := &runtimetesting.InternalSimple{ + TestString: "foo", + } + + s.Log(t) + + out, err := s.ConvertToVersion(simple, externalGV) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + internal, err := s.ConvertToVersion(out, internalGV) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if e, a := simple, internal; !reflect.DeepEqual(e, a) { + t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) + } + + if e, a := 1, internalToExternalCalls; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + if e, a := 1, externalToInternalCalls; e != a { + t.Errorf("Expected %v, got %v", e, a) + } +} + +func TestMetaValuesUnregisteredConvert(t *testing.T) { + type InternalSimple struct { + Version string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + TestString string `json:"testString"` + } + type ExternalSimple struct { + Version string `json:"apiVersion,omitempty"` + Kind string `json:"kind,omitempty"` + TestString string `json:"testString"` + } + s := runtime.NewScheme() + // We deliberately don't register the types. + + internalToExternalCalls := 0 + + // Register functions to verify that scope.Meta() gets set correctly. + err := s.AddConversionFuncs( + func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error { + scope.Convert(&in.TestString, &out.TestString, 0) + internalToExternalCalls++ + return nil + }, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + simple := &InternalSimple{TestString: "foo"} + external := &ExternalSimple{} + err = s.Convert(simple, external, nil) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if e, a := simple.TestString, external.TestString; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + + // Verify that our conversion handler got called. + if e, a := 1, internalToExternalCalls; e != a { + t.Errorf("Expected %v, got %v", e, a) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_test.go new file mode 100644 index 000000000..d27da113a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_test.go @@ -0,0 +1,339 @@ +/* +Copyright 2014 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 serializer + +import ( + "encoding/json" + "fmt" + "log" + "os" + "reflect" + "strings" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + serializertesting "k8s.io/apimachinery/pkg/runtime/serializer/testing" + "k8s.io/apimachinery/pkg/util/diff" + + "github.com/ghodss/yaml" + "github.com/google/gofuzz" + flag "github.com/spf13/pflag" +) + +var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.") + +type testMetaFactory struct{} + +func (testMetaFactory) Interpret(data []byte) (*schema.GroupVersionKind, error) { + findKind := struct { + APIVersion string `json:"myVersionKey,omitempty"` + ObjectKind string `json:"myKindKey,omitempty"` + }{} + // yaml is a superset of json, so we use it to decode here. That way, + // we understand both. + if err := yaml.Unmarshal(data, &findKind); err != nil { + return nil, fmt.Errorf("couldn't get version/kind: %v", err) + } + gv, err := schema.ParseGroupVersion(findKind.APIVersion) + if err != nil { + return nil, err + } + return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: findKind.ObjectKind}, nil +} + +// TestObjectFuzzer can randomly populate all the above objects. +var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs( + func(j *serializertesting.MyWeirdCustomEmbeddedVersionKindField, c fuzz.Continue) { + c.FuzzNoCustom(j) + j.APIVersion = "" + j.ObjectKind = "" + }, +) + +// Returns a new Scheme set up with the test objects. +func GetTestScheme() (*runtime.Scheme, runtime.Codec) { + internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Version: "v1"} + externalGV2 := schema.GroupVersion{Version: "v2"} + + s := runtime.NewScheme() + // Ordinarily, we wouldn't add TestType2, but because this is a test and + // both types are from the same package, we need to get it into the system + // so that converter will match it with ExternalType2. + s.AddKnownTypes(internalGV, &serializertesting.TestType1{}, &serializertesting.TestType2{}, &serializertesting.ExternalInternalSame{}) + s.AddKnownTypes(externalGV, &serializertesting.ExternalInternalSame{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &serializertesting.ExternalTestType1{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType2"), &serializertesting.ExternalTestType2{}) + s.AddKnownTypeWithName(internalGV.WithKind("TestType3"), &serializertesting.TestType1{}) + s.AddKnownTypeWithName(externalGV.WithKind("TestType3"), &serializertesting.ExternalTestType1{}) + s.AddKnownTypeWithName(externalGV2.WithKind("TestType1"), &serializertesting.ExternalTestType1{}) + + s.AddUnversionedTypes(externalGV, &metav1.Status{}) + + cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{})) + codec := cf.LegacyCodec(schema.GroupVersion{Version: "v1"}) + return s, codec +} + +var semantic = conversion.EqualitiesOrDie( + func(a, b serializertesting.MyWeirdCustomEmbeddedVersionKindField) bool { + a.APIVersion, a.ObjectKind = "", "" + b.APIVersion, b.ObjectKind = "", "" + return a == b + }, +) + +func runTest(t *testing.T, source interface{}) { + name := reflect.TypeOf(source).Elem().Name() + TestObjectFuzzer.Fuzz(source) + + _, codec := GetTestScheme() + data, err := runtime.Encode(codec, source.(runtime.Object)) + if err != nil { + t.Errorf("%v: %v (%#v)", name, err, source) + return + } + obj2, err := runtime.Decode(codec, data) + if err != nil { + t.Errorf("%v: %v (%v)", name, err, string(data)) + return + } + if !semantic.DeepEqual(source, obj2) { + t.Errorf("1: %v: diff: %v", name, diff.ObjectGoPrintSideBySide(source, obj2)) + return + } + obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface() + if err := runtime.DecodeInto(codec, data, obj3.(runtime.Object)); err != nil { + t.Errorf("2: %v: %v", name, err) + return + } + if !semantic.DeepEqual(source, obj3) { + t.Errorf("3: %v: diff: %v", name, diff.ObjectDiff(source, obj3)) + return + } +} + +func TestTypes(t *testing.T) { + table := []interface{}{ + &serializertesting.TestType1{}, + &serializertesting.ExternalInternalSame{}, + } + for _, item := range table { + // Try a few times, since runTest uses random values. + for i := 0; i < *fuzzIters; i++ { + runTest(t, item) + } + } +} + +func TestVersionedEncoding(t *testing.T) { + s, _ := GetTestScheme() + cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{})) + info, _ := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON) + encoder := info.Serializer + + codec := cf.CodecForVersions(encoder, nil, schema.GroupVersion{Version: "v2"}, nil) + out, err := runtime.Encode(codec, &serializertesting.TestType1{}) + if err != nil { + t.Fatal(err) + } + if string(out) != `{"myVersionKey":"v2","myKindKey":"TestType1"}`+"\n" { + t.Fatal(string(out)) + } + + codec = cf.CodecForVersions(encoder, nil, schema.GroupVersion{Version: "v3"}, nil) + _, err = runtime.Encode(codec, &serializertesting.TestType1{}) + if err == nil { + t.Fatal(err) + } + + // unversioned encode with no versions is written directly to wire + codec = cf.CodecForVersions(encoder, nil, runtime.InternalGroupVersioner, nil) + out, err = runtime.Encode(codec, &serializertesting.TestType1{}) + if err != nil { + t.Fatal(err) + } + if string(out) != `{}`+"\n" { + t.Fatal(string(out)) + } +} + +func TestMultipleNames(t *testing.T) { + _, codec := GetTestScheme() + + obj, _, err := codec.Decode([]byte(`{"myKindKey":"TestType3","myVersionKey":"v1","A":"value"}`), nil, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + internal := obj.(*serializertesting.TestType1) + if internal.A != "value" { + t.Fatalf("unexpected decoded object: %#v", internal) + } + + out, err := runtime.Encode(codec, internal) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !strings.Contains(string(out), `"myKindKey":"TestType1"`) { + t.Errorf("unexpected encoded output: %s", string(out)) + } +} + +func TestConvertTypesWhenDefaultNamesMatch(t *testing.T) { + internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Version: "v1"} + + s := runtime.NewScheme() + // create two names internally, with TestType1 being preferred + s.AddKnownTypeWithName(internalGV.WithKind("TestType1"), &serializertesting.TestType1{}) + s.AddKnownTypeWithName(internalGV.WithKind("OtherType1"), &serializertesting.TestType1{}) + // create two names externally, with TestType1 being preferred + s.AddKnownTypeWithName(externalGV.WithKind("TestType1"), &serializertesting.ExternalTestType1{}) + s.AddKnownTypeWithName(externalGV.WithKind("OtherType1"), &serializertesting.ExternalTestType1{}) + + ext := &serializertesting.ExternalTestType1{} + ext.APIVersion = "v1" + ext.ObjectKind = "OtherType1" + ext.A = "test" + data, err := json.Marshal(ext) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expect := &serializertesting.TestType1{A: "test"} + + codec := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{})).LegacyCodec(schema.GroupVersion{Version: "v1"}) + + obj, err := runtime.Decode(codec, data) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !semantic.DeepEqual(expect, obj) { + t.Errorf("unexpected object: %#v", obj) + } + + into := &serializertesting.TestType1{} + if err := runtime.DecodeInto(codec, data, into); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !semantic.DeepEqual(expect, into) { + t.Errorf("unexpected object: %#v", obj) + } +} + +func TestEncode_Ptr(t *testing.T) { + _, codec := GetTestScheme() + tt := &serializertesting.TestType1{A: "I am a pointer object"} + data, err := runtime.Encode(codec, tt) + obj2, err2 := runtime.Decode(codec, data) + if err != nil || err2 != nil { + t.Fatalf("Failure: '%v' '%v'\n%s", err, err2, data) + } + if _, ok := obj2.(*serializertesting.TestType1); !ok { + t.Fatalf("Got wrong type") + } + if !semantic.DeepEqual(obj2, tt) { + t.Errorf("Expected:\n %#v,\n Got:\n %#v", tt, obj2) + } +} + +func TestBadJSONRejection(t *testing.T) { + log.SetOutput(os.Stderr) + _, codec := GetTestScheme() + badJSONs := [][]byte{ + []byte(`{"myVersionKey":"v1"}`), // Missing kind + []byte(`{"myVersionKey":"v1","myKindKey":"bar"}`), // Unknown kind + []byte(`{"myVersionKey":"bar","myKindKey":"TestType1"}`), // Unknown version + []byte(`{"myKindKey":"TestType1"}`), // Missing version + } + for _, b := range badJSONs { + if _, err := runtime.Decode(codec, b); err == nil { + t.Errorf("Did not reject bad json: %s", string(b)) + } + } + badJSONKindMismatch := []byte(`{"myVersionKey":"v1","myKindKey":"ExternalInternalSame"}`) + if err := runtime.DecodeInto(codec, badJSONKindMismatch, &serializertesting.TestType1{}); err == nil { + t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch) + } + if err := runtime.DecodeInto(codec, []byte(``), &serializertesting.TestType1{}); err != nil { + t.Errorf("Should allow empty decode: %v", err) + } + if _, _, err := codec.Decode([]byte(``), &schema.GroupVersionKind{Kind: "ExternalInternalSame"}, nil); err == nil { + t.Errorf("Did not give error for empty data with only kind default") + } + if _, _, err := codec.Decode([]byte(`{"myVersionKey":"v1"}`), &schema.GroupVersionKind{Kind: "ExternalInternalSame"}, nil); err != nil { + t.Errorf("Gave error for version and kind default") + } + if _, _, err := codec.Decode([]byte(`{"myKindKey":"ExternalInternalSame"}`), &schema.GroupVersionKind{Version: "v1"}, nil); err != nil { + t.Errorf("Gave error for version and kind default") + } + if _, _, err := codec.Decode([]byte(``), &schema.GroupVersionKind{Kind: "ExternalInternalSame", Version: "v1"}, nil); err != nil { + t.Errorf("Gave error for version and kind defaulted: %v", err) + } + if _, err := runtime.Decode(codec, []byte(``)); err == nil { + t.Errorf("Did not give error for empty data") + } +} + +// Returns a new Scheme set up with the test objects needed by TestDirectCodec. +func GetDirectCodecTestScheme() *runtime.Scheme { + internalGV := schema.GroupVersion{Version: runtime.APIVersionInternal} + externalGV := schema.GroupVersion{Version: "v1"} + + s := runtime.NewScheme() + // Ordinarily, we wouldn't add TestType2, but because this is a test and + // both types are from the same package, we need to get it into the system + // so that converter will match it with ExternalType2. + s.AddKnownTypes(internalGV, &serializertesting.TestType1{}) + s.AddKnownTypes(externalGV, &serializertesting.ExternalTestType1{}) + + s.AddUnversionedTypes(externalGV, &metav1.Status{}) + return s +} + +func TestDirectCodec(t *testing.T) { + s := GetDirectCodecTestScheme() + cf := newCodecFactory(s, newSerializersForScheme(s, testMetaFactory{})) + info, _ := runtime.SerializerInfoForMediaType(cf.SupportedMediaTypes(), runtime.ContentTypeJSON) + serializer := info.Serializer + df := DirectCodecFactory{cf} + ignoredGV, err := schema.ParseGroupVersion("ignored group/ignored version") + if err != nil { + t.Fatal(err) + } + directEncoder := df.EncoderForVersion(serializer, ignoredGV) + directDecoder := df.DecoderToVersion(serializer, ignoredGV) + out, err := runtime.Encode(directEncoder, &serializertesting.ExternalTestType1{}) + if err != nil { + t.Fatal(err) + } + if string(out) != `{"myVersionKey":"v1","myKindKey":"ExternalTestType1"}`+"\n" { + t.Fatal(string(out)) + } + a, _, err := directDecoder.Decode(out, nil, nil) + e := &serializertesting.ExternalTestType1{ + MyWeirdCustomEmbeddedVersionKindField: serializertesting.MyWeirdCustomEmbeddedVersionKindField{ + APIVersion: "v1", + ObjectKind: "ExternalTestType1", + }, + } + if !semantic.DeepEqual(e, a) { + t.Fatalf("expect %v, got %v", e, a) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go new file mode 100644 index 000000000..7f358da68 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json_test.go @@ -0,0 +1,346 @@ +/* +Copyright 2015 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 json_test + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer/json" + "k8s.io/apimachinery/pkg/util/diff" +) + +type testDecodable struct { + Other string + Value int `json:"value"` + Spec DecodableSpec `json:"spec"` + Interface interface{} `json:"interface"` + gvk schema.GroupVersionKind +} + +// DecodableSpec has 15 fields. json-iterator treats struct with more than 10 +// fields differently from struct that has less than 10 fields. +type DecodableSpec struct { + A int `json:"A"` + B int `json:"B"` + C int `json:"C"` + D int `json:"D"` + E int `json:"E"` + F int `json:"F"` + G int `json:"G"` + H int `json:"h"` + I int `json:"i"` + J int `json:"j"` + K int `json:"k"` + L int `json:"l"` + M int `json:"m"` + N int `json:"n"` + O int `json:"o"` +} + +func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d } +func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk } +func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk } +func (d *testDecodable) DeepCopyObject() runtime.Object { + panic("testDecodable does not support DeepCopy") +} + +func TestDecode(t *testing.T) { + testCases := []struct { + creater runtime.ObjectCreater + typer runtime.ObjectTyper + yaml bool + pretty bool + + data []byte + defaultGVK *schema.GroupVersionKind + into runtime.Object + + errFn func(error) bool + expectedObject runtime.Object + expectedGVK *schema.GroupVersionKind + }{ + { + data: []byte("{}"), + + expectedGVK: &schema.GroupVersionKind{}, + errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'Kind' is missing in") }, + }, + { + data: []byte("{}"), + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + creater: &mockCreater{err: fmt.Errorf("fake error")}, + + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + errFn: func(err error) bool { return err.Error() == "fake error" }, + }, + { + data: []byte("{}"), + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + creater: &mockCreater{obj: &testDecodable{}}, + expectedObject: &testDecodable{}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + }, + + // version without group is not defaulted + { + data: []byte(`{"apiVersion":"blah"}`), + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + creater: &mockCreater{obj: &testDecodable{}}, + expectedObject: &testDecodable{}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"}, + }, + // group without version is defaulted + { + data: []byte(`{"apiVersion":"other/"}`), + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + creater: &mockCreater{obj: &testDecodable{}}, + expectedObject: &testDecodable{}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + }, + // group version, kind is defaulted + { + data: []byte(`{"apiVersion":"other1/blah1"}`), + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + creater: &mockCreater{obj: &testDecodable{}}, + expectedObject: &testDecodable{}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other1", Version: "blah1"}, + }, + // gvk all provided then not defaulted at all + { + data: []byte(`{"kind":"Test","apiVersion":"other/blah"}`), + defaultGVK: &schema.GroupVersionKind{Kind: "Test1", Group: "other1", Version: "blah1"}, + creater: &mockCreater{obj: &testDecodable{}}, + expectedObject: &testDecodable{}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + }, + //gvk defaulting if kind not provided in data and defaultGVK use into's kind + { + data: []byte(`{"apiVersion":"b1/c1"}`), + into: &testDecodable{gvk: schema.GroupVersionKind{Kind: "a3", Group: "b1", Version: "c1"}}, + typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "a3", Group: "b1", Version: "c1"}}, + defaultGVK: nil, + creater: &mockCreater{obj: &testDecodable{}}, + expectedObject: &testDecodable{gvk: schema.GroupVersionKind{Kind: "a3", Group: "b1", Version: "c1"}}, + expectedGVK: &schema.GroupVersionKind{Kind: "a3", Group: "b1", Version: "c1"}, + }, + + // accept runtime.Unknown as into and bypass creator + { + data: []byte(`{}`), + into: &runtime.Unknown{}, + + expectedGVK: &schema.GroupVersionKind{}, + expectedObject: &runtime.Unknown{ + Raw: []byte(`{}`), + ContentType: runtime.ContentTypeJSON, + }, + }, + { + data: []byte(`{"test":"object"}`), + into: &runtime.Unknown{}, + + expectedGVK: &schema.GroupVersionKind{}, + expectedObject: &runtime.Unknown{ + Raw: []byte(`{"test":"object"}`), + ContentType: runtime.ContentTypeJSON, + }, + }, + { + data: []byte(`{"test":"object"}`), + into: &runtime.Unknown{}, + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &runtime.Unknown{ + TypeMeta: runtime.TypeMeta{APIVersion: "other/blah", Kind: "Test"}, + Raw: []byte(`{"test":"object"}`), + ContentType: runtime.ContentTypeJSON, + }, + }, + + // unregistered objects can be decoded into directly + { + data: []byte(`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`), + into: &testDecodable{}, + typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind("mock", schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &testDecodable{ + Other: "test", + Value: 1, + }, + }, + // registered types get defaulted by the into object kind + { + data: []byte(`{"value":1,"Other":"test"}`), + into: &testDecodable{}, + typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &testDecodable{ + Other: "test", + Value: 1, + }, + }, + // registered types get defaulted by the into object kind even without version, but return an error + { + data: []byte(`{"value":1,"Other":"test"}`), + into: &testDecodable{}, + typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}, + errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'apiVersion' is missing in") }, + expectedObject: &testDecodable{ + Other: "test", + Value: 1, + }, + }, + + // runtime.VersionedObjects are decoded + { + data: []byte(`{"value":1,"Other":"test"}`), + into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, + creater: &mockCreater{obj: &testDecodable{}}, + typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}}, + defaultGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &runtime.VersionedObjects{ + Objects: []runtime.Object{ + &testDecodable{ + Other: "test", + Value: 1, + }, + }, + }, + }, + // runtime.VersionedObjects with an object are decoded into + { + data: []byte(`{"Other":"test"}`), + into: &runtime.VersionedObjects{Objects: []runtime.Object{&testDecodable{Value: 2}}}, + typer: &mockTyper{gvk: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &runtime.VersionedObjects{ + Objects: []runtime.Object{ + &testDecodable{ + Other: "test", + Value: 2, + }, + }, + }, + }, + // Error on invalid number + { + data: []byte(`{"kind":"Test","apiVersion":"other/blah","interface":1e1000}`), + creater: &mockCreater{obj: &testDecodable{}}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + errFn: func(err error) bool { + return strings.Contains(err.Error(), `json_test.testDecodable.Interface: DecodeNumber: strconv.ParseFloat: parsing "1e1000": value out of range`) + }, + }, + // Unmarshalling is case-sensitive + { + // "VaLue" should have been "value" + data: []byte(`{"kind":"Test","apiVersion":"other/blah","VaLue":1,"Other":"test"}`), + into: &testDecodable{}, + typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind("mock", schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &testDecodable{ + Other: "test", + }, + }, + // Unmarshalling is case-sensitive for big struct. + { + // "b" should have been "B", "I" should have been "i" + data: []byte(`{"kind":"Test","apiVersion":"other/blah","spec": {"A": 1, "b": 2, "h": 3, "I": 4}}`), + into: &testDecodable{}, + typer: &mockTyper{err: runtime.NewNotRegisteredErrForKind("mock", schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"})}, + expectedGVK: &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, + expectedObject: &testDecodable{ + Spec: DecodableSpec{A: 1, H: 3}, + }, + }, + } + + for i, test := range testCases { + var s runtime.Serializer + if test.yaml { + s = json.NewYAMLSerializer(json.DefaultMetaFactory, test.creater, test.typer) + } else { + s = json.NewSerializer(json.DefaultMetaFactory, test.creater, test.typer, test.pretty) + } + obj, gvk, err := s.Decode([]byte(test.data), test.defaultGVK, test.into) + + if !reflect.DeepEqual(test.expectedGVK, gvk) { + t.Errorf("%d: unexpected GVK: %v", i, gvk) + } + + switch { + case err == nil && test.errFn != nil: + t.Errorf("%d: failed: %v", i, err) + continue + case err != nil && test.errFn == nil: + t.Errorf("%d: failed: %v", i, err) + continue + case err != nil: + if !test.errFn(err) { + t.Errorf("%d: failed: %v", i, err) + } + if obj != nil { + t.Errorf("%d: should have returned nil object", i) + } + continue + } + + if test.into != nil && test.into != obj { + t.Errorf("%d: expected into to be returned: %v", i, obj) + continue + } + + if !reflect.DeepEqual(test.expectedObject, obj) { + t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj)) + } + } +} + +type mockCreater struct { + apiVersion string + kind string + err error + obj runtime.Object +} + +func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) { + c.apiVersion, c.kind = kind.GroupVersion().String(), kind.Kind + return c.obj, c.err +} + +type mockTyper struct { + gvk *schema.GroupVersionKind + err error +} + +func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) { + if t.gvk == nil { + return nil, false, t.err + } + return []schema.GroupVersionKind{*t.gvk}, false, t.err +} + +func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool { + return false +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta_test.go new file mode 100644 index 000000000..f4e34a22d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/meta_test.go @@ -0,0 +1,45 @@ +/* +Copyright 2014 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 json + +import "testing" + +func TestSimpleMetaFactoryInterpret(t *testing.T) { + factory := SimpleMetaFactory{} + gvk, err := factory.Interpret([]byte(`{"apiVersion":"1","kind":"object"}`)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gvk.Version != "1" || gvk.Kind != "object" { + t.Errorf("unexpected interpret: %#v", gvk) + } + + // no kind or version + gvk, err = factory.Interpret([]byte(`{}`)) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gvk.Version != "" || gvk.Kind != "" { + t.Errorf("unexpected interpret: %#v", gvk) + } + + // unparsable + gvk, err = factory.Interpret([]byte(`{`)) + if err == nil { + t.Errorf("unexpected non-error") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/sparse_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/sparse_test.go new file mode 100644 index 000000000..3bc9d13bb --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/sparse_test.go @@ -0,0 +1,91 @@ +/* +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. +*/ + +package serializer + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" +) + +type FakeV1Obj struct { + metav1.TypeMeta + metav1.ObjectMeta +} + +func (*FakeV1Obj) DeepCopyObject() runtime.Object { + panic("not supported") +} + +type FakeV2DifferentObj struct { + metav1.TypeMeta + metav1.ObjectMeta +} + +func (*FakeV2DifferentObj) DeepCopyObject() runtime.Object { + panic("not supported") +} +func TestSparse(t *testing.T) { + v1 := schema.GroupVersion{Group: "mygroup", Version: "v1"} + v2 := schema.GroupVersion{Group: "mygroup", Version: "v2"} + + scheme := runtime.NewScheme() + scheme.AddKnownTypes(v1, &FakeV1Obj{}) + scheme.AddKnownTypes(v2, &FakeV2DifferentObj{}) + codecs := NewCodecFactory(scheme) + + srcObj1 := &FakeV1Obj{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + srcObj2 := &FakeV2DifferentObj{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + + encoder := codecs.LegacyCodec(v2, v1) + decoder := codecs.UniversalDecoder(v2, v1) + + srcObj1Bytes, err := runtime.Encode(encoder, srcObj1) + if err != nil { + t.Fatal(err) + } + t.Log(string(srcObj1Bytes)) + srcObj2Bytes, err := runtime.Encode(encoder, srcObj2) + if err != nil { + t.Fatal(err) + } + t.Log(string(srcObj2Bytes)) + + uncastDstObj1, err := runtime.Decode(decoder, srcObj1Bytes) + if err != nil { + t.Fatal(err) + } + uncastDstObj2, err := runtime.Decode(decoder, srcObj2Bytes) + if err != nil { + t.Fatal(err) + } + + // clear typemeta + uncastDstObj1.(*FakeV1Obj).TypeMeta = metav1.TypeMeta{} + uncastDstObj2.(*FakeV2DifferentObj).TypeMeta = metav1.TypeMeta{} + + if !equality.Semantic.DeepEqual(srcObj1, uncastDstObj1) { + t.Fatal(diff.ObjectDiff(srcObj1, uncastDstObj1)) + } + if !equality.Semantic.DeepEqual(srcObj2, uncastDstObj2) { + t.Fatal(diff.ObjectDiff(srcObj2, uncastDstObj2)) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming/streaming_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming/streaming_test.go new file mode 100644 index 000000000..9cae6a32c --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming/streaming_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2016 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 streaming + +import ( + "bytes" + "io" + "io/ioutil" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/framer" +) + +type fakeDecoder struct { + got []byte + obj runtime.Object + err error +} + +func (d *fakeDecoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { + d.got = data + return d.obj, nil, d.err +} + +func TestEmptyDecoder(t *testing.T) { + buf := bytes.NewBuffer([]byte{}) + d := &fakeDecoder{} + _, _, err := NewDecoder(ioutil.NopCloser(buf), d).Decode(nil, nil) + if err != io.EOF { + t.Fatal(err) + } +} + +func TestDecoder(t *testing.T) { + frames := [][]byte{ + make([]byte, 1025), + make([]byte, 1024*5), + make([]byte, 1024*1024*5), + make([]byte, 1025), + } + pr, pw := io.Pipe() + fw := framer.NewLengthDelimitedFrameWriter(pw) + go func() { + for i := range frames { + fw.Write(frames[i]) + } + pw.Close() + }() + + r := framer.NewLengthDelimitedFrameReader(pr) + d := &fakeDecoder{} + dec := NewDecoder(r, d) + if _, _, err := dec.Decode(nil, nil); err != nil || !bytes.Equal(d.got, frames[0]) { + t.Fatalf("unexpected %v %v", err, len(d.got)) + } + if _, _, err := dec.Decode(nil, nil); err != nil || !bytes.Equal(d.got, frames[1]) { + t.Fatalf("unexpected %v %v", err, len(d.got)) + } + if _, _, err := dec.Decode(nil, nil); err != ErrObjectTooLarge || !bytes.Equal(d.got, frames[1]) { + t.Fatalf("unexpected %v %v", err, len(d.got)) + } + if _, _, err := dec.Decode(nil, nil); err != nil || !bytes.Equal(d.got, frames[3]) { + t.Fatalf("unexpected %v %v", err, len(d.got)) + } + if _, _, err := dec.Decode(nil, nil); err != io.EOF { + t.Fatalf("unexpected %v %v", err, len(d.got)) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning_test.go b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning_test.go new file mode 100644 index 000000000..7f13904d6 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning_test.go @@ -0,0 +1,382 @@ +/* +Copyright 2015 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 versioning + +import ( + "fmt" + "io" + "io/ioutil" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" +) + +type testDecodable struct { + Other string + Value int `json:"value"` + gvk schema.GroupVersionKind +} + +func (d *testDecodable) GetObjectKind() schema.ObjectKind { return d } +func (d *testDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk } +func (d *testDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk } +func (d *testDecodable) DeepCopyObject() runtime.Object { + // no real deepcopy because these tests check for pointer equality + return d +} + +type testNestedDecodable struct { + Other string + Value int `json:"value"` + + gvk schema.GroupVersionKind + nestedCalled bool + nestedErr error +} + +func (d *testNestedDecodable) GetObjectKind() schema.ObjectKind { return d } +func (d *testNestedDecodable) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk } +func (d *testNestedDecodable) GroupVersionKind() schema.GroupVersionKind { return d.gvk } +func (d *testNestedDecodable) DeepCopyObject() runtime.Object { + // no real deepcopy because these tests check for pointer equality + return d +} + +func (d *testNestedDecodable) EncodeNestedObjects(e runtime.Encoder) error { + d.nestedCalled = true + return d.nestedErr +} + +func (d *testNestedDecodable) DecodeNestedObjects(_ runtime.Decoder) error { + d.nestedCalled = true + return d.nestedErr +} + +func TestNestedDecode(t *testing.T) { + n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")} + decoder := &mockSerializer{obj: n} + codec := NewCodec(nil, decoder, nil, nil, nil, nil, nil, nil, "TestNestedDecode") + if _, _, err := codec.Decode([]byte(`{}`), nil, n); err != n.nestedErr { + t.Errorf("unexpected error: %v", err) + } + if !n.nestedCalled { + t.Errorf("did not invoke nested decoder") + } +} + +func TestNestedEncode(t *testing.T) { + n := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode")} + n2 := &testNestedDecodable{nestedErr: fmt.Errorf("unable to decode 2")} + encoder := &mockSerializer{obj: n} + codec := NewCodec( + encoder, nil, + &checkConvertor{obj: n2, groupVersion: schema.GroupVersion{Group: "other"}}, + nil, + &mockTyper{gvks: []schema.GroupVersionKind{{Kind: "test"}}}, + nil, + schema.GroupVersion{Group: "other"}, nil, + "TestNestedEncode", + ) + if err := codec.Encode(n, ioutil.Discard); err != n2.nestedErr { + t.Errorf("unexpected error: %v", err) + } + if n.nestedCalled || !n2.nestedCalled { + t.Errorf("did not invoke correct nested decoder") + } +} + +func TestDecode(t *testing.T) { + gvk1 := &schema.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"} + decodable1 := &testDecodable{} + decodable2 := &testDecodable{} + decodable3 := &testDecodable{} + versionedDecodable1 := &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}} + + testCases := []struct { + serializer runtime.Serializer + convertor runtime.ObjectConvertor + creater runtime.ObjectCreater + typer runtime.ObjectTyper + defaulter runtime.ObjectDefaulter + yaml bool + pretty bool + + encodes, decodes runtime.GroupVersioner + + defaultGVK *schema.GroupVersionKind + into runtime.Object + + errFn func(error) bool + expectedObject runtime.Object + sameObject runtime.Object + expectedGVK *schema.GroupVersionKind + }{ + { + serializer: &mockSerializer{actual: gvk1}, + convertor: &checkConvertor{groupVersion: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}}, + expectedGVK: gvk1, + decodes: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}, + }, + { + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}}, + expectedGVK: gvk1, + sameObject: decodable2, + decodes: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}, + }, + // defaultGVK.Group is allowed to force a conversion to the destination group + { + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + defaultGVK: &schema.GroupVersionKind{Group: "force"}, + convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "force", Version: runtime.APIVersionInternal}}, + expectedGVK: gvk1, + sameObject: decodable2, + decodes: schema.GroupVersion{Group: "force", Version: runtime.APIVersionInternal}, + }, + // uses direct conversion for into when objects differ + { + into: decodable3, + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable3, directConvert: true}, + expectedGVK: gvk1, + sameObject: decodable3, + }, + { + into: versionedDecodable1, + serializer: &mockSerializer{actual: gvk1, obj: decodable3}, + convertor: &checkConvertor{in: decodable3, obj: decodable1, directConvert: true}, + expectedGVK: gvk1, + sameObject: versionedDecodable1, + }, + // returns directly when serializer returns into + { + into: decodable3, + serializer: &mockSerializer{actual: gvk1, obj: decodable3}, + expectedGVK: gvk1, + sameObject: decodable3, + }, + // returns directly when serializer returns into + { + into: versionedDecodable1, + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + expectedGVK: gvk1, + sameObject: versionedDecodable1, + }, + + // runtime.VersionedObjects are decoded + { + into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, + + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}}, + expectedGVK: gvk1, + expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}}, + decodes: schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal}, + }, + + // decode into the same version as the serialized object + { + decodes: schema.GroupVersions{gvk1.GroupVersion()}, + + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "other", Version: "blah"}}}, + expectedGVK: gvk1, + expectedObject: decodable1, + }, + { + into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, + decodes: schema.GroupVersions{gvk1.GroupVersion()}, + + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "other", Version: "blah"}}}, + expectedGVK: gvk1, + expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}}, + }, + + // codec with non matching version skips conversion altogether + { + decodes: schema.GroupVersions{{Group: "something", Version: "else"}}, + + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "something", Version: "else"}}}, + expectedGVK: gvk1, + expectedObject: decodable1, + }, + { + into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, + decodes: schema.GroupVersions{{Group: "something", Version: "else"}}, + + serializer: &mockSerializer{actual: gvk1, obj: decodable1}, + convertor: &checkConvertor{in: decodable1, obj: decodable1, groupVersion: schema.GroupVersions{{Group: "something", Version: "else"}}}, + expectedGVK: gvk1, + expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}}, + }, + } + + for i, test := range testCases { + t.Logf("%d", i) + s := NewCodec(test.serializer, test.serializer, test.convertor, test.creater, test.typer, test.defaulter, test.encodes, test.decodes, fmt.Sprintf("mock-%d", i)) + obj, gvk, err := s.Decode([]byte(`{}`), test.defaultGVK, test.into) + + if !reflect.DeepEqual(test.expectedGVK, gvk) { + t.Errorf("%d: unexpected GVK: %v", i, gvk) + } + + switch { + case err == nil && test.errFn != nil: + t.Errorf("%d: failed: %v", i, err) + continue + case err != nil && test.errFn == nil: + t.Errorf("%d: failed: %v", i, err) + continue + case err != nil: + if !test.errFn(err) { + t.Errorf("%d: failed: %v", i, err) + } + if obj != nil { + t.Errorf("%d: should have returned nil object", i) + } + continue + } + + if test.into != nil && test.into != obj { + t.Errorf("%d: expected into to be returned: %v", i, obj) + continue + } + + switch { + case test.expectedObject != nil: + if !reflect.DeepEqual(test.expectedObject, obj) { + t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.expectedObject, obj)) + } + case test.sameObject != nil: + if test.sameObject != obj { + t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintSideBySide(test.sameObject, obj)) + } + case obj != nil: + t.Errorf("%d: unexpected object: %#v", i, obj) + } + } +} + +type checkConvertor struct { + err error + in, obj runtime.Object + groupVersion runtime.GroupVersioner + directConvert bool +} + +func (c *checkConvertor) Convert(in, out, context interface{}) error { + if !c.directConvert { + return fmt.Errorf("unexpected call to Convert") + } + if c.in != nil && c.in != in { + return fmt.Errorf("unexpected in: %s", in) + } + if c.obj != nil && c.obj != out { + return fmt.Errorf("unexpected out: %s", out) + } + return c.err +} +func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion runtime.GroupVersioner) (out runtime.Object, err error) { + if c.directConvert { + return nil, fmt.Errorf("unexpected call to ConvertToVersion") + } + if c.in != nil && c.in != in { + return nil, fmt.Errorf("unexpected in: %s", in) + } + if !reflect.DeepEqual(c.groupVersion, outVersion) { + return nil, fmt.Errorf("unexpected outversion: %s (%s)", outVersion, c.groupVersion) + } + return c.obj, c.err +} +func (c *checkConvertor) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) { + return "", "", fmt.Errorf("unexpected call to ConvertFieldLabel") +} + +type mockSerializer struct { + err error + obj runtime.Object + encodingObjGVK schema.GroupVersionKind + + defaults, actual *schema.GroupVersionKind + into runtime.Object +} + +func (s *mockSerializer) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { + s.defaults = defaults + s.into = into + return s.obj, s.actual, s.err +} + +func (s *mockSerializer) Encode(obj runtime.Object, w io.Writer) error { + s.obj = obj + s.encodingObjGVK = obj.GetObjectKind().GroupVersionKind() + return s.err +} + +type mockCreater struct { + err error + obj runtime.Object +} + +func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) { + return c.obj, c.err +} + +type mockTyper struct { + gvks []schema.GroupVersionKind + unversioned bool + err error +} + +func (t *mockTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) { + return t.gvks, t.unversioned, t.err +} + +func (t *mockTyper) Recognizes(_ schema.GroupVersionKind) bool { + return true +} + +func TestDirectCodecEncode(t *testing.T) { + serializer := mockSerializer{} + typer := mockTyper{ + gvks: []schema.GroupVersionKind{ + { + Group: "wrong_group", + Kind: "some_kind", + }, + { + Group: "expected_group", + Kind: "some_kind", + }, + }, + } + + c := DirectEncoder{ + Version: schema.GroupVersion{Group: "expected_group"}, + Encoder: &serializer, + ObjectTyper: &typer, + } + c.Encode(&testDecodable{}, ioutil.Discard) + if e, a := "expected_group", serializer.encodingObjGVK.Group; e != a { + t.Errorf("expected group to be %v, got %v", e, a) + } +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/main.go b/vendor/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator_test.go similarity index 50% rename from vendor/k8s.io/code-generator/cmd/go-to-protobuf/main.go rename to vendor/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator_test.go index 847a6a5a0..a6f338d31 100644 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/main.go +++ b/vendor/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator_test.go @@ -14,26 +14,30 @@ See the License for the specific language governing permissions and limitations under the License. */ -// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any -// existing IDL tags on the Go struct. -package main +package runtime import ( - goflag "flag" - - flag "github.com/spf13/pflag" - "k8s.io/code-generator/cmd/go-to-protobuf/protobuf" + "testing" ) -var g = protobuf.New() - -func init() { - g.BindFlags(flag.CommandLine) - goflag.Set("logtostderr", "true") - flag.CommandLine.AddGoFlagSet(goflag.CommandLine) -} - -func main() { - flag.Parse() - protobuf.Run(g) +func TestFmtRawDoc(t *testing.T) { + tests := []struct { + t, expected string + }{ + {"aaa\n --- asd\n TODO: tooooodo\n toooodoooooo\n", "aaa"}, + {"aaa\nasd\n TODO: tooooodo\nbbbb\n --- toooodoooooo\n", "aaa asd bbbb"}, + {" TODO: tooooodo\n", ""}, + {"Par1\n\nPar2\n\n", "Par1\\n\\nPar2"}, + {"", ""}, + {" ", ""}, + {" \n", ""}, + {" \n\n ", ""}, + {"Example:\n\tl1\n\t\tl2\n", "Example:\\n\\tl1\\n\\t\\tl2"}, + } + + for _, test := range tests { + if o := fmtRawDoc(test.t); o != test.expected { + t.Fatalf("Expected: %q, got %q", test.expected, o) + } + } } diff --git a/vendor/k8s.io/apimachinery/pkg/util/cache/cache_test.go b/vendor/k8s.io/apimachinery/pkg/util/cache/cache_test.go new file mode 100644 index 000000000..42a58a93d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/cache/cache_test.go @@ -0,0 +1,90 @@ +/* +Copyright 2014 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 cache + +import ( + "testing" +) + +const ( + maxTestCacheSize int = shardsCount * 2 +) + +func ExpectEntry(t *testing.T, cache Cache, index uint64, expectedValue interface{}) bool { + elem, found := cache.Get(index) + if !found { + t.Errorf("Expected to find entry with key %d", index) + return false + } else if elem != expectedValue { + t.Errorf("Expected to find %v, got %v", expectedValue, elem) + return false + } + return true +} + +func TestBasic(t *testing.T) { + cache := NewCache(maxTestCacheSize) + cache.Add(1, "xxx") + ExpectEntry(t, cache, 1, "xxx") +} + +func TestOverflow(t *testing.T) { + cache := NewCache(maxTestCacheSize) + for i := 0; i < maxTestCacheSize+1; i++ { + cache.Add(uint64(i), "xxx") + } + foundIndexes := make([]uint64, 0) + for i := 0; i < maxTestCacheSize+1; i++ { + _, found := cache.Get(uint64(i)) + if found { + foundIndexes = append(foundIndexes, uint64(i)) + } + } + if len(foundIndexes) != maxTestCacheSize { + t.Errorf("Expect to find %d elements, got %d %v", maxTestCacheSize, len(foundIndexes), foundIndexes) + } +} + +func TestOverwrite(t *testing.T) { + cache := NewCache(maxTestCacheSize) + cache.Add(1, "xxx") + ExpectEntry(t, cache, 1, "xxx") + cache.Add(1, "yyy") + ExpectEntry(t, cache, 1, "yyy") +} + +// TestEvict this test will fail sporatically depending on what add() +// selects for the randomKey to be evicted. Ensure that randomKey +// is never the key we most recently added. Since the chance of failure +// on each evict is 50%, if we do it 7 times, it should catch the problem +// if it exists >99% of the time. +func TestEvict(t *testing.T) { + cache := NewCache(shardsCount) + var found bool + for retry := 0; retry < 7; retry++ { + cache.Add(uint64(shardsCount), "xxx") + found = ExpectEntry(t, cache, uint64(shardsCount), "xxx") + if !found { + break + } + cache.Add(0, "xxx") + found = ExpectEntry(t, cache, 0, "xxx") + if !found { + break + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/cache/lruexpirecache_test.go b/vendor/k8s.io/apimachinery/pkg/util/cache/lruexpirecache_test.go new file mode 100644 index 000000000..bd44f60d4 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/cache/lruexpirecache_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2016 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 cache + +import ( + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/clock" + + "github.com/golang/groupcache/lru" +) + +func expectEntry(t *testing.T, c *LRUExpireCache, key lru.Key, value interface{}) { + result, ok := c.Get(key) + if !ok || result != value { + t.Errorf("Expected cache[%v]: %v, got %v", key, value, result) + } +} + +func expectNotEntry(t *testing.T, c *LRUExpireCache, key lru.Key) { + if result, ok := c.Get(key); ok { + t.Errorf("Expected cache[%v] to be empty, got %v", key, result) + } +} + +func TestSimpleGet(t *testing.T) { + c := NewLRUExpireCache(10) + c.Add("long-lived", "12345", 10*time.Hour) + expectEntry(t, c, "long-lived", "12345") +} + +func TestExpiredGet(t *testing.T) { + fakeClock := clock.NewFakeClock(time.Now()) + c := NewLRUExpireCacheWithClock(10, fakeClock) + c.Add("short-lived", "12345", 1*time.Millisecond) + // ensure the entry expired + fakeClock.Step(2 * time.Millisecond) + expectNotEntry(t, c, "short-lived") +} + +func TestLRUOverflow(t *testing.T) { + c := NewLRUExpireCache(4) + c.Add("elem1", "1", 10*time.Hour) + c.Add("elem2", "2", 10*time.Hour) + c.Add("elem3", "3", 10*time.Hour) + c.Add("elem4", "4", 10*time.Hour) + c.Add("elem5", "5", 10*time.Hour) + expectNotEntry(t, c, "elem1") + expectEntry(t, c, "elem2", "2") + expectEntry(t, c, "elem3", "3") + expectEntry(t, c, "elem4", "4") + expectEntry(t, c, "elem5", "5") +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/clock/clock_test.go b/vendor/k8s.io/apimachinery/pkg/util/clock/clock_test.go new file mode 100644 index 000000000..c7b371fc6 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/clock/clock_test.go @@ -0,0 +1,196 @@ +/* +Copyright 2015 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 clock + +import ( + "testing" + "time" +) + +var ( + _ = Clock(RealClock{}) + _ = Clock(&FakeClock{}) + _ = Clock(&IntervalClock{}) + + _ = Timer(&realTimer{}) + _ = Timer(&fakeTimer{}) + + _ = Ticker(&realTicker{}) + _ = Ticker(&fakeTicker{}) +) + +func TestFakeClock(t *testing.T) { + startTime := time.Now() + tc := NewFakeClock(startTime) + tc.Step(time.Second) + now := tc.Now() + if now.Sub(startTime) != time.Second { + t.Errorf("input: %s now=%s gap=%s expected=%s", startTime, now, now.Sub(startTime), time.Second) + } + + tt := tc.Now() + tc.SetTime(tt.Add(time.Hour)) + if tc.Now().Sub(tt) != time.Hour { + t.Errorf("input: %s now=%s gap=%s expected=%s", tt, tc.Now(), tc.Now().Sub(tt), time.Hour) + } +} + +func TestFakeClockSleep(t *testing.T) { + startTime := time.Now() + tc := NewFakeClock(startTime) + tc.Sleep(time.Duration(1) * time.Hour) + now := tc.Now() + if now.Sub(startTime) != time.Hour { + t.Errorf("Fake sleep failed, expected time to advance by one hour, instead, its %v", now.Sub(startTime)) + } +} + +func TestFakeAfter(t *testing.T) { + tc := NewFakeClock(time.Now()) + if tc.HasWaiters() { + t.Errorf("unexpected waiter?") + } + oneSec := tc.After(time.Second) + if !tc.HasWaiters() { + t.Errorf("unexpected lack of waiter?") + } + + oneOhOneSec := tc.After(time.Second + time.Millisecond) + twoSec := tc.After(2 * time.Second) + select { + case <-oneSec: + t.Errorf("unexpected channel read") + case <-oneOhOneSec: + t.Errorf("unexpected channel read") + case <-twoSec: + t.Errorf("unexpected channel read") + default: + } + + tc.Step(999 * time.Millisecond) + select { + case <-oneSec: + t.Errorf("unexpected channel read") + case <-oneOhOneSec: + t.Errorf("unexpected channel read") + case <-twoSec: + t.Errorf("unexpected channel read") + default: + } + + tc.Step(time.Millisecond) + select { + case <-oneSec: + // Expected! + case <-oneOhOneSec: + t.Errorf("unexpected channel read") + case <-twoSec: + t.Errorf("unexpected channel read") + default: + t.Errorf("unexpected non-channel read") + } + tc.Step(time.Millisecond) + select { + case <-oneSec: + // should not double-trigger! + t.Errorf("unexpected channel read") + case <-oneOhOneSec: + // Expected! + case <-twoSec: + t.Errorf("unexpected channel read") + default: + t.Errorf("unexpected non-channel read") + } +} + +func TestFakeTick(t *testing.T) { + tc := NewFakeClock(time.Now()) + if tc.HasWaiters() { + t.Errorf("unexpected waiter?") + } + oneSec := tc.NewTicker(time.Second).C() + if !tc.HasWaiters() { + t.Errorf("unexpected lack of waiter?") + } + + oneOhOneSec := tc.NewTicker(time.Second + time.Millisecond).C() + twoSec := tc.NewTicker(2 * time.Second).C() + select { + case <-oneSec: + t.Errorf("unexpected channel read") + case <-oneOhOneSec: + t.Errorf("unexpected channel read") + case <-twoSec: + t.Errorf("unexpected channel read") + default: + } + + tc.Step(999 * time.Millisecond) // t=.999 + select { + case <-oneSec: + t.Errorf("unexpected channel read") + case <-oneOhOneSec: + t.Errorf("unexpected channel read") + case <-twoSec: + t.Errorf("unexpected channel read") + default: + } + + tc.Step(time.Millisecond) // t=1.000 + select { + case <-oneSec: + // Expected! + case <-oneOhOneSec: + t.Errorf("unexpected channel read") + case <-twoSec: + t.Errorf("unexpected channel read") + default: + t.Errorf("unexpected non-channel read") + } + tc.Step(time.Millisecond) // t=1.001 + select { + case <-oneSec: + // should not double-trigger! + t.Errorf("unexpected channel read") + case <-oneOhOneSec: + // Expected! + case <-twoSec: + t.Errorf("unexpected channel read") + default: + t.Errorf("unexpected non-channel read") + } + + tc.Step(time.Second) // t=2.001 + tc.Step(time.Second) // t=3.001 + tc.Step(time.Second) // t=4.001 + tc.Step(time.Second) // t=5.001 + + // The one second ticker should not accumulate ticks + accumulatedTicks := 0 + drained := false + for !drained { + select { + case <-oneSec: + accumulatedTicks++ + default: + drained = true + } + } + if accumulatedTicks != 1 { + t.Errorf("unexpected number of accumulated ticks: %d", accumulatedTicks) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/diff/diff_test.go b/vendor/k8s.io/apimachinery/pkg/util/diff/diff_test.go new file mode 100644 index 000000000..79ea2216d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/diff/diff_test.go @@ -0,0 +1,148 @@ +/* +Copyright 2016 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 diff + +import ( + "testing" +) + +func TestObjectReflectDiff(t *testing.T) { + type struct1 struct{ A []int } + + testCases := map[string]struct { + a, b interface{} + out string + }{ + "map": { + a: map[string]int{}, + b: map[string]int{}, + }, + "detect nil map": { + a: map[string]int(nil), + b: map[string]int{}, + out: ` +object: + a: map[string]int(nil) + b: map[string]int{}`, + }, + "detect map changes": { + a: map[string]int{"test": 1, "other": 2}, + b: map[string]int{"test": 2, "third": 3}, + out: ` +object[other]: + a: 2 + b: <nil> +object[test]: + a: 1 + b: 2 +object[third]: + a: <nil> + b: 3`, + }, + "nil slice": {a: struct1{A: nil}, b: struct1{A: nil}}, + "empty slice": {a: struct1{A: []int{}}, b: struct1{A: []int{}}}, + "detect slice changes 1": {a: struct1{A: []int{1}}, b: struct1{A: []int{2}}, out: ` +object.A[0]: + a: 1 + b: 2`, + }, + "detect slice changes 2": {a: struct1{A: []int{}}, b: struct1{A: []int{2}}, out: ` +object.A[0]: + a: <nil> + b: 2`, + }, + "detect slice changes 3": {a: struct1{A: []int{1}}, b: struct1{A: []int{}}, out: ` +object.A[0]: + a: 1 + b: <nil>`, + }, + "detect nil vs empty slices": {a: struct1{A: nil}, b: struct1{A: []int{}}, out: ` +object.A: + a: []int(nil) + b: []int{}`, + }, + "display type differences": {a: []interface{}{int64(1)}, b: []interface{}{uint64(1)}, out: ` +object[0]: + a: 1 (int64) + b: 0x1 (uint64)`, + }, + } + for name, test := range testCases { + expect := test.out + if len(expect) == 0 { + expect = "<no diffs>" + } + if actual := ObjectReflectDiff(test.a, test.b); actual != expect { + t.Errorf("%s: unexpected output: %s", name, actual) + } + } +} + +func TestStringDiff(t *testing.T) { + diff := StringDiff("aaabb", "aaacc") + expect := "aaa\n\nA: bb\n\nB: cc\n\n" + if diff != expect { + t.Errorf("diff returned %v", diff) + } +} + +func TestLimit(t *testing.T) { + testcases := []struct { + a interface{} + b interface{} + expectA string + expectB string + }{ + { + a: `short a`, + b: `short b`, + expectA: `"short a"`, + expectB: `"short b"`, + }, + { + a: `short a`, + b: `long b needs truncating`, + expectA: `"short a"`, + expectB: `"long b ne...`, + }, + { + a: `long a needs truncating`, + b: `long b needs truncating`, + expectA: `...g a needs ...`, + expectB: `...g b needs ...`, + }, + { + a: `long common prefix with different stuff at the end of a`, + b: `long common prefix with different stuff at the end of b`, + expectA: `...end of a"`, + expectB: `...end of b"`, + }, + { + a: `long common prefix with different stuff at the end of a`, + b: `long common prefix with different stuff at the end of b which continues`, + expectA: `...of a"`, + expectB: `...of b which...`, + }, + } + + for _, tc := range testcases { + a, b := limit(tc.a, tc.b, 10) + if a != tc.expectA || b != tc.expectB { + t.Errorf("limit(%q, %q)\n\texpected: %s, %s\n\tgot: %s, %s", tc.a, tc.b, tc.expectA, tc.expectB, a, b) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/errors/errors_test.go b/vendor/k8s.io/apimachinery/pkg/util/errors/errors_test.go new file mode 100644 index 000000000..0ad3967d2 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/errors/errors_test.go @@ -0,0 +1,368 @@ +/* +Copyright 2015 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 errors + +import ( + "fmt" + "reflect" + "sort" + "testing" +) + +func TestEmptyAggregate(t *testing.T) { + var slice []error + var agg Aggregate + var err error + + agg = NewAggregate(slice) + if agg != nil { + t.Errorf("expected nil, got %#v", agg) + } + err = NewAggregate(slice) + if err != nil { + t.Errorf("expected nil, got %#v", err) + } + + // This is not normally possible, but pedantry demands I test it. + agg = aggregate(slice) // empty aggregate + if s := agg.Error(); s != "" { + t.Errorf("expected empty string, got %q", s) + } + if s := agg.Errors(); len(s) != 0 { + t.Errorf("expected empty slice, got %#v", s) + } + err = agg.(error) + if s := err.Error(); s != "" { + t.Errorf("expected empty string, got %q", s) + } +} + +func TestAggregateWithNil(t *testing.T) { + var slice []error + slice = []error{nil} + var agg Aggregate + var err error + + agg = NewAggregate(slice) + if agg != nil { + t.Errorf("expected nil, got %#v", agg) + } + err = NewAggregate(slice) + if err != nil { + t.Errorf("expected nil, got %#v", err) + } + + // Append a non-nil error + slice = append(slice, fmt.Errorf("err")) + agg = NewAggregate(slice) + if agg == nil { + t.Errorf("expected non-nil") + } + if s := agg.Error(); s != "err" { + t.Errorf("expected 'err', got %q", s) + } + if s := agg.Errors(); len(s) != 1 { + t.Errorf("expected one-element slice, got %#v", s) + } + if s := agg.Errors()[0].Error(); s != "err" { + t.Errorf("expected 'err', got %q", s) + } + + err = agg.(error) + if err == nil { + t.Errorf("expected non-nil") + } + if s := err.Error(); s != "err" { + t.Errorf("expected 'err', got %q", s) + } +} + +func TestSingularAggregate(t *testing.T) { + var slice []error = []error{fmt.Errorf("err")} + var agg Aggregate + var err error + + agg = NewAggregate(slice) + if agg == nil { + t.Errorf("expected non-nil") + } + if s := agg.Error(); s != "err" { + t.Errorf("expected 'err', got %q", s) + } + if s := agg.Errors(); len(s) != 1 { + t.Errorf("expected one-element slice, got %#v", s) + } + if s := agg.Errors()[0].Error(); s != "err" { + t.Errorf("expected 'err', got %q", s) + } + + err = agg.(error) + if err == nil { + t.Errorf("expected non-nil") + } + if s := err.Error(); s != "err" { + t.Errorf("expected 'err', got %q", s) + } +} + +func TestPluralAggregate(t *testing.T) { + var slice []error = []error{fmt.Errorf("abc"), fmt.Errorf("123")} + var agg Aggregate + var err error + + agg = NewAggregate(slice) + if agg == nil { + t.Errorf("expected non-nil") + } + if s := agg.Error(); s != "[abc, 123]" { + t.Errorf("expected '[abc, 123]', got %q", s) + } + if s := agg.Errors(); len(s) != 2 { + t.Errorf("expected two-elements slice, got %#v", s) + } + if s := agg.Errors()[0].Error(); s != "abc" { + t.Errorf("expected '[abc, 123]', got %q", s) + } + + err = agg.(error) + if err == nil { + t.Errorf("expected non-nil") + } + if s := err.Error(); s != "[abc, 123]" { + t.Errorf("expected '[abc, 123]', got %q", s) + } +} + +func TestFilterOut(t *testing.T) { + testCases := []struct { + err error + filter []Matcher + expected error + }{ + { + nil, + []Matcher{}, + nil, + }, + { + aggregate{}, + []Matcher{}, + nil, + }, + { + aggregate{fmt.Errorf("abc")}, + []Matcher{}, + aggregate{fmt.Errorf("abc")}, + }, + { + aggregate{fmt.Errorf("abc")}, + []Matcher{func(err error) bool { return false }}, + aggregate{fmt.Errorf("abc")}, + }, + { + aggregate{fmt.Errorf("abc")}, + []Matcher{func(err error) bool { return true }}, + nil, + }, + { + aggregate{fmt.Errorf("abc")}, + []Matcher{func(err error) bool { return false }, func(err error) bool { return false }}, + aggregate{fmt.Errorf("abc")}, + }, + { + aggregate{fmt.Errorf("abc")}, + []Matcher{func(err error) bool { return false }, func(err error) bool { return true }}, + nil, + }, + { + aggregate{fmt.Errorf("abc"), fmt.Errorf("def"), fmt.Errorf("ghi")}, + []Matcher{func(err error) bool { return err.Error() == "def" }}, + aggregate{fmt.Errorf("abc"), fmt.Errorf("ghi")}, + }, + { + aggregate{aggregate{fmt.Errorf("abc")}}, + []Matcher{}, + aggregate{aggregate{fmt.Errorf("abc")}}, + }, + { + aggregate{aggregate{fmt.Errorf("abc"), aggregate{fmt.Errorf("def")}}}, + []Matcher{}, + aggregate{aggregate{fmt.Errorf("abc"), aggregate{fmt.Errorf("def")}}}, + }, + { + aggregate{aggregate{fmt.Errorf("abc"), aggregate{fmt.Errorf("def")}}}, + []Matcher{func(err error) bool { return err.Error() == "def" }}, + aggregate{aggregate{fmt.Errorf("abc")}}, + }, + } + for i, testCase := range testCases { + err := FilterOut(testCase.err, testCase.filter...) + if !reflect.DeepEqual(testCase.expected, err) { + t.Errorf("%d: expected %v, got %v", i, testCase.expected, err) + } + } +} + +func TestFlatten(t *testing.T) { + testCases := []struct { + agg Aggregate + expected Aggregate + }{ + { + nil, + nil, + }, + { + aggregate{}, + nil, + }, + { + aggregate{fmt.Errorf("abc")}, + aggregate{fmt.Errorf("abc")}, + }, + { + aggregate{fmt.Errorf("abc"), fmt.Errorf("def"), fmt.Errorf("ghi")}, + aggregate{fmt.Errorf("abc"), fmt.Errorf("def"), fmt.Errorf("ghi")}, + }, + { + aggregate{aggregate{fmt.Errorf("abc")}}, + aggregate{fmt.Errorf("abc")}, + }, + { + aggregate{aggregate{aggregate{fmt.Errorf("abc")}}}, + aggregate{fmt.Errorf("abc")}, + }, + { + aggregate{aggregate{fmt.Errorf("abc"), aggregate{fmt.Errorf("def")}}}, + aggregate{fmt.Errorf("abc"), fmt.Errorf("def")}, + }, + { + aggregate{aggregate{aggregate{fmt.Errorf("abc")}, fmt.Errorf("def"), aggregate{fmt.Errorf("ghi")}}}, + aggregate{fmt.Errorf("abc"), fmt.Errorf("def"), fmt.Errorf("ghi")}, + }, + } + for i, testCase := range testCases { + agg := Flatten(testCase.agg) + if !reflect.DeepEqual(testCase.expected, agg) { + t.Errorf("%d: expected %v, got %v", i, testCase.expected, agg) + } + } +} + +func TestCreateAggregateFromMessageCountMap(t *testing.T) { + testCases := []struct { + name string + mcm MessageCountMap + expected Aggregate + }{ + { + "input has single instance of one message", + MessageCountMap{"abc": 1}, + aggregate{fmt.Errorf("abc")}, + }, + { + "input has multiple messages", + MessageCountMap{"abc": 2, "ghi": 1}, + aggregate{fmt.Errorf("abc (repeated 2 times)"), fmt.Errorf("ghi")}, + }, + { + "input has multiple messages", + MessageCountMap{"ghi": 1, "abc": 2}, + aggregate{fmt.Errorf("abc (repeated 2 times)"), fmt.Errorf("ghi")}, + }, + } + + var expected, agg []error + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + if testCase.expected != nil { + expected = testCase.expected.Errors() + sort.Slice(expected, func(i, j int) bool { return expected[i].Error() < expected[j].Error() }) + } + if testCase.mcm != nil { + agg = CreateAggregateFromMessageCountMap(testCase.mcm).Errors() + sort.Slice(agg, func(i, j int) bool { return agg[i].Error() < agg[j].Error() }) + } + if !reflect.DeepEqual(expected, agg) { + t.Errorf("expected %v, got %v", expected, agg) + } + }) + } +} + +func TestAggregateGoroutines(t *testing.T) { + testCases := []struct { + errs []error + expected map[string]bool // can't compare directly to Aggregate due to non-deterministic ordering + }{ + { + []error{}, + nil, + }, + { + []error{nil}, + nil, + }, + { + []error{nil, nil}, + nil, + }, + { + []error{fmt.Errorf("1")}, + map[string]bool{"1": true}, + }, + { + []error{fmt.Errorf("1"), nil}, + map[string]bool{"1": true}, + }, + { + []error{fmt.Errorf("1"), fmt.Errorf("267")}, + map[string]bool{"1": true, "267": true}, + }, + { + []error{fmt.Errorf("1"), nil, fmt.Errorf("1234")}, + map[string]bool{"1": true, "1234": true}, + }, + { + []error{nil, fmt.Errorf("1"), nil, fmt.Errorf("1234"), fmt.Errorf("22")}, + map[string]bool{"1": true, "1234": true, "22": true}, + }, + } + for i, testCase := range testCases { + funcs := make([]func() error, len(testCase.errs)) + for i := range testCase.errs { + err := testCase.errs[i] + funcs[i] = func() error { return err } + } + agg := AggregateGoroutines(funcs...) + if agg == nil { + if len(testCase.expected) > 0 { + t.Errorf("%d: expected %v, got nil", i, testCase.expected) + } + continue + } + if len(agg.Errors()) != len(testCase.expected) { + t.Errorf("%d: expected %d errors in aggregate, got %v", i, len(testCase.expected), agg) + continue + } + for _, err := range agg.Errors() { + if !testCase.expected[err.Error()] { + t.Errorf("%d: expected %v, got aggregate containing %v", i, testCase.expected, err) + } + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/framer/framer_test.go b/vendor/k8s.io/apimachinery/pkg/util/framer/framer_test.go new file mode 100644 index 000000000..b7ed00f53 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/framer/framer_test.go @@ -0,0 +1,176 @@ +/* +Copyright 2016 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 framer + +import ( + "bytes" + "io" + "io/ioutil" + "testing" +) + +func TestRead(t *testing.T) { + data := []byte{ + 0x00, 0x00, 0x00, 0x04, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x03, + 0x05, 0x06, 0x07, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x08, + } + b := bytes.NewBuffer(data) + r := NewLengthDelimitedFrameReader(ioutil.NopCloser(b)) + buf := make([]byte, 1) + if n, err := r.Read(buf); err != io.ErrShortBuffer && n != 1 && bytes.Equal(buf, []byte{0x01}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + if n, err := r.Read(buf); err != io.ErrShortBuffer && n != 1 && bytes.Equal(buf, []byte{0x02}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read the remaining frame + buf = make([]byte, 2) + if n, err := r.Read(buf); err != nil && n != 2 && bytes.Equal(buf, []byte{0x03, 0x04}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read with buffer equal to frame + buf = make([]byte, 3) + if n, err := r.Read(buf); err != nil && n != 3 && bytes.Equal(buf, []byte{0x05, 0x06, 0x07}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read empty frame + buf = make([]byte, 3) + if n, err := r.Read(buf); err != nil && n != 0 && bytes.Equal(buf, []byte{}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read with larger buffer than frame + buf = make([]byte, 3) + if n, err := r.Read(buf); err != nil && n != 1 && bytes.Equal(buf, []byte{0x08}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read EOF + if n, err := r.Read(buf); err != io.EOF && n != 0 { + t.Fatalf("unexpected: %v %d", err, n) + } +} + +func TestReadLarge(t *testing.T) { + data := []byte{ + 0x00, 0x00, 0x00, 0x04, + 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x03, + 0x05, 0x06, 0x07, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x08, + } + b := bytes.NewBuffer(data) + r := NewLengthDelimitedFrameReader(ioutil.NopCloser(b)) + buf := make([]byte, 40) + if n, err := r.Read(buf); err != nil && n != 4 && bytes.Equal(buf, []byte{0x01, 0x02, 0x03, 0x04}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + if n, err := r.Read(buf); err != nil && n != 3 && bytes.Equal(buf, []byte{0x05, 0x06, 0x7}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + if n, err := r.Read(buf); err != nil && n != 0 && bytes.Equal(buf, []byte{}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + if n, err := r.Read(buf); err != nil && n != 1 && bytes.Equal(buf, []byte{0x08}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read EOF + if n, err := r.Read(buf); err != io.EOF && n != 0 { + t.Fatalf("unexpected: %v %d", err, n) + } +} +func TestReadInvalidFrame(t *testing.T) { + data := []byte{ + 0x00, 0x00, 0x00, 0x04, + 0x01, 0x02, + } + b := bytes.NewBuffer(data) + r := NewLengthDelimitedFrameReader(ioutil.NopCloser(b)) + buf := make([]byte, 1) + if n, err := r.Read(buf); err != io.ErrShortBuffer && n != 1 && bytes.Equal(buf, []byte{0x01}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read the remaining frame + buf = make([]byte, 3) + if n, err := r.Read(buf); err != io.ErrUnexpectedEOF && n != 1 && bytes.Equal(buf, []byte{0x02}) { + t.Fatalf("unexpected: %v %d %v", err, n, buf) + } + // read EOF + if n, err := r.Read(buf); err != io.EOF && n != 0 { + t.Fatalf("unexpected: %v %d", err, n) + } +} + +func TestJSONFrameReader(t *testing.T) { + b := bytes.NewBufferString("{\"test\":true}\n1\n[\"a\"]") + r := NewJSONFramedReader(ioutil.NopCloser(b)) + buf := make([]byte, 20) + if n, err := r.Read(buf); err != nil || n != 13 || string(buf[:n]) != `{"test":true}` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != nil || n != 1 || string(buf[:n]) != `1` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != nil || n != 5 || string(buf[:n]) != `["a"]` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != io.EOF || n != 0 { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } +} + +func TestJSONFrameReaderShortBuffer(t *testing.T) { + b := bytes.NewBufferString("{\"test\":true}\n1\n[\"a\"]") + r := NewJSONFramedReader(ioutil.NopCloser(b)) + buf := make([]byte, 3) + + if n, err := r.Read(buf); err != io.ErrShortBuffer || n != 3 || string(buf[:n]) != `{"t` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != io.ErrShortBuffer || n != 3 || string(buf[:n]) != `est` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != io.ErrShortBuffer || n != 3 || string(buf[:n]) != `":t` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != io.ErrShortBuffer || n != 3 || string(buf[:n]) != `rue` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != nil || n != 1 || string(buf[:n]) != `}` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + + if n, err := r.Read(buf); err != nil || n != 1 || string(buf[:n]) != `1` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + + if n, err := r.Read(buf); err != io.ErrShortBuffer || n != 3 || string(buf[:n]) != `["a` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + if n, err := r.Read(buf); err != nil || n != 2 || string(buf[:n]) != `"]` { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } + + if n, err := r.Read(buf); err != io.EOF || n != 0 { + t.Fatalf("unexpected: %v %d %q", err, n, buf) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto b/vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto new file mode 100644 index 000000000..1c3ec732e --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/intstr/generated.proto @@ -0,0 +1,43 @@ +/* +Copyright 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. +*/ + + +// This file was autogenerated by go-to-protobuf. Do not edit it manually! + +syntax = 'proto2'; + +package k8s.io.apimachinery.pkg.util.intstr; + +// Package-wide variables from generator "generated". +option go_package = "intstr"; + +// IntOrString is a type that can hold an int32 or a string. When used in +// JSON or YAML marshalling and unmarshalling, it produces or consumes the +// inner type. This allows you to have, for example, a JSON field that can +// accept a name or number. +// TODO: Rename to Int32OrString +// +// +protobuf=true +// +protobuf.options.(gogoproto.goproto_stringer)=false +// +k8s:openapi-gen=true +message IntOrString { + optional int64 type = 1; + + optional int32 intVal = 2; + + optional string strVal = 3; +} + diff --git a/vendor/k8s.io/apimachinery/pkg/util/intstr/intstr_test.go b/vendor/k8s.io/apimachinery/pkg/util/intstr/intstr_test.go new file mode 100644 index 000000000..690fe2d53 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/intstr/intstr_test.go @@ -0,0 +1,183 @@ +/* +Copyright 2014 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 intstr + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/ghodss/yaml" +) + +func TestFromInt(t *testing.T) { + i := FromInt(93) + if i.Type != Int || i.IntVal != 93 { + t.Errorf("Expected IntVal=93, got %+v", i) + } +} + +func TestFromString(t *testing.T) { + i := FromString("76") + if i.Type != String || i.StrVal != "76" { + t.Errorf("Expected StrVal=\"76\", got %+v", i) + } +} + +type IntOrStringHolder struct { + IOrS IntOrString `json:"val"` +} + +func TestIntOrStringUnmarshalJSON(t *testing.T) { + cases := []struct { + input string + result IntOrString + }{ + {"{\"val\": 123}", FromInt(123)}, + {"{\"val\": \"123\"}", FromString("123")}, + } + + for _, c := range cases { + var result IntOrStringHolder + if err := json.Unmarshal([]byte(c.input), &result); err != nil { + t.Errorf("Failed to unmarshal input '%v': %v", c.input, err) + } + if result.IOrS != c.result { + t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result) + } + } +} + +func TestIntOrStringMarshalJSON(t *testing.T) { + cases := []struct { + input IntOrString + result string + }{ + {FromInt(123), "{\"val\":123}"}, + {FromString("123"), "{\"val\":\"123\"}"}, + } + + for _, c := range cases { + input := IntOrStringHolder{c.input} + result, err := json.Marshal(&input) + if err != nil { + t.Errorf("Failed to marshal input '%v': %v", input, err) + } + if string(result) != c.result { + t.Errorf("Failed to marshal input '%v': expected: %+v, got %q", input, c.result, string(result)) + } + } +} + +func TestIntOrStringMarshalJSONUnmarshalYAML(t *testing.T) { + cases := []struct { + input IntOrString + }{ + {FromInt(123)}, + {FromString("123")}, + } + + for _, c := range cases { + input := IntOrStringHolder{c.input} + jsonMarshalled, err := json.Marshal(&input) + if err != nil { + t.Errorf("1: Failed to marshal input: '%v': %v", input, err) + } + + var result IntOrStringHolder + err = yaml.Unmarshal(jsonMarshalled, &result) + if err != nil { + t.Errorf("2: Failed to unmarshal '%+v': %v", string(jsonMarshalled), err) + } + + if !reflect.DeepEqual(input, result) { + t.Errorf("3: Failed to marshal input '%+v': got %+v", input, result) + } + } +} + +func TestGetValueFromIntOrPercent(t *testing.T) { + tests := []struct { + input IntOrString + total int + roundUp bool + expectErr bool + expectVal int + }{ + { + input: FromInt(123), + expectErr: false, + expectVal: 123, + }, + { + input: FromString("90%"), + total: 100, + roundUp: true, + expectErr: false, + expectVal: 90, + }, + { + input: FromString("90%"), + total: 95, + roundUp: true, + expectErr: false, + expectVal: 86, + }, + { + input: FromString("90%"), + total: 95, + roundUp: false, + expectErr: false, + expectVal: 85, + }, + { + input: FromString("%"), + expectErr: true, + }, + { + input: FromString("90#"), + expectErr: true, + }, + { + input: FromString("#%"), + expectErr: true, + }, + } + + for i, test := range tests { + t.Logf("test case %d", i) + value, err := GetValueFromIntOrPercent(&test.input, test.total, test.roundUp) + if test.expectErr && err == nil { + t.Errorf("expected error, but got none") + continue + } + if !test.expectErr && err != nil { + t.Errorf("unexpected err: %v", err) + continue + } + if test.expectVal != value { + t.Errorf("expected %v, but got %v", test.expectVal, value) + } + } +} + +func TestGetValueFromIntOrPercentNil(t *testing.T) { + _, err := GetValueFromIntOrPercent(nil, 0, false) + if err == nil { + t.Errorf("expected error got none") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/json/json_test.go b/vendor/k8s.io/apimachinery/pkg/util/json/json_test.go new file mode 100644 index 000000000..cd0c18bb2 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/json/json_test.go @@ -0,0 +1,319 @@ +// +build go1.8 + +/* +Copyright 2015 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 json + +import ( + "fmt" + "math" + "reflect" + "strconv" + "strings" + "testing" +) + +func TestEvaluateTypes(t *testing.T) { + testCases := []struct { + In string + Data interface{} + Out string + Err bool + }{ + // Invalid syntaxes + { + In: `x`, + Err: true, + }, + { + In: ``, + Err: true, + }, + + // Null + { + In: `null`, + Data: nil, + Out: `null`, + }, + // Booleans + { + In: `true`, + Data: true, + Out: `true`, + }, + { + In: `false`, + Data: false, + Out: `false`, + }, + + // Integers + { + In: `0`, + Data: int64(0), + Out: `0`, + }, + { + In: `-0`, + Data: int64(-0), + Out: `0`, + }, + { + In: `1`, + Data: int64(1), + Out: `1`, + }, + { + In: `2147483647`, + Data: int64(math.MaxInt32), + Out: `2147483647`, + }, + { + In: `-2147483648`, + Data: int64(math.MinInt32), + Out: `-2147483648`, + }, + { + In: `9223372036854775807`, + Data: int64(math.MaxInt64), + Out: `9223372036854775807`, + }, + { + In: `-9223372036854775808`, + Data: int64(math.MinInt64), + Out: `-9223372036854775808`, + }, + + // Int overflow + { + In: `9223372036854775808`, // MaxInt64 + 1 + Data: float64(9223372036854775808), + Out: `9223372036854776000`, + }, + { + In: `-9223372036854775809`, // MinInt64 - 1 + Data: float64(math.MinInt64), + Out: `-9223372036854776000`, + }, + + // Floats + { + In: `0.0`, + Data: float64(0), + Out: `0`, + }, + { + In: `-0.0`, + Data: float64(-0.0), + Out: `-0`, + }, + { + In: `0.5`, + Data: float64(0.5), + Out: `0.5`, + }, + { + In: `1e3`, + Data: float64(1e3), + Out: `1000`, + }, + { + In: `1.5`, + Data: float64(1.5), + Out: `1.5`, + }, + { + In: `-0.3`, + Data: float64(-.3), + Out: `-0.3`, + }, + { + // Largest representable float32 + In: `3.40282346638528859811704183484516925440e+38`, + Data: float64(math.MaxFloat32), + Out: strconv.FormatFloat(math.MaxFloat32, 'g', -1, 64), + }, + { + // Smallest float32 without losing precision + In: `1.175494351e-38`, + Data: float64(1.175494351e-38), + Out: `1.175494351e-38`, + }, + { + // float32 closest to zero + In: `1.401298464324817070923729583289916131280e-45`, + Data: float64(math.SmallestNonzeroFloat32), + Out: strconv.FormatFloat(math.SmallestNonzeroFloat32, 'g', -1, 64), + }, + { + // Largest representable float64 + In: `1.797693134862315708145274237317043567981e+308`, + Data: float64(math.MaxFloat64), + Out: strconv.FormatFloat(math.MaxFloat64, 'g', -1, 64), + }, + { + // Closest to zero without losing precision + In: `2.2250738585072014e-308`, + Data: float64(2.2250738585072014e-308), + Out: `2.2250738585072014e-308`, + }, + + { + // float64 closest to zero + In: `4.940656458412465441765687928682213723651e-324`, + Data: float64(math.SmallestNonzeroFloat64), + Out: strconv.FormatFloat(math.SmallestNonzeroFloat64, 'g', -1, 64), + }, + + { + // math.MaxFloat64 + 2 overflow + In: `1.7976931348623159e+308`, + Err: true, + }, + + // Strings + { + In: `""`, + Data: string(""), + Out: `""`, + }, + { + In: `"0"`, + Data: string("0"), + Out: `"0"`, + }, + { + In: `"A"`, + Data: string("A"), + Out: `"A"`, + }, + { + In: `"Iñtërnâtiônàlizætiøn"`, + Data: string("Iñtërnâtiônàlizætiøn"), + Out: `"Iñtërnâtiônàlizætiøn"`, + }, + + // Arrays + { + In: `[]`, + Data: []interface{}{}, + Out: `[]`, + }, + { + In: `[` + strings.Join([]string{ + `null`, + `true`, + `false`, + `0`, + `9223372036854775807`, + `0.0`, + `0.5`, + `1.0`, + `1.797693134862315708145274237317043567981e+308`, + `"0"`, + `"A"`, + `"Iñtërnâtiônàlizætiøn"`, + `[null,true,1,1.0,1.5]`, + `{"boolkey":true,"floatkey":1.0,"intkey":1,"nullkey":null}`, + }, ",") + `]`, + Data: []interface{}{ + nil, + true, + false, + int64(0), + int64(math.MaxInt64), + float64(0.0), + float64(0.5), + float64(1.0), + float64(math.MaxFloat64), + string("0"), + string("A"), + string("Iñtërnâtiônàlizætiøn"), + []interface{}{nil, true, int64(1), float64(1.0), float64(1.5)}, + map[string]interface{}{"nullkey": nil, "boolkey": true, "intkey": int64(1), "floatkey": float64(1.0)}, + }, + Out: `[` + strings.Join([]string{ + `null`, + `true`, + `false`, + `0`, + `9223372036854775807`, + `0`, + `0.5`, + `1`, + strconv.FormatFloat(math.MaxFloat64, 'g', -1, 64), + `"0"`, + `"A"`, + `"Iñtërnâtiônàlizætiøn"`, + `[null,true,1,1,1.5]`, + `{"boolkey":true,"floatkey":1,"intkey":1,"nullkey":null}`, // gets alphabetized by Marshal + }, ",") + `]`, + }, + + // Maps + { + In: `{}`, + Data: map[string]interface{}{}, + Out: `{}`, + }, + { + In: `{"boolkey":true,"floatkey":1.0,"intkey":1,"nullkey":null}`, + Data: map[string]interface{}{"nullkey": nil, "boolkey": true, "intkey": int64(1), "floatkey": float64(1.0)}, + Out: `{"boolkey":true,"floatkey":1,"intkey":1,"nullkey":null}`, // gets alphabetized by Marshal + }, + } + + for _, tc := range testCases { + inputJSON := fmt.Sprintf(`{"data":%s}`, tc.In) + expectedJSON := fmt.Sprintf(`{"data":%s}`, tc.Out) + m := map[string]interface{}{} + err := Unmarshal([]byte(inputJSON), &m) + if tc.Err && err != nil { + // Expected error + continue + } + if err != nil { + t.Errorf("%s: error decoding: %v", tc.In, err) + continue + } + if tc.Err { + t.Errorf("%s: expected error, got none", tc.In) + continue + } + data, ok := m["data"] + if !ok { + t.Errorf("%s: decoded object missing data key: %#v", tc.In, m) + continue + } + if !reflect.DeepEqual(tc.Data, data) { + t.Errorf("%s: expected\n\t%#v (%v), got\n\t%#v (%v)", tc.In, tc.Data, reflect.TypeOf(tc.Data), data, reflect.TypeOf(data)) + continue + } + + outputJSON, err := Marshal(m) + if err != nil { + t.Errorf("%s: error encoding: %v", tc.In, err) + continue + } + + if expectedJSON != string(outputJSON) { + t.Errorf("%s: expected\n\t%s, got\n\t%s", tc.In, expectedJSON, string(outputJSON)) + continue + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/mergepatch/OWNERS b/vendor/k8s.io/apimachinery/pkg/util/mergepatch/OWNERS new file mode 100644 index 000000000..8e8d9fce8 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/mergepatch/OWNERS @@ -0,0 +1,5 @@ +approvers: +- pwittrock +reviewers: +- mengqiy +- apelisse diff --git a/vendor/k8s.io/apimachinery/pkg/util/mergepatch/util_test.go b/vendor/k8s.io/apimachinery/pkg/util/mergepatch/util_test.go new file mode 100644 index 000000000..e74dfabd4 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/mergepatch/util_test.go @@ -0,0 +1,136 @@ +/* +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 mergepatch + +import ( + "fmt" + "testing" +) + +func TestHasConflicts(t *testing.T) { + testCases := []struct { + A interface{} + B interface{} + Ret bool + }{ + {A: "hello", B: "hello", Ret: false}, + {A: "hello", B: "hell", Ret: true}, + {A: "hello", B: nil, Ret: true}, + {A: "hello", B: int64(1), Ret: true}, + {A: "hello", B: float64(1.0), Ret: true}, + {A: "hello", B: false, Ret: true}, + {A: int64(1), B: int64(1), Ret: false}, + {A: nil, B: nil, Ret: false}, + {A: false, B: false, Ret: false}, + {A: float64(3), B: float64(3), Ret: false}, + + {A: "hello", B: []interface{}{}, Ret: true}, + {A: []interface{}{int64(1)}, B: []interface{}{}, Ret: true}, + {A: []interface{}{}, B: []interface{}{}, Ret: false}, + {A: []interface{}{int64(1)}, B: []interface{}{int64(1)}, Ret: false}, + {A: map[string]interface{}{}, B: []interface{}{int64(1)}, Ret: true}, + + {A: map[string]interface{}{}, B: map[string]interface{}{"a": int64(1)}, Ret: false}, + {A: map[string]interface{}{"a": int64(1)}, B: map[string]interface{}{"a": int64(1)}, Ret: false}, + {A: map[string]interface{}{"a": int64(1)}, B: map[string]interface{}{"a": int64(2)}, Ret: true}, + {A: map[string]interface{}{"a": int64(1)}, B: map[string]interface{}{"b": int64(2)}, Ret: false}, + + { + A: map[string]interface{}{"a": []interface{}{int64(1)}}, + B: map[string]interface{}{"a": []interface{}{int64(1)}}, + Ret: false, + }, + { + A: map[string]interface{}{"a": []interface{}{int64(1)}}, + B: map[string]interface{}{"a": []interface{}{}}, + Ret: true, + }, + { + A: map[string]interface{}{"a": []interface{}{int64(1)}}, + B: map[string]interface{}{"a": int64(1)}, + Ret: true, + }, + + // Maps and lists with multiple entries. + { + A: map[string]interface{}{"a": int64(1), "b": int64(2)}, + B: map[string]interface{}{"a": int64(1), "b": int64(0)}, + Ret: true, + }, + { + A: map[string]interface{}{"a": int64(1), "b": int64(2)}, + B: map[string]interface{}{"a": int64(1), "b": int64(2)}, + Ret: false, + }, + { + A: map[string]interface{}{"a": int64(1), "b": int64(2)}, + B: map[string]interface{}{"a": int64(1), "b": int64(0), "c": int64(3)}, + Ret: true, + }, + { + A: map[string]interface{}{"a": int64(1), "b": int64(2)}, + B: map[string]interface{}{"a": int64(1), "b": int64(2), "c": int64(3)}, + Ret: false, + }, + { + A: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}, + B: map[string]interface{}{"a": []interface{}{int64(1), int64(0)}}, + Ret: true, + }, + { + A: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}, + B: map[string]interface{}{"a": []interface{}{int64(1), int64(2)}}, + Ret: false, + }, + + // Numeric types are not interchangeable. + // Callers are expected to ensure numeric types are consistent in 'left' and 'right'. + {A: int64(0), B: float64(0), Ret: true}, + // Other types are not interchangeable. + {A: int64(0), B: "0", Ret: true}, + {A: int64(0), B: nil, Ret: true}, + {A: int64(0), B: false, Ret: true}, + {A: "true", B: true, Ret: true}, + {A: "null", B: nil, Ret: true}, + } + + for _, testCase := range testCases { + testStr := fmt.Sprintf("A = %#v, B = %#v", testCase.A, testCase.B) + // Run each test case multiple times if it passes because HasConflicts() + // uses map iteration, which returns keys in nondeterministic order. + for try := 0; try < 10; try++ { + out, err := HasConflicts(testCase.A, testCase.B) + if err != nil { + t.Errorf("%v: unexpected error: %v", testStr, err) + break + } + if out != testCase.Ret { + t.Errorf("%v: expected %t got %t", testStr, testCase.Ret, out) + break + } + out, err = HasConflicts(testCase.B, testCase.A) + if err != nil { + t.Errorf("%v: unexpected error: %v", testStr, err) + break + } + if out != testCase.Ret { + t.Errorf("%v: expected reversed %t got %t", testStr, testCase.Ret, out) + break + } + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/naming/from_stack_test.go b/vendor/k8s.io/apimachinery/pkg/util/naming/from_stack_test.go new file mode 100644 index 000000000..1ff1ec8ad --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/naming/from_stack_test.go @@ -0,0 +1,56 @@ +/* +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. +*/ + +package naming + +import "testing" + +func TestGetNameFromCallsite(t *testing.T) { + tests := []struct { + name string + ignoredPackages []string + expected string + }{ + { + name: "simple", + expected: "k8s.io/apimachinery/pkg/util/naming/from_stack_test.go:50", + }, + { + name: "ignore-package", + ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming"}, + expected: "testing/testing.go:777", + }, + { + name: "ignore-file", + ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go"}, + expected: "testing/testing.go:777", + }, + { + name: "ignore-multiple", + ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go", "testing/testing.go"}, + expected: "????", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := GetNameFromCallsite(tc.ignoredPackages...) + if tc.expected != actual { + t.Fatalf("expected %q, got %q", tc.expected, actual) + } + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/http_test.go b/vendor/k8s.io/apimachinery/pkg/util/net/http_test.go new file mode 100644 index 000000000..98bd64971 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/net/http_test.go @@ -0,0 +1,282 @@ +// +build go1.8 + +/* +Copyright 2016 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 net + +import ( + "crypto/tls" + "fmt" + "net" + "net/http" + "net/url" + "os" + "reflect" + "testing" +) + +func TestGetClientIP(t *testing.T) { + ipString := "10.0.0.1" + ip := net.ParseIP(ipString) + invalidIPString := "invalidIPString" + testCases := []struct { + Request http.Request + ExpectedIP net.IP + }{ + { + Request: http.Request{}, + }, + { + Request: http.Request{ + Header: map[string][]string{ + "X-Real-Ip": {ipString}, + }, + }, + ExpectedIP: ip, + }, + { + Request: http.Request{ + Header: map[string][]string{ + "X-Real-Ip": {invalidIPString}, + }, + }, + }, + { + Request: http.Request{ + Header: map[string][]string{ + "X-Forwarded-For": {ipString}, + }, + }, + ExpectedIP: ip, + }, + { + Request: http.Request{ + Header: map[string][]string{ + "X-Forwarded-For": {invalidIPString}, + }, + }, + }, + { + Request: http.Request{ + Header: map[string][]string{ + "X-Forwarded-For": {invalidIPString + "," + ipString}, + }, + }, + ExpectedIP: ip, + }, + { + Request: http.Request{ + // RemoteAddr is in the form host:port + RemoteAddr: ipString + ":1234", + }, + ExpectedIP: ip, + }, + { + Request: http.Request{ + RemoteAddr: invalidIPString, + }, + }, + { + Request: http.Request{ + Header: map[string][]string{ + "X-Forwarded-For": {invalidIPString}, + }, + // RemoteAddr is in the form host:port + RemoteAddr: ipString, + }, + ExpectedIP: ip, + }, + } + + for i, test := range testCases { + if a, e := GetClientIP(&test.Request), test.ExpectedIP; reflect.DeepEqual(e, a) != true { + t.Fatalf("test case %d failed. expected: %v, actual: %v", i, e, a) + } + } +} + +func TestAppendForwardedForHeader(t *testing.T) { + testCases := []struct { + addr, forwarded, expected string + }{ + {"1.2.3.4:8000", "", "1.2.3.4"}, + {"1.2.3.4:8000", "8.8.8.8", "8.8.8.8, 1.2.3.4"}, + {"1.2.3.4:8000", "8.8.8.8, 1.2.3.4", "8.8.8.8, 1.2.3.4, 1.2.3.4"}, + {"1.2.3.4:8000", "foo,bar", "foo,bar, 1.2.3.4"}, + } + for i, test := range testCases { + req := &http.Request{ + RemoteAddr: test.addr, + Header: make(http.Header), + } + if test.forwarded != "" { + req.Header.Set("X-Forwarded-For", test.forwarded) + } + + AppendForwardedForHeader(req) + actual := req.Header.Get("X-Forwarded-For") + if actual != test.expected { + t.Errorf("[%d] Expected %q, Got %q", i, test.expected, actual) + } + } +} + +func TestProxierWithNoProxyCIDR(t *testing.T) { + testCases := []struct { + name string + noProxy string + url string + + expectedDelegated bool + }{ + { + name: "no env", + url: "https://192.168.143.1/api", + expectedDelegated: true, + }, + { + name: "no cidr", + noProxy: "192.168.63.1", + url: "https://192.168.143.1/api", + expectedDelegated: true, + }, + { + name: "hostname", + noProxy: "192.168.63.0/24,192.168.143.0/24", + url: "https://my-hostname/api", + expectedDelegated: true, + }, + { + name: "match second cidr", + noProxy: "192.168.63.0/24,192.168.143.0/24", + url: "https://192.168.143.1/api", + expectedDelegated: false, + }, + { + name: "match second cidr with host:port", + noProxy: "192.168.63.0/24,192.168.143.0/24", + url: "https://192.168.143.1:8443/api", + expectedDelegated: false, + }, + { + name: "IPv6 cidr", + noProxy: "2001:db8::/48", + url: "https://[2001:db8::1]/api", + expectedDelegated: false, + }, + { + name: "IPv6+port cidr", + noProxy: "2001:db8::/48", + url: "https://[2001:db8::1]:8443/api", + expectedDelegated: false, + }, + { + name: "IPv6, not matching cidr", + noProxy: "2001:db8::/48", + url: "https://[2001:db8:1::1]/api", + expectedDelegated: true, + }, + { + name: "IPv6+port, not matching cidr", + noProxy: "2001:db8::/48", + url: "https://[2001:db8:1::1]:8443/api", + expectedDelegated: true, + }, + } + + for _, test := range testCases { + os.Setenv("NO_PROXY", test.noProxy) + actualDelegated := false + proxyFunc := NewProxierWithNoProxyCIDR(func(req *http.Request) (*url.URL, error) { + actualDelegated = true + return nil, nil + }) + + req, err := http.NewRequest("GET", test.url, nil) + if err != nil { + t.Errorf("%s: unexpected err: %v", test.name, err) + continue + } + if _, err := proxyFunc(req); err != nil { + t.Errorf("%s: unexpected err: %v", test.name, err) + continue + } + + if test.expectedDelegated != actualDelegated { + t.Errorf("%s: expected %v, got %v", test.name, test.expectedDelegated, actualDelegated) + continue + } + } +} + +type fakeTLSClientConfigHolder struct { + called bool +} + +func (f *fakeTLSClientConfigHolder) TLSClientConfig() *tls.Config { + f.called = true + return nil +} +func (f *fakeTLSClientConfigHolder) RoundTrip(*http.Request) (*http.Response, error) { + return nil, nil +} + +func TestTLSClientConfigHolder(t *testing.T) { + rt := &fakeTLSClientConfigHolder{} + TLSClientConfig(rt) + + if !rt.called { + t.Errorf("didn't find tls config") + } +} + +func TestJoinPreservingTrailingSlash(t *testing.T) { + tests := []struct { + a string + b string + want string + }{ + // All empty + {"", "", ""}, + + // Empty a + {"", "/", "/"}, + {"", "foo", "foo"}, + {"", "/foo", "/foo"}, + {"", "/foo/", "/foo/"}, + + // Empty b + {"/", "", "/"}, + {"foo", "", "foo"}, + {"/foo", "", "/foo"}, + {"/foo/", "", "/foo/"}, + + // Both populated + {"/", "/", "/"}, + {"foo", "foo", "foo/foo"}, + {"/foo", "/foo", "/foo/foo"}, + {"/foo/", "/foo/", "/foo/foo/"}, + } + for _, tt := range tests { + name := fmt.Sprintf("%q+%q=%q", tt.a, tt.b, tt.want) + t.Run(name, func(t *testing.T) { + if got := JoinPreservingTrailingSlash(tt.a, tt.b); got != tt.want { + t.Errorf("JoinPreservingTrailingSlash() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/interface_test.go b/vendor/k8s.io/apimachinery/pkg/util/net/interface_test.go new file mode 100644 index 000000000..d652f479d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/net/interface_test.go @@ -0,0 +1,725 @@ +/* +Copyright 2014 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 net + +import ( + "fmt" + "io/ioutil" + "net" + "os" + "strings" + "testing" +) + +const gatewayfirst = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const gatewaylast = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +` +const gatewaymiddle = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const noInternetConnection = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const nothing = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +` +const badDestination = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0A 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0AA1 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const badGateway = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0AA1 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` +const route_Invalidhex = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +eth3 00000000 0100FE0AA 0003 0 0 1024 00000000 0 0 0 +eth3 0000FE0A 00000000 0001 0 0 0 0080FFFF 0 0 0 +docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 +virbr0 007AA8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +` + +const v6gatewayfirst = `00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010001000000000000000000000001 00000064 00000000 00000000 00000003 eth3 +20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3 +00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200 lo +` +const v6gatewaylast = `20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3 +00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200 lo +00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010001000000000000000000000001 00000064 00000000 00000000 00000003 eth3 +` +const v6gatewaymiddle = `20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3 +00000000000000000000000000000000 00 00000000000000000000000000000000 00 20010001000000000000000000000001 00000064 00000000 00000000 00000003 eth3 +00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200 lo +` +const v6noDefaultRoutes = `00000000000000000000000000000000 60 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200 lo +20010001000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00000001 docker0 +20010002000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3 +fe800000000000000000000000000000 40 00000000000000000000000000000000 00 00000000000000000000000000000000 00000100 00000000 00000000 00000001 eth3 +` +const v6nothing = `` +const v6badDestination = `2001000200000000 7a 00000000000000000000000000000000 00 00000000000000000000000000000000 00000400 00000000 00000000 00200200 lo +` +const v6badGateway = `00000000000000000000000000000000 00 00000000000000000000000000000000 00 200100010000000000000000000000000012 00000064 00000000 00000000 00000003 eth3 +` +const v6route_Invalidhex = `000000000000000000000000000000000 00 00000000000000000000000000000000 00 fe80000000000000021fcafffea0ec00 00000064 00000000 00000000 00000003 enp1s0f0 + +` + +const ( + flagUp = net.FlagUp | net.FlagBroadcast | net.FlagMulticast + flagDown = net.FlagBroadcast | net.FlagMulticast + flagLoopback = net.FlagUp | net.FlagLoopback + flagP2P = net.FlagUp | net.FlagPointToPoint +) + +func makeIntf(index int, name string, flags net.Flags) net.Interface { + mac := net.HardwareAddr{0, 0x32, 0x7d, 0x69, 0xf7, byte(0x30 + index)} + return net.Interface{ + Index: index, + MTU: 1500, + Name: name, + HardwareAddr: mac, + Flags: flags} +} + +var ( + downIntf = makeIntf(1, "eth3", flagDown) + loopbackIntf = makeIntf(1, "lo", flagLoopback) + p2pIntf = makeIntf(1, "lo", flagP2P) + upIntf = makeIntf(1, "eth3", flagUp) +) + +var ( + ipv4Route = Route{Interface: "eth3", Destination: net.ParseIP("0.0.0.0"), Gateway: net.ParseIP("10.254.0.1"), Family: familyIPv4} + ipv6Route = Route{Interface: "eth3", Destination: net.ParseIP("::"), Gateway: net.ParseIP("2001:1::1"), Family: familyIPv6} +) + +var ( + noRoutes = []Route{} + routeV4 = []Route{ipv4Route} + routeV6 = []Route{ipv6Route} + bothRoutes = []Route{ipv4Route, ipv6Route} +) + +func TestGetIPv4Routes(t *testing.T) { + testCases := []struct { + tcase string + route string + count int + expected *Route + errStrFrag string + }{ + {"gatewayfirst", gatewayfirst, 1, &ipv4Route, ""}, + {"gatewaymiddle", gatewaymiddle, 1, &ipv4Route, ""}, + {"gatewaylast", gatewaylast, 1, &ipv4Route, ""}, + {"no routes", nothing, 0, nil, ""}, + {"badDestination", badDestination, 0, nil, "invalid IPv4"}, + {"badGateway", badGateway, 0, nil, "invalid IPv4"}, + {"route_Invalidhex", route_Invalidhex, 0, nil, "odd length hex string"}, + {"no default routes", noInternetConnection, 0, nil, ""}, + } + for _, tc := range testCases { + r := strings.NewReader(tc.route) + routes, err := getIPv4DefaultRoutes(r) + if err != nil { + if !strings.Contains(err.Error(), tc.errStrFrag) { + t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag) + } + } else if tc.errStrFrag != "" { + t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag) + } else { + if tc.count != len(routes) { + t.Errorf("case[%s]: expected %d routes, have %v", tc.tcase, tc.count, routes) + } else if tc.count == 1 { + if !tc.expected.Gateway.Equal(routes[0].Gateway) { + t.Errorf("case[%s]: expected %v, got %v .err : %v", tc.tcase, tc.expected, routes, err) + } + if !routes[0].Destination.Equal(net.IPv4zero) { + t.Errorf("case[%s}: destination is not for default route (not zero)", tc.tcase) + } + + } + } + } +} + +func TestGetIPv6Routes(t *testing.T) { + testCases := []struct { + tcase string + route string + count int + expected *Route + errStrFrag string + }{ + {"v6 gatewayfirst", v6gatewayfirst, 1, &ipv6Route, ""}, + {"v6 gatewaymiddle", v6gatewaymiddle, 1, &ipv6Route, ""}, + {"v6 gatewaylast", v6gatewaylast, 1, &ipv6Route, ""}, + {"v6 no routes", v6nothing, 0, nil, ""}, + {"v6 badDestination", v6badDestination, 0, nil, "invalid IPv6"}, + {"v6 badGateway", v6badGateway, 0, nil, "invalid IPv6"}, + {"v6 route_Invalidhex", v6route_Invalidhex, 0, nil, "odd length hex string"}, + {"v6 no default routes", v6noDefaultRoutes, 0, nil, ""}, + } + for _, tc := range testCases { + r := strings.NewReader(tc.route) + routes, err := getIPv6DefaultRoutes(r) + if err != nil { + if !strings.Contains(err.Error(), tc.errStrFrag) { + t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag) + } + } else if tc.errStrFrag != "" { + t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag) + } else { + if tc.count != len(routes) { + t.Errorf("case[%s]: expected %d routes, have %v", tc.tcase, tc.count, routes) + } else if tc.count == 1 { + if !tc.expected.Gateway.Equal(routes[0].Gateway) { + t.Errorf("case[%s]: expected %v, got %v .err : %v", tc.tcase, tc.expected, routes, err) + } + if !routes[0].Destination.Equal(net.IPv6zero) { + t.Errorf("case[%s}: destination is not for default route (not zero)", tc.tcase) + } + } + } + } +} + +func TestParseIP(t *testing.T) { + testCases := []struct { + tcase string + ip string + family AddressFamily + success bool + expected net.IP + }{ + {"empty", "", familyIPv4, false, nil}, + {"too short", "AA", familyIPv4, false, nil}, + {"too long", "0011223344", familyIPv4, false, nil}, + {"invalid", "invalid!", familyIPv4, false, nil}, + {"zero", "00000000", familyIPv4, true, net.IP{0, 0, 0, 0}}, + {"ffff", "FFFFFFFF", familyIPv4, true, net.IP{0xff, 0xff, 0xff, 0xff}}, + {"valid v4", "12345678", familyIPv4, true, net.IP{120, 86, 52, 18}}, + {"valid v6", "fe800000000000000000000000000000", familyIPv6, true, net.IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {"v6 too short", "fe80000000000000021fcafffea0ec0", familyIPv6, false, nil}, + {"v6 too long", "fe80000000000000021fcafffea0ec002", familyIPv6, false, nil}, + } + for _, tc := range testCases { + ip, err := parseIP(tc.ip, tc.family) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %q, got %q . err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestIsInterfaceUp(t *testing.T) { + testCases := []struct { + tcase string + intf *net.Interface + expected bool + }{ + {"up", &net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: net.FlagUp}, true}, + {"down", &net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0}, false}, + {"no interface", nil, false}, + } + for _, tc := range testCases { + it := isInterfaceUp(tc.intf) + if it != tc.expected { + t.Errorf("case[%v]: expected %v, got %v .", tc.tcase, tc.expected, it) + } + } +} + +type addrStruct struct{ val string } + +func (a addrStruct) Network() string { + return a.val +} +func (a addrStruct) String() string { + return a.val +} + +func TestFinalIP(t *testing.T) { + testCases := []struct { + tcase string + addr []net.Addr + family AddressFamily + expected net.IP + }{ + {"no ipv4", []net.Addr{addrStruct{val: "2001::5/64"}}, familyIPv4, nil}, + {"no ipv6", []net.Addr{addrStruct{val: "10.128.0.4/32"}}, familyIPv6, nil}, + {"invalidV4CIDR", []net.Addr{addrStruct{val: "10.20.30.40.50/24"}}, familyIPv4, nil}, + {"invalidV6CIDR", []net.Addr{addrStruct{val: "fe80::2f7:67fff:fe6e:2956/64"}}, familyIPv6, nil}, + {"loopback", []net.Addr{addrStruct{val: "127.0.0.1/24"}}, familyIPv4, nil}, + {"loopbackv6", []net.Addr{addrStruct{val: "::1/128"}}, familyIPv6, nil}, + {"link local v4", []net.Addr{addrStruct{val: "169.254.1.10/16"}}, familyIPv4, nil}, + {"link local v6", []net.Addr{addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}}, familyIPv6, nil}, + {"ip4", []net.Addr{addrStruct{val: "10.254.12.132/17"}}, familyIPv4, net.ParseIP("10.254.12.132")}, + {"ip6", []net.Addr{addrStruct{val: "2001::5/64"}}, familyIPv6, net.ParseIP("2001::5")}, + + {"no addresses", []net.Addr{}, familyIPv4, nil}, + } + for _, tc := range testCases { + ip, err := getMatchingGlobalIP(tc.addr, tc.family) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestAddrs(t *testing.T) { + var nw networkInterfacer = validNetworkInterface{} + intf := net.Interface{Index: 0, MTU: 0, Name: "eth3", HardwareAddr: nil, Flags: 0} + addrs, err := nw.Addrs(&intf) + if err != nil { + t.Errorf("expected no error got : %v", err) + } + if len(addrs) != 2 { + t.Errorf("expected addrs: 2 got null") + } +} + +// Has a valid IPv4 address (IPv6 is LLA) +type validNetworkInterface struct { +} + +func (_ validNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ validNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{ + addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}} + return ifat, nil +} +func (_ validNetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +// Both IPv4 and IPv6 addresses (expecting IPv4 to be used) +type v4v6NetworkInterface struct { +} + +func (_ v4v6NetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ v4v6NetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{ + addrStruct{val: "2001::10/64"}, addrStruct{val: "10.254.71.145/17"}} + return ifat, nil +} +func (_ v4v6NetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +// Interface with only IPv6 address +type ipv6NetworkInterface struct { +} + +func (_ ipv6NetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ ipv6NetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{addrStruct{val: "2001::200/64"}} + return ifat, nil +} + +func (_ ipv6NetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +// Only with link local addresses +type networkInterfaceWithOnlyLinkLocals struct { +} + +func (_ networkInterfaceWithOnlyLinkLocals) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ networkInterfaceWithOnlyLinkLocals) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{addrStruct{val: "169.254.162.166/16"}, addrStruct{val: "fe80::200/10"}} + return ifat, nil +} +func (_ networkInterfaceWithOnlyLinkLocals) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +// Unable to get interface(s) +type failGettingNetworkInterface struct { +} + +func (_ failGettingNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return nil, fmt.Errorf("unable get Interface") +} +func (_ failGettingNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + return nil, nil +} +func (_ failGettingNetworkInterface) Interfaces() ([]net.Interface, error) { + return nil, fmt.Errorf("mock failed getting all interfaces") +} + +// No interfaces +type noNetworkInterface struct { +} + +func (_ noNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return nil, fmt.Errorf("no such network interface") +} +func (_ noNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + return nil, nil +} +func (_ noNetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{}, nil +} + +// Interface is down +type downNetworkInterface struct { +} + +func (_ downNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return &downIntf, nil +} +func (_ downNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{ + addrStruct{val: "fe80::2f7:6fff:fe6e:2956/64"}, addrStruct{val: "10.254.71.145/17"}} + return ifat, nil +} +func (_ downNetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{downIntf}, nil +} + +// Loopback interface +type loopbackNetworkInterface struct { +} + +func (_ loopbackNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return &loopbackIntf, nil +} +func (_ loopbackNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{ + addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"}} + return ifat, nil +} +func (_ loopbackNetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{loopbackIntf}, nil +} + +// Point to point interface +type p2pNetworkInterface struct { +} + +func (_ p2pNetworkInterface) InterfaceByName(intfName string) (*net.Interface, error) { + return &p2pIntf, nil +} +func (_ p2pNetworkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{ + addrStruct{val: "::1/128"}, addrStruct{val: "127.0.0.1/8"}} + return ifat, nil +} +func (_ p2pNetworkInterface) Interfaces() ([]net.Interface, error) { + return []net.Interface{p2pIntf}, nil +} + +// Unable to get IP addresses for interface +type networkInterfaceFailGetAddrs struct { +} + +func (_ networkInterfaceFailGetAddrs) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ networkInterfaceFailGetAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) { + return nil, fmt.Errorf("unable to get Addrs") +} +func (_ networkInterfaceFailGetAddrs) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +// No addresses for interface +type networkInterfaceWithNoAddrs struct { +} + +func (_ networkInterfaceWithNoAddrs) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ networkInterfaceWithNoAddrs) Addrs(intf *net.Interface) ([]net.Addr, error) { + ifat := []net.Addr{} + return ifat, nil +} +func (_ networkInterfaceWithNoAddrs) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +// Invalid addresses for interface +type networkInterfaceWithInvalidAddr struct { +} + +func (_ networkInterfaceWithInvalidAddr) InterfaceByName(intfName string) (*net.Interface, error) { + return &upIntf, nil +} +func (_ networkInterfaceWithInvalidAddr) Addrs(intf *net.Interface) ([]net.Addr, error) { + var ifat []net.Addr + ifat = []net.Addr{addrStruct{val: "10.20.30.40.50/24"}} + return ifat, nil +} +func (_ networkInterfaceWithInvalidAddr) Interfaces() ([]net.Interface, error) { + return []net.Interface{upIntf}, nil +} + +func TestGetIPFromInterface(t *testing.T) { + testCases := []struct { + tcase string + nwname string + family AddressFamily + nw networkInterfacer + expected net.IP + errStrFrag string + }{ + {"ipv4", "eth3", familyIPv4, validNetworkInterface{}, net.ParseIP("10.254.71.145"), ""}, + {"ipv6", "eth3", familyIPv6, ipv6NetworkInterface{}, net.ParseIP("2001::200"), ""}, + {"no ipv4", "eth3", familyIPv4, ipv6NetworkInterface{}, nil, ""}, + {"no ipv6", "eth3", familyIPv6, validNetworkInterface{}, nil, ""}, + {"I/F down", "eth3", familyIPv4, downNetworkInterface{}, nil, ""}, + {"I/F get fail", "eth3", familyIPv4, noNetworkInterface{}, nil, "no such network interface"}, + {"fail get addr", "eth3", familyIPv4, networkInterfaceFailGetAddrs{}, nil, "unable to get Addrs"}, + {"bad addr", "eth3", familyIPv4, networkInterfaceWithInvalidAddr{}, nil, "invalid CIDR"}, + } + for _, tc := range testCases { + ip, err := getIPFromInterface(tc.nwname, tc.family, tc.nw) + if err != nil { + if !strings.Contains(err.Error(), tc.errStrFrag) { + t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag) + } + } else if tc.errStrFrag != "" { + t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag) + } else if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestChooseHostInterfaceFromRoute(t *testing.T) { + testCases := []struct { + tcase string + routes []Route + nw networkInterfacer + expected net.IP + }{ + {"ipv4", routeV4, validNetworkInterface{}, net.ParseIP("10.254.71.145")}, + {"ipv6", routeV6, ipv6NetworkInterface{}, net.ParseIP("2001::200")}, + {"prefer ipv4", bothRoutes, v4v6NetworkInterface{}, net.ParseIP("10.254.71.145")}, + {"all LLA", routeV4, networkInterfaceWithOnlyLinkLocals{}, nil}, + {"no routes", noRoutes, validNetworkInterface{}, nil}, + {"fail get IP", routeV4, networkInterfaceFailGetAddrs{}, nil}, + } + for _, tc := range testCases { + ip, err := chooseHostInterfaceFromRoute(tc.routes, tc.nw) + if !ip.Equal(tc.expected) { + t.Errorf("case[%v]: expected %v, got %+v .err : %v", tc.tcase, tc.expected, ip, err) + } + } +} + +func TestMemberOf(t *testing.T) { + testCases := []struct { + tcase string + ip net.IP + family AddressFamily + expected bool + }{ + {"ipv4 is 4", net.ParseIP("10.20.30.40"), familyIPv4, true}, + {"ipv4 is 6", net.ParseIP("10.10.10.10"), familyIPv6, false}, + {"ipv6 is 4", net.ParseIP("2001::100"), familyIPv4, false}, + {"ipv6 is 6", net.ParseIP("2001::100"), familyIPv6, true}, + } + for _, tc := range testCases { + if memberOf(tc.ip, tc.family) != tc.expected { + t.Errorf("case[%s]: expected %+v", tc.tcase, tc.expected) + } + } +} + +func TestGetIPFromHostInterfaces(t *testing.T) { + testCases := []struct { + tcase string + nw networkInterfacer + expected net.IP + errStrFrag string + }{ + {"fail get I/Fs", failGettingNetworkInterface{}, nil, "failed getting all interfaces"}, + {"no interfaces", noNetworkInterface{}, nil, "no interfaces"}, + {"I/F not up", downNetworkInterface{}, nil, "no acceptable"}, + {"loopback only", loopbackNetworkInterface{}, nil, "no acceptable"}, + {"P2P I/F only", p2pNetworkInterface{}, nil, "no acceptable"}, + {"fail get addrs", networkInterfaceFailGetAddrs{}, nil, "unable to get Addrs"}, + {"no addresses", networkInterfaceWithNoAddrs{}, nil, "no acceptable"}, + {"invalid addr", networkInterfaceWithInvalidAddr{}, nil, "invalid CIDR"}, + {"no matches", networkInterfaceWithOnlyLinkLocals{}, nil, "no acceptable"}, + {"ipv4", validNetworkInterface{}, net.ParseIP("10.254.71.145"), ""}, + {"ipv6", ipv6NetworkInterface{}, net.ParseIP("2001::200"), ""}, + } + + for _, tc := range testCases { + ip, err := chooseIPFromHostInterfaces(tc.nw) + if !ip.Equal(tc.expected) { + t.Errorf("case[%s]: expected %+v, got %+v with err : %v", tc.tcase, tc.expected, ip, err) + } + if err != nil && !strings.Contains(err.Error(), tc.errStrFrag) { + t.Errorf("case[%s]: unable to find %q in error string %q", tc.tcase, tc.errStrFrag, err.Error()) + } + } +} + +func makeRouteFile(content string, t *testing.T) (*os.File, error) { + routeFile, err := ioutil.TempFile("", "route") + if err != nil { + return nil, err + } + + if _, err := routeFile.Write([]byte(content)); err != nil { + return routeFile, err + } + err = routeFile.Close() + return routeFile, err +} + +func TestFailGettingIPv4Routes(t *testing.T) { + defer func() { v4File.name = ipv4RouteFile }() + + // Try failure to open file (should not occur, as caller ensures we have IPv4 route file, but being thorough) + v4File.name = "no-such-file" + errStrFrag := "no such file" + _, err := v4File.extract() + if err == nil { + t.Errorf("Expected error trying to read non-existent v4 route file") + } + if !strings.Contains(err.Error(), errStrFrag) { + t.Errorf("Unable to find %q in error string %q", errStrFrag, err.Error()) + } +} + +func TestFailGettingIPv6Routes(t *testing.T) { + defer func() { v6File.name = ipv6RouteFile }() + + // Try failure to open file (this would be ignored by caller) + v6File.name = "no-such-file" + errStrFrag := "no such file" + _, err := v6File.extract() + if err == nil { + t.Errorf("Expected error trying to read non-existent v6 route file") + } + if !strings.Contains(err.Error(), errStrFrag) { + t.Errorf("Unable to find %q in error string %q", errStrFrag, err.Error()) + } +} + +func TestGetAllDefaultRoutesFailNoV4RouteFile(t *testing.T) { + defer func() { v4File.name = ipv4RouteFile }() + + // Should not occur, as caller ensures we have IPv4 route file, but being thorough + v4File.name = "no-such-file" + errStrFrag := "no such file" + _, err := getAllDefaultRoutes() + if err == nil { + t.Errorf("Expected error trying to read non-existent v4 route file") + } + if !strings.Contains(err.Error(), errStrFrag) { + t.Errorf("Unable to find %q in error string %q", errStrFrag, err.Error()) + } +} + +func TestGetAllDefaultRoutes(t *testing.T) { + testCases := []struct { + tcase string + v4Info string + v6Info string + count int + expected []Route + errStrFrag string + }{ + {"no routes", noInternetConnection, v6noDefaultRoutes, 0, nil, "no default routes"}, + {"only v4 route", gatewayfirst, v6noDefaultRoutes, 1, routeV4, ""}, + {"only v6 route", noInternetConnection, v6gatewayfirst, 1, routeV6, ""}, + {"v4 and v6 routes", gatewayfirst, v6gatewayfirst, 2, bothRoutes, ""}, + } + defer func() { + v4File.name = ipv4RouteFile + v6File.name = ipv6RouteFile + }() + + for _, tc := range testCases { + routeFile, err := makeRouteFile(tc.v4Info, t) + if routeFile != nil { + defer os.Remove(routeFile.Name()) + } + if err != nil { + t.Errorf("case[%s]: test setup failure for IPv4 route file: %v", tc.tcase, err) + } + v4File.name = routeFile.Name() + v6routeFile, err := makeRouteFile(tc.v6Info, t) + if v6routeFile != nil { + defer os.Remove(v6routeFile.Name()) + } + if err != nil { + t.Errorf("case[%s]: test setup failure for IPv6 route file: %v", tc.tcase, err) + } + v6File.name = v6routeFile.Name() + + routes, err := getAllDefaultRoutes() + if err != nil { + if !strings.Contains(err.Error(), tc.errStrFrag) { + t.Errorf("case[%s]: Error string %q does not contain %q", tc.tcase, err, tc.errStrFrag) + } + } else if tc.errStrFrag != "" { + t.Errorf("case[%s]: Error %q expected, but not seen", tc.tcase, tc.errStrFrag) + } else { + if tc.count != len(routes) { + t.Errorf("case[%s]: expected %d routes, have %v", tc.tcase, tc.count, routes) + } + for i, expected := range tc.expected { + if !expected.Gateway.Equal(routes[i].Gateway) { + t.Errorf("case[%s]: at %d expected %v, got %v .err : %v", tc.tcase, i, tc.expected, routes, err) + } + zeroIP := net.IPv4zero + if expected.Family == familyIPv6 { + zeroIP = net.IPv6zero + } + if !routes[i].Destination.Equal(zeroIP) { + t.Errorf("case[%s}: at %d destination is not for default route (not %v)", tc.tcase, i, zeroIP) + } + } + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/port_range_test.go b/vendor/k8s.io/apimachinery/pkg/util/net/port_range_test.go new file mode 100644 index 000000000..b4cbe8245 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/net/port_range_test.go @@ -0,0 +1,77 @@ +/* +Copyright 2015 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 net + +import ( + "testing" + + flag "github.com/spf13/pflag" +) + +func TestPortRange(t *testing.T) { + testCases := []struct { + input string + success bool + expected string + included int + excluded int + }{ + {"100-200", true, "100-200", 200, 201}, + {" 100-200 ", true, "100-200", 200, 201}, + {"0-0", true, "0-0", 0, 1}, + {"", true, "", -1, 0}, + {"100", true, "100-100", 100, 101}, + {"100 - 200", false, "", -1, -1}, + {"-100", false, "", -1, -1}, + {"100-", false, "", -1, -1}, + {"200-100", false, "", -1, -1}, + {"60000-70000", false, "", -1, -1}, + {"70000-80000", false, "", -1, -1}, + {"70000+80000", false, "", -1, -1}, + {"1+0", true, "1-1", 1, 2}, + {"0+0", true, "0-0", 0, 1}, + {"1+-1", false, "", -1, -1}, + {"1-+1", false, "", -1, -1}, + {"100+200", true, "100-300", 300, 301}, + {"1+65535", false, "", -1, -1}, + {"0+65535", true, "0-65535", 65535, 65536}, + } + + for i := range testCases { + tc := &testCases[i] + pr := &PortRange{} + var f flag.Value = pr + err := f.Set(tc.input) + if err != nil && tc.success == true { + t.Errorf("expected success, got %q", err) + continue + } else if err == nil && tc.success == false { + t.Errorf("expected failure %#v", testCases[i]) + continue + } else if tc.success { + if f.String() != tc.expected { + t.Errorf("expected %q, got %q", tc.expected, f.String()) + } + if tc.included >= 0 && !pr.Contains(tc.included) { + t.Errorf("expected %q to include %d", f.String(), tc.included) + } + if tc.excluded >= 0 && pr.Contains(tc.excluded) { + t.Errorf("expected %q to exclude %d", f.String(), tc.excluded) + } + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/port_split_test.go b/vendor/k8s.io/apimachinery/pkg/util/net/port_split_test.go new file mode 100644 index 000000000..e801bdbea --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/net/port_split_test.go @@ -0,0 +1,121 @@ +/* +Copyright 2015 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 net + +import ( + "testing" +) + +func TestSplitSchemeNamePort(t *testing.T) { + table := []struct { + in string + name, port, scheme string + valid bool + normalized bool + }{ + { + in: "aoeu:asdf", + name: "aoeu", + port: "asdf", + valid: true, + normalized: true, + }, { + in: "http:aoeu:asdf", + scheme: "http", + name: "aoeu", + port: "asdf", + valid: true, + normalized: true, + }, { + in: "https:aoeu:", + scheme: "https", + name: "aoeu", + port: "", + valid: true, + normalized: false, + }, { + in: "https:aoeu:asdf", + scheme: "https", + name: "aoeu", + port: "asdf", + valid: true, + normalized: true, + }, { + in: "aoeu:", + name: "aoeu", + valid: true, + normalized: false, + }, { + in: "aoeu", + name: "aoeu", + valid: true, + normalized: true, + }, { + in: ":asdf", + valid: false, + }, { + in: "aoeu:asdf:htns", + valid: false, + }, { + in: "http::asdf", + valid: false, + }, { + in: "http::", + valid: false, + }, { + in: "", + valid: false, + }, + } + + for _, item := range table { + scheme, name, port, valid := SplitSchemeNamePort(item.in) + if e, a := item.scheme, scheme; e != a { + t.Errorf("%q: Wanted %q, got %q", item.in, e, a) + } + if e, a := item.name, name; e != a { + t.Errorf("%q: Wanted %q, got %q", item.in, e, a) + } + if e, a := item.port, port; e != a { + t.Errorf("%q: Wanted %q, got %q", item.in, e, a) + } + if e, a := item.valid, valid; e != a { + t.Errorf("%q: Wanted %t, got %t", item.in, e, a) + } + + // Make sure valid items round trip through JoinSchemeNamePort + if item.valid { + out := JoinSchemeNamePort(scheme, name, port) + if item.normalized && out != item.in { + t.Errorf("%q: Wanted %s, got %s", item.in, item.in, out) + } + scheme, name, port, valid := SplitSchemeNamePort(out) + if e, a := item.scheme, scheme; e != a { + t.Errorf("%q: Wanted %q, got %q", item.in, e, a) + } + if e, a := item.name, name; e != a { + t.Errorf("%q: Wanted %q, got %q", item.in, e, a) + } + if e, a := item.port, port; e != a { + t.Errorf("%q: Wanted %q, got %q", item.in, e, a) + } + if e, a := item.valid, valid; e != a { + t.Errorf("%q: Wanted %t, got %t", item.in, e, a) + } + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/util_test.go b/vendor/k8s.io/apimachinery/pkg/util/net/util_test.go new file mode 100644 index 000000000..bcbef753b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/net/util_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2016 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 net + +import ( + "net" + "testing" +) + +func getIPNet(cidr string) *net.IPNet { + _, ipnet, _ := net.ParseCIDR(cidr) + return ipnet +} + +func TestIPNetEqual(t *testing.T) { + testCases := []struct { + ipnet1 *net.IPNet + ipnet2 *net.IPNet + expect bool + }{ + //null case + { + getIPNet("10.0.0.1/24"), + getIPNet(""), + false, + }, + { + getIPNet("10.0.0.0/24"), + getIPNet("10.0.0.0/24"), + true, + }, + { + getIPNet("10.0.0.0/24"), + getIPNet("10.0.0.1/24"), + true, + }, + { + getIPNet("10.0.0.0/25"), + getIPNet("10.0.0.0/24"), + false, + }, + { + getIPNet("10.0.1.0/24"), + getIPNet("10.0.0.0/24"), + false, + }, + } + + for _, tc := range testCases { + if tc.expect != IPNetEqual(tc.ipnet1, tc.ipnet2) { + t.Errorf("Expect equality of %s and %s be to %v", tc.ipnet1.String(), tc.ipnet2.String(), tc.expect) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/rand/rand_test.go b/vendor/k8s.io/apimachinery/pkg/util/rand/rand_test.go new file mode 100644 index 000000000..517043a52 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/rand/rand_test.go @@ -0,0 +1,114 @@ +/* +Copyright 2015 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 rand + +import ( + "math/rand" + "strings" + "testing" +) + +const ( + maxRangeTestCount = 500 + testStringLength = 32 +) + +func TestString(t *testing.T) { + valid := "0123456789abcdefghijklmnopqrstuvwxyz" + for _, l := range []int{0, 1, 2, 10, 123} { + s := String(l) + if len(s) != l { + t.Errorf("expected string of size %d, got %q", l, s) + } + for _, c := range s { + if !strings.ContainsRune(valid, c) { + t.Errorf("expected valid characters, got %v", c) + } + } + } +} + +// Confirm that panic occurs on invalid input. +func TestRangePanic(t *testing.T) { + defer func() { + if err := recover(); err == nil { + t.Errorf("Panic didn't occur!") + } + }() + // Should result in an error... + Intn(0) +} + +func TestIntn(t *testing.T) { + // 0 is invalid. + for _, max := range []int{1, 2, 10, 123} { + inrange := Intn(max) + if inrange < 0 || inrange > max { + t.Errorf("%v out of range (0,%v)", inrange, max) + } + } +} + +func TestPerm(t *testing.T) { + Seed(5) + rand.Seed(5) + for i := 1; i < 20; i++ { + actual := Perm(i) + expected := rand.Perm(i) + for j := 0; j < i; j++ { + if actual[j] != expected[j] { + t.Errorf("Perm call result is unexpected") + } + } + } +} + +func TestIntnRange(t *testing.T) { + // 0 is invalid. + for min, max := range map[int]int{1: 2, 10: 123, 100: 500} { + for i := 0; i < maxRangeTestCount; i++ { + inrange := IntnRange(min, max) + if inrange < min || inrange >= max { + t.Errorf("%v out of range (%v,%v)", inrange, min, max) + } + } + } +} + +func TestInt63nRange(t *testing.T) { + // 0 is invalid. + for min, max := range map[int64]int64{1: 2, 10: 123, 100: 500} { + for i := 0; i < maxRangeTestCount; i++ { + inrange := Int63nRange(min, max) + if inrange < min || inrange >= max { + t.Errorf("%v out of range (%v,%v)", inrange, min, max) + } + } + } +} + +func BenchmarkRandomStringGeneration(b *testing.B) { + b.ResetTimer() + var s string + for i := 0; i < b.N; i++ { + s = String(testStringLength) + } + b.StopTimer() + if len(s) == 0 { + b.Fatal(s) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime_test.go b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime_test.go new file mode 100644 index 000000000..9dff17ea5 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2014 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 runtime + +import ( + "fmt" + "testing" +) + +func TestHandleCrash(t *testing.T) { + defer func() { + if x := recover(); x == nil { + t.Errorf("Expected a panic to recover from") + } + }() + defer HandleCrash() + panic("Test Panic") +} + +func TestCustomHandleCrash(t *testing.T) { + old := PanicHandlers + defer func() { PanicHandlers = old }() + var result interface{} + PanicHandlers = []func(interface{}){ + func(r interface{}) { + result = r + }, + } + func() { + defer func() { + if x := recover(); x == nil { + t.Errorf("Expected a panic to recover from") + } + }() + defer HandleCrash() + panic("test") + }() + if result != "test" { + t.Errorf("did not receive custom handler") + } +} + +func TestCustomHandleError(t *testing.T) { + old := ErrorHandlers + defer func() { ErrorHandlers = old }() + var result error + ErrorHandlers = []func(error){ + func(err error) { + result = err + }, + } + err := fmt.Errorf("test") + HandleError(err) + if result != err { + t.Errorf("did not receive custom handler") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/sets/set_test.go b/vendor/k8s.io/apimachinery/pkg/util/sets/set_test.go new file mode 100644 index 000000000..df722ec27 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/sets/set_test.go @@ -0,0 +1,270 @@ +/* +Copyright 2014 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 sets + +import ( + "reflect" + "testing" +) + +func TestStringSet(t *testing.T) { + s := String{} + s2 := String{} + if len(s) != 0 { + t.Errorf("Expected len=0: %d", len(s)) + } + s.Insert("a", "b") + if len(s) != 2 { + t.Errorf("Expected len=2: %d", len(s)) + } + s.Insert("c") + if s.Has("d") { + t.Errorf("Unexpected contents: %#v", s) + } + if !s.Has("a") { + t.Errorf("Missing contents: %#v", s) + } + s.Delete("a") + if s.Has("a") { + t.Errorf("Unexpected contents: %#v", s) + } + s.Insert("a") + if s.HasAll("a", "b", "d") { + t.Errorf("Unexpected contents: %#v", s) + } + if !s.HasAll("a", "b") { + t.Errorf("Missing contents: %#v", s) + } + s2.Insert("a", "b", "d") + if s.IsSuperset(s2) { + t.Errorf("Unexpected contents: %#v", s) + } + s2.Delete("d") + if !s.IsSuperset(s2) { + t.Errorf("Missing contents: %#v", s) + } +} + +func TestStringSetDeleteMultiples(t *testing.T) { + s := String{} + s.Insert("a", "b", "c") + if len(s) != 3 { + t.Errorf("Expected len=3: %d", len(s)) + } + + s.Delete("a", "c") + if len(s) != 1 { + t.Errorf("Expected len=1: %d", len(s)) + } + if s.Has("a") { + t.Errorf("Unexpected contents: %#v", s) + } + if s.Has("c") { + t.Errorf("Unexpected contents: %#v", s) + } + if !s.Has("b") { + t.Errorf("Missing contents: %#v", s) + } + +} + +func TestNewStringSet(t *testing.T) { + s := NewString("a", "b", "c") + if len(s) != 3 { + t.Errorf("Expected len=3: %d", len(s)) + } + if !s.Has("a") || !s.Has("b") || !s.Has("c") { + t.Errorf("Unexpected contents: %#v", s) + } +} + +func TestStringSetList(t *testing.T) { + s := NewString("z", "y", "x", "a") + if !reflect.DeepEqual(s.List(), []string{"a", "x", "y", "z"}) { + t.Errorf("List gave unexpected result: %#v", s.List()) + } +} + +func TestStringSetDifference(t *testing.T) { + a := NewString("1", "2", "3") + b := NewString("1", "2", "4", "5") + c := a.Difference(b) + d := b.Difference(a) + if len(c) != 1 { + t.Errorf("Expected len=1: %d", len(c)) + } + if !c.Has("3") { + t.Errorf("Unexpected contents: %#v", c.List()) + } + if len(d) != 2 { + t.Errorf("Expected len=2: %d", len(d)) + } + if !d.Has("4") || !d.Has("5") { + t.Errorf("Unexpected contents: %#v", d.List()) + } +} + +func TestStringSetHasAny(t *testing.T) { + a := NewString("1", "2", "3") + + if !a.HasAny("1", "4") { + t.Errorf("expected true, got false") + } + + if a.HasAny("0", "4") { + t.Errorf("expected false, got true") + } +} + +func TestStringSetEquals(t *testing.T) { + // Simple case (order doesn't matter) + a := NewString("1", "2") + b := NewString("2", "1") + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + // It is a set; duplicates are ignored + b = NewString("2", "2", "1") + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + // Edge cases around empty sets / empty strings + a = NewString() + b = NewString() + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + b = NewString("1", "2", "3") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + b = NewString("1", "2", "") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + // Check for equality after mutation + a = NewString() + a.Insert("1") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + a.Insert("2") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + a.Insert("") + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + a.Delete("") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } +} + +func TestStringUnion(t *testing.T) { + tests := []struct { + s1 String + s2 String + expected String + }{ + { + NewString("1", "2", "3", "4"), + NewString("3", "4", "5", "6"), + NewString("1", "2", "3", "4", "5", "6"), + }, + { + NewString("1", "2", "3", "4"), + NewString(), + NewString("1", "2", "3", "4"), + }, + { + NewString(), + NewString("1", "2", "3", "4"), + NewString("1", "2", "3", "4"), + }, + { + NewString(), + NewString(), + NewString(), + }, + } + + for _, test := range tests { + union := test.s1.Union(test.s2) + if union.Len() != test.expected.Len() { + t.Errorf("Expected union.Len()=%d but got %d", test.expected.Len(), union.Len()) + } + + if !union.Equal(test.expected) { + t.Errorf("Expected union.Equal(expected) but not true. union:%v expected:%v", union.List(), test.expected.List()) + } + } +} + +func TestStringIntersection(t *testing.T) { + tests := []struct { + s1 String + s2 String + expected String + }{ + { + NewString("1", "2", "3", "4"), + NewString("3", "4", "5", "6"), + NewString("3", "4"), + }, + { + NewString("1", "2", "3", "4"), + NewString("1", "2", "3", "4"), + NewString("1", "2", "3", "4"), + }, + { + NewString("1", "2", "3", "4"), + NewString(), + NewString(), + }, + { + NewString(), + NewString("1", "2", "3", "4"), + NewString(), + }, + { + NewString(), + NewString(), + NewString(), + }, + } + + for _, test := range tests { + intersection := test.s1.Intersection(test.s2) + if intersection.Len() != test.expected.Len() { + t.Errorf("Expected intersection.Len()=%d but got %d", test.expected.Len(), intersection.Len()) + } + + if !intersection.Equal(test.expected) { + t.Errorf("Expected intersection.Equal(expected) but not true. intersection:%v expected:%v", intersection.List(), test.expected.List()) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/OWNERS b/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/OWNERS new file mode 100644 index 000000000..dbbe0de4c --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/OWNERS @@ -0,0 +1,6 @@ +approvers: +- pwittrock +- mengqiy +reviewers: +- mengqiy +- apelisse diff --git a/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go b/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go new file mode 100644 index 000000000..4721803cc --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/strategicpatch/patch_test.go @@ -0,0 +1,6763 @@ +/* +Copyright 2014 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 strategicpatch + +import ( + "fmt" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/ghodss/yaml" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/apimachinery/pkg/util/mergepatch" + "k8s.io/apimachinery/pkg/util/sets" + sptest "k8s.io/apimachinery/pkg/util/strategicpatch/testing" +) + +var ( + fakeMergeItemSchema = sptest.Fake{Path: filepath.Join("testdata", "swagger-merge-item.json")} + fakePrecisionItemSchema = sptest.Fake{Path: filepath.Join("testdata", "swagger-precision-item.json")} +) + +type SortMergeListTestCases struct { + TestCases []SortMergeListTestCase +} + +type SortMergeListTestCase struct { + Description string + Original map[string]interface{} + Sorted map[string]interface{} +} + +type StrategicMergePatchTestCases struct { + TestCases []StrategicMergePatchTestCase +} + +type StrategicMergePatchTestCase struct { + Description string + StrategicMergePatchTestCaseData +} + +type StrategicMergePatchRawTestCase struct { + Description string + StrategicMergePatchRawTestCaseData +} + +type StrategicMergePatchTestCaseData struct { + // Original is the original object (last-applied config in annotation) + Original map[string]interface{} + // Modified is the modified object (new config we want) + Modified map[string]interface{} + // Current is the current object (live config in the server) + Current map[string]interface{} + // TwoWay is the expected two-way merge patch diff between original and modified + TwoWay map[string]interface{} + // ThreeWay is the expected three-way merge patch + ThreeWay map[string]interface{} + // Result is the expected object after applying the three-way patch on current object. + Result map[string]interface{} + // TwoWayResult is the expected object after applying the two-way patch on current object. + // If nil, Modified is used. + TwoWayResult map[string]interface{} +} + +// The meaning of each field is the same as StrategicMergePatchTestCaseData's. +// The difference is that all the fields in StrategicMergePatchRawTestCaseData are json-encoded data. +type StrategicMergePatchRawTestCaseData struct { + Original []byte + Modified []byte + Current []byte + TwoWay []byte + ThreeWay []byte + Result []byte + TwoWayResult []byte + ExpectedError string +} + +type MergeItem struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` + Other string `json:"other,omitempty"` + MergingList []MergeItem `json:"mergingList,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + NonMergingList []MergeItem `json:"nonMergingList,omitempty"` + MergingIntList []int `json:"mergingIntList,omitempty" patchStrategy:"merge"` + NonMergingIntList []int `json:"nonMergingIntList,omitempty"` + MergeItemPtr *MergeItem `json:"mergeItemPtr,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + SimpleMap map[string]string `json:"simpleMap,omitempty"` + ReplacingItem runtime.RawExtension `json:"replacingItem,omitempty" patchStrategy:"replace"` + RetainKeysMap RetainKeysMergeItem `json:"retainKeysMap,omitempty" patchStrategy:"retainKeys"` + RetainKeysMergingList []MergeItem `json:"retainKeysMergingList,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name"` +} + +type RetainKeysMergeItem struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` + Other string `json:"other,omitempty"` + SimpleMap map[string]string `json:"simpleMap,omitempty"` + MergingIntList []int `json:"mergingIntList,omitempty" patchStrategy:"merge"` + MergingList []MergeItem `json:"mergingList,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + NonMergingList []MergeItem `json:"nonMergingList,omitempty"` +} + +var ( + mergeItem MergeItem + mergeItemStructSchema = PatchMetaFromStruct{T: GetTagStructTypeOrDie(mergeItem)} +) + +// These are test cases for SortMergeList, used to assert that it (recursively) +// sorts both merging and non merging lists correctly. +var sortMergeListTestCaseData = []byte(` +testCases: + - description: sort one list of maps + original: + mergingList: + - name: 1 + - name: 3 + - name: 2 + sorted: + mergingList: + - name: 1 + - name: 2 + - name: 3 + - description: sort lists of maps but not nested lists of maps + original: + mergingList: + - name: 2 + nonMergingList: + - name: 1 + - name: 3 + - name: 2 + - name: 1 + nonMergingList: + - name: 2 + - name: 1 + sorted: + mergingList: + - name: 1 + nonMergingList: + - name: 2 + - name: 1 + - name: 2 + nonMergingList: + - name: 1 + - name: 3 + - name: 2 + - description: sort lists of maps and nested lists of maps + original: + mergingList: + - name: 2 + mergingList: + - name: 1 + - name: 3 + - name: 2 + - name: 1 + mergingList: + - name: 2 + - name: 1 + sorted: + mergingList: + - name: 1 + mergingList: + - name: 1 + - name: 2 + - name: 2 + mergingList: + - name: 1 + - name: 2 + - name: 3 + - description: merging list should NOT sort when nested in non merging list + original: + nonMergingList: + - name: 2 + mergingList: + - name: 1 + - name: 3 + - name: 2 + - name: 1 + mergingList: + - name: 2 + - name: 1 + sorted: + nonMergingList: + - name: 2 + mergingList: + - name: 1 + - name: 3 + - name: 2 + - name: 1 + mergingList: + - name: 2 + - name: 1 + - description: sort very nested list of maps + fieldTypes: + original: + mergingList: + - mergingList: + - mergingList: + - name: 2 + - name: 1 + sorted: + mergingList: + - mergingList: + - mergingList: + - name: 1 + - name: 2 + - description: sort nested lists of ints + original: + mergingList: + - name: 2 + mergingIntList: + - 1 + - 3 + - 2 + - name: 1 + mergingIntList: + - 2 + - 1 + sorted: + mergingList: + - name: 1 + mergingIntList: + - 1 + - 2 + - name: 2 + mergingIntList: + - 1 + - 2 + - 3 + - description: sort nested pointers of ints + original: + mergeItemPtr: + - name: 2 + mergingIntList: + - 1 + - 3 + - 2 + - name: 1 + mergingIntList: + - 2 + - 1 + sorted: + mergeItemPtr: + - name: 1 + mergingIntList: + - 1 + - 2 + - name: 2 + mergingIntList: + - 1 + - 2 + - 3 + - description: sort merging list by pointer + original: + mergeItemPtr: + - name: 1 + - name: 3 + - name: 2 + sorted: + mergeItemPtr: + - name: 1 + - name: 2 + - name: 3 +`) + +func TestSortMergeLists(t *testing.T) { + mergeItemOpenapiSchema := PatchMetaFromOpenAPI{ + Schema: sptest.GetSchemaOrDie(fakeMergeItemSchema, "mergeItem"), + } + schemas := []LookupPatchMeta{ + mergeItemStructSchema, + mergeItemOpenapiSchema, + } + + tc := SortMergeListTestCases{} + err := yaml.Unmarshal(sortMergeListTestCaseData, &tc) + if err != nil { + t.Errorf("can't unmarshal test cases: %s\n", err) + return + } + + for _, schema := range schemas { + for _, c := range tc.TestCases { + temp := testObjectToJSONOrFail(t, c.Original) + got := sortJsonOrFail(t, temp, c.Description, schema) + expected := testObjectToJSONOrFail(t, c.Sorted) + if !reflect.DeepEqual(got, expected) { + t.Errorf("using %s error in test case: %s\ncannot sort object:\n%s\nexpected:\n%s\ngot:\n%s\n", + getSchemaType(schema), c.Description, mergepatch.ToYAMLOrError(c.Original), mergepatch.ToYAMLOrError(c.Sorted), jsonToYAMLOrError(got)) + } + } + } +} + +// These are test cases for StrategicMergePatch that cannot be generated using +// CreateTwoWayMergePatch because it may be one of the following cases: +// - not use the replace directive. +// - generate duplicate integers for a merging list patch. +// - generate empty merging lists. +// - use patch format from an old client. +var customStrategicMergePatchTestCaseData = []byte(` +testCases: + - description: unique scalars when merging lists + original: + mergingIntList: + - 1 + - 2 + twoWay: + mergingIntList: + - 2 + - 3 + modified: + mergingIntList: + - 1 + - 2 + - 3 + - description: delete map from nested map + original: + simpleMap: + key1: 1 + key2: 1 + twoWay: + simpleMap: + $patch: delete + modified: + simpleMap: + {} + - description: delete all items from merging list + original: + mergingList: + - name: 1 + - name: 2 + twoWay: + mergingList: + - $patch: replace + modified: + mergingList: [] + - description: merge empty merging lists + original: + mergingList: [] + twoWay: + mergingList: [] + modified: + mergingList: [] + - description: delete all keys from map + original: + name: 1 + value: 1 + twoWay: + $patch: replace + modified: {} + - description: add key and delete all keys from map + original: + name: 1 + value: 1 + twoWay: + other: a + $patch: replace + modified: + other: a + - description: delete all duplicate entries in a merging list + original: + mergingList: + - name: 1 + - name: 1 + - name: 2 + value: a + - name: 3 + - name: 3 + twoWay: + mergingList: + - name: 1 + $patch: delete + - name: 3 + $patch: delete + modified: + mergingList: + - name: 2 + value: a + - description: retainKeys map can add a field when no retainKeys directive present + original: + retainKeysMap: + name: foo + twoWay: + retainKeysMap: + value: bar + modified: + retainKeysMap: + name: foo + value: bar + - description: retainKeys map can change a field when no retainKeys directive present + original: + retainKeysMap: + name: foo + value: a + twoWay: + retainKeysMap: + value: b + modified: + retainKeysMap: + name: foo + value: b + - description: retainKeys map can delete a field when no retainKeys directive present + original: + retainKeysMap: + name: foo + value: a + twoWay: + retainKeysMap: + value: null + modified: + retainKeysMap: + name: foo + - description: retainKeys map merge an empty map + original: + retainKeysMap: + name: foo + value: a + twoWay: + retainKeysMap: {} + modified: + retainKeysMap: + name: foo + value: a + - description: retainKeys list can add a field when no retainKeys directive present + original: + retainKeysMergingList: + - name: bar + - name: foo + twoWay: + retainKeysMergingList: + - name: foo + value: a + modified: + retainKeysMergingList: + - name: bar + - name: foo + value: a + - description: retainKeys list can change a field when no retainKeys directive present + original: + retainKeysMergingList: + - name: bar + - name: foo + value: a + twoWay: + retainKeysMergingList: + - name: foo + value: b + modified: + retainKeysMergingList: + - name: bar + - name: foo + value: b + - description: retainKeys list can delete a field when no retainKeys directive present + original: + retainKeysMergingList: + - name: bar + - name: foo + value: a + twoWay: + retainKeysMergingList: + - name: foo + value: null + modified: + retainKeysMergingList: + - name: bar + - name: foo + - description: preserve the order from the patch in a merging list + original: + mergingList: + - name: 1 + - name: 2 + value: b + - name: 3 + twoWay: + mergingList: + - name: 3 + value: c + - name: 1 + value: a + - name: 2 + other: x + modified: + mergingList: + - name: 3 + value: c + - name: 1 + value: a + - name: 2 + value: b + other: x + - description: preserve the order from the patch in a merging list 2 + original: + mergingList: + - name: 1 + - name: 2 + value: b + - name: 3 + twoWay: + mergingList: + - name: 3 + value: c + - name: 1 + value: a + modified: + mergingList: + - name: 2 + value: b + - name: 3 + value: c + - name: 1 + value: a + - description: preserve the order from the patch in a merging int list + original: + mergingIntList: + - 1 + - 2 + - 3 + twoWay: + mergingIntList: + - 3 + - 1 + - 2 + modified: + mergingIntList: + - 3 + - 1 + - 2 + - description: preserve the order from the patch in a merging int list + original: + mergingIntList: + - 1 + - 2 + - 3 + twoWay: + mergingIntList: + - 3 + - 1 + modified: + mergingIntList: + - 2 + - 3 + - 1 +`) + +var customStrategicMergePatchRawTestCases = []StrategicMergePatchRawTestCase{ + { + Description: "$setElementOrder contains item that is not present in the list to be merged", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 3 + - name: 2 + - name: 1 +mergingList: + - name: 3 + value: 3 + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 3 + value: 3 + - name: 1 + value: 1 +`), + }, + }, + { + Description: "$setElementOrder contains item that is not present in the int list to be merged", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 3 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 3 + - 2 + - 1 +`), + Modified: []byte(` +mergingIntList: + - 3 + - 1 +`), + }, + }, + { + Description: "should check if order in $setElementOrder and patch list match", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 + - name: 3 +mergingList: + - name: 3 + value: 3 + - name: 1 + value: 1 +`), + ExpectedError: "doesn't match", + }, + }, + { + Description: "$setElementOrder contains item that is not present in the int list to be merged", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 3 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 + - 3 +mergingIntList: + - 3 + - 1 +`), + ExpectedError: "doesn't match", + }, + }, + { + Description: "missing merge key should error out", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: a +`), + TwoWay: []byte(` +mergingList: + - value: b +`), + ExpectedError: "does not contain declared merge key", + }, + }, +} + +func TestCustomStrategicMergePatch(t *testing.T) { + mergeItemOpenapiSchema := PatchMetaFromOpenAPI{ + Schema: sptest.GetSchemaOrDie(fakeMergeItemSchema, "mergeItem"), + } + schemas := []LookupPatchMeta{ + mergeItemStructSchema, + mergeItemOpenapiSchema, + } + + tc := StrategicMergePatchTestCases{} + err := yaml.Unmarshal(customStrategicMergePatchTestCaseData, &tc) + if err != nil { + t.Errorf("can't unmarshal test cases: %v\n", err) + return + } + + for _, schema := range schemas { + for _, c := range tc.TestCases { + original, expectedTwoWayPatch, _, expectedResult := twoWayTestCaseToJSONOrFail(t, c, schema) + testPatchApplication(t, original, expectedTwoWayPatch, expectedResult, c.Description, "", schema) + } + + for _, c := range customStrategicMergePatchRawTestCases { + original, expectedTwoWayPatch, _, expectedResult := twoWayRawTestCaseToJSONOrFail(t, c) + testPatchApplication(t, original, expectedTwoWayPatch, expectedResult, c.Description, c.ExpectedError, schema) + } + } +} + +// These are test cases for StrategicMergePatch, to assert that applying a patch +// yields the correct outcome. They are also test cases for CreateTwoWayMergePatch +// and CreateThreeWayMergePatch, to assert that they both generate the correct patch +// for the given set of input documents. +// +var createStrategicMergePatchTestCaseData = []byte(` +testCases: + - description: nil original + twoWay: + name: 1 + value: 1 + modified: + name: 1 + value: 1 + current: + name: 1 + other: a + threeWay: + value: 1 + result: + name: 1 + value: 1 + other: a + - description: nil patch + original: + name: 1 + twoWay: + {} + modified: + name: 1 + current: + name: 1 + threeWay: + {} + result: + name: 1 + - description: add field to map + original: + name: 1 + twoWay: + value: 1 + modified: + name: 1 + value: 1 + current: + name: 1 + other: a + threeWay: + value: 1 + result: + name: 1 + value: 1 + other: a + - description: add field to map with conflict + original: + name: 1 + twoWay: + value: 1 + modified: + name: 1 + value: 1 + current: + name: a + other: a + threeWay: + name: 1 + value: 1 + result: + name: 1 + value: 1 + other: a + - description: add field and delete field from map + original: + name: 1 + twoWay: + name: null + value: 1 + modified: + value: 1 + current: + name: 1 + other: a + threeWay: + name: null + value: 1 + result: + value: 1 + other: a + - description: add field and delete field from map with conflict + original: + name: 1 + twoWay: + name: null + value: 1 + modified: + value: 1 + current: + name: a + other: a + threeWay: + name: null + value: 1 + result: + value: 1 + other: a + - description: delete field from nested map + original: + simpleMap: + key1: 1 + key2: 1 + twoWay: + simpleMap: + key2: null + modified: + simpleMap: + key1: 1 + current: + simpleMap: + key1: 1 + key2: 1 + other: a + threeWay: + simpleMap: + key2: null + result: + simpleMap: + key1: 1 + other: a + - description: delete field from nested map with conflict + original: + simpleMap: + key1: 1 + key2: 1 + twoWay: + simpleMap: + key2: null + modified: + simpleMap: + key1: 1 + current: + simpleMap: + key1: a + key2: 1 + other: a + threeWay: + simpleMap: + key1: 1 + key2: null + result: + simpleMap: + key1: 1 + other: a + - description: delete all fields from map + original: + name: 1 + value: 1 + twoWay: + name: null + value: null + modified: {} + current: + name: 1 + value: 1 + other: a + threeWay: + name: null + value: null + result: + other: a + - description: delete all fields from map with conflict + original: + name: 1 + value: 1 + twoWay: + name: null + value: null + modified: {} + current: + name: 1 + value: a + other: a + threeWay: + name: null + value: null + result: + other: a + - description: add field and delete all fields from map + original: + name: 1 + value: 1 + twoWay: + name: null + value: null + other: a + modified: + other: a + current: + name: 1 + value: 1 + other: a + threeWay: + name: null + value: null + result: + other: a + - description: add field and delete all fields from map with conflict + original: + name: 1 + value: 1 + twoWay: + name: null + value: null + other: a + modified: + other: a + current: + name: 1 + value: 1 + other: b + threeWay: + name: null + value: null + other: a + result: + other: a + - description: replace list of scalars + original: + nonMergingIntList: + - 1 + - 2 + twoWay: + nonMergingIntList: + - 2 + - 3 + modified: + nonMergingIntList: + - 2 + - 3 + current: + nonMergingIntList: + - 1 + - 2 + threeWay: + nonMergingIntList: + - 2 + - 3 + result: + nonMergingIntList: + - 2 + - 3 + - description: replace list of scalars with conflict + original: + nonMergingIntList: + - 1 + - 2 + twoWay: + nonMergingIntList: + - 2 + - 3 + modified: + nonMergingIntList: + - 2 + - 3 + current: + nonMergingIntList: + - 1 + - 4 + threeWay: + nonMergingIntList: + - 2 + - 3 + result: + nonMergingIntList: + - 2 + - 3 + - description: delete all maps from merging list + original: + mergingList: + - name: 1 + - name: 2 + twoWay: + mergingList: + - name: 1 + $patch: delete + - name: 2 + $patch: delete + modified: + mergingList: [] + current: + mergingList: + - name: 1 + - name: 2 + threeWay: + mergingList: + - name: 1 + $patch: delete + - name: 2 + $patch: delete + result: + mergingList: [] + - description: delete all maps from merging list with conflict + original: + mergingList: + - name: 1 + - name: 2 + twoWay: + mergingList: + - name: 1 + $patch: delete + - name: 2 + $patch: delete + modified: + mergingList: [] + current: + mergingList: + - name: 1 + other: a + - name: 2 + other: b + threeWay: + mergingList: + - name: 1 + $patch: delete + - name: 2 + $patch: delete + result: + mergingList: [] + - description: delete all maps from empty merging list + original: + mergingList: + - name: 1 + - name: 2 + twoWay: + mergingList: + - name: 1 + $patch: delete + - name: 2 + $patch: delete + modified: + mergingList: [] + current: + mergingList: [] + threeWay: + mergingList: + - name: 1 + $patch: delete + - name: 2 + $patch: delete + result: + mergingList: [] + - description: merge empty merging lists + original: + mergingList: [] + twoWay: + {} + modified: + mergingList: [] + current: + mergingList: [] + threeWay: + {} + result: + mergingList: [] + - description: defined null values should propagate overwrite current fields (with conflict) + original: + name: 2 + twoWay: + name: 1 + value: 1 + other: null + twoWayResult: + name: 1 + value: 1 + modified: + name: 1 + value: 1 + other: null + current: + name: a + other: a + threeWay: + name: 1 + value: 1 + other: null + result: + name: 1 + value: 1 + - description: defined null values should propagate removing original fields + original: + name: original-name + value: original-value + current: + name: original-name + value: original-value + other: current-other + modified: + name: modified-name + value: null + twoWay: + name: modified-name + value: null + twoWayResult: + name: modified-name + threeWay: + name: modified-name + value: null + result: + name: modified-name + other: current-other + - description: nil patch with retainKeys map + original: + name: a + retainKeysMap: + name: foo + current: + name: a + value: b + retainKeysMap: + name: foo + modified: + name: a + retainKeysMap: + name: foo + twoWay: {} + threeWay: {} + result: + name: a + value: b + retainKeysMap: + name: foo + - description: retainKeys map with no change should not be present + original: + name: a + retainKeysMap: + name: foo + current: + name: a + other: c + retainKeysMap: + name: foo + modified: + name: a + value: b + retainKeysMap: + name: foo + twoWay: + value: b + threeWay: + value: b + result: + name: a + value: b + other: c + retainKeysMap: + name: foo +`) + +var strategicMergePatchRawTestCases = []StrategicMergePatchRawTestCase{ + { + Description: "delete items in lists of scalars", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Modified: []byte(` +mergingIntList: + - 1 + - 2 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 3 + - 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Result: []byte(` +mergingIntList: + - 1 + - 2 + - 4 +`), + }, + }, + { + Description: "delete all duplicate items in lists of scalars", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 + - 3 + - 3 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Modified: []byte(` +mergingIntList: + - 1 + - 2 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 3 + - 3 + - 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Result: []byte(` +mergingIntList: + - 1 + - 2 + - 4 +`), + }, + }, + { + Description: "add and delete items in lists of scalars", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 + - 4 +$deleteFromPrimitiveList/mergingIntList: + - 3 +mergingIntList: + - 4 +`), + Modified: []byte(` +mergingIntList: + - 1 + - 2 + - 4 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 3 + - 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 + - 4 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Result: []byte(` +mergingIntList: + - 1 + - 2 + - 4 +`), + }, + }, + { + Description: "merge lists of maps", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 1 + - name: 2 + - name: 3 +mergingList: + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + Modified: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 1 + - name: 2 + value: 2 + - name: 3 + value: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 1 + - name: 2 + - name: 3 +mergingList: + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + Result: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 3 + value: 3 +`), + }, + }, + { + Description: "merge lists of maps with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 + - name: 3 +mergingList: + - name: 3 + value: 3 +`), + Modified: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 3 + value: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 3 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 + - name: 3 +mergingList: + - name: 2 + value: 2 + - name: 3 + value: 3 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 3 + value: 3 +`), + }, + }, + { + Description: "add field to map in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "add field to map in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "add field to map in merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 3 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Result: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + - name: 3 + value: 2 + other: b +`), + }, + }, + { + Description: "add duplicate field to map in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(`{}`), + Result: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "add an item that already exists in current object in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: a + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 + - name: 3 +mergingList: + - name: 3 +`), + Modified: []byte(` +mergingList: + - name: 1 + value: a + - name: 2 + - name: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + value: a + other: x + - name: 2 + - name: 3 +`), + ThreeWay: []byte(`{}`), + Result: []byte(` +mergingList: + - name: 1 + value: a + other: x + - name: 2 + - name: 3 +`), + }, + }, + { + Description: "add duplicate field to map in merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 3 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 2 + value: 2 +`), + Result: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "replace map field value in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: a +`), + Modified: []byte(` +mergingList: + - name: 1 + value: a + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: a +`), + Result: []byte(` +mergingList: + - name: 1 + value: a + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "replace map field value in merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: a +`), + Modified: []byte(` +mergingList: + - name: 1 + value: a + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + value: 3 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: a +`), + Result: []byte(` +mergingList: + - name: 1 + value: a + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "delete map from merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 2 + other: b +`), + }, + }, + { + Description: "delete map from merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 2 + other: b +`), + }, + }, + { + Description: "delete missing map from merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 2 + other: b +`), + }, + }, + { + Description: "delete missing map from merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 1 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 3 + other: a +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 +mergingList: + - name: 2 + - name: 1 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 2 + - name: 3 + other: a +`), + }, + }, + { + Description: "add map and delete map from merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 3 +mergingList: + - name: 3 + - name: 1 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 + - name: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + - name: 2 + other: b + - name: 4 + other: c +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 3 +mergingList: + - name: 3 + - name: 1 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 2 + other: b + - name: 4 + other: c + - name: 3 +`), + }, + }, + { + Description: "add map and delete map from merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 3 +mergingList: + - name: 3 + - name: 1 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 + - name: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 4 + other: c +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 3 +mergingList: + - name: 2 + - name: 3 + - name: 1 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 4 + other: c + - name: 2 + - name: 3 +`), + }, + }, + { + Description: "delete field from map in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Modified: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "delete field from map in merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Modified: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + value: a + other: a + - name: 2 + value: 2 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 +`), + }, + }, + { + Description: "delete missing field from map in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Modified: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "delete missing field from map in merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null +`), + Modified: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + value: null + - name: 2 + value: 2 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "replace non merging list nested in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + nonMergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + nonMergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + nonMergingList: + - name: 1 + value: 1 + - name: 2 + other: b +`), + }, + }, + { + Description: "replace non merging list nested in merging list with value conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + nonMergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + nonMergingList: + - name: 1 + value: c + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + nonMergingList: + - name: 1 + value: 1 + - name: 2 + other: b +`), + }, + }, + { + Description: "replace non merging list nested in merging list with deletion conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + nonMergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + nonMergingList: + - name: 2 + value: 2 + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 1 + nonMergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + nonMergingList: + - name: 1 + value: 1 + - name: 2 + other: b +`), + }, + }, + { + Description: "add field to map in merging list nested in merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 1 + - name: 2 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 1 + - name: 2 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 + - name: 2 + other: b +`), + }, + }, + { + Description: "add field to map in merging list nested in merging list with value conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 1 + - name: 2 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 1 + value: a + other: c + - name: 2 + value: b + other: d + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 1 + - name: 2 + name: 1 + mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 1 + value: 1 + other: c + - name: 2 + value: 2 + other: d + - name: 2 + other: b +`), + }, + }, + { + Description: "add field to map in merging list nested in merging list with deletion conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 1 + - name: 2 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 2 + value: 2 + other: d + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 1 + - name: 2 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 1 + value: 1 + - name: 2 + value: 2 + other: d + - name: 2 + other: b +`), + }, + }, + + { + Description: "add field to map in merging list nested in merging list with deletion conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 2 + - name: 1 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergingList: + - name: 1 + mergingList: + - name: 2 + value: 2 + - name: 1 + value: 1 + - name: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 2 + value: 2 + other: d + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - $setElementOrder/mergingList: + - name: 2 + - name: 1 + name: 1 + mergingList: + - name: 1 + value: 1 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + mergingList: + - name: 2 + value: 2 + other: d + - name: 1 + value: 1 + - name: 2 + other: b +`), + }, + }, + { + Description: "add map to merging list by pointer", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergeItemPtr: + - name: 1 +`), + TwoWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - name: 2 +`), + Modified: []byte(` +mergeItemPtr: + - name: 1 + - name: 2 +`), + Current: []byte(` +mergeItemPtr: + - name: 1 + other: a + - name: 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - name: 2 +`), + Result: []byte(` +mergeItemPtr: + - name: 1 + other: a + - name: 2 + - name: 3 +`), + }, + }, + { + Description: "add map to merging list by pointer with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergeItemPtr: + - name: 1 +`), + TwoWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - name: 2 +`), + Modified: []byte(` +mergeItemPtr: + - name: 1 + - name: 2 +`), + Current: []byte(` +mergeItemPtr: + - name: 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - name: 1 + - name: 2 +`), + Result: []byte(` +mergeItemPtr: + - name: 1 + - name: 2 + - name: 3 +`), + }, + }, + { + Description: "add field to map in merging list by pointer", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergeItemPtr: + - name: 1 + mergeItemPtr: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - $setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 + name: 1 + mergeItemPtr: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergeItemPtr: + - name: 1 + mergeItemPtr: + - name: 1 + value: 1 + - name: 2 + value: 2 + - name: 2 +`), + Current: []byte(` +mergeItemPtr: + - name: 1 + other: a + mergeItemPtr: + - name: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - $setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 + name: 1 + mergeItemPtr: + - name: 1 + value: 1 +`), + Result: []byte(` +mergeItemPtr: + - name: 1 + other: a + mergeItemPtr: + - name: 1 + value: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 2 + other: b +`), + }, + }, + { + Description: "add field to map in merging list by pointer with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergeItemPtr: + - name: 1 + mergeItemPtr: + - name: 1 + - name: 2 + value: 2 + - name: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - $setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 + name: 1 + mergeItemPtr: + - name: 1 + value: 1 +`), + Modified: []byte(` +mergeItemPtr: + - name: 1 + mergeItemPtr: + - name: 1 + value: 1 + - name: 2 + value: 2 + - name: 2 +`), + Current: []byte(` +mergeItemPtr: + - name: 1 + other: a + mergeItemPtr: + - name: 1 + value: a + - name: 2 + value: 2 + other: b + - name: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 +mergeItemPtr: + - $setElementOrder/mergeItemPtr: + - name: 1 + - name: 2 + name: 1 + mergeItemPtr: + - name: 1 + value: 1 +`), + Result: []byte(` +mergeItemPtr: + - name: 1 + other: a + mergeItemPtr: + - name: 1 + value: 1 + - name: 2 + value: 2 + other: b + - name: 2 + other: b +`), + }, + }, + { + Description: "merge lists of scalars", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: +- 1 +- 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: +- 1 +- 2 +- 3 +mergingIntList: +- 3 +`), + Modified: []byte(` +mergingIntList: +- 1 +- 2 +- 3 +`), + Current: []byte(` +mergingIntList: +- 1 +- 2 +- 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: +- 1 +- 2 +- 3 +mergingIntList: +- 3 +`), + Result: []byte(` +mergingIntList: +- 1 +- 2 +- 3 +- 4 +`), + }, + }, + { + Description: "add duplicate field to map in merging int list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 2 + - 3 +mergingIntList: + - 3 +`), + Modified: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + ThreeWay: []byte(`{}`), + Result: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + }, + }, + // test case for setElementOrder + { + Description: "add an item in a list of primitives and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: +- 1 +- 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: +- 3 +- 1 +- 2 +mergingIntList: +- 3 +`), + Modified: []byte(` +mergingIntList: +- 3 +- 1 +- 2 +`), + Current: []byte(` +mergingIntList: +- 1 +- 4 +- 2 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: +- 3 +- 1 +- 2 +mergingIntList: +- 3 +`), + Result: []byte(` +mergingIntList: +- 3 +- 1 +- 4 +- 2 +`), + }, + }, + { + Description: "delete an item in a list of primitives and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: +- 1 +- 2 +- 3 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: +- 2 +- 1 +$deleteFromPrimitiveList/mergingIntList: +- 3 +`), + Modified: []byte(` +mergingIntList: +- 2 +- 1 +`), + Current: []byte(` +mergingIntList: +- 1 +- 2 +- 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: +- 2 +- 1 +$deleteFromPrimitiveList/mergingIntList: +- 3 +`), + Result: []byte(` +mergingIntList: +- 2 +- 1 +`), + }, + }, + { + Description: "add an item in a list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 3 + - name: 1 + - name: 2 +mergingList: + - name: 3 + value: 3 +`), + Modified: []byte(` +mergingList: + - name: 3 + value: 3 + - name: 1 + - name: 2 + value: 2 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 3 + - name: 1 + - name: 2 +mergingList: + - name: 3 + value: 3 +`), + Result: []byte(` +mergingList: + - name: 3 + value: 3 + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + }, + }, + { + Description: "add multiple items in a list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 4 + - name: 2 + - name: 3 +mergingList: + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + Modified: []byte(` +mergingList: + - name: 1 + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 3 + value: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 4 + - name: 2 + - name: 3 +mergingList: + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + Result: []byte(` +mergingList: + - name: 1 + other: a + - name: 4 + value: 4 + - name: 2 + value: 2 + other: b + - name: 3 + value: 3 +`), + }, + }, + { + Description: "delete an item in a list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 + value: 3 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 1 +mergingList: + - name: 3 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 2 + value: 2 + - name: 1 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 3 + value: 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 1 +mergingList: + - name: 3 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 2 + value: 2 + other: b + - name: 1 + other: a +`), + }, + }, + { + Description: "change an item in a list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 + value: 3 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 3 + - name: 1 +mergingList: + - name: 3 + value: x +`), + Modified: []byte(` +mergingList: + - name: 2 + value: 2 + - name: 3 + value: x + - name: 1 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 3 + value: 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 3 + - name: 1 +mergingList: + - name: 3 + value: x +`), + Result: []byte(` +mergingList: + - name: 2 + value: 2 + other: b + - name: 3 + value: x + - name: 1 + other: a +`), + }, + }, + { + Description: "add and delete an item in a list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 + value: 3 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 2 + - name: 1 +mergingList: + - name: 4 + value: 4 + - name: 3 + $patch: delete +`), + Modified: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 1 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + other: b + - name: 3 + value: 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 2 + - name: 1 +mergingList: + - name: 4 + value: 4 + - name: 3 + $patch: delete +`), + Result: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 2 + value: 2 + other: b + - name: 1 + other: a +`), + }, + }, + { + Description: "set elements order in a list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 + value: 3 + - name: 4 + value: 4 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 2 + - name: 3 + - name: 1 +`), + Modified: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 3 + value: 3 + - name: 1 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 3 + value: 3 + - name: 4 + value: 4 + - name: 2 + value: 2 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 2 + - name: 3 + - name: 1 +`), + Result: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 3 + value: 3 + - name: 1 + other: a +`), + }, + }, + { + Description: "set elements order in a list with server-only items", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 3 + value: 3 + - name: 4 + value: 4 + - name: 2 + value: 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 2 + - name: 3 + - name: 1 +`), + Modified: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 3 + value: 3 + - name: 1 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 3 + value: 3 + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 9 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 4 + - name: 2 + - name: 3 + - name: 1 +`), + Result: []byte(` +mergingList: + - name: 4 + value: 4 + - name: 2 + value: 2 + - name: 3 + value: 3 + - name: 1 + other: a + - name: 9 +`), + }, + }, + { + Description: "set elements order in a list with server-only items 2", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 3 + value: 3 + - name: 4 + value: 4 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 1 + - name: 4 + - name: 3 +`), + Modified: []byte(` +mergingList: + - name: 2 + value: 2 + - name: 1 + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + - name: 9 + - name: 3 + value: 3 + - name: 4 + value: 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 1 + - name: 4 + - name: 3 +`), + Result: []byte(` +mergingList: + - name: 2 + value: 2 + - name: 1 + other: a + - name: 9 + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + }, + }, + { + Description: "set elements order in a list with server-only items 3", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: + - name: 1 + - name: 2 + value: 2 + - name: 3 + value: 3 + - name: 4 + value: 4 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 1 + - name: 4 + - name: 3 +`), + Modified: []byte(` +mergingList: + - name: 2 + value: 2 + - name: 1 + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + Current: []byte(` +mergingList: + - name: 1 + other: a + - name: 2 + value: 2 + - name: 7 + - name: 9 + - name: 8 + - name: 3 + value: 3 + - name: 4 + value: 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 2 + - name: 1 + - name: 4 + - name: 3 +`), + Result: []byte(` +mergingList: + - name: 2 + value: 2 + - name: 1 + other: a + - name: 7 + - name: 9 + - name: 8 + - name: 4 + value: 4 + - name: 3 + value: 3 +`), + }, + }, + { + Description: "add an item in a int list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 3 + - 1 + - 2 +mergingIntList: + - 3 +`), + Modified: []byte(` +mergingIntList: + - 3 + - 1 + - 2 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 3 + - 1 + - 2 +mergingIntList: + - 3 +`), + Result: []byte(` +mergingIntList: + - 3 + - 1 + - 2 +`), + }, + }, + { + Description: "add multiple items in a int list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 4 + - 2 + - 3 +mergingIntList: + - 4 + - 3 +`), + Modified: []byte(` +mergingIntList: + - 1 + - 4 + - 2 + - 3 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 1 + - 4 + - 2 + - 3 +mergingIntList: + - 4 + - 3 +`), + Result: []byte(` +mergingIntList: + - 1 + - 4 + - 2 + - 3 +`), + }, + }, + { + Description: "delete an item in a int list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 3 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 2 + - 1 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Modified: []byte(` +mergingIntList: + - 2 + - 1 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 2 + - 1 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Result: []byte(` +mergingIntList: + - 2 + - 1 +`), + }, + }, + { + Description: "add and delete an item in a int list and preserve order", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 3 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 4 + - 2 + - 1 +mergingIntList: + - 4 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Modified: []byte(` +mergingIntList: + - 4 + - 2 + - 1 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 4 + - 2 + - 1 +mergingIntList: + - 4 +$deleteFromPrimitiveList/mergingIntList: + - 3 +`), + Result: []byte(` +mergingIntList: + - 4 + - 2 + - 1 +`), + }, + }, + { + Description: "set elements order in a int list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 3 + - 4 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + Modified: []byte(` +mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + Current: []byte(` +mergingIntList: + - 1 + - 3 + - 4 + - 2 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + Result: []byte(` +mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + }, + }, + { + Description: "set elements order in a int list with server-only items", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 3 + - 4 + - 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + Modified: []byte(` +mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + Current: []byte(` +mergingIntList: + - 1 + - 3 + - 4 + - 2 + - 9 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 4 + - 2 + - 3 + - 1 +`), + Result: []byte(` +mergingIntList: + - 4 + - 2 + - 3 + - 1 + - 9 +`), + }, + }, + { + Description: "set elements order in a int list with server-only items 2", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 + - 3 + - 4 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 2 + - 1 + - 4 + - 3 +`), + Modified: []byte(` +mergingIntList: + - 2 + - 1 + - 4 + - 3 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 9 + - 3 + - 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 2 + - 1 + - 4 + - 3 +`), + Result: []byte(` +mergingIntList: + - 2 + - 1 + - 9 + - 4 + - 3 +`), + }, + }, + { + Description: "set elements order in a int list with server-only items 3", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: + - 1 + - 2 + - 3 + - 4 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: + - 2 + - 1 + - 4 + - 3 +`), + Modified: []byte(` +mergingIntList: + - 2 + - 1 + - 4 + - 3 +`), + Current: []byte(` +mergingIntList: + - 1 + - 2 + - 7 + - 9 + - 8 + - 3 + - 4 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: + - 2 + - 1 + - 4 + - 3 +`), + Result: []byte(` +mergingIntList: + - 2 + - 1 + - 7 + - 9 + - 8 + - 4 + - 3 +`), + }, + }, + { + // This test case is used just to demonstrate the behavior when dealing with a list with duplicate + Description: "behavior of set element order for a merging list with duplicate", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: +- name: 1 +- name: 2 + value: dup1 +- name: 3 +- name: 2 + value: dup2 +- name: 4 +`), + Current: []byte(` +mergingList: +- name: 1 +- name: 2 + value: dup1 +- name: 3 +- name: 2 + value: dup2 +- name: 4 +`), + Modified: []byte(` +mergingList: +- name: 2 + value: dup1 +- name: 1 +- name: 4 +- name: 3 +- name: 2 + value: dup2 +`), + TwoWay: []byte(` +$setElementOrder/mergingList: +- name: 2 +- name: 1 +- name: 4 +- name: 3 +- name: 2 +`), + TwoWayResult: []byte(` +mergingList: +- name: 2 + value: dup1 +- name: 2 + value: dup2 +- name: 1 +- name: 4 +- name: 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: +- name: 2 +- name: 1 +- name: 4 +- name: 3 +- name: 2 +`), + Result: []byte(` +mergingList: +- name: 2 + value: dup1 +- name: 2 + value: dup2 +- name: 1 +- name: 4 +- name: 3 +`), + }, + }, + { + // This test case is used just to demonstrate the behavior when dealing with a list with duplicate + Description: "behavior of set element order for a merging int list with duplicate", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingIntList: +- 1 +- 2 +- 3 +- 2 +- 4 +`), + Current: []byte(` +mergingIntList: +- 1 +- 2 +- 3 +- 2 +- 4 +`), + Modified: []byte(` +mergingIntList: +- 2 +- 1 +- 4 +- 3 +- 2 +`), + TwoWay: []byte(` +$setElementOrder/mergingIntList: +- 2 +- 1 +- 4 +- 3 +- 2 +`), + TwoWayResult: []byte(` +mergingIntList: +- 2 +- 2 +- 1 +- 4 +- 3 +`), + ThreeWay: []byte(` +$setElementOrder/mergingIntList: +- 2 +- 1 +- 4 +- 3 +- 2 +`), + Result: []byte(` +mergingIntList: +- 2 +- 2 +- 1 +- 4 +- 3 +`), + }, + }, + { + Description: "retainKeys map should clear defaulted field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(`{}`), + Current: []byte(` +retainKeysMap: + value: foo +`), + Modified: []byte(` +retainKeysMap: + other: bar +`), + TwoWay: []byte(` +retainKeysMap: + other: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - other + other: bar +`), + Result: []byte(` +retainKeysMap: + other: bar +`), + }, + }, + { + Description: "retainKeys map should clear defaulted field with conflict (discriminated union)", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(`{}`), + Current: []byte(` +retainKeysMap: + name: type1 + value: foo +`), + Modified: []byte(` +retainKeysMap: + name: type2 + other: bar +`), + TwoWay: []byte(` +retainKeysMap: + name: type2 + other: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - other + name: type2 + other: bar +`), + Result: []byte(` +retainKeysMap: + name: type2 + other: bar +`), + }, + }, + { + Description: "retainKeys map adds a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo +`), + Current: []byte(` +retainKeysMap: + name: foo +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar +`), + }, + }, + { + Description: "retainKeys map adds a field and clear a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo +`), + Current: []byte(` +retainKeysMap: + name: foo + other: a +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar +`), + }, + }, + { + Description: "retainKeys map deletes a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar +`), + Modified: []byte(` +retainKeysMap: + name: foo +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + value: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + value: null +`), + Result: []byte(` +retainKeysMap: + name: foo +`), + }, + }, + { + Description: "retainKeys map deletes a field and clears a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + other: a +`), + Modified: []byte(` +retainKeysMap: + name: foo +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + value: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + value: null +`), + Result: []byte(` +retainKeysMap: + name: foo +`), + }, + }, + { + Description: "retainKeys map clears a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + other: a +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar +`), + TwoWay: []byte(`{}`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar +`), + }, + }, + { + Description: "retainKeys map nested map with no change", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + simpleMap: + key1: a +`), + Current: []byte(` +retainKeysMap: + name: foo + simpleMap: + key1: a +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a +`), + }, + }, + { + Description: "retainKeys map adds a field in a nested map", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key3: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key2: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key2: b +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key2: b +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key2: b + key3: c +`), + }, + }, + { + Description: "retainKeys map deletes a field in a nested map", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key2: b +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key2: b + key3: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key2: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key2: null +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key3: c +`), + }, + }, + { + Description: "retainKeys map changes a field in a nested map", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key2: b +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: a + key2: b + key3: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: x + key2: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key1: x +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key1: x +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: x + key2: b + key3: c +`), + }, + }, + { + Description: "retainKeys map changes a field in a nested map with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: old + key2: b +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: new + key2: b + key3: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: modified + key2: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key1: modified +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - simpleMap + - value + simpleMap: + key1: modified +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + simpleMap: + key1: modified + key2: b + key3: c +`), + }, + }, + { + Description: "retainKeys map replaces non-merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: b +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: c + - name: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - nonMergingList + - value + nonMergingList: + - name: a + - name: c + - name: b +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - nonMergingList + - value + nonMergingList: + - name: a + - name: c + - name: b +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: c + - name: b +`), + }, + }, + { + Description: "retainKeys map nested non-merging list with no change", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - nonMergingList + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - nonMergingList + - value + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: b +`), + }, + }, + { + Description: "retainKeys map nested non-merging list with no change with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b + - name: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - nonMergingList + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - nonMergingList + - value + value: bar + nonMergingList: + - name: a + - name: b +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + nonMergingList: + - name: a + - name: b +`), + }, + }, + { + Description: "retainKeys map deletes nested non-merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar + nonMergingList: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar + nonMergingList: null +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar +`), + }, + }, + { + Description: "retainKeys map delete nested non-merging list with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + nonMergingList: + - name: a + - name: b + - name: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar + nonMergingList: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar + nonMergingList: null +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar +`), + }, + }, + { + Description: "retainKeys map nested merging int list with no change", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + mergingIntList: + - 1 + - 2 +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingIntList + - name + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingIntList + - name + - value + $setElementOrder/mergingIntList: + - 1 + - 2 + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + mergingIntList: + - 1 + - 2 + - 3 +`), + }, + }, + { + Description: "retainKeys map adds an item in nested merging int list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 +`), + Modified: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 4 +`), + TwoWay: []byte(` +retainKeysMap: + $setElementOrder/mergingIntList: + - 1 + - 2 + - 4 + $retainKeys: + - mergingIntList + - name + mergingIntList: + - 4 +`), + ThreeWay: []byte(` +retainKeysMap: + $setElementOrder/mergingIntList: + - 1 + - 2 + - 4 + $retainKeys: + - mergingIntList + - name + mergingIntList: + - 4 +`), + Result: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 4 + - 3 +`), + }, + }, + { + Description: "retainKeys map deletes an item in nested merging int list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 + - 4 +`), + Modified: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 3 +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingIntList + - name + $deleteFromPrimitiveList/mergingIntList: + - 2 + $setElementOrder/mergingIntList: + - 1 + - 3 +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingIntList + - name + $deleteFromPrimitiveList/mergingIntList: + - 2 + $setElementOrder/mergingIntList: + - 1 + - 3 +`), + Result: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 3 + - 4 +`), + }, + }, + { + Description: "retainKeys map adds an item and deletes an item in nested merging int list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 + - 4 +`), + Modified: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 3 + - 5 +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingIntList + - name + mergingIntList: + - 5 + $deleteFromPrimitiveList/mergingIntList: + - 2 + $setElementOrder/mergingIntList: + - 1 + - 3 + - 5 +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingIntList + - name + mergingIntList: + - 5 + $deleteFromPrimitiveList/mergingIntList: + - 2 + $setElementOrder/mergingIntList: + - 1 + - 3 + - 5 +`), + Result: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 3 + - 5 + - 4 +`), + }, + }, + { + Description: "retainKeys map deletes nested merging int list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingIntList: + - 1 + - 2 + - 3 +`), + Modified: []byte(` +retainKeysMap: + name: foo +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + mergingIntList: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + mergingIntList: null +`), + Result: []byte(` +retainKeysMap: + name: foo +`), + }, + }, + { + Description: "retainKeys map nested merging list with no change", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + - name: c +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar + mergingList: + - name: a + - name: b +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + - value + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + - value + $setElementOrder/mergingList: + - name: a + - name: b + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar + mergingList: + - name: a + - name: b + - name: c +`), + }, + }, + { + Description: "retainKeys map adds an item in nested merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + - name: x +`), + Modified: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + - name: c +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + $setElementOrder/mergingList: + - name: a + - name: b + - name: c + mergingList: + - name: c +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + $setElementOrder/mergingList: + - name: a + - name: b + - name: c + mergingList: + - name: c +`), + Result: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + - name: c + - name: x +`), + }, + }, + { + Description: "retainKeys map changes an item in nested merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + value: foo +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + value: foo + - name: x +`), + Modified: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + value: bar +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + $setElementOrder/mergingList: + - name: a + - name: b + mergingList: + - name: b + value: bar +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + $setElementOrder/mergingList: + - name: a + - name: b + mergingList: + - name: b + value: bar +`), + Result: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + value: bar + - name: x +`), + }, + }, + { + Description: "retainKeys map deletes nested merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b +`), + Modified: []byte(` +retainKeysMap: + name: foo + value: bar +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar + mergingList: null +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - name + - value + value: bar + mergingList: null +`), + Result: []byte(` +retainKeysMap: + name: foo + value: bar +`), + }, + }, + { + Description: "retainKeys map deletes an item in nested merging list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b +`), + Current: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: b + - name: x +`), + Modified: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a +`), + TwoWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + $setElementOrder/mergingList: + - name: a + mergingList: + - name: b + $patch: delete +`), + ThreeWay: []byte(` +retainKeysMap: + $retainKeys: + - mergingList + - name + $setElementOrder/mergingList: + - name: a + mergingList: + - name: b + $patch: delete +`), + Result: []byte(` +retainKeysMap: + name: foo + mergingList: + - name: a + - name: x +`), + }, + }, + { + Description: "retainKeys list of maps clears a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a + other: x +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + TwoWay: []byte(`{}`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + }, + }, + { + Description: "retainKeys list of maps clears a field with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: old +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: new + other: x +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: modified +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: modified +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: modified +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: modified +`), + }, + }, + { + Description: "retainKeys list of maps changes a field and clear a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: old +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: old + other: x +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: new +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: new +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: new +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: new +`), + }, + }, + { + Description: "retainKeys list of maps changes a field and clear a field with conflict", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: old +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: modified + other: x +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: new +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: new +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: new +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: new +`), + }, + }, + { + Description: "retainKeys list of maps adds a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: a +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: a +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + }, + }, + { + Description: "retainKeys list of maps adds a field and clear a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + other: x +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: a +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + - value + name: foo + value: a +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + }, + }, + { + Description: "retainKeys list of maps deletes a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + name: foo + value: null +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + name: foo + value: null +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + }, + }, + { + Description: "retainKeys list of maps deletes a field and clear a field", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a +`), + Current: []byte(` +retainKeysMergingList: +- name: bar +- name: foo + value: a + other: x +`), + Modified: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + TwoWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + name: foo + value: null +`), + ThreeWay: []byte(` +$setElementOrder/retainKeysMergingList: + - name: bar + - name: foo +retainKeysMergingList: +- $retainKeys: + - name + name: foo + value: null +`), + Result: []byte(` +retainKeysMergingList: +- name: bar +- name: foo +`), + }, + }, + { + Description: "delete and reorder in one list, reorder in another", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +mergingList: +- name: a + value: a +- name: b + value: b +mergeItemPtr: +- name: c + value: c +- name: d + value: d +`), + Current: []byte(` +mergingList: +- name: a + value: a +- name: b + value: b +mergeItemPtr: +- name: c + value: c +- name: d + value: d +`), + Modified: []byte(` +mergingList: +- name: b + value: b +mergeItemPtr: +- name: d + value: d +- name: c + value: c +`), + TwoWay: []byte(` +$setElementOrder/mergingList: +- name: b +$setElementOrder/mergeItemPtr: +- name: d +- name: c +mergingList: +- $patch: delete + name: a +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: +- name: b +$setElementOrder/mergeItemPtr: +- name: d +- name: c +mergingList: +- $patch: delete + name: a +`), + Result: []byte(` +mergingList: +- name: b + value: b +mergeItemPtr: +- name: d + value: d +- name: c + value: c +`), + }, + }, +} + +func TestStrategicMergePatch(t *testing.T) { + testStrategicMergePatchWithCustomArgumentsUsingStruct(t, "bad struct", + "{}", "{}", []byte("<THIS IS NOT A STRUCT>"), mergepatch.ErrBadArgKind(struct{}{}, []byte{})) + + mergeItemOpenapiSchema := PatchMetaFromOpenAPI{ + Schema: sptest.GetSchemaOrDie(fakeMergeItemSchema, "mergeItem"), + } + schemas := []LookupPatchMeta{ + mergeItemStructSchema, + mergeItemOpenapiSchema, + } + + tc := StrategicMergePatchTestCases{} + err := yaml.Unmarshal(createStrategicMergePatchTestCaseData, &tc) + if err != nil { + t.Errorf("can't unmarshal test cases: %s\n", err) + return + } + + for _, schema := range schemas { + testStrategicMergePatchWithCustomArguments(t, "bad original", + "<THIS IS NOT JSON>", "{}", schema, mergepatch.ErrBadJSONDoc) + testStrategicMergePatchWithCustomArguments(t, "bad patch", + "{}", "<THIS IS NOT JSON>", schema, mergepatch.ErrBadJSONDoc) + testStrategicMergePatchWithCustomArguments(t, "nil struct", + "{}", "{}", nil, mergepatch.ErrBadArgKind(struct{}{}, nil)) + + for _, c := range tc.TestCases { + testTwoWayPatch(t, c, schema) + testThreeWayPatch(t, c, schema) + } + + // run multiple times to exercise different map traversal orders + for i := 0; i < 10; i++ { + for _, c := range strategicMergePatchRawTestCases { + testTwoWayPatchForRawTestCase(t, c, schema) + testThreeWayPatchForRawTestCase(t, c, schema) + } + } + } +} + +func testStrategicMergePatchWithCustomArgumentsUsingStruct(t *testing.T, description, original, patch string, dataStruct interface{}, expected error) { + schema, actual := NewPatchMetaFromStruct(dataStruct) + // If actual is not nil, check error. If errors match, return. + if actual != nil { + checkErrorsEqual(t, description, expected, actual, schema) + return + } + testStrategicMergePatchWithCustomArguments(t, description, original, patch, schema, expected) +} + +func testStrategicMergePatchWithCustomArguments(t *testing.T, description, original, patch string, schema LookupPatchMeta, expected error) { + _, actual := StrategicMergePatch([]byte(original), []byte(patch), schema) + checkErrorsEqual(t, description, expected, actual, schema) +} + +func checkErrorsEqual(t *testing.T, description string, expected, actual error, schema LookupPatchMeta) { + if actual != expected { + if actual == nil { + t.Errorf("using %s expected error: %s\ndid not occur in test case: %s", getSchemaType(schema), expected, description) + return + } + + if expected == nil || actual.Error() != expected.Error() { + t.Errorf("using %s unexpected error: %s\noccurred in test case: %s", getSchemaType(schema), actual, description) + return + } + } +} + +func testTwoWayPatch(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) { + original, expectedPatch, modified, expectedResult := twoWayTestCaseToJSONOrFail(t, c, schema) + + actualPatch, err := CreateTwoWayMergePatchUsingLookupPatchMeta(original, modified, schema) + if err != nil { + t.Errorf("using %s error: %s\nin test case: %s\ncannot create two way patch: %s:\n%s\n", + getSchemaType(schema), err, c.Description, original, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData)) + return + } + + testPatchCreation(t, expectedPatch, actualPatch, c.Description) + testPatchApplication(t, original, actualPatch, expectedResult, c.Description, "", schema) +} + +func testTwoWayPatchForRawTestCase(t *testing.T, c StrategicMergePatchRawTestCase, schema LookupPatchMeta) { + original, expectedPatch, modified, expectedResult := twoWayRawTestCaseToJSONOrFail(t, c) + + actualPatch, err := CreateTwoWayMergePatchUsingLookupPatchMeta(original, modified, schema) + if err != nil { + t.Errorf("error: %s\nin test case: %s\ncannot create two way patch:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n", + err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result) + return + } + + testPatchCreation(t, expectedPatch, actualPatch, c.Description) + testPatchApplication(t, original, actualPatch, expectedResult, c.Description, c.ExpectedError, schema) +} + +func twoWayTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) ([]byte, []byte, []byte, []byte) { + expectedResult := c.TwoWayResult + if expectedResult == nil { + expectedResult = c.Modified + } + return sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Original), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, c.TwoWay), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Modified), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, expectedResult), c.Description, schema) +} + +func twoWayRawTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchRawTestCase) ([]byte, []byte, []byte, []byte) { + expectedResult := c.TwoWayResult + if expectedResult == nil { + expectedResult = c.Modified + } + return yamlToJSONOrError(t, c.Original), + yamlToJSONOrError(t, c.TwoWay), + yamlToJSONOrError(t, c.Modified), + yamlToJSONOrError(t, expectedResult) +} + +func testThreeWayPatch(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) { + original, modified, current, expected, result := threeWayTestCaseToJSONOrFail(t, c, schema) + actual, err := CreateThreeWayMergePatch(original, modified, current, schema, false) + if err != nil { + if !mergepatch.IsConflict(err) { + t.Errorf("using %s error: %s\nin test case: %s\ncannot create three way patch:\n%s\n", + getSchemaType(schema), err, c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData)) + return + } + + if !strings.Contains(c.Description, "conflict") { + t.Errorf("using %s unexpected conflict: %s\nin test case: %s\ncannot create three way patch:\n%s\n", + getSchemaType(schema), err, c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData)) + return + } + + if len(c.Result) > 0 { + actual, err := CreateThreeWayMergePatch(original, modified, current, schema, true) + if err != nil { + t.Errorf("using %s error: %s\nin test case: %s\ncannot force three way patch application:\n%s\n", + getSchemaType(schema), err, c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData)) + return + } + + testPatchCreation(t, expected, actual, c.Description) + testPatchApplication(t, current, actual, result, c.Description, "", schema) + } + + return + } + + if strings.Contains(c.Description, "conflict") || len(c.Result) < 1 { + t.Errorf("using %s error in test case: %s\nexpected conflict did not occur:\n%s\n", + getSchemaType(schema), c.Description, mergepatch.ToYAMLOrError(c.StrategicMergePatchTestCaseData)) + return + } + + testPatchCreation(t, expected, actual, c.Description) + testPatchApplication(t, current, actual, result, c.Description, "", schema) +} + +func testThreeWayPatchForRawTestCase(t *testing.T, c StrategicMergePatchRawTestCase, schema LookupPatchMeta) { + original, modified, current, expected, result := threeWayRawTestCaseToJSONOrFail(t, c) + actual, err := CreateThreeWayMergePatch(original, modified, current, schema, false) + if err != nil { + if !mergepatch.IsConflict(err) { + t.Errorf("using %s error: %s\nin test case: %s\ncannot create three way patch:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n", + getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result) + return + } + + if !strings.Contains(c.Description, "conflict") { + t.Errorf("using %s unexpected conflict: %s\nin test case: %s\ncannot create three way patch:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n", + getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result) + return + } + + if len(c.Result) > 0 { + actual, err := CreateThreeWayMergePatch(original, modified, current, schema, true) + if err != nil { + t.Errorf("using %s error: %s\nin test case: %s\ncannot force three way patch application:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n", + getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result) + return + } + + testPatchCreation(t, expected, actual, c.Description) + testPatchApplication(t, current, actual, result, c.Description, c.ExpectedError, schema) + } + + return + } + + if strings.Contains(c.Description, "conflict") || len(c.Result) < 1 { + t.Errorf("using %s error: %s\nin test case: %s\nexpected conflict did not occur:\noriginal:%s\ntwoWay:%s\nmodified:%s\ncurrent:%s\nthreeWay:%s\nresult:%s\n", + getSchemaType(schema), err, c.Description, c.Original, c.TwoWay, c.Modified, c.Current, c.ThreeWay, c.Result) + return + } + + testPatchCreation(t, expected, actual, c.Description) + testPatchApplication(t, current, actual, result, c.Description, c.ExpectedError, schema) +} + +func threeWayTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchTestCase, schema LookupPatchMeta) ([]byte, []byte, []byte, []byte, []byte) { + return sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Original), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Modified), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Current), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, c.ThreeWay), c.Description, schema), + sortJsonOrFail(t, testObjectToJSONOrFail(t, c.Result), c.Description, schema) +} + +func threeWayRawTestCaseToJSONOrFail(t *testing.T, c StrategicMergePatchRawTestCase) ([]byte, []byte, []byte, []byte, []byte) { + return yamlToJSONOrError(t, c.Original), + yamlToJSONOrError(t, c.Modified), + yamlToJSONOrError(t, c.Current), + yamlToJSONOrError(t, c.ThreeWay), + yamlToJSONOrError(t, c.Result) +} + +func testPatchCreation(t *testing.T, expected, actual []byte, description string) { + if !reflect.DeepEqual(actual, expected) { + t.Errorf("error in test case: %s\nexpected patch:\n%s\ngot:\n%s\n", + description, jsonToYAMLOrError(expected), jsonToYAMLOrError(actual)) + return + } +} + +func testPatchApplication(t *testing.T, original, patch, expected []byte, description, expectedError string, schema LookupPatchMeta) { + result, err := StrategicMergePatchUsingLookupPatchMeta(original, patch, schema) + if len(expectedError) != 0 { + if err != nil && strings.Contains(err.Error(), expectedError) { + return + } + t.Errorf("using %s expected error should contain:\n%s\nin test case: %s\nbut got:\n%s\n", getSchemaType(schema), expectedError, description, err) + } + if err != nil { + t.Errorf("using %s error: %s\nin test case: %s\ncannot apply patch:\n%s\nto original:\n%s\n", + getSchemaType(schema), err, description, jsonToYAMLOrError(patch), jsonToYAMLOrError(original)) + return + } + + if !reflect.DeepEqual(result, expected) { + format := "using error in test case: %s\npatch application failed:\noriginal:\n%s\npatch:\n%s\nexpected:\n%s\ngot:\n%s\n" + t.Errorf(format, description, + jsonToYAMLOrError(original), jsonToYAMLOrError(patch), + jsonToYAMLOrError(expected), jsonToYAMLOrError(result)) + return + } +} + +func testObjectToJSONOrFail(t *testing.T, o map[string]interface{}) []byte { + if o == nil { + return nil + } + + j, err := toJSON(o) + if err != nil { + t.Error(err) + } + return j +} + +func sortJsonOrFail(t *testing.T, j []byte, description string, schema LookupPatchMeta) []byte { + if j == nil { + return nil + } + r, err := sortMergeListsByName(j, schema) + if err != nil { + t.Errorf("using %s error: %s\n in test case: %s\ncannot sort object:\n%s\n", getSchemaType(schema), err, description, j) + return nil + } + + return r +} + +func getSchemaType(schema LookupPatchMeta) string { + return reflect.TypeOf(schema).String() +} + +func jsonToYAMLOrError(j []byte) string { + y, err := jsonToYAML(j) + if err != nil { + return err.Error() + } + + return string(y) +} + +func toJSON(v interface{}) ([]byte, error) { + j, err := json.Marshal(v) + if err != nil { + return nil, fmt.Errorf("json marshal failed: %v\n%v\n", err, spew.Sdump(v)) + } + + return j, nil +} + +func jsonToYAML(j []byte) ([]byte, error) { + y, err := yaml.JSONToYAML(j) + if err != nil { + return nil, fmt.Errorf("json to yaml failed: %v\n%v\n", err, j) + } + + return y, nil +} + +func yamlToJSON(y []byte) ([]byte, error) { + j, err := yaml.YAMLToJSON(y) + if err != nil { + return nil, fmt.Errorf("yaml to json failed: %v\n%v\n", err, y) + } + + return j, nil +} + +func yamlToJSONOrError(t *testing.T, y []byte) []byte { + j, err := yamlToJSON(y) + if err != nil { + t.Errorf("%v", err) + } + + return j +} + +type PrecisionItem struct { + Name string `json:"name,omitempty"` + Int32 int32 `json:"int32,omitempty"` + Int64 int64 `json:"int64,omitempty"` + Float32 float32 `json:"float32,omitempty"` + Float64 float64 `json:"float64,omitempty"` +} + +var ( + precisionItem PrecisionItem + precisionItemStructSchema = PatchMetaFromStruct{T: GetTagStructTypeOrDie(precisionItem)} +) + +func TestNumberConversion(t *testing.T) { + testcases := map[string]struct { + Old string + New string + ExpectedPatch string + ExpectedResult string + }{ + "empty": { + Old: `{}`, + New: `{}`, + ExpectedPatch: `{}`, + ExpectedResult: `{}`, + }, + "int32 medium": { + Old: `{"int32":1000000}`, + New: `{"int32":1000000,"name":"newname"}`, + ExpectedPatch: `{"name":"newname"}`, + ExpectedResult: `{"int32":1000000,"name":"newname"}`, + }, + "int32 max": { + Old: `{"int32":2147483647}`, + New: `{"int32":2147483647,"name":"newname"}`, + ExpectedPatch: `{"name":"newname"}`, + ExpectedResult: `{"int32":2147483647,"name":"newname"}`, + }, + "int64 medium": { + Old: `{"int64":1000000}`, + New: `{"int64":1000000,"name":"newname"}`, + ExpectedPatch: `{"name":"newname"}`, + ExpectedResult: `{"int64":1000000,"name":"newname"}`, + }, + "int64 max": { + Old: `{"int64":9223372036854775807}`, + New: `{"int64":9223372036854775807,"name":"newname"}`, + ExpectedPatch: `{"name":"newname"}`, + ExpectedResult: `{"int64":9223372036854775807,"name":"newname"}`, + }, + "float32 max": { + Old: `{"float32":3.4028234663852886e+38}`, + New: `{"float32":3.4028234663852886e+38,"name":"newname"}`, + ExpectedPatch: `{"name":"newname"}`, + ExpectedResult: `{"float32":3.4028234663852886e+38,"name":"newname"}`, + }, + "float64 max": { + Old: `{"float64":1.7976931348623157e+308}`, + New: `{"float64":1.7976931348623157e+308,"name":"newname"}`, + ExpectedPatch: `{"name":"newname"}`, + ExpectedResult: `{"float64":1.7976931348623157e+308,"name":"newname"}`, + }, + } + + precisionItemOpenapiSchema := PatchMetaFromOpenAPI{ + Schema: sptest.GetSchemaOrDie(fakePrecisionItemSchema, "precisionItem"), + } + precisionItemSchemas := []LookupPatchMeta{ + precisionItemStructSchema, + precisionItemOpenapiSchema, + } + + for _, schema := range precisionItemSchemas { + for k, tc := range testcases { + patch, err := CreateTwoWayMergePatchUsingLookupPatchMeta([]byte(tc.Old), []byte(tc.New), schema) + if err != nil { + t.Errorf("using %s in testcase %s: unexpected error %v", getSchemaType(schema), k, err) + continue + } + if tc.ExpectedPatch != string(patch) { + t.Errorf("using %s in testcase %s: expected %s, got %s", getSchemaType(schema), k, tc.ExpectedPatch, string(patch)) + continue + } + + result, err := StrategicMergePatchUsingLookupPatchMeta([]byte(tc.Old), patch, schema) + if err != nil { + t.Errorf("using %s in testcase %s: unexpected error %v", getSchemaType(schema), k, err) + continue + } + if tc.ExpectedResult != string(result) { + t.Errorf("using %s in testcase %s: expected %s, got %s", getSchemaType(schema), k, tc.ExpectedResult, string(result)) + continue + } + } + } +} + +var replaceRawExtensionPatchTestCases = []StrategicMergePatchRawTestCase{ + { + Description: "replace RawExtension field, rest unchanched", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +name: my-object +value: some-value +other: current-other +replacingItem: + Some: Generic + Yaml: Inside + The: RawExtension + Field: Period +`), + Current: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 + - name: 3 +replacingItem: + Some: Generic + Yaml: Inside + The: RawExtension + Field: Period +`), + Modified: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 + - name: 3 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + TwoWay: []byte(` +mergingList: + - name: 1 + - name: 2 + - name: 3 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + TwoWayResult: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 + - name: 3 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + ThreeWay: []byte(` +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + Result: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 + - name: 3 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + }, + }, + { + Description: "replace RawExtension field and merge list", + StrategicMergePatchRawTestCaseData: StrategicMergePatchRawTestCaseData{ + Original: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 +replacingItem: + Some: Generic + Yaml: Inside + The: RawExtension + Field: Period +`), + Current: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 3 +replacingItem: + Some: Generic + Yaml: Inside + The: RawExtension + Field: Period +`), + Modified: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + TwoWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 2 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + TwoWayResult: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + ThreeWay: []byte(` +$setElementOrder/mergingList: + - name: 1 + - name: 2 +mergingList: + - name: 2 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + Result: []byte(` +name: my-object +value: some-value +other: current-other +mergingList: + - name: 1 + - name: 2 + - name: 3 +replacingItem: + Newly: Modified + Yaml: Inside + The: RawExtension +`), + }, + }, +} + +func TestReplaceWithRawExtension(t *testing.T) { + mergeItemOpenapiSchema := PatchMetaFromOpenAPI{ + Schema: sptest.GetSchemaOrDie(fakeMergeItemSchema, "mergeItem"), + } + schemas := []LookupPatchMeta{ + mergeItemStructSchema, + mergeItemOpenapiSchema, + } + + for _, schema := range schemas { + for _, c := range replaceRawExtensionPatchTestCases { + testTwoWayPatchForRawTestCase(t, c, schema) + testThreeWayPatchForRawTestCase(t, c, schema) + } + } +} + +func TestUnknownField(t *testing.T) { + testcases := map[string]struct { + Original string + Current string + Modified string + + ExpectedTwoWay string + ExpectedTwoWayErr string + ExpectedTwoWayResult string + ExpectedThreeWay string + ExpectedThreeWayErr string + ExpectedThreeWayResult string + }{ + // cases we can successfully strategically merge + "no diff": { + Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + Current: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + Modified: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + + ExpectedTwoWay: `{}`, + ExpectedTwoWayResult: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + ExpectedThreeWay: `{}`, + ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + }, + "added only": { + Original: `{"name":"foo"}`, + Current: `{"name":"foo"}`, + Modified: `{"name":"foo","scalar":true,"complex":{"nested":true},"array":[1,2,3]}`, + + ExpectedTwoWay: `{"array":[1,2,3],"complex":{"nested":true},"scalar":true}`, + ExpectedTwoWayResult: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + ExpectedThreeWay: `{"array":[1,2,3],"complex":{"nested":true},"scalar":true}`, + ExpectedThreeWayResult: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + }, + "removed only": { + Original: `{"name":"foo","scalar":true,"complex":{"nested":true}}`, + Current: `{"name":"foo","scalar":true,"complex":{"nested":true},"array":[1,2,3]}`, + Modified: `{"name":"foo"}`, + + ExpectedTwoWay: `{"complex":null,"scalar":null}`, + ExpectedTwoWayResult: `{"name":"foo"}`, + ExpectedThreeWay: `{"complex":null,"scalar":null}`, + ExpectedThreeWayResult: `{"array":[1,2,3],"name":"foo"}`, + }, + + // cases we cannot successfully strategically merge (expect errors) + "diff": { + Original: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + Current: `{"array":[1,2,3],"complex":{"nested":true},"name":"foo","scalar":true}`, + Modified: `{"array":[1,2,3],"complex":{"nested":false},"name":"foo","scalar":true}`, + + ExpectedTwoWayErr: `unable to find api field`, + ExpectedThreeWayErr: `unable to find api field`, + }, + } + + mergeItemOpenapiSchema := PatchMetaFromOpenAPI{ + Schema: sptest.GetSchemaOrDie(fakeMergeItemSchema, "mergeItem"), + } + schemas := []LookupPatchMeta{ + mergeItemStructSchema, + mergeItemOpenapiSchema, + } + + for _, k := range sets.StringKeySet(testcases).List() { + tc := testcases[k] + for _, schema := range schemas { + func() { + twoWay, err := CreateTwoWayMergePatchUsingLookupPatchMeta([]byte(tc.Original), []byte(tc.Modified), schema) + if err != nil { + if len(tc.ExpectedTwoWayErr) == 0 { + t.Errorf("using %s in testcase %s: error making two-way patch: %v", getSchemaType(schema), k, err) + } + if !strings.Contains(err.Error(), tc.ExpectedTwoWayErr) { + t.Errorf("using %s in testcase %s: expected error making two-way patch to contain '%s', got %s", getSchemaType(schema), k, tc.ExpectedTwoWayErr, err) + } + return + } + + if string(twoWay) != tc.ExpectedTwoWay { + t.Errorf("using %s in testcase %s: expected two-way patch:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedTwoWay), string(twoWay)) + return + } + + twoWayResult, err := StrategicMergePatchUsingLookupPatchMeta([]byte(tc.Original), twoWay, schema) + if err != nil { + t.Errorf("using %s in testcase %s: error applying two-way patch: %v", getSchemaType(schema), k, err) + return + } + if string(twoWayResult) != tc.ExpectedTwoWayResult { + t.Errorf("using %s in testcase %s: expected two-way result:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedTwoWayResult), string(twoWayResult)) + return + } + }() + + func() { + threeWay, err := CreateThreeWayMergePatch([]byte(tc.Original), []byte(tc.Modified), []byte(tc.Current), schema, false) + if err != nil { + if len(tc.ExpectedThreeWayErr) == 0 { + t.Errorf("using %s in testcase %s: error making three-way patch: %v", getSchemaType(schema), k, err) + } else if !strings.Contains(err.Error(), tc.ExpectedThreeWayErr) { + t.Errorf("using %s in testcase %s: expected error making three-way patch to contain '%s', got %s", getSchemaType(schema), k, tc.ExpectedThreeWayErr, err) + } + return + } + + if string(threeWay) != tc.ExpectedThreeWay { + t.Errorf("using %s in testcase %s: expected three-way patch:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedThreeWay), string(threeWay)) + return + } + + threeWayResult, err := StrategicMergePatch([]byte(tc.Current), threeWay, schema) + if err != nil { + t.Errorf("using %s in testcase %s: error applying three-way patch: %v", getSchemaType(schema), k, err) + return + } else if string(threeWayResult) != tc.ExpectedThreeWayResult { + t.Errorf("using %s in testcase %s: expected three-way result:\n\t%s\ngot\n\t%s", getSchemaType(schema), k, string(tc.ExpectedThreeWayResult), string(threeWayResult)) + return + } + }() + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors_test.go b/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors_test.go new file mode 100644 index 000000000..fe747319b --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/field/errors_test.go @@ -0,0 +1,175 @@ +/* +Copyright 2014 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 field + +import ( + "fmt" + "strings" + "testing" +) + +func TestMakeFuncs(t *testing.T) { + testCases := []struct { + fn func() *Error + expected ErrorType + }{ + { + func() *Error { return Invalid(NewPath("f"), "v", "d") }, + ErrorTypeInvalid, + }, + { + func() *Error { return NotSupported(NewPath("f"), "v", nil) }, + ErrorTypeNotSupported, + }, + { + func() *Error { return Duplicate(NewPath("f"), "v") }, + ErrorTypeDuplicate, + }, + { + func() *Error { return NotFound(NewPath("f"), "v") }, + ErrorTypeNotFound, + }, + { + func() *Error { return Required(NewPath("f"), "d") }, + ErrorTypeRequired, + }, + { + func() *Error { return InternalError(NewPath("f"), fmt.Errorf("e")) }, + ErrorTypeInternal, + }, + } + + for _, testCase := range testCases { + err := testCase.fn() + if err.Type != testCase.expected { + t.Errorf("expected Type %q, got %q", testCase.expected, err.Type) + } + } +} + +func TestErrorUsefulMessage(t *testing.T) { + { + s := Invalid(nil, nil, "").Error() + t.Logf("message: %v", s) + if !strings.Contains(s, "null") { + t.Errorf("error message did not contain 'null': %s", s) + } + } + + s := Invalid(NewPath("foo"), "bar", "deet").Error() + t.Logf("message: %v", s) + for _, part := range []string{"foo", "bar", "deet", ErrorTypeInvalid.String()} { + if !strings.Contains(s, part) { + t.Errorf("error message did not contain expected part '%v'", part) + } + } + + type complicated struct { + Baz int + Qux string + Inner interface{} + KV map[string]int + } + s = Invalid( + NewPath("foo"), + &complicated{ + Baz: 1, + Qux: "aoeu", + Inner: &complicated{Qux: "asdf"}, + KV: map[string]int{"Billy": 2}, + }, + "detail", + ).Error() + t.Logf("message: %v", s) + for _, part := range []string{ + "foo", ErrorTypeInvalid.String(), + "Baz", "Qux", "Inner", "KV", "detail", + "1", "aoeu", "Billy", "2", + // "asdf", TODO: re-enable once we have a better nested printer + } { + if !strings.Contains(s, part) { + t.Errorf("error message did not contain expected part '%v'", part) + } + } +} + +func TestToAggregate(t *testing.T) { + testCases := struct { + ErrList []ErrorList + NumExpectedErrs []int + }{ + []ErrorList{ + nil, + {}, + {Invalid(NewPath("f"), "v", "d")}, + {Invalid(NewPath("f"), "v", "d"), Invalid(NewPath("f"), "v", "d")}, + {Invalid(NewPath("f"), "v", "d"), InternalError(NewPath(""), fmt.Errorf("e"))}, + }, + []int{ + 0, + 0, + 1, + 1, + 2, + }, + } + + if len(testCases.ErrList) != len(testCases.NumExpectedErrs) { + t.Errorf("Mismatch: length of NumExpectedErrs does not match length of ErrList") + } + for i, tc := range testCases.ErrList { + agg := tc.ToAggregate() + numErrs := 0 + + if agg != nil { + numErrs = len(agg.Errors()) + } + if numErrs != testCases.NumExpectedErrs[i] { + t.Errorf("[%d] Expected %d, got %d", i, testCases.NumExpectedErrs[i], numErrs) + } + + if len(tc) == 0 { + if agg != nil { + t.Errorf("[%d] Expected nil, got %#v", i, agg) + } + } else if agg == nil { + t.Errorf("[%d] Expected non-nil", i) + } + } +} + +func TestErrListFilter(t *testing.T) { + list := ErrorList{ + Invalid(NewPath("test.field"), "", ""), + Invalid(NewPath("field.test"), "", ""), + Duplicate(NewPath("test"), "value"), + } + if len(list.Filter(NewErrorTypeMatcher(ErrorTypeDuplicate))) != 2 { + t.Errorf("should not filter") + } + if len(list.Filter(NewErrorTypeMatcher(ErrorTypeInvalid))) != 1 { + t.Errorf("should filter") + } +} + +func TestNotSupported(t *testing.T) { + notSupported := NotSupported(NewPath("f"), "v", []string{"a", "b", "c"}) + expected := `Unsupported value: "v": supported values: "a", "b", "c"` + if notSupported.ErrorBody() != expected { + t.Errorf("Expected: %s\n, but got: %s\n", expected, notSupported.ErrorBody()) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/field/path_test.go b/vendor/k8s.io/apimachinery/pkg/util/validation/field/path_test.go new file mode 100644 index 000000000..d2f568c36 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/field/path_test.go @@ -0,0 +1,123 @@ +/* +Copyright 2015 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 field + +import "testing" + +func TestPath(t *testing.T) { + testCases := []struct { + op func(*Path) *Path + expected string + }{ + { + func(p *Path) *Path { return p }, + "root", + }, + { + func(p *Path) *Path { return p.Child("first") }, + "root.first", + }, + { + func(p *Path) *Path { return p.Child("second") }, + "root.first.second", + }, + { + func(p *Path) *Path { return p.Index(0) }, + "root.first.second[0]", + }, + { + func(p *Path) *Path { return p.Child("third") }, + "root.first.second[0].third", + }, + { + func(p *Path) *Path { return p.Index(93) }, + "root.first.second[0].third[93]", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second[0].third", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second[0]", + }, + { + func(p *Path) *Path { return p.Key("key") }, + "root.first.second[0][key]", + }, + } + + root := NewPath("root") + p := root + for i, tc := range testCases { + p = tc.op(p) + if p.String() != tc.expected { + t.Errorf("[%d] Expected %q, got %q", i, tc.expected, p.String()) + } + if p.Root() != root { + t.Errorf("[%d] Wrong root: %#v", i, p.Root()) + } + } +} + +func TestPathMultiArg(t *testing.T) { + testCases := []struct { + op func(*Path) *Path + expected string + }{ + { + func(p *Path) *Path { return p }, + "root.first", + }, + { + func(p *Path) *Path { return p.Child("second", "third") }, + "root.first.second.third", + }, + { + func(p *Path) *Path { return p.Index(0) }, + "root.first.second.third[0]", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second.third", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first", + }, + { + func(p *Path) *Path { return p.parent }, + "root", + }, + } + + root := NewPath("root", "first") + p := root + for i, tc := range testCases { + p = tc.op(p) + if p.String() != tc.expected { + t.Errorf("[%d] Expected %q, got %q", i, tc.expected, p.String()) + } + if p.Root() != root.Root() { + t.Errorf("[%d] Wrong root: %#v", i, p.Root()) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/validation/validation_test.go b/vendor/k8s.io/apimachinery/pkg/util/validation/validation_test.go new file mode 100644 index 000000000..b3892e1c9 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/validation/validation_test.go @@ -0,0 +1,541 @@ +/* +Copyright 2014 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 validation + +import ( + "strings" + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func TestIsDNS1123Label(t *testing.T) { + goodValues := []string{ + "a", "ab", "abc", "a1", "a-1", "a--1--2--b", + "0", "01", "012", "1a", "1-a", "1--a--b--2", + strings.Repeat("a", 63), + } + for _, val := range goodValues { + if msgs := IsDNS1123Label(val); len(msgs) != 0 { + t.Errorf("expected true for '%s': %v", val, msgs) + } + } + + badValues := []string{ + "", "A", "ABC", "aBc", "A1", "A-1", "1-A", + "-", "a-", "-a", "1-", "-1", + "_", "a_", "_a", "a_b", "1_", "_1", "1_2", + ".", "a.", ".a", "a.b", "1.", ".1", "1.2", + " ", "a ", " a", "a b", "1 ", " 1", "1 2", + strings.Repeat("a", 64), + } + for _, val := range badValues { + if msgs := IsDNS1123Label(val); len(msgs) == 0 { + t.Errorf("expected false for '%s'", val) + } + } +} + +func TestIsDNS1123Subdomain(t *testing.T) { + goodValues := []string{ + "a", "ab", "abc", "a1", "a-1", "a--1--2--b", + "0", "01", "012", "1a", "1-a", "1--a--b--2", + "a.a", "ab.a", "abc.a", "a1.a", "a-1.a", "a--1--2--b.a", + "a.1", "ab.1", "abc.1", "a1.1", "a-1.1", "a--1--2--b.1", + "0.a", "01.a", "012.a", "1a.a", "1-a.a", "1--a--b--2", + "0.1", "01.1", "012.1", "1a.1", "1-a.1", "1--a--b--2.1", + "a.b.c.d.e", "aa.bb.cc.dd.ee", "1.2.3.4.5", "11.22.33.44.55", + strings.Repeat("a", 253), + } + for _, val := range goodValues { + if msgs := IsDNS1123Subdomain(val); len(msgs) != 0 { + t.Errorf("expected true for '%s': %v", val, msgs) + } + } + + badValues := []string{ + "", "A", "ABC", "aBc", "A1", "A-1", "1-A", + "-", "a-", "-a", "1-", "-1", + "_", "a_", "_a", "a_b", "1_", "_1", "1_2", + ".", "a.", ".a", "a..b", "1.", ".1", "1..2", + " ", "a ", " a", "a b", "1 ", " 1", "1 2", + "A.a", "aB.a", "ab.A", "A1.a", "a1.A", + "A.1", "aB.1", "A1.1", "1A.1", + "0.A", "01.A", "012.A", "1A.a", "1a.A", + "A.B.C.D.E", "AA.BB.CC.DD.EE", "a.B.c.d.e", "aa.bB.cc.dd.ee", + "a@b", "a,b", "a_b", "a;b", + "a:b", "a%b", "a?b", "a$b", + strings.Repeat("a", 254), + } + for _, val := range badValues { + if msgs := IsDNS1123Subdomain(val); len(msgs) == 0 { + t.Errorf("expected false for '%s'", val) + } + } +} + +func TestIsDNS1035Label(t *testing.T) { + goodValues := []string{ + "a", "ab", "abc", "a1", "a-1", "a--1--2--b", + strings.Repeat("a", 63), + } + for _, val := range goodValues { + if msgs := IsDNS1035Label(val); len(msgs) != 0 { + t.Errorf("expected true for '%s': %v", val, msgs) + } + } + + badValues := []string{ + "0", "01", "012", "1a", "1-a", "1--a--b--2", + "", "A", "ABC", "aBc", "A1", "A-1", "1-A", + "-", "a-", "-a", "1-", "-1", + "_", "a_", "_a", "a_b", "1_", "_1", "1_2", + ".", "a.", ".a", "a.b", "1.", ".1", "1.2", + " ", "a ", " a", "a b", "1 ", " 1", "1 2", + strings.Repeat("a", 64), + } + for _, val := range badValues { + if msgs := IsDNS1035Label(val); len(msgs) == 0 { + t.Errorf("expected false for '%s'", val) + } + } +} + +func TestIsCIdentifier(t *testing.T) { + goodValues := []string{ + "a", "ab", "abc", "a1", "_a", "a_", "a_b", "a_1", "a__1__2__b", "__abc_123", + "A", "AB", "AbC", "A1", "_A", "A_", "A_B", "A_1", "A__1__2__B", "__123_ABC", + } + for _, val := range goodValues { + if msgs := IsCIdentifier(val); len(msgs) != 0 { + t.Errorf("expected true for '%s': %v", val, msgs) + } + } + + badValues := []string{ + "", "1", "123", "1a", + "-", "a-", "-a", "1-", "-1", "1_", "1_2", + ".", "a.", ".a", "a.b", "1.", ".1", "1.2", + " ", "a ", " a", "a b", "1 ", " 1", "1 2", + "#a#", + } + for _, val := range badValues { + if msgs := IsCIdentifier(val); len(msgs) == 0 { + t.Errorf("expected false for '%s'", val) + } + } +} + +func TestIsValidPortNum(t *testing.T) { + goodValues := []int{1, 2, 1000, 16384, 32768, 65535} + for _, val := range goodValues { + if msgs := IsValidPortNum(val); len(msgs) != 0 { + t.Errorf("expected true for %d, got %v", val, msgs) + } + } + + badValues := []int{0, -1, 65536, 100000} + for _, val := range badValues { + if msgs := IsValidPortNum(val); len(msgs) == 0 { + t.Errorf("expected false for %d", val) + } + } +} + +func TestIsInRange(t *testing.T) { + goodValues := []struct { + value int + min int + max int + }{{1, 0, 10}, {5, 5, 20}, {25, 10, 25}} + for _, val := range goodValues { + if msgs := IsInRange(val.value, val.min, val.max); len(msgs) > 0 { + t.Errorf("expected no errors for %#v, but got %v", val, msgs) + } + } + + badValues := []struct { + value int + min int + max int + }{{1, 2, 10}, {5, -4, 2}, {25, 100, 120}} + for _, val := range badValues { + if msgs := IsInRange(val.value, val.min, val.max); len(msgs) == 0 { + t.Errorf("expected errors for %#v", val) + } + } +} + +func createGroupIDs(ids ...int64) []int64 { + var output []int64 + for _, id := range ids { + output = append(output, int64(id)) + } + return output +} + +func createUserIDs(ids ...int64) []int64 { + var output []int64 + for _, id := range ids { + output = append(output, int64(id)) + } + return output +} + +func TestIsValidGroupID(t *testing.T) { + goodValues := createGroupIDs(0, 1, 1000, 65535, 2147483647) + for _, val := range goodValues { + if msgs := IsValidGroupID(val); len(msgs) != 0 { + t.Errorf("expected true for '%d': %v", val, msgs) + } + } + + badValues := createGroupIDs(-1, -1003, 2147483648, 4147483647) + for _, val := range badValues { + if msgs := IsValidGroupID(val); len(msgs) == 0 { + t.Errorf("expected false for '%d'", val) + } + } +} + +func TestIsValidUserID(t *testing.T) { + goodValues := createUserIDs(0, 1, 1000, 65535, 2147483647) + for _, val := range goodValues { + if msgs := IsValidUserID(val); len(msgs) != 0 { + t.Errorf("expected true for '%d': %v", val, msgs) + } + } + + badValues := createUserIDs(-1, -1003, 2147483648, 4147483647) + for _, val := range badValues { + if msgs := IsValidUserID(val); len(msgs) == 0 { + t.Errorf("expected false for '%d'", val) + } + } +} + +func TestIsValidPortName(t *testing.T) { + goodValues := []string{"telnet", "re-mail-ck", "pop3", "a", "a-1", "1-a", "a-1-b-2-c", "1-a-2-b-3"} + for _, val := range goodValues { + if msgs := IsValidPortName(val); len(msgs) != 0 { + t.Errorf("expected true for %q: %v", val, msgs) + } + } + + badValues := []string{"longerthan15characters", "", strings.Repeat("a", 16), "12345", "1-2-3-4", "-begin", "end-", "two--hyphens", "whois++"} + for _, val := range badValues { + if msgs := IsValidPortName(val); len(msgs) == 0 { + t.Errorf("expected false for %q", val) + } + } +} + +func TestIsQualifiedName(t *testing.T) { + successCases := []string{ + "simple", + "now-with-dashes", + "1-starts-with-num", + "1234", + "simple/simple", + "now-with-dashes/simple", + "now-with-dashes/now-with-dashes", + "now.with.dots/simple", + "now-with.dashes-and.dots/simple", + "1-num.2-num/3-num", + "1234/5678", + "1.2.3.4/5678", + "Uppercase_Is_OK_123", + "example.com/Uppercase_Is_OK_123", + "requests.storage-foo", + strings.Repeat("a", 63), + strings.Repeat("a", 253) + "/" + strings.Repeat("b", 63), + } + for i := range successCases { + if errs := IsQualifiedName(successCases[i]); len(errs) != 0 { + t.Errorf("case[%d]: %q: expected success: %v", i, successCases[i], errs) + } + } + + errorCases := []string{ + "nospecialchars%^=@", + "cantendwithadash-", + "-cantstartwithadash-", + "only/one/slash", + "Example.com/abc", + "example_com/abc", + "example.com/", + "/simple", + strings.Repeat("a", 64), + strings.Repeat("a", 254) + "/abc", + } + for i := range errorCases { + if errs := IsQualifiedName(errorCases[i]); len(errs) == 0 { + t.Errorf("case[%d]: %q: expected failure", i, errorCases[i]) + } + } +} + +func TestIsValidLabelValue(t *testing.T) { + successCases := []string{ + "simple", + "now-with-dashes", + "1-starts-with-num", + "end-with-num-1", + "1234", // only num + strings.Repeat("a", 63), // to the limit + "", // empty value + } + for i := range successCases { + if errs := IsValidLabelValue(successCases[i]); len(errs) != 0 { + t.Errorf("case %s expected success: %v", successCases[i], errs) + } + } + + errorCases := []string{ + "nospecialchars%^=@", + "Tama-nui-te-rā.is.Māori.sun", + "\\backslashes\\are\\bad", + "-starts-with-dash", + "ends-with-dash-", + ".starts.with.dot", + "ends.with.dot.", + strings.Repeat("a", 64), // over the limit + } + for i := range errorCases { + if errs := IsValidLabelValue(errorCases[i]); len(errs) == 0 { + t.Errorf("case[%d] expected failure", i) + } + } +} + +func TestIsValidIP(t *testing.T) { + goodValues := []string{ + "::1", + "2a00:79e0:2:0:f1c3:e797:93c1:df80", + "::", + "2001:4860:4860::8888", + "::fff:1.1.1.1", + "1.1.1.1", + "1.1.1.01", + "255.0.0.1", + "1.0.0.0", + "0.0.0.0", + } + for _, val := range goodValues { + if msgs := IsValidIP(val); len(msgs) != 0 { + t.Errorf("expected true for %q: %v", val, msgs) + } + } + + badValues := []string{ + "[2001:db8:0:1]:80", + "myhost.mydomain", + "-1.0.0.0", + "[2001:db8:0:1]", + "a", + } + for _, val := range badValues { + if msgs := IsValidIP(val); len(msgs) == 0 { + t.Errorf("expected false for %q", val) + } + } +} + +func TestIsHTTPHeaderName(t *testing.T) { + goodValues := []string{ + // Common ones + "Accept-Encoding", "Host", "If-Modified-Since", "X-Forwarded-For", + // Weirdo, but still conforming names + "a", "ab", "abc", "a1", "-a", "a-", "a-b", "a-1", "a--1--2--b", "--abc-123", + "A", "AB", "AbC", "A1", "-A", "A-", "A-B", "A-1", "A--1--2--B", "--123-ABC", + } + for _, val := range goodValues { + if msgs := IsHTTPHeaderName(val); len(msgs) != 0 { + t.Errorf("expected true for '%s': %v", val, msgs) + } + } + + badValues := []string{ + "Host:", "X-Forwarded-For:", "X-@Home", + "", "_", "a_", "_a", "1_", "1_2", ".", "a.", ".a", "a.b", "1.", ".1", "1.2", + " ", "a ", " a", "a b", "1 ", " 1", "1 2", "#a#", "^", ",", ";", "=", "<", + "?", "@", "{", + } + for _, val := range badValues { + if msgs := IsHTTPHeaderName(val); len(msgs) == 0 { + t.Errorf("expected false for '%s'", val) + } + } +} + +func TestIsValidPercent(t *testing.T) { + goodValues := []string{ + "0%", + "00000%", + "1%", + "01%", + "99%", + "100%", + "101%", + } + for _, val := range goodValues { + if msgs := IsValidPercent(val); len(msgs) != 0 { + t.Errorf("expected true for %q: %v", val, msgs) + } + } + + badValues := []string{ + "", + "0", + "100", + "0.0%", + "99.9%", + "hundred", + " 1%", + "1% ", + "-0%", + "-1%", + "+1%", + } + for _, val := range badValues { + if msgs := IsValidPercent(val); len(msgs) == 0 { + t.Errorf("expected false for %q", val) + } + } +} + +func TestIsConfigMapKey(t *testing.T) { + successCases := []string{ + "a", + "good", + "good-good", + "still.good", + "this.is.also.good", + ".so.is.this", + "THIS_IS_GOOD", + "so_is_this_17", + } + + for i := range successCases { + if errs := IsConfigMapKey(successCases[i]); len(errs) != 0 { + t.Errorf("[%d] expected success: %v", i, errs) + } + } + + failureCases := []string{ + ".", + "..", + "..bad", + "b*d", + "bad!&bad", + } + + for i := range failureCases { + if errs := IsConfigMapKey(failureCases[i]); len(errs) == 0 { + t.Errorf("[%d] expected failure", i) + } + } +} + +func TestIsWildcardDNS1123Subdomain(t *testing.T) { + goodValues := []string{ + "*.example.com", + "*.bar.com", + "*.foo.bar.com", + } + for _, val := range goodValues { + if errs := IsWildcardDNS1123Subdomain(val); len(errs) != 0 { + t.Errorf("expected no errors for %q: %v", val, errs) + } + } + + badValues := []string{ + "*.*.bar.com", + "*.foo.*.com", + "*bar.com", + "f*.bar.com", + "*", + } + for _, val := range badValues { + if errs := IsWildcardDNS1123Subdomain(val); len(errs) == 0 { + t.Errorf("expected errors for %q", val) + } + } +} + +func TestIsFullyQualifiedName(t *testing.T) { + tests := []struct { + name string + targetName string + err string + }{ + { + name: "name needs to be fully qualified, i.e., contains at least 2 dots", + targetName: "k8s.io", + err: "should be a domain with at least three segments separated by dots", + }, + { + name: "name cannot be empty", + targetName: "", + err: "Required value", + }, + { + name: "name must conform to RFC 1123", + targetName: "A.B.C", + err: "a DNS-1123 subdomain must consist of lower case alphanumeric characters", + }, + } + for _, tc := range tests { + err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate() + switch { + case tc.err == "" && err != nil: + t.Errorf("%q: unexpected error: %v", tc.name, err) + case tc.err != "" && err == nil: + t.Errorf("%q: unexpected no error, expected %s", tc.name, tc.err) + case tc.err != "" && err != nil && !strings.Contains(err.Error(), tc.err): + t.Errorf("%q: expected %s, got %v", tc.name, tc.err, err) + } + } +} + +func TestIsValidSocketAddr(t *testing.T) { + goodValues := []string{ + "0.0.0.0:10254", + "127.0.0.1:8888", + "[2001:db8:1f70::999:de8:7648:6e8]:10254", + "[::]:10254", + } + for _, val := range goodValues { + if errs := IsValidSocketAddr(val); len(errs) != 0 { + t.Errorf("expected no errors for %q: %v", val, errs) + } + } + + badValues := []string{ + "0.0.0.0.0:2020", + "0.0.0.0", + "6.6.6.6:909090", + "2001:db8:1f70::999:de8:7648:6e8:87567:102545", + "", + "*", + } + for _, val := range badValues { + if errs := IsValidSocketAddr(val); len(errs) == 0 { + t.Errorf("expected errors for %q", val) + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/wait_test.go b/vendor/k8s.io/apimachinery/pkg/util/wait/wait_test.go new file mode 100644 index 000000000..2dfd28777 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/wait/wait_test.go @@ -0,0 +1,501 @@ +/* +Copyright 2014 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 wait + +import ( + "errors" + "fmt" + "sync" + "sync/atomic" + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/runtime" +) + +func TestUntil(t *testing.T) { + ch := make(chan struct{}) + close(ch) + Until(func() { + t.Fatal("should not have been invoked") + }, 0, ch) + + ch = make(chan struct{}) + called := make(chan struct{}) + go func() { + Until(func() { + called <- struct{}{} + }, 0, ch) + close(called) + }() + <-called + close(ch) + <-called +} + +func TestNonSlidingUntil(t *testing.T) { + ch := make(chan struct{}) + close(ch) + NonSlidingUntil(func() { + t.Fatal("should not have been invoked") + }, 0, ch) + + ch = make(chan struct{}) + called := make(chan struct{}) + go func() { + NonSlidingUntil(func() { + called <- struct{}{} + }, 0, ch) + close(called) + }() + <-called + close(ch) + <-called +} + +func TestUntilReturnsImmediately(t *testing.T) { + now := time.Now() + ch := make(chan struct{}) + Until(func() { + close(ch) + }, 30*time.Second, ch) + if now.Add(25 * time.Second).Before(time.Now()) { + t.Errorf("Until did not return immediately when the stop chan was closed inside the func") + } +} + +func TestJitterUntil(t *testing.T) { + ch := make(chan struct{}) + // if a channel is closed JitterUntil never calls function f + // and returns immediately + close(ch) + JitterUntil(func() { + t.Fatal("should not have been invoked") + }, 0, 1.0, true, ch) + + ch = make(chan struct{}) + called := make(chan struct{}) + go func() { + JitterUntil(func() { + called <- struct{}{} + }, 0, 1.0, true, ch) + close(called) + }() + <-called + close(ch) + <-called +} + +func TestJitterUntilReturnsImmediately(t *testing.T) { + now := time.Now() + ch := make(chan struct{}) + JitterUntil(func() { + close(ch) + }, 30*time.Second, 1.0, true, ch) + if now.Add(25 * time.Second).Before(time.Now()) { + t.Errorf("JitterUntil did not return immediately when the stop chan was closed inside the func") + } +} + +func TestJitterUntilRecoversPanic(t *testing.T) { + // Save and restore crash handlers + originalReallyCrash := runtime.ReallyCrash + originalHandlers := runtime.PanicHandlers + defer func() { + runtime.ReallyCrash = originalReallyCrash + runtime.PanicHandlers = originalHandlers + }() + + called := 0 + handled := 0 + + // Hook up a custom crash handler to ensure it is called when a jitter function panics + runtime.ReallyCrash = false + runtime.PanicHandlers = []func(interface{}){ + func(p interface{}) { + handled++ + }, + } + + ch := make(chan struct{}) + JitterUntil(func() { + called++ + if called > 2 { + close(ch) + return + } + panic("TestJitterUntilRecoversPanic") + }, time.Millisecond, 1.0, true, ch) + + if called != 3 { + t.Errorf("Expected panic recovers") + } +} + +func TestJitterUntilNegativeFactor(t *testing.T) { + now := time.Now() + ch := make(chan struct{}) + called := make(chan struct{}) + received := make(chan struct{}) + go func() { + JitterUntil(func() { + called <- struct{}{} + <-received + }, time.Second, -30.0, true, ch) + }() + // first loop + <-called + received <- struct{}{} + // second loop + <-called + close(ch) + received <- struct{}{} + + // it should take at most 2 seconds + some overhead, not 3 + if now.Add(3 * time.Second).Before(time.Now()) { + t.Errorf("JitterUntil did not returned after predefined period with negative jitter factor when the stop chan was closed inside the func") + } + +} + +func TestExponentialBackoff(t *testing.T) { + opts := Backoff{Factor: 1.0, Steps: 3} + + // waits up to steps + i := 0 + err := ExponentialBackoff(opts, func() (bool, error) { + i++ + return false, nil + }) + if err != ErrWaitTimeout || i != opts.Steps { + t.Errorf("unexpected error: %v", err) + } + + // returns immediately + i = 0 + err = ExponentialBackoff(opts, func() (bool, error) { + i++ + return true, nil + }) + if err != nil || i != 1 { + t.Errorf("unexpected error: %v", err) + } + + // returns immediately on error + testErr := fmt.Errorf("some other error") + err = ExponentialBackoff(opts, func() (bool, error) { + return false, testErr + }) + if err != testErr { + t.Errorf("unexpected error: %v", err) + } + + // invoked multiple times + i = 1 + err = ExponentialBackoff(opts, func() (bool, error) { + if i < opts.Steps { + i++ + return false, nil + } + return true, nil + }) + if err != nil || i != opts.Steps { + t.Errorf("unexpected error: %v", err) + } +} + +func TestPoller(t *testing.T) { + done := make(chan struct{}) + defer close(done) + w := poller(time.Millisecond, 2*time.Millisecond) + ch := w(done) + count := 0 +DRAIN: + for { + select { + case _, open := <-ch: + if !open { + break DRAIN + } + count++ + case <-time.After(ForeverTestTimeout): + t.Errorf("unexpected timeout after poll") + } + } + if count > 3 { + t.Errorf("expected up to three values, got %d", count) + } +} + +type fakePoller struct { + max int + used int32 // accessed with atomics + wg sync.WaitGroup +} + +func fakeTicker(max int, used *int32, doneFunc func()) WaitFunc { + return func(done <-chan struct{}) <-chan struct{} { + ch := make(chan struct{}) + go func() { + defer doneFunc() + defer close(ch) + for i := 0; i < max; i++ { + select { + case ch <- struct{}{}: + case <-done: + return + } + if used != nil { + atomic.AddInt32(used, 1) + } + } + }() + return ch + } +} + +func (fp *fakePoller) GetWaitFunc() WaitFunc { + fp.wg.Add(1) + return fakeTicker(fp.max, &fp.used, fp.wg.Done) +} + +func TestPoll(t *testing.T) { + invocations := 0 + f := ConditionFunc(func() (bool, error) { + invocations++ + return true, nil + }) + fp := fakePoller{max: 1} + if err := pollInternal(fp.GetWaitFunc(), f); err != nil { + t.Fatalf("unexpected error %v", err) + } + fp.wg.Wait() + if invocations != 1 { + t.Errorf("Expected exactly one invocation, got %d", invocations) + } + used := atomic.LoadInt32(&fp.used) + if used != 1 { + t.Errorf("Expected exactly one tick, got %d", used) + } +} + +func TestPollError(t *testing.T) { + expectedError := errors.New("Expected error") + f := ConditionFunc(func() (bool, error) { + return false, expectedError + }) + fp := fakePoller{max: 1} + if err := pollInternal(fp.GetWaitFunc(), f); err == nil || err != expectedError { + t.Fatalf("Expected error %v, got none %v", expectedError, err) + } + fp.wg.Wait() + used := atomic.LoadInt32(&fp.used) + if used != 1 { + t.Errorf("Expected exactly one tick, got %d", used) + } +} + +func TestPollImmediate(t *testing.T) { + invocations := 0 + f := ConditionFunc(func() (bool, error) { + invocations++ + return true, nil + }) + fp := fakePoller{max: 0} + if err := pollImmediateInternal(fp.GetWaitFunc(), f); err != nil { + t.Fatalf("unexpected error %v", err) + } + // We don't need to wait for fp.wg, as pollImmediate shouldn't call WaitFunc at all. + if invocations != 1 { + t.Errorf("Expected exactly one invocation, got %d", invocations) + } + used := atomic.LoadInt32(&fp.used) + if used != 0 { + t.Errorf("Expected exactly zero ticks, got %d", used) + } +} + +func TestPollImmediateError(t *testing.T) { + expectedError := errors.New("Expected error") + f := ConditionFunc(func() (bool, error) { + return false, expectedError + }) + fp := fakePoller{max: 0} + if err := pollImmediateInternal(fp.GetWaitFunc(), f); err == nil || err != expectedError { + t.Fatalf("Expected error %v, got none %v", expectedError, err) + } + // We don't need to wait for fp.wg, as pollImmediate shouldn't call WaitFunc at all. + used := atomic.LoadInt32(&fp.used) + if used != 0 { + t.Errorf("Expected exactly zero ticks, got %d", used) + } +} + +func TestPollForever(t *testing.T) { + ch := make(chan struct{}) + done := make(chan struct{}, 1) + complete := make(chan struct{}) + go func() { + f := ConditionFunc(func() (bool, error) { + ch <- struct{}{} + select { + case <-done: + return true, nil + default: + } + return false, nil + }) + + if err := PollInfinite(time.Microsecond, f); err != nil { + t.Fatalf("unexpected error %v", err) + } + + close(ch) + complete <- struct{}{} + }() + + // ensure the condition is opened + <-ch + + // ensure channel sends events + for i := 0; i < 10; i++ { + select { + case _, open := <-ch: + if !open { + t.Fatalf("did not expect channel to be closed") + } + case <-time.After(ForeverTestTimeout): + t.Fatalf("channel did not return at least once within the poll interval") + } + } + + // at most one poll notification should be sent once we return from the condition + done <- struct{}{} + go func() { + for i := 0; i < 2; i++ { + _, open := <-ch + if !open { + return + } + } + t.Fatalf("expected closed channel after two iterations") + }() + <-complete +} + +func TestWaitFor(t *testing.T) { + var invocations int + testCases := map[string]struct { + F ConditionFunc + Ticks int + Invoked int + Err bool + }{ + "invoked once": { + ConditionFunc(func() (bool, error) { + invocations++ + return true, nil + }), + 2, + 1, + false, + }, + "invoked and returns a timeout": { + ConditionFunc(func() (bool, error) { + invocations++ + return false, nil + }), + 2, + 3, // the contract of WaitFor() says the func is called once more at the end of the wait + true, + }, + "returns immediately on error": { + ConditionFunc(func() (bool, error) { + invocations++ + return false, errors.New("test") + }), + 2, + 1, + true, + }, + } + for k, c := range testCases { + invocations = 0 + ticker := fakeTicker(c.Ticks, nil, func() {}) + err := func() error { + done := make(chan struct{}) + defer close(done) + return WaitFor(ticker, c.F, done) + }() + switch { + case c.Err && err == nil: + t.Errorf("%s: Expected error, got nil", k) + continue + case !c.Err && err != nil: + t.Errorf("%s: Expected no error, got: %#v", k, err) + continue + } + if invocations != c.Invoked { + t.Errorf("%s: Expected %d invocations, got %d", k, c.Invoked, invocations) + } + } +} + +func TestWaitForWithDelay(t *testing.T) { + done := make(chan struct{}) + defer close(done) + WaitFor(poller(time.Millisecond, ForeverTestTimeout), func() (bool, error) { + time.Sleep(10 * time.Millisecond) + return true, nil + }, done) + // If polling goroutine doesn't see the done signal it will leak timers. + select { + case done <- struct{}{}: + case <-time.After(ForeverTestTimeout): + t.Errorf("expected an ack of the done signal.") + } +} + +func TestPollUntil(t *testing.T) { + stopCh := make(chan struct{}) + called := make(chan bool) + pollDone := make(chan struct{}) + + go func() { + PollUntil(time.Microsecond, ConditionFunc(func() (bool, error) { + called <- true + return false, nil + }), stopCh) + + close(pollDone) + }() + + // make sure we're called once + <-called + // this should trigger a "done" + close(stopCh) + + go func() { + // release the condition func if needed + for { + <-called + } + }() + + // make sure we finished the poll + <-pollDone +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder_test.go b/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder_test.go new file mode 100644 index 000000000..03e502ec6 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/util/yaml/decoder_test.go @@ -0,0 +1,405 @@ +/* +Copyright 2014 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 yaml + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "math/rand" + "reflect" + "strings" + "testing" +) + +func TestYAMLDecoderReadBytesLength(t *testing.T) { + d := `--- +stuff: 1 + test-foo: 1 +` + testCases := []struct { + bufLen int + expectLen int + expectErr error + }{ + {len(d), len(d), nil}, + {len(d) + 10, len(d), nil}, + {len(d) - 10, len(d) - 10, io.ErrShortBuffer}, + } + + for i, testCase := range testCases { + r := NewDocumentDecoder(ioutil.NopCloser(bytes.NewReader([]byte(d)))) + b := make([]byte, testCase.bufLen) + n, err := r.Read(b) + if err != testCase.expectErr || n != testCase.expectLen { + t.Fatalf("%d: unexpected body: %d / %v", i, n, err) + } + } +} + +func TestYAMLDecoderCallsAfterErrShortBufferRestOfFrame(t *testing.T) { + d := `--- +stuff: 1 + test-foo: 1` + r := NewDocumentDecoder(ioutil.NopCloser(bytes.NewReader([]byte(d)))) + b := make([]byte, 12) + n, err := r.Read(b) + if err != io.ErrShortBuffer || n != 12 { + t.Fatalf("expected ErrShortBuffer: %d / %v", n, err) + } + expected := "---\nstuff: 1" + if string(b) != expected { + t.Fatalf("expected bytes read to be: %s got: %s", expected, string(b)) + } + b = make([]byte, 13) + n, err = r.Read(b) + if err != nil || n != 13 { + t.Fatalf("expected nil: %d / %v", n, err) + } + expected = "\n\ttest-foo: 1" + if string(b) != expected { + t.Fatalf("expected bytes read to be: '%s' got: '%s'", expected, string(b)) + } + b = make([]byte, 15) + n, err = r.Read(b) + if err != io.EOF || n != 0 { + t.Fatalf("expected EOF: %d / %v", n, err) + } +} + +func TestSplitYAMLDocument(t *testing.T) { + testCases := []struct { + input string + atEOF bool + expect string + adv int + }{ + {"foo", true, "foo", 3}, + {"fo", false, "", 0}, + + {"---", true, "---", 3}, + {"---\n", true, "---\n", 4}, + {"---\n", false, "", 0}, + + {"\n---\n", false, "", 5}, + {"\n---\n", true, "", 5}, + + {"abc\n---\ndef", true, "abc", 8}, + {"def", true, "def", 3}, + {"", true, "", 0}, + } + for i, testCase := range testCases { + adv, token, err := splitYAMLDocument([]byte(testCase.input), testCase.atEOF) + if err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + continue + } + if adv != testCase.adv { + t.Errorf("%d: advance did not match: %d %d", i, testCase.adv, adv) + } + if testCase.expect != string(token) { + t.Errorf("%d: token did not match: %q %q", i, testCase.expect, string(token)) + } + } +} + +func TestGuessJSON(t *testing.T) { + if r, _, isJSON := GuessJSONStream(bytes.NewReader([]byte(" \n{}")), 100); !isJSON { + t.Fatalf("expected stream to be JSON") + } else { + b := make([]byte, 30) + n, err := r.Read(b) + if err != nil || n != 4 { + t.Fatalf("unexpected body: %d / %v", n, err) + } + if string(b[:n]) != " \n{}" { + t.Fatalf("unexpected body: %q", string(b[:n])) + } + } +} + +func TestScanYAML(t *testing.T) { + s := bufio.NewScanner(bytes.NewReader([]byte(`--- +stuff: 1 + +--- + `))) + s.Split(splitYAMLDocument) + if !s.Scan() { + t.Fatalf("should have been able to scan") + } + t.Logf("scan: %s", s.Text()) + if !s.Scan() { + t.Fatalf("should have been able to scan") + } + t.Logf("scan: %s", s.Text()) + if s.Scan() { + t.Fatalf("scan should have been done") + } + if s.Err() != nil { + t.Fatalf("err should have been nil: %v", s.Err()) + } +} + +func TestDecodeYAML(t *testing.T) { + s := NewYAMLToJSONDecoder(bytes.NewReader([]byte(`--- +stuff: 1 + +--- + `))) + obj := generic{} + if err := s.Decode(&obj); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if fmt.Sprintf("%#v", obj) != `yaml.generic{"stuff":1}` { + t.Errorf("unexpected object: %#v", obj) + } + obj = generic{} + if err := s.Decode(&obj); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(obj) != 0 { + t.Fatalf("unexpected object: %#v", obj) + } + obj = generic{} + if err := s.Decode(&obj); err != io.EOF { + t.Fatalf("unexpected error: %v", err) + } +} + +func TestDecodeBrokenYAML(t *testing.T) { + s := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`--- +stuff: 1 + test-foo: 1 + +--- + `)), 100) + obj := generic{} + err := s.Decode(&obj) + if err == nil { + t.Fatal("expected error with yaml: violate, got no error") + } + fmt.Printf("err: %s\n", err.Error()) + if !strings.Contains(err.Error(), "yaml: line 2:") { + t.Fatalf("expected %q to have 'yaml: line 2:' found a tab character", err.Error()) + } +} + +func TestDecodeBrokenJSON(t *testing.T) { + s := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`{ + "foo": { + "stuff": 1 + "otherStuff": 2 + } +} + `)), 100) + obj := generic{} + err := s.Decode(&obj) + if err == nil { + t.Fatal("expected error with json: prefix, got no error") + } + if !strings.HasPrefix(err.Error(), "json: line 3:") { + t.Fatalf("expected %q to have 'json: line 3:' prefix", err.Error()) + } +} + +type generic map[string]interface{} + +func TestYAMLOrJSONDecoder(t *testing.T) { + testCases := []struct { + input string + buffer int + isJSON bool + err bool + out []generic + }{ + {` {"1":2}{"3":4}`, 2, true, false, []generic{ + {"1": 2}, + {"3": 4}, + }}, + {" \n{}", 3, true, false, []generic{ + {}, + }}, + {" \na: b", 2, false, false, []generic{ + {"a": "b"}, + }}, + {" \n{\"a\": \"b\"}", 2, false, true, []generic{ + {"a": "b"}, + }}, + {" \n{\"a\": \"b\"}", 3, true, false, []generic{ + {"a": "b"}, + }}, + {` {"a":"b"}`, 100, true, false, []generic{ + {"a": "b"}, + }}, + {"", 1, false, false, []generic{}}, + {"foo: bar\n---\nbaz: biz", 100, false, false, []generic{ + {"foo": "bar"}, + {"baz": "biz"}, + }}, + {"foo: bar\n---\n", 100, false, false, []generic{ + {"foo": "bar"}, + }}, + {"foo: bar\n---", 100, false, false, []generic{ + {"foo": "bar"}, + }}, + {"foo: bar\n--", 100, false, true, []generic{ + {"foo": "bar"}, + }}, + {"foo: bar\n-", 100, false, true, []generic{ + {"foo": "bar"}, + }}, + {"foo: bar\n", 100, false, false, []generic{ + {"foo": "bar"}, + }}, + } + for i, testCase := range testCases { + decoder := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(testCase.input)), testCase.buffer) + objs := []generic{} + + var err error + for { + out := make(generic) + err = decoder.Decode(&out) + if err != nil { + break + } + objs = append(objs, out) + } + if err != io.EOF { + switch { + case testCase.err && err == nil: + t.Errorf("%d: unexpected non-error", i) + continue + case !testCase.err && err != nil: + t.Errorf("%d: unexpected error: %v", i, err) + continue + case err != nil: + continue + } + } + switch decoder.decoder.(type) { + case *YAMLToJSONDecoder: + if testCase.isJSON { + t.Errorf("%d: expected JSON decoder, got YAML", i) + } + case *json.Decoder: + if !testCase.isJSON { + t.Errorf("%d: expected YAML decoder, got JSON", i) + } + } + if fmt.Sprintf("%#v", testCase.out) != fmt.Sprintf("%#v", objs) { + t.Errorf("%d: objects were not equal: \n%#v\n%#v", i, testCase.out, objs) + } + } +} + +func TestReadSingleLongLine(t *testing.T) { + testReadLines(t, []int{128 * 1024}) +} + +func TestReadRandomLineLengths(t *testing.T) { + minLength := 100 + maxLength := 96 * 1024 + maxLines := 100 + + lineLengths := make([]int, maxLines) + for i := 0; i < maxLines; i++ { + lineLengths[i] = rand.Intn(maxLength-minLength) + minLength + } + + testReadLines(t, lineLengths) +} + +func testReadLines(t *testing.T, lineLengths []int) { + var ( + lines [][]byte + inputStream []byte + ) + for _, lineLength := range lineLengths { + inputLine := make([]byte, lineLength+1) + for i := 0; i < lineLength; i++ { + char := rand.Intn('z'-'A') + 'A' + inputLine[i] = byte(char) + } + inputLine[len(inputLine)-1] = '\n' + lines = append(lines, inputLine) + } + for _, line := range lines { + inputStream = append(inputStream, line...) + } + + // init Reader + reader := bufio.NewReader(bytes.NewReader(inputStream)) + lineReader := &LineReader{reader: reader} + + // read lines + var readLines [][]byte + for range lines { + bytes, err := lineReader.Read() + if err != nil && err != io.EOF { + t.Fatalf("failed to read lines: %v", err) + } + readLines = append(readLines, bytes) + } + + // validate + for i := range lines { + if len(lines[i]) != len(readLines[i]) { + t.Fatalf("expected line length: %d, but got %d", len(lines[i]), len(readLines[i])) + } + if !reflect.DeepEqual(lines[i], readLines[i]) { + t.Fatalf("expected line: %v, but got %v", lines[i], readLines[i]) + } + } +} + +func TestTypedJSONOrYamlErrors(t *testing.T) { + s := NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`{ + "foo": { + "stuff": 1 + "otherStuff": 2 + } +} + `)), 100) + obj := generic{} + err := s.Decode(&obj) + if err == nil { + t.Fatal("expected error with json: prefix, got no error") + } + if _, ok := err.(JSONSyntaxError); !ok { + t.Fatalf("expected %q to be of type JSONSyntaxError", err.Error()) + } + + s = NewYAMLOrJSONDecoder(bytes.NewReader([]byte(`--- +stuff: 1 + test-foo: 1 + +--- + `)), 100) + obj = generic{} + err = s.Decode(&obj) + if err == nil { + t.Fatal("expected error with yaml: prefix, got no error") + } + if _, ok := err.(YAMLSyntaxError); !ok { + t.Fatalf("expected %q to be of type YAMLSyntaxError", err.Error()) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/version/helpers_test.go b/vendor/k8s.io/apimachinery/pkg/version/helpers_test.go new file mode 100644 index 000000000..863a53697 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/version/helpers_test.go @@ -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. +*/ + +package version + +import ( + "testing" +) + +func TestCompareKubeAwareVersionStrings(t *testing.T) { + tests := []*struct { + v1, v2 string + expectedGreater bool + }{ + {"v1", "v2", false}, + {"v2", "v1", true}, + {"v10", "v2", true}, + {"v1", "v2alpha1", true}, + {"v1", "v2beta1", true}, + {"v1alpha2", "v1alpha1", true}, + {"v1beta1", "v2alpha3", true}, + {"v1alpha10", "v1alpha2", true}, + {"v1beta10", "v1beta2", true}, + {"foo", "v1beta2", false}, + {"bar", "foo", true}, + {"version1", "version2", true}, // Non kube-like versions are sorted alphabetically + {"version1", "version10", true}, // Non kube-like versions are sorted alphabetically + } + + for _, tc := range tests { + if e, a := tc.expectedGreater, CompareKubeAwareVersionStrings(tc.v1, tc.v2) > 0; e != a { + if e { + t.Errorf("expected %s to be greater than %s", tc.v1, tc.v2) + } else { + t.Errorf("expected %s to be less than than %s", tc.v1, tc.v2) + } + } + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/watch/filter_test.go b/vendor/k8s.io/apimachinery/pkg/watch/filter_test.go new file mode 100644 index 000000000..4b5ae898a --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/watch/filter_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2014 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 watch_test + +import ( + "reflect" + "testing" + + . "k8s.io/apimachinery/pkg/watch" +) + +func TestFilter(t *testing.T) { + table := []Event{ + {Type: Added, Object: testType("foo")}, + {Type: Added, Object: testType("bar")}, + {Type: Added, Object: testType("baz")}, + {Type: Added, Object: testType("qux")}, + {Type: Added, Object: testType("zoo")}, + } + + source := NewFake() + filtered := Filter(source, func(e Event) (Event, bool) { + return e, e.Object.(testType)[0] != 'b' + }) + + go func() { + for _, item := range table { + source.Action(item.Type, item.Object) + } + source.Stop() + }() + + var got []string + for { + event, ok := <-filtered.ResultChan() + if !ok { + break + } + got = append(got, string(event.Object.(testType))) + } + + if e, a := []string{"foo", "qux", "zoo"}, got; !reflect.DeepEqual(e, a) { + t.Errorf("got %v, wanted %v", e, a) + } +} + +func TestFilterStop(t *testing.T) { + source := NewFake() + filtered := Filter(source, func(e Event) (Event, bool) { + return e, e.Object.(testType)[0] != 'b' + }) + + go func() { + source.Add(testType("foo")) + filtered.Stop() + }() + + var got []string + for { + event, ok := <-filtered.ResultChan() + if !ok { + break + } + got = append(got, string(event.Object.(testType))) + } + + if e, a := []string{"foo"}, got; !reflect.DeepEqual(e, a) { + t.Errorf("got %v, wanted %v", e, a) + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/watch/mux_test.go b/vendor/k8s.io/apimachinery/pkg/watch/mux_test.go new file mode 100644 index 000000000..7029cf1f4 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/watch/mux_test.go @@ -0,0 +1,176 @@ +/* +Copyright 2014 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 watch_test + +import ( + "reflect" + "sync" + "testing" + "time" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/wait" + . "k8s.io/apimachinery/pkg/watch" +) + +type myType struct { + ID string + Value string +} + +func (obj *myType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (obj *myType) DeepCopyObject() runtime.Object { + if obj == nil { + return nil + } + clone := *obj + return &clone +} + +func TestBroadcaster(t *testing.T) { + table := []Event{ + {Type: Added, Object: &myType{"foo", "hello world 1"}}, + {Type: Added, Object: &myType{"bar", "hello world 2"}}, + {Type: Modified, Object: &myType{"foo", "goodbye world 3"}}, + {Type: Deleted, Object: &myType{"bar", "hello world 4"}}, + } + + // The broadcaster we're testing + m := NewBroadcaster(0, WaitIfChannelFull) + + // Add a bunch of watchers + const testWatchers = 2 + wg := sync.WaitGroup{} + wg.Add(testWatchers) + for i := 0; i < testWatchers; i++ { + // Verify that each watcher gets the events in the correct order + go func(watcher int, w Interface) { + tableLine := 0 + for { + event, ok := <-w.ResultChan() + if !ok { + break + } + if e, a := table[tableLine], event; !reflect.DeepEqual(e, a) { + t.Errorf("Watcher %v, line %v: Expected (%v, %#v), got (%v, %#v)", + watcher, tableLine, e.Type, e.Object, a.Type, a.Object) + } else { + t.Logf("Got (%v, %#v)", event.Type, event.Object) + } + tableLine++ + } + wg.Done() + }(i, m.Watch()) + } + + for i, item := range table { + t.Logf("Sending %v", i) + m.Action(item.Type, item.Object) + } + + m.Shutdown() + + wg.Wait() +} + +func TestBroadcasterWatcherClose(t *testing.T) { + m := NewBroadcaster(0, WaitIfChannelFull) + w := m.Watch() + w2 := m.Watch() + w.Stop() + m.Shutdown() + if _, open := <-w.ResultChan(); open { + t.Errorf("Stop didn't work?") + } + if _, open := <-w2.ResultChan(); open { + t.Errorf("Shutdown didn't work?") + } + // Extra stops don't hurt things + w.Stop() + w2.Stop() +} + +func TestBroadcasterWatcherStopDeadlock(t *testing.T) { + done := make(chan bool) + m := NewBroadcaster(0, WaitIfChannelFull) + go func(w0, w1 Interface) { + // We know Broadcaster is in the distribute loop once one watcher receives + // an event. Stop the other watcher while distribute is trying to + // send to it. + select { + case <-w0.ResultChan(): + w1.Stop() + case <-w1.ResultChan(): + w0.Stop() + } + close(done) + }(m.Watch(), m.Watch()) + m.Action(Added, &myType{}) + select { + case <-time.After(wait.ForeverTestTimeout): + t.Error("timeout: deadlocked") + case <-done: + } + m.Shutdown() +} + +func TestBroadcasterDropIfChannelFull(t *testing.T) { + m := NewBroadcaster(1, DropIfChannelFull) + + event1 := Event{Type: Added, Object: &myType{"foo", "hello world 1"}} + event2 := Event{Type: Added, Object: &myType{"bar", "hello world 2"}} + + // Add a couple watchers + watches := make([]Interface, 2) + for i := range watches { + watches[i] = m.Watch() + } + + // Send a couple events before closing the broadcast channel. + t.Log("Sending event 1") + m.Action(event1.Type, event1.Object) + t.Log("Sending event 2") + m.Action(event2.Type, event2.Object) + m.Shutdown() + + // Pull events from the queue. + wg := sync.WaitGroup{} + wg.Add(len(watches)) + for i := range watches { + // Verify that each watcher only gets the first event because its watch + // queue of length one was full from the first one. + go func(watcher int, w Interface) { + defer wg.Done() + e1, ok := <-w.ResultChan() + if !ok { + t.Errorf("Watcher %v failed to retrieve first event.", watcher) + } + if e, a := event1, e1; !reflect.DeepEqual(e, a) { + t.Errorf("Watcher %v: Expected (%v, %#v), got (%v, %#v)", + watcher, e.Type, e.Object, a.Type, a.Object) + } + t.Logf("Got (%v, %#v)", e1.Type, e1.Object) + e2, ok := <-w.ResultChan() + if ok { + t.Errorf("Watcher %v received second event (%v, %#v) even though it shouldn't have.", + watcher, e2.Type, e2.Object) + } + }(i, watches[i]) + } + wg.Wait() +} diff --git a/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher_test.go b/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher_test.go new file mode 100644 index 000000000..1e3029115 --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/watch/streamwatcher_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2014 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 watch_test + +import ( + "io" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + . "k8s.io/apimachinery/pkg/watch" +) + +type fakeDecoder struct { + items chan Event +} + +func (f fakeDecoder) Decode() (action EventType, object runtime.Object, err error) { + item, open := <-f.items + if !open { + return action, nil, io.EOF + } + return item.Type, item.Object, nil +} + +func (f fakeDecoder) Close() { + close(f.items) +} + +func TestStreamWatcher(t *testing.T) { + table := []Event{ + {Type: Added, Object: testType("foo")}, + } + + fd := fakeDecoder{make(chan Event, 5)} + sw := NewStreamWatcher(fd) + + for _, item := range table { + fd.items <- item + got, open := <-sw.ResultChan() + if !open { + t.Errorf("unexpected early close") + } + if e, a := item, got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } + } + + sw.Stop() + _, open := <-sw.ResultChan() + if open { + t.Errorf("Unexpected failure to close") + } +} diff --git a/vendor/k8s.io/apimachinery/pkg/watch/watch_test.go b/vendor/k8s.io/apimachinery/pkg/watch/watch_test.go new file mode 100644 index 000000000..4fb159b0d --- /dev/null +++ b/vendor/k8s.io/apimachinery/pkg/watch/watch_test.go @@ -0,0 +1,175 @@ +/* +Copyright 2014 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 watch_test + +import ( + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + . "k8s.io/apimachinery/pkg/watch" +) + +type testType string + +func (obj testType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (obj testType) DeepCopyObject() runtime.Object { return obj } + +func TestFake(t *testing.T) { + f := NewFake() + + table := []struct { + t EventType + s testType + }{ + {Added, testType("foo")}, + {Modified, testType("qux")}, + {Modified, testType("bar")}, + {Deleted, testType("bar")}, + {Error, testType("error: blah")}, + } + + // Prove that f implements Interface by phrasing this as a function. + consumer := func(w Interface) { + for _, expect := range table { + got, ok := <-w.ResultChan() + if !ok { + t.Fatalf("closed early") + } + if e, a := expect.t, got.Type; e != a { + t.Fatalf("Expected %v, got %v", e, a) + } + if a, ok := got.Object.(testType); !ok || a != expect.s { + t.Fatalf("Expected %v, got %v", expect.s, a) + } + } + _, stillOpen := <-w.ResultChan() + if stillOpen { + t.Fatal("Never stopped") + } + } + + sender := func() { + f.Add(testType("foo")) + f.Action(Modified, testType("qux")) + f.Modify(testType("bar")) + f.Delete(testType("bar")) + f.Error(testType("error: blah")) + f.Stop() + } + + go sender() + consumer(f) +} + +func TestRaceFreeFake(t *testing.T) { + f := NewRaceFreeFake() + + table := []struct { + t EventType + s testType + }{ + {Added, testType("foo")}, + {Modified, testType("qux")}, + {Modified, testType("bar")}, + {Deleted, testType("bar")}, + {Error, testType("error: blah")}, + } + + // Prove that f implements Interface by phrasing this as a function. + consumer := func(w Interface) { + for _, expect := range table { + got, ok := <-w.ResultChan() + if !ok { + t.Fatalf("closed early") + } + if e, a := expect.t, got.Type; e != a { + t.Fatalf("Expected %v, got %v", e, a) + } + if a, ok := got.Object.(testType); !ok || a != expect.s { + t.Fatalf("Expected %v, got %v", expect.s, a) + } + } + _, stillOpen := <-w.ResultChan() + if stillOpen { + t.Fatal("Never stopped") + } + } + + sender := func() { + f.Add(testType("foo")) + f.Action(Modified, testType("qux")) + f.Modify(testType("bar")) + f.Delete(testType("bar")) + f.Error(testType("error: blah")) + f.Stop() + } + + go sender() + consumer(f) +} + +func TestEmpty(t *testing.T) { + w := NewEmptyWatch() + _, ok := <-w.ResultChan() + if ok { + t.Errorf("unexpected result channel result") + } + w.Stop() + _, ok = <-w.ResultChan() + if ok { + t.Errorf("unexpected result channel result") + } +} + +func TestProxyWatcher(t *testing.T) { + events := []Event{ + {Added, testType("foo")}, + {Modified, testType("qux")}, + {Modified, testType("bar")}, + {Deleted, testType("bar")}, + {Error, testType("error: blah")}, + } + + ch := make(chan Event, len(events)) + w := NewProxyWatcher(ch) + + for _, e := range events { + ch <- e + } + + for _, e := range events { + g := <-w.ResultChan() + if !reflect.DeepEqual(e, g) { + t.Errorf("Expected %#v, got %#v", e, g) + continue + } + } + + w.Stop() + + select { + // Closed channel always reads immediately + case <-w.StopChan(): + default: + t.Error("Channel isn't closed") + } + + // Test double close + w.Stop() +} diff --git a/vendor/k8s.io/apimachinery/third_party/forked/golang/json/OWNERS b/vendor/k8s.io/apimachinery/third_party/forked/golang/json/OWNERS new file mode 100644 index 000000000..8e8d9fce8 --- /dev/null +++ b/vendor/k8s.io/apimachinery/third_party/forked/golang/json/OWNERS @@ -0,0 +1,5 @@ +approvers: +- pwittrock +reviewers: +- mengqiy +- apelisse diff --git a/vendor/k8s.io/apimachinery/third_party/forked/golang/json/fields_test.go b/vendor/k8s.io/apimachinery/third_party/forked/golang/json/fields_test.go new file mode 100644 index 000000000..33b78bc43 --- /dev/null +++ b/vendor/k8s.io/apimachinery/third_party/forked/golang/json/fields_test.go @@ -0,0 +1,30 @@ +package json + +import ( + "reflect" + "testing" +) + +func TestLookupPtrToStruct(t *testing.T) { + type Elem struct { + Key string + Value string + } + type Outer struct { + Inner []Elem `json:"inner" patchStrategy:"merge" patchMergeKey:"key"` + } + outer := &Outer{} + elemType, patchStrategies, patchMergeKey, err := LookupPatchMetadataForStruct(reflect.TypeOf(outer), "inner") + if err != nil { + t.Fatal(err) + } + if elemType != reflect.TypeOf([]Elem{}) { + t.Errorf("elemType = %v, want: %v", elemType, reflect.TypeOf([]Elem{})) + } + if !reflect.DeepEqual(patchStrategies, []string{"merge"}) { + t.Errorf("patchStrategies = %v, want: %v", patchStrategies, []string{"merge"}) + } + if patchMergeKey != "key" { + t.Errorf("patchMergeKey = %v, want: %v", patchMergeKey, "key") + } +} diff --git a/vendor/k8s.io/apimachinery/third_party/forked/golang/reflect/deep_equal_test.go b/vendor/k8s.io/apimachinery/third_party/forked/golang/reflect/deep_equal_test.go new file mode 100644 index 000000000..4a0629930 --- /dev/null +++ b/vendor/k8s.io/apimachinery/third_party/forked/golang/reflect/deep_equal_test.go @@ -0,0 +1,137 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "testing" +) + +func TestEqualities(t *testing.T) { + e := Equalities{} + type Bar struct { + X int + } + type Baz struct { + Y Bar + } + err := e.AddFuncs( + func(a, b int) bool { + return a+1 == b + }, + func(a, b Bar) bool { + return a.X*10 == b.X + }, + ) + if err != nil { + t.Fatalf("Unexpected: %v", err) + } + + type Foo struct { + X int + } + + table := []struct { + a, b interface{} + equal bool + }{ + {1, 2, true}, + {2, 1, false}, + {"foo", "fo", false}, + {"foo", "foo", true}, + {"foo", "foobar", false}, + {Foo{1}, Foo{2}, true}, + {Foo{2}, Foo{1}, false}, + {Bar{1}, Bar{10}, true}, + {&Bar{1}, &Bar{10}, true}, + {Baz{Bar{1}}, Baz{Bar{10}}, true}, + {[...]string{}, [...]string{"1", "2", "3"}, false}, + {[...]string{"1"}, [...]string{"1", "2", "3"}, false}, + {[...]string{"1", "2", "3"}, [...]string{}, false}, + {[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true}, + {map[string]int{"foo": 1}, map[string]int{}, false}, + {map[string]int{"foo": 1}, map[string]int{"foo": 2}, true}, + {map[string]int{"foo": 2}, map[string]int{"foo": 1}, false}, + {map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, false}, + {map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false}, + {map[string]int{}, map[string]int(nil), true}, + {[]string(nil), []string(nil), true}, + {[]string{}, []string(nil), true}, + {[]string(nil), []string{}, true}, + {[]string{"1"}, []string(nil), false}, + {[]string{}, []string{"1", "2", "3"}, false}, + {[]string{"1"}, []string{"1", "2", "3"}, false}, + {[]string{"1", "2", "3"}, []string{}, false}, + } + + for _, item := range table { + if e, a := item.equal, e.DeepEqual(item.a, item.b); e != a { + t.Errorf("Expected (%+v == %+v) == %v, but got %v", item.a, item.b, e, a) + } + } +} + +func TestDerivates(t *testing.T) { + e := Equalities{} + type Bar struct { + X int + } + type Baz struct { + Y Bar + } + err := e.AddFuncs( + func(a, b int) bool { + return a+1 == b + }, + func(a, b Bar) bool { + return a.X*10 == b.X + }, + ) + if err != nil { + t.Fatalf("Unexpected: %v", err) + } + + type Foo struct { + X int + } + + table := []struct { + a, b interface{} + equal bool + }{ + {1, 2, true}, + {2, 1, false}, + {"foo", "fo", false}, + {"foo", "foo", true}, + {"foo", "foobar", false}, + {Foo{1}, Foo{2}, true}, + {Foo{2}, Foo{1}, false}, + {Bar{1}, Bar{10}, true}, + {&Bar{1}, &Bar{10}, true}, + {Baz{Bar{1}}, Baz{Bar{10}}, true}, + {[...]string{}, [...]string{"1", "2", "3"}, false}, + {[...]string{"1"}, [...]string{"1", "2", "3"}, false}, + {[...]string{"1", "2", "3"}, [...]string{}, false}, + {[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true}, + {map[string]int{"foo": 1}, map[string]int{}, false}, + {map[string]int{"foo": 1}, map[string]int{"foo": 2}, true}, + {map[string]int{"foo": 2}, map[string]int{"foo": 1}, false}, + {map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, true}, + {map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false}, + {map[string]int{}, map[string]int(nil), true}, + {[]string(nil), []string(nil), true}, + {[]string{}, []string(nil), true}, + {[]string(nil), []string{}, true}, + {[]string{"1"}, []string(nil), false}, + {[]string{}, []string{"1", "2", "3"}, true}, + {[]string{"1"}, []string{"1", "2", "3"}, true}, + {[]string{"1", "2", "3"}, []string{}, false}, + } + + for _, item := range table { + if e, a := item.equal, e.DeepDerivative(item.a, item.b); e != a { + t.Errorf("Expected (%+v ~ %+v) == %v, but got %v", item.a, item.b, e, a) + } + } +} diff --git a/vendor/k8s.io/apiserver/.import-restrictions b/vendor/k8s.io/apiserver/.import-restrictions new file mode 100644 index 000000000..c80e742d5 --- /dev/null +++ b/vendor/k8s.io/apiserver/.import-restrictions @@ -0,0 +1,10 @@ +{ + "Rules": [ + { + "SelectorRegexp": "k8s[.]io/kubernetes", + "ForbiddenPrefixes": [ + "" + ] + } + ] +} diff --git a/vendor/k8s.io/apiserver/CONTRIBUTING.md b/vendor/k8s.io/apiserver/CONTRIBUTING.md new file mode 100644 index 000000000..94a288993 --- /dev/null +++ b/vendor/k8s.io/apiserver/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/apiserver](https://git.k8s.io/kubernetes/staging/src/k8s.io/apiserver) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/vendor/k8s.io/apiserver/OWNERS b/vendor/k8s.io/apiserver/OWNERS new file mode 100644 index 000000000..9617c2778 --- /dev/null +++ b/vendor/k8s.io/apiserver/OWNERS @@ -0,0 +1,22 @@ +approvers: +- lavalamp +- smarterclayton +- deads2k +- sttts +- liggitt +reviewers: +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- caesarxuchao +- liggitt +- sttts +- ncdc +- tallclair +- enj +- hzxuzhonghu +- CaoShuFeng +labels: +- sig/api-machinery +- area/apiserver diff --git a/vendor/k8s.io/apiserver/README.md b/vendor/k8s.io/apiserver/README.md new file mode 100644 index 000000000..90160ce91 --- /dev/null +++ b/vendor/k8s.io/apiserver/README.md @@ -0,0 +1,30 @@ +# apiserver + +Generic library for building a Kubernetes aggregated API server. + + +## Purpose + +This library contains code to create Kubernetes aggregation server complete with delegated authentication and authorization, +`kubectl` compatible discovery information, optional admission chain, and versioned types. It's first consumers are +`k8s.io/kubernetes`, `k8s.io/kube-aggregator`, and `github.com/kubernetes-incubator/service-catalog`. + + +## Compatibility + +There are *NO compatibility guarantees* for this repository, yet. It is in direct support of Kubernetes, so branches +will track Kubernetes and be compatible with that repo. As we more cleanly separate the layers, we will review the +compatibility guarantee. We have a goal to make this easier to use in the future. + + +## Where does it come from? + +`apiserver` is synced from https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apiserver. +Code changes are made in that location, merged into `k8s.io/kubernetes` and later synced here. + + +## Things you should *NOT* do + + 1. Directly modify any files under `pkg` in this repo. Those are driven from `k8s.io/kubernetes/staging/src/k8s.io/apiserver`. + 2. Expect compatibility. This repo is changing quickly in direct support of + Kubernetes and the API isn't yet stable enough for API guarantees. diff --git a/vendor/k8s.io/apiserver/SECURITY_CONTACTS b/vendor/k8s.io/apiserver/SECURITY_CONTACTS new file mode 100644 index 000000000..0648a8ebf --- /dev/null +++ b/vendor/k8s.io/apiserver/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# 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/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/vendor/k8s.io/apiserver/code-of-conduct.md b/vendor/k8s.io/apiserver/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/apiserver/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/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go b/vendor/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go new file mode 100644 index 000000000..14ec86948 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/feature/feature_gate_test.go @@ -0,0 +1,347 @@ +/* +Copyright 2016 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 feature + +import ( + "fmt" + "strings" + "testing" + + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" +) + +func TestFeatureGateFlag(t *testing.T) { + // gates for testing + const testAlphaGate Feature = "TestAlpha" + const testBetaGate Feature = "TestBeta" + + tests := []struct { + arg string + expect map[Feature]bool + parseError string + }{ + { + arg: "", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: false, + testBetaGate: false, + }, + }, + { + arg: "fooBarBaz=true", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: false, + testBetaGate: false, + }, + parseError: "unrecognized feature gate: fooBarBaz", + }, + { + arg: "AllAlpha=false", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: false, + testBetaGate: false, + }, + }, + { + arg: "AllAlpha=true", + expect: map[Feature]bool{ + allAlphaGate: true, + testAlphaGate: true, + testBetaGate: false, + }, + }, + { + arg: "AllAlpha=banana", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: false, + testBetaGate: false, + }, + parseError: "invalid value of AllAlpha", + }, + { + arg: "AllAlpha=false,TestAlpha=true", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: true, + testBetaGate: false, + }, + }, + { + arg: "TestAlpha=true,AllAlpha=false", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: true, + testBetaGate: false, + }, + }, + { + arg: "AllAlpha=true,TestAlpha=false", + expect: map[Feature]bool{ + allAlphaGate: true, + testAlphaGate: false, + testBetaGate: false, + }, + }, + { + arg: "TestAlpha=false,AllAlpha=true", + expect: map[Feature]bool{ + allAlphaGate: true, + testAlphaGate: false, + testBetaGate: false, + }, + }, + { + arg: "TestBeta=true,AllAlpha=false", + expect: map[Feature]bool{ + allAlphaGate: false, + testAlphaGate: false, + testBetaGate: true, + }, + }, + } + for i, test := range tests { + fs := pflag.NewFlagSet("testfeaturegateflag", pflag.ContinueOnError) + f := NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: false, PreRelease: Beta}, + }) + f.AddFlag(fs) + + err := fs.Parse([]string{fmt.Sprintf("--%s=%s", flagName, test.arg)}) + if test.parseError != "" { + if !strings.Contains(err.Error(), test.parseError) { + t.Errorf("%d: Parse() Expected %v, Got %v", i, test.parseError, err) + } + } else if err != nil { + t.Errorf("%d: Parse() Expected nil, Got %v", i, err) + } + for k, v := range test.expect { + if actual := f.enabled.Load().(map[Feature]bool)[k]; actual != v { + t.Errorf("%d: expected %s=%v, Got %v", i, k, v, actual) + } + } + } +} + +func TestFeatureGateOverride(t *testing.T) { + const testAlphaGate Feature = "TestAlpha" + const testBetaGate Feature = "TestBeta" + + // Don't parse the flag, assert defaults are used. + var f FeatureGate = NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: false, PreRelease: Beta}, + }) + + f.Set("TestAlpha=true,TestBeta=true") + if f.Enabled(testAlphaGate) != true { + t.Errorf("Expected true") + } + if f.Enabled(testBetaGate) != true { + t.Errorf("Expected true") + } + + f.Set("TestAlpha=false") + if f.Enabled(testAlphaGate) != false { + t.Errorf("Expected false") + } + if f.Enabled(testBetaGate) != true { + t.Errorf("Expected true") + } +} + +func TestFeatureGateFlagDefaults(t *testing.T) { + // gates for testing + const testAlphaGate Feature = "TestAlpha" + const testBetaGate Feature = "TestBeta" + + // Don't parse the flag, assert defaults are used. + var f FeatureGate = NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: true, PreRelease: Beta}, + }) + + if f.Enabled(testAlphaGate) != false { + t.Errorf("Expected false") + } + if f.Enabled(testBetaGate) != true { + t.Errorf("Expected true") + } +} + +func TestFeatureGateKnownFeatures(t *testing.T) { + // gates for testing + const ( + testAlphaGate Feature = "TestAlpha" + testBetaGate Feature = "TestBeta" + testGAGate Feature = "TestGA" + testDeprecatedGate Feature = "TestDeprecated" + ) + + // Don't parse the flag, assert defaults are used. + var f FeatureGate = NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: true, PreRelease: Beta}, + testGAGate: {Default: true, PreRelease: GA}, + testDeprecatedGate: {Default: false, PreRelease: Deprecated}, + }) + + known := strings.Join(f.KnownFeatures(), " ") + + assert.Contains(t, known, testAlphaGate) + assert.Contains(t, known, testBetaGate) + assert.NotContains(t, known, testGAGate) + assert.NotContains(t, known, testDeprecatedGate) +} + +func TestFeatureGateSetFromMap(t *testing.T) { + // gates for testing + const testAlphaGate Feature = "TestAlpha" + const testBetaGate Feature = "TestBeta" + + tests := []struct { + name string + setmap map[string]bool + expect map[Feature]bool + setmapError string + }{ + { + name: "set TestAlpha and TestBeta true", + setmap: map[string]bool{ + "TestAlpha": true, + "TestBeta": true, + }, + expect: map[Feature]bool{ + testAlphaGate: true, + testBetaGate: true, + }, + }, + { + name: "set TestBeta true", + setmap: map[string]bool{ + "TestBeta": true, + }, + expect: map[Feature]bool{ + testAlphaGate: false, + testBetaGate: true, + }, + }, + { + name: "set TestAlpha false", + setmap: map[string]bool{ + "TestAlpha": false, + }, + expect: map[Feature]bool{ + testAlphaGate: false, + testBetaGate: false, + }, + }, + { + name: "set TestInvaild true", + setmap: map[string]bool{ + "TestInvaild": true, + }, + expect: map[Feature]bool{ + testAlphaGate: false, + testBetaGate: false, + }, + setmapError: "unrecognized feature gate:", + }, + } + for i, test := range tests { + t.Run(fmt.Sprintf("SetFromMap %s", test.name), func(t *testing.T) { + f := NewFeatureGate() + f.Add(map[Feature]FeatureSpec{ + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: false, PreRelease: Beta}, + }) + err := f.SetFromMap(test.setmap) + if test.setmapError != "" { + if !strings.Contains(err.Error(), test.setmapError) { + t.Errorf("%d: SetFromMap(%#v) Expected err:%v, Got err:%v", i, test.setmap, test.setmapError, err) + } + } else if err != nil { + t.Errorf("%d: SetFromMap(%#v) Expected success, Got err:%v", i, test.setmap, err) + } + for k, v := range test.expect { + if actual := f.Enabled(k); actual != v { + t.Errorf("%d: SetFromMap(%#v) Expected %s=%v, Got %s=%v", i, test.setmap, k, v, k, actual) + } + } + }) + } +} + +func TestFeatureGateString(t *testing.T) { + // gates for testing + const testAlphaGate Feature = "TestAlpha" + const testBetaGate Feature = "TestBeta" + const testGAGate Feature = "TestGA" + + featuremap := map[Feature]FeatureSpec{ + testGAGate: {Default: true, PreRelease: GA}, + testAlphaGate: {Default: false, PreRelease: Alpha}, + testBetaGate: {Default: true, PreRelease: Beta}, + } + + tests := []struct { + setmap map[string]bool + expect string + }{ + { + setmap: map[string]bool{ + "TestAlpha": false, + }, + expect: "TestAlpha=false", + }, + { + setmap: map[string]bool{ + "TestAlpha": false, + "TestBeta": true, + }, + expect: "TestAlpha=false,TestBeta=true", + }, + { + setmap: map[string]bool{ + "TestGA": true, + "TestAlpha": false, + "TestBeta": true, + }, + expect: "TestAlpha=false,TestBeta=true,TestGA=true", + }, + } + for i, test := range tests { + t.Run(fmt.Sprintf("SetFromMap %s", test.expect), func(t *testing.T) { + f := NewFeatureGate() + f.Add(featuremap) + f.SetFromMap(test.setmap) + result := f.String() + if result != test.expect { + t.Errorf("%d: SetFromMap(%#v) Expected %s, Got %s", i, test.setmap, test.expect, result) + } + }) + } +} diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/ciphersuites_flag_test.go b/vendor/k8s.io/apiserver/pkg/util/flag/ciphersuites_flag_test.go new file mode 100644 index 000000000..4a8c4efeb --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/flag/ciphersuites_flag_test.go @@ -0,0 +1,114 @@ +/* +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 flag + +import ( + "crypto/tls" + "fmt" + "go/importer" + "reflect" + "strings" + "testing" +) + +func TestStrToUInt16(t *testing.T) { + tests := []struct { + flag []string + expected []uint16 + expected_error bool + }{ + { + // Happy case + flag: []string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"}, + expected: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, + expected_error: false, + }, + { + // One flag only + flag: []string{"TLS_RSA_WITH_RC4_128_SHA"}, + expected: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA}, + expected_error: false, + }, + { + // Empty flag + flag: []string{}, + expected: nil, + expected_error: false, + }, + { + // Duplicated flag + flag: []string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_RC4_128_SHA"}, + expected: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_RC4_128_SHA}, + expected_error: false, + }, + { + // Invalid flag + flag: []string{"foo"}, + expected: nil, + expected_error: true, + }, + } + + for i, test := range tests { + uIntFlags, err := TLSCipherSuites(test.flag) + if reflect.DeepEqual(uIntFlags, test.expected) == false { + t.Errorf("%d: expected %+v, got %+v", i, test.expected, uIntFlags) + } + if test.expected_error && err == nil { + t.Errorf("%d: expecting error, got %+v", i, err) + } + } +} + +func TestConstantMaps(t *testing.T) { + pkg, err := importer.Default().Import("crypto/tls") + if err != nil { + fmt.Printf("error: %s\n", err.Error()) + return + } + discoveredVersions := map[string]bool{} + discoveredCiphers := map[string]bool{} + for _, declName := range pkg.Scope().Names() { + if strings.HasPrefix(declName, "VersionTLS") { + discoveredVersions[declName] = true + } + if strings.HasPrefix(declName, "TLS_RSA_") || strings.HasPrefix(declName, "TLS_ECDHE_") { + discoveredCiphers[declName] = true + } + } + + for k := range discoveredCiphers { + if _, ok := ciphers[k]; !ok { + t.Errorf("discovered cipher tls.%s not in ciphers map", k) + } + } + for k := range ciphers { + if _, ok := discoveredCiphers[k]; !ok { + t.Errorf("ciphers map has %s not in tls package", k) + } + } + for k := range discoveredVersions { + if _, ok := versions[k]; !ok { + t.Errorf("discovered version tls.%s not in version map", k) + } + } + for k := range versions { + if _, ok := discoveredVersions[k]; !ok { + t.Errorf("versions map has %s not in tls package", k) + } + } +} diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/colon_separated_multimap_string_string_test.go b/vendor/k8s.io/apiserver/pkg/util/flag/colon_separated_multimap_string_string_test.go new file mode 100644 index 000000000..9e77035c3 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/flag/colon_separated_multimap_string_string_test.go @@ -0,0 +1,242 @@ +/* +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 flag + +import ( + "reflect" + "testing" +) + +func TestStringColonSeparatedMultimapStringString(t *testing.T) { + var nilMap map[string][]string + cases := []struct { + desc string + m *ColonSeparatedMultimapStringString + expect string + }{ + {"nil", NewColonSeparatedMultimapStringString(&nilMap), ""}, + {"empty", NewColonSeparatedMultimapStringString(&map[string][]string{}), ""}, + {"empty key", NewColonSeparatedMultimapStringString( + &map[string][]string{ + "": {"foo"}, + }), + ":foo"}, + {"one key", NewColonSeparatedMultimapStringString( + &map[string][]string{ + "one": {"foo"}, + }), + "one:foo"}, + {"two keys", NewColonSeparatedMultimapStringString( + &map[string][]string{ + "one": {"foo"}, + "two": {"bar"}, + }), + "one:foo,two:bar"}, + {"two keys, multiple items in one key", NewColonSeparatedMultimapStringString( + &map[string][]string{ + "one": {"foo", "baz"}, + "two": {"bar"}, + }), + "one:foo,one:baz,two:bar"}, + {"three keys, multiple items in one key", NewColonSeparatedMultimapStringString( + &map[string][]string{ + "a": {"hello"}, + "b": {"again", "beautiful"}, + "c": {"world"}, + }), + "a:hello,b:again,b:beautiful,c:world"}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + str := c.m.String() + if c.expect != str { + t.Fatalf("expect %q but got %q", c.expect, str) + } + }) + } +} + +func TestSetColonSeparatedMultimapStringString(t *testing.T) { + var nilMap map[string][]string + cases := []struct { + desc string + vals []string + start *ColonSeparatedMultimapStringString + expect *ColonSeparatedMultimapStringString + err string + }{ + // we initialize the map with a default key that should be cleared by Set + {"clears defaults", []string{""}, + NewColonSeparatedMultimapStringString(&map[string][]string{"default": {}}), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{}}, ""}, + // make sure we still allocate for "initialized" multimaps where Multimap was initially set to a nil map + {"allocates map if currently nil", []string{""}, + &ColonSeparatedMultimapStringString{initialized: true, Multimap: &nilMap}, + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{}, + }, ""}, + // for most cases, we just reuse nilMap, which should be allocated by Set, and is reset before each test case + {"empty", []string{""}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{}}, ""}, + {"empty key", []string{":foo"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "": {"foo"}, + }}, ""}, + {"one key", []string{"one:foo"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "one": {"foo"}, + }}, ""}, + {"two keys", []string{"one:foo,two:bar"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "one": {"foo"}, + "two": {"bar"}, + }}, ""}, + {"two keys with space", []string{"one:foo, two:bar"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "one": {"foo"}, + "two": {"bar"}, + }}, ""}, + {"two keys, multiple items in one key", []string{"one: foo, two:bar, one:baz"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "one": {"foo", "baz"}, + "two": {"bar"}, + }}, ""}, + {"three keys, multiple items in one key", []string{"a:hello,b:again,c:world,b:beautiful"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "a": {"hello"}, + "b": {"again", "beautiful"}, + "c": {"world"}, + }}, ""}, + {"three keys, multiple items in one key, multiple Set invocations", []string{"a:hello,b:again", "c:world", "b:beautiful"}, + NewColonSeparatedMultimapStringString(&nilMap), + &ColonSeparatedMultimapStringString{ + initialized: true, + Multimap: &map[string][]string{ + "a": {"hello"}, + "b": {"again", "beautiful"}, + "c": {"world"}, + }}, ""}, + {"missing value", []string{"a"}, + NewColonSeparatedMultimapStringString(&nilMap), + nil, + "malformed pair, expect string:string"}, + {"no target", []string{"a:foo"}, + NewColonSeparatedMultimapStringString(nil), + nil, + "no target (nil pointer to map[string][]string)"}, + } + + for _, c := range cases { + nilMap = nil + t.Run(c.desc, func(t *testing.T) { + var err error + for _, val := range c.vals { + err = c.start.Set(val) + if err != nil { + break + } + } + if c.err != "" { + if err == nil || err.Error() != c.err { + t.Fatalf("expect error %s but got %v", c.err, err) + } + return + } else if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(c.expect, c.start) { + t.Fatalf("expect %#v but got %#v", c.expect, c.start) + } + }) + } +} + +func TestRoundTripColonSeparatedMultimapStringString(t *testing.T) { + cases := []struct { + desc string + vals []string + expect string + }{ + {"empty", []string{""}, ""}, + {"empty key", []string{":foo"}, ":foo"}, + {"one key", []string{"one:foo"}, "one:foo"}, + {"two keys", []string{"one:foo,two:bar"}, "one:foo,two:bar"}, + {"two keys, multiple items in one key", []string{"one:foo, two:bar, one:baz"}, "one:foo,one:baz,two:bar"}, + {"three keys, multiple items in one key", []string{"a:hello,b:again,c:world,b:beautiful"}, "a:hello,b:again,b:beautiful,c:world"}, + {"three keys, multiple items in one key, multiple Set invocations", []string{"a:hello,b:again", "c:world", "b:beautiful"}, "a:hello,b:again,b:beautiful,c:world"}, + } + + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + m := NewColonSeparatedMultimapStringString(&map[string][]string{}) + for _, val := range c.vals { + if err := m.Set(val); err != nil { + t.Fatalf("unexpected error: %v", err) + } + } + str := m.String() + if c.expect != str { + t.Fatalf("expect %q but got %q", c.expect, str) + } + }) + } +} + +func TestEmptyColonSeparatedMultimapStringString(t *testing.T) { + var nilMap map[string][]string + cases := []struct { + desc string + val *ColonSeparatedMultimapStringString + expect bool + }{ + {"nil", NewColonSeparatedMultimapStringString(&nilMap), true}, + {"empty", NewColonSeparatedMultimapStringString(&map[string][]string{}), true}, + {"populated", NewColonSeparatedMultimapStringString(&map[string][]string{"foo": {}}), false}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + result := c.val.Empty() + if result != c.expect { + t.Fatalf("expect %t but got %t", c.expect, result) + } + }) + } +} diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/langle_separated_map_string_string_test.go b/vendor/k8s.io/apiserver/pkg/util/flag/langle_separated_map_string_string_test.go new file mode 100644 index 000000000..80c67c32b --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/flag/langle_separated_map_string_string_test.go @@ -0,0 +1,159 @@ +/* +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 flag + +import ( + "reflect" + "testing" +) + +func TestStringLangleSeparatedMapStringString(t *testing.T) { + var nilMap map[string]string + cases := []struct { + desc string + m *LangleSeparatedMapStringString + expect string + }{ + {"nil", NewLangleSeparatedMapStringString(&nilMap), ""}, + {"empty", NewLangleSeparatedMapStringString(&map[string]string{}), ""}, + {"one key", NewLangleSeparatedMapStringString(&map[string]string{"one": "foo"}), "one<foo"}, + {"two keys", NewLangleSeparatedMapStringString(&map[string]string{"one": "foo", "two": "bar"}), "one<foo,two<bar"}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + str := c.m.String() + if c.expect != str { + t.Fatalf("expect %q but got %q", c.expect, str) + } + }) + } +} + +func TestSetLangleSeparatedMapStringString(t *testing.T) { + var nilMap map[string]string + cases := []struct { + desc string + vals []string + start *LangleSeparatedMapStringString + expect *LangleSeparatedMapStringString + err string + }{ + // we initialize the map with a default key that should be cleared by Set + {"clears defaults", []string{""}, + NewLangleSeparatedMapStringString(&map[string]string{"default": ""}), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{}, + }, ""}, + // make sure we still allocate for "initialized" maps where Map was initially set to a nil map + {"allocates map if currently nil", []string{""}, + &LangleSeparatedMapStringString{initialized: true, Map: &nilMap}, + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{}, + }, ""}, + // for most cases, we just reuse nilMap, which should be allocated by Set, and is reset before each test case + {"empty", []string{""}, + NewLangleSeparatedMapStringString(&nilMap), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{}, + }, ""}, + {"one key", []string{"one<foo"}, + NewLangleSeparatedMapStringString(&nilMap), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo"}, + }, ""}, + {"two keys", []string{"one<foo,two<bar"}, + NewLangleSeparatedMapStringString(&nilMap), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo", "two": "bar"}, + }, ""}, + {"two keys, multiple Set invocations", []string{"one<foo", "two<bar"}, + NewLangleSeparatedMapStringString(&nilMap), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo", "two": "bar"}, + }, ""}, + {"two keys with space", []string{"one<foo, two<bar"}, + NewLangleSeparatedMapStringString(&nilMap), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo", "two": "bar"}, + }, ""}, + {"empty key", []string{"<foo"}, + NewLangleSeparatedMapStringString(&nilMap), + &LangleSeparatedMapStringString{ + initialized: true, + Map: &map[string]string{"": "foo"}, + }, ""}, + {"missing value", []string{"one"}, + NewLangleSeparatedMapStringString(&nilMap), + nil, + "malformed pair, expect string<string"}, + {"no target", []string{"a:foo"}, + NewLangleSeparatedMapStringString(nil), + nil, + "no target (nil pointer to map[string]string)"}, + } + for _, c := range cases { + nilMap = nil + t.Run(c.desc, func(t *testing.T) { + var err error + for _, val := range c.vals { + err = c.start.Set(val) + if err != nil { + break + } + } + if c.err != "" { + if err == nil || err.Error() != c.err { + t.Fatalf("expect error %s but got %v", c.err, err) + } + return + } else if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(c.expect, c.start) { + t.Fatalf("expect %#v but got %#v", c.expect, c.start) + } + }) + } +} + +func TestEmptyLangleSeparatedMapStringString(t *testing.T) { + var nilMap map[string]string + cases := []struct { + desc string + val *LangleSeparatedMapStringString + expect bool + }{ + {"nil", NewLangleSeparatedMapStringString(&nilMap), true}, + {"empty", NewLangleSeparatedMapStringString(&map[string]string{}), true}, + {"populated", NewLangleSeparatedMapStringString(&map[string]string{"foo": ""}), false}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + result := c.val.Empty() + if result != c.expect { + t.Fatalf("expect %t but got %t", c.expect, result) + } + }) + } +} diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/map_string_bool_test.go b/vendor/k8s.io/apiserver/pkg/util/flag/map_string_bool_test.go new file mode 100644 index 000000000..f23b240a1 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/flag/map_string_bool_test.go @@ -0,0 +1,163 @@ +/* +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 flag + +import ( + "reflect" + "testing" +) + +func TestStringMapStringBool(t *testing.T) { + var nilMap map[string]bool + cases := []struct { + desc string + m *MapStringBool + expect string + }{ + {"nil", NewMapStringBool(&nilMap), ""}, + {"empty", NewMapStringBool(&map[string]bool{}), ""}, + {"one key", NewMapStringBool(&map[string]bool{"one": true}), "one=true"}, + {"two keys", NewMapStringBool(&map[string]bool{"one": true, "two": false}), "one=true,two=false"}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + str := c.m.String() + if c.expect != str { + t.Fatalf("expect %q but got %q", c.expect, str) + } + }) + } +} + +func TestSetMapStringBool(t *testing.T) { + var nilMap map[string]bool + cases := []struct { + desc string + vals []string + start *MapStringBool + expect *MapStringBool + err string + }{ + // we initialize the map with a default key that should be cleared by Set + {"clears defaults", []string{""}, + NewMapStringBool(&map[string]bool{"default": true}), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{}, + }, ""}, + // make sure we still allocate for "initialized" maps where Map was initially set to a nil map + {"allocates map if currently nil", []string{""}, + &MapStringBool{initialized: true, Map: &nilMap}, + &MapStringBool{ + initialized: true, + Map: &map[string]bool{}, + }, ""}, + // for most cases, we just reuse nilMap, which should be allocated by Set, and is reset before each test case + {"empty", []string{""}, + NewMapStringBool(&nilMap), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{}, + }, ""}, + {"one key", []string{"one=true"}, + NewMapStringBool(&nilMap), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{"one": true}, + }, ""}, + {"two keys", []string{"one=true,two=false"}, + NewMapStringBool(&nilMap), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{"one": true, "two": false}, + }, ""}, + {"two keys, multiple Set invocations", []string{"one=true", "two=false"}, + NewMapStringBool(&nilMap), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{"one": true, "two": false}, + }, ""}, + {"two keys with space", []string{"one=true, two=false"}, + NewMapStringBool(&nilMap), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{"one": true, "two": false}, + }, ""}, + {"empty key", []string{"=true"}, + NewMapStringBool(&nilMap), + &MapStringBool{ + initialized: true, + Map: &map[string]bool{"": true}, + }, ""}, + {"missing value", []string{"one"}, + NewMapStringBool(&nilMap), + nil, + "malformed pair, expect string=bool"}, + {"non-boolean value", []string{"one=foo"}, + NewMapStringBool(&nilMap), + nil, + `invalid value of one: foo, err: strconv.ParseBool: parsing "foo": invalid syntax`}, + {"no target", []string{"one=true"}, + NewMapStringBool(nil), + nil, + "no target (nil pointer to map[string]bool)"}, + } + for _, c := range cases { + nilMap = nil + t.Run(c.desc, func(t *testing.T) { + var err error + for _, val := range c.vals { + err = c.start.Set(val) + if err != nil { + break + } + } + if c.err != "" { + if err == nil || err.Error() != c.err { + t.Fatalf("expect error %s but got %v", c.err, err) + } + return + } else if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(c.expect, c.start) { + t.Fatalf("expect %#v but got %#v", c.expect, c.start) + } + }) + } +} + +func TestEmptyMapStringBool(t *testing.T) { + var nilMap map[string]bool + cases := []struct { + desc string + val *MapStringBool + expect bool + }{ + {"nil", NewMapStringBool(&nilMap), true}, + {"empty", NewMapStringBool(&map[string]bool{}), true}, + {"populated", NewMapStringBool(&map[string]bool{"foo": true}), false}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + result := c.val.Empty() + if result != c.expect { + t.Fatalf("expect %t but got %t", c.expect, result) + } + }) + } +} diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/map_string_string_test.go b/vendor/k8s.io/apiserver/pkg/util/flag/map_string_string_test.go new file mode 100644 index 000000000..aba984e7a --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/flag/map_string_string_test.go @@ -0,0 +1,181 @@ +/* +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 flag + +import ( + "reflect" + "testing" +) + +func TestStringMapStringString(t *testing.T) { + var nilMap map[string]string + cases := []struct { + desc string + m *MapStringString + expect string + }{ + {"nil", NewMapStringString(&nilMap), ""}, + {"empty", NewMapStringString(&map[string]string{}), ""}, + {"one key", NewMapStringString(&map[string]string{"one": "foo"}), "one=foo"}, + {"two keys", NewMapStringString(&map[string]string{"one": "foo", "two": "bar"}), "one=foo,two=bar"}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + str := c.m.String() + if c.expect != str { + t.Fatalf("expect %q but got %q", c.expect, str) + } + }) + } +} + +func TestSetMapStringString(t *testing.T) { + var nilMap map[string]string + cases := []struct { + desc string + vals []string + start *MapStringString + expect *MapStringString + err string + }{ + // we initialize the map with a default key that should be cleared by Set + {"clears defaults", []string{""}, + NewMapStringString(&map[string]string{"default": ""}), + &MapStringString{ + initialized: true, + Map: &map[string]string{}, + NoSplit: false, + }, ""}, + // make sure we still allocate for "initialized" maps where Map was initially set to a nil map + {"allocates map if currently nil", []string{""}, + &MapStringString{initialized: true, Map: &nilMap}, + &MapStringString{ + initialized: true, + Map: &map[string]string{}, + NoSplit: false, + }, ""}, + // for most cases, we just reuse nilMap, which should be allocated by Set, and is reset before each test case + {"empty", []string{""}, + NewMapStringString(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{}, + NoSplit: false, + }, ""}, + {"one key", []string{"one=foo"}, + NewMapStringString(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo"}, + NoSplit: false, + }, ""}, + {"two keys", []string{"one=foo,two=bar"}, + NewMapStringString(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo", "two": "bar"}, + NoSplit: false, + }, ""}, + {"one key, multi flag invocation only", []string{"one=foo,bar"}, + NewMapStringStringNoSplit(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo,bar"}, + NoSplit: true, + }, ""}, + {"two keys, multi flag invocation only", []string{"one=foo,bar", "two=foo,bar"}, + NewMapStringStringNoSplit(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo,bar", "two": "foo,bar"}, + NoSplit: true, + }, ""}, + {"two keys, multiple Set invocations", []string{"one=foo", "two=bar"}, + NewMapStringString(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo", "two": "bar"}, + NoSplit: false, + }, ""}, + {"two keys with space", []string{"one=foo, two=bar"}, + NewMapStringString(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"one": "foo", "two": "bar"}, + NoSplit: false, + }, ""}, + {"empty key", []string{"=foo"}, + NewMapStringString(&nilMap), + &MapStringString{ + initialized: true, + Map: &map[string]string{"": "foo"}, + NoSplit: false, + }, ""}, + {"missing value", []string{"one"}, + NewMapStringString(&nilMap), + nil, + "malformed pair, expect string=string"}, + {"no target", []string{"a:foo"}, + NewMapStringString(nil), + nil, + "no target (nil pointer to map[string]string)"}, + } + for _, c := range cases { + nilMap = nil + t.Run(c.desc, func(t *testing.T) { + var err error + for _, val := range c.vals { + err = c.start.Set(val) + if err != nil { + break + } + } + if c.err != "" { + if err == nil || err.Error() != c.err { + t.Fatalf("expect error %s but got %v", c.err, err) + } + return + } else if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !reflect.DeepEqual(c.expect, c.start) { + t.Fatalf("expect %#v but got %#v", c.expect, c.start) + } + }) + } +} + +func TestEmptyMapStringString(t *testing.T) { + var nilMap map[string]string + cases := []struct { + desc string + val *MapStringString + expect bool + }{ + {"nil", NewMapStringString(&nilMap), true}, + {"empty", NewMapStringString(&map[string]string{}), true}, + {"populated", NewMapStringString(&map[string]string{"foo": ""}), false}, + } + for _, c := range cases { + t.Run(c.desc, func(t *testing.T) { + result := c.val.Empty() + if result != c.expect { + t.Fatalf("expect %t but got %t", c.expect, result) + } + }) + } +} diff --git a/vendor/k8s.io/apiserver/pkg/util/flag/namedcertkey_flag_test.go b/vendor/k8s.io/apiserver/pkg/util/flag/namedcertkey_flag_test.go new file mode 100644 index 000000000..542e221c9 --- /dev/null +++ b/vendor/k8s.io/apiserver/pkg/util/flag/namedcertkey_flag_test.go @@ -0,0 +1,138 @@ +/* +Copyright 2016 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 flag + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "github.com/spf13/pflag" +) + +func TestNamedCertKeyArrayFlag(t *testing.T) { + tests := []struct { + args []string + def []NamedCertKey + expected []NamedCertKey + parseError string + }{ + { + args: []string{}, + expected: nil, + }, + { + args: []string{"foo.crt,foo.key"}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + }}, + }, + { + args: []string{" foo.crt , foo.key "}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + }}, + }, + { + args: []string{"foo.crt,foo.key:abc"}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + Names: []string{"abc"}, + }}, + }, + { + args: []string{"foo.crt,foo.key: abc "}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + Names: []string{"abc"}, + }}, + }, + { + args: []string{"foo.crt,foo.key:"}, + parseError: "empty names list is not allowed", + }, + { + args: []string{""}, + parseError: "expected comma separated certificate and key file paths", + }, + { + args: []string{" "}, + parseError: "expected comma separated certificate and key file paths", + }, + { + args: []string{"a,b,c"}, + parseError: "expected comma separated certificate and key file paths", + }, + { + args: []string{"foo.crt,foo.key:abc,def,ghi"}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + Names: []string{"abc", "def", "ghi"}, + }}, + }, + { + args: []string{"foo.crt,foo.key:*.*.*"}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + Names: []string{"*.*.*"}, + }}, + }, + { + args: []string{"foo.crt,foo.key", "bar.crt,bar.key"}, + expected: []NamedCertKey{{ + KeyFile: "foo.key", + CertFile: "foo.crt", + }, { + KeyFile: "bar.key", + CertFile: "bar.crt", + }}, + }, + } + for i, test := range tests { + fs := pflag.NewFlagSet("testNamedCertKeyArray", pflag.ContinueOnError) + var nkcs []NamedCertKey + nkcs = append(nkcs, test.def...) + + fs.Var(NewNamedCertKeyArray(&nkcs), "tls-sni-cert-key", "usage") + + args := []string{} + for _, a := range test.args { + args = append(args, fmt.Sprintf("--tls-sni-cert-key=%s", a)) + } + + err := fs.Parse(args) + if test.parseError != "" { + if err == nil { + t.Errorf("%d: expected error %q, got nil", i, test.parseError) + } else if !strings.Contains(err.Error(), test.parseError) { + t.Errorf("%d: expected error %q, got %q", i, test.parseError, err) + } + } else if err != nil { + t.Errorf("%d: expected nil error, got %v", i, err) + } + if !reflect.DeepEqual(nkcs, test.expected) { + t.Errorf("%d: expected %+v, got %+v", i, test.expected, nkcs) + } + } +} diff --git a/vendor/k8s.io/client-go/.travis.yml b/vendor/k8s.io/client-go/.travis.yml new file mode 100644 index 000000000..b80875cae --- /dev/null +++ b/vendor/k8s.io/client-go/.travis.yml @@ -0,0 +1,8 @@ +language: go + +go_import_path: k8s.io/client-go + +go: + - 1.10.2 + +script: go build ./... diff --git a/vendor/k8s.io/client-go/CHANGELOG.md b/vendor/k8s.io/client-go/CHANGELOG.md new file mode 100644 index 000000000..7e556dd29 --- /dev/null +++ b/vendor/k8s.io/client-go/CHANGELOG.md @@ -0,0 +1,590 @@ +TODO: This document was manually maintained so might be incomplete. The +automation effort is tracked in +https://github.com/kubernetes/test-infra/issues/5843. + +Changes in `k8s.io/api` and `k8s.io/apimachinery` are mentioned here +because `k8s.io/client-go` depends on them. + +# v8.0.0 + +**Breaking Changes:** + +* `KUBE_API_VERSIONS` has been removed. + + * [https://github.com/kubernetes/kubernetes/pull/63165](https://github.com/kubernetes/kubernetes/pull/63165) + +* The client-go/discovery `RESTMapper` has been moved to client-go/restmapper. + + * [https://github.com/kubernetes/kubernetes/pull/63507](https://github.com/kubernetes/kubernetes/pull/63507) + +* `CachedDiscoveryClient` has been moved from kubectl to client-go. + + * [https://github.com/kubernetes/kubernetes/pull/63550](https://github.com/kubernetes/kubernetes/pull/63550) + +* The `EventRecorder` interface is changed to include an `AnnotatedEventf` method, which can add annotations to an event. + + * [https://github.com/kubernetes/kubernetes/pull/64213](https://github.com/kubernetes/kubernetes/pull/64213) + +* [k8s.io/apimachinery] The deprecated `RepairMalformedUpdates` flag has been removed. + + * [https://github.com/kubernetes/kubernetes/pull/61455](https://github.com/kubernetes/kubernetes/pull/61455) + +**New Features:** + +* A new easy-to-use dynamic client is added and the old dynamic client is now deprecated. + + * [https://github.com/kubernetes/kubernetes/pull/62913](https://github.com/kubernetes/kubernetes/pull/62913) + +* client-go and kubectl now detect and report an error on duplicated name for user, cluster and context, while loading the kubeconfig. + + * [https://github.com/kubernetes/kubernetes/pull/60464](https://github.com/kubernetes/kubernetes/pull/60464) + +* The informer code-generator now allows specifying a custom resync period for certain informer types and uses the default resync period if none is specified. + + * [https://github.com/kubernetes/kubernetes/pull/61400](https://github.com/kubernetes/kubernetes/pull/61400) + +* Exec authenticator plugin now supports TLS client certificates. + + * [https://github.com/kubernetes/kubernetes/pull/61803](https://github.com/kubernetes/kubernetes/pull/61803) + +* The discovery client now has a default request timeout of 32 seconds. + + * [https://github.com/kubernetes/kubernetes/pull/62733](https://github.com/kubernetes/kubernetes/pull/62733) + +* The OpenStack auth config from is now read from the client config. If the client config is not available, it falls back to reading from the environment variables. + + * [https://github.com/kubernetes/kubernetes/pull/60200](https://github.com/kubernetes/kubernetes/pull/60200) + +* The in-tree support for openstack credentials is now deprecated. Please use the `client-keystone-auth` from the cloud-provider-openstack repository. Details on how to use this new capability is documented [here](https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/using-client-keystone-auth.md) + + * [https://github.com/kubernetes/kubernetes/pull/64346](https://github.com/kubernetes/kubernetes/pull/64346) + +**Bug fixes and Improvements:** + +* 406 mime-type errors are now tolerated while attempting to load new openapi schema. This improves compatibility with older servers when creating/updating API objects. + + * [https://github.com/kubernetes/kubernetes/pull/61949](https://github.com/kubernetes/kubernetes/pull/61949) + +* Removes the generated `DeleteCollection()` method for `Services` since the API does not support it. + + * [https://github.com/kubernetes/kubernetes/pull/63861](https://github.com/kubernetes/kubernetes/pull/63861) + +* Event object references with apiversion now report an apiversion, instead of just the group. + + * [https://github.com/kubernetes/kubernetes/pull/63913](https://github.com/kubernetes/kubernetes/pull/63913) + + [https://github.com/kubernetes/kubernetes/pull/62462](https://github.com/kubernetes/kubernetes/pull/62462) + +* [k8s.io/apimachinery] `runtime.Unstructured.UnstructuredContent()` no longer mutates the source while returning the contents. + + * [https://github.com/kubernetes/kubernetes/pull/62063](https://github.com/kubernetes/kubernetes/pull/62063) + +* [k8s.io/apimachinery] Incomplete support for `uint64` is now removed. This fixes a panic encountered while using `DeepCopyJSON` with `uint64`. + + * [https://github.com/kubernetes/kubernetes/pull/62981](https://github.com/kubernetes/kubernetes/pull/62981) + +* [k8s.io/apimachinery] API server can now parse `propagationPolicy` when it sent as a query parameter sent with a delete request. + + * [https://github.com/kubernetes/kubernetes/pull/63414](https://github.com/kubernetes/kubernetes/pull/63414) + +* [k8s.io/apimachinery] APIServices with kube-like versions (e.g. v1, v2beta1, etc.) will be sorted appropriately within each group. + + * [https://github.com/kubernetes/kubernetes/pull/64004](https://github.com/kubernetes/kubernetes/pull/64004) + +* [k8s.io/apimachinery] `int64` is the only allowed integer for printers. + + * [https://github.com/kubernetes/kubernetes/pull/64639](https://github.com/kubernetes/kubernetes/pull/64639) + +## API changes + +**Breaking Changes:** + +* Support for `alpha.kubernetes.io/nvidia-gpu` resource which was deprecated in 1.10 is removed. Please use the resource exposed by `DevicePlugins` instead (`nvidia.com/gpu`). + + * [https://github.com/kubernetes/kubernetes/pull/61498](https://github.com/kubernetes/kubernetes/pull/61498) + +* Alpha annotation for `PersistentVolume` node affinity has been removed. Update your `PersistentVolume`s to use the beta `PersistentVolume.nodeAffinity` field before upgrading. + + * [https://github.com/kubernetes/kubernetes/pull/61816](https://github.com/kubernetes/kubernetes/pull/61816) + +* `ObjectMeta ` `ListOptions` `DeleteOptions` are removed from the core api group. Please use the ones in `meta/v1` instead. + + * [https://github.com/kubernetes/kubernetes/pull/61809](https://github.com/kubernetes/kubernetes/pull/61809) + +* `ExternalID` in `NodeSpec` is deprecated. The externalID of the node is no longer set in the Node spec. + + * [https://github.com/kubernetes/kubernetes/pull/61877](https://github.com/kubernetes/kubernetes/pull/61877) + +* PSP-related types in the `extensions/v1beta1` API group are now deprecated. It is suggested to use the `policy/v1beta1` API group instead. + + * [https://github.com/kubernetes/kubernetes/pull/61777](https://github.com/kubernetes/kubernetes/pull/61777) + +**New Features:** + +* `PodSecurityPolicy` now supports restricting hostPath volume mounts to be readOnly and under specific path prefixes. + + * [https://github.com/kubernetes/kubernetes/pull/58647](https://github.com/kubernetes/kubernetes/pull/58647) + +* `Node.Spec.ConfigSource.ConfigMap.KubeletConfigKey` must be specified when using dynamic Kubelet config to tell the Kubelet which key of the `ConfigMap` identifies its config file. + + * [https://github.com/kubernetes/kubernetes/pull/59847](https://github.com/kubernetes/kubernetes/pull/59847) + +* `serverAddressByClientCIDRs` in `meta/v1` APIGroup is now optional. + + * [https://github.com/kubernetes/kubernetes/pull/61963](https://github.com/kubernetes/kubernetes/pull/61963) + +* A new field `MatchFields` is added to `NodeSelectorTerm`. Currently, it only supports `metadata.name`. + + * [https://github.com/kubernetes/kubernetes/pull/62002](https://github.com/kubernetes/kubernetes/pull/62002) + +* The `PriorityClass` API is promoted to `scheduling.k8s.io/v1beta1`. + + * [https://github.com/kubernetes/kubernetes/pull/63100](https://github.com/kubernetes/kubernetes/pull/63100) + +* The status of dynamic Kubelet config is now reported via `Node.Status.Config`, rather than the `KubeletConfigOk` node condition. + + * [https://github.com/kubernetes/kubernetes/pull/63314](https://github.com/kubernetes/kubernetes/pull/63314) + +* The `GitRepo` volume type is deprecated. To provision a container with a git repo, mount an `EmptyDir` into an `InitContainer` that clones the repo using git, then mount the `EmptyDir` into the Pod's container. + + * [https://github.com/kubernetes/kubernetes/pull/63445](https://github.com/kubernetes/kubernetes/pull/63445) + +* The Sysctls experimental feature has been promoted to beta (enabled by default via the `Sysctls` feature flag). `PodSecurityPolicy` and `Pod` objects now have fields for specifying and controlling sysctls. Alpha sysctl annotations will be ignored by 1.11+ kubelets. All alpha sysctl annotations in existing deployments must be converted to API fields to be effective. + + * [https://github.com/kubernetes/kubernetes/pull/63717](https://github.com/kubernetes/kubernetes/pull/63717) + +* The annotation `service.alpha.kubernetes.io/tolerate-unready-endpoints` is deprecated. Users should use `Service.spec.publishNotReadyAddresses` instead. + + * [https://github.com/kubernetes/kubernetes/pull/63742](https://github.com/kubernetes/kubernetes/pull/63742) + +* `VerticalPodAutoscaler` has been added to `autoscaling/v1` API group. + + * [https://github.com/kubernetes/kubernetes/pull/63797](https://github.com/kubernetes/kubernetes/pull/63797) + +* Alpha support is added for dynamic volume limits based on node type. + + * [https://github.com/kubernetes/kubernetes/pull/64154](https://github.com/kubernetes/kubernetes/pull/64154) + +* `ContainersReady` condition is added to the Pod status. + + * [https://github.com/kubernetes/kubernetes/pull/64646](https://github.com/kubernetes/kubernetes/pull/64646) + +**Bug fixes and Improvements:** + +* Default mount propagation has changed from `HostToContainer` (`rslave` in Linux terminology) to `None` (`private`) to match the behavior in 1.9 and earlier releases. `HostToContainer` as a default caused regressions in some pods. + + * [https://github.com/kubernetes/kubernetes/pull/62462](https://github.com/kubernetes/kubernetes/pull/62462) + +# v7.0.0 + +**Breaking Changes:** + +* Google Cloud Service Account email addresses can now be used in RBAC Role bindings since the default scopes now include the `userinfo.email` scope. This is a breaking change if the numeric uniqueIDs of the Google service accounts were being used in RBAC role bindings. The behavior can be overridden by explicitly specifying the scope values as comma-separated string in the `users[*].config.scopes` field in the `KUBECONFIG` file. + + * [https://github.com/kubernetes/kubernetes/pull/58141](https://github.com/kubernetes/kubernetes/pull/58141) + +* [k8s.io/api] The `ConfigOK` node condition has been renamed to `KubeletConfigOk`. + + * [https://github.com/kubernetes/kubernetes/pull/59905](https://github.com/kubernetes/kubernetes/pull/59905) + +**New Features:** + +* Subresource support is added to the dynamic client. + + * [https://github.com/kubernetes/kubernetes/pull/56717](https://github.com/kubernetes/kubernetes/pull/56717) + +* A watch method is added to the Fake Client. + + * [https://github.com/kubernetes/kubernetes/pull/57504](https://github.com/kubernetes/kubernetes/pull/57504) + +* `ListOptions` can be modified when creating a `ListWatch`. + + * [https://github.com/kubernetes/kubernetes/pull/57508](https://github.com/kubernetes/kubernetes/pull/57508) + +* A `/token` subresource for ServiceAccount is added. + + * [https://github.com/kubernetes/kubernetes/pull/58111](https://github.com/kubernetes/kubernetes/pull/58111) + +* If an informer delivery fails, the particular notification is skipped and continued the next time. + + * [https://github.com/kubernetes/kubernetes/pull/58394](https://github.com/kubernetes/kubernetes/pull/58394) + +* Certificate manager will no longer wait until the initial rotation succeeds or fails before returning from `Start()`. + + * [https://github.com/kubernetes/kubernetes/pull/58930](https://github.com/kubernetes/kubernetes/pull/58930) + +* [k8s.io/api] `VolumeScheduling` and `LocalPersistentVolume` features are beta and enabled by default. The PersistentVolume NodeAffinity alpha annotation is deprecated and will be removed in a future release. + + * [https://github.com/kubernetes/kubernetes/pull/59391](https://github.com/kubernetes/kubernetes/pull/59391) + +* [k8s.io/api] The `PodSecurityPolicy` API has been moved to the `policy/v1beta1` API group. The `PodSecurityPolicy` API in the `extensions/v1beta1` API group is deprecated and will be removed in a future release. + + * [https://github.com/kubernetes/kubernetes/pull/54933](https://github.com/kubernetes/kubernetes/pull/54933) + +* [k8s.io/api] ConfigMap objects now support binary data via a new `binaryData` field. + + * [https://github.com/kubernetes/kubernetes/pull/57938](https://github.com/kubernetes/kubernetes/pull/57938) + +* [k8s.io/api] Service account TokenRequest API is added. + + * [https://github.com/kubernetes/kubernetes/pull/58027](https://github.com/kubernetes/kubernetes/pull/58027) + +* [k8s.io/api] FSType is added in CSI volume source to specify filesystems. + + * [https://github.com/kubernetes/kubernetes/pull/58209](https://github.com/kubernetes/kubernetes/pull/58209) + +* [k8s.io/api] v1beta1 VolumeAttachment API is added. + + * [https://github.com/kubernetes/kubernetes/pull/58462](https://github.com/kubernetes/kubernetes/pull/58462) + +* [k8s.io/api] `v1.Pod` now has a field `ShareProcessNamespace` to configure whether a single process namespace should be shared between all containers in a pod. This feature is in alpha preview. + + * [https://github.com/kubernetes/kubernetes/pull/58716](https://github.com/kubernetes/kubernetes/pull/58716) + +* [k8s.io/api] Add `NominatedNodeName` field to `PodStatus`. This field is set when a pod preempts other pods on the node. + + * [https://github.com/kubernetes/kubernetes/pull/58990](https://github.com/kubernetes/kubernetes/pull/58990) + +* [k8s.io/api] Promote `CSIPersistentVolumeSourc`e to beta. + + * [https://github.com/kubernetes/kubernetes/pull/59157](https://github.com/kubernetes/kubernetes/pull/59157) + +* [k8s.io/api] Promote `DNSPolicy` and `DNSConfig` in `PodSpec` to beta. + + * [https://github.com/kubernetes/kubernetes/pull/59771](https://github.com/kubernetes/kubernetes/pull/59771) + +* [k8s.io/api] External metric types are added to the HPA API. + + * [https://github.com/kubernetes/kubernetes/pull/60096](https://github.com/kubernetes/kubernetes/pull/60096) + +* [k8s.io/apimachinery] The `meta.k8s.io/v1alpha1` objects for retrieving tabular responses from the server (`Table`) or fetching just the `ObjectMeta` for an object (as `PartialObjectMetadata`) are now beta as part of `meta.k8s.io/v1beta1`. Clients may request alternate representations of normal Kubernetes objects by passing an `Accept` header like `application/json;as=Table;g=meta.k8s.io;v=v1beta1` or `application/json;as=PartialObjectMetadata;g=meta.k8s.io;v1=v1beta1`. Older servers will ignore this representation or return an error if it is not available. Clients may request fallback to the normal object by adding a non-qualified mime-type to their `Accept` header like `application/json` - the server will then respond with either the alternate representation if it is supported or the fallback mime-type which is the normal object response. + + * [https://github.com/kubernetes/kubernetes/pull/59059](https://github.com/kubernetes/kubernetes/pull/59059) + + +**Bug fixes and Improvements:** + +* Port-forwarding of TCP6 ports is fixed. + + * [https://github.com/kubernetes/kubernetes/pull/57457](https://github.com/kubernetes/kubernetes/pull/57457) + +* A race condition in SharedInformer that could violate the sequential delivery guarantee and cause panics on shutdown is fixed. + + * [https://github.com/kubernetes/kubernetes/pull/59828](https://github.com/kubernetes/kubernetes/pull/59828) + +* [k8s.io/api] PersistentVolume flexVolume sources can now reference secrets in a namespace other than the PersistentVolumeClaim's namespace. + + * [https://github.com/kubernetes/kubernetes/pull/56460](https://github.com/kubernetes/kubernetes/pull/56460) + +* [k8s.io/apimachinery] YAMLDecoder Read can now return the number of bytes read. + + * [https://github.com/kubernetes/kubernetes/pull/57000](https://github.com/kubernetes/kubernetes/pull/57000) + +* [k8s.io/apimachinery] YAMLDecoder Read now tracks rest of buffer on `io.ErrShortBuffer`. + + * [https://github.com/kubernetes/kubernetes/pull/58817](https://github.com/kubernetes/kubernetes/pull/58817) + +* [k8s.io/apimachinery] Prompt required merge key in the error message while applying a strategic merge patch. + + * [https://github.com/kubernetes/kubernetes/pull/57854](https://github.com/kubernetes/kubernetes/pull/57854) + +# v6.0.0 + +**Breaking Changes:** + +* If you upgrade your client-go libs and use the `AppsV1() or Apps()` interface, please note that the default garbage collection behavior is changed. + + * [https://github.com/kubernetes/kubernetes/pull/55148](https://github.com/kubernetes/kubernetes/pull/55148) + +* Swagger 1.2 retriever `DiscoveryClient.SwaggerSchema` was removed from the discovery client + + * [https://github.com/kubernetes/kubernetes/pull/53441](https://github.com/kubernetes/kubernetes/pull/53441) + +* Informers got a NewFilteredSharedInformerFactory to e.g. filter by namespace + + * [https://github.com/kubernetes/kubernetes/pull/54660](https://github.com/kubernetes/kubernetes/pull/54660) + +* [k8s.io/api] The dynamic admission webhook is split into two kinds, mutating and validating. +The kinds have changed completely and old code must be ported to `admissionregistration.k8s.io/v1beta1` - +`MutatingWebhookConfiguration` and `ValidatingWebhookConfiguration` + + * [https://github.com/kubernetes/kubernetes/pull/55282](https://github.com/kubernetes/kubernetes/pull/55282) + +* [k8s.io/api] Renamed `core/v1.ScaleIOVolumeSource` to `ScaleIOPersistentVolumeSource` + + * [https://github.com/kubernetes/kubernetes/pull/54013](https://github.com/kubernetes/kubernetes/pull/54013) + +* [k8s.io/api] Renamed `core/v1.RBDVolumeSource` to `RBDPersistentVolumeSource` + + * [https://github.com/kubernetes/kubernetes/pull/54302](https://github.com/kubernetes/kubernetes/pull/54302) + +* [k8s.io/api] Removed `core/v1.CreatedByAnnotation` + + * [https://github.com/kubernetes/kubernetes/pull/54445](https://github.com/kubernetes/kubernetes/pull/54445) + +* [k8s.io/api] Renamed `core/v1.StorageMediumHugepages` to `StorageMediumHugePages` + + * [https://github.com/kubernetes/kubernetes/pull/54748](https://github.com/kubernetes/kubernetes/pull/54748) + +* [k8s.io/api] `core/v1.Taint.TimeAdded` became a pointer + + * [https://github.com/kubernetes/kubernetes/pull/43016](https://github.com/kubernetes/kubernetes/pull/43016) + +* [k8s.io/api] `core/v1.DefaultHardPodAffinitySymmetricWeight` type changed from int to int32 + + * [https://github.com/kubernetes/kubernetes/pull/53850](https://github.com/kubernetes/kubernetes/pull/53850) + +* [k8s.io/apimachinery] `ObjectCopier` interface was removed (requires switch to new generators with DeepCopy methods) + + * [https://github.com/kubernetes/kubernetes/pull/53525](https://github.com/kubernetes/kubernetes/pull/53525) + +**New Features:** + +* Certificate manager was moved from kubelet to `k8s.io/client-go/util/certificates` + + * [https://github.com/kubernetes/kubernetes/pull/49654](https://github.com/kubernetes/kubernetes/pull/49654) + +* [k8s.io/api] Workloads api types are promoted to `apps/v1` version + + * [https://github.com/kubernetes/kubernetes/pull/53679](https://github.com/kubernetes/kubernetes/pull/53679) + +* [k8s.io/api] Added `storage.k8s.io/v1alpha1` API group + + * [https://github.com/kubernetes/kubernetes/pull/54463](https://github.com/kubernetes/kubernetes/pull/54463) + +* [k8s.io/api] Added support for conditions in StatefulSet status + + * [https://github.com/kubernetes/kubernetes/pull/55268](https://github.com/kubernetes/kubernetes/pull/55268) + +* [k8s.io/api] Added support for conditions in DaemonSet status + + * [https://github.com/kubernetes/kubernetes/pull/55272](https://github.com/kubernetes/kubernetes/pull/55272) + +* [k8s.io/apimachinery] Added polymorphic scale client in `k8s.io/client-go/scale`, which supports scaling of resources in arbitrary API groups + + * [https://github.com/kubernetes/kubernetes/pull/53743](https://github.com/kubernetes/kubernetes/pull/53743) + +* [k8s.io/apimachinery] `meta.MetadataAccessor` got API chunking support + + * [https://github.com/kubernetes/kubernetes/pull/53768](https://github.com/kubernetes/kubernetes/pull/53768) + +* [k8s.io/apimachinery] `unstructured.Unstructured` got getters and setters + + * [https://github.com/kubernetes/kubernetes/pull/51940](https://github.com/kubernetes/kubernetes/pull/51940) + +**Bug fixes and Improvements:** + +* The body in glog output is not truncated with log level 10 + + * [https://github.com/kubernetes/kubernetes/pull/54801](https://github.com/kubernetes/kubernetes/pull/54801) + +* [k8s.io/api] Unset `creationTimestamp` field is output as null if encoded from an unstructured object + + * [https://github.com/kubernetes/kubernetes/pull/53464](https://github.com/kubernetes/kubernetes/pull/53464) + +* [k8s.io/apimachinery] Redirect behavior is restored for proxy subresources + + * [https://github.com/kubernetes/kubernetes/pull/52933](https://github.com/kubernetes/kubernetes/pull/52933) + +* [k8s.io/apimachinery] Random string generation functions are optimized + + * [https://github.com/kubernetes/kubernetes/pull/53720](https://github.com/kubernetes/kubernetes/pull/53720) + +# v5.0.1 + +Bug fix: picked up a security fix [kubernetes/kubernetes#53443](https://github.com/kubernetes/kubernetes/pull/53443) for `PodSecurityPolicy`. + +# v5.0.0 + +**New features:** + +* Added paging support + + * [https://github.com/kubernetes/kubernetes/pull/51876](https://github.com/kubernetes/kubernetes/pull/51876) + +* Added support for client-side spam filtering of events + + * [https://github.com/kubernetes/kubernetes/pull/47367](https://github.com/kubernetes/kubernetes/pull/47367) + +* Added support for http etag and caching + + * [https://github.com/kubernetes/kubernetes/pull/50404](https://github.com/kubernetes/kubernetes/pull/50404) + +* Added priority queue support to informer cache + + * [https://github.com/kubernetes/kubernetes/pull/49752](https://github.com/kubernetes/kubernetes/pull/49752) + +* Added openstack auth provider + + * [https://github.com/kubernetes/kubernetes/pull/39587](https://github.com/kubernetes/kubernetes/pull/39587) + +* Added metrics for checking reflector health + + * [https://github.com/kubernetes/kubernetes/pull/48224](https://github.com/kubernetes/kubernetes/pull/48224) + +* Client-go now includes the leaderelection package + + * [https://github.com/kubernetes/kubernetes/pull/39173](https://github.com/kubernetes/kubernetes/pull/39173) + +**API changes:** + +* Promoted Autoscaling v2alpha1 to v2beta1 + + * [https://github.com/kubernetes/kubernetes/pull/50708](https://github.com/kubernetes/kubernetes/pull/50708) + +* Promoted CronJobs to batch/v1beta1 + + * [https://github.com/kubernetes/kubernetes/pull/41901](https://github.com/kubernetes/kubernetes/pull/41901) + +* Promoted rbac.authorization.k8s.io/v1beta1 to rbac.authorization.k8s.io/v1 + + * [https://github.com/kubernetes/kubernetes/pull/49642](https://github.com/kubernetes/kubernetes/pull/49642) + +* Added a new API version apps/v1beta2 + + * [https://github.com/kubernetes/kubernetes/pull/48746](https://github.com/kubernetes/kubernetes/pull/48746) + +* Added a new API version scheduling/v1alpha1 + + * [https://github.com/kubernetes/kubernetes/pull/48377](https://github.com/kubernetes/kubernetes/pull/48377) + +**Breaking changes:** + +* Moved pkg/api and pkg/apis to [k8s.io/api](https://github.com/kubernetes/api). Other kubernetes repositories also import types from there, so they are composable with client-go. + +* Removed helper functions in pkg/api and pkg/apis. They are planned to be exported in other repos. The issue is tracked [here](https://github.com/kubernetes/kubernetes/issues/48209#issuecomment-314537745). During the transition, you'll have to copy the helper functions to your projects. + +* The discovery client now fetches the protobuf encoded OpenAPI schema and returns `openapi_v2.Document` + + * [https://github.com/kubernetes/kubernetes/pull/46803](https://github.com/kubernetes/kubernetes/pull/46803) + +* Enforced explicit references to API group client interfaces in clientsets to avoid ambiguity. + + * [https://github.com/kubernetes/kubernetes/pull/49370](https://github.com/kubernetes/kubernetes/pull/49370) + +* The generic RESTClient type (`k8s.io/client-go/rest`) no longer exposes `LabelSelectorParam` or `FieldSelectorParam` methods - use `VersionedParams` with `metav1.ListOptions` instead. The `UintParam` method has been removed. The `timeout` parameter will no longer cause an error when using `Param()`. + + * [https://github.com/kubernetes/kubernetes/pull/48991](https://github.com/kubernetes/kubernetes/pull/48991) + +# v4.0.0 + +No significant changes since v4.0.0-beta.0. + +# v4.0.0-beta.0 + +**New features:** + +* Added OpenAPISchema support in the discovery client + + * [https://github.com/kubernetes/kubernetes/pull/44531](https://github.com/kubernetes/kubernetes/pull/44531) + +* Added mutation cache filter: MutationCache is able to take the result of update operations and stores them in an LRU that can be used to provide a more current view of a requested object. + + * [https://github.com/kubernetes/kubernetes/pull/45838](https://github.com/kubernetes/kubernetes/pull/45838/commits/f88c7725b4f9446c652d160bdcfab7c6201bddea) + +* Moved the remotecommand package (used by `kubectl exec/attach`) to client-go + + * [https://github.com/kubernetes/kubernetes/pull/41331](https://github.com/kubernetes/kubernetes/pull/41331) + +* Added support for following redirects to the SpdyRoundTripper + + * [https://github.com/kubernetes/kubernetes/pull/44451](https://github.com/kubernetes/kubernetes/pull/44451) + +* Added Azure Active Directory plugin + + * [https://github.com/kubernetes/kubernetes/pull/43987](https://github.com/kubernetes/kubernetes/pull/43987) + +**Usability improvements:** + +* Added several new examples and reorganized client-go/examples + + * [Related PRs](https://github.com/kubernetes/kubernetes/commits/release-1.7/staging/src/k8s.io/client-go/examples) + +**API changes:** + +* Added networking.k8s.io/v1 API + + * [https://github.com/kubernetes/kubernetes/pull/39164](https://github.com/kubernetes/kubernetes/pull/39164) + +* ControllerRevision type added for StatefulSet and DaemonSet history. + + * [https://github.com/kubernetes/kubernetes/pull/45867](https://github.com/kubernetes/kubernetes/pull/45867) + +* Added support for initializers + + * [https://github.com/kubernetes/kubernetes/pull/38058](https://github.com/kubernetes/kubernetes/pull/38058) + +* Added admissionregistration.k8s.io/v1alpha1 API + + * [https://github.com/kubernetes/kubernetes/pull/46294](https://github.com/kubernetes/kubernetes/pull/46294) + +**Breaking changes:** + +* Moved client-go/util/clock to apimachinery/pkg/util/clock + + * [https://github.com/kubernetes/kubernetes/pull/45933](https://github.com/kubernetes/kubernetes/pull/45933/commits/8013212db54e95050c622675c6706cce5de42b45) + +* Some [API helpers](https://github.com/kubernetes/client-go/blob/release-3.0/pkg/api/helpers.go) were removed. + +* Dynamic client takes GetOptions as an input parameter + + * [https://github.com/kubernetes/kubernetes/pull/47251](https://github.com/kubernetes/kubernetes/pull/47251) + +**Bug fixes:** + +* PortForwarder: don't log an error if net.Listen fails. [https://github.com/kubernetes/kubernetes/pull/44636](https://github.com/kubernetes/kubernetes/pull/44636) + +* oidc auth plugin not to override the Auth header if it's already exits. [https://github.com/kubernetes/kubernetes/pull/45529](https://github.com/kubernetes/kubernetes/pull/45529) + +* The --namespace flag is now honored for in-cluster clients that have an empty configuration. [https://github.com/kubernetes/kubernetes/pull/46299](https://github.com/kubernetes/kubernetes/pull/46299) + +* GCP auth plugin no longer overwrites existing Authorization headers. [https://github.com/kubernetes/kubernetes/pull/45575](https://github.com/kubernetes/kubernetes/pull/45575) + +# v3.0.0 + +Bug fixes: +* Use OS-specific libs when computing client User-Agent in kubectl, etc. (https://github.com/kubernetes/kubernetes/pull/44423) +* kubectl commands run inside a pod using a kubeconfig file now use the namespace specified in the kubeconfig file, instead of using the pod namespace. If no kubeconfig file is used, or the kubeconfig does not specify a namespace, the pod namespace is still used as a fallback. (https://github.com/kubernetes/kubernetes/pull/44570) +* Restored the ability of kubectl running inside a pod to consume resource files specifying a different namespace than the one the pod is running in. (https://github.com/kubernetes/kubernetes/pull/44862) + +# v3.0.0-beta.0 + +* Added dependency on k8s.io/apimachinery. The impacts include changing import path of API objects like `ListOptions` from `k8s.io/client-go/pkg/api/v1` to `k8s.io/apimachinery/pkg/apis/meta/v1`. +* Added generated listers (listers/) and informers (informers/) +* Kubernetes API changes: + * Added client support for: + * authentication/v1 + * authorization/v1 + * autoscaling/v2alpha1 + * rbac/v1beta1 + * settings/v1alpha1 + * storage/v1 + * Changed client support for: + * certificates from v1alpha1 to v1beta1 + * policy from v1alpha1 to v1beta1 + * Deleted client support for: + * extensions/v1beta1#Job +* CHANGED: pass typed options to dynamic client (https://github.com/kubernetes/kubernetes/pull/41887) + +# v2.0.0 + +* Included bug fixes in k8s.io/kuberentes release-1.5 branch, up to commit + bde8578d9675129b7a2aa08f1b825ec6cc0f3420 + +# v2.0.0-alpha.1 + +* Removed top-level version folder (e.g., 1.4 and 1.5), switching to maintaining separate versions + in separate branches. +* Clientset supported multiple versions per API group +* Added ThirdPartyResources example +* Kubernetes API changes + * Apps API group graduated to v1beta1 + * Policy API group graduated to v1beta1 + * Added support for batch/v2alpha1/cronjob + * Renamed PetSet to StatefulSet + + +# v1.5.0 + +* Included the auth plugin (https://github.com/kubernetes/kubernetes/pull/33334) +* Added timeout field to RESTClient config (https://github.com/kubernetes/kubernetes/pull/33958) diff --git a/vendor/k8s.io/client-go/CONTRIBUTING.md b/vendor/k8s.io/client-go/CONTRIBUTING.md new file mode 100644 index 000000000..a85350aae --- /dev/null +++ b/vendor/k8s.io/client-go/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository. They will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). +The exception is changes to the `README.md` itself. +Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/client-go](https://git.k8s.io/kubernetes/staging/src/k8s.io/client-go) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/staging.md) for more information diff --git a/vendor/k8s.io/client-go/INSTALL.md b/vendor/k8s.io/client-go/INSTALL.md new file mode 100644 index 000000000..d3592f490 --- /dev/null +++ b/vendor/k8s.io/client-go/INSTALL.md @@ -0,0 +1,162 @@ +# Installing client-go + +## For the casual user + +If you want to write a simple script, don't care about a reproducible client +library install, don't mind getting head (which may be less stable than a +particular release), then simply: + +```sh +$ go get k8s.io/client-go/... +``` + +This will install `k8s.io/client-go` in your `$GOPATH`. `k8s.io/client-go` +includes most of its own dependencies in its `k8s.io/client-go/vendor` path, +except for `k8s.io/apimachinery` and `glog`. `go get` will recursively download +these excluded repos to your `$GOPATH`, if they don't already exist. If +`k8s.io/apimachinery` preexisted in `$GOPATH`, you also need to: + +```sh +$ go get -u k8s.io/apimachinery/... +``` + +because the head of client-go is only guaranteed to work with the head of +apimachinery. + +We excluded `k8s.io/apimachinery` and `glog` from `k8s.io/client-go/vendor` to +prevent `go get` users from hitting issues like +[#19](https://github.com/kubernetes/client-go/issues/19) and +[#83](https://github.com/kubernetes/client-go/issues/83). If your project share +other dependencies with client-go, and you hit issues similar to #19 or #83, +then you'll need to look down at the next section. + +Note: the official go policy is that libraries should not vendor their +dependencies. This is unworkable for us, since our dependencies change and HEAD +on every dependency has not necessarily been tested with client-go. In fact, +HEAD from all dependencies may not even compile with client-go! + +## Dependency management for the serious (or reluctant) user + +Reasons why you might need to use a dependency management system: +* You use a dependency that client-go also uses, and don't want two copies of + the dependency compiled into your application. For some dependencies with + singletons or global inits (e.g. `glog`) this wouldn't even compile... +* You want to lock in a particular version (so you don't have to change your + code every time we change a public interface). +* You want your install to be reproducible. For example, for your CI system or + for new team members. + +There are three tools you could in theory use for this. Instructions +for each follows. + +### Godep + +[godep](https://github.com/tools/godep) is an older dependency management tool, which is +used by the main Kubernetes repo and `client-go` to manage dependencies. + +Before proceeding with the below instructions, you should ensure that your +$GOPATH is empty except for containing your own package and its dependencies, +and you have a copy of godep somewhere in your $PATH. + +To install `client-go` and place its dependencies in your `$GOPATH`: + +```sh +go get k8s.io/client-go/... +cd $GOPATH/src/k8s.io/client-go +git checkout v9.0.0 # replace v9.0.0 with the required version +# cd 1.5 # only necessary with 1.5 and 1.4 clients. +godep restore ./... +``` + +At this point, `client-go`'s dependencies have been placed in your $GOPATH, but +if you were to build, `client-go` would still see its own copy of its +dependencies in its `vendor` directory. You have two options at this point. + +If you would like to keep dependencies in your own project's vendor directory, +then you can continue like this: + +```sh +cd $GOPATH/src/<my-pkg> +godep save ./... +``` + +Alternatively, if you want to build using the dependencies in your `$GOPATH`, +then `rm -rf vendor/` to remove `client-go`'s copy of its dependencies. + +### Glide + +[Glide](https://github.com/Masterminds/glide) is another popular dependency +management tool for Go. Glide will manage your /vendor directory, but unlike +godep, will not use or modify your $GOPATH (there's no equivalent of +`godep restore` or `godep save`). + +Generally, it's best to avoid Glide's many subcommands, favoring modifying +Glide's manifest file (`glide.yaml`) directly, then running +`glide update --strip-vendor`. First create a `glide.yaml` file at the root of +your project: + +```yaml +package: ( your project's import path ) # e.g. github.com/foo/bar +import: +- package: k8s.io/client-go + version: v9.0.0 # replace v9.0.0 with the required version +``` + +Second, add a Go file that imports `client-go` somewhere in your project, +otherwise `client-go`'s dependencies will not be added to your project's +vendor/. Then run the following command in the same directory as `glide.yaml`: + +```sh +glide update --strip-vendor +``` + +This can also be abbreviated as: + +```sh +glide up -v +``` + +At this point, `k8s.io/client-go` should be added to your project's vendor/. +`client-go`'s dependencies should be flattened and be added to your project's +vendor/ as well. + +Glide will detect the versions of dependencies `client-go` specified in +`client-go`'s Godep.json file, and automatically set the versions of these +imports in your /vendor directory. It will also record the detected version of +all dependencies in the `glide.lock` file. + +Projects that require a different version of a dependency than `client-go` +requests can override the version manually in `glide.yaml`. For example: + +```yaml +package: ( your project's import path ) # e.g. github.com/foo/bar +import: +- package: k8s.io/client-go + version: v9.0.0 # replace v9.0.0 with the required version +# Use a newer version of go-spew even though client-go wants an old one. +- package: github.com/davecgh/go-spew + version: v1.1.0 +``` + +After modifying, run `glide up -v` again to re-populate your /vendor directory. + +Optionally, Glide users can also use [`glide-vc`](https://github.com/sgotti/glide-vc) +after running `glide up -v` to remove unused files from /vendor. + +### Dep (Not supported yet!) + +[dep](https://github.com/golang/dep) is an up-and-coming dependency management +tool, which has the goal of being accepted as part of the standard go toolchain. +However, client-go does **NOT** work well with `dep` yet. To support `dep`, we +need to fix at least two issues: +1. publish native `Gopkg.toml` in client-go and other k8s.io repos, like `k8s.io/apimachinery`; +2. find a way to express transitive constraints (see https://github.com/golang/dep/issues/1124). + +As a workaround, which may or may not be worthwhile, you can specify all +client-go dependencies manually as +[override](https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md#override) +in Gopkg.toml with the versions listed in [Godeps.json](./Godeps/Godeps.json), +and manually update them when you upgrade client-go version. + +We are actively working on the two issues blocking using `dep`. For the +meantime, we recommend using `glide` or `godeps`. diff --git a/vendor/k8s.io/client-go/OWNERS b/vendor/k8s.io/client-go/OWNERS new file mode 100644 index 000000000..52d334653 --- /dev/null +++ b/vendor/k8s.io/client-go/OWNERS @@ -0,0 +1,17 @@ +approvers: +- caesarxuchao +- deads2k +- lavalamp +- liggitt +- smarterclayton +- sttts +reviewers: +- caesarxuchao +- deads2k +- lavalamp +- liggitt +- soltysh +- sttts +- yliaog +labels: +- sig/api-machinery diff --git a/vendor/k8s.io/client-go/README.md b/vendor/k8s.io/client-go/README.md new file mode 100644 index 000000000..5f01fa180 --- /dev/null +++ b/vendor/k8s.io/client-go/README.md @@ -0,0 +1,193 @@ +# client-go + +Go clients for talking to a [kubernetes](http://kubernetes.io/) cluster. + +We currently recommend using the v8.0.0 tag. See [INSTALL.md](/INSTALL.md) for +detailed installation instructions. `go get k8s.io/client-go/...` works, but +will build `master`, which doesn't handle the dependencies well. + +[![BuildStatus Widget]][BuildStatus Result] +[![GoReport Widget]][GoReport Status] +[![GoDocWidget]][GoDocReference] + +[BuildStatus Result]: https://travis-ci.org/kubernetes/client-go +[BuildStatus Widget]: https://travis-ci.org/kubernetes/client-go.svg?branch=master + +[GoReport Status]: https://goreportcard.com/report/github.com/kubernetes/client-go +[GoReport Widget]: https://goreportcard.com/badge/github.com/kubernetes/client-go + +[GoDocWidget]: https://godoc.org/k8s.io/client-go?status.svg +[GoDocReference]:https://godoc.org/k8s.io/client-go + +## Table of Contents + +- [What's included](#whats-included) +- [Versioning](#versioning) + - [Compatibility: your code <-> client-go](#compatibility-your-code---client-go) + - [Compatibility: client-go <-> Kubernetes clusters](#compatibility-client-go---kubernetes-clusters) + - [Compatibility matrix](#compatibility-matrix) + - [Why do the 1.4 and 1.5 branch contain top-level folder named after the version?](#why-do-the-14-and-15-branch-contain-top-level-folder-named-after-the-version) +- [Kubernetes tags](#kubernetes-tags) +- [How to get it](#how-to-get-it) +- [How to use it](#how-to-use-it) +- [Dependency management](#dependency-management) +- [Contributing code](#contributing-code) + +### What's included + +* The `kubernetes` package contains the clientset to access Kubernetes API. +* The `discovery` package is used to discover APIs supported by a Kubernetes API server. +* The `dynamic` package contains a dynamic client that can perform generic operations on arbitrary Kubernetes API objects. +* The `transport` package is used to set up auth and start a connection. +* The `tools/cache` package is useful for writing controllers. + +### Versioning + +`client-go` follows [semver](http://semver.org/). We will not make +backwards-incompatible changes without incrementing the major version number. A +change is backwards-incompatible either if it *i)* changes the public interfaces +of `client-go`, or *ii)* makes `client-go` incompatible with otherwise supported +versions of Kubernetes clusters. + +Changes that add features in a backwards-compatible way will result in bumping +the minor version (second digit) number. + +Bugfixes will result in the patch version (third digit) changing. PRs that are +cherry-picked into an older Kubernetes release branch will result in an update +to the corresponding branch in `client-go`, with a corresponding new tag +changing the patch version. + +A consequence of this is that `client-go` version numbers will be unrelated to +Kubernetes version numbers. + +#### Branches and tags. + +We will create a new branch and tag for each increment in the major version number or +minor version number. We will create only a new tag for each increment in the patch +version number. See [semver](http://semver.org/) for definitions of major, +minor, and patch. + +The master branch will track HEAD in the main Kubernetes repo and +accumulate changes. Consider HEAD to have the version `x.(y+1).0-alpha` or +`(x+1).0.0-alpha` (depending on whether it has accumulated a breaking change or +not), where `x` and `y` are the current major and minor versions. + +#### Compatibility: your code <-> client-go + +`client-go` follows [semver](http://semver.org/), so until the major version of +client-go gets increased, your code will compile and will continue to work with +explicitly supported versions of Kubernetes clusters. You must use a dependency +management system and pin a specific major version of `client-go` to get this +benefit, as HEAD follows the upstream Kubernetes repo. + +#### Compatibility: client-go <-> Kubernetes clusters + +Since Kubernetes is backwards compatible with clients, older `client-go` +versions will work with many different Kubernetes cluster versions. + +We will backport bugfixes--but not new features--into older versions of +`client-go`. + + +#### Compatibility matrix + +| | Kubernetes 1.5 | Kubernetes 1.6 | Kubernetes 1.7 | Kubernetes 1.8 | Kubernetes 1.9 | Kubernetes 1.10 | Kubernetes 1.11 | +|---------------------|----------------|----------------|----------------|----------------|----------------|-----------------|-----------------| +| client-go 1.5 | - | - | - | - | - | - | - | +| client-go 2.0 | ✓ | +- | +- | +- | +- | +- | +- | +| client-go 3.0 | +- | ✓ | - | +- | +- | +- | +- | +| client-go 4.0 | +- | +- | ✓ | +- | +- | +- | +- | +| client-go 5.0 | +- | +- | +- | ✓ | +- | +- | +- | +| client-go 6.0 | +- | +- | +- | +- | ✓ | +- | +- | +| client-go 7.0 | +- | +- | +- | +- | +- | ✓ | +- | +| client-go 8.0 | +- | +- | +- | +- | +- | +- | ✓ | +| client-go HEAD | +- | +- | +- | +- | +- | +- | +- | + +Key: + +* `✓` Exactly the same features / API objects in both client-go and the Kubernetes + version. +* `+` client-go has features or API objects that may not be present in the + Kubernetes cluster, either due to that client-go has additional new API, or + that the server has removed old API. However, everything they have in + common (i.e., most APIs) will work. Please note that alpha APIs may vanish or + change significantly in a single release. +* `-` The Kubernetes cluster has features the client-go library can't use, + either due to the server has additional new API, or that client-go has + removed old API. However, everything they share in common (i.e., most APIs) + will work. + +See the [CHANGELOG](./CHANGELOG.md) for a detailed description of changes +between client-go versions. + +| Branch | Canonical source code location | Maintenance status | +|----------------|--------------------------------------|-------------------------------| +| client-go 1.4 | Kubernetes main repo, 1.4 branch | = - | +| client-go 1.5 | Kubernetes main repo, 1.5 branch | = - | +| client-go 2.0 | Kubernetes main repo, 1.5 branch | = - | +| client-go 3.0 | Kubernetes main repo, 1.6 branch | = - | +| client-go 4.0 | Kubernetes main repo, 1.7 branch | = - | +| client-go 5.0 | Kubernetes main repo, 1.8 branch | = - | +| client-go 6.0 | Kubernetes main repo, 1.9 branch | ✓ | +| client-go 7.0 | Kubernetes main repo, 1.10 branch | ✓ | +| client-go 8.0 | Kubernetes main repo, 1.11 branch | ✓ | +| client-go HEAD | Kubernetes main repo, master branch | ✓ | + +Key: + +* `✓` Changes in main Kubernetes repo are actively published to client-go by a bot +* `=` Maintenance is manual, only severe security bugs will be patched. +* `-` Deprecated; please upgrade. + +#### Deprecation policy + +We will maintain branches for at least six months after their first stable tag +is cut. (E.g., the clock for the release-2.0 branch started ticking when we +tagged v2.0.0, not when we made the first alpha.) This policy applies to +every version greater than or equal to 2.0. + +#### Why do the 1.4 and 1.5 branch contain top-level folder named after the version? + +For the initial release of client-go, we thought it would be easiest to keep +separate directories for each minor version. That soon proved to be a mistake. +We are keeping the top-level folders in the 1.4 and 1.5 branches so that +existing users won't be broken. + +### Kubernetes tags + +This repository is still a mirror of +[k8s.io/kubernetes/staging/src/client-go](https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/client-go), +the code development is still done in the staging area. Since Kubernetes 1.8 +release, when syncing the code from the staging area, we also sync the Kubernetes +version tags to client-go, prefixed with "kubernetes-". For example, if you check +out the `kubernetes-v1.8.0` tag in client-go, the code you get is exactly the +same as if you check out the `v1.8.0` tag in kubernetes, and change directory to +`staging/src/k8s.io/client-go`. The purpose is to let users quickly find matching +commits among published repos, like +[sample-apiserver](https://github.com/kubernetes/sample-apiserver), +[apiextension-apiserver](https://github.com/kubernetes/apiextensions-apiserver), +etc. The Kubernetes version tag does NOT claim any backwards compatibility +guarantees for client-go. Please check the [semantic versions](#versioning) if +you care about backwards compatibility. + +### How to get it + +You can use `go get k8s.io/client-go/...` to get client-go, but **you will get +the unstable master branch** and `client-go`'s vendored dependencies will not be +added to your `$GOPATH`. So we think most users will want to use a dependency +management system. See [INSTALL.md](/INSTALL.md) for detailed instructions. + +### How to use it + +If your application runs in a Pod in the cluster, please refer to the +in-cluster [example](examples/in-cluster-client-configuration), otherwise please +refer to the out-of-cluster [example](examples/out-of-cluster-client-configuration). + +### Dependency management + +If your application depends on a package that client-go depends on, and you let the Go compiler find the dependency in `GOPATH`, you will end up with duplicated dependencies: one copy from the `GOPATH`, and one from the vendor folder of client-go. This will cause unexpected runtime error like flag redefinition, since the go compiler ends up importing both packages separately, even if they are exactly the same thing. If this happens, you can either +* run `godep restore` ([godep](https://github.com/tools/godep)) in the client-go/ folder, then remove the vendor folder of client-go. Then the packages in your GOPATH will be the only copy +* or run `godep save` in your application folder to flatten all dependencies. + +### Contributing code +Please send pull requests against the client packages in the Kubernetes main [repository](https://github.com/kubernetes/kubernetes). Changes in the staging area will be published to this repository every day. diff --git a/vendor/k8s.io/client-go/SECURITY_CONTACTS b/vendor/k8s.io/client-go/SECURITY_CONTACTS new file mode 100644 index 000000000..0648a8ebf --- /dev/null +++ b/vendor/k8s.io/client-go/SECURITY_CONTACTS @@ -0,0 +1,17 @@ +# 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/ + +cjcullen +jessfraz +liggitt +philips +tallclair diff --git a/vendor/k8s.io/client-go/code-of-conduct.md b/vendor/k8s.io/client-go/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/client-go/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/k8s.io/client-go/discovery/cached_discovery_test.go b/vendor/k8s.io/client-go/discovery/cached_discovery_test.go new file mode 100644 index 000000000..278931c2d --- /dev/null +++ b/vendor/k8s.io/client-go/discovery/cached_discovery_test.go @@ -0,0 +1,169 @@ +/* +Copyright 2016 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 discovery + +import ( + "io/ioutil" + "os" + "testing" + "time" + + "github.com/googleapis/gnostic/OpenAPIv2" + "github.com/stretchr/testify/assert" + + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/version" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/rest/fake" +) + +func TestCachedDiscoveryClient_Fresh(t *testing.T) { + assert := assert.New(t) + + d, err := ioutil.TempDir("", "") + assert.NoError(err) + defer os.RemoveAll(d) + + c := fakeDiscoveryClient{} + cdc := newCachedDiscoveryClient(&c, d, 60*time.Second) + assert.True(cdc.Fresh(), "should be fresh after creation") + + cdc.ServerGroups() + assert.True(cdc.Fresh(), "should be fresh after groups call without cache") + assert.Equal(c.groupCalls, 1) + + cdc.ServerGroups() + assert.True(cdc.Fresh(), "should be fresh after another groups call") + assert.Equal(c.groupCalls, 1) + + cdc.ServerResources() + assert.True(cdc.Fresh(), "should be fresh after resources call") + assert.Equal(c.resourceCalls, 1) + + cdc.ServerResources() + assert.True(cdc.Fresh(), "should be fresh after another resources call") + assert.Equal(c.resourceCalls, 1) + + cdc = newCachedDiscoveryClient(&c, d, 60*time.Second) + cdc.ServerGroups() + assert.False(cdc.Fresh(), "should NOT be fresh after recreation with existing groups cache") + assert.Equal(c.groupCalls, 1) + + cdc.ServerResources() + assert.False(cdc.Fresh(), "should NOT be fresh after recreation with existing resources cache") + assert.Equal(c.resourceCalls, 1) + + cdc.Invalidate() + assert.True(cdc.Fresh(), "should be fresh after cache invalidation") + + cdc.ServerResources() + assert.True(cdc.Fresh(), "should ignore existing resources cache after invalidation") + assert.Equal(c.resourceCalls, 2) +} + +func TestNewCachedDiscoveryClient_TTL(t *testing.T) { + assert := assert.New(t) + + d, err := ioutil.TempDir("", "") + assert.NoError(err) + defer os.RemoveAll(d) + + c := fakeDiscoveryClient{} + cdc := newCachedDiscoveryClient(&c, d, 1*time.Nanosecond) + cdc.ServerGroups() + assert.Equal(c.groupCalls, 1) + + time.Sleep(1 * time.Second) + + cdc.ServerGroups() + assert.Equal(c.groupCalls, 2) +} + +type fakeDiscoveryClient struct { + groupCalls int + resourceCalls int + versionCalls int + openAPICalls int + + serverResourcesHandler func() ([]*metav1.APIResourceList, error) +} + +var _ DiscoveryInterface = &fakeDiscoveryClient{} + +func (c *fakeDiscoveryClient) RESTClient() restclient.Interface { + return &fake.RESTClient{} +} + +func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) { + c.groupCalls = c.groupCalls + 1 + return &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Name: "a", + Versions: []metav1.GroupVersionForDiscovery{ + { + GroupVersion: "a/v1", + Version: "v1", + }, + }, + PreferredVersion: metav1.GroupVersionForDiscovery{ + GroupVersion: "a/v1", + Version: "v1", + }, + }, + }, + }, nil +} + +func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) { + c.resourceCalls = c.resourceCalls + 1 + if groupVersion == "a/v1" { + return &metav1.APIResourceList{APIResources: []metav1.APIResource{{Name: "widgets", Kind: "Widget"}}}, nil + } + + return nil, errors.NewNotFound(schema.GroupResource{}, "") +} + +func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) { + c.resourceCalls = c.resourceCalls + 1 + if c.serverResourcesHandler != nil { + return c.serverResourcesHandler() + } + return []*metav1.APIResourceList{}, nil +} + +func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) { + c.resourceCalls = c.resourceCalls + 1 + return nil, nil +} + +func (c *fakeDiscoveryClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) { + c.resourceCalls = c.resourceCalls + 1 + return nil, nil +} + +func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) { + c.versionCalls = c.versionCalls + 1 + return &version.Info{}, nil +} + +func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { + c.openAPICalls = c.openAPICalls + 1 + return &openapi_v2.Document{}, nil +} diff --git a/vendor/k8s.io/client-go/discovery/discovery_client_test.go b/vendor/k8s.io/client-go/discovery/discovery_client_test.go new file mode 100644 index 000000000..10e494322 --- /dev/null +++ b/vendor/k8s.io/client-go/discovery/discovery_client_test.go @@ -0,0 +1,882 @@ +/* +Copyright 2014 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 discovery + +import ( + "encoding/json" + "fmt" + "mime" + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/gogo/protobuf/proto" + "github.com/googleapis/gnostic/OpenAPIv2" + "github.com/stretchr/testify/assert" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/version" + restclient "k8s.io/client-go/rest" +) + +func TestGetServerVersion(t *testing.T) { + expect := version.Info{ + Major: "foo", + Minor: "bar", + GitCommit: "baz", + } + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + output, err := json.Marshal(expect) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + })) + defer server.Close() + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + + got, err := client.ServerVersion() + if err != nil { + t.Fatalf("unexpected encoding error: %v", err) + } + if e, a := expect, *got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestGetServerGroupsWithV1Server(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + var obj interface{} + switch req.URL.Path { + case "/api": + obj = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + case "/apis": + obj = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Name: "extensions", + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "extensions/v1beta1"}, + }, + }, + }, + } + default: + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(obj) + if err != nil { + t.Fatalf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + })) + defer server.Close() + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + // ServerGroups should not return an error even if server returns error at /api and /apis + apiGroupList, err := client.ServerGroups() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + groupVersions := metav1.ExtractGroupVersions(apiGroupList) + if !reflect.DeepEqual(groupVersions, []string{"v1", "extensions/v1beta1"}) { + t.Errorf("expected: %q, got: %q", []string{"v1", "extensions/v1beta1"}, groupVersions) + } +} + +func TestGetServerGroupsWithBrokenServer(t *testing.T) { + for _, statusCode := range []int{http.StatusNotFound, http.StatusForbidden} { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(statusCode) + })) + defer server.Close() + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + // ServerGroups should not return an error even if server returns Not Found or Forbidden error at all end points + apiGroupList, err := client.ServerGroups() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + groupVersions := metav1.ExtractGroupVersions(apiGroupList) + if len(groupVersions) != 0 { + t.Errorf("expected empty list, got: %q", groupVersions) + } + } +} + +func TestTimeoutIsSet(t *testing.T) { + cfg := &restclient.Config{} + setDiscoveryDefaults(cfg) + assert.Equal(t, defaultTimeout, cfg.Timeout) +} + +func TestGetServerResourcesWithV1Server(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + var obj interface{} + switch req.URL.Path { + case "/api": + obj = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + default: + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(obj) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + })) + defer server.Close() + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + // ServerResources should not return an error even if server returns error at /api/v1. + serverResources, err := client.ServerResources() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + gvs := groupVersions(serverResources) + if !sets.NewString(gvs...).Has("v1") { + t.Errorf("missing v1 in resource list: %v", serverResources) + } +} + +func TestGetServerResources(t *testing.T) { + stable := metav1.APIResourceList{ + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod"}, + {Name: "services", Namespaced: true, Kind: "Service"}, + {Name: "namespaces", Namespaced: false, Kind: "Namespace"}, + }, + } + beta := metav1.APIResourceList{ + GroupVersion: "extensions/v1beta1", + APIResources: []metav1.APIResource{ + {Name: "deployments", Namespaced: true, Kind: "Deployment"}, + {Name: "ingresses", Namespaced: true, Kind: "Ingress"}, + {Name: "jobs", Namespaced: true, Kind: "Job"}, + }, + } + beta2 := metav1.APIResourceList{ + GroupVersion: "extensions/v1beta2", + APIResources: []metav1.APIResource{ + {Name: "deployments", Namespaced: true, Kind: "Deployment"}, + {Name: "ingresses", Namespaced: true, Kind: "Ingress"}, + {Name: "jobs", Namespaced: true, Kind: "Job"}, + }, + } + tests := []struct { + resourcesList *metav1.APIResourceList + path string + request string + expectErr bool + }{ + { + resourcesList: &stable, + path: "/api/v1", + request: "v1", + expectErr: false, + }, + { + resourcesList: &beta, + path: "/apis/extensions/v1beta1", + request: "extensions/v1beta1", + expectErr: false, + }, + { + resourcesList: &stable, + path: "/api/v1", + request: "foobar", + expectErr: true, + }, + } + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/api/v1": + list = &stable + case "/apis/extensions/v1beta1": + list = &beta + case "/apis/extensions/v1beta2": + list = &beta2 + case "/api": + list = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + case "/apis": + list = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Name: "extensions", + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "extensions/v1beta1", Version: "v1beta1"}, + {GroupVersion: "extensions/v1beta2", Version: "v1beta2"}, + }, + }, + }, + } + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + })) + defer server.Close() + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + for _, test := range tests { + got, err := client.ServerResourcesForGroupVersion(test.request) + if test.expectErr { + if err == nil { + t.Error("unexpected non-error") + } + continue + } + if err != nil { + t.Errorf("unexpected error: %v", err) + continue + } + if !reflect.DeepEqual(got, test.resourcesList) { + t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got) + } + } + + serverResources, err := client.ServerResources() + if err != nil { + t.Errorf("unexpected error: %v", err) + } + serverGroupVersions := groupVersions(serverResources) + expectedGroupVersions := []string{"v1", "extensions/v1beta1", "extensions/v1beta2"} + if !reflect.DeepEqual(expectedGroupVersions, serverGroupVersions) { + t.Errorf("unexpected group versions: %v", diff.ObjectReflectDiff(expectedGroupVersions, serverGroupVersions)) + } +} + +var returnedOpenAPI = openapi_v2.Document{ + Definitions: &openapi_v2.Definitions{ + AdditionalProperties: []*openapi_v2.NamedSchema{ + { + Name: "fake.type.1", + Value: &openapi_v2.Schema{ + Properties: &openapi_v2.Properties{ + AdditionalProperties: []*openapi_v2.NamedSchema{ + { + Name: "count", + Value: &openapi_v2.Schema{ + Type: &openapi_v2.TypeItem{ + Value: []string{"integer"}, + }, + }, + }, + }, + }, + }, + }, + { + Name: "fake.type.2", + Value: &openapi_v2.Schema{ + Properties: &openapi_v2.Properties{ + AdditionalProperties: []*openapi_v2.NamedSchema{ + { + Name: "count", + Value: &openapi_v2.Schema{ + Type: &openapi_v2.TypeItem{ + Value: []string{"array"}, + }, + Items: &openapi_v2.ItemsItem{ + Schema: []*openapi_v2.Schema{ + { + Type: &openapi_v2.TypeItem{ + Value: []string{"string"}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, +} + +func openapiSchemaDeprecatedFakeServer(status int) (*httptest.Server, error) { + var sErr error + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if req.URL.Path == "/openapi/v2" { + // write the error status for the new endpoint request + w.WriteHeader(status) + return + } + if req.URL.Path != "/swagger-2.0.0.pb-v1" { + sErr = fmt.Errorf("Unexpected url %v", req.URL) + } + if req.Method != "GET" { + sErr = fmt.Errorf("Unexpected method %v", req.Method) + } + + mime.AddExtensionType(".pb-v1", "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf") + + output, err := proto.Marshal(&returnedOpenAPI) + if err != nil { + sErr = err + return + } + w.WriteHeader(http.StatusOK) + w.Write(output) + })) + return server, sErr +} + +func openapiSchemaFakeServer() (*httptest.Server, error) { + var sErr error + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if req.URL.Path != "/openapi/v2" { + sErr = fmt.Errorf("Unexpected url %v", req.URL) + } + if req.Method != "GET" { + sErr = fmt.Errorf("Unexpected method %v", req.Method) + } + decipherableFormat := req.Header.Get("Accept") + if decipherableFormat != "application/com.github.proto-openapi.spec.v2@v1.0+protobuf" { + sErr = fmt.Errorf("Unexpected accept mime type %v", decipherableFormat) + } + + mime.AddExtensionType(".pb-v1", "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf") + + output, err := proto.Marshal(&returnedOpenAPI) + if err != nil { + sErr = err + return + } + w.WriteHeader(http.StatusOK) + w.Write(output) + })) + return server, sErr +} + +func TestGetOpenAPISchema(t *testing.T) { + server, err := openapiSchemaFakeServer() + if err != nil { + t.Errorf("unexpected error starting fake server: %v", err) + } + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + got, err := client.OpenAPISchema() + if err != nil { + t.Fatalf("unexpected error getting openapi: %v", err) + } + if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestGetOpenAPISchemaForbiddenFallback(t *testing.T) { + server, err := openapiSchemaDeprecatedFakeServer(http.StatusForbidden) + if err != nil { + t.Errorf("unexpected error starting fake server: %v", err) + } + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + got, err := client.OpenAPISchema() + if err != nil { + t.Fatalf("unexpected error getting openapi: %v", err) + } + if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestGetOpenAPISchemaNotFoundFallback(t *testing.T) { + server, err := openapiSchemaDeprecatedFakeServer(http.StatusNotFound) + if err != nil { + t.Errorf("unexpected error starting fake server: %v", err) + } + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + got, err := client.OpenAPISchema() + if err != nil { + t.Fatalf("unexpected error getting openapi: %v", err) + } + if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestGetOpenAPISchemaNotAcceptableFallback(t *testing.T) { + server, err := openapiSchemaDeprecatedFakeServer(http.StatusNotAcceptable) + if err != nil { + t.Errorf("unexpected error starting fake server: %v", err) + } + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + got, err := client.OpenAPISchema() + if err != nil { + t.Fatalf("unexpected error getting openapi: %v", err) + } + if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestServerPreferredResources(t *testing.T) { + stable := metav1.APIResourceList{ + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod"}, + {Name: "services", Namespaced: true, Kind: "Service"}, + {Name: "namespaces", Namespaced: false, Kind: "Namespace"}, + }, + } + tests := []struct { + resourcesList []*metav1.APIResourceList + response func(w http.ResponseWriter, req *http.Request) + expectErr func(err error) bool + }{ + { + resourcesList: []*metav1.APIResourceList{&stable}, + expectErr: IsGroupDiscoveryFailedError, + response: func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/apis/extensions/v1beta1": + w.WriteHeader(http.StatusInternalServerError) + return + case "/api/v1": + list = &stable + case "/api": + list = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + case "/apis": + list = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "extensions/v1beta1"}, + }, + }, + }, + } + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + }, + }, + { + resourcesList: nil, + expectErr: IsGroupDiscoveryFailedError, + response: func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/apis/extensions/v1beta1": + w.WriteHeader(http.StatusInternalServerError) + return + case "/api/v1": + w.WriteHeader(http.StatusInternalServerError) + case "/api": + list = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + case "/apis": + list = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "extensions/v1beta1"}, + }, + }, + }, + } + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + }, + }, + } + for _, test := range tests { + server := httptest.NewServer(http.HandlerFunc(test.response)) + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + resources, err := client.ServerPreferredResources() + if test.expectErr != nil { + if err == nil { + t.Error("unexpected non-error") + } + + continue + } + if err != nil { + t.Errorf("unexpected error: %v", err) + continue + } + got, err := GroupVersionResources(resources) + if err != nil { + t.Errorf("unexpected error: %v", err) + continue + } + expected, _ := GroupVersionResources(test.resourcesList) + if !reflect.DeepEqual(got, expected) { + t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got) + } + server.Close() + } +} + +func TestServerPreferredResourcesRetries(t *testing.T) { + stable := metav1.APIResourceList{ + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod"}, + }, + } + beta := metav1.APIResourceList{ + GroupVersion: "extensions/v1", + APIResources: []metav1.APIResource{ + {Name: "deployments", Namespaced: true, Kind: "Deployment"}, + }, + } + + response := func(numErrors int) http.HandlerFunc { + var i = 0 + return func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/apis/extensions/v1beta1": + if i < numErrors { + i++ + w.WriteHeader(http.StatusInternalServerError) + return + } + list = &beta + case "/api/v1": + list = &stable + case "/api": + list = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + case "/apis": + list = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Name: "extensions", + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "extensions/v1beta1", Version: "v1beta1"}, + }, + PreferredVersion: metav1.GroupVersionForDiscovery{ + GroupVersion: "extensions/v1beta1", + Version: "v1beta1", + }, + }, + }, + } + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + } + } + tests := []struct { + responseErrors int + expectResources int + expectedError func(err error) bool + }{ + { + responseErrors: 1, + expectResources: 2, + expectedError: func(err error) bool { + return err == nil + }, + }, + { + responseErrors: 2, + expectResources: 1, + expectedError: IsGroupDiscoveryFailedError, + }, + } + + for i, tc := range tests { + server := httptest.NewServer(http.HandlerFunc(response(tc.responseErrors))) + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + resources, err := client.ServerPreferredResources() + if !tc.expectedError(err) { + t.Errorf("case %d: unexpected error: %v", i, err) + } + got, err := GroupVersionResources(resources) + if err != nil { + t.Errorf("case %d: unexpected error: %v", i, err) + } + if len(got) != tc.expectResources { + t.Errorf("case %d: expect %d resources, got %#v", i, tc.expectResources, got) + } + server.Close() + } +} + +func TestServerPreferredNamespacedResources(t *testing.T) { + stable := metav1.APIResourceList{ + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + {Name: "pods", Namespaced: true, Kind: "Pod"}, + {Name: "services", Namespaced: true, Kind: "Service"}, + {Name: "namespaces", Namespaced: false, Kind: "Namespace"}, + }, + } + batchv1 := metav1.APIResourceList{ + GroupVersion: "batch/v1", + APIResources: []metav1.APIResource{ + {Name: "jobs", Namespaced: true, Kind: "Job"}, + }, + } + batchv2alpha1 := metav1.APIResourceList{ + GroupVersion: "batch/v2alpha1", + APIResources: []metav1.APIResource{ + {Name: "jobs", Namespaced: true, Kind: "Job"}, + {Name: "cronjobs", Namespaced: true, Kind: "CronJob"}, + }, + } + batchv3alpha1 := metav1.APIResourceList{ + GroupVersion: "batch/v3alpha1", + APIResources: []metav1.APIResource{ + {Name: "jobs", Namespaced: true, Kind: "Job"}, + {Name: "cronjobs", Namespaced: true, Kind: "CronJob"}, + }, + } + tests := []struct { + response func(w http.ResponseWriter, req *http.Request) + expected map[schema.GroupVersionResource]struct{} + }{ + { + response: func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/api/v1": + list = &stable + case "/api": + list = &metav1.APIVersions{ + Versions: []string{ + "v1", + }, + } + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + }, + expected: map[schema.GroupVersionResource]struct{}{ + {Group: "", Version: "v1", Resource: "pods"}: {}, + {Group: "", Version: "v1", Resource: "services"}: {}, + }, + }, + { + response: func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/apis": + list = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Name: "batch", + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "batch/v1", Version: "v1"}, + {GroupVersion: "batch/v2alpha1", Version: "v2alpha1"}, + {GroupVersion: "batch/v3alpha1", Version: "v3alpha1"}, + }, + PreferredVersion: metav1.GroupVersionForDiscovery{GroupVersion: "batch/v1", Version: "v1"}, + }, + }, + } + case "/apis/batch/v1": + list = &batchv1 + case "/apis/batch/v2alpha1": + list = &batchv2alpha1 + case "/apis/batch/v3alpha1": + list = &batchv3alpha1 + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + }, + expected: map[schema.GroupVersionResource]struct{}{ + {Group: "batch", Version: "v1", Resource: "jobs"}: {}, + {Group: "batch", Version: "v2alpha1", Resource: "cronjobs"}: {}, + }, + }, + { + response: func(w http.ResponseWriter, req *http.Request) { + var list interface{} + switch req.URL.Path { + case "/apis": + list = &metav1.APIGroupList{ + Groups: []metav1.APIGroup{ + { + Name: "batch", + Versions: []metav1.GroupVersionForDiscovery{ + {GroupVersion: "batch/v1", Version: "v1"}, + {GroupVersion: "batch/v2alpha1", Version: "v2alpha1"}, + {GroupVersion: "batch/v3alpha1", Version: "v3alpha1"}, + }, + PreferredVersion: metav1.GroupVersionForDiscovery{GroupVersion: "batch/v2alpha", Version: "v2alpha1"}, + }, + }, + } + case "/apis/batch/v1": + list = &batchv1 + case "/apis/batch/v2alpha1": + list = &batchv2alpha1 + case "/apis/batch/v3alpha1": + list = &batchv3alpha1 + default: + t.Logf("unexpected request: %s", req.URL.Path) + w.WriteHeader(http.StatusNotFound) + return + } + output, err := json.Marshal(list) + if err != nil { + t.Errorf("unexpected encoding error: %v", err) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(output) + }, + expected: map[schema.GroupVersionResource]struct{}{ + {Group: "batch", Version: "v2alpha1", Resource: "jobs"}: {}, + {Group: "batch", Version: "v2alpha1", Resource: "cronjobs"}: {}, + }, + }, + } + for i, test := range tests { + server := httptest.NewServer(http.HandlerFunc(test.response)) + defer server.Close() + + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + resources, err := client.ServerPreferredNamespacedResources() + if err != nil { + t.Errorf("[%d] unexpected error: %v", i, err) + continue + } + got, err := GroupVersionResources(resources) + if err != nil { + t.Errorf("[%d] unexpected error: %v", i, err) + continue + } + + if !reflect.DeepEqual(got, test.expected) { + t.Errorf("[%d] expected:\n%v\ngot:\n%v\n", i, test.expected, got) + } + server.Close() + } +} + +func groupVersions(resources []*metav1.APIResourceList) []string { + result := []string{} + for _, resourceList := range resources { + result = append(result, resourceList.GroupVersion) + } + return result +} diff --git a/vendor/k8s.io/client-go/discovery/fake/discovery_test.go b/vendor/k8s.io/client-go/discovery/fake/discovery_test.go new file mode 100644 index 000000000..cfdcf1a23 --- /dev/null +++ b/vendor/k8s.io/client-go/discovery/fake/discovery_test.go @@ -0,0 +1,46 @@ +/* +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 fake_test + +import ( + "testing" + + "k8s.io/apimachinery/pkg/version" + fakediscovery "k8s.io/client-go/discovery/fake" + fakeclientset "k8s.io/client-go/kubernetes/fake" +) + +func TestFakingServerVersion(t *testing.T) { + client := fakeclientset.NewSimpleClientset() + fakeDiscovery, ok := client.Discovery().(*fakediscovery.FakeDiscovery) + if !ok { + t.Fatalf("couldn't convert Discovery() to *FakeDiscovery") + } + + testGitCommit := "v1.0.0" + fakeDiscovery.FakedServerVersion = &version.Info{ + GitCommit: testGitCommit, + } + + sv, err := client.Discovery().ServerVersion() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if sv.GitCommit != testGitCommit { + t.Fatalf("unexpected faked discovery return value: %q", sv.GitCommit) + } +} diff --git a/vendor/k8s.io/client-go/discovery/helper_blackbox_test.go b/vendor/k8s.io/client-go/discovery/helper_blackbox_test.go new file mode 100644 index 000000000..9cd85cb16 --- /dev/null +++ b/vendor/k8s.io/client-go/discovery/helper_blackbox_test.go @@ -0,0 +1,184 @@ +/* +Copyright 2015 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 discovery_test + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "io/ioutil" + "net/http" + "strings" + "testing" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/discovery" + "k8s.io/client-go/kubernetes/scheme" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/rest/fake" +) + +func objBody(object interface{}) io.ReadCloser { + output, err := json.MarshalIndent(object, "", "") + if err != nil { + panic(err) + } + return ioutil.NopCloser(bytes.NewReader([]byte(output))) +} + +func TestServerSupportsVersion(t *testing.T) { + tests := []struct { + name string + requiredVersion schema.GroupVersion + serverVersions []string + expectErr func(err error) bool + sendErr error + statusCode int + }{ + { + name: "explicit version supported", + requiredVersion: schema.GroupVersion{Version: "v1"}, + serverVersions: []string{"/version1", v1.SchemeGroupVersion.String()}, + statusCode: http.StatusOK, + }, + { + name: "explicit version not supported on server", + requiredVersion: schema.GroupVersion{Version: "v1"}, + serverVersions: []string{"version1"}, + expectErr: func(err error) bool { return strings.Contains(err.Error(), `server does not support API version "v1"`) }, + statusCode: http.StatusOK, + }, + { + name: "connection refused error", + serverVersions: []string{"version1"}, + sendErr: errors.New("connection refused"), + expectErr: func(err error) bool { return strings.Contains(err.Error(), "connection refused") }, + statusCode: http.StatusOK, + }, + { + name: "discovery fails due to 404 Not Found errors and thus serverVersions is empty, use requested GroupVersion", + requiredVersion: schema.GroupVersion{Version: "version1"}, + statusCode: http.StatusNotFound, + }, + } + + for _, test := range tests { + fakeClient := &fake.RESTClient{ + NegotiatedSerializer: scheme.Codecs, + Resp: &http.Response{ + StatusCode: test.statusCode, + Body: objBody(&metav1.APIVersions{Versions: test.serverVersions}), + }, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + if test.sendErr != nil { + return nil, test.sendErr + } + header := http.Header{} + header.Set("Content-Type", runtime.ContentTypeJSON) + return &http.Response{StatusCode: test.statusCode, Header: header, Body: objBody(&metav1.APIVersions{Versions: test.serverVersions})}, nil + }), + } + c := discovery.NewDiscoveryClientForConfigOrDie(&restclient.Config{}) + c.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client + err := discovery.ServerSupportsVersion(c, test.requiredVersion) + if err == nil && test.expectErr != nil { + t.Errorf("expected error, got nil for [%s].", test.name) + } + if err != nil { + if test.expectErr == nil || !test.expectErr(err) { + t.Errorf("unexpected error for [%s]: %v.", test.name, err) + } + continue + } + } +} + +func TestFilteredBy(t *testing.T) { + all := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool { + return true + }) + none := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool { + return false + }) + onlyV2 := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool { + return strings.HasSuffix(gv, "/v2") || gv == "v2" + }) + onlyBar := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool { + return r.Kind == "Bar" + }) + + foo := []*metav1.APIResourceList{ + { + GroupVersion: "foo/v1", + APIResources: []metav1.APIResource{ + {Name: "bar", Kind: "Bar"}, + {Name: "test", Kind: "Test"}, + }, + }, + { + GroupVersion: "foo/v2", + APIResources: []metav1.APIResource{ + {Name: "bar", Kind: "Bar"}, + {Name: "test", Kind: "Test"}, + }, + }, + { + GroupVersion: "foo/v3", + APIResources: []metav1.APIResource{}, + }, + } + + tests := []struct { + input []*metav1.APIResourceList + pred discovery.ResourcePredicate + expectedResources []string + }{ + {nil, all, []string{}}, + {[]*metav1.APIResourceList{ + {GroupVersion: "foo/v1"}, + }, all, []string{}}, + {foo, all, []string{"foo/v1.bar", "foo/v1.test", "foo/v2.bar", "foo/v2.test"}}, + {foo, onlyV2, []string{"foo/v2.bar", "foo/v2.test"}}, + {foo, onlyBar, []string{"foo/v1.bar", "foo/v2.bar"}}, + {foo, none, []string{}}, + } + for i, test := range tests { + filtered := discovery.FilteredBy(test.pred, test.input) + + if expected, got := sets.NewString(test.expectedResources...), sets.NewString(stringify(filtered)...); !expected.Equal(got) { + t.Errorf("[%d] unexpected group versions: expected=%v, got=%v", i, test.expectedResources, stringify(filtered)) + } + } +} + +func stringify(rls []*metav1.APIResourceList) []string { + result := []string{} + for _, rl := range rls { + for _, r := range rl.APIResources { + result = append(result, rl.GroupVersion+"."+r.Name) + } + if len(rl.APIResources) == 0 { + result = append(result, rl.GroupVersion) + } + } + return result +} diff --git a/vendor/k8s.io/client-go/discovery/round_tripper_test.go b/vendor/k8s.io/client-go/discovery/round_tripper_test.go new file mode 100644 index 000000000..b15e2e771 --- /dev/null +++ b/vendor/k8s.io/client-go/discovery/round_tripper_test.go @@ -0,0 +1,95 @@ +/* +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 discovery + +import ( + "bytes" + "io/ioutil" + "net/http" + "net/url" + "os" + "testing" +) + +// copied from k8s.io/client-go/transport/round_trippers_test.go +type testRoundTripper struct { + Request *http.Request + Response *http.Response + Err error +} + +func (rt *testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + rt.Request = req + return rt.Response, rt.Err +} + +func TestCacheRoundTripper(t *testing.T) { + rt := &testRoundTripper{} + cacheDir, err := ioutil.TempDir("", "cache-rt") + defer os.RemoveAll(cacheDir) + if err != nil { + t.Fatal(err) + } + cache := newCacheRoundTripper(cacheDir, rt) + + // First call, caches the response + req := &http.Request{ + Method: http.MethodGet, + URL: &url.URL{Host: "localhost"}, + } + rt.Response = &http.Response{ + Header: http.Header{"ETag": []string{`"123456"`}}, + Body: ioutil.NopCloser(bytes.NewReader([]byte("Content"))), + StatusCode: http.StatusOK, + } + resp, err := cache.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(content) != "Content" { + t.Errorf(`Expected Body to be "Content", got %q`, string(content)) + } + + // Second call, returns cached response + req = &http.Request{ + Method: http.MethodGet, + URL: &url.URL{Host: "localhost"}, + } + rt.Response = &http.Response{ + StatusCode: http.StatusNotModified, + Body: ioutil.NopCloser(bytes.NewReader([]byte("Other Content"))), + } + + resp, err = cache.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + + // Read body and make sure we have the initial content + content, err = ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + t.Fatal(err) + } + if string(content) != "Content" { + t.Errorf("Invalid content read from cache %q", string(content)) + } +} diff --git a/vendor/k8s.io/client-go/listers/extensions/v1beta1/daemonset_expansion_test.go b/vendor/k8s.io/client-go/listers/extensions/v1beta1/daemonset_expansion_test.go new file mode 100644 index 000000000..77180854e --- /dev/null +++ b/vendor/k8s.io/client-go/listers/extensions/v1beta1/daemonset_expansion_test.go @@ -0,0 +1,152 @@ +/* +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 v1beta1 + +import ( + "testing" + + "k8s.io/api/core/v1" + extensions "k8s.io/api/extensions/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/cache" +) + +func TestDaemonSetLister(t *testing.T) { + store := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc}) + lister := NewDaemonSetLister(store) + testCases := []struct { + inDSs []*extensions.DaemonSet + list func() ([]*extensions.DaemonSet, error) + outDaemonSetNames sets.String + expectErr bool + }{ + // Basic listing + { + inDSs: []*extensions.DaemonSet{ + {ObjectMeta: metav1.ObjectMeta{Name: "basic"}}, + }, + list: func() ([]*extensions.DaemonSet, error) { + return lister.List(labels.Everything()) + }, + outDaemonSetNames: sets.NewString("basic"), + }, + // Listing multiple daemon sets + { + inDSs: []*extensions.DaemonSet{ + {ObjectMeta: metav1.ObjectMeta{Name: "basic"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "complex"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "complex2"}}, + }, + list: func() ([]*extensions.DaemonSet, error) { + return lister.List(labels.Everything()) + }, + outDaemonSetNames: sets.NewString("basic", "complex", "complex2"), + }, + // No pod labels + { + inDSs: []*extensions.DaemonSet{ + { + ObjectMeta: metav1.ObjectMeta{Name: "basic", Namespace: "ns"}, + Spec: extensions.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "baz"}}, + }, + }, + }, + list: func() ([]*extensions.DaemonSet, error) { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns"}, + } + return lister.GetPodDaemonSets(pod) + }, + outDaemonSetNames: sets.NewString(), + expectErr: true, + }, + // No DS selectors + { + inDSs: []*extensions.DaemonSet{ + { + ObjectMeta: metav1.ObjectMeta{Name: "basic", Namespace: "ns"}, + }, + }, + list: func() ([]*extensions.DaemonSet, error) { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + Namespace: "ns", + Labels: map[string]string{"foo": "bar"}, + }, + } + return lister.GetPodDaemonSets(pod) + }, + outDaemonSetNames: sets.NewString(), + expectErr: true, + }, + // Matching labels to selectors and namespace + { + inDSs: []*extensions.DaemonSet{ + { + ObjectMeta: metav1.ObjectMeta{Name: "foo"}, + Spec: extensions.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: "bar", Namespace: "ns"}, + Spec: extensions.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, + }, + }, + }, + list: func() ([]*extensions.DaemonSet, error) { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + Labels: map[string]string{"foo": "bar"}, + Namespace: "ns", + }, + } + return lister.GetPodDaemonSets(pod) + }, + outDaemonSetNames: sets.NewString("bar"), + }, + } + for _, c := range testCases { + for _, r := range c.inDSs { + store.Add(r) + } + + daemonSets, err := c.list() + if err != nil && c.expectErr { + continue + } else if c.expectErr { + t.Error("Expected error, got none") + continue + } else if err != nil { + t.Errorf("Unexpected error %#v", err) + continue + } + daemonSetNames := make([]string, len(daemonSets)) + for ix := range daemonSets { + daemonSetNames[ix] = daemonSets[ix].Name + } + if !c.outDaemonSetNames.HasAll(daemonSetNames...) || len(daemonSetNames) != len(c.outDaemonSetNames) { + t.Errorf("Unexpected got controllers %+v expected %+v", daemonSetNames, c.outDaemonSetNames) + } + } +} diff --git a/vendor/k8s.io/client-go/pkg/version/.gitattributes b/vendor/k8s.io/client-go/pkg/version/.gitattributes new file mode 100644 index 000000000..7e349eff6 --- /dev/null +++ b/vendor/k8s.io/client-go/pkg/version/.gitattributes @@ -0,0 +1 @@ +base.go export-subst diff --git a/vendor/k8s.io/client-go/pkg/version/def.bzl b/vendor/k8s.io/client-go/pkg/version/def.bzl new file mode 100644 index 000000000..9c018a4ef --- /dev/null +++ b/vendor/k8s.io/client-go/pkg/version/def.bzl @@ -0,0 +1,38 @@ +# 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. + +# Implements hack/lib/version.sh's kube::version::ldflags() for Bazel. +def version_x_defs(): + # This should match the list of packages in kube::version::ldflag + stamp_pkgs = [ + "k8s.io/kubernetes/pkg/version", + # In hack/lib/version.sh, this has a vendor/ prefix. That isn't needed here? + "k8s.io/client-go/pkg/version", + ] + # This should match the list of vars in kube::version::ldflags + # It should also match the list of vars set in hack/print-workspace-status.sh. + stamp_vars = [ + "buildDate", + "gitCommit", + "gitMajor", + "gitMinor", + "gitTreeState", + "gitVersion", + ] + # Generate the cross-product. + x_defs = {} + for pkg in stamp_pkgs: + for var in stamp_vars: + x_defs["%s.%s" % (pkg, var)] = "{%s}" % var + return x_defs diff --git a/vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go b/vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go new file mode 100644 index 000000000..e3398e821 --- /dev/null +++ b/vendor/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go @@ -0,0 +1,748 @@ +/* +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. +*/ + +package exec + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "fmt" + "io/ioutil" + "math/big" + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/pkg/apis/clientauthentication" + "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/client-go/transport" +) + +var ( + certData = []byte(`-----BEGIN CERTIFICATE----- +MIIC6jCCAdSgAwIBAgIBCzALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu +MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIyMDEzMVoXDTE2MDExNTIyMDEz +MlowGzEZMBcGA1UEAxMQb3BlbnNoaWZ0LWNsaWVudDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKtdhz0+uCLXw5cSYns9rU/XifFSpb/x24WDdrm72S/v +b9BPYsAStiP148buylr1SOuNi8sTAZmlVDDIpIVwMLff+o2rKYDicn9fjbrTxTOj +lI4pHJBH+JU3AJ0tbajupioh70jwFS0oYpwtneg2zcnE2Z4l6mhrj2okrc5Q1/X2 +I2HChtIU4JYTisObtin10QKJX01CLfYXJLa8upWzKZ4/GOcHG+eAV3jXWoXidtjb +1Usw70amoTZ6mIVCkiu1QwCoa8+ycojGfZhvqMsAp1536ZcCul+Na+AbCv4zKS7F +kQQaImVrXdUiFansIoofGlw/JNuoKK6ssVpS5Ic3pgcCAwEAAaM1MDMwDgYDVR0P +AQH/BAQDAgCgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJ +KoZIhvcNAQELA4IBAQCKLREH7bXtXtZ+8vI6cjD7W3QikiArGqbl36bAhhWsJLp/ +p/ndKz39iFNaiZ3GlwIURWOOKx3y3GA0x9m8FR+Llthf0EQ8sUjnwaknWs0Y6DQ3 +jjPFZOpV3KPCFrdMJ3++E3MgwFC/Ih/N2ebFX9EcV9Vcc6oVWMdwT0fsrhu683rq +6GSR/3iVX1G/pmOiuaR0fNUaCyCfYrnI4zHBDgSfnlm3vIvN2lrsR/DQBakNL8DJ +HBgKxMGeUPoneBv+c8DMXIL0EhaFXRlBv9QW45/GiAIOuyFJ0i6hCtGZpJjq4OpQ +BRjCI+izPzFTjsxD4aORE+WOkyWFCGPWKfNejfw0 +-----END CERTIFICATE-----`) + keyData = []byte(`-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAq12HPT64ItfDlxJiez2tT9eJ8VKlv/HbhYN2ubvZL+9v0E9i +wBK2I/Xjxu7KWvVI642LyxMBmaVUMMikhXAwt9/6jaspgOJyf1+NutPFM6OUjikc +kEf4lTcAnS1tqO6mKiHvSPAVLShinC2d6DbNycTZniXqaGuPaiStzlDX9fYjYcKG +0hTglhOKw5u2KfXRAolfTUIt9hcktry6lbMpnj8Y5wcb54BXeNdaheJ22NvVSzDv +RqahNnqYhUKSK7VDAKhrz7JyiMZ9mG+oywCnXnfplwK6X41r4BsK/jMpLsWRBBoi +ZWtd1SIVqewiih8aXD8k26gorqyxWlLkhzemBwIDAQABAoIBAD2XYRs3JrGHQUpU +FkdbVKZkvrSY0vAZOqBTLuH0zUv4UATb8487anGkWBjRDLQCgxH+jucPTrztekQK +aW94clo0S3aNtV4YhbSYIHWs1a0It0UdK6ID7CmdWkAj6s0T8W8lQT7C46mWYVLm +5mFnCTHi6aB42jZrqmEpC7sivWwuU0xqj3Ml8kkxQCGmyc9JjmCB4OrFFC8NNt6M +ObvQkUI6Z3nO4phTbpxkE1/9dT0MmPIF7GhHVzJMS+EyyRYUDllZ0wvVSOM3qZT0 +JMUaBerkNwm9foKJ1+dv2nMKZZbJajv7suUDCfU44mVeaEO+4kmTKSGCGjjTBGkr +7L1ySDECgYEA5ElIMhpdBzIivCuBIH8LlUeuzd93pqssO1G2Xg0jHtfM4tz7fyeI +cr90dc8gpli24dkSxzLeg3Tn3wIj/Bu64m2TpZPZEIlukYvgdgArmRIPQVxerYey +OkrfTNkxU1HXsYjLCdGcGXs5lmb+K/kuTcFxaMOs7jZi7La+jEONwf8CgYEAwCs/ +rUOOA0klDsWWisbivOiNPII79c9McZCNBqncCBfMUoiGe8uWDEO4TFHN60vFuVk9 +8PkwpCfvaBUX+ajvbafIfHxsnfk1M04WLGCeqQ/ym5Q4sQoQOcC1b1y9qc/xEWfg +nIUuia0ukYRpl7qQa3tNg+BNFyjypW8zukUAC/kCgYB1/Kojuxx5q5/oQVPrx73k +2bevD+B3c+DYh9MJqSCNwFtUpYIWpggPxoQan4LwdsmO0PKzocb/ilyNFj4i/vII +NToqSc/WjDFpaDIKyuu9oWfhECye45NqLWhb/6VOuu4QA/Nsj7luMhIBehnEAHW+ +GkzTKM8oD1PxpEG3nPKXYQKBgQC6AuMPRt3XBl1NkCrpSBy/uObFlFaP2Enpf39S +3OZ0Gv0XQrnSaL1kP8TMcz68rMrGX8DaWYsgytstR4W+jyy7WvZwsUu+GjTJ5aMG +77uEcEBpIi9CBzivfn7hPccE8ZgqPf+n4i6q66yxBJflW5xhvafJqDtW2LcPNbW/ +bvzdmQKBgExALRUXpq+5dbmkdXBHtvXdRDZ6rVmrnjy4nI5bPw+1GqQqk6uAR6B/ +F6NmLCQOO4PDG/cuatNHIr2FrwTmGdEL6ObLUGWn9Oer9gJhHVqqsY5I4sEPo4XX +stR0Yiw0buV6DL/moUO0HIM9Bjh96HJp+LxiIS6UCdIhMPp5HoQa +-----END RSA PRIVATE KEY-----`) + validCert *tls.Certificate +) + +func init() { + cert, err := tls.X509KeyPair(certData, keyData) + if err != nil { + panic(err) + } + validCert = &cert +} + +func TestCacheKey(t *testing.T) { + c1 := &api.ExecConfig{ + Command: "foo-bar", + Args: []string{"1", "2"}, + Env: []api.ExecEnvVar{ + {Name: "3", Value: "4"}, + {Name: "5", Value: "6"}, + {Name: "7", Value: "8"}, + }, + APIVersion: "client.authentication.k8s.io/v1alpha1", + } + c2 := &api.ExecConfig{ + Command: "foo-bar", + Args: []string{"1", "2"}, + Env: []api.ExecEnvVar{ + {Name: "3", Value: "4"}, + {Name: "5", Value: "6"}, + {Name: "7", Value: "8"}, + }, + APIVersion: "client.authentication.k8s.io/v1alpha1", + } + c3 := &api.ExecConfig{ + Command: "foo-bar", + Args: []string{"1", "2"}, + Env: []api.ExecEnvVar{ + {Name: "3", Value: "4"}, + {Name: "5", Value: "6"}, + }, + APIVersion: "client.authentication.k8s.io/v1alpha1", + } + key1 := cacheKey(c1) + key2 := cacheKey(c2) + key3 := cacheKey(c3) + if key1 != key2 { + t.Error("key1 and key2 didn't match") + } + if key1 == key3 { + t.Error("key1 and key3 matched") + } + if key2 == key3 { + t.Error("key2 and key3 matched") + } +} + +func compJSON(t *testing.T, got, want []byte) { + t.Helper() + gotJSON := &bytes.Buffer{} + wantJSON := &bytes.Buffer{} + + if err := json.Indent(gotJSON, got, "", " "); err != nil { + t.Errorf("got invalid JSON: %v", err) + } + if err := json.Indent(wantJSON, want, "", " "); err != nil { + t.Errorf("want invalid JSON: %v", err) + } + g := strings.TrimSpace(gotJSON.String()) + w := strings.TrimSpace(wantJSON.String()) + if g != w { + t.Errorf("wanted %q, got %q", w, g) + } +} + +func TestRefreshCreds(t *testing.T) { + tests := []struct { + name string + config api.ExecConfig + output string + interactive bool + response *clientauthentication.Response + wantInput string + wantCreds credentials + wantExpiry time.Time + wantErr bool + }{ + { + name: "basic-request", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "foo-bar" + } + }`, + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "interactive", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + interactive: true, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": { + "interactive": true + } + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "foo-bar" + } + }`, + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "response", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + response: &clientauthentication.Response{ + Header: map[string][]string{ + "WWW-Authenticate": {`Basic realm="Access to the staging site", charset="UTF-8"`}, + }, + Code: 401, + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": { + "response": { + "header": { + "WWW-Authenticate": [ + "Basic realm=\"Access to the staging site\", charset=\"UTF-8\"" + ] + }, + "code": 401 + } + } + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "foo-bar" + } + }`, + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "expiry", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "foo-bar", + "expirationTimestamp": "2006-01-02T15:04:05Z" + } + }`, + wantExpiry: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "no-group-version", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: `{ + "kind": "ExecCredential", + "status": { + "token": "foo-bar" + } + }`, + wantErr: true, + }, + { + name: "no-status", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1" + }`, + wantErr: true, + }, + { + name: "no-creds", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "status": {} + }`, + wantErr: true, + }, + { + name: "TLS credentials", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: fmt.Sprintf(`{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "clientKeyData": %q, + "clientCertificateData": %q + } + }`, keyData, certData), + wantCreds: credentials{cert: validCert}, + }, + { + name: "bad TLS credentials", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "clientKeyData": "foo", + "clientCertificateData": "bar" + } + }`, + wantErr: true, + }, + { + name: "cert but no key", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1alpha1", + }, + wantInput: `{ + "kind":"ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1alpha1", + "spec": {} + }`, + output: fmt.Sprintf(`{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "clientCertificateData": %q + } + }`, certData), + wantErr: true, + }, + { + name: "beta-basic-request", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1beta1", + "status": { + "token": "foo-bar" + } + }`, + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "beta-expiry", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1beta1", + "status": { + "token": "foo-bar", + "expirationTimestamp": "2006-01-02T15:04:05Z" + } + }`, + wantExpiry: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "beta-no-group-version", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + output: `{ + "kind": "ExecCredential", + "status": { + "token": "foo-bar" + } + }`, + wantErr: true, + }, + { + name: "beta-no-status", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + output: `{ + "kind": "ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1beta1" + }`, + wantErr: true, + }, + { + name: "beta-no-token", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + }, + output: `{ + "kind": "ExecCredential", + "apiVersion":"client.authentication.k8s.io/v1beta1", + "status": {} + }`, + wantErr: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + c := test.config + + c.Command = "./testdata/test-plugin.sh" + c.Env = append(c.Env, api.ExecEnvVar{ + Name: "TEST_OUTPUT", + Value: test.output, + }) + + a, err := newAuthenticator(newCache(), &c) + if err != nil { + t.Fatal(err) + } + + stderr := &bytes.Buffer{} + a.stderr = stderr + a.interactive = test.interactive + a.environ = func() []string { return nil } + + if err := a.refreshCredsLocked(test.response); err != nil { + if !test.wantErr { + t.Errorf("get token %v", err) + } + return + } + if test.wantErr { + t.Fatal("expected error getting token") + } + + if !reflect.DeepEqual(a.cachedCreds, &test.wantCreds) { + t.Errorf("expected credentials %+v got %+v", &test.wantCreds, a.cachedCreds) + } + + if !a.exp.Equal(test.wantExpiry) { + t.Errorf("expected expiry %v got %v", test.wantExpiry, a.exp) + } + + if test.wantInput == "" { + if got := strings.TrimSpace(stderr.String()); got != "" { + t.Errorf("expected no input parameters, got %q", got) + } + return + } + + compJSON(t, stderr.Bytes(), []byte(test.wantInput)) + }) + } +} + +func TestRoundTripper(t *testing.T) { + wantToken := "" + + n := time.Now() + now := func() time.Time { return n } + + env := []string{""} + environ := func() []string { + s := make([]string, len(env)) + copy(s, env) + return s + } + + setOutput := func(s string) { + env[0] = "TEST_OUTPUT=" + s + } + + handler := func(w http.ResponseWriter, r *http.Request) { + gotToken := "" + parts := strings.Split(r.Header.Get("Authorization"), " ") + if len(parts) > 1 && strings.EqualFold(parts[0], "bearer") { + gotToken = parts[1] + } + + if wantToken != gotToken { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + return + } + fmt.Fprintln(w, "ok") + } + server := httptest.NewServer(http.HandlerFunc(handler)) + + c := api.ExecConfig{ + Command: "./testdata/test-plugin.sh", + APIVersion: "client.authentication.k8s.io/v1alpha1", + } + a, err := newAuthenticator(newCache(), &c) + if err != nil { + t.Fatal(err) + } + a.environ = environ + a.now = now + a.stderr = ioutil.Discard + + tc := &transport.Config{} + if err := a.UpdateTransportConfig(tc); err != nil { + t.Fatal(err) + } + client := http.Client{ + Transport: tc.WrapTransport(http.DefaultTransport), + } + + get := func(t *testing.T, statusCode int) { + t.Helper() + resp, err := client.Get(server.URL) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != statusCode { + t.Errorf("wanted status %d got %d", statusCode, resp.StatusCode) + } + } + + setOutput(`{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "token1" + } + }`) + wantToken = "token1" + get(t, http.StatusOK) + + setOutput(`{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "token2" + } + }`) + // Previous token should be cached + get(t, http.StatusOK) + + wantToken = "token2" + // Token is still cached, hits unauthorized but causes token to rotate. + get(t, http.StatusUnauthorized) + // Follow up request uses the rotated token. + get(t, http.StatusOK) + + setOutput(`{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "token3", + "expirationTimestamp": "` + now().Add(time.Hour).Format(time.RFC3339Nano) + `" + } + }`) + wantToken = "token3" + // Token is still cached, hit's unauthorized but causes rotation to token with an expiry. + get(t, http.StatusUnauthorized) + get(t, http.StatusOK) + + // Move time forward 2 hours, "token3" is now expired. + n = n.Add(time.Hour * 2) + setOutput(`{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1alpha1", + "status": { + "token": "token4", + "expirationTimestamp": "` + now().Add(time.Hour).Format(time.RFC3339Nano) + `" + } + }`) + wantToken = "token4" + // Old token is expired, should refresh automatically without hitting a 401. + get(t, http.StatusOK) +} + +func TestTLSCredentials(t *testing.T) { + now := time.Now() + + certPool := x509.NewCertPool() + cert, key := genClientCert(t) + if !certPool.AppendCertsFromPEM(cert) { + t.Fatal("failed to add client cert to CertPool") + } + + server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "ok") + })) + server.TLS = &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: certPool, + } + server.StartTLS() + defer server.Close() + + a, err := newAuthenticator(newCache(), &api.ExecConfig{ + Command: "./testdata/test-plugin.sh", + APIVersion: "client.authentication.k8s.io/v1alpha1", + }) + if err != nil { + t.Fatal(err) + } + var output *clientauthentication.ExecCredential + a.environ = func() []string { + data, err := runtime.Encode(codecs.LegacyCodec(a.group), output) + if err != nil { + t.Fatal(err) + } + return []string{"TEST_OUTPUT=" + string(data)} + } + a.now = func() time.Time { return now } + a.stderr = ioutil.Discard + + // We're not interested in server's cert, this test is about client cert. + tc := &transport.Config{TLS: transport.TLSConfig{Insecure: true}} + if err := a.UpdateTransportConfig(tc); err != nil { + t.Fatal(err) + } + + get := func(t *testing.T, desc string, wantErr bool) { + t.Run(desc, func(t *testing.T) { + tlsCfg, err := transport.TLSConfigFor(tc) + if err != nil { + t.Fatal("TLSConfigFor:", err) + } + client := http.Client{ + Transport: &http.Transport{TLSClientConfig: tlsCfg}, + } + resp, err := client.Get(server.URL) + switch { + case err != nil && !wantErr: + t.Errorf("got client.Get error: %q, want nil", err) + case err == nil && wantErr: + t.Error("got nil client.Get error, want non-nil") + } + if err == nil { + resp.Body.Close() + } + }) + } + + output = &clientauthentication.ExecCredential{ + Status: &clientauthentication.ExecCredentialStatus{ + ClientCertificateData: string(cert), + ClientKeyData: string(key), + ExpirationTimestamp: &v1.Time{now.Add(time.Hour)}, + }, + } + get(t, "valid TLS cert", false) + + // Advance time to force re-exec. + nCert, nKey := genClientCert(t) + now = now.Add(time.Hour * 2) + output = &clientauthentication.ExecCredential{ + Status: &clientauthentication.ExecCredentialStatus{ + ClientCertificateData: string(nCert), + ClientKeyData: string(nKey), + ExpirationTimestamp: &v1.Time{now.Add(time.Hour)}, + }, + } + get(t, "untrusted TLS cert", true) + + now = now.Add(time.Hour * 2) + output = &clientauthentication.ExecCredential{ + Status: &clientauthentication.ExecCredentialStatus{ + ClientCertificateData: string(cert), + ClientKeyData: string(key), + ExpirationTimestamp: &v1.Time{now.Add(time.Hour)}, + }, + } + get(t, "valid TLS cert again", false) +} + +// genClientCert generates an x509 certificate for testing. Certificate and key +// are returned in PEM encoding. +func genClientCert(t *testing.T) ([]byte, []byte) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + keyRaw, err := x509.MarshalECPrivateKey(key) + if err != nil { + t.Fatal(err) + } + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + t.Fatal(err) + } + cert := &x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{Organization: []string{"Acme Co"}}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(24 * time.Hour), + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, + BasicConstraintsValid: true, + } + certRaw, err := x509.CreateCertificate(rand.Reader, cert, cert, key.Public(), key) + if err != nil { + t.Fatal(err) + } + return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certRaw}), + pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyRaw}) +} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/doc.go b/vendor/k8s.io/client-go/plugin/pkg/client/auth/plugins.go similarity index 67% rename from vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/doc.go rename to vendor/k8s.io/client-go/plugin/pkg/client/auth/plugins.go index 36bd4549c..42085d7ae 100644 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/doc.go +++ b/vendor/k8s.io/client-go/plugin/pkg/client/auth/plugins.go @@ -14,9 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -// +k8s:deepcopy-gen=package -// +k8s:defaulter-gen=TypeMeta -// +groupName=example.test.apiserver.code-generator.k8s.io -// +k8s:conversion-gen=k8s.io/code-generator/_examples/apiserver/apis/example2 -// +groupGoName=SecondExample -package v1 +package auth + +import ( + // Initialize all known client auth plugins. + _ "k8s.io/client-go/plugin/pkg/client/auth/azure" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" + _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" +) diff --git a/vendor/k8s.io/client-go/rest/OWNERS b/vendor/k8s.io/client-go/rest/OWNERS new file mode 100755 index 000000000..8d97da007 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/OWNERS @@ -0,0 +1,24 @@ +reviewers: +- thockin +- smarterclayton +- caesarxuchao +- wojtek-t +- deads2k +- brendandburns +- liggitt +- nikhiljindal +- gmarek +- erictune +- sttts +- luxas +- dims +- errordeveloper +- hongchaodeng +- krousey +- resouer +- cjcullen +- rmmh +- lixiaobing10051267 +- asalkeld +- juanvallejo +- lojies diff --git a/vendor/k8s.io/client-go/rest/client_test.go b/vendor/k8s.io/client-go/rest/client_test.go new file mode 100644 index 000000000..2eae9be2d --- /dev/null +++ b/vendor/k8s.io/client-go/rest/client_test.go @@ -0,0 +1,343 @@ +/* +Copyright 2014 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 rest + +import ( + "net/http" + "net/http/httptest" + "net/url" + "os" + "reflect" + "testing" + "time" + + "fmt" + + "k8s.io/api/core/v1" + v1beta1 "k8s.io/api/extensions/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/client-go/kubernetes/scheme" + utiltesting "k8s.io/client-go/util/testing" +) + +type TestParam struct { + actualError error + expectingError bool + actualCreated bool + expCreated bool + expStatus *metav1.Status + testBody bool + testBodyErrorIsNotNil bool +} + +// TestSerializer makes sure that you're always able to decode metav1.Status +func TestSerializer(t *testing.T) { + gv := v1beta1.SchemeGroupVersion + contentConfig := ContentConfig{ + ContentType: "application/json", + GroupVersion: &gv, + NegotiatedSerializer: serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}, + } + + serializer, err := createSerializers(contentConfig) + if err != nil { + t.Fatal(err) + } + // bytes based on actual return from API server when encoding an "unversioned" object + obj, err := runtime.Decode(serializer.Decoder, []byte(`{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Success"}`)) + t.Log(obj) + if err != nil { + t.Fatal(err) + } +} + +func TestDoRequestSuccess(t *testing.T) { + testServer, fakeHandler, status := testServerEnv(t, 200) + defer testServer.Close() + + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + body, err := c.Get().Prefix("test").Do().Raw() + + testParam := TestParam{actualError: err, expectingError: false, expCreated: true, + expStatus: status, testBody: true, testBodyErrorIsNotNil: false} + validate(testParam, t, body, fakeHandler) +} + +func TestDoRequestFailed(t *testing.T) { + status := &metav1.Status{ + Code: http.StatusNotFound, + Status: metav1.StatusFailure, + Reason: metav1.StatusReasonNotFound, + Message: " \"\" not found", + Details: &metav1.StatusDetails{}, + } + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), status) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 404, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + err = c.Get().Do().Error() + if err == nil { + t.Errorf("unexpected non-error") + } + ss, ok := err.(errors.APIStatus) + if !ok { + t.Errorf("unexpected error type %v", err) + } + actual := ss.Status() + if !reflect.DeepEqual(status, &actual) { + t.Errorf("Unexpected mis-match: %s", diff.ObjectReflectDiff(status, &actual)) + } +} + +func TestDoRawRequestFailed(t *testing.T) { + status := &metav1.Status{ + Code: http.StatusNotFound, + Status: metav1.StatusFailure, + Reason: metav1.StatusReasonNotFound, + Message: "the server could not find the requested resource", + Details: &metav1.StatusDetails{ + Causes: []metav1.StatusCause{ + {Type: metav1.CauseTypeUnexpectedServerResponse, Message: "unknown"}, + }, + }, + } + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), status) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 404, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + body, err := c.Get().Do().Raw() + + if err == nil || body == nil { + t.Errorf("unexpected non-error: %#v", body) + } + ss, ok := err.(errors.APIStatus) + if !ok { + t.Errorf("unexpected error type %v", err) + } + actual := ss.Status() + if !reflect.DeepEqual(status, &actual) { + t.Errorf("Unexpected mis-match: %s", diff.ObjectReflectDiff(status, &actual)) + } +} + +func TestDoRequestCreated(t *testing.T) { + testServer, fakeHandler, status := testServerEnv(t, 201) + defer testServer.Close() + + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + created := false + body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw() + + testParam := TestParam{actualError: err, expectingError: false, expCreated: true, + expStatus: status, testBody: false} + validate(testParam, t, body, fakeHandler) +} + +func TestDoRequestNotCreated(t *testing.T) { + testServer, fakeHandler, expectedStatus := testServerEnv(t, 202) + defer testServer.Close() + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + created := false + body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw() + testParam := TestParam{actualError: err, expectingError: false, expCreated: false, + expStatus: expectedStatus, testBody: false} + validate(testParam, t, body, fakeHandler) +} + +func TestDoRequestAcceptedNoContentReturned(t *testing.T) { + testServer, fakeHandler, _ := testServerEnv(t, 204) + defer testServer.Close() + + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + created := false + body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw() + testParam := TestParam{actualError: err, expectingError: false, expCreated: false, + testBody: false} + validate(testParam, t, body, fakeHandler) +} + +func TestBadRequest(t *testing.T) { + testServer, fakeHandler, _ := testServerEnv(t, 400) + defer testServer.Close() + c, err := restClient(testServer) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + created := false + body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw() + testParam := TestParam{actualError: err, expectingError: true, expCreated: false, + testBody: true} + validate(testParam, t, body, fakeHandler) +} + +func validate(testParam TestParam, t *testing.T, body []byte, fakeHandler *utiltesting.FakeHandler) { + switch { + case testParam.expectingError && testParam.actualError == nil: + t.Errorf("Expected error") + case !testParam.expectingError && testParam.actualError != nil: + t.Error(testParam.actualError) + } + if !testParam.expCreated { + if testParam.actualCreated { + t.Errorf("Expected object not to be created") + } + } + statusOut, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), body) + if testParam.testBody { + if testParam.testBodyErrorIsNotNil && err == nil { + t.Errorf("Expected Error") + } + if !testParam.testBodyErrorIsNotNil && err != nil { + t.Errorf("Unexpected Error: %v", err) + } + } + + if testParam.expStatus != nil { + if !reflect.DeepEqual(testParam.expStatus, statusOut) { + t.Errorf("Unexpected mis-match. Expected %#v. Saw %#v", testParam.expStatus, statusOut) + } + } + fakeHandler.ValidateRequest(t, "/"+v1.SchemeGroupVersion.String()+"/test", "GET", nil) + +} + +func TestHttpMethods(t *testing.T) { + testServer, _, _ := testServerEnv(t, 200) + defer testServer.Close() + c, _ := restClient(testServer) + + request := c.Post() + if request == nil { + t.Errorf("Post : Object returned should not be nil") + } + + request = c.Get() + if request == nil { + t.Errorf("Get: Object returned should not be nil") + } + + request = c.Put() + if request == nil { + t.Errorf("Put : Object returned should not be nil") + } + + request = c.Delete() + if request == nil { + t.Errorf("Delete : Object returned should not be nil") + } + + request = c.Patch(types.JSONPatchType) + if request == nil { + t.Errorf("Patch : Object returned should not be nil") + } +} + +func TestCreateBackoffManager(t *testing.T) { + + theUrl, _ := url.Parse("http://localhost") + + // 1 second base backoff + duration of 2 seconds -> exponential backoff for requests. + os.Setenv(envBackoffBase, "1") + os.Setenv(envBackoffDuration, "2") + backoff := readExpBackoffConfig() + backoff.UpdateBackoff(theUrl, nil, 500) + backoff.UpdateBackoff(theUrl, nil, 500) + if backoff.CalculateBackoff(theUrl)/time.Second != 2 { + t.Errorf("Backoff env not working.") + } + + // 0 duration -> no backoff. + os.Setenv(envBackoffBase, "1") + os.Setenv(envBackoffDuration, "0") + backoff.UpdateBackoff(theUrl, nil, 500) + backoff.UpdateBackoff(theUrl, nil, 500) + backoff = readExpBackoffConfig() + if backoff.CalculateBackoff(theUrl)/time.Second != 0 { + t.Errorf("Zero backoff duration, but backoff still occurring.") + } + + // No env -> No backoff. + os.Setenv(envBackoffBase, "") + os.Setenv(envBackoffDuration, "") + backoff = readExpBackoffConfig() + backoff.UpdateBackoff(theUrl, nil, 500) + backoff.UpdateBackoff(theUrl, nil, 500) + if backoff.CalculateBackoff(theUrl)/time.Second != 0 { + t.Errorf("Backoff should have been 0.") + } + +} + +func testServerEnv(t *testing.T, statusCode int) (*httptest.Server, *utiltesting.FakeHandler, *metav1.Status) { + status := &metav1.Status{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Status"}, Status: fmt.Sprintf("%s", metav1.StatusSuccess)} + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), status) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: statusCode, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + return testServer, &fakeHandler, status +} + +func restClient(testServer *httptest.Server) (*RESTClient, error) { + c, err := RESTClientFor(&Config{ + Host: testServer.URL, + ContentConfig: ContentConfig{ + GroupVersion: &v1.SchemeGroupVersion, + NegotiatedSerializer: serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}, + }, + Username: "user", + Password: "pass", + }) + return c, err +} diff --git a/vendor/k8s.io/client-go/rest/config_test.go b/vendor/k8s.io/client-go/rest/config_test.go new file mode 100644 index 000000000..347864285 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/config_test.go @@ -0,0 +1,375 @@ +/* +Copyright 2016 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 rest + +import ( + "context" + "errors" + "io" + "net" + "net/http" + "path/filepath" + "reflect" + "strings" + "testing" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/client-go/kubernetes/scheme" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/client-go/util/flowcontrol" + + fuzz "github.com/google/gofuzz" + "github.com/stretchr/testify/assert" +) + +func TestIsConfigTransportTLS(t *testing.T) { + testCases := []struct { + Config *Config + TransportTLS bool + }{ + { + Config: &Config{}, + TransportTLS: false, + }, + { + Config: &Config{ + Host: "https://localhost", + }, + TransportTLS: true, + }, + { + Config: &Config{ + Host: "localhost", + TLSClientConfig: TLSClientConfig{ + CertFile: "foo", + }, + }, + TransportTLS: true, + }, + { + Config: &Config{ + Host: "///:://localhost", + TLSClientConfig: TLSClientConfig{ + CertFile: "foo", + }, + }, + TransportTLS: false, + }, + { + Config: &Config{ + Host: "1.2.3.4:567", + TLSClientConfig: TLSClientConfig{ + Insecure: true, + }, + }, + TransportTLS: true, + }, + } + for _, testCase := range testCases { + if err := SetKubernetesDefaults(testCase.Config); err != nil { + t.Errorf("setting defaults failed for %#v: %v", testCase.Config, err) + continue + } + useTLS := IsConfigTransportTLS(*testCase.Config) + if testCase.TransportTLS != useTLS { + t.Errorf("expected %v for %#v", testCase.TransportTLS, testCase.Config) + } + } +} + +func TestSetKubernetesDefaultsUserAgent(t *testing.T) { + config := &Config{} + if err := SetKubernetesDefaults(config); err != nil { + t.Errorf("unexpected error: %v", err) + } + if !strings.Contains(config.UserAgent, "kubernetes/") { + t.Errorf("no user agent set: %#v", config) + } +} + +func TestAdjustVersion(t *testing.T) { + assert := assert.New(t) + assert.Equal("1.2.3", adjustVersion("1.2.3-alpha4")) + assert.Equal("1.2.3", adjustVersion("1.2.3-alpha")) + assert.Equal("1.2.3", adjustVersion("1.2.3")) + assert.Equal("unknown", adjustVersion("")) +} + +func TestAdjustCommit(t *testing.T) { + assert := assert.New(t) + assert.Equal("1234567", adjustCommit("1234567890")) + assert.Equal("123456", adjustCommit("123456")) + assert.Equal("unknown", adjustCommit("")) +} + +func TestAdjustCommand(t *testing.T) { + assert := assert.New(t) + assert.Equal("beans", adjustCommand(filepath.Join("home", "bob", "Downloads", "beans"))) + assert.Equal("beans", adjustCommand(filepath.Join(".", "beans"))) + assert.Equal("beans", adjustCommand("beans")) + assert.Equal("unknown", adjustCommand("")) +} + +func TestBuildUserAgent(t *testing.T) { + assert.New(t).Equal( + "lynx/nicest (beos/itanium) kubernetes/baaaaaaaaad", + buildUserAgent( + "lynx", "nicest", + "beos", "itanium", "baaaaaaaaad")) +} + +// This function untestable since it doesn't accept arguments. +func TestDefaultKubernetesUserAgent(t *testing.T) { + assert.New(t).Contains(DefaultKubernetesUserAgent(), "kubernetes") +} + +func TestRESTClientRequires(t *testing.T) { + if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{NegotiatedSerializer: scheme.Codecs}}); err == nil { + t.Errorf("unexpected non-error") + } + if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: &v1.SchemeGroupVersion}}); err == nil { + t.Errorf("unexpected non-error") + } + if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: &v1.SchemeGroupVersion, NegotiatedSerializer: scheme.Codecs}}); err != nil { + t.Errorf("unexpected error: %v", err) + } +} + +type fakeLimiter struct { + FakeSaturation float64 + FakeQPS float32 +} + +func (t *fakeLimiter) TryAccept() bool { + return true +} + +func (t *fakeLimiter) Saturation() float64 { + return t.FakeSaturation +} + +func (t *fakeLimiter) QPS() float32 { + return t.FakeQPS +} + +func (t *fakeLimiter) Stop() {} + +func (t *fakeLimiter) Accept() {} + +type fakeCodec struct{} + +func (c *fakeCodec) Decode([]byte, *schema.GroupVersionKind, runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { + return nil, nil, nil +} + +func (c *fakeCodec) Encode(obj runtime.Object, stream io.Writer) error { + return nil +} + +type fakeRoundTripper struct{} + +func (r *fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { + return nil, nil +} + +var fakeWrapperFunc = func(http.RoundTripper) http.RoundTripper { + return &fakeRoundTripper{} +} + +type fakeNegotiatedSerializer struct{} + +func (n *fakeNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo { + return nil +} + +func (n *fakeNegotiatedSerializer) EncoderForVersion(serializer runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder { + return &fakeCodec{} +} + +func (n *fakeNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder { + return &fakeCodec{} +} + +var fakeDialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) { + return nil, fakeDialerError +} +var fakeDialerError = errors.New("fakedialer") + +type fakeAuthProviderConfigPersister struct{} + +func (fakeAuthProviderConfigPersister) Persist(map[string]string) error { + return fakeAuthProviderConfigPersisterError +} + +var fakeAuthProviderConfigPersisterError = errors.New("fakeAuthProviderConfigPersisterError") + +func TestAnonymousConfig(t *testing.T) { + f := fuzz.New().NilChance(0.0).NumElements(1, 1) + f.Funcs( + func(r *runtime.Codec, f fuzz.Continue) { + codec := &fakeCodec{} + f.Fuzz(codec) + *r = codec + }, + func(r *http.RoundTripper, f fuzz.Continue) { + roundTripper := &fakeRoundTripper{} + f.Fuzz(roundTripper) + *r = roundTripper + }, + func(fn *func(http.RoundTripper) http.RoundTripper, f fuzz.Continue) { + *fn = fakeWrapperFunc + }, + func(r *runtime.NegotiatedSerializer, f fuzz.Continue) { + serializer := &fakeNegotiatedSerializer{} + f.Fuzz(serializer) + *r = serializer + }, + func(r *flowcontrol.RateLimiter, f fuzz.Continue) { + limiter := &fakeLimiter{} + f.Fuzz(limiter) + *r = limiter + }, + // Authentication does not require fuzzer + func(r *AuthProviderConfigPersister, f fuzz.Continue) {}, + func(r *clientcmdapi.AuthProviderConfig, f fuzz.Continue) { + r.Config = map[string]string{} + }, + // Dial does not require fuzzer + func(r *func(ctx context.Context, network, addr string) (net.Conn, error), f fuzz.Continue) {}, + ) + for i := 0; i < 20; i++ { + original := &Config{} + f.Fuzz(original) + actual := AnonymousClientConfig(original) + expected := *original + + // this is the list of known security related fields, add to this list if a new field + // is added to Config, update AnonymousClientConfig to preserve the field otherwise. + expected.Impersonate = ImpersonationConfig{} + expected.BearerToken = "" + expected.Username = "" + expected.Password = "" + expected.AuthProvider = nil + expected.AuthConfigPersister = nil + expected.ExecProvider = nil + expected.TLSClientConfig.CertData = nil + expected.TLSClientConfig.CertFile = "" + expected.TLSClientConfig.KeyData = nil + expected.TLSClientConfig.KeyFile = "" + + // The DeepEqual cannot handle the func comparison, so we just verify if the + // function return the expected object. + if actual.WrapTransport == nil || !reflect.DeepEqual(expected.WrapTransport(nil), &fakeRoundTripper{}) { + t.Fatalf("AnonymousClientConfig dropped the WrapTransport field") + } else { + actual.WrapTransport = nil + expected.WrapTransport = nil + } + if actual.Dial != nil { + _, actualError := actual.Dial(context.Background(), "", "") + _, expectedError := expected.Dial(context.Background(), "", "") + if !reflect.DeepEqual(expectedError, actualError) { + t.Fatalf("CopyConfig dropped the Dial field") + } + } else { + actual.Dial = nil + expected.Dial = nil + } + + if !reflect.DeepEqual(*actual, expected) { + t.Fatalf("AnonymousClientConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectGoPrintDiff(expected, actual)) + } + } +} + +func TestCopyConfig(t *testing.T) { + f := fuzz.New().NilChance(0.0).NumElements(1, 1) + f.Funcs( + func(r *runtime.Codec, f fuzz.Continue) { + codec := &fakeCodec{} + f.Fuzz(codec) + *r = codec + }, + func(r *http.RoundTripper, f fuzz.Continue) { + roundTripper := &fakeRoundTripper{} + f.Fuzz(roundTripper) + *r = roundTripper + }, + func(fn *func(http.RoundTripper) http.RoundTripper, f fuzz.Continue) { + *fn = fakeWrapperFunc + }, + func(r *runtime.NegotiatedSerializer, f fuzz.Continue) { + serializer := &fakeNegotiatedSerializer{} + f.Fuzz(serializer) + *r = serializer + }, + func(r *flowcontrol.RateLimiter, f fuzz.Continue) { + limiter := &fakeLimiter{} + f.Fuzz(limiter) + *r = limiter + }, + func(r *AuthProviderConfigPersister, f fuzz.Continue) { + *r = fakeAuthProviderConfigPersister{} + }, + func(r *func(ctx context.Context, network, addr string) (net.Conn, error), f fuzz.Continue) { + *r = fakeDialFunc + }, + ) + for i := 0; i < 20; i++ { + original := &Config{} + f.Fuzz(original) + actual := CopyConfig(original) + expected := *original + + // this is the list of known risky fields, add to this list if a new field + // is added to Config, update CopyConfig to preserve the field otherwise. + + // The DeepEqual cannot handle the func comparison, so we just verify if the + // function return the expected object. + if actual.WrapTransport == nil || !reflect.DeepEqual(expected.WrapTransport(nil), &fakeRoundTripper{}) { + t.Fatalf("CopyConfig dropped the WrapTransport field") + } else { + actual.WrapTransport = nil + expected.WrapTransport = nil + } + if actual.Dial != nil { + _, actualError := actual.Dial(context.Background(), "", "") + _, expectedError := expected.Dial(context.Background(), "", "") + if !reflect.DeepEqual(expectedError, actualError) { + t.Fatalf("CopyConfig dropped the Dial field") + } + } + actual.Dial = nil + expected.Dial = nil + if actual.AuthConfigPersister != nil { + actualError := actual.AuthConfigPersister.Persist(nil) + expectedError := expected.AuthConfigPersister.Persist(nil) + if !reflect.DeepEqual(expectedError, actualError) { + t.Fatalf("CopyConfig dropped the Dial field") + } + } + actual.AuthConfigPersister = nil + expected.AuthConfigPersister = nil + + if !reflect.DeepEqual(*actual, expected) { + t.Fatalf("CopyConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectReflectDiff(expected, *actual)) + } + } +} diff --git a/vendor/k8s.io/client-go/rest/plugin_test.go b/vendor/k8s.io/client-go/rest/plugin_test.go new file mode 100644 index 000000000..070e53790 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/plugin_test.go @@ -0,0 +1,311 @@ +/* +Copyright 2016 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 rest + +import ( + "fmt" + "net/http" + "reflect" + "strconv" + "testing" + + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +func TestAuthPluginWrapTransport(t *testing.T) { + if err := RegisterAuthProviderPlugin("pluginA", pluginAProvider); err != nil { + t.Errorf("Unexpected error: failed to register pluginA: %v", err) + } + if err := RegisterAuthProviderPlugin("pluginB", pluginBProvider); err != nil { + t.Errorf("Unexpected error: failed to register pluginB: %v", err) + } + if err := RegisterAuthProviderPlugin("pluginFail", pluginFailProvider); err != nil { + t.Errorf("Unexpected error: failed to register pluginFail: %v", err) + } + testCases := []struct { + useWrapTransport bool + plugin string + expectErr bool + expectPluginA bool + expectPluginB bool + }{ + {false, "", false, false, false}, + {false, "pluginA", false, true, false}, + {false, "pluginB", false, false, true}, + {false, "pluginFail", true, false, false}, + {false, "pluginUnknown", true, false, false}, + } + for i, tc := range testCases { + c := Config{} + if tc.useWrapTransport { + // Specify an existing WrapTransport in the config to make sure that + // plugins play nicely. + c.WrapTransport = func(rt http.RoundTripper) http.RoundTripper { + return &wrapTransport{rt} + } + } + if len(tc.plugin) != 0 { + c.AuthProvider = &clientcmdapi.AuthProviderConfig{Name: tc.plugin} + } + tConfig, err := c.TransportConfig() + if err != nil { + // Unknown/bad plugins are expected to fail here. + if !tc.expectErr { + t.Errorf("%d. Did not expect errors loading Auth Plugin: %q. Got: %v", i, tc.plugin, err) + } + continue + } + var fullyWrappedTransport http.RoundTripper + fullyWrappedTransport = &emptyTransport{} + if tConfig.WrapTransport != nil { + fullyWrappedTransport = tConfig.WrapTransport(&emptyTransport{}) + } + res, err := fullyWrappedTransport.RoundTrip(&http.Request{}) + if err != nil { + t.Errorf("%d. Unexpected error in RoundTrip: %v", i, err) + continue + } + hasWrapTransport := res.Header.Get("wrapTransport") == "Y" + hasPluginA := res.Header.Get("pluginA") == "Y" + hasPluginB := res.Header.Get("pluginB") == "Y" + if hasWrapTransport != tc.useWrapTransport { + t.Errorf("%d. Expected Existing config.WrapTransport: %t; Got: %t", i, tc.useWrapTransport, hasWrapTransport) + } + if hasPluginA != tc.expectPluginA { + t.Errorf("%d. Expected Plugin A: %t; Got: %t", i, tc.expectPluginA, hasPluginA) + } + if hasPluginB != tc.expectPluginB { + t.Errorf("%d. Expected Plugin B: %t; Got: %t", i, tc.expectPluginB, hasPluginB) + } + } +} + +func TestAuthPluginPersist(t *testing.T) { + // register pluginA by a different name so we don't collide across tests. + if err := RegisterAuthProviderPlugin("pluginA2", pluginAProvider); err != nil { + t.Errorf("Unexpected error: failed to register pluginA: %v", err) + } + if err := RegisterAuthProviderPlugin("pluginPersist", pluginPersistProvider); err != nil { + t.Errorf("Unexpected error: failed to register pluginPersist: %v", err) + } + fooBarConfig := map[string]string{"foo": "bar"} + testCases := []struct { + plugin string + startingConfig map[string]string + expectedConfigAfterLogin map[string]string + expectedConfigAfterRoundTrip map[string]string + }{ + // non-persisting plugins should work fine without modifying config. + {"pluginA2", map[string]string{}, map[string]string{}, map[string]string{}}, + {"pluginA2", fooBarConfig, fooBarConfig, fooBarConfig}, + // plugins that persist config should be able to persist when they want. + { + "pluginPersist", + map[string]string{}, + map[string]string{ + "login": "Y", + }, + map[string]string{ + "login": "Y", + "roundTrips": "1", + }, + }, + { + "pluginPersist", + map[string]string{ + "login": "Y", + "roundTrips": "123", + }, + map[string]string{ + "login": "Y", + "roundTrips": "123", + }, + map[string]string{ + "login": "Y", + "roundTrips": "124", + }, + }, + } + for i, tc := range testCases { + cfg := &clientcmdapi.AuthProviderConfig{ + Name: tc.plugin, + Config: tc.startingConfig, + } + persister := &inMemoryPersister{make(map[string]string)} + persister.Persist(tc.startingConfig) + plugin, err := GetAuthProvider("127.0.0.1", cfg, persister) + if err != nil { + t.Errorf("%d. Unexpected error: failed to get plugin %q: %v", i, tc.plugin, err) + } + if err := plugin.Login(); err != nil { + t.Errorf("%d. Unexpected error calling Login() w/ plugin %q: %v", i, tc.plugin, err) + } + // Make sure the plugin persisted what we expect after Login(). + if !reflect.DeepEqual(persister.savedConfig, tc.expectedConfigAfterLogin) { + t.Errorf("%d. Unexpected persisted config after calling %s.Login(): \nGot:\n%v\nExpected:\n%v", + i, tc.plugin, persister.savedConfig, tc.expectedConfigAfterLogin) + } + if _, err := plugin.WrapTransport(&emptyTransport{}).RoundTrip(&http.Request{}); err != nil { + t.Errorf("%d. Unexpected error round-tripping w/ plugin %q: %v", i, tc.plugin, err) + } + // Make sure the plugin persisted what we expect after RoundTrip(). + if !reflect.DeepEqual(persister.savedConfig, tc.expectedConfigAfterRoundTrip) { + t.Errorf("%d. Unexpected persisted config after calling %s.WrapTransport.RoundTrip(): \nGot:\n%v\nExpected:\n%v", + i, tc.plugin, persister.savedConfig, tc.expectedConfigAfterLogin) + } + } + +} + +// emptyTransport provides an empty http.Response with an initialized header +// to allow wrapping RoundTrippers to set header values. +type emptyTransport struct{} + +func (*emptyTransport) RoundTrip(req *http.Request) (*http.Response, error) { + res := &http.Response{ + Header: make(map[string][]string), + } + return res, nil +} + +// wrapTransport sets "wrapTransport" = "Y" on the response. +type wrapTransport struct { + rt http.RoundTripper +} + +func (w *wrapTransport) RoundTrip(req *http.Request) (*http.Response, error) { + res, err := w.rt.RoundTrip(req) + if err != nil { + return nil, err + } + res.Header.Add("wrapTransport", "Y") + return res, nil +} + +// wrapTransportA sets "pluginA" = "Y" on the response. +type wrapTransportA struct { + rt http.RoundTripper +} + +func (w *wrapTransportA) RoundTrip(req *http.Request) (*http.Response, error) { + res, err := w.rt.RoundTrip(req) + if err != nil { + return nil, err + } + res.Header.Add("pluginA", "Y") + return res, nil +} + +type pluginA struct{} + +func (*pluginA) WrapTransport(rt http.RoundTripper) http.RoundTripper { + return &wrapTransportA{rt} +} + +func (*pluginA) Login() error { return nil } + +func pluginAProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) { + return &pluginA{}, nil +} + +// wrapTransportB sets "pluginB" = "Y" on the response. +type wrapTransportB struct { + rt http.RoundTripper +} + +func (w *wrapTransportB) RoundTrip(req *http.Request) (*http.Response, error) { + res, err := w.rt.RoundTrip(req) + if err != nil { + return nil, err + } + res.Header.Add("pluginB", "Y") + return res, nil +} + +type pluginB struct{} + +func (*pluginB) WrapTransport(rt http.RoundTripper) http.RoundTripper { + return &wrapTransportB{rt} +} + +func (*pluginB) Login() error { return nil } + +func pluginBProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) { + return &pluginB{}, nil +} + +// pluginFailProvider simulates a registered AuthPlugin that fails to load. +func pluginFailProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) { + return nil, fmt.Errorf("Failed to load AuthProvider") +} + +type inMemoryPersister struct { + savedConfig map[string]string +} + +func (i *inMemoryPersister) Persist(config map[string]string) error { + i.savedConfig = make(map[string]string) + for k, v := range config { + i.savedConfig[k] = v + } + return nil +} + +// wrapTransportPersist increments the "roundTrips" entry from the config when +// roundTrip is called. +type wrapTransportPersist struct { + rt http.RoundTripper + config map[string]string + persister AuthProviderConfigPersister +} + +func (w *wrapTransportPersist) RoundTrip(req *http.Request) (*http.Response, error) { + roundTrips := 0 + if rtVal, ok := w.config["roundTrips"]; ok { + var err error + roundTrips, err = strconv.Atoi(rtVal) + if err != nil { + return nil, err + } + } + roundTrips++ + w.config["roundTrips"] = fmt.Sprintf("%d", roundTrips) + if err := w.persister.Persist(w.config); err != nil { + return nil, err + } + return w.rt.RoundTrip(req) +} + +type pluginPersist struct { + config map[string]string + persister AuthProviderConfigPersister +} + +func (p *pluginPersist) WrapTransport(rt http.RoundTripper) http.RoundTripper { + return &wrapTransportPersist{rt, p.config, p.persister} +} + +// Login sets the config entry "login" to "Y". +func (p *pluginPersist) Login() error { + p.config["login"] = "Y" + p.persister.Persist(p.config) + return nil +} + +func pluginPersistProvider(_ string, config map[string]string, persister AuthProviderConfigPersister) (AuthProvider, error) { + return &pluginPersist{config, persister}, nil +} diff --git a/vendor/k8s.io/client-go/rest/request_test.go b/vendor/k8s.io/client-go/rest/request_test.go new file mode 100755 index 000000000..2660c0be5 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/request_test.go @@ -0,0 +1,1937 @@ +/* +Copyright 2014 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 rest + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "net/http/httptest" + "net/url" + "os" + "reflect" + "strings" + "syscall" + "testing" + "time" + + "github.com/golang/glog" + + "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/runtime/serializer/streaming" + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/apimachinery/pkg/util/httpstream" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes/scheme" + restclientwatch "k8s.io/client-go/rest/watch" + "k8s.io/client-go/util/flowcontrol" + utiltesting "k8s.io/client-go/util/testing" +) + +func TestNewRequestSetsAccept(t *testing.T) { + r := NewRequest(nil, "get", &url.URL{Path: "/path/"}, "", ContentConfig{}, Serializers{}, nil, nil, 0) + if r.headers.Get("Accept") != "" { + t.Errorf("unexpected headers: %#v", r.headers) + } + r = NewRequest(nil, "get", &url.URL{Path: "/path/"}, "", ContentConfig{ContentType: "application/other"}, Serializers{}, nil, nil, 0) + if r.headers.Get("Accept") != "application/other, */*" { + t.Errorf("unexpected headers: %#v", r.headers) + } +} + +type clientFunc func(req *http.Request) (*http.Response, error) + +func (f clientFunc) Do(req *http.Request) (*http.Response, error) { + return f(req) +} + +func TestRequestSetsHeaders(t *testing.T) { + server := clientFunc(func(req *http.Request) (*http.Response, error) { + if req.Header.Get("Accept") != "application/other, */*" { + t.Errorf("unexpected headers: %#v", req.Header) + } + return &http.Response{ + StatusCode: http.StatusForbidden, + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + }, nil + }) + config := defaultContentConfig() + config.ContentType = "application/other" + serializers := defaultSerializers(t) + r := NewRequest(server, "get", &url.URL{Path: "/path"}, "", config, serializers, nil, nil, 0) + + // Check if all "issue" methods are setting headers. + _ = r.Do() + _, _ = r.Watch() + _, _ = r.Stream() +} + +func TestRequestWithErrorWontChange(t *testing.T) { + gvCopy := v1.SchemeGroupVersion + original := Request{ + err: errors.New("test"), + content: ContentConfig{GroupVersion: &gvCopy}, + } + r := original + changed := r.Param("foo", "bar"). + AbsPath("/abs"). + Prefix("test"). + Suffix("testing"). + Namespace("new"). + Resource("foos"). + Name("bars"). + Body("foo"). + Timeout(time.Millisecond) + if changed != &r { + t.Errorf("returned request should point to the same object") + } + if !reflect.DeepEqual(changed, &original) { + t.Errorf("expected %#v, got %#v", &original, changed) + } +} + +func TestRequestPreservesBaseTrailingSlash(t *testing.T) { + r := &Request{baseURL: &url.URL{}, pathPrefix: "/path/"} + if s := r.URL().String(); s != "/path/" { + t.Errorf("trailing slash should be preserved: %s", s) + } +} + +func TestRequestAbsPathPreservesTrailingSlash(t *testing.T) { + r := (&Request{baseURL: &url.URL{}}).AbsPath("/foo/") + if s := r.URL().String(); s != "/foo/" { + t.Errorf("trailing slash should be preserved: %s", s) + } + + r = (&Request{baseURL: &url.URL{}}).AbsPath("/foo/") + if s := r.URL().String(); s != "/foo/" { + t.Errorf("trailing slash should be preserved: %s", s) + } +} + +func TestRequestAbsPathJoins(t *testing.T) { + r := (&Request{baseURL: &url.URL{}}).AbsPath("foo/bar", "baz") + if s := r.URL().String(); s != "foo/bar/baz" { + t.Errorf("trailing slash should be preserved: %s", s) + } +} + +func TestRequestSetsNamespace(t *testing.T) { + r := (&Request{ + baseURL: &url.URL{ + Path: "/", + }, + }).Namespace("foo") + if r.namespace == "" { + t.Errorf("namespace should be set: %#v", r) + } + + if s := r.URL().String(); s != "namespaces/foo" { + t.Errorf("namespace should be in path: %s", s) + } +} + +func TestRequestOrdersNamespaceInPath(t *testing.T) { + r := (&Request{ + baseURL: &url.URL{}, + pathPrefix: "/test/", + }).Name("bar").Resource("baz").Namespace("foo") + if s := r.URL().String(); s != "/test/namespaces/foo/baz/bar" { + t.Errorf("namespace should be in order in path: %s", s) + } +} + +func TestRequestOrdersSubResource(t *testing.T) { + r := (&Request{ + baseURL: &url.URL{}, + pathPrefix: "/test/", + }).Name("bar").Resource("baz").Namespace("foo").Suffix("test").SubResource("a", "b") + if s := r.URL().String(); s != "/test/namespaces/foo/baz/bar/a/b/test" { + t.Errorf("namespace should be in order in path: %s", s) + } +} + +func TestRequestSetTwiceError(t *testing.T) { + if (&Request{}).Name("bar").Name("baz").err == nil { + t.Errorf("setting name twice should result in error") + } + if (&Request{}).Namespace("bar").Namespace("baz").err == nil { + t.Errorf("setting namespace twice should result in error") + } + if (&Request{}).Resource("bar").Resource("baz").err == nil { + t.Errorf("setting resource twice should result in error") + } + if (&Request{}).SubResource("bar").SubResource("baz").err == nil { + t.Errorf("setting subresource twice should result in error") + } +} + +func TestInvalidSegments(t *testing.T) { + invalidSegments := []string{".", "..", "test/segment", "test%2bsegment"} + setters := map[string]func(string, *Request){ + "namespace": func(s string, r *Request) { r.Namespace(s) }, + "resource": func(s string, r *Request) { r.Resource(s) }, + "name": func(s string, r *Request) { r.Name(s) }, + "subresource": func(s string, r *Request) { r.SubResource(s) }, + } + for _, invalidSegment := range invalidSegments { + for setterName, setter := range setters { + r := &Request{} + setter(invalidSegment, r) + if r.err == nil { + t.Errorf("%s: %s: expected error, got none", setterName, invalidSegment) + } + } + } +} + +func TestRequestParam(t *testing.T) { + r := (&Request{}).Param("foo", "a") + if !reflect.DeepEqual(r.params, url.Values{"foo": []string{"a"}}) { + t.Errorf("should have set a param: %#v", r) + } + + r.Param("bar", "1") + r.Param("bar", "2") + if !reflect.DeepEqual(r.params, url.Values{"foo": []string{"a"}, "bar": []string{"1", "2"}}) { + t.Errorf("should have set a param: %#v", r) + } +} + +func TestRequestVersionedParams(t *testing.T) { + r := (&Request{content: ContentConfig{GroupVersion: &v1.SchemeGroupVersion}}).Param("foo", "a") + if !reflect.DeepEqual(r.params, url.Values{"foo": []string{"a"}}) { + t.Errorf("should have set a param: %#v", r) + } + r.VersionedParams(&v1.PodLogOptions{Follow: true, Container: "bar"}, scheme.ParameterCodec) + + if !reflect.DeepEqual(r.params, url.Values{ + "foo": []string{"a"}, + "container": []string{"bar"}, + "follow": []string{"true"}, + }) { + t.Errorf("should have set a param: %#v", r) + } +} + +func TestRequestVersionedParamsFromListOptions(t *testing.T) { + r := &Request{content: ContentConfig{GroupVersion: &v1.SchemeGroupVersion}} + r.VersionedParams(&metav1.ListOptions{ResourceVersion: "1"}, scheme.ParameterCodec) + if !reflect.DeepEqual(r.params, url.Values{ + "resourceVersion": []string{"1"}, + }) { + t.Errorf("should have set a param: %#v", r) + } + + var timeout int64 = 10 + r.VersionedParams(&metav1.ListOptions{ResourceVersion: "2", TimeoutSeconds: &timeout}, scheme.ParameterCodec) + if !reflect.DeepEqual(r.params, url.Values{ + "resourceVersion": []string{"1", "2"}, + "timeoutSeconds": []string{"10"}, + }) { + t.Errorf("should have set a param: %#v %v", r.params, r.err) + } +} + +func TestRequestURI(t *testing.T) { + r := (&Request{}).Param("foo", "a") + r.Prefix("other") + r.RequestURI("/test?foo=b&a=b&c=1&c=2") + if r.pathPrefix != "/test" { + t.Errorf("path is wrong: %#v", r) + } + if !reflect.DeepEqual(r.params, url.Values{"a": []string{"b"}, "foo": []string{"b"}, "c": []string{"1", "2"}}) { + t.Errorf("should have set a param: %#v", r) + } +} + +type NotAnAPIObject struct{} + +func (obj NotAnAPIObject) GroupVersionKind() *schema.GroupVersionKind { return nil } +func (obj NotAnAPIObject) SetGroupVersionKind(gvk *schema.GroupVersionKind) {} + +func defaultContentConfig() ContentConfig { + gvCopy := v1.SchemeGroupVersion + return ContentConfig{ + ContentType: "application/json", + GroupVersion: &gvCopy, + NegotiatedSerializer: serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}, + } +} + +func defaultSerializers(t *testing.T) Serializers { + config := defaultContentConfig() + serializers, err := createSerializers(config) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + return *serializers +} + +func TestRequestBody(t *testing.T) { + // test unknown type + r := (&Request{}).Body([]string{"test"}) + if r.err == nil || r.body != nil { + t.Errorf("should have set err and left body nil: %#v", r) + } + + // test error set when failing to read file + f, err := ioutil.TempFile("", "test") + if err != nil { + t.Fatalf("unable to create temp file") + } + defer f.Close() + os.Remove(f.Name()) + r = (&Request{}).Body(f.Name()) + if r.err == nil || r.body != nil { + t.Errorf("should have set err and left body nil: %#v", r) + } + + // test unencodable api object + r = (&Request{content: defaultContentConfig()}).Body(&NotAnAPIObject{}) + if r.err == nil || r.body != nil { + t.Errorf("should have set err and left body nil: %#v", r) + } +} + +func TestResultIntoWithErrReturnsErr(t *testing.T) { + res := Result{err: errors.New("test")} + if err := res.Into(&v1.Pod{}); err != res.err { + t.Errorf("should have returned exact error from result") + } +} + +func TestResultIntoWithNoBodyReturnsErr(t *testing.T) { + res := Result{ + body: []byte{}, + decoder: scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), + } + if err := res.Into(&v1.Pod{}); err == nil || !strings.Contains(err.Error(), "0-length") { + t.Errorf("should have complained about 0 length body") + } +} + +func TestURLTemplate(t *testing.T) { + uri, _ := url.Parse("http://localhost/some/base/url/path") + testCases := []struct { + Request *Request + ExpectedFullURL string + ExpectedFinalURL string + }{ + { + // non dynamic client + Request: NewRequest(nil, "POST", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("api", "v1").Resource("r1").Namespace("ns").Name("nm").Param("p0", "v0"), + ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/namespaces/ns/r1/nm?p0=v0", + ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D?p0=%7Bvalue%7D", + }, + { + // non dynamic client with wrong api group + Request: NewRequest(nil, "POST", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("pre1", "v1").Resource("r1").Namespace("ns").Name("nm").Param("p0", "v0"), + ExpectedFullURL: "http://localhost/some/base/url/path/pre1/v1/namespaces/ns/r1/nm?p0=v0", + ExpectedFinalURL: "http://localhost/%7Bprefix%7D", + }, + { + // dynamic client with core group + namespace + resourceResource (with name) + // /api/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/api/v1/namespaces/ns/r1/name1"), + ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/namespaces/ns/r1/name1", + ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D", + }, + { + // dynamic client with named group + namespace + resourceResource (with name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/g1/v1/namespaces/ns/r1/name1"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/ns/r1/name1", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D", + }, + { + // dynamic client with core group + namespace + resourceResource (with NO name) + // /api/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/api/v1/namespaces/ns/r1"), + ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/namespaces/ns/r1", + ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/namespaces/%7Bnamespace%7D/r1", + }, + { + // dynamic client with named group + namespace + resourceResource (with NO name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/g1/v1/namespaces/ns/r1"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/ns/r1", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/%7Bnamespace%7D/r1", + }, + { + // dynamic client with core group + resourceResource (with name) + // /api/$RESOURCEVERSION/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/api/v1/r1/name1"), + ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/r1/name1", + ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/r1/%7Bname%7D", + }, + { + // dynamic client with named group + resourceResource (with name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/g1/v1/r1/name1"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/g1/v1/r1/name1", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/g1/v1/r1/%7Bname%7D", + }, + { + // dynamic client with named group + namespace + resourceResource (with name) + subresource + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME/$SUBRESOURCE + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/%7Bname%7D/finalize", + }, + { + // dynamic client with named group + namespace + resourceResource (with name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/%7Bname%7D", + }, + { + // dynamic client with named group + namespace + resourceResource (with NO name) + subresource + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%SUBRESOURCE + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/finalize"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/finalize", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/finalize", + }, + { + // dynamic client with named group + namespace + resourceResource (with NO name) + subresource + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%SUBRESOURCE + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/status"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/status", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/status", + }, + { + // dynamic client with named group + namespace + resourceResource (with no name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces", + }, + { + // dynamic client with named group + resourceResource (with name) + subresource + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/finalize"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/finalize", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bname%7D/finalize", + }, + { + // dynamic client with named group + resourceResource (with name) + subresource + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces/status"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/status", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bname%7D/status", + }, + { + // dynamic client with named group + resourceResource (with name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces/namespaces"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bname%7D", + }, + { + // dynamic client with named group + resourceResource (with no name) + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/$RESOURCE/%NAME + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/apis/namespaces/namespaces/namespaces"), + ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces", + ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces", + }, + { + // dynamic client with wrong api group + namespace + resourceResource (with name) + subresource + // /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME/$SUBRESOURCE + Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0). + Prefix("/pre1/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize"), + ExpectedFullURL: "http://localhost/some/base/url/path/pre1/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize", + ExpectedFinalURL: "http://localhost/%7Bprefix%7D", + }, + } + for i, testCase := range testCases { + r := testCase.Request + full := r.URL() + if full.String() != testCase.ExpectedFullURL { + t.Errorf("%d: unexpected initial URL: %s %s", i, full, testCase.ExpectedFullURL) + } + actualURL := r.finalURLTemplate() + actual := actualURL.String() + if actual != testCase.ExpectedFinalURL { + t.Errorf("%d: unexpected URL template: %s %s", i, actual, testCase.ExpectedFinalURL) + } + if r.URL().String() != full.String() { + t.Errorf("%d, creating URL template changed request: %s -> %s", i, full.String(), r.URL().String()) + } + } +} + +func TestTransformResponse(t *testing.T) { + invalid := []byte("aaaaa") + uri, _ := url.Parse("http://localhost") + testCases := []struct { + Response *http.Response + Data []byte + Created bool + Error bool + ErrFn func(err error) bool + }{ + {Response: &http.Response{StatusCode: 200}, Data: []byte{}}, + {Response: &http.Response{StatusCode: 201}, Data: []byte{}, Created: true}, + {Response: &http.Response{StatusCode: 199}, Error: true}, + {Response: &http.Response{StatusCode: 500}, Error: true}, + {Response: &http.Response{StatusCode: 422}, Error: true}, + {Response: &http.Response{StatusCode: 409}, Error: true}, + {Response: &http.Response{StatusCode: 404}, Error: true}, + {Response: &http.Response{StatusCode: 401}, Error: true}, + { + Response: &http.Response{ + StatusCode: 401, + Header: http.Header{"Content-Type": []string{"application/json"}}, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Error: true, + ErrFn: func(err error) bool { + return err.Error() != "aaaaa" && apierrors.IsUnauthorized(err) + }, + }, + { + Response: &http.Response{ + StatusCode: 401, + Header: http.Header{"Content-Type": []string{"text/any"}}, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Error: true, + ErrFn: func(err error) bool { + return strings.Contains(err.Error(), "server has asked for the client to provide") && apierrors.IsUnauthorized(err) + }, + }, + {Response: &http.Response{StatusCode: 403}, Error: true}, + {Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid}, + {Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid}, + } + for i, test := range testCases { + r := NewRequest(nil, "", uri, "", defaultContentConfig(), defaultSerializers(t), nil, nil, 0) + if test.Response.Body == nil { + test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) + } + result := r.transformResponse(test.Response, &http.Request{}) + response, created, err := result.body, result.statusCode == http.StatusCreated, result.err + hasErr := err != nil + if hasErr != test.Error { + t.Errorf("%d: unexpected error: %t %v", i, test.Error, err) + } else if hasErr && test.Response.StatusCode > 399 { + status, ok := err.(apierrors.APIStatus) + if !ok { + t.Errorf("%d: response should have been transformable into APIStatus: %v", i, err) + continue + } + if int(status.Status().Code) != test.Response.StatusCode { + t.Errorf("%d: status code did not match response: %#v", i, status.Status()) + } + } + if test.ErrFn != nil && !test.ErrFn(err) { + t.Errorf("%d: error function did not match: %v", i, err) + } + if !(test.Data == nil && response == nil) && !apiequality.Semantic.DeepDerivative(test.Data, response) { + t.Errorf("%d: unexpected response: %#v %#v", i, test.Data, response) + } + if test.Created != created { + t.Errorf("%d: expected created %t, got %t", i, test.Created, created) + } + } +} + +type renegotiator struct { + called bool + contentType string + params map[string]string + decoder runtime.Decoder + err error +} + +func (r *renegotiator) invoke(contentType string, params map[string]string) (runtime.Decoder, error) { + r.called = true + r.contentType = contentType + r.params = params + return r.decoder, r.err +} + +func TestTransformResponseNegotiate(t *testing.T) { + invalid := []byte("aaaaa") + uri, _ := url.Parse("http://localhost") + testCases := []struct { + Response *http.Response + Data []byte + Created bool + Error bool + ErrFn func(err error) bool + + ContentType string + Called bool + ExpectContentType string + Decoder runtime.Decoder + NegotiateErr error + }{ + { + ContentType: "application/json", + Response: &http.Response{ + StatusCode: 401, + Header: http.Header{"Content-Type": []string{"application/json"}}, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Error: true, + ErrFn: func(err error) bool { + return err.Error() != "aaaaa" && apierrors.IsUnauthorized(err) + }, + }, + { + ContentType: "application/json", + Response: &http.Response{ + StatusCode: 401, + Header: http.Header{"Content-Type": []string{"application/protobuf"}}, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Decoder: scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), + + Called: true, + ExpectContentType: "application/protobuf", + + Error: true, + ErrFn: func(err error) bool { + return err.Error() != "aaaaa" && apierrors.IsUnauthorized(err) + }, + }, + { + ContentType: "application/json", + Response: &http.Response{ + StatusCode: 500, + Header: http.Header{"Content-Type": []string{"application/,others"}}, + }, + Decoder: scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), + + Error: true, + ErrFn: func(err error) bool { + return err.Error() == "Internal error occurred: mime: expected token after slash" && err.(apierrors.APIStatus).Status().Code == 500 + }, + }, + { + // no negotiation when no content type specified + Response: &http.Response{ + StatusCode: 200, + Header: http.Header{"Content-Type": []string{"text/any"}}, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Decoder: scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), + }, + { + // no negotiation when no response content type specified + ContentType: "text/any", + Response: &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Decoder: scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), + }, + { + // unrecognized content type is not handled + ContentType: "application/json", + Response: &http.Response{ + StatusCode: 404, + Header: http.Header{"Content-Type": []string{"application/unrecognized"}}, + Body: ioutil.NopCloser(bytes.NewReader(invalid)), + }, + Decoder: scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), + + NegotiateErr: fmt.Errorf("aaaa"), + Called: true, + ExpectContentType: "application/unrecognized", + + Error: true, + ErrFn: func(err error) bool { + return err.Error() != "aaaaa" && apierrors.IsNotFound(err) + }, + }, + } + for i, test := range testCases { + serializers := defaultSerializers(t) + negotiator := &renegotiator{ + decoder: test.Decoder, + err: test.NegotiateErr, + } + serializers.RenegotiatedDecoder = negotiator.invoke + contentConfig := defaultContentConfig() + contentConfig.ContentType = test.ContentType + r := NewRequest(nil, "", uri, "", contentConfig, serializers, nil, nil, 0) + if test.Response.Body == nil { + test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) + } + result := r.transformResponse(test.Response, &http.Request{}) + _, err := result.body, result.err + hasErr := err != nil + if hasErr != test.Error { + t.Errorf("%d: unexpected error: %t %v", i, test.Error, err) + continue + } else if hasErr && test.Response.StatusCode > 399 { + status, ok := err.(apierrors.APIStatus) + if !ok { + t.Errorf("%d: response should have been transformable into APIStatus: %v", i, err) + continue + } + if int(status.Status().Code) != test.Response.StatusCode { + t.Errorf("%d: status code did not match response: %#v", i, status.Status()) + } + } + if test.ErrFn != nil && !test.ErrFn(err) { + t.Errorf("%d: error function did not match: %v", i, err) + } + if negotiator.called != test.Called { + t.Errorf("%d: negotiator called %t != %t", i, negotiator.called, test.Called) + } + if !test.Called { + continue + } + if negotiator.contentType != test.ExpectContentType { + t.Errorf("%d: unexpected content type: %s", i, negotiator.contentType) + } + } +} + +func TestTransformUnstructuredError(t *testing.T) { + testCases := []struct { + Req *http.Request + Res *http.Response + + Resource string + Name string + + ErrFn func(error) bool + Transformed error + }{ + { + Resource: "foo", + Name: "bar", + Req: &http.Request{ + Method: "POST", + }, + Res: &http.Response{ + StatusCode: http.StatusConflict, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + }, + ErrFn: apierrors.IsAlreadyExists, + }, + { + Resource: "foo", + Name: "bar", + Req: &http.Request{ + Method: "PUT", + }, + Res: &http.Response{ + StatusCode: http.StatusConflict, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + }, + ErrFn: apierrors.IsConflict, + }, + { + Resource: "foo", + Name: "bar", + Req: &http.Request{}, + Res: &http.Response{ + StatusCode: http.StatusNotFound, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + }, + ErrFn: apierrors.IsNotFound, + }, + { + Req: &http.Request{}, + Res: &http.Response{ + StatusCode: http.StatusBadRequest, + Body: ioutil.NopCloser(bytes.NewReader(nil)), + }, + ErrFn: apierrors.IsBadRequest, + }, + { + // status in response overrides transformed result + Req: &http.Request{}, + Res: &http.Response{StatusCode: http.StatusBadRequest, Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"kind":"Status","apiVersion":"v1","status":"Failure","code":404}`)))}, + ErrFn: apierrors.IsBadRequest, + Transformed: &apierrors.StatusError{ + ErrStatus: metav1.Status{Status: metav1.StatusFailure, Code: http.StatusNotFound}, + }, + }, + { + // successful status is ignored + Req: &http.Request{}, + Res: &http.Response{StatusCode: http.StatusBadRequest, Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"kind":"Status","apiVersion":"v1","status":"Success","code":404}`)))}, + ErrFn: apierrors.IsBadRequest, + }, + { + // empty object does not change result + Req: &http.Request{}, + Res: &http.Response{StatusCode: http.StatusBadRequest, Body: ioutil.NopCloser(bytes.NewReader([]byte(`{}`)))}, + ErrFn: apierrors.IsBadRequest, + }, + { + // we default apiVersion for backwards compatibility with old clients + // TODO: potentially remove in 1.7 + Req: &http.Request{}, + Res: &http.Response{StatusCode: http.StatusBadRequest, Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"kind":"Status","status":"Failure","code":404}`)))}, + ErrFn: apierrors.IsBadRequest, + Transformed: &apierrors.StatusError{ + ErrStatus: metav1.Status{Status: metav1.StatusFailure, Code: http.StatusNotFound}, + }, + }, + { + // we do not default kind + Req: &http.Request{}, + Res: &http.Response{StatusCode: http.StatusBadRequest, Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"status":"Failure","code":404}`)))}, + ErrFn: apierrors.IsBadRequest, + }, + } + + for i, testCase := range testCases { + r := &Request{ + content: defaultContentConfig(), + serializers: defaultSerializers(t), + resourceName: testCase.Name, + resource: testCase.Resource, + } + result := r.transformResponse(testCase.Res, testCase.Req) + err := result.err + if !testCase.ErrFn(err) { + t.Errorf("unexpected error: %v", err) + continue + } + if !apierrors.IsUnexpectedServerError(err) { + t.Errorf("%d: unexpected error type: %v", i, err) + } + if len(testCase.Name) != 0 && !strings.Contains(err.Error(), testCase.Name) { + t.Errorf("unexpected error string: %s", err) + } + if len(testCase.Resource) != 0 && !strings.Contains(err.Error(), testCase.Resource) { + t.Errorf("unexpected error string: %s", err) + } + + // verify Error() properly transforms the error + transformed := result.Error() + expect := testCase.Transformed + if expect == nil { + expect = err + } + if !reflect.DeepEqual(expect, transformed) { + t.Errorf("%d: unexpected Error(): %s", i, diff.ObjectReflectDiff(expect, transformed)) + } + + // verify result.Get properly transforms the error + if _, err := result.Get(); !reflect.DeepEqual(expect, err) { + t.Errorf("%d: unexpected error on Get(): %s", i, diff.ObjectReflectDiff(expect, err)) + } + + // verify result.Into properly handles the error + if err := result.Into(&v1.Pod{}); !reflect.DeepEqual(expect, err) { + t.Errorf("%d: unexpected error on Into(): %s", i, diff.ObjectReflectDiff(expect, err)) + } + + // verify result.Raw leaves the error in the untransformed state + if _, err := result.Raw(); !reflect.DeepEqual(result.err, err) { + t.Errorf("%d: unexpected error on Raw(): %s", i, diff.ObjectReflectDiff(expect, err)) + } + } +} + +func TestRequestWatch(t *testing.T) { + testCases := []struct { + Request *Request + Err bool + ErrFn func(error) bool + Empty bool + }{ + { + Request: &Request{err: errors.New("bail")}, + Err: true, + }, + { + Request: &Request{baseURL: &url.URL{}, pathPrefix: "%"}, + Err: true, + }, + { + Request: &Request{ + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, errors.New("err") + }), + baseURL: &url.URL{}, + }, + Err: true, + }, + { + Request: &Request{ + content: defaultContentConfig(), + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusForbidden, + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + }, nil + }), + baseURL: &url.URL{}, + }, + Err: true, + ErrFn: func(err error) bool { + return apierrors.IsForbidden(err) + }, + }, + { + Request: &Request{ + content: defaultContentConfig(), + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusUnauthorized, + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + }, nil + }), + baseURL: &url.URL{}, + }, + Err: true, + ErrFn: func(err error) bool { + return apierrors.IsUnauthorized(err) + }, + }, + { + Request: &Request{ + content: defaultContentConfig(), + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusUnauthorized, + Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &metav1.Status{ + Status: metav1.StatusFailure, + Reason: metav1.StatusReasonUnauthorized, + })))), + }, nil + }), + baseURL: &url.URL{}, + }, + Err: true, + ErrFn: func(err error) bool { + return apierrors.IsUnauthorized(err) + }, + }, + { + Request: &Request{ + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, io.EOF + }), + baseURL: &url.URL{}, + }, + Empty: true, + }, + { + Request: &Request{ + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, &url.Error{Err: io.EOF} + }), + baseURL: &url.URL{}, + }, + Empty: true, + }, + { + Request: &Request{ + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, errors.New("http: can't write HTTP request on broken connection") + }), + baseURL: &url.URL{}, + }, + Empty: true, + }, + { + Request: &Request{ + serializers: defaultSerializers(t), + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, errors.New("foo: connection reset by peer") + }), + baseURL: &url.URL{}, + }, + Empty: true, + }, + } + for i, testCase := range testCases { + t.Logf("testcase %v", testCase.Request) + testCase.Request.backoffMgr = &NoBackoff{} + watch, err := testCase.Request.Watch() + hasErr := err != nil + if hasErr != testCase.Err { + t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, err) + continue + } + if testCase.ErrFn != nil && !testCase.ErrFn(err) { + t.Errorf("%d: error not valid: %v", i, err) + } + if hasErr && watch != nil { + t.Errorf("%d: watch should be nil when error is returned", i) + continue + } + if testCase.Empty { + _, ok := <-watch.ResultChan() + if ok { + t.Errorf("%d: expected the watch to be empty: %#v", i, watch) + } + } + } +} + +func TestRequestStream(t *testing.T) { + testCases := []struct { + Request *Request + Err bool + ErrFn func(error) bool + }{ + { + Request: &Request{err: errors.New("bail")}, + Err: true, + }, + { + Request: &Request{baseURL: &url.URL{}, pathPrefix: "%"}, + Err: true, + }, + { + Request: &Request{ + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, errors.New("err") + }), + baseURL: &url.URL{}, + }, + Err: true, + }, + { + Request: &Request{ + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusUnauthorized, + Body: ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &metav1.Status{ + Status: metav1.StatusFailure, + Reason: metav1.StatusReasonUnauthorized, + })))), + }, nil + }), + content: defaultContentConfig(), + serializers: defaultSerializers(t), + baseURL: &url.URL{}, + }, + Err: true, + }, + { + Request: &Request{ + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusBadRequest, + Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"a container name must be specified for pod kube-dns-v20-mz5cv, choose one of: [kubedns dnsmasq healthz]","reason":"BadRequest","code":400}`))), + }, nil + }), + content: defaultContentConfig(), + serializers: defaultSerializers(t), + baseURL: &url.URL{}, + }, + Err: true, + ErrFn: func(err error) bool { + if err.Error() == "a container name must be specified for pod kube-dns-v20-mz5cv, choose one of: [kubedns dnsmasq healthz]" { + return true + } + return false + }, + }, + } + for i, testCase := range testCases { + testCase.Request.backoffMgr = &NoBackoff{} + body, err := testCase.Request.Stream() + hasErr := err != nil + if hasErr != testCase.Err { + t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, err) + } + if hasErr && body != nil { + t.Errorf("%d: body should be nil when error is returned", i) + } + + if hasErr { + if testCase.ErrFn != nil && !testCase.ErrFn(err) { + t.Errorf("unexpected error: %v", err) + } + } + } +} + +type fakeUpgradeConnection struct{} + +func (c *fakeUpgradeConnection) CreateStream(headers http.Header) (httpstream.Stream, error) { + return nil, nil +} +func (c *fakeUpgradeConnection) Close() error { + return nil +} +func (c *fakeUpgradeConnection) CloseChan() <-chan bool { + return make(chan bool) +} +func (c *fakeUpgradeConnection) SetIdleTimeout(timeout time.Duration) { +} + +type fakeUpgradeRoundTripper struct { + req *http.Request + conn httpstream.Connection +} + +func (f *fakeUpgradeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + f.req = req + b := []byte{} + body := ioutil.NopCloser(bytes.NewReader(b)) + resp := &http.Response{ + StatusCode: 101, + Body: body, + } + return resp, nil +} + +func (f *fakeUpgradeRoundTripper) NewConnection(resp *http.Response) (httpstream.Connection, error) { + return f.conn, nil +} + +func TestRequestDo(t *testing.T) { + testCases := []struct { + Request *Request + Err bool + }{ + { + Request: &Request{err: errors.New("bail")}, + Err: true, + }, + { + Request: &Request{baseURL: &url.URL{}, pathPrefix: "%"}, + Err: true, + }, + { + Request: &Request{ + client: clientFunc(func(req *http.Request) (*http.Response, error) { + return nil, errors.New("err") + }), + baseURL: &url.URL{}, + }, + Err: true, + }, + } + for i, testCase := range testCases { + testCase.Request.backoffMgr = &NoBackoff{} + body, err := testCase.Request.Do().Raw() + hasErr := err != nil + if hasErr != testCase.Err { + t.Errorf("%d: expected %t, got %t: %v", i, testCase.Err, hasErr, err) + } + if hasErr && body != nil { + t.Errorf("%d: body should be nil when error is returned", i) + } + } +} + +func TestDoRequestNewWay(t *testing.T) { + reqBody := "request body" + expectedObj := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{ + Protocol: "TCP", + Port: 12345, + TargetPort: intstr.FromInt(12345), + }}}} + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), expectedObj) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 200, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + c := testRESTClient(t, testServer) + obj, err := c.Verb("POST"). + Prefix("foo", "bar"). + Suffix("baz"). + Timeout(time.Second). + Body([]byte(reqBody)). + Do().Get() + if err != nil { + t.Errorf("Unexpected error: %v %#v", err, err) + return + } + if obj == nil { + t.Error("nil obj") + } else if !apiequality.Semantic.DeepDerivative(expectedObj, obj) { + t.Errorf("Expected: %#v, got %#v", expectedObj, obj) + } + requestURL := defaultResourcePathWithPrefix("foo/bar", "", "", "baz") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &reqBody) +} + +// This test assumes that the client implementation backs off exponentially, for an individual request. +func TestBackoffLifecycle(t *testing.T) { + count := 0 + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + count++ + t.Logf("Attempt %d", count) + if count == 5 || count == 9 { + w.WriteHeader(http.StatusOK) + return + } else { + w.WriteHeader(http.StatusGatewayTimeout) + return + } + })) + defer testServer.Close() + c := testRESTClient(t, testServer) + + // Test backoff recovery and increase. This correlates to the constants + // which are used in the server implementation returning StatusOK above. + seconds := []int{0, 1, 2, 4, 8, 0, 1, 2, 4, 0} + request := c.Verb("POST").Prefix("backofftest").Suffix("abc") + clock := clock.FakeClock{} + request.backoffMgr = &URLBackoff{ + // Use a fake backoff here to avoid flakes and speed the test up. + Backoff: flowcontrol.NewFakeBackOff( + time.Duration(1)*time.Second, + time.Duration(200)*time.Second, + &clock, + )} + + for _, sec := range seconds { + thisBackoff := request.backoffMgr.CalculateBackoff(request.URL()) + t.Logf("Current backoff %v", thisBackoff) + if thisBackoff != time.Duration(sec)*time.Second { + t.Errorf("Backoff is %v instead of %v", thisBackoff, sec) + } + now := clock.Now() + request.DoRaw() + elapsed := clock.Since(now) + if clock.Since(now) != thisBackoff { + t.Errorf("CalculatedBackoff not honored by clock: Expected time of %v, but got %v ", thisBackoff, elapsed) + } + } +} + +type testBackoffManager struct { + sleeps []time.Duration +} + +func (b *testBackoffManager) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) { +} + +func (b *testBackoffManager) CalculateBackoff(actualUrl *url.URL) time.Duration { + return time.Duration(0) +} + +func (b *testBackoffManager) Sleep(d time.Duration) { + b.sleeps = append(b.sleeps, d) +} + +func TestCheckRetryClosesBody(t *testing.T) { + count := 0 + ch := make(chan struct{}) + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + count++ + t.Logf("attempt %d", count) + if count >= 5 { + w.WriteHeader(http.StatusOK) + close(ch) + return + } + w.Header().Set("Retry-After", "1") + http.Error(w, "Too many requests, please try again later.", http.StatusTooManyRequests) + })) + defer testServer.Close() + + backoffMgr := &testBackoffManager{} + expectedSleeps := []time.Duration{0, time.Second, 0, time.Second, 0, time.Second, 0, time.Second, 0} + + c := testRESTClient(t, testServer) + c.createBackoffMgr = func() BackoffManager { return backoffMgr } + _, err := c.Verb("POST"). + Prefix("foo", "bar"). + Suffix("baz"). + Timeout(time.Second). + Body([]byte(strings.Repeat("abcd", 1000))). + DoRaw() + if err != nil { + t.Fatalf("Unexpected error: %v %#v", err, err) + } + <-ch + if count != 5 { + t.Errorf("unexpected retries: %d", count) + } + if !reflect.DeepEqual(backoffMgr.sleeps, expectedSleeps) { + t.Errorf("unexpected sleeps, expected: %v, got: %v", expectedSleeps, backoffMgr.sleeps) + } +} + +func TestConnectionResetByPeerIsRetried(t *testing.T) { + count := 0 + backoff := &testBackoffManager{} + req := &Request{ + verb: "GET", + client: clientFunc(func(req *http.Request) (*http.Response, error) { + count++ + if count >= 3 { + return &http.Response{ + StatusCode: 200, + Body: ioutil.NopCloser(bytes.NewReader([]byte{})), + }, nil + } + return nil, &net.OpError{Err: syscall.ECONNRESET} + }), + backoffMgr: backoff, + } + // We expect two retries of "connection reset by peer" and the success. + _, err := req.Do().Raw() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + // We have a sleep before each retry (including the initial one) and for + // every "retry-after" call - thus 5 together. + if len(backoff.sleeps) != 5 { + t.Errorf("Expected 5 retries, got: %d", len(backoff.sleeps)) + } +} + +func TestCheckRetryHandles429And5xx(t *testing.T) { + count := 0 + ch := make(chan struct{}) + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + data, err := ioutil.ReadAll(req.Body) + if err != nil { + t.Fatalf("unable to read request body: %v", err) + } + if !bytes.Equal(data, []byte(strings.Repeat("abcd", 1000))) { + t.Fatalf("retry did not send a complete body: %s", data) + } + t.Logf("attempt %d", count) + if count >= 4 { + w.WriteHeader(http.StatusOK) + close(ch) + return + } + w.Header().Set("Retry-After", "0") + w.WriteHeader([]int{http.StatusTooManyRequests, 500, 501, 504}[count]) + count++ + })) + defer testServer.Close() + + c := testRESTClient(t, testServer) + _, err := c.Verb("POST"). + Prefix("foo", "bar"). + Suffix("baz"). + Timeout(time.Second). + Body([]byte(strings.Repeat("abcd", 1000))). + DoRaw() + if err != nil { + t.Fatalf("Unexpected error: %v %#v", err, err) + } + <-ch + if count != 4 { + t.Errorf("unexpected retries: %d", count) + } +} + +func BenchmarkCheckRetryClosesBody(b *testing.B) { + count := 0 + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + count++ + if count%3 == 0 { + w.WriteHeader(http.StatusOK) + return + } + w.Header().Set("Retry-After", "0") + w.WriteHeader(http.StatusTooManyRequests) + })) + defer testServer.Close() + + c := testRESTClient(b, testServer) + r := c.Verb("POST"). + Prefix("foo", "bar"). + Suffix("baz"). + Timeout(time.Second). + Body([]byte(strings.Repeat("abcd", 1000))) + + for i := 0; i < b.N; i++ { + if _, err := r.DoRaw(); err != nil { + b.Fatalf("Unexpected error: %v %#v", err, err) + } + } +} + +func TestDoRequestNewWayReader(t *testing.T) { + reqObj := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + reqBodyExpected, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), reqObj) + expectedObj := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{ + Protocol: "TCP", + Port: 12345, + TargetPort: intstr.FromInt(12345), + }}}} + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), expectedObj) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 200, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + c := testRESTClient(t, testServer) + obj, err := c.Verb("POST"). + Resource("bar"). + Name("baz"). + Prefix("foo"). + Timeout(time.Second). + Body(bytes.NewBuffer(reqBodyExpected)). + Do().Get() + if err != nil { + t.Errorf("Unexpected error: %v %#v", err, err) + return + } + if obj == nil { + t.Error("nil obj") + } else if !apiequality.Semantic.DeepDerivative(expectedObj, obj) { + t.Errorf("Expected: %#v, got %#v", expectedObj, obj) + } + tmpStr := string(reqBodyExpected) + requestURL := defaultResourcePathWithPrefix("foo", "bar", "", "baz") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) +} + +func TestDoRequestNewWayObj(t *testing.T) { + reqObj := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + reqBodyExpected, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), reqObj) + expectedObj := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{ + Protocol: "TCP", + Port: 12345, + TargetPort: intstr.FromInt(12345), + }}}} + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), expectedObj) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 200, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + c := testRESTClient(t, testServer) + obj, err := c.Verb("POST"). + Suffix("baz"). + Name("bar"). + Resource("foo"). + Timeout(time.Second). + Body(reqObj). + Do().Get() + if err != nil { + t.Errorf("Unexpected error: %v %#v", err, err) + return + } + if obj == nil { + t.Error("nil obj") + } else if !apiequality.Semantic.DeepDerivative(expectedObj, obj) { + t.Errorf("Expected: %#v, got %#v", expectedObj, obj) + } + tmpStr := string(reqBodyExpected) + requestURL := defaultResourcePathWithPrefix("", "foo", "", "bar/baz") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) +} + +func TestDoRequestNewWayFile(t *testing.T) { + reqObj := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + reqBodyExpected, err := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), reqObj) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + file, err := ioutil.TempFile("", "foo") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + defer file.Close() + defer os.Remove(file.Name()) + + _, err = file.Write(reqBodyExpected) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + expectedObj := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{ + Protocol: "TCP", + Port: 12345, + TargetPort: intstr.FromInt(12345), + }}}} + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), expectedObj) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 200, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + c := testRESTClient(t, testServer) + wasCreated := true + obj, err := c.Verb("POST"). + Prefix("foo/bar", "baz"). + Timeout(time.Second). + Body(file.Name()). + Do().WasCreated(&wasCreated).Get() + if err != nil { + t.Errorf("Unexpected error: %v %#v", err, err) + return + } + if obj == nil { + t.Error("nil obj") + } else if !apiequality.Semantic.DeepDerivative(expectedObj, obj) { + t.Errorf("Expected: %#v, got %#v", expectedObj, obj) + } + if wasCreated { + t.Errorf("expected object was created") + } + tmpStr := string(reqBodyExpected) + requestURL := defaultResourcePathWithPrefix("foo/bar/baz", "", "", "") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) +} + +func TestWasCreated(t *testing.T) { + reqObj := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + reqBodyExpected, err := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), reqObj) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + expectedObj := &v1.Service{Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{ + Protocol: "TCP", + Port: 12345, + TargetPort: intstr.FromInt(12345), + }}}} + expectedBody, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), expectedObj) + fakeHandler := utiltesting.FakeHandler{ + StatusCode: 201, + ResponseBody: string(expectedBody), + T: t, + } + testServer := httptest.NewServer(&fakeHandler) + defer testServer.Close() + c := testRESTClient(t, testServer) + wasCreated := false + obj, err := c.Verb("PUT"). + Prefix("foo/bar", "baz"). + Timeout(time.Second). + Body(reqBodyExpected). + Do().WasCreated(&wasCreated).Get() + if err != nil { + t.Errorf("Unexpected error: %v %#v", err, err) + return + } + if obj == nil { + t.Error("nil obj") + } else if !apiequality.Semantic.DeepDerivative(expectedObj, obj) { + t.Errorf("Expected: %#v, got %#v", expectedObj, obj) + } + if !wasCreated { + t.Errorf("Expected object was created") + } + + tmpStr := string(reqBodyExpected) + requestURL := defaultResourcePathWithPrefix("foo/bar/baz", "", "", "") + requestURL += "?timeout=1s" + fakeHandler.ValidateRequest(t, requestURL, "PUT", &tmpStr) +} + +func TestVerbs(t *testing.T) { + c := testRESTClient(t, nil) + if r := c.Post(); r.verb != "POST" { + t.Errorf("Post verb is wrong") + } + if r := c.Put(); r.verb != "PUT" { + t.Errorf("Put verb is wrong") + } + if r := c.Get(); r.verb != "GET" { + t.Errorf("Get verb is wrong") + } + if r := c.Delete(); r.verb != "DELETE" { + t.Errorf("Delete verb is wrong") + } +} + +func TestAbsPath(t *testing.T) { + for i, tc := range []struct { + configPrefix string + resourcePrefix string + absPath string + wantsAbsPath string + }{ + {"/", "", "", "/"}, + {"", "", "/", "/"}, + {"", "", "/api", "/api"}, + {"", "", "/api/", "/api/"}, + {"", "", "/apis", "/apis"}, + {"", "/foo", "/bar/foo", "/bar/foo"}, + {"", "/api/foo/123", "/bar/foo", "/bar/foo"}, + {"/p1", "", "", "/p1"}, + {"/p1", "", "/", "/p1/"}, + {"/p1", "", "/api", "/p1/api"}, + {"/p1", "", "/apis", "/p1/apis"}, + {"/p1", "/r1", "/apis", "/p1/apis"}, + {"/p1", "/api/r1", "/apis", "/p1/apis"}, + {"/p1/api/p2", "", "", "/p1/api/p2"}, + {"/p1/api/p2", "", "/", "/p1/api/p2/"}, + {"/p1/api/p2", "", "/api", "/p1/api/p2/api"}, + {"/p1/api/p2", "", "/api/", "/p1/api/p2/api/"}, + {"/p1/api/p2", "/r1", "/api/", "/p1/api/p2/api/"}, + {"/p1/api/p2", "/api/r1", "/api/", "/p1/api/p2/api/"}, + } { + u, _ := url.Parse("http://localhost:123" + tc.configPrefix) + r := NewRequest(nil, "POST", u, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).Prefix(tc.resourcePrefix).AbsPath(tc.absPath) + if r.pathPrefix != tc.wantsAbsPath { + t.Errorf("test case %d failed, unexpected path: %q, expected %q", i, r.pathPrefix, tc.wantsAbsPath) + } + } +} + +func TestUnacceptableParamNames(t *testing.T) { + table := []struct { + name string + testVal string + expectSuccess bool + }{ + // timeout is no longer "protected" + {"timeout", "42", true}, + } + + for _, item := range table { + c := testRESTClient(t, nil) + r := c.Get().setParam(item.name, item.testVal) + if e, a := item.expectSuccess, r.err == nil; e != a { + t.Errorf("expected %v, got %v (%v)", e, a, r.err) + } + } +} + +func TestBody(t *testing.T) { + const data = "test payload" + + obj := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + bodyExpected, _ := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), obj) + + f, err := ioutil.TempFile("", "test_body") + if err != nil { + t.Fatalf("TempFile error: %v", err) + } + if _, err := f.WriteString(data); err != nil { + t.Fatalf("TempFile.WriteString error: %v", err) + } + f.Close() + defer os.Remove(f.Name()) + + var nilObject *metav1.DeleteOptions + typedObject := interface{}(nilObject) + c := testRESTClient(t, nil) + tests := []struct { + input interface{} + expected string + headers map[string]string + }{ + {[]byte(data), data, nil}, + {f.Name(), data, nil}, + {strings.NewReader(data), data, nil}, + {obj, string(bodyExpected), map[string]string{"Content-Type": "application/json"}}, + {typedObject, "", nil}, + } + for i, tt := range tests { + r := c.Post().Body(tt.input) + if r.err != nil { + t.Errorf("%d: r.Body(%#v) error: %v", i, tt, r.err) + continue + } + if tt.headers != nil { + for k, v := range tt.headers { + if r.headers.Get(k) != v { + t.Errorf("%d: r.headers[%q] = %q; want %q", i, k, v, v) + } + } + } + + if r.body == nil { + if len(tt.expected) != 0 { + t.Errorf("%d: r.body = %q; want %q", i, r.body, tt.expected) + } + continue + } + buf := make([]byte, len(tt.expected)) + if _, err := r.body.Read(buf); err != nil { + t.Errorf("%d: r.body.Read error: %v", i, err) + continue + } + body := string(buf) + if body != tt.expected { + t.Errorf("%d: r.body = %q; want %q", i, body, tt.expected) + } + } +} + +func TestWatch(t *testing.T) { + var table = []struct { + t watch.EventType + obj runtime.Object + }{ + {watch.Added, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "first"}}}, + {watch.Modified, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "second"}}}, + {watch.Deleted, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "last"}}}, + } + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + flusher, ok := w.(http.Flusher) + if !ok { + panic("need flusher!") + } + + w.Header().Set("Transfer-Encoding", "chunked") + w.WriteHeader(http.StatusOK) + flusher.Flush() + + encoder := restclientwatch.NewEncoder(streaming.NewEncoder(w, scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)), scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion)) + for _, item := range table { + if err := encoder.Encode(&watch.Event{Type: item.t, Object: item.obj}); err != nil { + panic(err) + } + flusher.Flush() + } + })) + defer testServer.Close() + + s := testRESTClient(t, testServer) + watching, err := s.Get().Prefix("path/to/watch/thing").Watch() + if err != nil { + t.Fatalf("Unexpected error") + } + + for _, item := range table { + got, ok := <-watching.ResultChan() + if !ok { + t.Fatalf("Unexpected early close") + } + if e, a := item.t, got.Type; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + if e, a := item.obj, got.Object; !apiequality.Semantic.DeepDerivative(e, a) { + t.Errorf("Expected %v, got %v", e, a) + } + } + + _, ok := <-watching.ResultChan() + if ok { + t.Fatal("Unexpected non-close") + } +} + +func TestStream(t *testing.T) { + expectedBody := "expected body" + + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + flusher, ok := w.(http.Flusher) + if !ok { + panic("need flusher!") + } + w.Header().Set("Transfer-Encoding", "chunked") + w.WriteHeader(http.StatusOK) + w.Write([]byte(expectedBody)) + flusher.Flush() + })) + defer testServer.Close() + + s := testRESTClient(t, testServer) + readCloser, err := s.Get().Prefix("path/to/stream/thing").Stream() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + defer readCloser.Close() + buf := new(bytes.Buffer) + buf.ReadFrom(readCloser) + resultBody := buf.String() + + if expectedBody != resultBody { + t.Errorf("Expected %s, got %s", expectedBody, resultBody) + } +} + +func testRESTClient(t testing.TB, srv *httptest.Server) *RESTClient { + baseURL, _ := url.Parse("http://localhost") + if srv != nil { + var err error + baseURL, err = url.Parse(srv.URL) + if err != nil { + t.Fatalf("failed to parse test URL: %v", err) + } + } + versionedAPIPath := defaultResourcePathWithPrefix("", "", "", "") + client, err := NewRESTClient(baseURL, versionedAPIPath, defaultContentConfig(), 0, 0, nil, nil) + if err != nil { + t.Fatalf("failed to create a client: %v", err) + } + return client +} + +func TestDoContext(t *testing.T) { + receivedCh := make(chan struct{}) + block := make(chan struct{}) + testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + close(receivedCh) + <-block + w.WriteHeader(http.StatusOK) + })) + defer testServer.Close() + defer close(block) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + <-receivedCh + cancel() + }() + + c := testRESTClient(t, testServer) + _, err := c.Verb("GET"). + Context(ctx). + Prefix("foo"). + DoRaw() + if err == nil { + t.Fatal("Expected context cancellation error") + } +} + +func buildString(length int) string { + s := make([]byte, length) + for i := range s { + s[i] = 'a' + } + return string(s) +} + +func TestTruncateBody(t *testing.T) { + tests := []struct { + body string + want string + level string + }{ + // Anything below 8 is completely truncated + { + body: "Completely truncated below 8", + want: " [truncated 28 chars]", + level: "0", + }, + // Small strings are not truncated by high levels + { + body: "Small body never gets truncated", + want: "Small body never gets truncated", + level: "10", + }, + { + body: "Small body never gets truncated", + want: "Small body never gets truncated", + level: "8", + }, + // Strings are truncated to 1024 if level is less than 9. + { + body: buildString(2000), + level: "8", + want: fmt.Sprintf("%s [truncated 976 chars]", buildString(1024)), + }, + // Strings are truncated to 10240 if level is 9. + { + body: buildString(20000), + level: "9", + want: fmt.Sprintf("%s [truncated 9760 chars]", buildString(10240)), + }, + // Strings are not truncated if level is 10 or higher + { + body: buildString(20000), + level: "10", + want: buildString(20000), + }, + // Strings are not truncated if level is 10 or higher + { + body: buildString(20000), + level: "11", + want: buildString(20000), + }, + } + + l := flag.Lookup("v").Value.(flag.Getter).Get().(glog.Level) + for _, test := range tests { + flag.Set("v", test.level) + got := truncateBody(test.body) + if got != test.want { + t.Errorf("truncateBody(%v) = %v, want %v", test.body, got, test.want) + } + } + flag.Set("v", l.String()) +} + +func defaultResourcePathWithPrefix(prefix, resource, namespace, name string) string { + var path string + path = "/api/" + v1.SchemeGroupVersion.Version + + if prefix != "" { + path = path + "/" + prefix + } + if namespace != "" { + path = path + "/namespaces/" + namespace + } + // Resource names are lower case. + resource = strings.ToLower(resource) + if resource != "" { + path = path + "/" + resource + } + if name != "" { + path = path + "/" + name + } + return path +} diff --git a/vendor/k8s.io/client-go/rest/token_source_test.go b/vendor/k8s.io/client-go/rest/token_source_test.go new file mode 100644 index 000000000..40851f80d --- /dev/null +++ b/vendor/k8s.io/client-go/rest/token_source_test.go @@ -0,0 +1,156 @@ +/* +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. +*/ + +package rest + +import ( + "fmt" + "reflect" + "sync" + "testing" + "time" + + "golang.org/x/oauth2" +) + +type testTokenSource struct { + calls int + tok *oauth2.Token + err error +} + +func (ts *testTokenSource) Token() (*oauth2.Token, error) { + ts.calls++ + return ts.tok, ts.err +} + +func TestCachingTokenSource(t *testing.T) { + start := time.Now() + tokA := &oauth2.Token{ + AccessToken: "a", + Expiry: start.Add(10 * time.Minute), + } + tokB := &oauth2.Token{ + AccessToken: "b", + Expiry: start.Add(20 * time.Minute), + } + tests := []struct { + name string + + tok *oauth2.Token + tsTok *oauth2.Token + tsErr error + wait time.Duration + + wantTok *oauth2.Token + wantErr bool + wantTSCalls int + }{ + { + name: "valid token returned from cache", + tok: tokA, + wantTok: tokA, + }, + { + name: "valid token returned from cache 1 minute before scheduled refresh", + tok: tokA, + wait: 8 * time.Minute, + wantTok: tokA, + }, + { + name: "new token created when cache is empty", + tsTok: tokA, + wantTok: tokA, + wantTSCalls: 1, + }, + { + name: "new token created 1 minute after scheduled refresh", + tok: tokA, + tsTok: tokB, + wait: 10 * time.Minute, + wantTok: tokB, + wantTSCalls: 1, + }, + { + name: "error on create token returns error", + tsErr: fmt.Errorf("error"), + wantErr: true, + wantTSCalls: 1, + }, + } + for _, c := range tests { + t.Run(c.name, func(t *testing.T) { + tts := &testTokenSource{ + tok: c.tsTok, + err: c.tsErr, + } + + ts := &cachingTokenSource{ + base: tts, + tok: c.tok, + leeway: 1 * time.Minute, + now: func() time.Time { return start.Add(c.wait) }, + } + + gotTok, gotErr := ts.Token() + if got, want := gotTok, c.wantTok; !reflect.DeepEqual(got, want) { + t.Errorf("unexpected token:\n\tgot:\t%#v\n\twant:\t%#v", got, want) + } + if got, want := tts.calls, c.wantTSCalls; got != want { + t.Errorf("unexpected number of Token() calls: got %d, want %d", got, want) + } + if gotErr == nil && c.wantErr { + t.Errorf("wanted error but got none") + } + if gotErr != nil && !c.wantErr { + t.Errorf("unexpected error: %v", gotErr) + } + }) + } +} + +func TestCachingTokenSourceRace(t *testing.T) { + for i := 0; i < 100; i++ { + tts := &testTokenSource{ + tok: &oauth2.Token{ + AccessToken: "a", + Expiry: time.Now().Add(1000 * time.Hour), + }, + } + + ts := &cachingTokenSource{ + now: time.Now, + base: tts, + leeway: 1 * time.Minute, + } + + var wg sync.WaitGroup + wg.Add(100) + + for i := 0; i < 100; i++ { + go func() { + defer wg.Done() + if _, err := ts.Token(); err != nil { + t.Fatalf("err: %v", err) + } + }() + } + wg.Wait() + if tts.calls != 1 { + t.Errorf("expected one call to Token() but saw: %d", tts.calls) + } + } +} diff --git a/vendor/k8s.io/client-go/rest/url_utils_test.go b/vendor/k8s.io/client-go/rest/url_utils_test.go new file mode 100644 index 000000000..6321678a4 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/url_utils_test.go @@ -0,0 +1,61 @@ +/* +Copyright 2016 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 rest + +import ( + "path" + "testing" + + "k8s.io/api/core/v1" +) + +func TestValidatesHostParameter(t *testing.T) { + testCases := []struct { + Host string + APIPath string + + URL string + Err bool + }{ + {"127.0.0.1", "", "http://127.0.0.1/" + v1.SchemeGroupVersion.Version, false}, + {"127.0.0.1:8080", "", "http://127.0.0.1:8080/" + v1.SchemeGroupVersion.Version, false}, + {"foo.bar.com", "", "http://foo.bar.com/" + v1.SchemeGroupVersion.Version, false}, + {"http://host/prefix", "", "http://host/prefix/" + v1.SchemeGroupVersion.Version, false}, + {"http://host", "", "http://host/" + v1.SchemeGroupVersion.Version, false}, + {"http://host", "/", "http://host/" + v1.SchemeGroupVersion.Version, false}, + {"http://host", "/other", "http://host/other/" + v1.SchemeGroupVersion.Version, false}, + {"host/server", "", "", true}, + } + for i, testCase := range testCases { + u, versionedAPIPath, err := DefaultServerURL(testCase.Host, testCase.APIPath, v1.SchemeGroupVersion, false) + switch { + case err == nil && testCase.Err: + t.Errorf("expected error but was nil") + continue + case err != nil && !testCase.Err: + t.Errorf("unexpected error %v", err) + continue + case err != nil: + continue + } + u.Path = path.Join(u.Path, versionedAPIPath) + if e, a := testCase.URL, u.String(); e != a { + t.Errorf("%d: expected host %s, got %s", i, e, a) + continue + } + } +} diff --git a/vendor/k8s.io/client-go/rest/urlbackoff_test.go b/vendor/k8s.io/client-go/rest/urlbackoff_test.go new file mode 100644 index 000000000..c5f439238 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/urlbackoff_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2014 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 rest + +import ( + "net/url" + "testing" + "time" + + "k8s.io/client-go/util/flowcontrol" +) + +func parse(raw string) *url.URL { + theUrl, _ := url.Parse(raw) + return theUrl +} + +func TestURLBackoffFunctionalityCollisions(t *testing.T) { + myBackoff := &URLBackoff{ + Backoff: flowcontrol.NewBackOff(1*time.Second, 60*time.Second), + } + + // Add some noise and make sure backoff for a clean URL is zero. + myBackoff.UpdateBackoff(parse("http://100.200.300.400:8080"), nil, 500) + + myBackoff.UpdateBackoff(parse("http://1.2.3.4:8080"), nil, 500) + + if myBackoff.CalculateBackoff(parse("http://1.2.3.4:100")) > 0 { + t.Errorf("URLs are colliding in the backoff map!") + } +} + +// TestURLBackoffFunctionality generally tests the URLBackoff wrapper. We avoid duplicating tests from backoff and request. +func TestURLBackoffFunctionality(t *testing.T) { + myBackoff := &URLBackoff{ + Backoff: flowcontrol.NewBackOff(1*time.Second, 60*time.Second), + } + + // Now test that backoff increases, then recovers. + // 200 and 300 should both result in clearing the backoff. + // all others like 429 should result in increased backoff. + seconds := []int{0, + 1, 2, 4, 8, 0, + 1, 2} + returnCodes := []int{ + 429, 500, 501, 502, 300, + 500, 501, 502, + } + + if len(seconds) != len(returnCodes) { + t.Fatalf("responseCode to backoff arrays should be the same length... sanity check failed.") + } + + for i, sec := range seconds { + backoffSec := myBackoff.CalculateBackoff(parse("http://1.2.3.4:100")) + if backoffSec < time.Duration(sec)*time.Second || backoffSec > time.Duration(sec+5)*time.Second { + t.Errorf("Backoff out of range %v: %v %v", i, sec, backoffSec) + } + myBackoff.UpdateBackoff(parse("http://1.2.3.4:100/responseCodeForFuncTest"), nil, returnCodes[i]) + } + + if myBackoff.CalculateBackoff(parse("http://1.2.3.4:100")) == 0 { + t.Errorf("The final return code %v should have resulted in a backoff ! ", returnCodes[7]) + } +} diff --git a/vendor/k8s.io/client-go/rest/watch/decoder_test.go b/vendor/k8s.io/client-go/rest/watch/decoder_test.go new file mode 100644 index 000000000..2d29d437d --- /dev/null +++ b/vendor/k8s.io/client-go/rest/watch/decoder_test.go @@ -0,0 +1,123 @@ +/* +Copyright 2014 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 versioned_test + +import ( + "encoding/json" + "io" + "testing" + "time" + + "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + runtimejson "k8s.io/apimachinery/pkg/runtime/serializer/json" + "k8s.io/apimachinery/pkg/runtime/serializer/streaming" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes/scheme" + restclientwatch "k8s.io/client-go/rest/watch" +) + +// getDecoder mimics how k8s.io/client-go/rest.createSerializers creates a decoder +func getDecoder() runtime.Decoder { + jsonSerializer := runtimejson.NewSerializer(runtimejson.DefaultMetaFactory, scheme.Scheme, scheme.Scheme, false) + directCodecFactory := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + return directCodecFactory.DecoderToVersion(jsonSerializer, v1.SchemeGroupVersion) +} + +func TestDecoder(t *testing.T) { + table := []watch.EventType{watch.Added, watch.Deleted, watch.Modified, watch.Error} + + for _, eventType := range table { + out, in := io.Pipe() + + decoder := restclientwatch.NewDecoder(streaming.NewDecoder(out, getDecoder()), getDecoder()) + + expect := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + encoder := json.NewEncoder(in) + go func() { + data, err := runtime.Encode(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), expect) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + event := metav1.WatchEvent{ + Type: string(eventType), + Object: runtime.RawExtension{Raw: json.RawMessage(data)}, + } + if err := encoder.Encode(&event); err != nil { + t.Errorf("Unexpected error %v", err) + } + in.Close() + }() + + done := make(chan struct{}) + go func() { + action, got, err := decoder.Decode() + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if e, a := eventType, action; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + if e, a := expect, got; !apiequality.Semantic.DeepDerivative(e, a) { + t.Errorf("Expected %v, got %v", e, a) + } + t.Logf("Exited read") + close(done) + }() + <-done + + done = make(chan struct{}) + go func() { + _, _, err := decoder.Decode() + if err == nil { + t.Errorf("Unexpected nil error") + } + close(done) + }() + <-done + + decoder.Close() + } +} + +func TestDecoder_SourceClose(t *testing.T) { + out, in := io.Pipe() + decoder := restclientwatch.NewDecoder(streaming.NewDecoder(out, getDecoder()), getDecoder()) + + done := make(chan struct{}) + + go func() { + _, _, err := decoder.Decode() + if err == nil { + t.Errorf("Unexpected nil error") + } + close(done) + }() + + in.Close() + + select { + case <-done: + break + case <-time.After(wait.ForeverTestTimeout): + t.Error("Timeout") + } +} diff --git a/vendor/k8s.io/client-go/rest/watch/encoder_test.go b/vendor/k8s.io/client-go/rest/watch/encoder_test.go new file mode 100644 index 000000000..1388d1cc6 --- /dev/null +++ b/vendor/k8s.io/client-go/rest/watch/encoder_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2014 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 versioned_test + +import ( + "bytes" + "io/ioutil" + "testing" + + "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + runtimejson "k8s.io/apimachinery/pkg/runtime/serializer/json" + "k8s.io/apimachinery/pkg/runtime/serializer/streaming" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes/scheme" + restclientwatch "k8s.io/client-go/rest/watch" +) + +// getEncoder mimics how k8s.io/client-go/rest.createSerializers creates a encoder +func getEncoder() runtime.Encoder { + jsonSerializer := runtimejson.NewSerializer(runtimejson.DefaultMetaFactory, scheme.Scheme, scheme.Scheme, false) + directCodecFactory := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + return directCodecFactory.EncoderForVersion(jsonSerializer, v1.SchemeGroupVersion) +} + +func TestEncodeDecodeRoundTrip(t *testing.T) { + testCases := []struct { + Type watch.EventType + Object runtime.Object + }{ + { + watch.Added, + &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, + }, + { + watch.Modified, + &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, + }, + { + watch.Deleted, + &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, + }, + } + for i, testCase := range testCases { + buf := &bytes.Buffer{} + + encoder := restclientwatch.NewEncoder(streaming.NewEncoder(buf, getEncoder()), getEncoder()) + if err := encoder.Encode(&watch.Event{Type: testCase.Type, Object: testCase.Object}); err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + continue + } + + rc := ioutil.NopCloser(buf) + decoder := restclientwatch.NewDecoder(streaming.NewDecoder(rc, getDecoder()), getDecoder()) + event, obj, err := decoder.Decode() + if err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + continue + } + if !apiequality.Semantic.DeepDerivative(testCase.Object, obj) { + t.Errorf("%d: expected %#v, got %#v", i, testCase.Object, obj) + } + if event != testCase.Type { + t.Errorf("%d: unexpected type: %#v", i, event) + } + } +} diff --git a/vendor/k8s.io/client-go/testing/fixture_test.go b/vendor/k8s.io/client-go/testing/fixture_test.go new file mode 100644 index 000000000..405fe1a7e --- /dev/null +++ b/vendor/k8s.io/client-go/testing/fixture_test.go @@ -0,0 +1,235 @@ +/* +Copyright 2015 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 testing + +import ( + "fmt" + "math/rand" + "strconv" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/watch" +) + +func getArbitraryResource(s schema.GroupVersionResource, name, namespace string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "kind": s.Resource, + "apiVersion": s.Version, + "metadata": map[string]interface{}{ + "name": name, + "namespace": namespace, + "generateName": "test_generateName", + "uid": "test_uid", + "resourceVersion": "test_resourceVersion", + "selfLink": "test_selfLink", + }, + "data": strconv.Itoa(rand.Int()), + }, + } +} + +func TestWatchCallNonNamespace(t *testing.T) { + testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"} + testObj := getArbitraryResource(testResource, "test_name", "test_namespace") + accessor, err := meta.Accessor(testObj) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + ns := accessor.GetNamespace() + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + o := NewObjectTracker(scheme, codecs.UniversalDecoder()) + watch, err := o.Watch(testResource, ns) + if err != nil { + t.Fatalf("test resource watch failed in %s: %v ", ns, err) + } + go func() { + err := o.Create(testResource, testObj, ns) + if err != nil { + t.Errorf("test resource creation failed: %v", err) + } + }() + out := <-watch.ResultChan() + assert.Equal(t, testObj, out.Object, "watched object mismatch") +} + +func TestWatchCallAllNamespace(t *testing.T) { + testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"} + testObj := getArbitraryResource(testResource, "test_name", "test_namespace") + accessor, err := meta.Accessor(testObj) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + ns := accessor.GetNamespace() + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + o := NewObjectTracker(scheme, codecs.UniversalDecoder()) + w, err := o.Watch(testResource, "test_namespace") + if err != nil { + t.Fatalf("test resource watch failed in test_namespace: %v", err) + } + wAll, err := o.Watch(testResource, "") + if err != nil { + t.Fatalf("test resource watch failed in all namespaces: %v", err) + } + go func() { + err := o.Create(testResource, testObj, ns) + assert.NoError(t, err, "test resource creation failed") + }() + out := <-w.ResultChan() + outAll := <-wAll.ResultChan() + assert.Equal(t, watch.Added, out.Type, "watch event mismatch") + assert.Equal(t, watch.Added, outAll.Type, "watch event mismatch") + assert.Equal(t, testObj, out.Object, "watched created object mismatch") + assert.Equal(t, testObj, outAll.Object, "watched created object mismatch") + go func() { + err := o.Update(testResource, testObj, ns) + assert.NoError(t, err, "test resource updating failed") + }() + out = <-w.ResultChan() + outAll = <-wAll.ResultChan() + assert.Equal(t, watch.Modified, out.Type, "watch event mismatch") + assert.Equal(t, watch.Modified, outAll.Type, "watch event mismatch") + assert.Equal(t, testObj, out.Object, "watched updated object mismatch") + assert.Equal(t, testObj, outAll.Object, "watched updated object mismatch") + go func() { + err := o.Delete(testResource, "test_namespace", "test_name") + assert.NoError(t, err, "test resource deletion failed") + }() + out = <-w.ResultChan() + outAll = <-wAll.ResultChan() + assert.Equal(t, watch.Deleted, out.Type, "watch event mismatch") + assert.Equal(t, watch.Deleted, outAll.Type, "watch event mismatch") + assert.Equal(t, testObj, out.Object, "watched deleted object mismatch") + assert.Equal(t, testObj, outAll.Object, "watched deleted object mismatch") +} + +func TestWatchCallMultipleInvocation(t *testing.T) { + cases := []struct { + name string + op watch.EventType + }{ + { + "foo", + watch.Added, + }, + { + "bar", + watch.Added, + }, + { + "bar", + watch.Modified, + }, + { + "foo", + watch.Deleted, + }, + { + "bar", + watch.Deleted, + }, + } + + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"} + + o := NewObjectTracker(scheme, codecs.UniversalDecoder()) + watchNamespaces := []string{ + "", + "", + "test_namespace", + "test_namespace", + } + var wg sync.WaitGroup + wg.Add(len(watchNamespaces)) + for idx, watchNamespace := range watchNamespaces { + i := idx + w, err := o.Watch(testResource, watchNamespace) + if err != nil { + t.Fatalf("test resource watch failed in %s: %v", watchNamespace, err) + } + go func() { + assert.NoError(t, err, "watch invocation failed") + for _, c := range cases { + fmt.Printf("%#v %#v\n", c, i) + event := <-w.ResultChan() + accessor, err := meta.Accessor(event.Object) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + assert.Equal(t, c.op, event.Type, "watch event mismatched") + assert.Equal(t, c.name, accessor.GetName(), "watched object mismatch") + } + wg.Done() + }() + } + for _, c := range cases { + switch c.op { + case watch.Added: + obj := getArbitraryResource(testResource, c.name, "test_namespace") + o.Create(testResource, obj, "test_namespace") + case watch.Modified: + obj := getArbitraryResource(testResource, c.name, "test_namespace") + o.Update(testResource, obj, "test_namespace") + case watch.Deleted: + o.Delete(testResource, "test_namespace", c.name) + } + } + wg.Wait() +} + +func TestWatchAddAfterStop(t *testing.T) { + testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"} + testObj := getArbitraryResource(testResource, "test_name", "test_namespace") + accessor, err := meta.Accessor(testObj) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ns := accessor.GetNamespace() + scheme := runtime.NewScheme() + codecs := serializer.NewCodecFactory(scheme) + o := NewObjectTracker(scheme, codecs.UniversalDecoder()) + watch, err := o.Watch(testResource, ns) + if err != nil { + t.Errorf("watch creation failed: %v", err) + } + + // When the watch is stopped it should ignore later events without panicking. + defer func() { + if r := recover(); r != nil { + t.Errorf("Watch panicked when it should have ignored create after stop: %v", r) + } + }() + + watch.Stop() + err = o.Create(testResource, testObj, ns) + if err != nil { + t.Errorf("test resource creation failed: %v", err) + } +} diff --git a/vendor/k8s.io/client-go/tools/auth/clientauth_test.go b/vendor/k8s.io/client-go/tools/auth/clientauth_test.go new file mode 100644 index 000000000..11f7369de --- /dev/null +++ b/vendor/k8s.io/client-go/tools/auth/clientauth_test.go @@ -0,0 +1,69 @@ +/* +Copyright 2014 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 auth_test + +import ( + "io/ioutil" + "os" + "reflect" + "testing" + + clientauth "k8s.io/client-go/tools/auth" +) + +func TestLoadFromFile(t *testing.T) { + loadAuthInfoTests := []struct { + authData string + authInfo *clientauth.Info + expectErr bool + }{ + { + `{"user": "user", "password": "pass"}`, + &clientauth.Info{User: "user", Password: "pass"}, + false, + }, + { + "", nil, true, + }, + } + for _, loadAuthInfoTest := range loadAuthInfoTests { + tt := loadAuthInfoTest + aifile, err := ioutil.TempFile("", "testAuthInfo") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if tt.authData != "missing" { + defer os.Remove(aifile.Name()) + defer aifile.Close() + _, err = aifile.WriteString(tt.authData) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } else { + aifile.Close() + os.Remove(aifile.Name()) + } + authInfo, err := clientauth.LoadFromFile(aifile.Name()) + gotErr := err != nil + if gotErr != tt.expectErr { + t.Errorf("expected errorness: %v, actual errorness: %v", tt.expectErr, gotErr) + } + if !reflect.DeepEqual(authInfo, tt.authInfo) { + t.Errorf("Expected %v, got %v", tt.authInfo, authInfo) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/cache/OWNERS b/vendor/k8s.io/client-go/tools/cache/OWNERS new file mode 100755 index 000000000..727377f9d --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/OWNERS @@ -0,0 +1,50 @@ +approvers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- caesarxuchao +- liggitt +- ncdc +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- brendandburns +- derekwaynecarr +- caesarxuchao +- mikedanese +- liggitt +- nikhiljindal +- erictune +- davidopp +- pmorie +- kargakis +- janetkuo +- justinsb +- eparis +- soltysh +- jsafrane +- dims +- madhusudancs +- hongchaodeng +- krousey +- markturansky +- fgrzadkowski +- xiang90 +- mml +- ingvagabund +- resouer +- jessfraz +- david-mcmahon +- mfojtik +- '249043822' +- lixiaobing10051267 +- ddysher +- mqliang +- feihujiang +- sdminonne +- ncdc diff --git a/vendor/k8s.io/client-go/tools/cache/controller_test.go b/vendor/k8s.io/client-go/tools/cache/controller_test.go new file mode 100644 index 000000000..64aca8d7d --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/controller_test.go @@ -0,0 +1,405 @@ +/* +Copyright 2015 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 cache + +import ( + "fmt" + "math/rand" + "sync" + "testing" + "time" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" + fcache "k8s.io/client-go/tools/cache/testing" + + "github.com/google/gofuzz" +) + +func Example() { + // source simulates an apiserver object endpoint. + source := fcache.NewFakeControllerSource() + + // This will hold the downstream state, as we know it. + downstream := NewStore(DeletionHandlingMetaNamespaceKeyFunc) + + // This will hold incoming changes. Note how we pass downstream in as a + // KeyLister, that way resync operations will result in the correct set + // of update/delete deltas. + fifo := NewDeltaFIFO(MetaNamespaceKeyFunc, downstream) + + // Let's do threadsafe output to get predictable test results. + deletionCounter := make(chan string, 1000) + + cfg := &Config{ + Queue: fifo, + ListerWatcher: source, + ObjectType: &v1.Pod{}, + FullResyncPeriod: time.Millisecond * 100, + RetryOnError: false, + + // Let's implement a simple controller that just deletes + // everything that comes in. + Process: func(obj interface{}) error { + // Obj is from the Pop method of the Queue we make above. + newest := obj.(Deltas).Newest() + + if newest.Type != Deleted { + // Update our downstream store. + err := downstream.Add(newest.Object) + if err != nil { + return err + } + + // Delete this object. + source.Delete(newest.Object.(runtime.Object)) + } else { + // Update our downstream store. + err := downstream.Delete(newest.Object) + if err != nil { + return err + } + + // fifo's KeyOf is easiest, because it handles + // DeletedFinalStateUnknown markers. + key, err := fifo.KeyOf(newest.Object) + if err != nil { + return err + } + + // Report this deletion. + deletionCounter <- key + } + return nil + }, + } + + // Create the controller and run it until we close stop. + stop := make(chan struct{}) + defer close(stop) + go New(cfg).Run(stop) + + // Let's add a few objects to the source. + testIDs := []string{"a-hello", "b-controller", "c-framework"} + for _, name := range testIDs { + // Note that these pods are not valid-- the fake source doesn't + // call validation or anything. + source.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: name}}) + } + + // Let's wait for the controller to process the things we just added. + outputSet := sets.String{} + for i := 0; i < len(testIDs); i++ { + outputSet.Insert(<-deletionCounter) + } + + for _, key := range outputSet.List() { + fmt.Println(key) + } + // Output: + // a-hello + // b-controller + // c-framework +} + +func ExampleNewInformer() { + // source simulates an apiserver object endpoint. + source := fcache.NewFakeControllerSource() + + // Let's do threadsafe output to get predictable test results. + deletionCounter := make(chan string, 1000) + + // Make a controller that immediately deletes anything added to it, and + // logs anything deleted. + _, controller := NewInformer( + source, + &v1.Pod{}, + time.Millisecond*100, + ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + source.Delete(obj.(runtime.Object)) + }, + DeleteFunc: func(obj interface{}) { + key, err := DeletionHandlingMetaNamespaceKeyFunc(obj) + if err != nil { + key = "oops something went wrong with the key" + } + + // Report this deletion. + deletionCounter <- key + }, + }, + ) + + // Run the controller and run it until we close stop. + stop := make(chan struct{}) + defer close(stop) + go controller.Run(stop) + + // Let's add a few objects to the source. + testIDs := []string{"a-hello", "b-controller", "c-framework"} + for _, name := range testIDs { + // Note that these pods are not valid-- the fake source doesn't + // call validation or anything. + source.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: name}}) + } + + // Let's wait for the controller to process the things we just added. + outputSet := sets.String{} + for i := 0; i < len(testIDs); i++ { + outputSet.Insert(<-deletionCounter) + } + + for _, key := range outputSet.List() { + fmt.Println(key) + } + // Output: + // a-hello + // b-controller + // c-framework +} + +func TestHammerController(t *testing.T) { + // This test executes a bunch of requests through the fake source and + // controller framework to make sure there's no locking/threading + // errors. If an error happens, it should hang forever or trigger the + // race detector. + + // source simulates an apiserver object endpoint. + source := fcache.NewFakeControllerSource() + + // Let's do threadsafe output to get predictable test results. + outputSetLock := sync.Mutex{} + // map of key to operations done on the key + outputSet := map[string][]string{} + + recordFunc := func(eventType string, obj interface{}) { + key, err := DeletionHandlingMetaNamespaceKeyFunc(obj) + if err != nil { + t.Errorf("something wrong with key: %v", err) + key = "oops something went wrong with the key" + } + + // Record some output when items are deleted. + outputSetLock.Lock() + defer outputSetLock.Unlock() + outputSet[key] = append(outputSet[key], eventType) + } + + // Make a controller which just logs all the changes it gets. + _, controller := NewInformer( + source, + &v1.Pod{}, + time.Millisecond*100, + ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { recordFunc("add", obj) }, + UpdateFunc: func(oldObj, newObj interface{}) { recordFunc("update", newObj) }, + DeleteFunc: func(obj interface{}) { recordFunc("delete", obj) }, + }, + ) + + if controller.HasSynced() { + t.Errorf("Expected HasSynced() to return false before we started the controller") + } + + // Run the controller and run it until we close stop. + stop := make(chan struct{}) + go controller.Run(stop) + + // Let's wait for the controller to do its initial sync + wait.Poll(100*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) { + return controller.HasSynced(), nil + }) + if !controller.HasSynced() { + t.Errorf("Expected HasSynced() to return true after the initial sync") + } + + wg := sync.WaitGroup{} + const threads = 3 + wg.Add(threads) + for i := 0; i < threads; i++ { + go func() { + defer wg.Done() + // Let's add a few objects to the source. + currentNames := sets.String{} + rs := rand.NewSource(rand.Int63()) + f := fuzz.New().NilChance(.5).NumElements(0, 2).RandSource(rs) + r := rand.New(rs) // Mustn't use r and f concurrently! + for i := 0; i < 100; i++ { + var name string + var isNew bool + if currentNames.Len() == 0 || r.Intn(3) == 1 { + f.Fuzz(&name) + isNew = true + } else { + l := currentNames.List() + name = l[r.Intn(len(l))] + } + + pod := &v1.Pod{} + f.Fuzz(pod) + pod.ObjectMeta.Name = name + pod.ObjectMeta.Namespace = "default" + // Add, update, or delete randomly. + // Note that these pods are not valid-- the fake source doesn't + // call validation or perform any other checking. + if isNew { + currentNames.Insert(name) + source.Add(pod) + continue + } + switch r.Intn(2) { + case 0: + currentNames.Insert(name) + source.Modify(pod) + case 1: + currentNames.Delete(name) + source.Delete(pod) + } + } + }() + } + wg.Wait() + + // Let's wait for the controller to finish processing the things we just added. + // TODO: look in the queue to see how many items need to be processed. + time.Sleep(100 * time.Millisecond) + close(stop) + + // TODO: Verify that no goroutines were leaked here and that everything shut + // down cleanly. + + outputSetLock.Lock() + t.Logf("got: %#v", outputSet) +} + +func TestUpdate(t *testing.T) { + // This test is going to exercise the various paths that result in a + // call to update. + + // source simulates an apiserver object endpoint. + source := fcache.NewFakeControllerSource() + + const ( + FROM = "from" + TO = "to" + ) + + // These are the transitions we expect to see; because this is + // asynchronous, there are a lot of valid possibilities. + type pair struct{ from, to string } + allowedTransitions := map[pair]bool{ + {FROM, TO}: true, + + // Because a resync can happen when we've already observed one + // of the above but before the item is deleted. + {TO, TO}: true, + // Because a resync could happen before we observe an update. + {FROM, FROM}: true, + } + + pod := func(name, check string, final bool) *v1.Pod { + p := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: map[string]string{"check": check}, + }, + } + if final { + p.Labels["final"] = "true" + } + return p + } + deletePod := func(p *v1.Pod) bool { + return p.Labels["final"] == "true" + } + + tests := []func(string){ + func(name string) { + name = "a-" + name + source.Add(pod(name, FROM, false)) + source.Modify(pod(name, TO, true)) + }, + } + + const threads = 3 + + var testDoneWG sync.WaitGroup + testDoneWG.Add(threads * len(tests)) + + // Make a controller that deletes things once it observes an update. + // It calls Done() on the wait group on deletions so we can tell when + // everything we've added has been deleted. + watchCh := make(chan struct{}) + _, controller := NewInformer( + &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + watch, err := source.Watch(options) + close(watchCh) + return watch, err + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return source.List(options) + }, + }, + &v1.Pod{}, + 0, + ResourceEventHandlerFuncs{ + UpdateFunc: func(oldObj, newObj interface{}) { + o, n := oldObj.(*v1.Pod), newObj.(*v1.Pod) + from, to := o.Labels["check"], n.Labels["check"] + if !allowedTransitions[pair{from, to}] { + t.Errorf("observed transition %q -> %q for %v", from, to, n.Name) + } + if deletePod(n) { + source.Delete(n) + } + }, + DeleteFunc: func(obj interface{}) { + testDoneWG.Done() + }, + }, + ) + + // Run the controller and run it until we close stop. + // Once Run() is called, calls to testDoneWG.Done() might start, so + // all testDoneWG.Add() calls must happen before this point + stop := make(chan struct{}) + go controller.Run(stop) + <-watchCh + + // run every test a few times, in parallel + var wg sync.WaitGroup + wg.Add(threads * len(tests)) + for i := 0; i < threads; i++ { + for j, f := range tests { + go func(name string, f func(string)) { + defer wg.Done() + f(name) + }(fmt.Sprintf("%v-%v", i, j), f) + } + } + wg.Wait() + + // Let's wait for the controller to process the things we just added. + testDoneWG.Wait() + close(stop) +} diff --git a/vendor/k8s.io/client-go/tools/cache/delta_fifo_test.go b/vendor/k8s.io/client-go/tools/cache/delta_fifo_test.go new file mode 100644 index 000000000..9f8e57580 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/delta_fifo_test.go @@ -0,0 +1,492 @@ +/* +Copyright 2014 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 cache + +import ( + "fmt" + "reflect" + "testing" + "time" +) + +// helper function to reduce stuttering +func testPop(f *DeltaFIFO) testFifoObject { + return Pop(f).(Deltas).Newest().Object.(testFifoObject) +} + +// keyLookupFunc adapts a raw function to be a KeyLookup. +type keyLookupFunc func() []testFifoObject + +// ListKeys just calls kl. +func (kl keyLookupFunc) ListKeys() []string { + result := []string{} + for _, fifoObj := range kl() { + result = append(result, fifoObj.name) + } + return result +} + +// GetByKey returns the key if it exists in the list returned by kl. +func (kl keyLookupFunc) GetByKey(key string) (interface{}, bool, error) { + for _, v := range kl() { + if v.name == key { + return v, true, nil + } + } + return nil, false, nil +} + +func TestDeltaFIFO_basic(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + const amount = 500 + go func() { + for i := 0; i < amount; i++ { + f.Add(mkFifoObj(string([]rune{'a', rune(i)}), i+1)) + } + }() + go func() { + for u := uint64(0); u < amount; u++ { + f.Add(mkFifoObj(string([]rune{'b', rune(u)}), u+1)) + } + }() + + lastInt := int(0) + lastUint := uint64(0) + for i := 0; i < amount*2; i++ { + switch obj := testPop(f).val.(type) { + case int: + if obj <= lastInt { + t.Errorf("got %v (int) out of order, last was %v", obj, lastInt) + } + lastInt = obj + case uint64: + if obj <= lastUint { + t.Errorf("got %v (uint) out of order, last was %v", obj, lastUint) + } else { + lastUint = obj + } + default: + t.Fatalf("unexpected type %#v", obj) + } + } +} + +func TestDeltaFIFO_requeueOnPop(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + + f.Add(mkFifoObj("foo", 10)) + _, err := f.Pop(func(obj interface{}) error { + if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { + t.Fatalf("unexpected object: %#v", obj) + } + return ErrRequeue{Err: nil} + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, ok, err := f.GetByKey("foo"); !ok || err != nil { + t.Fatalf("object should have been requeued: %t %v", ok, err) + } + + _, err = f.Pop(func(obj interface{}) error { + if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { + t.Fatalf("unexpected object: %#v", obj) + } + return ErrRequeue{Err: fmt.Errorf("test error")} + }) + if err == nil || err.Error() != "test error" { + t.Fatalf("unexpected error: %v", err) + } + if _, ok, err := f.GetByKey("foo"); !ok || err != nil { + t.Fatalf("object should have been requeued: %t %v", ok, err) + } + + _, err = f.Pop(func(obj interface{}) error { + if obj.(Deltas)[0].Object.(testFifoObject).name != "foo" { + t.Fatalf("unexpected object: %#v", obj) + } + return nil + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, ok, err := f.GetByKey("foo"); ok || err != nil { + t.Fatalf("object should have been removed: %t %v", ok, err) + } +} + +func TestDeltaFIFO_addUpdate(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + f.Add(mkFifoObj("foo", 10)) + f.Update(mkFifoObj("foo", 12)) + f.Delete(mkFifoObj("foo", 15)) + + if e, a := []interface{}{mkFifoObj("foo", 15)}, f.List(); !reflect.DeepEqual(e, a) { + t.Errorf("Expected %+v, got %+v", e, a) + } + if e, a := []string{"foo"}, f.ListKeys(); !reflect.DeepEqual(e, a) { + t.Errorf("Expected %+v, got %+v", e, a) + } + + got := make(chan testFifoObject, 2) + go func() { + for { + obj := testPop(f) + t.Logf("got a thing %#v", obj) + t.Logf("D len: %v", len(f.queue)) + got <- obj + } + }() + + first := <-got + if e, a := 15, first.val; e != a { + t.Errorf("Didn't get updated value (%v), got %v", e, a) + } + select { + case unexpected := <-got: + t.Errorf("Got second value %v", unexpected.val) + case <-time.After(50 * time.Millisecond): + } + _, exists, _ := f.Get(mkFifoObj("foo", "")) + if exists { + t.Errorf("item did not get removed") + } +} + +func TestDeltaFIFO_enqueueingNoLister(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + f.Add(mkFifoObj("foo", 10)) + f.Update(mkFifoObj("bar", 15)) + f.Add(mkFifoObj("qux", 17)) + f.Delete(mkFifoObj("qux", 18)) + + // This delete does not enqueue anything because baz doesn't exist. + f.Delete(mkFifoObj("baz", 20)) + + expectList := []int{10, 15, 18} + for _, expect := range expectList { + if e, a := expect, testPop(f).val; e != a { + t.Errorf("Didn't get updated value (%v), got %v", e, a) + } + } + if e, a := 0, len(f.items); e != a { + t.Errorf("queue unexpectedly not empty: %v != %v\n%#v", e, a, f.items) + } +} + +func TestDeltaFIFO_enqueueingWithLister(t *testing.T) { + f := NewDeltaFIFO( + testFifoObjectKeyFunc, + keyLookupFunc(func() []testFifoObject { + return []testFifoObject{mkFifoObj("foo", 5), mkFifoObj("bar", 6), mkFifoObj("baz", 7)} + }), + ) + f.Add(mkFifoObj("foo", 10)) + f.Update(mkFifoObj("bar", 15)) + + // This delete does enqueue the deletion, because "baz" is in the key lister. + f.Delete(mkFifoObj("baz", 20)) + + expectList := []int{10, 15, 20} + for _, expect := range expectList { + if e, a := expect, testPop(f).val; e != a { + t.Errorf("Didn't get updated value (%v), got %v", e, a) + } + } + if e, a := 0, len(f.items); e != a { + t.Errorf("queue unexpectedly not empty: %v != %v", e, a) + } +} + +func TestDeltaFIFO_addReplace(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + f.Add(mkFifoObj("foo", 10)) + f.Replace([]interface{}{mkFifoObj("foo", 15)}, "0") + got := make(chan testFifoObject, 2) + go func() { + for { + got <- testPop(f) + } + }() + + first := <-got + if e, a := 15, first.val; e != a { + t.Errorf("Didn't get updated value (%v), got %v", e, a) + } + select { + case unexpected := <-got: + t.Errorf("Got second value %v", unexpected.val) + case <-time.After(50 * time.Millisecond): + } + _, exists, _ := f.Get(mkFifoObj("foo", "")) + if exists { + t.Errorf("item did not get removed") + } +} + +func TestDeltaFIFO_ResyncNonExisting(t *testing.T) { + f := NewDeltaFIFO( + testFifoObjectKeyFunc, + keyLookupFunc(func() []testFifoObject { + return []testFifoObject{mkFifoObj("foo", 5)} + }), + ) + f.Delete(mkFifoObj("foo", 10)) + f.Resync() + + deltas := f.items["foo"] + if len(deltas) != 1 { + t.Fatalf("unexpected deltas length: %v", deltas) + } + if deltas[0].Type != Deleted { + t.Errorf("unexpected delta: %v", deltas[0]) + } +} + +func TestDeltaFIFO_DeleteExistingNonPropagated(t *testing.T) { + f := NewDeltaFIFO( + testFifoObjectKeyFunc, + keyLookupFunc(func() []testFifoObject { + return []testFifoObject{} + }), + ) + f.Add(mkFifoObj("foo", 5)) + f.Delete(mkFifoObj("foo", 6)) + + deltas := f.items["foo"] + if len(deltas) != 2 { + t.Fatalf("unexpected deltas length: %v", deltas) + } + if deltas[len(deltas)-1].Type != Deleted { + t.Errorf("unexpected delta: %v", deltas[len(deltas)-1]) + } +} + +func TestDeltaFIFO_ReplaceMakesDeletions(t *testing.T) { + f := NewDeltaFIFO( + testFifoObjectKeyFunc, + keyLookupFunc(func() []testFifoObject { + return []testFifoObject{mkFifoObj("foo", 5), mkFifoObj("bar", 6), mkFifoObj("baz", 7)} + }), + ) + f.Delete(mkFifoObj("baz", 10)) + f.Replace([]interface{}{mkFifoObj("foo", 5)}, "0") + + expectedList := []Deltas{ + {{Deleted, mkFifoObj("baz", 10)}}, + {{Sync, mkFifoObj("foo", 5)}}, + // Since "bar" didn't have a delete event and wasn't in the Replace list + // it should get a tombstone key with the right Obj. + {{Deleted, DeletedFinalStateUnknown{Key: "bar", Obj: mkFifoObj("bar", 6)}}}, + } + + for _, expected := range expectedList { + cur := Pop(f).(Deltas) + if e, a := expected, cur; !reflect.DeepEqual(e, a) { + t.Errorf("Expected %#v, got %#v", e, a) + } + } +} + +func TestDeltaFIFO_UpdateResyncRace(t *testing.T) { + f := NewDeltaFIFO( + testFifoObjectKeyFunc, + keyLookupFunc(func() []testFifoObject { + return []testFifoObject{mkFifoObj("foo", 5)} + }), + ) + f.Update(mkFifoObj("foo", 6)) + f.Resync() + + expectedList := []Deltas{ + {{Updated, mkFifoObj("foo", 6)}}, + } + + for _, expected := range expectedList { + cur := Pop(f).(Deltas) + if e, a := expected, cur; !reflect.DeepEqual(e, a) { + t.Errorf("Expected %#v, got %#v", e, a) + } + } +} + +func TestDeltaFIFO_HasSyncedCorrectOnDeletion(t *testing.T) { + f := NewDeltaFIFO( + testFifoObjectKeyFunc, + keyLookupFunc(func() []testFifoObject { + return []testFifoObject{mkFifoObj("foo", 5), mkFifoObj("bar", 6), mkFifoObj("baz", 7)} + }), + ) + f.Replace([]interface{}{mkFifoObj("foo", 5)}, "0") + + expectedList := []Deltas{ + {{Sync, mkFifoObj("foo", 5)}}, + // Since "bar" didn't have a delete event and wasn't in the Replace list + // it should get a tombstone key with the right Obj. + {{Deleted, DeletedFinalStateUnknown{Key: "bar", Obj: mkFifoObj("bar", 6)}}}, + } + + for _, expected := range expectedList { + if f.HasSynced() { + t.Errorf("Expected HasSynced to be false") + } + cur := Pop(f).(Deltas) + if e, a := expected, cur; !reflect.DeepEqual(e, a) { + t.Errorf("Expected %#v, got %#v", e, a) + } + } + if f.HasSynced() { + t.Errorf("Expected HasSynced to be true") + } +} + +func TestDeltaFIFO_detectLineJumpers(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + + f.Add(mkFifoObj("foo", 10)) + f.Add(mkFifoObj("bar", 1)) + f.Add(mkFifoObj("foo", 11)) + f.Add(mkFifoObj("foo", 13)) + f.Add(mkFifoObj("zab", 30)) + + if e, a := 13, testPop(f).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } + + f.Add(mkFifoObj("foo", 14)) // ensure foo doesn't jump back in line + + if e, a := 1, testPop(f).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } + + if e, a := 30, testPop(f).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } + + if e, a := 14, testPop(f).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } +} + +func TestDeltaFIFO_addIfNotPresent(t *testing.T) { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + + f.Add(mkFifoObj("b", 3)) + b3 := Pop(f) + f.Add(mkFifoObj("c", 4)) + c4 := Pop(f) + if e, a := 0, len(f.items); e != a { + t.Fatalf("Expected %v, got %v items in queue", e, a) + } + + f.Add(mkFifoObj("a", 1)) + f.Add(mkFifoObj("b", 2)) + f.AddIfNotPresent(b3) + f.AddIfNotPresent(c4) + + if e, a := 3, len(f.items); a != e { + t.Fatalf("expected queue length %d, got %d", e, a) + } + + expectedValues := []int{1, 2, 4} + for _, expected := range expectedValues { + if actual := testPop(f).val; actual != expected { + t.Fatalf("expected value %d, got %d", expected, actual) + } + } +} + +func TestDeltaFIFO_KeyOf(t *testing.T) { + f := DeltaFIFO{keyFunc: testFifoObjectKeyFunc} + + table := []struct { + obj interface{} + key string + }{ + {obj: testFifoObject{name: "A"}, key: "A"}, + {obj: DeletedFinalStateUnknown{Key: "B", Obj: nil}, key: "B"}, + {obj: Deltas{{Object: testFifoObject{name: "C"}}}, key: "C"}, + {obj: Deltas{{Object: DeletedFinalStateUnknown{Key: "D", Obj: nil}}}, key: "D"}, + } + + for _, item := range table { + got, err := f.KeyOf(item.obj) + if err != nil { + t.Errorf("Unexpected error for %q: %v", item.obj, err) + continue + } + if e, a := item.key, got; e != a { + t.Errorf("Expected %v, got %v", e, a) + } + } +} + +func TestDeltaFIFO_HasSynced(t *testing.T) { + tests := []struct { + actions []func(f *DeltaFIFO) + expectedSynced bool + }{ + { + actions: []func(f *DeltaFIFO){}, + expectedSynced: false, + }, + { + actions: []func(f *DeltaFIFO){ + func(f *DeltaFIFO) { f.Add(mkFifoObj("a", 1)) }, + }, + expectedSynced: true, + }, + { + actions: []func(f *DeltaFIFO){ + func(f *DeltaFIFO) { f.Replace([]interface{}{}, "0") }, + }, + expectedSynced: true, + }, + { + actions: []func(f *DeltaFIFO){ + func(f *DeltaFIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") }, + }, + expectedSynced: false, + }, + { + actions: []func(f *DeltaFIFO){ + func(f *DeltaFIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") }, + func(f *DeltaFIFO) { Pop(f) }, + }, + expectedSynced: false, + }, + { + actions: []func(f *DeltaFIFO){ + func(f *DeltaFIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") }, + func(f *DeltaFIFO) { Pop(f) }, + func(f *DeltaFIFO) { Pop(f) }, + }, + expectedSynced: true, + }, + } + + for i, test := range tests { + f := NewDeltaFIFO(testFifoObjectKeyFunc, nil) + + for _, action := range test.actions { + action(f) + } + if e, a := test.expectedSynced, f.HasSynced(); a != e { + t.Errorf("test case %v failed, expected: %v , got %v", i, e, a) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/cache/expiration_cache_test.go b/vendor/k8s.io/client-go/tools/cache/expiration_cache_test.go new file mode 100644 index 000000000..fac621cbc --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/expiration_cache_test.go @@ -0,0 +1,189 @@ +/* +Copyright 2014 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 cache + +import ( + "reflect" + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" +) + +func TestTTLExpirationBasic(t *testing.T) { + testObj := testStoreObject{id: "foo", val: "bar"} + deleteChan := make(chan string, 1) + ttlStore := NewFakeExpirationStore( + testStoreKeyFunc, deleteChan, + &FakeExpirationPolicy{ + NeverExpire: sets.NewString(), + RetrieveKeyFunc: func(obj interface{}) (string, error) { + return obj.(*timestampedEntry).obj.(testStoreObject).id, nil + }, + }, + clock.RealClock{}, + ) + err := ttlStore.Add(testObj) + if err != nil { + t.Errorf("Unable to add obj %#v", testObj) + } + item, exists, err := ttlStore.Get(testObj) + if err != nil { + t.Errorf("Failed to get from store, %v", err) + } + if exists || item != nil { + t.Errorf("Got unexpected item %#v", item) + } + key, _ := testStoreKeyFunc(testObj) + select { + case delKey := <-deleteChan: + if delKey != key { + t.Errorf("Unexpected delete for key %s", key) + } + case <-time.After(wait.ForeverTestTimeout): + t.Errorf("Unexpected timeout waiting on delete") + } + close(deleteChan) +} + +func TestReAddExpiredItem(t *testing.T) { + deleteChan := make(chan string, 1) + exp := &FakeExpirationPolicy{ + NeverExpire: sets.NewString(), + RetrieveKeyFunc: func(obj interface{}) (string, error) { + return obj.(*timestampedEntry).obj.(testStoreObject).id, nil + }, + } + ttlStore := NewFakeExpirationStore( + testStoreKeyFunc, deleteChan, exp, clock.RealClock{}) + testKey := "foo" + testObj := testStoreObject{id: testKey, val: "bar"} + err := ttlStore.Add(testObj) + if err != nil { + t.Errorf("Unable to add obj %#v", testObj) + } + + // This get will expire the item. + item, exists, err := ttlStore.Get(testObj) + if err != nil { + t.Errorf("Failed to get from store, %v", err) + } + if exists || item != nil { + t.Errorf("Got unexpected item %#v", item) + } + + key, _ := testStoreKeyFunc(testObj) + differentValue := "different_bar" + err = ttlStore.Add( + testStoreObject{id: testKey, val: differentValue}) + if err != nil { + t.Errorf("Failed to add second value") + } + + select { + case delKey := <-deleteChan: + if delKey != key { + t.Errorf("Unexpected delete for key %s", key) + } + case <-time.After(wait.ForeverTestTimeout): + t.Errorf("Unexpected timeout waiting on delete") + } + exp.NeverExpire = sets.NewString(testKey) + item, exists, err = ttlStore.GetByKey(testKey) + if err != nil { + t.Errorf("Failed to get from store, %v", err) + } + if !exists || item == nil || item.(testStoreObject).val != differentValue { + t.Errorf("Got unexpected item %#v", item) + } + close(deleteChan) +} + +func TestTTLList(t *testing.T) { + testObjs := []testStoreObject{ + {id: "foo", val: "bar"}, + {id: "foo1", val: "bar1"}, + {id: "foo2", val: "bar2"}, + } + expireKeys := sets.NewString(testObjs[0].id, testObjs[2].id) + deleteChan := make(chan string, len(testObjs)) + defer close(deleteChan) + + ttlStore := NewFakeExpirationStore( + testStoreKeyFunc, deleteChan, + &FakeExpirationPolicy{ + NeverExpire: sets.NewString(testObjs[1].id), + RetrieveKeyFunc: func(obj interface{}) (string, error) { + return obj.(*timestampedEntry).obj.(testStoreObject).id, nil + }, + }, + clock.RealClock{}, + ) + for _, obj := range testObjs { + err := ttlStore.Add(obj) + if err != nil { + t.Errorf("Unable to add obj %#v", obj) + } + } + listObjs := ttlStore.List() + if len(listObjs) != 1 || !reflect.DeepEqual(listObjs[0], testObjs[1]) { + t.Errorf("List returned unexpected results %#v", listObjs) + } + + // Make sure all our deletes come through in an acceptable rate (1/100ms) + for expireKeys.Len() != 0 { + select { + case delKey := <-deleteChan: + if !expireKeys.Has(delKey) { + t.Errorf("Unexpected delete for key %s", delKey) + } + expireKeys.Delete(delKey) + case <-time.After(wait.ForeverTestTimeout): + t.Errorf("Unexpected timeout waiting on delete") + return + } + } +} + +func TestTTLPolicy(t *testing.T) { + fakeTime := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) + ttl := 30 * time.Second + exactlyOnTTL := fakeTime.Add(-ttl) + expiredTime := fakeTime.Add(-(ttl + 1)) + + policy := TTLPolicy{ttl, clock.NewFakeClock(fakeTime)} + fakeTimestampedEntry := &timestampedEntry{obj: struct{}{}, timestamp: exactlyOnTTL} + if policy.IsExpired(fakeTimestampedEntry) { + t.Errorf("TTL cache should not expire entries exactly on ttl") + } + fakeTimestampedEntry.timestamp = fakeTime + if policy.IsExpired(fakeTimestampedEntry) { + t.Errorf("TTL Cache should not expire entries before ttl") + } + fakeTimestampedEntry.timestamp = expiredTime + if !policy.IsExpired(fakeTimestampedEntry) { + t.Errorf("TTL Cache should expire entries older than ttl") + } + for _, ttl = range []time.Duration{0, -1} { + policy.Ttl = ttl + if policy.IsExpired(fakeTimestampedEntry) { + t.Errorf("TTL policy should only expire entries when initialized with a ttl > 0") + } + } +} diff --git a/vendor/k8s.io/client-go/tools/cache/fifo_test.go b/vendor/k8s.io/client-go/tools/cache/fifo_test.go new file mode 100644 index 000000000..afd311d78 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/fifo_test.go @@ -0,0 +1,280 @@ +/* +Copyright 2014 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 cache + +import ( + "fmt" + "reflect" + "testing" + "time" +) + +func testFifoObjectKeyFunc(obj interface{}) (string, error) { + return obj.(testFifoObject).name, nil +} + +type testFifoObject struct { + name string + val interface{} +} + +func mkFifoObj(name string, val interface{}) testFifoObject { + return testFifoObject{name: name, val: val} +} + +func TestFIFO_basic(t *testing.T) { + f := NewFIFO(testFifoObjectKeyFunc) + const amount = 500 + go func() { + for i := 0; i < amount; i++ { + f.Add(mkFifoObj(string([]rune{'a', rune(i)}), i+1)) + } + }() + go func() { + for u := uint64(0); u < amount; u++ { + f.Add(mkFifoObj(string([]rune{'b', rune(u)}), u+1)) + } + }() + + lastInt := int(0) + lastUint := uint64(0) + for i := 0; i < amount*2; i++ { + switch obj := Pop(f).(testFifoObject).val.(type) { + case int: + if obj <= lastInt { + t.Errorf("got %v (int) out of order, last was %v", obj, lastInt) + } + lastInt = obj + case uint64: + if obj <= lastUint { + t.Errorf("got %v (uint) out of order, last was %v", obj, lastUint) + } else { + lastUint = obj + } + default: + t.Fatalf("unexpected type %#v", obj) + } + } +} + +func TestFIFO_requeueOnPop(t *testing.T) { + f := NewFIFO(testFifoObjectKeyFunc) + + f.Add(mkFifoObj("foo", 10)) + _, err := f.Pop(func(obj interface{}) error { + if obj.(testFifoObject).name != "foo" { + t.Fatalf("unexpected object: %#v", obj) + } + return ErrRequeue{Err: nil} + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, ok, err := f.GetByKey("foo"); !ok || err != nil { + t.Fatalf("object should have been requeued: %t %v", ok, err) + } + + _, err = f.Pop(func(obj interface{}) error { + if obj.(testFifoObject).name != "foo" { + t.Fatalf("unexpected object: %#v", obj) + } + return ErrRequeue{Err: fmt.Errorf("test error")} + }) + if err == nil || err.Error() != "test error" { + t.Fatalf("unexpected error: %v", err) + } + if _, ok, err := f.GetByKey("foo"); !ok || err != nil { + t.Fatalf("object should have been requeued: %t %v", ok, err) + } + + _, err = f.Pop(func(obj interface{}) error { + if obj.(testFifoObject).name != "foo" { + t.Fatalf("unexpected object: %#v", obj) + } + return nil + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, ok, err := f.GetByKey("foo"); ok || err != nil { + t.Fatalf("object should have been removed: %t %v", ok, err) + } +} + +func TestFIFO_addUpdate(t *testing.T) { + f := NewFIFO(testFifoObjectKeyFunc) + f.Add(mkFifoObj("foo", 10)) + f.Update(mkFifoObj("foo", 15)) + + if e, a := []interface{}{mkFifoObj("foo", 15)}, f.List(); !reflect.DeepEqual(e, a) { + t.Errorf("Expected %+v, got %+v", e, a) + } + if e, a := []string{"foo"}, f.ListKeys(); !reflect.DeepEqual(e, a) { + t.Errorf("Expected %+v, got %+v", e, a) + } + + got := make(chan testFifoObject, 2) + go func() { + for { + got <- Pop(f).(testFifoObject) + } + }() + + first := <-got + if e, a := 15, first.val; e != a { + t.Errorf("Didn't get updated value (%v), got %v", e, a) + } + select { + case unexpected := <-got: + t.Errorf("Got second value %v", unexpected.val) + case <-time.After(50 * time.Millisecond): + } + _, exists, _ := f.Get(mkFifoObj("foo", "")) + if exists { + t.Errorf("item did not get removed") + } +} + +func TestFIFO_addReplace(t *testing.T) { + f := NewFIFO(testFifoObjectKeyFunc) + f.Add(mkFifoObj("foo", 10)) + f.Replace([]interface{}{mkFifoObj("foo", 15)}, "15") + got := make(chan testFifoObject, 2) + go func() { + for { + got <- Pop(f).(testFifoObject) + } + }() + + first := <-got + if e, a := 15, first.val; e != a { + t.Errorf("Didn't get updated value (%v), got %v", e, a) + } + select { + case unexpected := <-got: + t.Errorf("Got second value %v", unexpected.val) + case <-time.After(50 * time.Millisecond): + } + _, exists, _ := f.Get(mkFifoObj("foo", "")) + if exists { + t.Errorf("item did not get removed") + } +} + +func TestFIFO_detectLineJumpers(t *testing.T) { + f := NewFIFO(testFifoObjectKeyFunc) + + f.Add(mkFifoObj("foo", 10)) + f.Add(mkFifoObj("bar", 1)) + f.Add(mkFifoObj("foo", 11)) + f.Add(mkFifoObj("foo", 13)) + f.Add(mkFifoObj("zab", 30)) + + if e, a := 13, Pop(f).(testFifoObject).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } + + f.Add(mkFifoObj("foo", 14)) // ensure foo doesn't jump back in line + + if e, a := 1, Pop(f).(testFifoObject).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } + + if e, a := 30, Pop(f).(testFifoObject).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } + + if e, a := 14, Pop(f).(testFifoObject).val; a != e { + t.Fatalf("expected %d, got %d", e, a) + } +} + +func TestFIFO_addIfNotPresent(t *testing.T) { + f := NewFIFO(testFifoObjectKeyFunc) + + f.Add(mkFifoObj("a", 1)) + f.Add(mkFifoObj("b", 2)) + f.AddIfNotPresent(mkFifoObj("b", 3)) + f.AddIfNotPresent(mkFifoObj("c", 4)) + + if e, a := 3, len(f.items); a != e { + t.Fatalf("expected queue length %d, got %d", e, a) + } + + expectedValues := []int{1, 2, 4} + for _, expected := range expectedValues { + if actual := Pop(f).(testFifoObject).val; actual != expected { + t.Fatalf("expected value %d, got %d", expected, actual) + } + } +} + +func TestFIFO_HasSynced(t *testing.T) { + tests := []struct { + actions []func(f *FIFO) + expectedSynced bool + }{ + { + actions: []func(f *FIFO){}, + expectedSynced: false, + }, + { + actions: []func(f *FIFO){ + func(f *FIFO) { f.Add(mkFifoObj("a", 1)) }, + }, + expectedSynced: true, + }, + { + actions: []func(f *FIFO){ + func(f *FIFO) { f.Replace([]interface{}{}, "0") }, + }, + expectedSynced: true, + }, + { + actions: []func(f *FIFO){ + func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") }, + }, + expectedSynced: false, + }, + { + actions: []func(f *FIFO){ + func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") }, + func(f *FIFO) { Pop(f) }, + }, + expectedSynced: false, + }, + { + actions: []func(f *FIFO){ + func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") }, + func(f *FIFO) { Pop(f) }, + func(f *FIFO) { Pop(f) }, + }, + expectedSynced: true, + }, + } + + for i, test := range tests { + f := NewFIFO(testFifoObjectKeyFunc) + + for _, action := range test.actions { + action(f) + } + if e, a := test.expectedSynced, f.HasSynced(); a != e { + t.Errorf("test case %v failed, expected: %v , got %v", i, e, a) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/cache/heap_test.go b/vendor/k8s.io/client-go/tools/cache/heap_test.go new file mode 100644 index 000000000..c2e476988 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/heap_test.go @@ -0,0 +1,382 @@ +/* +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 cache + +import ( + "sync" + "testing" + "time" +) + +func testHeapObjectKeyFunc(obj interface{}) (string, error) { + return obj.(testHeapObject).name, nil +} + +type testHeapObject struct { + name string + val interface{} +} + +func mkHeapObj(name string, val interface{}) testHeapObject { + return testHeapObject{name: name, val: val} +} + +func compareInts(val1 interface{}, val2 interface{}) bool { + first := val1.(testHeapObject).val.(int) + second := val2.(testHeapObject).val.(int) + return first < second +} + +// TestHeapBasic tests Heap invariant and synchronization. +func TestHeapBasic(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + var wg sync.WaitGroup + wg.Add(2) + const amount = 500 + var i, u int + // Insert items in the heap in opposite orders in two go routines. + go func() { + for i = amount; i > 0; i-- { + h.Add(mkHeapObj(string([]rune{'a', rune(i)}), i)) + } + wg.Done() + }() + go func() { + for u = 0; u < amount; u++ { + h.Add(mkHeapObj(string([]rune{'b', rune(u)}), u+1)) + } + wg.Done() + }() + // Wait for the two go routines to finish. + wg.Wait() + // Make sure that the numbers are popped in ascending order. + prevNum := 0 + for i := 0; i < amount*2; i++ { + obj, err := h.Pop() + num := obj.(testHeapObject).val.(int) + // All the items must be sorted. + if err != nil || prevNum > num { + t.Errorf("got %v out of order, last was %v", obj, prevNum) + } + prevNum = num + } +} + +// Tests Heap.Add and ensures that heap invariant is preserved after adding items. +func TestHeap_Add(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Add(mkHeapObj("foo", 10)) + h.Add(mkHeapObj("bar", 1)) + h.Add(mkHeapObj("baz", 11)) + h.Add(mkHeapObj("zab", 30)) + h.Add(mkHeapObj("foo", 13)) // This updates "foo". + + item, err := h.Pop() + if e, a := 1, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + item, err = h.Pop() + if e, a := 11, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + h.Delete(mkHeapObj("baz", 11)) // Nothing is deleted. + h.Add(mkHeapObj("foo", 14)) // foo is updated. + item, err = h.Pop() + if e, a := 14, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + item, err = h.Pop() + if e, a := 30, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } +} + +// TestHeap_BulkAdd tests Heap.BulkAdd functionality and ensures that all the +// items given to BulkAdd are added to the queue before Pop reads them. +func TestHeap_BulkAdd(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + const amount = 500 + // Insert items in the heap in opposite orders in a go routine. + go func() { + l := []interface{}{} + for i := amount; i > 0; i-- { + l = append(l, mkHeapObj(string([]rune{'a', rune(i)}), i)) + } + h.BulkAdd(l) + }() + prevNum := -1 + for i := 0; i < amount; i++ { + obj, err := h.Pop() + num := obj.(testHeapObject).val.(int) + // All the items must be sorted. + if err != nil || prevNum >= num { + t.Errorf("got %v out of order, last was %v", obj, prevNum) + } + prevNum = num + } +} + +// TestHeapEmptyPop tests that pop returns properly after heap is closed. +func TestHeapEmptyPop(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + go func() { + time.Sleep(1 * time.Second) + h.Close() + }() + _, err := h.Pop() + if err == nil || err.Error() != closedMsg { + t.Errorf("pop should have returned heap closed error: %v", err) + } +} + +// TestHeap_AddIfNotPresent tests Heap.AddIfNotPresent and ensures that heap +// invariant is preserved after adding items. +func TestHeap_AddIfNotPresent(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.AddIfNotPresent(mkHeapObj("foo", 10)) + h.AddIfNotPresent(mkHeapObj("bar", 1)) + h.AddIfNotPresent(mkHeapObj("baz", 11)) + h.AddIfNotPresent(mkHeapObj("zab", 30)) + h.AddIfNotPresent(mkHeapObj("foo", 13)) // This is not added. + + if len := len(h.data.items); len != 4 { + t.Errorf("unexpected number of items: %d", len) + } + if val := h.data.items["foo"].obj.(testHeapObject).val; val != 10 { + t.Errorf("unexpected value: %d", val) + } + item, err := h.Pop() + if e, a := 1, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + item, err = h.Pop() + if e, a := 10, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + // bar is already popped. Let's add another one. + h.AddIfNotPresent(mkHeapObj("bar", 14)) + item, err = h.Pop() + if e, a := 11, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + item, err = h.Pop() + if e, a := 14, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } +} + +// TestHeap_Delete tests Heap.Delete and ensures that heap invariant is +// preserved after deleting items. +func TestHeap_Delete(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Add(mkHeapObj("foo", 10)) + h.Add(mkHeapObj("bar", 1)) + h.Add(mkHeapObj("bal", 31)) + h.Add(mkHeapObj("baz", 11)) + + // Delete head. Delete should work with "key" and doesn't care about the value. + if err := h.Delete(mkHeapObj("bar", 200)); err != nil { + t.Fatalf("Failed to delete head.") + } + item, err := h.Pop() + if e, a := 10, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + h.Add(mkHeapObj("zab", 30)) + h.Add(mkHeapObj("faz", 30)) + len := h.data.Len() + // Delete non-existing item. + if err = h.Delete(mkHeapObj("non-existent", 10)); err == nil || len != h.data.Len() { + t.Fatalf("Didn't expect any item removal") + } + // Delete tail. + if err = h.Delete(mkHeapObj("bal", 31)); err != nil { + t.Fatalf("Failed to delete tail.") + } + // Delete one of the items with value 30. + if err = h.Delete(mkHeapObj("zab", 30)); err != nil { + t.Fatalf("Failed to delete item.") + } + item, err = h.Pop() + if e, a := 11, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + item, err = h.Pop() + if e, a := 30, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + if h.data.Len() != 0 { + t.Fatalf("expected an empty heap.") + } +} + +// TestHeap_Update tests Heap.Update and ensures that heap invariant is +// preserved after adding items. +func TestHeap_Update(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Add(mkHeapObj("foo", 10)) + h.Add(mkHeapObj("bar", 1)) + h.Add(mkHeapObj("bal", 31)) + h.Add(mkHeapObj("baz", 11)) + + // Update an item to a value that should push it to the head. + h.Update(mkHeapObj("baz", 0)) + if h.data.queue[0] != "baz" || h.data.items["baz"].index != 0 { + t.Fatalf("expected baz to be at the head") + } + item, err := h.Pop() + if e, a := 0, item.(testHeapObject).val; err != nil || a != e { + t.Fatalf("expected %d, got %d", e, a) + } + // Update bar to push it farther back in the queue. + h.Update(mkHeapObj("bar", 100)) + if h.data.queue[0] != "foo" || h.data.items["foo"].index != 0 { + t.Fatalf("expected foo to be at the head") + } +} + +// TestHeap_Get tests Heap.Get. +func TestHeap_Get(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Add(mkHeapObj("foo", 10)) + h.Add(mkHeapObj("bar", 1)) + h.Add(mkHeapObj("bal", 31)) + h.Add(mkHeapObj("baz", 11)) + + // Get works with the key. + obj, exists, err := h.Get(mkHeapObj("baz", 0)) + if err != nil || exists == false || obj.(testHeapObject).val != 11 { + t.Fatalf("unexpected error in getting element") + } + // Get non-existing object. + _, exists, err = h.Get(mkHeapObj("non-existing", 0)) + if err != nil || exists == true { + t.Fatalf("didn't expect to get any object") + } +} + +// TestHeap_GetByKey tests Heap.GetByKey and is very similar to TestHeap_Get. +func TestHeap_GetByKey(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Add(mkHeapObj("foo", 10)) + h.Add(mkHeapObj("bar", 1)) + h.Add(mkHeapObj("bal", 31)) + h.Add(mkHeapObj("baz", 11)) + + obj, exists, err := h.GetByKey("baz") + if err != nil || exists == false || obj.(testHeapObject).val != 11 { + t.Fatalf("unexpected error in getting element") + } + // Get non-existing object. + _, exists, err = h.GetByKey("non-existing") + if err != nil || exists == true { + t.Fatalf("didn't expect to get any object") + } +} + +// TestHeap_Close tests Heap.Close and Heap.IsClosed functions. +func TestHeap_Close(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Add(mkHeapObj("foo", 10)) + h.Add(mkHeapObj("bar", 1)) + + if h.IsClosed() { + t.Fatalf("didn't expect heap to be closed") + } + h.Close() + if !h.IsClosed() { + t.Fatalf("expect heap to be closed") + } +} + +// TestHeap_List tests Heap.List function. +func TestHeap_List(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + list := h.List() + if len(list) != 0 { + t.Errorf("expected an empty list") + } + + items := map[string]int{ + "foo": 10, + "bar": 1, + "bal": 30, + "baz": 11, + "faz": 30, + } + for k, v := range items { + h.Add(mkHeapObj(k, v)) + } + list = h.List() + if len(list) != len(items) { + t.Errorf("expected %d items, got %d", len(items), len(list)) + } + for _, obj := range list { + heapObj := obj.(testHeapObject) + v, ok := items[heapObj.name] + if !ok || v != heapObj.val { + t.Errorf("unexpected item in the list: %v", heapObj) + } + } +} + +// TestHeap_ListKeys tests Heap.ListKeys function. Scenario is the same as +// TestHeap_list. +func TestHeap_ListKeys(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + list := h.ListKeys() + if len(list) != 0 { + t.Errorf("expected an empty list") + } + + items := map[string]int{ + "foo": 10, + "bar": 1, + "bal": 30, + "baz": 11, + "faz": 30, + } + for k, v := range items { + h.Add(mkHeapObj(k, v)) + } + list = h.ListKeys() + if len(list) != len(items) { + t.Errorf("expected %d items, got %d", len(items), len(list)) + } + for _, key := range list { + _, ok := items[key] + if !ok { + t.Errorf("unexpected item in the list: %v", key) + } + } +} + +// TestHeapAddAfterClose tests that heap returns an error if anything is added +// after it is closed. +func TestHeapAddAfterClose(t *testing.T) { + h := NewHeap(testHeapObjectKeyFunc, compareInts) + h.Close() + if err := h.Add(mkHeapObj("test", 1)); err == nil || err.Error() != closedMsg { + t.Errorf("expected heap closed error") + } + if err := h.AddIfNotPresent(mkHeapObj("test", 1)); err == nil || err.Error() != closedMsg { + t.Errorf("expected heap closed error") + } + if err := h.BulkAdd([]interface{}{mkHeapObj("test", 1)}); err == nil || err.Error() != closedMsg { + t.Errorf("expected heap closed error") + } +} diff --git a/vendor/k8s.io/client-go/tools/cache/index_test.go b/vendor/k8s.io/client-go/tools/cache/index_test.go new file mode 100644 index 000000000..ecc104c0c --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/index_test.go @@ -0,0 +1,163 @@ +/* +Copyright 2015 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 cache + +import ( + "strings" + "testing" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func testIndexFunc(obj interface{}) ([]string, error) { + pod := obj.(*v1.Pod) + return []string{pod.Labels["foo"]}, nil +} + +func TestGetIndexFuncValues(t *testing.T) { + index := NewIndexer(MetaNamespaceKeyFunc, Indexers{"testmodes": testIndexFunc}) + + pod1 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "one", Labels: map[string]string{"foo": "bar"}}} + pod2 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "two", Labels: map[string]string{"foo": "bar"}}} + pod3 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "tre", Labels: map[string]string{"foo": "biz"}}} + + index.Add(pod1) + index.Add(pod2) + index.Add(pod3) + + keys := index.ListIndexFuncValues("testmodes") + if len(keys) != 2 { + t.Errorf("Expected 2 keys but got %v", len(keys)) + } + + for _, key := range keys { + if key != "bar" && key != "biz" { + t.Errorf("Expected only 'bar' or 'biz' but got %s", key) + } + } +} + +func testUsersIndexFunc(obj interface{}) ([]string, error) { + pod := obj.(*v1.Pod) + usersString := pod.Annotations["users"] + + return strings.Split(usersString, ","), nil +} + +func TestMultiIndexKeys(t *testing.T) { + index := NewIndexer(MetaNamespaceKeyFunc, Indexers{"byUser": testUsersIndexFunc}) + + pod1 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "one", Annotations: map[string]string{"users": "ernie,bert"}}} + pod2 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "two", Annotations: map[string]string{"users": "bert,oscar"}}} + pod3 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "tre", Annotations: map[string]string{"users": "ernie,elmo"}}} + + index.Add(pod1) + index.Add(pod2) + index.Add(pod3) + + erniePods, err := index.ByIndex("byUser", "ernie") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(erniePods) != 2 { + t.Errorf("Expected 2 pods but got %v", len(erniePods)) + } + for _, erniePod := range erniePods { + if erniePod.(*v1.Pod).Name != "one" && erniePod.(*v1.Pod).Name != "tre" { + t.Errorf("Expected only 'one' or 'tre' but got %s", erniePod.(*v1.Pod).Name) + } + } + + bertPods, err := index.ByIndex("byUser", "bert") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(bertPods) != 2 { + t.Errorf("Expected 2 pods but got %v", len(bertPods)) + } + for _, bertPod := range bertPods { + if bertPod.(*v1.Pod).Name != "one" && bertPod.(*v1.Pod).Name != "two" { + t.Errorf("Expected only 'one' or 'two' but got %s", bertPod.(*v1.Pod).Name) + } + } + + oscarPods, err := index.ByIndex("byUser", "oscar") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(oscarPods) != 1 { + t.Errorf("Expected 1 pods but got %v", len(erniePods)) + } + for _, oscarPod := range oscarPods { + if oscarPod.(*v1.Pod).Name != "two" { + t.Errorf("Expected only 'two' but got %s", oscarPod.(*v1.Pod).Name) + } + } + + ernieAndBertKeys, err := index.Index("byUser", pod1) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(ernieAndBertKeys) != 3 { + t.Errorf("Expected 3 pods but got %v", len(ernieAndBertKeys)) + } + for _, ernieAndBertKey := range ernieAndBertKeys { + if ernieAndBertKey.(*v1.Pod).Name != "one" && ernieAndBertKey.(*v1.Pod).Name != "two" && ernieAndBertKey.(*v1.Pod).Name != "tre" { + t.Errorf("Expected only 'one', 'two' or 'tre' but got %s", ernieAndBertKey.(*v1.Pod).Name) + } + } + + index.Delete(pod3) + erniePods, err = index.ByIndex("byUser", "ernie") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(erniePods) != 1 { + t.Errorf("Expected 1 pods but got %v", len(erniePods)) + } + for _, erniePod := range erniePods { + if erniePod.(*v1.Pod).Name != "one" { + t.Errorf("Expected only 'one' but got %s", erniePod.(*v1.Pod).Name) + } + } + + elmoPods, err := index.ByIndex("byUser", "elmo") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(elmoPods) != 0 { + t.Errorf("Expected 0 pods but got %v", len(elmoPods)) + } + + copyOfPod2 := pod2.DeepCopy() + copyOfPod2.Annotations["users"] = "oscar" + index.Update(copyOfPod2) + bertPods, err = index.ByIndex("byUser", "bert") + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if len(bertPods) != 1 { + t.Errorf("Expected 1 pods but got %v", len(bertPods)) + } + for _, bertPod := range bertPods { + if bertPod.(*v1.Pod).Name != "one" { + t.Errorf("Expected only 'one' but got %s", bertPod.(*v1.Pod).Name) + } + } + +} diff --git a/vendor/k8s.io/client-go/tools/cache/mutation_detector_test.go b/vendor/k8s.io/client-go/tools/cache/mutation_detector_test.go new file mode 100644 index 000000000..41b6942f5 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/mutation_detector_test.go @@ -0,0 +1,81 @@ +// +build !race + +/* +Copyright 2016 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 cache + +import ( + "testing" + "time" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" +) + +func TestMutationDetector(t *testing.T) { + fakeWatch := watch.NewFake() + lw := &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return fakeWatch, nil + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return &v1.PodList{}, nil + }, + } + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "anything", + Labels: map[string]string{"check": "foo"}, + }, + } + stopCh := make(chan struct{}) + defer close(stopCh) + addReceived := make(chan bool) + mutationFound := make(chan bool) + + informer := NewSharedInformer(lw, &v1.Pod{}, 1*time.Second).(*sharedIndexInformer) + informer.cacheMutationDetector = &defaultCacheMutationDetector{ + name: "name", + period: 1 * time.Second, + failureFunc: func(message string) { + mutationFound <- true + }, + } + informer.AddEventHandler( + ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + addReceived <- true + }, + }, + ) + go informer.Run(stopCh) + + fakeWatch.Add(pod) + + select { + case <-addReceived: + } + + pod.Labels["change"] = "true" + + select { + case <-mutationFound: + } + +} diff --git a/vendor/k8s.io/client-go/tools/cache/processor_listener_test.go b/vendor/k8s.io/client-go/tools/cache/processor_listener_test.go new file mode 100644 index 000000000..1da73420f --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/processor_listener_test.go @@ -0,0 +1,58 @@ +/* +Copyright 2016 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 cache + +import ( + "sync" + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/wait" +) + +const ( + concurrencyLevel = 5 +) + +func BenchmarkListener(b *testing.B) { + var notification addNotification + + var swg sync.WaitGroup + swg.Add(b.N) + b.SetParallelism(concurrencyLevel) + // Preallocate enough space so that benchmark does not run out of it + pl := newProcessListener(&ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + swg.Done() + }, + }, 0, 0, time.Now(), 1024*1024) + var wg wait.Group + defer wg.Wait() // Wait for .run and .pop to stop + defer close(pl.addCh) // Tell .run and .pop to stop + wg.Start(pl.run) + wg.Start(pl.pop) + + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + pl.add(notification) + } + }) + swg.Wait() // Block until all notifications have been received + b.StopTimer() +} diff --git a/vendor/k8s.io/client-go/tools/cache/reflector_test.go b/vendor/k8s.io/client-go/tools/cache/reflector_test.go new file mode 100644 index 000000000..bb06059f7 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/reflector_test.go @@ -0,0 +1,389 @@ +/* +Copyright 2014 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 cache + +import ( + "errors" + "fmt" + "math/rand" + "strconv" + "testing" + "time" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" +) + +var nevererrc chan error + +type testLW struct { + ListFunc func(options metav1.ListOptions) (runtime.Object, error) + WatchFunc func(options metav1.ListOptions) (watch.Interface, error) +} + +func (t *testLW) List(options metav1.ListOptions) (runtime.Object, error) { + return t.ListFunc(options) +} +func (t *testLW) Watch(options metav1.ListOptions) (watch.Interface, error) { + return t.WatchFunc(options) +} + +func TestCloseWatchChannelOnError(t *testing.T) { + r := NewReflector(&testLW{}, &v1.Pod{}, NewStore(MetaNamespaceKeyFunc), 0) + pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}} + fw := watch.NewFake() + r.listerWatcher = &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return fw, nil + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil + }, + } + go r.ListAndWatch(wait.NeverStop) + fw.Error(pod) + select { + case _, ok := <-fw.ResultChan(): + if ok { + t.Errorf("Watch channel left open after cancellation") + } + case <-time.After(wait.ForeverTestTimeout): + t.Errorf("the cancellation is at least %s late", wait.ForeverTestTimeout.String()) + break + } +} + +func TestRunUntil(t *testing.T) { + stopCh := make(chan struct{}) + store := NewStore(MetaNamespaceKeyFunc) + r := NewReflector(&testLW{}, &v1.Pod{}, store, 0) + fw := watch.NewFake() + r.listerWatcher = &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return fw, nil + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil + }, + } + go r.Run(stopCh) + // Synchronously add a dummy pod into the watch channel so we + // know the RunUntil go routine is in the watch handler. + fw.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}}) + close(stopCh) + select { + case _, ok := <-fw.ResultChan(): + if ok { + t.Errorf("Watch channel left open after stopping the watch") + } + case <-time.After(wait.ForeverTestTimeout): + t.Errorf("the cancellation is at least %s late", wait.ForeverTestTimeout.String()) + break + } +} + +func TestReflectorResyncChan(t *testing.T) { + s := NewStore(MetaNamespaceKeyFunc) + g := NewReflector(&testLW{}, &v1.Pod{}, s, time.Millisecond) + a, _ := g.resyncChan() + b := time.After(wait.ForeverTestTimeout) + select { + case <-a: + t.Logf("got timeout as expected") + case <-b: + t.Errorf("resyncChan() is at least 99 milliseconds late??") + } +} + +func BenchmarkReflectorResyncChanMany(b *testing.B) { + s := NewStore(MetaNamespaceKeyFunc) + g := NewReflector(&testLW{}, &v1.Pod{}, s, 25*time.Millisecond) + // The improvement to this (calling the timer's Stop() method) makes + // this benchmark about 40% faster. + for i := 0; i < b.N; i++ { + g.resyncPeriod = time.Duration(rand.Float64() * float64(time.Millisecond) * 25) + _, stop := g.resyncChan() + stop() + } +} + +func TestReflectorWatchHandlerError(t *testing.T) { + s := NewStore(MetaNamespaceKeyFunc) + g := NewReflector(&testLW{}, &v1.Pod{}, s, 0) + fw := watch.NewFake() + go func() { + fw.Stop() + }() + var resumeRV string + err := g.watchHandler(fw, &resumeRV, nevererrc, wait.NeverStop) + if err == nil { + t.Errorf("unexpected non-error") + } +} + +func TestReflectorWatchHandler(t *testing.T) { + s := NewStore(MetaNamespaceKeyFunc) + g := NewReflector(&testLW{}, &v1.Pod{}, s, 0) + fw := watch.NewFake() + s.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) + s.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}}) + go func() { + fw.Add(&v1.Service{ObjectMeta: metav1.ObjectMeta{Name: "rejected"}}) + fw.Delete(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) + fw.Modify(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar", ResourceVersion: "55"}}) + fw.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "baz", ResourceVersion: "32"}}) + fw.Stop() + }() + var resumeRV string + err := g.watchHandler(fw, &resumeRV, nevererrc, wait.NeverStop) + if err != nil { + t.Errorf("unexpected error %v", err) + } + + mkPod := func(id string, rv string) *v1.Pod { + return &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: id, ResourceVersion: rv}} + } + + table := []struct { + Pod *v1.Pod + exists bool + }{ + {mkPod("foo", ""), false}, + {mkPod("rejected", ""), false}, + {mkPod("bar", "55"), true}, + {mkPod("baz", "32"), true}, + } + for _, item := range table { + obj, exists, _ := s.Get(item.Pod) + if e, a := item.exists, exists; e != a { + t.Errorf("%v: expected %v, got %v", item.Pod, e, a) + } + if !exists { + continue + } + if e, a := item.Pod.ResourceVersion, obj.(*v1.Pod).ResourceVersion; e != a { + t.Errorf("%v: expected %v, got %v", item.Pod, e, a) + } + } + + // RV should send the last version we see. + if e, a := "32", resumeRV; e != a { + t.Errorf("expected %v, got %v", e, a) + } + + // last sync resource version should be the last version synced with store + if e, a := "32", g.LastSyncResourceVersion(); e != a { + t.Errorf("expected %v, got %v", e, a) + } +} + +func TestReflectorStopWatch(t *testing.T) { + s := NewStore(MetaNamespaceKeyFunc) + g := NewReflector(&testLW{}, &v1.Pod{}, s, 0) + fw := watch.NewFake() + var resumeRV string + stopWatch := make(chan struct{}, 1) + stopWatch <- struct{}{} + err := g.watchHandler(fw, &resumeRV, nevererrc, stopWatch) + if err != errorStopRequested { + t.Errorf("expected stop error, got %q", err) + } +} + +func TestReflectorListAndWatch(t *testing.T) { + createdFakes := make(chan *watch.FakeWatcher) + + // The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc + // to get called at the beginning of the watch with 1, and again with 3 when we + // inject an error. + expectedRVs := []string{"1", "3"} + lw := &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + rv := options.ResourceVersion + fw := watch.NewFake() + if e, a := expectedRVs[0], rv; e != a { + t.Errorf("Expected rv %v, but got %v", e, a) + } + expectedRVs = expectedRVs[1:] + // channel is not buffered because the for loop below needs to block. But + // we don't want to block here, so report the new fake via a go routine. + go func() { createdFakes <- fw }() + return fw, nil + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "1"}}, nil + }, + } + s := NewFIFO(MetaNamespaceKeyFunc) + r := NewReflector(lw, &v1.Pod{}, s, 0) + go r.ListAndWatch(wait.NeverStop) + + ids := []string{"foo", "bar", "baz", "qux", "zoo"} + var fw *watch.FakeWatcher + for i, id := range ids { + if fw == nil { + fw = <-createdFakes + } + sendingRV := strconv.FormatUint(uint64(i+2), 10) + fw.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: id, ResourceVersion: sendingRV}}) + if sendingRV == "3" { + // Inject a failure. + fw.Stop() + fw = nil + } + } + + // Verify we received the right ids with the right resource versions. + for i, id := range ids { + pod := Pop(s).(*v1.Pod) + if e, a := id, pod.Name; e != a { + t.Errorf("%v: Expected %v, got %v", i, e, a) + } + if e, a := strconv.FormatUint(uint64(i+2), 10), pod.ResourceVersion; e != a { + t.Errorf("%v: Expected %v, got %v", i, e, a) + } + } + + if len(expectedRVs) != 0 { + t.Error("called watchStarter an unexpected number of times") + } +} + +func TestReflectorListAndWatchWithErrors(t *testing.T) { + mkPod := func(id string, rv string) *v1.Pod { + return &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: id, ResourceVersion: rv}} + } + mkList := func(rv string, pods ...*v1.Pod) *v1.PodList { + list := &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: rv}} + for _, pod := range pods { + list.Items = append(list.Items, *pod) + } + return list + } + table := []struct { + list *v1.PodList + listErr error + events []watch.Event + watchErr error + }{ + { + list: mkList("1"), + events: []watch.Event{ + {Type: watch.Added, Object: mkPod("foo", "2")}, + {Type: watch.Added, Object: mkPod("bar", "3")}, + }, + }, { + list: mkList("3", mkPod("foo", "2"), mkPod("bar", "3")), + events: []watch.Event{ + {Type: watch.Deleted, Object: mkPod("foo", "4")}, + {Type: watch.Added, Object: mkPod("qux", "5")}, + }, + }, { + listErr: fmt.Errorf("a list error"), + }, { + list: mkList("5", mkPod("bar", "3"), mkPod("qux", "5")), + watchErr: fmt.Errorf("a watch error"), + }, { + list: mkList("5", mkPod("bar", "3"), mkPod("qux", "5")), + events: []watch.Event{ + {Type: watch.Added, Object: mkPod("baz", "6")}, + }, + }, { + list: mkList("6", mkPod("bar", "3"), mkPod("qux", "5"), mkPod("baz", "6")), + }, + } + + s := NewFIFO(MetaNamespaceKeyFunc) + for line, item := range table { + if item.list != nil { + // Test that the list is what currently exists in the store. + current := s.List() + checkMap := map[string]string{} + for _, item := range current { + pod := item.(*v1.Pod) + checkMap[pod.Name] = pod.ResourceVersion + } + for _, pod := range item.list.Items { + if e, a := pod.ResourceVersion, checkMap[pod.Name]; e != a { + t.Errorf("%v: expected %v, got %v for pod %v", line, e, a, pod.Name) + } + } + if e, a := len(item.list.Items), len(checkMap); e != a { + t.Errorf("%v: expected %v, got %v", line, e, a) + } + } + watchRet, watchErr := item.events, item.watchErr + lw := &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if watchErr != nil { + return nil, watchErr + } + watchErr = fmt.Errorf("second watch") + fw := watch.NewFake() + go func() { + for _, e := range watchRet { + fw.Action(e.Type, e.Object) + } + fw.Stop() + }() + return fw, nil + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return item.list, item.listErr + }, + } + r := NewReflector(lw, &v1.Pod{}, s, 0) + r.ListAndWatch(wait.NeverStop) + } +} + +func TestReflectorResync(t *testing.T) { + iteration := 0 + stopCh := make(chan struct{}) + rerr := errors.New("expected resync reached") + s := &FakeCustomStore{ + ResyncFunc: func() error { + iteration++ + if iteration == 2 { + return rerr + } + return nil + }, + } + + lw := &testLW{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + fw := watch.NewFake() + return fw, nil + }, + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "0"}}, nil + }, + } + resyncPeriod := 1 * time.Millisecond + r := NewReflector(lw, &v1.Pod{}, s, resyncPeriod) + if err := r.ListAndWatch(stopCh); err != nil { + // error from Resync is not propaged up to here. + t.Errorf("expected error %v", err) + } + if iteration != 2 { + t.Errorf("exactly 2 iterations were expected, got: %v", iteration) + } +} diff --git a/vendor/k8s.io/client-go/tools/cache/shared_informer_test.go b/vendor/k8s.io/client-go/tools/cache/shared_informer_test.go new file mode 100644 index 000000000..22e4a90dd --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/shared_informer_test.go @@ -0,0 +1,265 @@ +/* +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 cache + +import ( + "fmt" + "sync" + "testing" + "time" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + fcache "k8s.io/client-go/tools/cache/testing" +) + +type testListener struct { + lock sync.RWMutex + resyncPeriod time.Duration + expectedItemNames sets.String + receivedItemNames []string + name string +} + +func newTestListener(name string, resyncPeriod time.Duration, expected ...string) *testListener { + l := &testListener{ + resyncPeriod: resyncPeriod, + expectedItemNames: sets.NewString(expected...), + name: name, + } + return l +} + +func (l *testListener) OnAdd(obj interface{}) { + l.handle(obj) +} + +func (l *testListener) OnUpdate(old, new interface{}) { + l.handle(new) +} + +func (l *testListener) OnDelete(obj interface{}) { +} + +func (l *testListener) handle(obj interface{}) { + key, _ := MetaNamespaceKeyFunc(obj) + fmt.Printf("%s: handle: %v\n", l.name, key) + l.lock.Lock() + defer l.lock.Unlock() + + objectMeta, _ := meta.Accessor(obj) + l.receivedItemNames = append(l.receivedItemNames, objectMeta.GetName()) +} + +func (l *testListener) ok() bool { + fmt.Println("polling") + err := wait.PollImmediate(100*time.Millisecond, 2*time.Second, func() (bool, error) { + if l.satisfiedExpectations() { + return true, nil + } + return false, nil + }) + if err != nil { + return false + } + + // wait just a bit to allow any unexpected stragglers to come in + fmt.Println("sleeping") + time.Sleep(1 * time.Second) + fmt.Println("final check") + return l.satisfiedExpectations() +} + +func (l *testListener) satisfiedExpectations() bool { + l.lock.RLock() + defer l.lock.RUnlock() + + return len(l.receivedItemNames) == l.expectedItemNames.Len() && sets.NewString(l.receivedItemNames...).Equal(l.expectedItemNames) +} + +func TestListenerResyncPeriods(t *testing.T) { + // source simulates an apiserver object endpoint. + source := fcache.NewFakeControllerSource() + source.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}}) + source.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod2"}}) + + // create the shared informer and resync every 1s + informer := NewSharedInformer(source, &v1.Pod{}, 1*time.Second).(*sharedIndexInformer) + + clock := clock.NewFakeClock(time.Now()) + informer.clock = clock + informer.processor.clock = clock + + // listener 1, never resync + listener1 := newTestListener("listener1", 0, "pod1", "pod2") + informer.AddEventHandlerWithResyncPeriod(listener1, listener1.resyncPeriod) + + // listener 2, resync every 2s + listener2 := newTestListener("listener2", 2*time.Second, "pod1", "pod2") + informer.AddEventHandlerWithResyncPeriod(listener2, listener2.resyncPeriod) + + // listener 3, resync every 3s + listener3 := newTestListener("listener3", 3*time.Second, "pod1", "pod2") + informer.AddEventHandlerWithResyncPeriod(listener3, listener3.resyncPeriod) + listeners := []*testListener{listener1, listener2, listener3} + + stop := make(chan struct{}) + defer close(stop) + + go informer.Run(stop) + + // ensure all listeners got the initial List + for _, listener := range listeners { + if !listener.ok() { + t.Errorf("%s: expected %v, got %v", listener.name, listener.expectedItemNames, listener.receivedItemNames) + } + } + + // reset + for _, listener := range listeners { + listener.receivedItemNames = []string{} + } + + // advance so listener2 gets a resync + clock.Step(2 * time.Second) + + // make sure listener2 got the resync + if !listener2.ok() { + t.Errorf("%s: expected %v, got %v", listener2.name, listener2.expectedItemNames, listener2.receivedItemNames) + } + + // wait a bit to give errant items a chance to go to 1 and 3 + time.Sleep(1 * time.Second) + + // make sure listeners 1 and 3 got nothing + if len(listener1.receivedItemNames) != 0 { + t.Errorf("listener1: should not have resynced (got %d)", len(listener1.receivedItemNames)) + } + if len(listener3.receivedItemNames) != 0 { + t.Errorf("listener3: should not have resynced (got %d)", len(listener3.receivedItemNames)) + } + + // reset + for _, listener := range listeners { + listener.receivedItemNames = []string{} + } + + // advance so listener3 gets a resync + clock.Step(1 * time.Second) + + // make sure listener3 got the resync + if !listener3.ok() { + t.Errorf("%s: expected %v, got %v", listener3.name, listener3.expectedItemNames, listener3.receivedItemNames) + } + + // wait a bit to give errant items a chance to go to 1 and 2 + time.Sleep(1 * time.Second) + + // make sure listeners 1 and 2 got nothing + if len(listener1.receivedItemNames) != 0 { + t.Errorf("listener1: should not have resynced (got %d)", len(listener1.receivedItemNames)) + } + if len(listener2.receivedItemNames) != 0 { + t.Errorf("listener2: should not have resynced (got %d)", len(listener2.receivedItemNames)) + } +} + +func TestResyncCheckPeriod(t *testing.T) { + // source simulates an apiserver object endpoint. + source := fcache.NewFakeControllerSource() + + // create the shared informer and resync every 12 hours + informer := NewSharedInformer(source, &v1.Pod{}, 12*time.Hour).(*sharedIndexInformer) + + clock := clock.NewFakeClock(time.Now()) + informer.clock = clock + informer.processor.clock = clock + + // listener 1, never resync + listener1 := newTestListener("listener1", 0) + informer.AddEventHandlerWithResyncPeriod(listener1, listener1.resyncPeriod) + if e, a := 12*time.Hour, informer.resyncCheckPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := time.Duration(0), informer.processor.listeners[0].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + + // listener 2, resync every minute + listener2 := newTestListener("listener2", 1*time.Minute) + informer.AddEventHandlerWithResyncPeriod(listener2, listener2.resyncPeriod) + if e, a := 1*time.Minute, informer.resyncCheckPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := time.Duration(0), informer.processor.listeners[0].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := 1*time.Minute, informer.processor.listeners[1].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + + // listener 3, resync every 55 seconds + listener3 := newTestListener("listener3", 55*time.Second) + informer.AddEventHandlerWithResyncPeriod(listener3, listener3.resyncPeriod) + if e, a := 55*time.Second, informer.resyncCheckPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := time.Duration(0), informer.processor.listeners[0].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := 1*time.Minute, informer.processor.listeners[1].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := 55*time.Second, informer.processor.listeners[2].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + + // listener 4, resync every 5 seconds + listener4 := newTestListener("listener4", 5*time.Second) + informer.AddEventHandlerWithResyncPeriod(listener4, listener4.resyncPeriod) + if e, a := 5*time.Second, informer.resyncCheckPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := time.Duration(0), informer.processor.listeners[0].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := 1*time.Minute, informer.processor.listeners[1].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := 55*time.Second, informer.processor.listeners[2].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } + if e, a := 5*time.Second, informer.processor.listeners[3].resyncPeriod; e != a { + t.Errorf("expected %d, got %d", e, a) + } +} + +// verify that https://github.com/kubernetes/kubernetes/issues/59822 is fixed +func TestSharedInformerInitializationRace(t *testing.T) { + source := fcache.NewFakeControllerSource() + informer := NewSharedInformer(source, &v1.Pod{}, 1*time.Second).(*sharedIndexInformer) + listener := newTestListener("raceListener", 0) + + stop := make(chan struct{}) + go informer.AddEventHandlerWithResyncPeriod(listener, listener.resyncPeriod) + go informer.Run(stop) + close(stop) +} diff --git a/vendor/k8s.io/client-go/tools/cache/store_test.go b/vendor/k8s.io/client-go/tools/cache/store_test.go new file mode 100644 index 000000000..52c9585a9 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/store_test.go @@ -0,0 +1,156 @@ +/* +Copyright 2014 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 cache + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/sets" +) + +// Test public interface +func doTestStore(t *testing.T, store Store) { + mkObj := func(id string, val string) testStoreObject { + return testStoreObject{id: id, val: val} + } + + store.Add(mkObj("foo", "bar")) + if item, ok, _ := store.Get(mkObj("foo", "")); !ok { + t.Errorf("didn't find inserted item") + } else { + if e, a := "bar", item.(testStoreObject).val; e != a { + t.Errorf("expected %v, got %v", e, a) + } + } + store.Update(mkObj("foo", "baz")) + if item, ok, _ := store.Get(mkObj("foo", "")); !ok { + t.Errorf("didn't find inserted item") + } else { + if e, a := "baz", item.(testStoreObject).val; e != a { + t.Errorf("expected %v, got %v", e, a) + } + } + store.Delete(mkObj("foo", "")) + if _, ok, _ := store.Get(mkObj("foo", "")); ok { + t.Errorf("found deleted item??") + } + + // Test List. + store.Add(mkObj("a", "b")) + store.Add(mkObj("c", "d")) + store.Add(mkObj("e", "e")) + { + found := sets.String{} + for _, item := range store.List() { + found.Insert(item.(testStoreObject).val) + } + if !found.HasAll("b", "d", "e") { + t.Errorf("missing items, found: %v", found) + } + if len(found) != 3 { + t.Errorf("extra items") + } + } + + // Test Replace. + store.Replace([]interface{}{ + mkObj("foo", "foo"), + mkObj("bar", "bar"), + }, "0") + + { + found := sets.String{} + for _, item := range store.List() { + found.Insert(item.(testStoreObject).val) + } + if !found.HasAll("foo", "bar") { + t.Errorf("missing items") + } + if len(found) != 2 { + t.Errorf("extra items") + } + } +} + +// Test public interface +func doTestIndex(t *testing.T, indexer Indexer) { + mkObj := func(id string, val string) testStoreObject { + return testStoreObject{id: id, val: val} + } + + // Test Index + expected := map[string]sets.String{} + expected["b"] = sets.NewString("a", "c") + expected["f"] = sets.NewString("e") + expected["h"] = sets.NewString("g") + indexer.Add(mkObj("a", "b")) + indexer.Add(mkObj("c", "b")) + indexer.Add(mkObj("e", "f")) + indexer.Add(mkObj("g", "h")) + { + for k, v := range expected { + found := sets.String{} + indexResults, err := indexer.Index("by_val", mkObj("", k)) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + for _, item := range indexResults { + found.Insert(item.(testStoreObject).id) + } + items := v.List() + if !found.HasAll(items...) { + t.Errorf("missing items, index %s, expected %v but found %v", k, items, found.List()) + } + } + } +} + +func testStoreKeyFunc(obj interface{}) (string, error) { + return obj.(testStoreObject).id, nil +} + +func testStoreIndexFunc(obj interface{}) ([]string, error) { + return []string{obj.(testStoreObject).val}, nil +} + +func testStoreIndexers() Indexers { + indexers := Indexers{} + indexers["by_val"] = testStoreIndexFunc + return indexers +} + +type testStoreObject struct { + id string + val string +} + +func TestCache(t *testing.T) { + doTestStore(t, NewStore(testStoreKeyFunc)) +} + +func TestFIFOCache(t *testing.T) { + doTestStore(t, NewFIFO(testStoreKeyFunc)) +} + +func TestUndeltaStore(t *testing.T) { + nop := func([]interface{}) {} + doTestStore(t, NewUndeltaStore(nop, testStoreKeyFunc)) +} + +func TestIndex(t *testing.T) { + doTestIndex(t, NewIndexer(testStoreKeyFunc, testStoreIndexers())) +} diff --git a/vendor/k8s.io/client-go/tools/cache/undelta_store_test.go b/vendor/k8s.io/client-go/tools/cache/undelta_store_test.go new file mode 100644 index 000000000..6316442e6 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/cache/undelta_store_test.go @@ -0,0 +1,131 @@ +/* +Copyright 2015 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 cache + +import ( + "reflect" + "testing" +) + +// store_test.go checks that UndeltaStore conforms to the Store interface +// behavior. This test just tests that it calls the push func in addition. + +type testUndeltaObject struct { + name string + val interface{} +} + +func testUndeltaKeyFunc(obj interface{}) (string, error) { + return obj.(testUndeltaObject).name, nil +} + +/* +var ( + o1 interface{} = t{1} + o2 interface{} = t{2} + l1 []interface{} = []interface{}{t{1}} +) +*/ + +func TestUpdateCallsPush(t *testing.T) { + mkObj := func(name string, val interface{}) testUndeltaObject { + return testUndeltaObject{name: name, val: val} + } + + var got []interface{} + var callcount int = 0 + push := func(m []interface{}) { + callcount++ + got = m + } + + u := NewUndeltaStore(push, testUndeltaKeyFunc) + + u.Add(mkObj("a", 2)) + u.Update(mkObj("a", 1)) + if callcount != 2 { + t.Errorf("Expected 2 calls, got %d", callcount) + } + + l := []interface{}{mkObj("a", 1)} + if !reflect.DeepEqual(l, got) { + t.Errorf("Expected %#v, Got %#v", l, got) + } +} + +func TestDeleteCallsPush(t *testing.T) { + mkObj := func(name string, val interface{}) testUndeltaObject { + return testUndeltaObject{name: name, val: val} + } + + var got []interface{} + var callcount int = 0 + push := func(m []interface{}) { + callcount++ + got = m + } + + u := NewUndeltaStore(push, testUndeltaKeyFunc) + + u.Add(mkObj("a", 2)) + u.Delete(mkObj("a", "")) + if callcount != 2 { + t.Errorf("Expected 2 calls, got %d", callcount) + } + expected := []interface{}{} + if !reflect.DeepEqual(expected, got) { + t.Errorf("Expected %#v, Got %#v", expected, got) + } +} + +func TestReadsDoNotCallPush(t *testing.T) { + push := func(m []interface{}) { + t.Errorf("Unexpected call to push!") + } + + u := NewUndeltaStore(push, testUndeltaKeyFunc) + + // These should not call push. + _ = u.List() + _, _, _ = u.Get(testUndeltaObject{"a", ""}) +} + +func TestReplaceCallsPush(t *testing.T) { + mkObj := func(name string, val interface{}) testUndeltaObject { + return testUndeltaObject{name: name, val: val} + } + + var got []interface{} + var callcount int = 0 + push := func(m []interface{}) { + callcount++ + got = m + } + + u := NewUndeltaStore(push, testUndeltaKeyFunc) + + m := []interface{}{mkObj("a", 1)} + + u.Replace(m, "0") + if callcount != 1 { + t.Errorf("Expected 1 calls, got %d", callcount) + } + expected := []interface{}{mkObj("a", 1)} + if !reflect.DeepEqual(expected, got) { + t.Errorf("Expected %#v, Got %#v", expected, got) + } +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/api/helpers_test.go b/vendor/k8s.io/client-go/tools/clientcmd/api/helpers_test.go new file mode 100644 index 000000000..7ec30e5da --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/api/helpers_test.go @@ -0,0 +1,302 @@ +/* +Copyright 2015 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 api + +import ( + "fmt" + "io/ioutil" + "os" + "reflect" + "testing" + + "github.com/ghodss/yaml" +) + +func newMergedConfig(certFile, certContent, keyFile, keyContent, caFile, caContent string, t *testing.T) Config { + if err := ioutil.WriteFile(certFile, []byte(certContent), 0644); err != nil { + t.Errorf("unexpected error: %v", err) + } + if err := ioutil.WriteFile(keyFile, []byte(keyContent), 0600); err != nil { + t.Errorf("unexpected error: %v", err) + } + if err := ioutil.WriteFile(caFile, []byte(caContent), 0644); err != nil { + t.Errorf("unexpected error: %v", err) + } + + return Config{ + AuthInfos: map[string]*AuthInfo{ + "red-user": {Token: "red-token", ClientCertificateData: []byte(certContent), ClientKeyData: []byte(keyContent)}, + "blue-user": {Token: "blue-token", ClientCertificate: certFile, ClientKey: keyFile}}, + Clusters: map[string]*Cluster{ + "cow-cluster": {Server: "http://cow.org:8080", CertificateAuthorityData: []byte(caContent)}, + "chicken-cluster": {Server: "http://chicken.org:8080", CertificateAuthority: caFile}}, + Contexts: map[string]*Context{ + "federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"}, + "shaker-context": {AuthInfo: "blue-user", Cluster: "chicken-cluster"}}, + CurrentContext: "federal-context", + } +} + +func TestMinifySuccess(t *testing.T) { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t) + + if err := MinifyConfig(&mutatingConfig); err != nil { + t.Errorf("unexpected error: %v", err) + } + + if len(mutatingConfig.Contexts) > 1 { + t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts) + } + if _, exists := mutatingConfig.Contexts["federal-context"]; !exists { + t.Errorf("missing context") + } + + if len(mutatingConfig.Clusters) > 1 { + t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters) + } + if _, exists := mutatingConfig.Clusters["cow-cluster"]; !exists { + t.Errorf("missing cluster") + } + + if len(mutatingConfig.AuthInfos) > 1 { + t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos) + } + if _, exists := mutatingConfig.AuthInfos["red-user"]; !exists { + t.Errorf("missing user") + } +} + +func TestMinifyMissingContext(t *testing.T) { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t) + mutatingConfig.CurrentContext = "missing" + + errMsg := "cannot locate context missing" + + if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg { + t.Errorf("expected %v, got %v", errMsg, err) + } +} + +func TestMinifyMissingCluster(t *testing.T) { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t) + delete(mutatingConfig.Clusters, mutatingConfig.Contexts[mutatingConfig.CurrentContext].Cluster) + + errMsg := "cannot locate cluster cow-cluster" + + if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg { + t.Errorf("expected %v, got %v", errMsg, err) + } +} + +func TestMinifyMissingAuthInfo(t *testing.T) { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t) + delete(mutatingConfig.AuthInfos, mutatingConfig.Contexts[mutatingConfig.CurrentContext].AuthInfo) + + errMsg := "cannot locate user red-user" + + if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg { + t.Errorf("expected %v, got %v", errMsg, err) + } +} + +func TestFlattenSuccess(t *testing.T) { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + certData := "cert" + keyData := "key" + caData := "ca" + + unchangingCluster := "cow-cluster" + unchangingAuthInfo := "red-user" + changingCluster := "chicken-cluster" + changingAuthInfo := "blue-user" + + startingConfig := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, t) + mutatingConfig := startingConfig + + if err := FlattenConfig(&mutatingConfig); err != nil { + t.Errorf("unexpected error: %v", err) + } + + if len(mutatingConfig.Contexts) != 2 { + t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts) + } + if !reflect.DeepEqual(startingConfig.Contexts, mutatingConfig.Contexts) { + t.Errorf("expected %v, got %v", startingConfig.Contexts, mutatingConfig.Contexts) + } + + if len(mutatingConfig.Clusters) != 2 { + t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters) + } + if !reflect.DeepEqual(startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) { + t.Errorf("expected %v, got %v", startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) + } + if len(mutatingConfig.Clusters[changingCluster].CertificateAuthority) != 0 { + t.Errorf("unexpected caFile") + } + if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != caData { + t.Errorf("expected %v, got %v", caData, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData)) + } + + if len(mutatingConfig.AuthInfos) != 2 { + t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos) + } + if !reflect.DeepEqual(startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) { + t.Errorf("expected %v, got %v", startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) + } + if len(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificate) != 0 { + t.Errorf("unexpected caFile") + } + if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData) != certData { + t.Errorf("expected %v, got %v", certData, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData)) + } + if len(mutatingConfig.AuthInfos[changingAuthInfo].ClientKey) != 0 { + t.Errorf("unexpected caFile") + } + if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData) != keyData { + t.Errorf("expected %v, got %v", keyData, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData)) + } + +} + +func Example_minifyAndShorten() { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + certData := "cert" + keyData := "key" + caData := "ca" + + config := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, nil) + + MinifyConfig(&config) + ShortenConfig(&config) + + output, _ := yaml.Marshal(config) + fmt.Printf("%s", string(output)) + // Output: + // clusters: + // cow-cluster: + // LocationOfOrigin: "" + // certificate-authority-data: DATA+OMITTED + // server: http://cow.org:8080 + // contexts: + // federal-context: + // LocationOfOrigin: "" + // cluster: cow-cluster + // user: red-user + // current-context: federal-context + // preferences: {} + // users: + // red-user: + // LocationOfOrigin: "" + // client-certificate-data: REDACTED + // client-key-data: REDACTED + // token: red-token +} + +func TestShortenSuccess(t *testing.T) { + certFile, _ := ioutil.TempFile("", "") + defer os.Remove(certFile.Name()) + keyFile, _ := ioutil.TempFile("", "") + defer os.Remove(keyFile.Name()) + caFile, _ := ioutil.TempFile("", "") + defer os.Remove(caFile.Name()) + + certData := "cert" + keyData := "key" + caData := "ca" + + unchangingCluster := "chicken-cluster" + unchangingAuthInfo := "blue-user" + changingCluster := "cow-cluster" + changingAuthInfo := "red-user" + + startingConfig := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, t) + mutatingConfig := startingConfig + + ShortenConfig(&mutatingConfig) + + if len(mutatingConfig.Contexts) != 2 { + t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts) + } + if !reflect.DeepEqual(startingConfig.Contexts, mutatingConfig.Contexts) { + t.Errorf("expected %v, got %v", startingConfig.Contexts, mutatingConfig.Contexts) + } + + redacted := string(redactedBytes) + dataOmitted := string(dataOmittedBytes) + if len(mutatingConfig.Clusters) != 2 { + t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters) + } + if !reflect.DeepEqual(startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) { + t.Errorf("expected %v, got %v", startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) + } + if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != dataOmitted { + t.Errorf("expected %v, got %v", dataOmitted, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData)) + } + + if len(mutatingConfig.AuthInfos) != 2 { + t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos) + } + if !reflect.DeepEqual(startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) { + t.Errorf("expected %v, got %v", startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) + } + if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData) != redacted { + t.Errorf("expected %v, got %v", redacted, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData)) + } + if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData) != redacted { + t.Errorf("expected %v, got %v", redacted, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData)) + } +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/api/types_test.go b/vendor/k8s.io/client-go/tools/clientcmd/api/types_test.go new file mode 100644 index 000000000..bd3483452 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/api/types_test.go @@ -0,0 +1,135 @@ +/* +Copyright 2014 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 api + +import ( + "fmt" + + "github.com/ghodss/yaml" +) + +func Example_emptyConfig() { + defaultConfig := NewConfig() + + output, err := yaml.Marshal(defaultConfig) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + + fmt.Printf("%v", string(output)) + // Output: + // clusters: {} + // contexts: {} + // current-context: "" + // preferences: {} + // users: {} +} + +func Example_ofOptionsConfig() { + defaultConfig := NewConfig() + defaultConfig.Preferences.Colors = true + defaultConfig.Clusters["alfa"] = &Cluster{ + Server: "https://alfa.org:8080", + InsecureSkipTLSVerify: true, + CertificateAuthority: "path/to/my/cert-ca-filename", + } + defaultConfig.Clusters["bravo"] = &Cluster{ + Server: "https://bravo.org:8080", + InsecureSkipTLSVerify: false, + } + defaultConfig.AuthInfos["white-mage-via-cert"] = &AuthInfo{ + ClientCertificate: "path/to/my/client-cert-filename", + ClientKey: "path/to/my/client-key-filename", + } + defaultConfig.AuthInfos["red-mage-via-token"] = &AuthInfo{ + Token: "my-secret-token", + } + defaultConfig.AuthInfos["black-mage-via-auth-provider"] = &AuthInfo{ + AuthProvider: &AuthProviderConfig{ + Name: "gcp", + Config: map[string]string{ + "foo": "bar", + "token": "s3cr3t-t0k3n", + }, + }, + } + defaultConfig.Contexts["bravo-as-black-mage"] = &Context{ + Cluster: "bravo", + AuthInfo: "black-mage-via-auth-provider", + Namespace: "yankee", + } + defaultConfig.Contexts["alfa-as-black-mage"] = &Context{ + Cluster: "alfa", + AuthInfo: "black-mage-via-auth-provider", + Namespace: "zulu", + } + defaultConfig.Contexts["alfa-as-white-mage"] = &Context{ + Cluster: "alfa", + AuthInfo: "white-mage-via-cert", + } + defaultConfig.CurrentContext = "alfa-as-white-mage" + + output, err := yaml.Marshal(defaultConfig) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + + fmt.Printf("%v", string(output)) + // Output: + // clusters: + // alfa: + // LocationOfOrigin: "" + // certificate-authority: path/to/my/cert-ca-filename + // insecure-skip-tls-verify: true + // server: https://alfa.org:8080 + // bravo: + // LocationOfOrigin: "" + // server: https://bravo.org:8080 + // contexts: + // alfa-as-black-mage: + // LocationOfOrigin: "" + // cluster: alfa + // namespace: zulu + // user: black-mage-via-auth-provider + // alfa-as-white-mage: + // LocationOfOrigin: "" + // cluster: alfa + // user: white-mage-via-cert + // bravo-as-black-mage: + // LocationOfOrigin: "" + // cluster: bravo + // namespace: yankee + // user: black-mage-via-auth-provider + // current-context: alfa-as-white-mage + // preferences: + // colors: true + // users: + // black-mage-via-auth-provider: + // LocationOfOrigin: "" + // auth-provider: + // config: + // foo: bar + // token: s3cr3t-t0k3n + // name: gcp + // red-mage-via-token: + // LocationOfOrigin: "" + // token: my-secret-token + // white-mage-via-cert: + // LocationOfOrigin: "" + // client-certificate: path/to/my/client-cert-filename + // client-key: path/to/my/client-key-filename +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/client_config_test.go b/vendor/k8s.io/client-go/tools/clientcmd/client_config_test.go new file mode 100644 index 000000000..21a7d3227 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/client_config_test.go @@ -0,0 +1,681 @@ +/* +Copyright 2014 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 clientcmd + +import ( + "io/ioutil" + "os" + "reflect" + "strings" + "testing" + + "github.com/imdario/mergo" + restclient "k8s.io/client-go/rest" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +func TestMergoSemantics(t *testing.T) { + type U struct { + A string + B int64 + } + type T struct { + S []string + X string + Y int64 + U U + } + var testDataStruct = []struct { + dst T + src T + expected T + }{ + { + dst: T{X: "one"}, + src: T{X: "two"}, + expected: T{X: "two"}, + }, + { + dst: T{X: "one", Y: 5, U: U{A: "four", B: 6}}, + src: T{X: "two", U: U{A: "three", B: 4}}, + expected: T{X: "two", Y: 5, U: U{A: "three", B: 4}}, + }, + { + dst: T{S: []string{"test3", "test4", "test5"}}, + src: T{S: []string{"test1", "test2", "test3"}}, + expected: T{S: []string{"test1", "test2", "test3"}}, + }, + } + for _, data := range testDataStruct { + err := mergo.MergeWithOverwrite(&data.dst, &data.src) + if err != nil { + t.Errorf("error while merging: %s", err) + } + if !reflect.DeepEqual(data.dst, data.expected) { + // The mergo library has previously changed in a an incompatible way. + // example: + // + // https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a + // + // This test verifies that the semantics of the merge are what we expect. + // If they are not, the mergo library may have been updated and broken + // unexpectedly. + t.Errorf("mergo.MergeWithOverwrite did not provide expected output: %+v doesn't match %+v", data.dst, data.expected) + } + } + + var testDataMap = []struct { + dst map[string]int + src map[string]int + expected map[string]int + }{ + { + dst: map[string]int{"rsc": 6543, "r": 2138, "gri": 1908, "adg": 912, "prt": 22}, + src: map[string]int{"rsc": 3711, "r": 2138, "gri": 1908, "adg": 912}, + expected: map[string]int{"rsc": 3711, "r": 2138, "gri": 1908, "adg": 912, "prt": 22}, + }, + } + for _, data := range testDataMap { + err := mergo.MergeWithOverwrite(&data.dst, &data.src) + if err != nil { + t.Errorf("error while merging: %s", err) + } + if !reflect.DeepEqual(data.dst, data.expected) { + // The mergo library has previously changed in a an incompatible way. + // example: + // + // https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a + // + // This test verifies that the semantics of the merge are what we expect. + // If they are not, the mergo library may have been updated and broken + // unexpectedly. + t.Errorf("mergo.MergeWithOverwrite did not provide expected output: %+v doesn't match %+v", data.dst, data.expected) + } + } +} + +func createValidTestConfig() *clientcmdapi.Config { + const ( + server = "https://anything.com:8080" + token = "the-token" + ) + + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: server, + } + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + Token: token, + } + config.Contexts["clean"] = &clientcmdapi.Context{ + Cluster: "clean", + AuthInfo: "clean", + } + config.CurrentContext = "clean" + + return config +} + +func createCAValidTestConfig() *clientcmdapi.Config { + + config := createValidTestConfig() + config.Clusters["clean"].CertificateAuthorityData = []byte{0, 0} + return config +} + +func TestInsecureOverridesCA(t *testing.T) { + config := createCAValidTestConfig() + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + InsecureSkipTLSVerify: true, + }, + }, nil) + + actualCfg, err := clientBuilder.ClientConfig() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + matchBoolArg(true, actualCfg.Insecure, t) + matchStringArg("", actualCfg.TLSClientConfig.CAFile, t) + matchByteArg(nil, actualCfg.TLSClientConfig.CAData, t) +} + +func TestMergeContext(t *testing.T) { + const namespace = "overridden-namespace" + + config := createValidTestConfig() + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) + + _, overridden, err := clientBuilder.Namespace() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if overridden { + t.Error("Expected namespace to not be overridden") + } + + clientBuilder = NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{ + Context: clientcmdapi.Context{ + Namespace: namespace, + }, + }, nil) + + actual, overridden, err := clientBuilder.Namespace() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !overridden { + t.Error("Expected namespace to be overridden") + } + + matchStringArg(namespace, actual, t) +} + +func TestModifyContext(t *testing.T) { + expectedCtx := map[string]bool{ + "updated": true, + "clean": true, + } + + tempPath, err := ioutil.TempFile("", "testclientcmd-") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + defer os.Remove(tempPath.Name()) + + pathOptions := NewDefaultPathOptions() + config := createValidTestConfig() + + pathOptions.GlobalFile = tempPath.Name() + + // define new context and assign it - our path options config + config.Contexts["updated"] = &clientcmdapi.Context{ + Cluster: "updated", + AuthInfo: "updated", + } + config.CurrentContext = "updated" + + if err := ModifyConfig(pathOptions, *config, true); err != nil { + t.Errorf("Unexpected error: %v", err) + } + + startingConfig, err := pathOptions.GetStartingConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // make sure the current context was updated + matchStringArg("updated", startingConfig.CurrentContext, t) + + // there should now be two contexts + if len(startingConfig.Contexts) != len(expectedCtx) { + t.Fatalf("unexpected nuber of contexts, expecting %v, but found %v", len(expectedCtx), len(startingConfig.Contexts)) + } + + for key := range startingConfig.Contexts { + if !expectedCtx[key] { + t.Fatalf("expected context %q to exist", key) + } + } +} + +func TestCertificateData(t *testing.T) { + caData := []byte("ca-data") + certData := []byte("cert-data") + keyData := []byte("key-data") + + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "https://localhost:8443", + CertificateAuthorityData: caData, + } + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + ClientCertificateData: certData, + ClientKeyData: keyData, + } + config.Contexts["clean"] = &clientcmdapi.Context{ + Cluster: "clean", + AuthInfo: "clean", + } + config.CurrentContext = "clean" + + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // Make sure cert data gets into config (will override file paths) + matchByteArg(caData, clientConfig.TLSClientConfig.CAData, t) + matchByteArg(certData, clientConfig.TLSClientConfig.CertData, t) + matchByteArg(keyData, clientConfig.TLSClientConfig.KeyData, t) +} + +func TestBasicAuthData(t *testing.T) { + username := "myuser" + password := "mypass" + + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "https://localhost:8443", + } + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + Username: username, + Password: password, + } + config.Contexts["clean"] = &clientcmdapi.Context{ + Cluster: "clean", + AuthInfo: "clean", + } + config.CurrentContext = "clean" + + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // Make sure basic auth data gets into config + matchStringArg(username, clientConfig.Username, t) + matchStringArg(password, clientConfig.Password, t) +} + +func TestBasicTokenFile(t *testing.T) { + token := "exampletoken" + f, err := ioutil.TempFile("", "tokenfile") + if err != nil { + t.Errorf("Unexpected error: %v", err) + return + } + defer os.Remove(f.Name()) + if err := ioutil.WriteFile(f.Name(), []byte(token), 0644); err != nil { + t.Errorf("Unexpected error: %v", err) + return + } + + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "https://localhost:8443", + } + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + TokenFile: f.Name(), + } + config.Contexts["clean"] = &clientcmdapi.Context{ + Cluster: "clean", + AuthInfo: "clean", + } + config.CurrentContext = "clean" + + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + matchStringArg(token, clientConfig.BearerToken, t) +} + +func TestPrecedenceTokenFile(t *testing.T) { + token := "exampletoken" + f, err := ioutil.TempFile("", "tokenfile") + if err != nil { + t.Errorf("Unexpected error: %v", err) + return + } + defer os.Remove(f.Name()) + if err := ioutil.WriteFile(f.Name(), []byte(token), 0644); err != nil { + t.Errorf("Unexpected error: %v", err) + return + } + + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "https://localhost:8443", + } + expectedToken := "expected" + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + Token: expectedToken, + TokenFile: f.Name(), + } + config.Contexts["clean"] = &clientcmdapi.Context{ + Cluster: "clean", + AuthInfo: "clean", + } + config.CurrentContext = "clean" + + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + matchStringArg(expectedToken, clientConfig.BearerToken, t) +} + +func TestCreateClean(t *testing.T) { + config := createValidTestConfig() + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t) + matchStringArg("", clientConfig.APIPath, t) + matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t) + matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t) +} + +func TestCreateCleanWithPrefix(t *testing.T) { + tt := []struct { + server string + host string + }{ + {"https://anything.com:8080/foo/bar", "https://anything.com:8080/foo/bar"}, + {"http://anything.com:8080/foo/bar", "http://anything.com:8080/foo/bar"}, + {"http://anything.com:8080/foo/bar/", "http://anything.com:8080/foo/bar/"}, + {"http://anything.com:8080/", "http://anything.com:8080/"}, + {"http://anything.com:8080//", "http://anything.com:8080//"}, + {"anything.com:8080/foo/bar", "anything.com:8080/foo/bar"}, + {"anything.com:8080", "anything.com:8080"}, + {"anything.com", "anything.com"}, + {"anything", "anything"}, + } + + tt = append(tt, struct{ server, host string }{"", "http://localhost:8080"}) + + for _, tc := range tt { + config := createValidTestConfig() + + cleanConfig := config.Clusters["clean"] + cleanConfig.Server = tc.server + config.Clusters["clean"] = cleanConfig + + clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{ + ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"}, + }, nil) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + matchStringArg(tc.host, clientConfig.Host, t) + } +} + +func TestCreateCleanDefault(t *testing.T) { + config := createValidTestConfig() + clientBuilder := NewDefaultClientConfig(*config, &ConfigOverrides{}) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t) + matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t) + matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t) +} + +func TestCreateCleanDefaultCluster(t *testing.T) { + config := createValidTestConfig() + clientBuilder := NewDefaultClientConfig(*config, &ConfigOverrides{ + ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"}, + }) + + clientConfig, err := clientBuilder.ClientConfig() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t) + matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t) + matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t) +} + +func TestCreateMissingContextNoDefault(t *testing.T) { + const expectedErrorContains = "Context was not found for specified context" + config := createValidTestConfig() + clientBuilder := NewNonInteractiveClientConfig(*config, "not-present", &ConfigOverrides{}, nil) + + _, err := clientBuilder.ClientConfig() + if err == nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestCreateMissingContext(t *testing.T) { + const expectedErrorContains = "context was not found for specified context: not-present" + config := createValidTestConfig() + clientBuilder := NewNonInteractiveClientConfig(*config, "not-present", &ConfigOverrides{ + ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"}, + }, nil) + + _, err := clientBuilder.ClientConfig() + if err == nil { + t.Fatalf("Expected error: %v", expectedErrorContains) + } + if !strings.Contains(err.Error(), expectedErrorContains) { + t.Fatalf("Expected error: %v, but got %v", expectedErrorContains, err) + } +} + +func TestInClusterClientConfigPrecedence(t *testing.T) { + tt := []struct { + overrides *ConfigOverrides + }{ + { + overrides: &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + Server: "https://host-from-overrides.com", + }, + }, + }, + { + overrides: &ConfigOverrides{ + AuthInfo: clientcmdapi.AuthInfo{ + Token: "https://host-from-overrides.com", + }, + }, + }, + { + overrides: &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + CertificateAuthority: "/path/to/ca-from-overrides.crt", + }, + }, + }, + { + overrides: &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + Server: "https://host-from-overrides.com", + }, + AuthInfo: clientcmdapi.AuthInfo{ + Token: "https://host-from-overrides.com", + }, + }, + }, + { + overrides: &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + Server: "https://host-from-overrides.com", + CertificateAuthority: "/path/to/ca-from-overrides.crt", + }, + }, + }, + { + overrides: &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + CertificateAuthority: "/path/to/ca-from-overrides.crt", + }, + AuthInfo: clientcmdapi.AuthInfo{ + Token: "https://host-from-overrides.com", + }, + }, + }, + { + overrides: &ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + Server: "https://host-from-overrides.com", + CertificateAuthority: "/path/to/ca-from-overrides.crt", + }, + AuthInfo: clientcmdapi.AuthInfo{ + Token: "https://host-from-overrides.com", + }, + }, + }, + { + overrides: &ConfigOverrides{}, + }, + } + + for _, tc := range tt { + expectedServer := "https://host-from-cluster.com" + expectedToken := "token-from-cluster" + expectedCAFile := "/path/to/ca-from-cluster.crt" + + icc := &inClusterClientConfig{ + inClusterConfigProvider: func() (*restclient.Config, error) { + return &restclient.Config{ + Host: expectedServer, + BearerToken: expectedToken, + TLSClientConfig: restclient.TLSClientConfig{ + CAFile: expectedCAFile, + }, + }, nil + }, + overrides: tc.overrides, + } + + clientConfig, err := icc.ClientConfig() + if err != nil { + t.Fatalf("Unxpected error: %v", err) + } + + if overridenServer := tc.overrides.ClusterInfo.Server; len(overridenServer) > 0 { + expectedServer = overridenServer + } + if overridenToken := tc.overrides.AuthInfo.Token; len(overridenToken) > 0 { + expectedToken = overridenToken + } + if overridenCAFile := tc.overrides.ClusterInfo.CertificateAuthority; len(overridenCAFile) > 0 { + expectedCAFile = overridenCAFile + } + + if clientConfig.Host != expectedServer { + t.Errorf("Expected server %v, got %v", expectedServer, clientConfig.Host) + } + if clientConfig.BearerToken != expectedToken { + t.Errorf("Expected token %v, got %v", expectedToken, clientConfig.BearerToken) + } + if clientConfig.TLSClientConfig.CAFile != expectedCAFile { + t.Errorf("Expected Certificate Authority %v, got %v", expectedCAFile, clientConfig.TLSClientConfig.CAFile) + } + } +} + +func matchBoolArg(expected, got bool, t *testing.T) { + if expected != got { + t.Errorf("Expected %v, got %v", expected, got) + } +} + +func matchStringArg(expected, got string, t *testing.T) { + if expected != got { + t.Errorf("Expected %q, got %q", expected, got) + } +} + +func matchByteArg(expected, got []byte, t *testing.T) { + if !reflect.DeepEqual(expected, got) { + t.Errorf("Expected %v, got %v", expected, got) + } +} + +func TestNamespaceOverride(t *testing.T) { + config := &DirectClientConfig{ + overrides: &ConfigOverrides{ + Context: clientcmdapi.Context{ + Namespace: "foo", + }, + }, + } + + ns, overridden, err := config.Namespace() + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !overridden { + t.Errorf("Expected overridden = true") + } + + matchStringArg("foo", ns, t) +} + +func TestAuthConfigMerge(t *testing.T) { + content := ` +apiVersion: v1 +clusters: +- cluster: + server: https://localhost:8080 + name: foo-cluster +contexts: +- context: + cluster: foo-cluster + user: foo-user + namespace: bar + name: foo-context +current-context: foo-context +kind: Config +users: +- name: foo-user + user: + exec: + apiVersion: client.authentication.k8s.io/v1alpha1 + args: + - arg-1 + - arg-2 + command: foo-command +` + tmpfile, err := ioutil.TempFile("", "kubeconfig") + if err != nil { + t.Error(err) + } + defer os.Remove(tmpfile.Name()) + if err := ioutil.WriteFile(tmpfile.Name(), []byte(content), 0666); err != nil { + t.Error(err) + } + config, err := BuildConfigFromFlags("", tmpfile.Name()) + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(config.ExecProvider.Args, []string{"arg-1", "arg-2"}) { + t.Errorf("Got args %v when they should be %v\n", config.ExecProvider.Args, []string{"arg-1", "arg-2"}) + } + +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/loader_test.go b/vendor/k8s.io/client-go/tools/clientcmd/loader_test.go new file mode 100644 index 000000000..86eccac45 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/loader_test.go @@ -0,0 +1,789 @@ +/* +Copyright 2014 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 clientcmd + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "reflect" + "strings" + "testing" + + "github.com/ghodss/yaml" + + "k8s.io/apimachinery/pkg/runtime" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest" +) + +var ( + testConfigAlfa = clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "red-user": {Token: "red-token"}}, + Clusters: map[string]*clientcmdapi.Cluster{ + "cow-cluster": {Server: "http://cow.org:8080"}}, + Contexts: map[string]*clientcmdapi.Context{ + "federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster", Namespace: "hammer-ns"}}, + } + testConfigBravo = clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "black-user": {Token: "black-token"}}, + Clusters: map[string]*clientcmdapi.Cluster{ + "pig-cluster": {Server: "http://pig.org:8080"}}, + Contexts: map[string]*clientcmdapi.Context{ + "queen-anne-context": {AuthInfo: "black-user", Cluster: "pig-cluster", Namespace: "saw-ns"}}, + } + testConfigCharlie = clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "green-user": {Token: "green-token"}}, + Clusters: map[string]*clientcmdapi.Cluster{ + "horse-cluster": {Server: "http://horse.org:8080"}}, + Contexts: map[string]*clientcmdapi.Context{ + "shaker-context": {AuthInfo: "green-user", Cluster: "horse-cluster", Namespace: "chisel-ns"}}, + } + testConfigDelta = clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "blue-user": {Token: "blue-token"}}, + Clusters: map[string]*clientcmdapi.Cluster{ + "chicken-cluster": {Server: "http://chicken.org:8080"}}, + Contexts: map[string]*clientcmdapi.Context{ + "gothic-context": {AuthInfo: "blue-user", Cluster: "chicken-cluster", Namespace: "plane-ns"}}, + } + + testConfigConflictAlfa = clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "red-user": {Token: "a-different-red-token"}, + "yellow-user": {Token: "yellow-token"}}, + Clusters: map[string]*clientcmdapi.Cluster{ + "cow-cluster": {Server: "http://a-different-cow.org:8080", InsecureSkipTLSVerify: true}, + "donkey-cluster": {Server: "http://donkey.org:8080", InsecureSkipTLSVerify: true}}, + CurrentContext: "federal-context", + } +) + +func TestNonExistentCommandLineFile(t *testing.T) { + loadingRules := ClientConfigLoadingRules{ + ExplicitPath: "bogus_file", + } + + _, err := loadingRules.Load() + if err == nil { + t.Fatalf("Expected error for missing command-line file, got none") + } + if !strings.Contains(err.Error(), "bogus_file") { + t.Fatalf("Expected error about 'bogus_file', got %s", err.Error()) + } +} + +func TestToleratingMissingFiles(t *testing.T) { + loadingRules := ClientConfigLoadingRules{ + Precedence: []string{"bogus1", "bogus2", "bogus3"}, + } + + _, err := loadingRules.Load() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestErrorReadingFile(t *testing.T) { + commandLineFile, _ := ioutil.TempFile("", "") + defer os.Remove(commandLineFile.Name()) + + if err := ioutil.WriteFile(commandLineFile.Name(), []byte("bogus value"), 0644); err != nil { + t.Fatalf("Error creating tempfile: %v", err) + } + + loadingRules := ClientConfigLoadingRules{ + ExplicitPath: commandLineFile.Name(), + } + + _, err := loadingRules.Load() + if err == nil { + t.Fatalf("Expected error for unloadable file, got none") + } + if !strings.Contains(err.Error(), commandLineFile.Name()) { + t.Fatalf("Expected error about '%s', got %s", commandLineFile.Name(), err.Error()) + } +} + +func TestErrorReadingNonFile(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("Couldn't create tmpdir") + } + defer os.RemoveAll(tmpdir) + + loadingRules := ClientConfigLoadingRules{ + ExplicitPath: tmpdir, + } + + _, err = loadingRules.Load() + if err == nil { + t.Fatalf("Expected error for non-file, got none") + } + if !strings.Contains(err.Error(), tmpdir) { + t.Fatalf("Expected error about '%s', got %s", tmpdir, err.Error()) + } +} + +func TestConflictingCurrentContext(t *testing.T) { + commandLineFile, _ := ioutil.TempFile("", "") + defer os.Remove(commandLineFile.Name()) + envVarFile, _ := ioutil.TempFile("", "") + defer os.Remove(envVarFile.Name()) + + mockCommandLineConfig := clientcmdapi.Config{ + CurrentContext: "any-context-value", + } + mockEnvVarConfig := clientcmdapi.Config{ + CurrentContext: "a-different-context", + } + + WriteToFile(mockCommandLineConfig, commandLineFile.Name()) + WriteToFile(mockEnvVarConfig, envVarFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + ExplicitPath: commandLineFile.Name(), + Precedence: []string{envVarFile.Name()}, + } + + mergedConfig, err := loadingRules.Load() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if mergedConfig.CurrentContext != mockCommandLineConfig.CurrentContext { + t.Errorf("expected %v, got %v", mockCommandLineConfig.CurrentContext, mergedConfig.CurrentContext) + } +} + +func TestLoadingEmptyMaps(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + mockConfig := clientcmdapi.Config{ + CurrentContext: "any-context-value", + } + + WriteToFile(mockConfig, configFile.Name()) + + config, err := LoadFromFile(configFile.Name()) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if config.Clusters == nil { + t.Error("expected config.Clusters to be non-nil") + } + if config.AuthInfos == nil { + t.Error("expected config.AuthInfos to be non-nil") + } + if config.Contexts == nil { + t.Error("expected config.Contexts to be non-nil") + } +} + +func TestDuplicateClusterName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +- cluster: + api-version: v2 + server: https://test.example.server:443 + certificate-authority: /var/run/secrets/test.example.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedCluster into *map[string]*api.Cluster: duplicate name \"kubeconfig-cluster\" in list") { + t.Error("Expected error in loading duplicate cluster name, got none") + } +} + +func TestDuplicateContextName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +- context: + cluster: test-example-cluster + namespace: test-example + user: test-example-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedContext into *map[string]*api.Context: duplicate name \"kubeconfig-context\" in list") { + t.Error("Expected error in loading duplicate context name, got none") + } +} + +func TestDuplicateUserName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/test.example.com/serviceaccount/token +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedAuthInfo into *map[string]*api.AuthInfo: duplicate name \"kubeconfig-user\" in list") { + t.Error("Expected error in loading duplicate user name, got none") + } +} + +func TestDuplicateExtensionName(t *testing.T) { + configFile, _ := ioutil.TempFile("", "") + defer os.Remove(configFile.Name()) + + err := ioutil.WriteFile(configFile.Name(), []byte(` +kind: Config +apiVersion: v1 +clusters: +- cluster: + api-version: v1 + server: https://kubernetes.default.svc:443 + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + name: kubeconfig-cluster +contexts: +- context: + cluster: kubeconfig-cluster + namespace: default + user: kubeconfig-user + name: kubeconfig-context +current-context: kubeconfig-context +users: +- name: kubeconfig-user + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +extensions: +- extension: + bytes: test + name: test-extension +- extension: + bytes: some-example + name: test-extension +`), os.FileMode(0755)) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + _, err = LoadFromFile(configFile.Name()) + if err == nil || !strings.Contains(err.Error(), + "error converting *[]NamedExtension into *map[string]runtime.Object: duplicate name \"test-extension\" in list") { + t.Error("Expected error in loading duplicate extension name, got none") + } +} + +func TestResolveRelativePaths(t *testing.T) { + pathResolutionConfig1 := clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "relative-user-1": {ClientCertificate: "relative/client/cert", ClientKey: "../relative/client/key"}, + "absolute-user-1": {ClientCertificate: "/absolute/client/cert", ClientKey: "/absolute/client/key"}, + "relative-cmd-1": {Exec: &clientcmdapi.ExecConfig{Command: "../relative/client/cmd"}}, + "absolute-cmd-1": {Exec: &clientcmdapi.ExecConfig{Command: "/absolute/client/cmd"}}, + "PATH-cmd-1": {Exec: &clientcmdapi.ExecConfig{Command: "cmd"}}, + }, + Clusters: map[string]*clientcmdapi.Cluster{ + "relative-server-1": {CertificateAuthority: "../relative/ca"}, + "absolute-server-1": {CertificateAuthority: "/absolute/ca"}, + }, + } + pathResolutionConfig2 := clientcmdapi.Config{ + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "relative-user-2": {ClientCertificate: "relative/client/cert2", ClientKey: "../relative/client/key2"}, + "absolute-user-2": {ClientCertificate: "/absolute/client/cert2", ClientKey: "/absolute/client/key2"}, + }, + Clusters: map[string]*clientcmdapi.Cluster{ + "relative-server-2": {CertificateAuthority: "../relative/ca2"}, + "absolute-server-2": {CertificateAuthority: "/absolute/ca2"}, + }, + } + + configDir1, _ := ioutil.TempDir("", "") + defer os.RemoveAll(configDir1) + configFile1 := path.Join(configDir1, ".kubeconfig") + configDir1, _ = filepath.Abs(configDir1) + + configDir2, _ := ioutil.TempDir("", "") + defer os.RemoveAll(configDir2) + configDir2, _ = ioutil.TempDir(configDir2, "") + configFile2 := path.Join(configDir2, ".kubeconfig") + configDir2, _ = filepath.Abs(configDir2) + + WriteToFile(pathResolutionConfig1, configFile1) + WriteToFile(pathResolutionConfig2, configFile2) + + loadingRules := ClientConfigLoadingRules{ + Precedence: []string{configFile1, configFile2}, + } + + mergedConfig, err := loadingRules.Load() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + foundClusterCount := 0 + for key, cluster := range mergedConfig.Clusters { + if key == "relative-server-1" { + foundClusterCount++ + matchStringArg(path.Join(configDir1, pathResolutionConfig1.Clusters["relative-server-1"].CertificateAuthority), cluster.CertificateAuthority, t) + } + if key == "relative-server-2" { + foundClusterCount++ + matchStringArg(path.Join(configDir2, pathResolutionConfig2.Clusters["relative-server-2"].CertificateAuthority), cluster.CertificateAuthority, t) + } + if key == "absolute-server-1" { + foundClusterCount++ + matchStringArg(pathResolutionConfig1.Clusters["absolute-server-1"].CertificateAuthority, cluster.CertificateAuthority, t) + } + if key == "absolute-server-2" { + foundClusterCount++ + matchStringArg(pathResolutionConfig2.Clusters["absolute-server-2"].CertificateAuthority, cluster.CertificateAuthority, t) + } + } + if foundClusterCount != 4 { + t.Errorf("Expected 4 clusters, found %v: %v", foundClusterCount, mergedConfig.Clusters) + } + + foundAuthInfoCount := 0 + for key, authInfo := range mergedConfig.AuthInfos { + if key == "relative-user-1" { + foundAuthInfoCount++ + matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos["relative-user-1"].ClientCertificate), authInfo.ClientCertificate, t) + matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos["relative-user-1"].ClientKey), authInfo.ClientKey, t) + } + if key == "relative-user-2" { + foundAuthInfoCount++ + matchStringArg(path.Join(configDir2, pathResolutionConfig2.AuthInfos["relative-user-2"].ClientCertificate), authInfo.ClientCertificate, t) + matchStringArg(path.Join(configDir2, pathResolutionConfig2.AuthInfos["relative-user-2"].ClientKey), authInfo.ClientKey, t) + } + if key == "absolute-user-1" { + foundAuthInfoCount++ + matchStringArg(pathResolutionConfig1.AuthInfos["absolute-user-1"].ClientCertificate, authInfo.ClientCertificate, t) + matchStringArg(pathResolutionConfig1.AuthInfos["absolute-user-1"].ClientKey, authInfo.ClientKey, t) + } + if key == "absolute-user-2" { + foundAuthInfoCount++ + matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientCertificate, authInfo.ClientCertificate, t) + matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientKey, authInfo.ClientKey, t) + } + if key == "relative-cmd-1" { + foundAuthInfoCount++ + matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos[key].Exec.Command), authInfo.Exec.Command, t) + } + if key == "absolute-cmd-1" { + foundAuthInfoCount++ + matchStringArg(pathResolutionConfig1.AuthInfos[key].Exec.Command, authInfo.Exec.Command, t) + } + if key == "PATH-cmd-1" { + foundAuthInfoCount++ + matchStringArg(pathResolutionConfig1.AuthInfos[key].Exec.Command, authInfo.Exec.Command, t) + } + } + if foundAuthInfoCount != 7 { + t.Errorf("Expected 7 users, found %v: %v", foundAuthInfoCount, mergedConfig.AuthInfos) + } + +} + +func TestMigratingFile(t *testing.T) { + sourceFile, _ := ioutil.TempFile("", "") + defer os.Remove(sourceFile.Name()) + destinationFile, _ := ioutil.TempFile("", "") + // delete the file so that we'll write to it + os.Remove(destinationFile.Name()) + + WriteToFile(testConfigAlfa, sourceFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()}, + } + + if _, err := loadingRules.Load(); err != nil { + t.Errorf("unexpected error %v", err) + } + + // the load should have recreated this file + defer os.Remove(destinationFile.Name()) + + sourceContent, err := ioutil.ReadFile(sourceFile.Name()) + if err != nil { + t.Errorf("unexpected error %v", err) + } + destinationContent, err := ioutil.ReadFile(destinationFile.Name()) + if err != nil { + t.Errorf("unexpected error %v", err) + } + + if !reflect.DeepEqual(sourceContent, destinationContent) { + t.Errorf("source and destination do not match") + } +} + +func TestMigratingFileLeaveExistingFileAlone(t *testing.T) { + sourceFile, _ := ioutil.TempFile("", "") + defer os.Remove(sourceFile.Name()) + destinationFile, _ := ioutil.TempFile("", "") + defer os.Remove(destinationFile.Name()) + + WriteToFile(testConfigAlfa, sourceFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()}, + } + + if _, err := loadingRules.Load(); err != nil { + t.Errorf("unexpected error %v", err) + } + + destinationContent, err := ioutil.ReadFile(destinationFile.Name()) + if err != nil { + t.Errorf("unexpected error %v", err) + } + + if len(destinationContent) > 0 { + t.Errorf("destination should not have been touched") + } +} + +func TestMigratingFileSourceMissingSkip(t *testing.T) { + sourceFilename := "some-missing-file" + destinationFile, _ := ioutil.TempFile("", "") + // delete the file so that we'll write to it + os.Remove(destinationFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + MigrationRules: map[string]string{destinationFile.Name(): sourceFilename}, + } + + if _, err := loadingRules.Load(); err != nil { + t.Errorf("unexpected error %v", err) + } + + if _, err := os.Stat(destinationFile.Name()); !os.IsNotExist(err) { + t.Errorf("destination should not exist") + } +} + +func TestFileLocking(t *testing.T) { + f, _ := ioutil.TempFile("", "") + defer os.Remove(f.Name()) + + err := lockFile(f.Name()) + if err != nil { + t.Errorf("unexpected error while locking file: %v", err) + } + defer unlockFile(f.Name()) + + err = lockFile(f.Name()) + if err == nil { + t.Error("expected error while locking file.") + } +} + +func Example_noMergingOnExplicitPaths() { + commandLineFile, _ := ioutil.TempFile("", "") + defer os.Remove(commandLineFile.Name()) + envVarFile, _ := ioutil.TempFile("", "") + defer os.Remove(envVarFile.Name()) + + WriteToFile(testConfigAlfa, commandLineFile.Name()) + WriteToFile(testConfigConflictAlfa, envVarFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + ExplicitPath: commandLineFile.Name(), + Precedence: []string{envVarFile.Name()}, + } + + mergedConfig, err := loadingRules.Load() + + json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + output, err := yaml.JSONToYAML(json) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + + fmt.Printf("%v", string(output)) + // Output: + // apiVersion: v1 + // clusters: + // - cluster: + // server: http://cow.org:8080 + // name: cow-cluster + // contexts: + // - context: + // cluster: cow-cluster + // namespace: hammer-ns + // user: red-user + // name: federal-context + // current-context: "" + // kind: Config + // preferences: {} + // users: + // - name: red-user + // user: + // token: red-token +} + +func Example_mergingSomeWithConflict() { + commandLineFile, _ := ioutil.TempFile("", "") + defer os.Remove(commandLineFile.Name()) + envVarFile, _ := ioutil.TempFile("", "") + defer os.Remove(envVarFile.Name()) + + WriteToFile(testConfigAlfa, commandLineFile.Name()) + WriteToFile(testConfigConflictAlfa, envVarFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + Precedence: []string{commandLineFile.Name(), envVarFile.Name()}, + } + + mergedConfig, err := loadingRules.Load() + + json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + output, err := yaml.JSONToYAML(json) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + + fmt.Printf("%v", string(output)) + // Output: + // apiVersion: v1 + // clusters: + // - cluster: + // server: http://cow.org:8080 + // name: cow-cluster + // - cluster: + // insecure-skip-tls-verify: true + // server: http://donkey.org:8080 + // name: donkey-cluster + // contexts: + // - context: + // cluster: cow-cluster + // namespace: hammer-ns + // user: red-user + // name: federal-context + // current-context: federal-context + // kind: Config + // preferences: {} + // users: + // - name: red-user + // user: + // token: red-token + // - name: yellow-user + // user: + // token: yellow-token +} + +func Example_mergingEverythingNoConflicts() { + commandLineFile, _ := ioutil.TempFile("", "") + defer os.Remove(commandLineFile.Name()) + envVarFile, _ := ioutil.TempFile("", "") + defer os.Remove(envVarFile.Name()) + currentDirFile, _ := ioutil.TempFile("", "") + defer os.Remove(currentDirFile.Name()) + homeDirFile, _ := ioutil.TempFile("", "") + defer os.Remove(homeDirFile.Name()) + + WriteToFile(testConfigAlfa, commandLineFile.Name()) + WriteToFile(testConfigBravo, envVarFile.Name()) + WriteToFile(testConfigCharlie, currentDirFile.Name()) + WriteToFile(testConfigDelta, homeDirFile.Name()) + + loadingRules := ClientConfigLoadingRules{ + Precedence: []string{commandLineFile.Name(), envVarFile.Name(), currentDirFile.Name(), homeDirFile.Name()}, + } + + mergedConfig, err := loadingRules.Load() + + json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + output, err := yaml.JSONToYAML(json) + if err != nil { + fmt.Printf("Unexpected error: %v", err) + } + + fmt.Printf("%v", string(output)) + // Output: + // apiVersion: v1 + // clusters: + // - cluster: + // server: http://chicken.org:8080 + // name: chicken-cluster + // - cluster: + // server: http://cow.org:8080 + // name: cow-cluster + // - cluster: + // server: http://horse.org:8080 + // name: horse-cluster + // - cluster: + // server: http://pig.org:8080 + // name: pig-cluster + // contexts: + // - context: + // cluster: cow-cluster + // namespace: hammer-ns + // user: red-user + // name: federal-context + // - context: + // cluster: chicken-cluster + // namespace: plane-ns + // user: blue-user + // name: gothic-context + // - context: + // cluster: pig-cluster + // namespace: saw-ns + // user: black-user + // name: queen-anne-context + // - context: + // cluster: horse-cluster + // namespace: chisel-ns + // user: green-user + // name: shaker-context + // current-context: "" + // kind: Config + // preferences: {} + // users: + // - name: black-user + // user: + // token: black-token + // - name: blue-user + // user: + // token: blue-token + // - name: green-user + // user: + // token: green-token + // - name: red-user + // user: + // token: red-token +} + +func TestDeduplicate(t *testing.T) { + testCases := []struct { + src []string + expect []string + }{ + { + src: []string{"a", "b", "c", "d", "e", "f"}, + expect: []string{"a", "b", "c", "d", "e", "f"}, + }, + { + src: []string{"a", "b", "c", "b", "e", "f"}, + expect: []string{"a", "b", "c", "e", "f"}, + }, + { + src: []string{"a", "a", "b", "b", "c", "b"}, + expect: []string{"a", "b", "c"}, + }, + } + + for _, testCase := range testCases { + get := deduplicate(testCase.src) + if !reflect.DeepEqual(get, testCase.expect) { + t.Errorf("expect: %v, get: %v", testCase.expect, get) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder_test.go b/vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder_test.go new file mode 100644 index 000000000..8b0386764 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/merged_client_builder_test.go @@ -0,0 +1,328 @@ +/* +Copyright 2014 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 clientcmd + +import ( + "fmt" + "testing" + + restclient "k8s.io/client-go/rest" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +type testLoader struct { + ClientConfigLoader + + called bool + config *clientcmdapi.Config + err error +} + +func (l *testLoader) Load() (*clientcmdapi.Config, error) { + l.called = true + return l.config, l.err +} + +type testClientConfig struct { + config *restclient.Config + namespace string + namespaceSpecified bool + err error +} + +func (c *testClientConfig) RawConfig() (clientcmdapi.Config, error) { + return clientcmdapi.Config{}, fmt.Errorf("unexpected call") +} +func (c *testClientConfig) ClientConfig() (*restclient.Config, error) { + return c.config, c.err +} +func (c *testClientConfig) Namespace() (string, bool, error) { + return c.namespace, c.namespaceSpecified, c.err +} +func (c *testClientConfig) ConfigAccess() ConfigAccess { + return nil +} + +type testICC struct { + testClientConfig + + possible bool + called bool +} + +func (icc *testICC) Possible() bool { + icc.called = true + return icc.possible +} + +func TestInClusterConfig(t *testing.T) { + default1 := &DirectClientConfig{ + config: *createValidTestConfig(), + contextName: "clean", + overrides: &ConfigOverrides{}, + } + invalidDefaultConfig := clientcmdapi.NewConfig() + invalidDefaultConfig.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "http://localhost:8080", + } + invalidDefaultConfig.Contexts["other"] = &clientcmdapi.Context{ + Cluster: "clean", + } + invalidDefaultConfig.CurrentContext = "clean" + + defaultInvalid := &DirectClientConfig{ + config: *invalidDefaultConfig, + overrides: &ConfigOverrides{}, + } + if _, err := defaultInvalid.ClientConfig(); err == nil || !IsConfigurationInvalid(err) { + t.Fatal(err) + } + config1, err := default1.ClientConfig() + if err != nil { + t.Fatal(err) + } + config2 := &restclient.Config{Host: "config2"} + err1 := fmt.Errorf("unique error") + + testCases := map[string]struct { + clientConfig *testClientConfig + icc *testICC + defaultConfig *DirectClientConfig + + checkedICC bool + result *restclient.Config + err error + }{ + "in-cluster checked on other error": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{}, + + checkedICC: true, + result: nil, + err: ErrEmptyConfig, + }, + + "in-cluster not checked on non-empty error": { + clientConfig: &testClientConfig{err: ErrEmptyCluster}, + icc: &testICC{}, + + checkedICC: false, + result: nil, + err: ErrEmptyCluster, + }, + + "in-cluster checked when config is default": { + defaultConfig: default1, + clientConfig: &testClientConfig{config: config1}, + icc: &testICC{}, + + checkedICC: true, + result: config1, + err: nil, + }, + + "in-cluster not checked when default config is invalid": { + defaultConfig: defaultInvalid, + clientConfig: &testClientConfig{config: config1}, + icc: &testICC{}, + + checkedICC: false, + result: config1, + err: nil, + }, + + "in-cluster not checked when config is not equal to default": { + defaultConfig: default1, + clientConfig: &testClientConfig{config: config2}, + icc: &testICC{}, + + checkedICC: false, + result: config2, + err: nil, + }, + + "in-cluster checked when config is not equal to default and error is empty": { + clientConfig: &testClientConfig{config: config2, err: ErrEmptyConfig}, + icc: &testICC{}, + + checkedICC: true, + result: config2, + err: ErrEmptyConfig, + }, + + "in-cluster error returned when config is empty": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{ + possible: true, + testClientConfig: testClientConfig{ + err: err1, + }, + }, + + checkedICC: true, + result: nil, + err: err1, + }, + + "in-cluster config returned when config is empty": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{ + possible: true, + testClientConfig: testClientConfig{ + config: config2, + }, + }, + + checkedICC: true, + result: config2, + err: nil, + }, + + "in-cluster not checked when standard default is invalid": { + defaultConfig: &DefaultClientConfig, + clientConfig: &testClientConfig{config: config2}, + icc: &testICC{}, + + checkedICC: false, + result: config2, + err: nil, + }, + } + + for name, test := range testCases { + c := &DeferredLoadingClientConfig{icc: test.icc} + c.loader = &ClientConfigLoadingRules{DefaultClientConfig: test.defaultConfig} + c.clientConfig = test.clientConfig + + cfg, err := c.ClientConfig() + if test.icc.called != test.checkedICC { + t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called) + } + if err != test.err || cfg != test.result { + t.Errorf("%s: unexpected result: %v %#v", name, err, cfg) + } + } +} + +func TestInClusterConfigNamespace(t *testing.T) { + err1 := fmt.Errorf("unique error") + + testCases := map[string]struct { + clientConfig *testClientConfig + icc *testICC + + checkedICC bool + result string + ok bool + err error + }{ + "in-cluster checked on empty error": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{}, + + checkedICC: true, + err: ErrEmptyConfig, + }, + + "in-cluster not checked on non-empty error": { + clientConfig: &testClientConfig{err: ErrEmptyCluster}, + icc: &testICC{}, + + err: ErrEmptyCluster, + }, + + "in-cluster checked when config is default": { + clientConfig: &testClientConfig{}, + icc: &testICC{}, + + checkedICC: true, + }, + + "in-cluster not checked when config is not equal to default": { + clientConfig: &testClientConfig{namespace: "test", namespaceSpecified: true}, + icc: &testICC{}, + + result: "test", + ok: true, + }, + + "in-cluster checked when namespace is not specified, but is defaulted": { + clientConfig: &testClientConfig{namespace: "test", namespaceSpecified: false}, + icc: &testICC{}, + + checkedICC: true, + result: "test", + ok: false, + }, + + "in-cluster error returned when config is empty": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{ + possible: true, + testClientConfig: testClientConfig{ + err: err1, + }, + }, + + checkedICC: true, + err: err1, + }, + + "in-cluster config returned when config is empty": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{ + possible: true, + testClientConfig: testClientConfig{ + namespace: "test", + namespaceSpecified: true, + }, + }, + + checkedICC: true, + result: "test", + ok: true, + }, + + "in-cluster config returned when config is empty and namespace is defaulted but not explicitly set": { + clientConfig: &testClientConfig{err: ErrEmptyConfig}, + icc: &testICC{ + possible: true, + testClientConfig: testClientConfig{ + namespace: "test", + namespaceSpecified: false, + }, + }, + + checkedICC: true, + result: "test", + ok: false, + }, + } + + for name, test := range testCases { + c := &DeferredLoadingClientConfig{icc: test.icc} + c.clientConfig = test.clientConfig + + ns, ok, err := c.Namespace() + if test.icc.called != test.checkedICC { + t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called) + } + if err != test.err || ns != test.result || ok != test.ok { + t.Errorf("%s: unexpected result: %v %s %t", name, err, ns, ok) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/overrides_test.go b/vendor/k8s.io/client-go/tools/clientcmd/overrides_test.go new file mode 100644 index 000000000..13a995cf5 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/overrides_test.go @@ -0,0 +1,50 @@ +/* +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 clientcmd + +import ( + "testing" + + "github.com/spf13/pflag" +) + +func TestNamespacePrefixStrip(t *testing.T) { + testData := map[string]string{ + "namespaces/foo": "foo", + "NAMESPACES/foo": "foo", + "NameSpaces/foo": "foo", + "namespace/foo": "foo", + "NAMESPACE/foo": "foo", + "nameSpace/foo": "foo", + "ns/foo": "foo", + "NS/foo": "foo", + "namespaces/": "namespaces/", + "namespace/": "namespace/", + "ns/": "ns/", + } + + for before, after := range testData { + overrides := &ConfigOverrides{} + fs := &pflag.FlagSet{} + BindOverrideFlags(overrides, fs, RecommendedConfigOverrideFlags("")) + fs.Parse([]string{"--namespace", before}) + + if overrides.Context.Namespace != after { + t.Fatalf("Expected %s, got %s", after, overrides.Context.Namespace) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/clientcmd/validation_test.go b/vendor/k8s.io/client-go/tools/clientcmd/validation_test.go new file mode 100644 index 000000000..4742b1a14 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/clientcmd/validation_test.go @@ -0,0 +1,574 @@ +/* +Copyright 2014 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 clientcmd + +import ( + "io/ioutil" + "os" + "strings" + "testing" + + utilerrors "k8s.io/apimachinery/pkg/util/errors" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +func TestConfirmUsableBadInfoButOkConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + config.Clusters["missing ca"] = &clientcmdapi.Cluster{ + Server: "anything", + CertificateAuthority: "missing", + } + config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ + Username: "anything", + Token: "here", + } + config.Contexts["dirty"] = &clientcmdapi.Context{ + Cluster: "missing ca", + AuthInfo: "error", + } + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "anything", + } + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + Token: "here", + } + config.Contexts["clean"] = &clientcmdapi.Context{ + Cluster: "clean", + AuthInfo: "clean", + } + + badValidation := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"unable to read certificate-authority"}, + } + okTest := configValidationTest{ + config: config, + } + + okTest.testConfirmUsable("clean", t) + badValidation.testConfig(t) +} + +func TestConfirmUsableBadInfoConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + config.Clusters["missing ca"] = &clientcmdapi.Cluster{ + Server: "anything", + CertificateAuthority: "missing", + } + config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ + Username: "anything", + Token: "here", + } + config.Contexts["first"] = &clientcmdapi.Context{ + Cluster: "missing ca", + AuthInfo: "error", + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"unable to read certificate-authority"}, + } + + test.testConfirmUsable("first", t) +} + +func TestConfirmUsableEmptyConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"}, + } + + test.testConfirmUsable("", t) +} + +func TestConfirmUsableMissingConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"}, + } + + test.testConfirmUsable("not-here", t) +} + +func TestValidateEmptyConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"}, + } + + test.testConfig(t) +} + +func TestValidateMissingCurrentContextConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + config.CurrentContext = "anything" + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"context was not found for specified "}, + } + + test.testConfig(t) +} + +func TestIsContextNotFound(t *testing.T) { + config := clientcmdapi.NewConfig() + config.CurrentContext = "anything" + + err := Validate(*config) + if !IsContextNotFound(err) { + t.Errorf("Expected context not found, but got %v", err) + } + if !IsConfigurationInvalid(err) { + t.Errorf("Expected configuration invalid, but got %v", err) + } +} + +func TestIsEmptyConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + + err := Validate(*config) + if !IsEmptyConfig(err) { + t.Errorf("Expected context not found, but got %v", err) + } + if !IsConfigurationInvalid(err) { + t.Errorf("Expected configuration invalid, but got %v", err) + } +} + +func TestIsConfigurationInvalid(t *testing.T) { + if newErrConfigurationInvalid([]error{}) != nil { + t.Errorf("unexpected error") + } + if newErrConfigurationInvalid([]error{ErrNoContext}) == ErrNoContext { + t.Errorf("unexpected error") + } + if newErrConfigurationInvalid([]error{ErrNoContext, ErrNoContext}) == nil { + t.Errorf("unexpected error") + } + if !IsConfigurationInvalid(newErrConfigurationInvalid([]error{ErrNoContext, ErrNoContext})) { + t.Errorf("unexpected error") + } +} + +func TestValidateMissingReferencesConfig(t *testing.T) { + config := clientcmdapi.NewConfig() + config.CurrentContext = "anything" + config.Contexts["anything"] = &clientcmdapi.Context{Cluster: "missing", AuthInfo: "missing"} + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"user \"missing\" was not found for context \"anything\"", "cluster \"missing\" was not found for context \"anything\""}, + } + + test.testContext("anything", t) + test.testConfig(t) +} + +func TestValidateEmptyContext(t *testing.T) { + config := clientcmdapi.NewConfig() + config.CurrentContext = "anything" + config.Contexts["anything"] = &clientcmdapi.Context{} + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"user was not specified for context \"anything\"", "cluster was not specified for context \"anything\""}, + } + + test.testContext("anything", t) + test.testConfig(t) +} + +func TestValidateEmptyContextName(t *testing.T) { + config := clientcmdapi.NewConfig() + config.CurrentContext = "anything" + config.Contexts[""] = &clientcmdapi.Context{Cluster: "missing", AuthInfo: "missing"} + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"empty context name", "is not allowed"}, + } + + test.testContext("", t) + test.testConfig(t) +} + +func TestValidateEmptyClusterInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.Clusters["empty"] = clientcmdapi.NewCluster() + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"cluster has no server defined"}, + } + + test.testCluster("empty", t) + test.testConfig(t) +} + +func TestValidateClusterInfoErrEmptyCluster(t *testing.T) { + cluster := clientcmdapi.NewCluster() + errs := validateClusterInfo("", *cluster) + + if len(errs) != 1 { + t.Fatalf("unexpected errors: %v", errs) + } + if errs[0] != ErrEmptyCluster { + t.Errorf("unexpected error: %v", errs[0]) + } +} + +func TestValidateMissingCAFileClusterInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.Clusters["missing ca"] = &clientcmdapi.Cluster{ + Server: "anything", + CertificateAuthority: "missing", + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"unable to read certificate-authority"}, + } + + test.testCluster("missing ca", t) + test.testConfig(t) +} + +func TestValidateCleanClusterInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "anything", + } + test := configValidationTest{ + config: config, + } + + test.testCluster("clean", t) + test.testConfig(t) +} + +func TestValidateCleanWithCAClusterInfo(t *testing.T) { + tempFile, _ := ioutil.TempFile("", "") + defer os.Remove(tempFile.Name()) + + config := clientcmdapi.NewConfig() + config.Clusters["clean"] = &clientcmdapi.Cluster{ + Server: "anything", + CertificateAuthority: tempFile.Name(), + } + test := configValidationTest{ + config: config, + } + + test.testCluster("clean", t) + test.testConfig(t) +} + +func TestValidateEmptyAuthInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["error"] = &clientcmdapi.AuthInfo{} + test := configValidationTest{ + config: config, + } + + test.testAuthInfo("error", t) + test.testConfig(t) +} + +func TestValidateCertFilesNotFoundAuthInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ + ClientCertificate: "missing", + ClientKey: "missing", + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"unable to read client-cert", "unable to read client-key"}, + } + + test.testAuthInfo("error", t) + test.testConfig(t) +} + +func TestValidateCertDataOverridesFiles(t *testing.T) { + tempFile, _ := ioutil.TempFile("", "") + defer os.Remove(tempFile.Name()) + + config := clientcmdapi.NewConfig() + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + ClientCertificate: tempFile.Name(), + ClientCertificateData: []byte("certdata"), + ClientKey: tempFile.Name(), + ClientKeyData: []byte("keydata"), + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"client-cert-data and client-cert are both specified", "client-key-data and client-key are both specified"}, + } + + test.testAuthInfo("clean", t) + test.testConfig(t) +} + +func TestValidateCleanCertFilesAuthInfo(t *testing.T) { + tempFile, _ := ioutil.TempFile("", "") + defer os.Remove(tempFile.Name()) + + config := clientcmdapi.NewConfig() + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + ClientCertificate: tempFile.Name(), + ClientKey: tempFile.Name(), + } + test := configValidationTest{ + config: config, + } + + test.testAuthInfo("clean", t) + test.testConfig(t) +} + +func TestValidateCleanTokenAuthInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{ + Token: "any-value", + } + test := configValidationTest{ + config: config, + } + + test.testAuthInfo("clean", t) + test.testConfig(t) +} + +func TestValidateMultipleMethodsAuthInfo(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["error"] = &clientcmdapi.AuthInfo{ + Token: "token", + Username: "username", + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{"more than one authentication method", "token", "basicAuth"}, + } + + test.testAuthInfo("error", t) + test.testConfig(t) +} + +func TestValidateAuthInfoExec(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["user"] = &clientcmdapi.AuthInfo{ + Exec: &clientcmdapi.ExecConfig{ + Command: "/bin/example", + APIVersion: "clientauthentication.k8s.io/v1alpha1", + Args: []string{"hello", "world"}, + Env: []clientcmdapi.ExecEnvVar{ + {Name: "foo", Value: "bar"}, + }, + }, + } + test := configValidationTest{ + config: config, + } + + test.testAuthInfo("user", t) + test.testConfig(t) +} + +func TestValidateAuthInfoExecNoVersion(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["user"] = &clientcmdapi.AuthInfo{ + Exec: &clientcmdapi.ExecConfig{ + Command: "/bin/example", + }, + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{ + "apiVersion must be specified for user to use exec authentication plugin", + }, + } + + test.testAuthInfo("user", t) + test.testConfig(t) +} + +func TestValidateAuthInfoExecNoCommand(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["user"] = &clientcmdapi.AuthInfo{ + Exec: &clientcmdapi.ExecConfig{ + APIVersion: "clientauthentication.k8s.io/v1alpha1", + }, + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{ + "command must be specified for user to use exec authentication plugin", + }, + } + + test.testAuthInfo("user", t) + test.testConfig(t) +} + +func TestValidateAuthInfoExecWithAuthProvider(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["user"] = &clientcmdapi.AuthInfo{ + AuthProvider: &clientcmdapi.AuthProviderConfig{ + Name: "oidc", + }, + Exec: &clientcmdapi.ExecConfig{ + Command: "/bin/example", + APIVersion: "clientauthentication.k8s.io/v1alpha1", + }, + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{ + "authProvider cannot be provided in combination with an exec plugin for user", + }, + } + + test.testAuthInfo("user", t) + test.testConfig(t) +} + +func TestValidateAuthInfoExecInvalidEnv(t *testing.T) { + config := clientcmdapi.NewConfig() + config.AuthInfos["user"] = &clientcmdapi.AuthInfo{ + Exec: &clientcmdapi.ExecConfig{ + Command: "/bin/example", + APIVersion: "clientauthentication.k8s.io/v1alpha1", + Env: []clientcmdapi.ExecEnvVar{ + {Name: "foo"}, // No value + }, + }, + } + test := configValidationTest{ + config: config, + expectedErrorSubstring: []string{ + "env variable foo value must be specified for user to use exec authentication plugin", + }, + } + + test.testAuthInfo("user", t) + test.testConfig(t) +} + +type configValidationTest struct { + config *clientcmdapi.Config + expectedErrorSubstring []string +} + +func (c configValidationTest) testContext(contextName string, t *testing.T) { + errs := validateContext(contextName, *c.config.Contexts[contextName], *c.config) + + if len(c.expectedErrorSubstring) != 0 { + if len(errs) == 0 { + t.Errorf("Expected error containing: %v", c.expectedErrorSubstring) + } + for _, curr := range c.expectedErrorSubstring { + if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) { + t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs)) + } + } + + } else { + if len(errs) != 0 { + t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs)) + } + } +} + +func (c configValidationTest) testConfirmUsable(contextName string, t *testing.T) { + err := ConfirmUsable(*c.config, contextName) + + if len(c.expectedErrorSubstring) != 0 { + if err == nil { + t.Errorf("Expected error containing: %v", c.expectedErrorSubstring) + } else { + for _, curr := range c.expectedErrorSubstring { + if err != nil && !strings.Contains(err.Error(), curr) { + t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, err) + } + } + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } +} + +func (c configValidationTest) testConfig(t *testing.T) { + err := Validate(*c.config) + + if len(c.expectedErrorSubstring) != 0 { + if err == nil { + t.Errorf("Expected error containing: %v", c.expectedErrorSubstring) + } else { + for _, curr := range c.expectedErrorSubstring { + if err != nil && !strings.Contains(err.Error(), curr) { + t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, err) + } + } + if !IsConfigurationInvalid(err) { + t.Errorf("all errors should be configuration invalid: %v", err) + } + } + } else { + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } +} + +func (c configValidationTest) testCluster(clusterName string, t *testing.T) { + errs := validateClusterInfo(clusterName, *c.config.Clusters[clusterName]) + + if len(c.expectedErrorSubstring) != 0 { + if len(errs) == 0 { + t.Errorf("Expected error containing: %v", c.expectedErrorSubstring) + } + for _, curr := range c.expectedErrorSubstring { + if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) { + t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs)) + } + } + + } else { + if len(errs) != 0 { + t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs)) + } + } +} + +func (c configValidationTest) testAuthInfo(authInfoName string, t *testing.T) { + errs := validateAuthInfo(authInfoName, *c.config.AuthInfos[authInfoName]) + + if len(c.expectedErrorSubstring) != 0 { + if len(errs) == 0 { + t.Errorf("Expected error containing: %v", c.expectedErrorSubstring) + } + for _, curr := range c.expectedErrorSubstring { + if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) { + t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs)) + } + } + + } else { + if len(errs) != 0 { + t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs)) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/leaderelection/OWNERS b/vendor/k8s.io/client-go/tools/leaderelection/OWNERS new file mode 100644 index 000000000..d9516f8a8 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/leaderelection/OWNERS @@ -0,0 +1,13 @@ +approvers: +- mikedanese +- timothysc +reviewers: +- wojtek-t +- deads2k +- mikedanese +- gmarek +- eparis +- timothysc +- ingvagabund +- resouer +- goltermann diff --git a/vendor/k8s.io/client-go/tools/leaderelection/leaderelection_test.go b/vendor/k8s.io/client-go/tools/leaderelection/leaderelection_test.go new file mode 100644 index 000000000..e99cf57af --- /dev/null +++ b/vendor/k8s.io/client-go/tools/leaderelection/leaderelection_test.go @@ -0,0 +1,292 @@ +/* +Copyright 2015 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 leaderelection + +import ( + "fmt" + "sync" + "testing" + "time" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + fakecorev1 "k8s.io/client-go/kubernetes/typed/core/v1/fake" + core "k8s.io/client-go/testing" + rl "k8s.io/client-go/tools/leaderelection/resourcelock" + "k8s.io/client-go/tools/record" +) + +func createLockObject(objectType string, objectMeta metav1.ObjectMeta) (obj runtime.Object) { + switch objectType { + case "endpoints": + obj = &v1.Endpoints{ObjectMeta: objectMeta} + case "configmaps": + obj = &v1.ConfigMap{ObjectMeta: objectMeta} + default: + panic("unexpected objType:" + objectType) + } + return +} + +// Will test leader election using endpoints as the resource +func TestTryAcquireOrRenewEndpoints(t *testing.T) { + testTryAcquireOrRenew(t, "endpoints") +} + +func testTryAcquireOrRenew(t *testing.T, objectType string) { + future := time.Now().Add(1000 * time.Hour) + past := time.Now().Add(-1000 * time.Hour) + + tests := []struct { + observedRecord rl.LeaderElectionRecord + observedTime time.Time + reactors []struct { + verb string + reaction core.ReactionFunc + } + + expectSuccess bool + transitionLeader bool + outHolder string + }{ + // acquire from no object + { + reactors: []struct { + verb string + reaction core.ReactionFunc + }{ + { + verb: "get", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, nil, errors.NewNotFound(action.(core.GetAction).GetResource().GroupResource(), action.(core.GetAction).GetName()) + }, + }, + { + verb: "create", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, action.(core.CreateAction).GetObject(), nil + }, + }, + }, + expectSuccess: true, + outHolder: "baz", + }, + // acquire from unled object + { + reactors: []struct { + verb string + reaction core.ReactionFunc + }{ + { + verb: "get", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + objectMeta := metav1.ObjectMeta{ + Namespace: action.GetNamespace(), + Name: action.(core.GetAction).GetName(), + } + return true, createLockObject(objectType, objectMeta), nil + }, + }, + { + verb: "update", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, action.(core.CreateAction).GetObject(), nil + }, + }, + }, + + expectSuccess: true, + transitionLeader: true, + outHolder: "baz", + }, + // acquire from led, unacked object + { + reactors: []struct { + verb string + reaction core.ReactionFunc + }{ + { + verb: "get", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + objectMeta := metav1.ObjectMeta{ + Namespace: action.GetNamespace(), + Name: action.(core.GetAction).GetName(), + Annotations: map[string]string{ + rl.LeaderElectionRecordAnnotationKey: `{"holderIdentity":"bing"}`, + }, + } + return true, createLockObject(objectType, objectMeta), nil + }, + }, + { + verb: "update", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, action.(core.CreateAction).GetObject(), nil + }, + }, + }, + observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, + observedTime: past, + + expectSuccess: true, + transitionLeader: true, + outHolder: "baz", + }, + // don't acquire from led, acked object + { + reactors: []struct { + verb string + reaction core.ReactionFunc + }{ + { + verb: "get", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + objectMeta := metav1.ObjectMeta{ + Namespace: action.GetNamespace(), + Name: action.(core.GetAction).GetName(), + Annotations: map[string]string{ + rl.LeaderElectionRecordAnnotationKey: `{"holderIdentity":"bing"}`, + }, + } + return true, createLockObject(objectType, objectMeta), nil + }, + }, + }, + observedTime: future, + + expectSuccess: false, + outHolder: "bing", + }, + // renew already acquired object + { + reactors: []struct { + verb string + reaction core.ReactionFunc + }{ + { + verb: "get", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + objectMeta := metav1.ObjectMeta{ + Namespace: action.GetNamespace(), + Name: action.(core.GetAction).GetName(), + Annotations: map[string]string{ + rl.LeaderElectionRecordAnnotationKey: `{"holderIdentity":"baz"}`, + }, + } + return true, createLockObject(objectType, objectMeta), nil + }, + }, + { + verb: "update", + reaction: func(action core.Action) (handled bool, ret runtime.Object, err error) { + return true, action.(core.CreateAction).GetObject(), nil + }, + }, + }, + observedTime: future, + observedRecord: rl.LeaderElectionRecord{HolderIdentity: "baz"}, + + expectSuccess: true, + outHolder: "baz", + }, + } + + for i, test := range tests { + // OnNewLeader is called async so we have to wait for it. + var wg sync.WaitGroup + wg.Add(1) + var reportedLeader string + var lock rl.Interface + + objectMeta := metav1.ObjectMeta{Namespace: "foo", Name: "bar"} + resourceLockConfig := rl.ResourceLockConfig{ + Identity: "baz", + EventRecorder: &record.FakeRecorder{}, + } + c := &fakecorev1.FakeCoreV1{Fake: &core.Fake{}} + for _, reactor := range test.reactors { + c.AddReactor(reactor.verb, objectType, reactor.reaction) + } + c.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) { + t.Errorf("[%v] unreachable action. testclient called too many times: %+v", i, action) + return true, nil, fmt.Errorf("unreachable action") + }) + + switch objectType { + case "endpoints": + lock = &rl.EndpointsLock{ + EndpointsMeta: objectMeta, + LockConfig: resourceLockConfig, + Client: c, + } + case "configmaps": + lock = &rl.ConfigMapLock{ + ConfigMapMeta: objectMeta, + LockConfig: resourceLockConfig, + Client: c, + } + } + + lec := LeaderElectionConfig{ + Lock: lock, + LeaseDuration: 10 * time.Second, + Callbacks: LeaderCallbacks{ + OnNewLeader: func(l string) { + defer wg.Done() + reportedLeader = l + }, + }, + } + le := &LeaderElector{ + config: lec, + observedRecord: test.observedRecord, + observedTime: test.observedTime, + } + + if test.expectSuccess != le.tryAcquireOrRenew() { + t.Errorf("[%v]unexpected result of tryAcquireOrRenew: [succeeded=%v]", i, !test.expectSuccess) + } + + le.observedRecord.AcquireTime = metav1.Time{} + le.observedRecord.RenewTime = metav1.Time{} + if le.observedRecord.HolderIdentity != test.outHolder { + t.Errorf("[%v]expected holder:\n\t%+v\ngot:\n\t%+v", i, test.outHolder, le.observedRecord.HolderIdentity) + } + if len(test.reactors) != len(c.Actions()) { + t.Errorf("[%v]wrong number of api interactions", i) + } + if test.transitionLeader && le.observedRecord.LeaderTransitions != 1 { + t.Errorf("[%v]leader should have transitioned but did not", i) + } + if !test.transitionLeader && le.observedRecord.LeaderTransitions != 0 { + t.Errorf("[%v]leader should not have transitioned but did", i) + } + + le.maybeReportTransition() + wg.Wait() + if reportedLeader != test.outHolder { + t.Errorf("[%v]reported leader was not the new leader. expected %q, got %q", i, test.outHolder, reportedLeader) + } + } +} + +// Will test leader election using configmap as the resource +func TestTryAcquireOrRenewConfigMaps(t *testing.T) { + testTryAcquireOrRenew(t, "configmaps") +} diff --git a/vendor/k8s.io/client-go/tools/metrics/OWNERS b/vendor/k8s.io/client-go/tools/metrics/OWNERS new file mode 100755 index 000000000..ff5179807 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/metrics/OWNERS @@ -0,0 +1,7 @@ +reviewers: +- wojtek-t +- eparis +- krousey +- jayunit100 +- fgrzadkowski +- tmrts diff --git a/vendor/k8s.io/client-go/tools/pager/pager_test.go b/vendor/k8s.io/client-go/tools/pager/pager_test.go new file mode 100644 index 000000000..ae517cab2 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/pager/pager_test.go @@ -0,0 +1,206 @@ +/* +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 pager + +import ( + "context" + "fmt" + "reflect" + "testing" + + "k8s.io/apimachinery/pkg/api/errors" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" + "k8s.io/apimachinery/pkg/runtime" +) + +func list(count int, rv string) *metainternalversion.List { + var list metainternalversion.List + for i := 0; i < count; i++ { + list.Items = append(list.Items, &metav1beta1.PartialObjectMetadata{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%d", i), + }, + }) + } + list.ResourceVersion = rv + return &list +} + +type testPager struct { + t *testing.T + rv string + index int + remaining int + last int + continuing bool + done bool + expectPage int64 +} + +func (p *testPager) reset() { + p.continuing = false + p.remaining += p.index + p.index = 0 + p.last = 0 + p.done = false +} + +func (p *testPager) PagedList(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if p.done { + p.t.Errorf("did not expect additional call to paged list") + return nil, fmt.Errorf("unexpected list call") + } + expectedContinue := fmt.Sprintf("%s:%d", p.rv, p.last) + if options.Limit != p.expectPage || (p.continuing && options.Continue != expectedContinue) { + p.t.Errorf("invariant violated, expected limit %d and continue %s, got %#v", p.expectPage, expectedContinue, options) + return nil, fmt.Errorf("invariant violated") + } + var list metainternalversion.List + total := options.Limit + if total == 0 { + total = int64(p.remaining) + } + for i := int64(0); i < total; i++ { + if p.remaining <= 0 { + break + } + list.Items = append(list.Items, &metav1beta1.PartialObjectMetadata{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%d", p.index), + }, + }) + p.remaining-- + p.index++ + } + p.last = p.index + if p.remaining > 0 { + list.Continue = fmt.Sprintf("%s:%d", p.rv, p.last) + p.continuing = true + } else { + p.done = true + } + list.ResourceVersion = p.rv + return &list, nil +} + +func (p *testPager) ExpiresOnSecondPage(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if p.continuing { + p.done = true + return nil, errors.NewResourceExpired("this list has expired") + } + return p.PagedList(ctx, options) +} + +func (p *testPager) ExpiresOnSecondPageThenFullList(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if p.continuing { + p.reset() + p.expectPage = 0 + return nil, errors.NewResourceExpired("this list has expired") + } + return p.PagedList(ctx, options) +} + +func TestListPager_List(t *testing.T) { + type fields struct { + PageSize int64 + PageFn ListPageFunc + FullListIfExpired bool + } + type args struct { + ctx context.Context + options metav1.ListOptions + } + tests := []struct { + name string + fields fields + args args + want runtime.Object + wantErr bool + isExpired bool + }{ + { + name: "empty page", + fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 0, rv: "rv:20"}).PagedList}, + args: args{}, + want: list(0, "rv:20"), + }, + { + name: "one page", + fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 9, rv: "rv:20"}).PagedList}, + args: args{}, + want: list(9, "rv:20"), + }, + { + name: "one full page", + fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 10, rv: "rv:20"}).PagedList}, + args: args{}, + want: list(10, "rv:20"), + }, + { + name: "two pages", + fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 11, rv: "rv:20"}).PagedList}, + args: args{}, + want: list(11, "rv:20"), + }, + { + name: "three pages", + fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 21, rv: "rv:20"}).PagedList}, + args: args{}, + want: list(21, "rv:20"), + }, + { + name: "expires on second page", + fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 21, rv: "rv:20"}).ExpiresOnSecondPage}, + args: args{}, + wantErr: true, + isExpired: true, + }, + { + name: "expires on second page and then lists", + fields: fields{ + FullListIfExpired: true, + PageSize: 10, + PageFn: (&testPager{t: t, expectPage: 10, remaining: 21, rv: "rv:20"}).ExpiresOnSecondPageThenFullList, + }, + args: args{}, + want: list(21, "rv:20"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &ListPager{ + PageSize: tt.fields.PageSize, + PageFn: tt.fields.PageFn, + FullListIfExpired: tt.fields.FullListIfExpired, + } + got, err := p.List(tt.args.ctx, tt.args.options) + if (err != nil) != tt.wantErr { + t.Errorf("ListPager.List() error = %v, wantErr %v", err, tt.wantErr) + return + } + if tt.isExpired != errors.IsResourceExpired(err) { + t.Errorf("ListPager.List() error = %v, isExpired %v", err, tt.isExpired) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ListPager.List() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/vendor/k8s.io/client-go/tools/record/OWNERS b/vendor/k8s.io/client-go/tools/record/OWNERS new file mode 100755 index 000000000..4dd54bbce --- /dev/null +++ b/vendor/k8s.io/client-go/tools/record/OWNERS @@ -0,0 +1,27 @@ +reviewers: +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- derekwaynecarr +- caesarxuchao +- vishh +- mikedanese +- liggitt +- nikhiljindal +- erictune +- pmorie +- dchen1107 +- saad-ali +- luxas +- yifan-gu +- eparis +- mwielgus +- timothysc +- jsafrane +- dims +- krousey +- a-robinson +- aveshagarwal +- resouer +- cjcullen diff --git a/vendor/k8s.io/client-go/tools/record/event_test.go b/vendor/k8s.io/client-go/tools/record/event_test.go new file mode 100644 index 000000000..4fcebc353 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/record/event_test.go @@ -0,0 +1,924 @@ +/* +Copyright 2014 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 record + +import ( + "encoding/json" + "fmt" + "math/rand" + "net/http" + "strconv" + "testing" + "time" + + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8sruntime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/client-go/kubernetes/scheme" + restclient "k8s.io/client-go/rest" + ref "k8s.io/client-go/tools/reference" +) + +type testEventSink struct { + OnCreate func(e *v1.Event) (*v1.Event, error) + OnUpdate func(e *v1.Event) (*v1.Event, error) + OnPatch func(e *v1.Event, p []byte) (*v1.Event, error) +} + +// CreateEvent records the event for testing. +func (t *testEventSink) Create(e *v1.Event) (*v1.Event, error) { + if t.OnCreate != nil { + return t.OnCreate(e) + } + return e, nil +} + +// UpdateEvent records the event for testing. +func (t *testEventSink) Update(e *v1.Event) (*v1.Event, error) { + if t.OnUpdate != nil { + return t.OnUpdate(e) + } + return e, nil +} + +// PatchEvent records the event for testing. +func (t *testEventSink) Patch(e *v1.Event, p []byte) (*v1.Event, error) { + if t.OnPatch != nil { + return t.OnPatch(e, p) + } + return e, nil +} + +type OnCreateFunc func(*v1.Event) (*v1.Event, error) + +func OnCreateFactory(testCache map[string]*v1.Event, createEvent chan<- *v1.Event) OnCreateFunc { + return func(event *v1.Event) (*v1.Event, error) { + testCache[getEventKey(event)] = event + createEvent <- event + return event, nil + } +} + +type OnPatchFunc func(*v1.Event, []byte) (*v1.Event, error) + +func OnPatchFactory(testCache map[string]*v1.Event, patchEvent chan<- *v1.Event) OnPatchFunc { + return func(event *v1.Event, patch []byte) (*v1.Event, error) { + cachedEvent, found := testCache[getEventKey(event)] + if !found { + return nil, fmt.Errorf("unexpected error: couldn't find Event in testCache.") + } + originalData, err := json.Marshal(cachedEvent) + if err != nil { + return nil, fmt.Errorf("unexpected error: %v", err) + } + patched, err := strategicpatch.StrategicMergePatch(originalData, patch, event) + if err != nil { + return nil, fmt.Errorf("unexpected error: %v", err) + } + patchedObj := &v1.Event{} + err = json.Unmarshal(patched, patchedObj) + if err != nil { + return nil, fmt.Errorf("unexpected error: %v", err) + } + patchEvent <- patchedObj + return patchedObj, nil + } +} + +func TestEventf(t *testing.T) { + testPod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + SelfLink: "/api/version/pods/foo", + Name: "foo", + Namespace: "baz", + UID: "bar", + }, + } + testPod2 := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + SelfLink: "/api/version/pods/foo", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + }, + } + testRef, err := ref.GetPartialReference(scheme.Scheme, testPod, "spec.containers[2]") + if err != nil { + t.Fatal(err) + } + testRef2, err := ref.GetPartialReference(scheme.Scheme, testPod2, "spec.containers[3]") + if err != nil { + t.Fatal(err) + } + table := []struct { + obj k8sruntime.Object + eventtype string + reason string + messageFmt string + elements []interface{} + expect *v1.Event + expectLog string + expectUpdate bool + }{ + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: false, + }, + { + obj: testPod, + eventtype: v1.EventTypeNormal, + reason: "Killed", + messageFmt: "some other verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + }, + Reason: "Killed", + Message: "some other verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:""}): type: 'Normal' reason: 'Killed' some other verbose message: 1`, + expectUpdate: false, + }, + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 2, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: true, + }, + { + obj: testRef2, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + APIVersion: "version", + FieldPath: "spec.containers[3]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: false, + }, + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 3, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: true, + }, + { + obj: testRef2, + eventtype: v1.EventTypeNormal, + reason: "Stopped", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + APIVersion: "version", + FieldPath: "spec.containers[3]", + }, + Reason: "Stopped", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`, + expectUpdate: false, + }, + { + obj: testRef2, + eventtype: v1.EventTypeNormal, + reason: "Stopped", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + APIVersion: "version", + FieldPath: "spec.containers[3]", + }, + Reason: "Stopped", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 2, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`, + expectUpdate: true, + }, + } + + testCache := map[string]*v1.Event{} + logCalled := make(chan struct{}) + createEvent := make(chan *v1.Event) + updateEvent := make(chan *v1.Event) + patchEvent := make(chan *v1.Event) + testEvents := testEventSink{ + OnCreate: OnCreateFactory(testCache, createEvent), + OnUpdate: func(event *v1.Event) (*v1.Event, error) { + updateEvent <- event + return event, nil + }, + OnPatch: OnPatchFactory(testCache, patchEvent), + } + eventBroadcaster := NewBroadcasterForTests(0) + sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents) + + clock := clock.NewFakeClock(time.Now()) + recorder := recorderWithFakeClock(v1.EventSource{Component: "eventTest"}, eventBroadcaster, clock) + for index, item := range table { + clock.Step(1 * time.Second) + logWatcher := eventBroadcaster.StartLogging(func(formatter string, args ...interface{}) { + if e, a := item.expectLog, fmt.Sprintf(formatter, args...); e != a { + t.Errorf("Expected '%v', got '%v'", e, a) + } + logCalled <- struct{}{} + }) + recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...) + + <-logCalled + + // validate event + if item.expectUpdate { + actualEvent := <-patchEvent + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } else { + actualEvent := <-createEvent + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } + logWatcher.Stop() + } + sinkWatcher.Stop() +} + +func recorderWithFakeClock(eventSource v1.EventSource, eventBroadcaster EventBroadcaster, clock clock.Clock) EventRecorder { + return &recorderImpl{scheme.Scheme, eventSource, eventBroadcaster.(*eventBroadcasterImpl).Broadcaster, clock} +} + +func TestWriteEventError(t *testing.T) { + type entry struct { + timesToSendError int + attemptsWanted int + err error + } + table := map[string]*entry{ + "giveUp1": { + timesToSendError: 1000, + attemptsWanted: 1, + err: &restclient.RequestConstructionError{}, + }, + "giveUp2": { + timesToSendError: 1000, + attemptsWanted: 1, + err: &errors.StatusError{}, + }, + "retry1": { + timesToSendError: 1000, + attemptsWanted: 12, + err: &errors.UnexpectedObjectError{}, + }, + "retry2": { + timesToSendError: 1000, + attemptsWanted: 12, + err: fmt.Errorf("A weird error"), + }, + "succeedEventually": { + timesToSendError: 2, + attemptsWanted: 2, + err: fmt.Errorf("A weird error"), + }, + } + + clock := clock.IntervalClock{Time: time.Now(), Duration: time.Second} + eventCorrelator := NewEventCorrelator(&clock) + randGen := rand.New(rand.NewSource(time.Now().UnixNano())) + + for caseName, ent := range table { + attempts := 0 + sink := &testEventSink{ + OnCreate: func(event *v1.Event) (*v1.Event, error) { + attempts++ + if attempts < ent.timesToSendError { + return nil, ent.err + } + return event, nil + }, + } + ev := &v1.Event{} + recordToSink(sink, ev, eventCorrelator, randGen, 0) + if attempts != ent.attemptsWanted { + t.Errorf("case %v: wanted %d, got %d attempts", caseName, ent.attemptsWanted, attempts) + } + } +} + +func TestUpdateExpiredEvent(t *testing.T) { + clock := clock.IntervalClock{Time: time.Now(), Duration: time.Second} + eventCorrelator := NewEventCorrelator(&clock) + randGen := rand.New(rand.NewSource(time.Now().UnixNano())) + + var createdEvent *v1.Event + + sink := &testEventSink{ + OnPatch: func(*v1.Event, []byte) (*v1.Event, error) { + return nil, &errors.StatusError{ + ErrStatus: metav1.Status{ + Code: http.StatusNotFound, + Reason: metav1.StatusReasonNotFound, + }} + }, + OnCreate: func(event *v1.Event) (*v1.Event, error) { + createdEvent = event + return event, nil + }, + } + + ev := &v1.Event{} + ev.ResourceVersion = "updated-resource-version" + ev.Count = 2 + recordToSink(sink, ev, eventCorrelator, randGen, 0) + + if createdEvent == nil { + t.Error("Event did not get created after patch failed") + return + } + + if createdEvent.ResourceVersion != "" { + t.Errorf("Event did not have its resource version cleared, was %s", createdEvent.ResourceVersion) + } +} + +func TestLotsOfEvents(t *testing.T) { + recorderCalled := make(chan struct{}) + loggerCalled := make(chan struct{}) + + // Fail each event a few times to ensure there's some load on the tested code. + var counts [1000]int + testEvents := testEventSink{ + OnCreate: func(event *v1.Event) (*v1.Event, error) { + num, err := strconv.Atoi(event.Message) + if err != nil { + t.Error(err) + return event, nil + } + counts[num]++ + if counts[num] < 5 { + return nil, fmt.Errorf("fake error") + } + recorderCalled <- struct{}{} + return event, nil + }, + } + + eventBroadcaster := NewBroadcasterForTests(0) + sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents) + logWatcher := eventBroadcaster.StartLogging(func(formatter string, args ...interface{}) { + loggerCalled <- struct{}{} + }) + recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "eventTest"}) + for i := 0; i < maxQueuedEvents; i++ { + // we want a unique object to stop spam filtering + ref := &v1.ObjectReference{ + Kind: "Pod", + Name: fmt.Sprintf("foo-%v", i), + Namespace: "baz", + UID: "bar", + APIVersion: "version", + } + // we need to vary the reason to prevent aggregation + go recorder.Eventf(ref, v1.EventTypeNormal, "Reason-"+string(i), strconv.Itoa(i)) + } + // Make sure no events were dropped by either of the listeners. + for i := 0; i < maxQueuedEvents; i++ { + <-recorderCalled + <-loggerCalled + } + // Make sure that every event was attempted 5 times + for i := 0; i < maxQueuedEvents; i++ { + if counts[i] < 5 { + t.Errorf("Only attempted to record event '%d' %d times.", i, counts[i]) + } + } + sinkWatcher.Stop() + logWatcher.Stop() +} + +func TestEventfNoNamespace(t *testing.T) { + testPod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + SelfLink: "/api/version/pods/foo", + Name: "foo", + UID: "bar", + }, + } + testRef, err := ref.GetPartialReference(scheme.Scheme, testPod, "spec.containers[2]") + if err != nil { + t.Fatal(err) + } + table := []struct { + obj k8sruntime.Object + eventtype string + reason string + messageFmt string + elements []interface{} + expect *v1.Event + expectLog string + expectUpdate bool + }{ + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: false, + }, + } + + testCache := map[string]*v1.Event{} + logCalled := make(chan struct{}) + createEvent := make(chan *v1.Event) + updateEvent := make(chan *v1.Event) + patchEvent := make(chan *v1.Event) + testEvents := testEventSink{ + OnCreate: OnCreateFactory(testCache, createEvent), + OnUpdate: func(event *v1.Event) (*v1.Event, error) { + updateEvent <- event + return event, nil + }, + OnPatch: OnPatchFactory(testCache, patchEvent), + } + eventBroadcaster := NewBroadcasterForTests(0) + sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents) + + clock := clock.NewFakeClock(time.Now()) + recorder := recorderWithFakeClock(v1.EventSource{Component: "eventTest"}, eventBroadcaster, clock) + + for index, item := range table { + clock.Step(1 * time.Second) + logWatcher := eventBroadcaster.StartLogging(func(formatter string, args ...interface{}) { + if e, a := item.expectLog, fmt.Sprintf(formatter, args...); e != a { + t.Errorf("Expected '%v', got '%v'", e, a) + } + logCalled <- struct{}{} + }) + recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...) + + <-logCalled + + // validate event + if item.expectUpdate { + actualEvent := <-patchEvent + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } else { + actualEvent := <-createEvent + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } + + logWatcher.Stop() + } + sinkWatcher.Stop() +} + +func TestMultiSinkCache(t *testing.T) { + testPod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + SelfLink: "/api/version/pods/foo", + Name: "foo", + Namespace: "baz", + UID: "bar", + }, + } + testPod2 := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + SelfLink: "/api/version/pods/foo", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + }, + } + testRef, err := ref.GetPartialReference(scheme.Scheme, testPod, "spec.containers[2]") + if err != nil { + t.Fatal(err) + } + testRef2, err := ref.GetPartialReference(scheme.Scheme, testPod2, "spec.containers[3]") + if err != nil { + t.Fatal(err) + } + table := []struct { + obj k8sruntime.Object + eventtype string + reason string + messageFmt string + elements []interface{} + expect *v1.Event + expectLog string + expectUpdate bool + }{ + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: false, + }, + { + obj: testPod, + eventtype: v1.EventTypeNormal, + reason: "Killed", + messageFmt: "some other verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + }, + Reason: "Killed", + Message: "some other verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:""}): type: 'Normal' reason: 'Killed' some other verbose message: 1`, + expectUpdate: false, + }, + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 2, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: true, + }, + { + obj: testRef2, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + APIVersion: "version", + FieldPath: "spec.containers[3]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: false, + }, + { + obj: testRef, + eventtype: v1.EventTypeNormal, + reason: "Started", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "bar", + APIVersion: "version", + FieldPath: "spec.containers[2]", + }, + Reason: "Started", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 3, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`, + expectUpdate: true, + }, + { + obj: testRef2, + eventtype: v1.EventTypeNormal, + reason: "Stopped", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + APIVersion: "version", + FieldPath: "spec.containers[3]", + }, + Reason: "Stopped", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 1, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`, + expectUpdate: false, + }, + { + obj: testRef2, + eventtype: v1.EventTypeNormal, + reason: "Stopped", + messageFmt: "some verbose message: %v", + elements: []interface{}{1}, + expect: &v1.Event{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "baz", + }, + InvolvedObject: v1.ObjectReference{ + Kind: "Pod", + Name: "foo", + Namespace: "baz", + UID: "differentUid", + APIVersion: "version", + FieldPath: "spec.containers[3]", + }, + Reason: "Stopped", + Message: "some verbose message: 1", + Source: v1.EventSource{Component: "eventTest"}, + Count: 2, + Type: v1.EventTypeNormal, + }, + expectLog: `Event(v1.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`, + expectUpdate: true, + }, + } + + testCache := map[string]*v1.Event{} + createEvent := make(chan *v1.Event) + updateEvent := make(chan *v1.Event) + patchEvent := make(chan *v1.Event) + testEvents := testEventSink{ + OnCreate: OnCreateFactory(testCache, createEvent), + OnUpdate: func(event *v1.Event) (*v1.Event, error) { + updateEvent <- event + return event, nil + }, + OnPatch: OnPatchFactory(testCache, patchEvent), + } + + testCache2 := map[string]*v1.Event{} + createEvent2 := make(chan *v1.Event) + updateEvent2 := make(chan *v1.Event) + patchEvent2 := make(chan *v1.Event) + testEvents2 := testEventSink{ + OnCreate: OnCreateFactory(testCache2, createEvent2), + OnUpdate: func(event *v1.Event) (*v1.Event, error) { + updateEvent2 <- event + return event, nil + }, + OnPatch: OnPatchFactory(testCache2, patchEvent2), + } + + eventBroadcaster := NewBroadcasterForTests(0) + clock := clock.NewFakeClock(time.Now()) + recorder := recorderWithFakeClock(v1.EventSource{Component: "eventTest"}, eventBroadcaster, clock) + + sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents) + for index, item := range table { + clock.Step(1 * time.Second) + recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...) + + // validate event + if item.expectUpdate { + actualEvent := <-patchEvent + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } else { + actualEvent := <-createEvent + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } + } + + // Another StartRecordingToSink call should start to record events with new clean cache. + sinkWatcher2 := eventBroadcaster.StartRecordingToSink(&testEvents2) + for index, item := range table { + clock.Step(1 * time.Second) + recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...) + + // validate event + if item.expectUpdate { + actualEvent := <-patchEvent2 + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } else { + actualEvent := <-createEvent2 + validateEvent(strconv.Itoa(index), actualEvent, item.expect, t) + } + } + + sinkWatcher.Stop() + sinkWatcher2.Stop() +} diff --git a/vendor/k8s.io/client-go/tools/record/events_cache_test.go b/vendor/k8s.io/client-go/tools/record/events_cache_test.go new file mode 100644 index 000000000..8cb4a39e8 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/record/events_cache_test.go @@ -0,0 +1,279 @@ +/* +Copyright 2015 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 record + +import ( + "reflect" + "strings" + "testing" + "time" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/util/diff" +) + +func makeObjectReference(kind, name, namespace string) v1.ObjectReference { + return v1.ObjectReference{ + Kind: kind, + Name: name, + Namespace: namespace, + UID: "C934D34AFB20242", + APIVersion: "version", + FieldPath: "spec.containers{mycontainer}", + } +} + +func makeEvent(reason, message string, involvedObject v1.ObjectReference) v1.Event { + eventTime := metav1.Now() + event := v1.Event{ + Reason: reason, + Message: message, + InvolvedObject: involvedObject, + Source: v1.EventSource{ + Component: "kubelet", + Host: "kublet.node1", + }, + Count: 1, + FirstTimestamp: eventTime, + LastTimestamp: eventTime, + Type: v1.EventTypeNormal, + } + return event +} + +func makeEvents(num int, template v1.Event) []v1.Event { + events := []v1.Event{} + for i := 0; i < num; i++ { + events = append(events, template) + } + return events +} + +func makeUniqueEvents(num int) []v1.Event { + events := []v1.Event{} + kind := "Pod" + for i := 0; i < num; i++ { + reason := strings.Join([]string{"reason", string(i)}, "-") + message := strings.Join([]string{"message", string(i)}, "-") + name := strings.Join([]string{"pod", string(i)}, "-") + namespace := strings.Join([]string{"ns", string(i)}, "-") + involvedObject := makeObjectReference(kind, name, namespace) + events = append(events, makeEvent(reason, message, involvedObject)) + } + return events +} + +func makeSimilarEvents(num int, template v1.Event, messagePrefix string) []v1.Event { + events := makeEvents(num, template) + for i := range events { + events[i].Message = strings.Join([]string{messagePrefix, string(i), events[i].Message}, "-") + } + return events +} + +func setCount(event v1.Event, count int) v1.Event { + event.Count = int32(count) + return event +} + +func validateEvent(messagePrefix string, actualEvent *v1.Event, expectedEvent *v1.Event, t *testing.T) (*v1.Event, error) { + recvEvent := *actualEvent + expectCompression := expectedEvent.Count > 1 + t.Logf("%v - expectedEvent.Count is %d\n", messagePrefix, expectedEvent.Count) + // Just check that the timestamp was set. + if recvEvent.FirstTimestamp.IsZero() || recvEvent.LastTimestamp.IsZero() { + t.Errorf("%v - timestamp wasn't set: %#v", messagePrefix, recvEvent) + } + actualFirstTimestamp := recvEvent.FirstTimestamp + actualLastTimestamp := recvEvent.LastTimestamp + if actualFirstTimestamp.Equal(&actualLastTimestamp) { + if expectCompression { + t.Errorf("%v - FirstTimestamp (%q) and LastTimestamp (%q) must be different to indicate event compression happened, but were the same. Actual Event: %#v", messagePrefix, actualFirstTimestamp, actualLastTimestamp, recvEvent) + } + } else { + if expectedEvent.Count == 1 { + t.Errorf("%v - FirstTimestamp (%q) and LastTimestamp (%q) must be equal to indicate only one occurrence of the event, but were different. Actual Event: %#v", messagePrefix, actualFirstTimestamp, actualLastTimestamp, recvEvent) + } + } + // Temp clear time stamps for comparison because actual values don't matter for comparison + recvEvent.FirstTimestamp = expectedEvent.FirstTimestamp + recvEvent.LastTimestamp = expectedEvent.LastTimestamp + // Check that name has the right prefix. + if n, en := recvEvent.Name, expectedEvent.Name; !strings.HasPrefix(n, en) { + t.Errorf("%v - Name '%v' does not contain prefix '%v'", messagePrefix, n, en) + } + recvEvent.Name = expectedEvent.Name + if e, a := expectedEvent, &recvEvent; !reflect.DeepEqual(e, a) { + t.Errorf("%v - diff: %s", messagePrefix, diff.ObjectGoPrintDiff(e, a)) + } + recvEvent.FirstTimestamp = actualFirstTimestamp + recvEvent.LastTimestamp = actualLastTimestamp + return actualEvent, nil +} + +// TestEventAggregatorByReasonFunc ensures that two events are aggregated if they vary only by event.message +func TestEventAggregatorByReasonFunc(t *testing.T) { + event1 := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other")) + event2 := makeEvent("end-of-world", "it was awful", makeObjectReference("Pod", "pod1", "other")) + event3 := makeEvent("nevermind", "it was a bug", makeObjectReference("Pod", "pod1", "other")) + + aggKey1, localKey1 := EventAggregatorByReasonFunc(&event1) + aggKey2, localKey2 := EventAggregatorByReasonFunc(&event2) + aggKey3, _ := EventAggregatorByReasonFunc(&event3) + + if aggKey1 != aggKey2 { + t.Errorf("Expected %v equal %v", aggKey1, aggKey2) + } + if localKey1 == localKey2 { + t.Errorf("Expected %v to not equal %v", aggKey1, aggKey3) + } + if aggKey1 == aggKey3 { + t.Errorf("Expected %v to not equal %v", aggKey1, aggKey3) + } +} + +// TestEventAggregatorByReasonMessageFunc validates the proper output for an aggregate message +func TestEventAggregatorByReasonMessageFunc(t *testing.T) { + expectedPrefix := "(combined from similar events): " + event1 := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other")) + actual := EventAggregatorByReasonMessageFunc(&event1) + if !strings.HasPrefix(actual, expectedPrefix) { + t.Errorf("Expected %v to begin with prefix %v", actual, expectedPrefix) + } +} + +// TestEventCorrelator validates proper counting, aggregation of events +func TestEventCorrelator(t *testing.T) { + firstEvent := makeEvent("first", "i am first", makeObjectReference("Pod", "my-pod", "my-ns")) + duplicateEvent := makeEvent("duplicate", "me again", makeObjectReference("Pod", "my-pod", "my-ns")) + uniqueEvent := makeEvent("unique", "snowflake", makeObjectReference("Pod", "my-pod", "my-ns")) + similarEvent := makeEvent("similar", "similar message", makeObjectReference("Pod", "my-pod", "my-ns")) + similarEvent.InvolvedObject.FieldPath = "spec.containers{container1}" + aggregateEvent := makeEvent(similarEvent.Reason, EventAggregatorByReasonMessageFunc(&similarEvent), similarEvent.InvolvedObject) + similarButDifferentContainerEvent := similarEvent + similarButDifferentContainerEvent.InvolvedObject.FieldPath = "spec.containers{container2}" + scenario := map[string]struct { + previousEvents []v1.Event + newEvent v1.Event + expectedEvent v1.Event + intervalSeconds int + expectedSkip bool + }{ + "create-a-single-event": { + previousEvents: []v1.Event{}, + newEvent: firstEvent, + expectedEvent: setCount(firstEvent, 1), + intervalSeconds: 5, + }, + "the-same-event-should-just-count": { + previousEvents: makeEvents(1, duplicateEvent), + newEvent: duplicateEvent, + expectedEvent: setCount(duplicateEvent, 2), + intervalSeconds: 5, + }, + "the-same-event-should-just-count-even-if-more-than-aggregate": { + previousEvents: makeEvents(defaultAggregateMaxEvents, duplicateEvent), + newEvent: duplicateEvent, + expectedEvent: setCount(duplicateEvent, defaultAggregateMaxEvents+1), + intervalSeconds: 30, // larger interval induces aggregation but not spam. + }, + "the-same-event-is-spam-if-happens-too-frequently": { + previousEvents: makeEvents(defaultSpamBurst+1, duplicateEvent), + newEvent: duplicateEvent, + expectedSkip: true, + intervalSeconds: 1, + }, + "create-many-unique-events": { + previousEvents: makeUniqueEvents(30), + newEvent: uniqueEvent, + expectedEvent: setCount(uniqueEvent, 1), + intervalSeconds: 5, + }, + "similar-events-should-aggregate-event": { + previousEvents: makeSimilarEvents(defaultAggregateMaxEvents-1, similarEvent, similarEvent.Message), + newEvent: similarEvent, + expectedEvent: setCount(aggregateEvent, 1), + intervalSeconds: 5, + }, + "similar-events-many-times-should-count-the-aggregate": { + previousEvents: makeSimilarEvents(defaultAggregateMaxEvents, similarEvent, similarEvent.Message), + newEvent: similarEvent, + expectedEvent: setCount(aggregateEvent, 2), + intervalSeconds: 5, + }, + "events-from-different-containers-do-not-aggregate": { + previousEvents: makeEvents(1, similarButDifferentContainerEvent), + newEvent: similarEvent, + expectedEvent: setCount(similarEvent, 1), + intervalSeconds: 5, + }, + "similar-events-whose-interval-is-greater-than-aggregate-interval-do-not-aggregate": { + previousEvents: makeSimilarEvents(defaultAggregateMaxEvents-1, similarEvent, similarEvent.Message), + newEvent: similarEvent, + expectedEvent: setCount(similarEvent, 1), + intervalSeconds: defaultAggregateIntervalInSeconds, + }, + } + + for testScenario, testInput := range scenario { + eventInterval := time.Duration(testInput.intervalSeconds) * time.Second + clock := clock.IntervalClock{Time: time.Now(), Duration: eventInterval} + correlator := NewEventCorrelator(&clock) + for i := range testInput.previousEvents { + event := testInput.previousEvents[i] + now := metav1.NewTime(clock.Now()) + event.FirstTimestamp = now + event.LastTimestamp = now + result, err := correlator.EventCorrelate(&event) + if err != nil { + t.Errorf("scenario %v: unexpected error playing back prevEvents %v", testScenario, err) + } + // if we are skipping the event, we can avoid updating state + if !result.Skip { + correlator.UpdateState(result.Event) + } + } + + // update the input to current clock value + now := metav1.NewTime(clock.Now()) + testInput.newEvent.FirstTimestamp = now + testInput.newEvent.LastTimestamp = now + result, err := correlator.EventCorrelate(&testInput.newEvent) + if err != nil { + t.Errorf("scenario %v: unexpected error correlating input event %v", testScenario, err) + } + + // verify we did not get skip from filter function unexpectedly... + if result.Skip != testInput.expectedSkip { + t.Errorf("scenario %v: expected skip %v, but got %v", testScenario, testInput.expectedSkip, result.Skip) + continue + } + + // we wanted to actually skip, so no event is needed to validate + if testInput.expectedSkip { + continue + } + + // validate event + _, err = validateEvent(testScenario, result.Event, &testInput.expectedEvent, t) + if err != nil { + t.Errorf("scenario %v: unexpected error validating result %v", testScenario, err) + } + } +} diff --git a/vendor/k8s.io/client-go/tools/reference/ref_test.go b/vendor/k8s.io/client-go/tools/reference/ref_test.go new file mode 100644 index 000000000..b0cf06a97 --- /dev/null +++ b/vendor/k8s.io/client-go/tools/reference/ref_test.go @@ -0,0 +1,72 @@ +/* +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. +*/ + +package reference + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type TestRuntimeObj struct { + metav1.TypeMeta + metav1.ObjectMeta +} + +func (o *TestRuntimeObj) DeepCopyObject() runtime.Object { + panic("die") +} + +func TestGetReferenceRefVersion(t *testing.T) { + tests := []struct { + name string + input *TestRuntimeObj + expectedRefVersion string + }{ + { + name: "api from selflink", + input: &TestRuntimeObj{ + ObjectMeta: metav1.ObjectMeta{SelfLink: "/api/v1/namespaces"}, + }, + expectedRefVersion: "v1", + }, + { + name: "foo.group/v3 from selflink", + input: &TestRuntimeObj{ + ObjectMeta: metav1.ObjectMeta{SelfLink: "/apis/foo.group/v3/namespaces"}, + }, + expectedRefVersion: "foo.group/v3", + }, + } + + scheme := runtime.NewScheme() + scheme.AddKnownTypes(schema.GroupVersion{Group: "this", Version: "is ignored"}, &TestRuntimeObj{}) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ref, err := GetReference(scheme, test.input) + if err != nil { + t.Fatal(err) + } + if test.expectedRefVersion != ref.APIVersion { + t.Errorf("expected %q, got %q", test.expectedRefVersion, ref.APIVersion) + } + }) + } +} diff --git a/vendor/k8s.io/client-go/transport/OWNERS b/vendor/k8s.io/client-go/transport/OWNERS new file mode 100755 index 000000000..bf0ba5b9f --- /dev/null +++ b/vendor/k8s.io/client-go/transport/OWNERS @@ -0,0 +1,7 @@ +reviewers: +- smarterclayton +- wojtek-t +- deads2k +- liggitt +- krousey +- caesarxuchao diff --git a/vendor/k8s.io/client-go/transport/cache_test.go b/vendor/k8s.io/client-go/transport/cache_test.go new file mode 100644 index 000000000..9b740cdec --- /dev/null +++ b/vendor/k8s.io/client-go/transport/cache_test.go @@ -0,0 +1,157 @@ +/* +Copyright 2015 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 transport + +import ( + "context" + "crypto/tls" + "net" + "net/http" + "testing" +) + +func TestTLSConfigKey(t *testing.T) { + // Make sure config fields that don't affect the tls config don't affect the cache key + identicalConfigurations := map[string]*Config{ + "empty": {}, + "basic": {Username: "bob", Password: "password"}, + "bearer": {BearerToken: "token"}, + "user agent": {UserAgent: "useragent"}, + "transport": {Transport: http.DefaultTransport}, + "wrap transport": {WrapTransport: func(http.RoundTripper) http.RoundTripper { return nil }}, + } + for nameA, valueA := range identicalConfigurations { + for nameB, valueB := range identicalConfigurations { + keyA, err := tlsConfigKey(valueA) + if err != nil { + t.Errorf("Unexpected error for %q: %v", nameA, err) + continue + } + keyB, err := tlsConfigKey(valueB) + if err != nil { + t.Errorf("Unexpected error for %q: %v", nameB, err) + continue + } + if keyA != keyB { + t.Errorf("Expected identical cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB) + continue + } + } + } + + // Make sure config fields that affect the tls config affect the cache key + dialer := net.Dialer{} + getCert := func() (*tls.Certificate, error) { return nil, nil } + uniqueConfigurations := map[string]*Config{ + "no tls": {}, + "dialer": {Dial: dialer.DialContext}, + "dialer2": {Dial: func(ctx context.Context, network, address string) (net.Conn, error) { return nil, nil }}, + "insecure": {TLS: TLSConfig{Insecure: true}}, + "cadata 1": {TLS: TLSConfig{CAData: []byte{1}}}, + "cadata 2": {TLS: TLSConfig{CAData: []byte{2}}}, + "cert 1, key 1": { + TLS: TLSConfig{ + CertData: []byte{1}, + KeyData: []byte{1}, + }, + }, + "cert 1, key 1, servername 1": { + TLS: TLSConfig{ + CertData: []byte{1}, + KeyData: []byte{1}, + ServerName: "1", + }, + }, + "cert 1, key 1, servername 2": { + TLS: TLSConfig{ + CertData: []byte{1}, + KeyData: []byte{1}, + ServerName: "2", + }, + }, + "cert 1, key 2": { + TLS: TLSConfig{ + CertData: []byte{1}, + KeyData: []byte{2}, + }, + }, + "cert 2, key 1": { + TLS: TLSConfig{ + CertData: []byte{2}, + KeyData: []byte{1}, + }, + }, + "cert 2, key 2": { + TLS: TLSConfig{ + CertData: []byte{2}, + KeyData: []byte{2}, + }, + }, + "cadata 1, cert 1, key 1": { + TLS: TLSConfig{ + CAData: []byte{1}, + CertData: []byte{1}, + KeyData: []byte{1}, + }, + }, + "getCert1": { + TLS: TLSConfig{ + KeyData: []byte{1}, + GetCert: getCert, + }, + }, + "getCert2": { + TLS: TLSConfig{ + KeyData: []byte{1}, + GetCert: func() (*tls.Certificate, error) { return nil, nil }, + }, + }, + "getCert1, key 2": { + TLS: TLSConfig{ + KeyData: []byte{2}, + GetCert: getCert, + }, + }, + } + for nameA, valueA := range uniqueConfigurations { + for nameB, valueB := range uniqueConfigurations { + keyA, err := tlsConfigKey(valueA) + if err != nil { + t.Errorf("Unexpected error for %q: %v", nameA, err) + continue + } + keyB, err := tlsConfigKey(valueB) + if err != nil { + t.Errorf("Unexpected error for %q: %v", nameB, err) + continue + } + + // Make sure we get the same key on the same config + if nameA == nameB { + if keyA != keyB { + t.Errorf("Expected identical cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB) + } + continue + } + + if keyA == keyB { + t.Errorf("Expected unique cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB) + continue + } + } + } +} diff --git a/vendor/k8s.io/client-go/transport/round_trippers_test.go b/vendor/k8s.io/client-go/transport/round_trippers_test.go new file mode 100644 index 000000000..74d3dc212 --- /dev/null +++ b/vendor/k8s.io/client-go/transport/round_trippers_test.go @@ -0,0 +1,329 @@ +/* +Copyright 2014 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 transport + +import ( + "net/http" + "net/url" + "reflect" + "strings" + "testing" +) + +type testRoundTripper struct { + Request *http.Request + Response *http.Response + Err error +} + +func (rt *testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + rt.Request = req + return rt.Response, rt.Err +} + +func TestBearerAuthRoundTripper(t *testing.T) { + rt := &testRoundTripper{} + req := &http.Request{} + NewBearerAuthRoundTripper("test", rt).RoundTrip(req) + if rt.Request == nil { + t.Fatalf("unexpected nil request: %v", rt) + } + if rt.Request == req { + t.Fatalf("round tripper should have copied request object: %#v", rt.Request) + } + if rt.Request.Header.Get("Authorization") != "Bearer test" { + t.Errorf("unexpected authorization header: %#v", rt.Request) + } +} + +func TestBasicAuthRoundTripper(t *testing.T) { + for n, tc := range map[string]struct { + user string + pass string + }{ + "basic": {user: "user", pass: "pass"}, + "no pass": {user: "user"}, + } { + rt := &testRoundTripper{} + req := &http.Request{} + NewBasicAuthRoundTripper(tc.user, tc.pass, rt).RoundTrip(req) + if rt.Request == nil { + t.Fatalf("%s: unexpected nil request: %v", n, rt) + } + if rt.Request == req { + t.Fatalf("%s: round tripper should have copied request object: %#v", n, rt.Request) + } + if user, pass, found := rt.Request.BasicAuth(); !found || user != tc.user || pass != tc.pass { + t.Errorf("%s: unexpected authorization header: %#v", n, rt.Request) + } + } +} + +func TestUserAgentRoundTripper(t *testing.T) { + rt := &testRoundTripper{} + req := &http.Request{ + Header: make(http.Header), + } + req.Header.Set("User-Agent", "other") + NewUserAgentRoundTripper("test", rt).RoundTrip(req) + if rt.Request == nil { + t.Fatalf("unexpected nil request: %v", rt) + } + if rt.Request != req { + t.Fatalf("round tripper should not have copied request object: %#v", rt.Request) + } + if rt.Request.Header.Get("User-Agent") != "other" { + t.Errorf("unexpected user agent header: %#v", rt.Request) + } + + req = &http.Request{} + NewUserAgentRoundTripper("test", rt).RoundTrip(req) + if rt.Request == nil { + t.Fatalf("unexpected nil request: %v", rt) + } + if rt.Request == req { + t.Fatalf("round tripper should have copied request object: %#v", rt.Request) + } + if rt.Request.Header.Get("User-Agent") != "test" { + t.Errorf("unexpected user agent header: %#v", rt.Request) + } +} + +func TestImpersonationRoundTripper(t *testing.T) { + tcs := []struct { + name string + impersonationConfig ImpersonationConfig + expected map[string][]string + }{ + { + name: "all", + impersonationConfig: ImpersonationConfig{ + UserName: "user", + Groups: []string{"one", "two"}, + Extra: map[string][]string{ + "first": {"A", "a"}, + "second": {"B", "b"}, + }, + }, + expected: map[string][]string{ + ImpersonateUserHeader: {"user"}, + ImpersonateGroupHeader: {"one", "two"}, + ImpersonateUserExtraHeaderPrefix + "First": {"A", "a"}, + ImpersonateUserExtraHeaderPrefix + "Second": {"B", "b"}, + }, + }, + { + name: "escape handling", + impersonationConfig: ImpersonationConfig{ + UserName: "user", + Extra: map[string][]string{ + "test.example.com/thing.thing": {"A", "a"}, + }, + }, + expected: map[string][]string{ + ImpersonateUserHeader: {"user"}, + ImpersonateUserExtraHeaderPrefix + `Test.example.com%2fthing.thing`: {"A", "a"}, + }, + }, + { + name: "double escape handling", + impersonationConfig: ImpersonationConfig{ + UserName: "user", + Extra: map[string][]string{ + "test.example.com/thing.thing%20another.thing": {"A", "a"}, + }, + }, + expected: map[string][]string{ + ImpersonateUserHeader: {"user"}, + ImpersonateUserExtraHeaderPrefix + `Test.example.com%2fthing.thing%2520another.thing`: {"A", "a"}, + }, + }, + } + + for _, tc := range tcs { + rt := &testRoundTripper{} + req := &http.Request{ + Header: make(http.Header), + } + NewImpersonatingRoundTripper(tc.impersonationConfig, rt).RoundTrip(req) + + for k, v := range rt.Request.Header { + expected, ok := tc.expected[k] + if !ok { + t.Errorf("%v missing %v=%v", tc.name, k, v) + continue + } + if !reflect.DeepEqual(expected, v) { + t.Errorf("%v expected %v: %v, got %v", tc.name, k, expected, v) + } + } + for k, v := range tc.expected { + expected, ok := rt.Request.Header[k] + if !ok { + t.Errorf("%v missing %v=%v", tc.name, k, v) + continue + } + if !reflect.DeepEqual(expected, v) { + t.Errorf("%v expected %v: %v, got %v", tc.name, k, expected, v) + } + } + } +} + +func TestAuthProxyRoundTripper(t *testing.T) { + for n, tc := range map[string]struct { + username string + groups []string + extra map[string][]string + expectedExtra map[string][]string + }{ + "allfields": { + username: "user", + groups: []string{"groupA", "groupB"}, + extra: map[string][]string{ + "one": {"alpha", "bravo"}, + "two": {"charlie", "delta"}, + }, + expectedExtra: map[string][]string{ + "one": {"alpha", "bravo"}, + "two": {"charlie", "delta"}, + }, + }, + "escaped extra": { + username: "user", + groups: []string{"groupA", "groupB"}, + extra: map[string][]string{ + "one": {"alpha", "bravo"}, + "example.com/two": {"charlie", "delta"}, + }, + expectedExtra: map[string][]string{ + "one": {"alpha", "bravo"}, + "example.com%2ftwo": {"charlie", "delta"}, + }, + }, + "double escaped extra": { + username: "user", + groups: []string{"groupA", "groupB"}, + extra: map[string][]string{ + "one": {"alpha", "bravo"}, + "example.com/two%20three": {"charlie", "delta"}, + }, + expectedExtra: map[string][]string{ + "one": {"alpha", "bravo"}, + "example.com%2ftwo%2520three": {"charlie", "delta"}, + }, + }, + } { + rt := &testRoundTripper{} + req := &http.Request{} + NewAuthProxyRoundTripper(tc.username, tc.groups, tc.extra, rt).RoundTrip(req) + if rt.Request == nil { + t.Errorf("%s: unexpected nil request: %v", n, rt) + continue + } + if rt.Request == req { + t.Errorf("%s: round tripper should have copied request object: %#v", n, rt.Request) + continue + } + + actualUsernames, ok := rt.Request.Header["X-Remote-User"] + if !ok { + t.Errorf("%s missing value", n) + continue + } + if e, a := []string{tc.username}, actualUsernames; !reflect.DeepEqual(e, a) { + t.Errorf("%s expected %v, got %v", n, e, a) + continue + } + actualGroups, ok := rt.Request.Header["X-Remote-Group"] + if !ok { + t.Errorf("%s missing value", n) + continue + } + if e, a := tc.groups, actualGroups; !reflect.DeepEqual(e, a) { + t.Errorf("%s expected %v, got %v", n, e, a) + continue + } + + actualExtra := map[string][]string{} + for key, values := range rt.Request.Header { + if strings.HasPrefix(strings.ToLower(key), strings.ToLower("X-Remote-Extra-")) { + extraKey := strings.ToLower(key[len("X-Remote-Extra-"):]) + actualExtra[extraKey] = append(actualExtra[key], values...) + } + } + if e, a := tc.expectedExtra, actualExtra; !reflect.DeepEqual(e, a) { + t.Errorf("%s expected %v, got %v", n, e, a) + continue + } + } +} + +// TestHeaderEscapeRoundTrip tests to see if foo == url.PathUnescape(headerEscape(foo)) +// This behavior is important for client -> API server transmission of extra values. +func TestHeaderEscapeRoundTrip(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + key string + }{ + { + name: "alpha", + key: "alphabetical", + }, + { + name: "alphanumeric", + key: "alph4num3r1c", + }, + { + name: "percent encoded", + key: "percent%20encoded", + }, + { + name: "almost percent encoded", + key: "almost%zzpercent%xxencoded", + }, + { + name: "illegal char & percent encoding", + key: "example.com/percent%20encoded", + }, + { + name: "weird unicode stuff", + key: "example.com/ᛒᚥᛏᛖᚥᚢとロビン", + }, + { + name: "header legal chars", + key: "abc123!#$+.-_*\\^`~|'", + }, + { + name: "legal path, illegal header", + key: "@=:", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + escaped := headerKeyEscape(tc.key) + unescaped, err := url.PathUnescape(escaped) + if err != nil { + t.Fatalf("url.PathUnescape(%q) returned error: %v", escaped, err) + } + if tc.key != unescaped { + t.Errorf("url.PathUnescape(headerKeyEscape(%q)) returned %q, wanted %q", tc.key, unescaped, tc.key) + } + }) + } +} diff --git a/vendor/k8s.io/client-go/transport/transport_test.go b/vendor/k8s.io/client-go/transport/transport_test.go new file mode 100644 index 000000000..2e9896a08 --- /dev/null +++ b/vendor/k8s.io/client-go/transport/transport_test.go @@ -0,0 +1,288 @@ +/* +Copyright 2015 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 transport + +import ( + "crypto/tls" + "errors" + "net/http" + "testing" +) + +const ( + rootCACert = `-----BEGIN CERTIFICATE----- +MIIC4DCCAcqgAwIBAgIBATALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu +MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIxNTczN1oXDTE2MDExNTIxNTcz +OFowIzEhMB8GA1UEAwwYMTAuMTMuMTI5LjEwNkAxNDIxMzU5MDU4MIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunDRXGwsiYWGFDlWH6kjGun+PshDGeZX +xtx9lUnL8pIRWH3wX6f13PO9sktaOWW0T0mlo6k2bMlSLlSZgG9H6og0W6gLS3vq +s4VavZ6DbXIwemZG2vbRwsvR+t4G6Nbwelm6F8RFnA1Fwt428pavmNQ/wgYzo+T1 +1eS+HiN4ACnSoDSx3QRWcgBkB1g6VReofVjx63i0J+w8Q/41L9GUuLqquFxu6ZnH +60vTB55lHgFiDLjA1FkEz2dGvGh/wtnFlRvjaPC54JH2K1mPYAUXTreoeJtLJKX0 +ycoiyB24+zGCniUmgIsmQWRPaOPircexCp1BOeze82BT1LCZNTVaxQIDAQABoyMw +ITAOBgNVHQ8BAf8EBAMCAKQwDwYDVR0TAQH/BAUwAwEB/zALBgkqhkiG9w0BAQsD +ggEBADMxsUuAFlsYDpF4fRCzXXwrhbtj4oQwcHpbu+rnOPHCZupiafzZpDu+rw4x +YGPnCb594bRTQn4pAu3Ac18NbLD5pV3uioAkv8oPkgr8aUhXqiv7KdDiaWm6sbAL +EHiXVBBAFvQws10HMqMoKtO8f1XDNAUkWduakR/U6yMgvOPwS7xl0eUTqyRB6zGb +K55q2dejiFWaFqB/y78txzvz6UlOZKE44g2JAVoJVM6kGaxh33q8/FmrL4kuN3ut +W+MmJCVDvd4eEqPwbp7146ZWTqpIJ8lvA6wuChtqV8lhAPka2hD/LMqY8iXNmfXD +uml0obOEy+ON91k+SWTJ3ggmF/U= +-----END CERTIFICATE-----` + + certData = `-----BEGIN CERTIFICATE----- +MIIC6jCCAdSgAwIBAgIBCzALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu +MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIyMDEzMVoXDTE2MDExNTIyMDEz +MlowGzEZMBcGA1UEAxMQb3BlbnNoaWZ0LWNsaWVudDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKtdhz0+uCLXw5cSYns9rU/XifFSpb/x24WDdrm72S/v +b9BPYsAStiP148buylr1SOuNi8sTAZmlVDDIpIVwMLff+o2rKYDicn9fjbrTxTOj +lI4pHJBH+JU3AJ0tbajupioh70jwFS0oYpwtneg2zcnE2Z4l6mhrj2okrc5Q1/X2 +I2HChtIU4JYTisObtin10QKJX01CLfYXJLa8upWzKZ4/GOcHG+eAV3jXWoXidtjb +1Usw70amoTZ6mIVCkiu1QwCoa8+ycojGfZhvqMsAp1536ZcCul+Na+AbCv4zKS7F +kQQaImVrXdUiFansIoofGlw/JNuoKK6ssVpS5Ic3pgcCAwEAAaM1MDMwDgYDVR0P +AQH/BAQDAgCgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJ +KoZIhvcNAQELA4IBAQCKLREH7bXtXtZ+8vI6cjD7W3QikiArGqbl36bAhhWsJLp/ +p/ndKz39iFNaiZ3GlwIURWOOKx3y3GA0x9m8FR+Llthf0EQ8sUjnwaknWs0Y6DQ3 +jjPFZOpV3KPCFrdMJ3++E3MgwFC/Ih/N2ebFX9EcV9Vcc6oVWMdwT0fsrhu683rq +6GSR/3iVX1G/pmOiuaR0fNUaCyCfYrnI4zHBDgSfnlm3vIvN2lrsR/DQBakNL8DJ +HBgKxMGeUPoneBv+c8DMXIL0EhaFXRlBv9QW45/GiAIOuyFJ0i6hCtGZpJjq4OpQ +BRjCI+izPzFTjsxD4aORE+WOkyWFCGPWKfNejfw0 +-----END CERTIFICATE-----` + + keyData = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAq12HPT64ItfDlxJiez2tT9eJ8VKlv/HbhYN2ubvZL+9v0E9i +wBK2I/Xjxu7KWvVI642LyxMBmaVUMMikhXAwt9/6jaspgOJyf1+NutPFM6OUjikc +kEf4lTcAnS1tqO6mKiHvSPAVLShinC2d6DbNycTZniXqaGuPaiStzlDX9fYjYcKG +0hTglhOKw5u2KfXRAolfTUIt9hcktry6lbMpnj8Y5wcb54BXeNdaheJ22NvVSzDv +RqahNnqYhUKSK7VDAKhrz7JyiMZ9mG+oywCnXnfplwK6X41r4BsK/jMpLsWRBBoi +ZWtd1SIVqewiih8aXD8k26gorqyxWlLkhzemBwIDAQABAoIBAD2XYRs3JrGHQUpU +FkdbVKZkvrSY0vAZOqBTLuH0zUv4UATb8487anGkWBjRDLQCgxH+jucPTrztekQK +aW94clo0S3aNtV4YhbSYIHWs1a0It0UdK6ID7CmdWkAj6s0T8W8lQT7C46mWYVLm +5mFnCTHi6aB42jZrqmEpC7sivWwuU0xqj3Ml8kkxQCGmyc9JjmCB4OrFFC8NNt6M +ObvQkUI6Z3nO4phTbpxkE1/9dT0MmPIF7GhHVzJMS+EyyRYUDllZ0wvVSOM3qZT0 +JMUaBerkNwm9foKJ1+dv2nMKZZbJajv7suUDCfU44mVeaEO+4kmTKSGCGjjTBGkr +7L1ySDECgYEA5ElIMhpdBzIivCuBIH8LlUeuzd93pqssO1G2Xg0jHtfM4tz7fyeI +cr90dc8gpli24dkSxzLeg3Tn3wIj/Bu64m2TpZPZEIlukYvgdgArmRIPQVxerYey +OkrfTNkxU1HXsYjLCdGcGXs5lmb+K/kuTcFxaMOs7jZi7La+jEONwf8CgYEAwCs/ +rUOOA0klDsWWisbivOiNPII79c9McZCNBqncCBfMUoiGe8uWDEO4TFHN60vFuVk9 +8PkwpCfvaBUX+ajvbafIfHxsnfk1M04WLGCeqQ/ym5Q4sQoQOcC1b1y9qc/xEWfg +nIUuia0ukYRpl7qQa3tNg+BNFyjypW8zukUAC/kCgYB1/Kojuxx5q5/oQVPrx73k +2bevD+B3c+DYh9MJqSCNwFtUpYIWpggPxoQan4LwdsmO0PKzocb/ilyNFj4i/vII +NToqSc/WjDFpaDIKyuu9oWfhECye45NqLWhb/6VOuu4QA/Nsj7luMhIBehnEAHW+ +GkzTKM8oD1PxpEG3nPKXYQKBgQC6AuMPRt3XBl1NkCrpSBy/uObFlFaP2Enpf39S +3OZ0Gv0XQrnSaL1kP8TMcz68rMrGX8DaWYsgytstR4W+jyy7WvZwsUu+GjTJ5aMG +77uEcEBpIi9CBzivfn7hPccE8ZgqPf+n4i6q66yxBJflW5xhvafJqDtW2LcPNbW/ +bvzdmQKBgExALRUXpq+5dbmkdXBHtvXdRDZ6rVmrnjy4nI5bPw+1GqQqk6uAR6B/ +F6NmLCQOO4PDG/cuatNHIr2FrwTmGdEL6ObLUGWn9Oer9gJhHVqqsY5I4sEPo4XX +stR0Yiw0buV6DL/moUO0HIM9Bjh96HJp+LxiIS6UCdIhMPp5HoQa +-----END RSA PRIVATE KEY-----` +) + +func TestNew(t *testing.T) { + testCases := map[string]struct { + Config *Config + Err bool + TLS bool + TLSCert bool + TLSErr bool + Default bool + }{ + "default transport": { + Default: true, + Config: &Config{}, + }, + + "server name": { + TLS: true, + Config: &Config{TLS: TLSConfig{ + ServerName: "foo", + }}, + }, + + "ca transport": { + TLS: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + }, + }, + }, + "bad ca file transport": { + Err: true, + Config: &Config{ + TLS: TLSConfig{ + CAFile: "invalid file", + }, + }, + }, + "ca data overriding bad ca file transport": { + TLS: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + CAFile: "invalid file", + }, + }, + }, + + "cert transport": { + TLS: true, + TLSCert: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + CertData: []byte(certData), + KeyData: []byte(keyData), + }, + }, + }, + "bad cert data transport": { + Err: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + CertData: []byte(certData), + KeyData: []byte("bad key data"), + }, + }, + }, + "bad file cert transport": { + Err: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + CertData: []byte(certData), + KeyFile: "invalid file", + }, + }, + }, + "key data overriding bad file cert transport": { + TLS: true, + TLSCert: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + CertData: []byte(certData), + KeyData: []byte(keyData), + KeyFile: "invalid file", + }, + }, + }, + "callback cert and key": { + TLS: true, + TLSCert: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + GetCert: func() (*tls.Certificate, error) { + crt, err := tls.X509KeyPair([]byte(certData), []byte(keyData)) + return &crt, err + }, + }, + }, + }, + "cert callback error": { + TLS: true, + TLSCert: true, + TLSErr: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + GetCert: func() (*tls.Certificate, error) { + return nil, errors.New("GetCert failure") + }, + }, + }, + }, + "cert data overrides empty callback result": { + TLS: true, + TLSCert: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + GetCert: func() (*tls.Certificate, error) { + return nil, nil + }, + CertData: []byte(certData), + KeyData: []byte(keyData), + }, + }, + }, + "callback returns nothing": { + TLS: true, + TLSCert: true, + Config: &Config{ + TLS: TLSConfig{ + CAData: []byte(rootCACert), + GetCert: func() (*tls.Certificate, error) { + return nil, nil + }, + }, + }, + }, + } + for k, testCase := range testCases { + t.Run(k, func(t *testing.T) { + rt, err := New(testCase.Config) + switch { + case testCase.Err && err == nil: + t.Fatal("unexpected non-error") + case !testCase.Err && err != nil: + t.Fatalf("unexpected error: %v", err) + } + if testCase.Err { + return + } + + switch { + case testCase.Default && rt != http.DefaultTransport: + t.Fatalf("got %#v, expected the default transport", rt) + case !testCase.Default && rt == http.DefaultTransport: + t.Fatalf("got %#v, expected non-default transport", rt) + } + + // We only know how to check TLSConfig on http.Transports + transport := rt.(*http.Transport) + switch { + case testCase.TLS && transport.TLSClientConfig == nil: + t.Fatalf("got %#v, expected TLSClientConfig", transport) + case !testCase.TLS && transport.TLSClientConfig != nil: + t.Fatalf("got %#v, expected no TLSClientConfig", transport) + } + if !testCase.TLS { + return + } + + switch { + case testCase.TLSCert && transport.TLSClientConfig.GetClientCertificate == nil: + t.Fatalf("got %#v, expected TLSClientConfig.GetClientCertificate", transport.TLSClientConfig) + case !testCase.TLSCert && transport.TLSClientConfig.GetClientCertificate != nil: + t.Fatalf("got %#v, expected no TLSClientConfig.GetClientCertificate", transport.TLSClientConfig) + } + if !testCase.TLSCert { + return + } + + _, err = transport.TLSClientConfig.GetClientCertificate(nil) + switch { + case testCase.TLSErr && err == nil: + t.Error("got nil error from GetClientCertificate, expected non-nil") + case !testCase.TLSErr && err != nil: + t.Errorf("got error from GetClientCertificate: %q, expected nil", err) + } + }) + } +} diff --git a/vendor/k8s.io/client-go/util/buffer/ring_growing_test.go b/vendor/k8s.io/client-go/util/buffer/ring_growing_test.go new file mode 100644 index 000000000..31a4c079d --- /dev/null +++ b/vendor/k8s.io/client-go/util/buffer/ring_growing_test.go @@ -0,0 +1,50 @@ +/* +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 buffer + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGrowth(t *testing.T) { + t.Parallel() + x := 10 + g := NewRingGrowing(1) + for i := 0; i < x; i++ { + assert.Equal(t, i, g.readable) + g.WriteOne(i) + } + read := 0 + for g.readable > 0 { + v, ok := g.ReadOne() + assert.True(t, ok) + assert.Equal(t, read, v) + read++ + } + assert.Equalf(t, x, read, "expected to have read %d items: %d", x, read) + assert.Zerof(t, g.readable, "expected readable to be zero: %d", g.readable) + assert.Equalf(t, 16, g.n, "expected N to be 16: %d", g.n) +} + +func TestEmpty(t *testing.T) { + t.Parallel() + g := NewRingGrowing(1) + _, ok := g.ReadOne() + assert.False(t, ok) +} diff --git a/vendor/k8s.io/client-go/util/cert/csr_test.go b/vendor/k8s.io/client-go/util/cert/csr_test.go new file mode 100644 index 000000000..ed28f021e --- /dev/null +++ b/vendor/k8s.io/client-go/util/cert/csr_test.go @@ -0,0 +1,75 @@ +/* +Copyright 2016 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 cert + +import ( + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "io/ioutil" + "net" + "testing" +) + +func TestMakeCSR(t *testing.T) { + keyFile := "testdata/dontUseThisKey.pem" + subject := &pkix.Name{ + CommonName: "kube-worker", + } + dnsSANs := []string{"localhost"} + ipSANs := []net.IP{net.ParseIP("127.0.0.1")} + + keyData, err := ioutil.ReadFile(keyFile) + if err != nil { + t.Fatal(err) + } + key, err := ParsePrivateKeyPEM(keyData) + if err != nil { + t.Fatal(err) + } + csrPEM, err := MakeCSR(key, subject, dnsSANs, ipSANs) + if err != nil { + t.Error(err) + } + csrBlock, rest := pem.Decode(csrPEM) + if csrBlock == nil { + t.Error("Unable to decode MakeCSR result.") + } + if len(rest) != 0 { + t.Error("Found more than one PEM encoded block in the result.") + } + if csrBlock.Type != CertificateRequestBlockType { + t.Errorf("Found block type %q, wanted 'CERTIFICATE REQUEST'", csrBlock.Type) + } + csr, err := x509.ParseCertificateRequest(csrBlock.Bytes) + if err != nil { + t.Errorf("Found %v parsing MakeCSR result as a CertificateRequest.", err) + } + if csr.Subject.CommonName != subject.CommonName { + t.Errorf("Wanted %v, got %v", subject, csr.Subject) + } + if len(csr.DNSNames) != 1 { + t.Errorf("Wanted 1 DNS name in the result, got %d", len(csr.DNSNames)) + } else if csr.DNSNames[0] != dnsSANs[0] { + t.Errorf("Wanted %v, got %v", dnsSANs[0], csr.DNSNames[0]) + } + if len(csr.IPAddresses) != 1 { + t.Errorf("Wanted 1 IP address in the result, got %d", len(csr.IPAddresses)) + } else if csr.IPAddresses[0].String() != ipSANs[0].String() { + t.Errorf("Wanted %v, got %v", ipSANs[0], csr.IPAddresses[0]) + } +} diff --git a/vendor/k8s.io/client-go/util/cert/pem_test.go b/vendor/k8s.io/client-go/util/cert/pem_test.go new file mode 100644 index 000000000..de3ce5253 --- /dev/null +++ b/vendor/k8s.io/client-go/util/cert/pem_test.go @@ -0,0 +1,197 @@ +/* +Copyright 2014 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 cert + +import ( + "io/ioutil" + "os" + "testing" +) + +const ( + // rsaPrivateKey is a RSA Private Key in PKCS#1 format + // openssl genrsa -out rsa2048.pem 2048 + rsaPrivateKey = `-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA92mVjhBKOFsdxFzb/Pjq+7b5TJlODAdY5hK+WxLZTIrfhDPq +FWrGKdjSNiHbXrdEtwJh9V+RqPZVSN3aWy1224RgkyNdMJsXhJKuCC24ZKY8SXtW +xuTYmMRaMnCsv6QBGRTIbZ2EFbAObVM7lDyv1VqY3amZIWFQMlZ9CNpxDSPa5yi4 +3gopbXkne0oGNmey9X0qtpk7NMZIgAL6Zz4rZ30bcfC2ag6RLOFI2E/c4n8c38R8 +9MfXfLkj8/Cxo4JfI9NvRCpPOpFO8d/ZtWVUuIrBQN+Y7tkN2T60Qq/TkKXUrhDe +fwlTlktZVJ/GztLYU41b2GcWsh/XO+PH831rmwIDAQABAoIBAQCC9c6GDjVbM0/E +WurPMusfJjE7zII1d8YkspM0HfwLug6qKdikUYpnKC/NG4rEzfl/bbFwco/lgc6O +7W/hh2U8uQttlvCDA/Uk5YddKOZL0Hpk4vaB/SxxYK3luSKXpjY2knutGg2KdVCN +qdsFkkH4iyYTXuyBcMNEgedZQldI/kEujIH/L7FE+DF5TMzT4lHhozDoG+fy564q +qVGUZXJn0ubc3GaPn2QOLNNM44sfYA4UJCpKBXPu85bvNObjxVQO4WqwwxU1vRnL +UUsaGaelhSVJCo0dVPRvrfPPKZ09HTwpy40EkgQo6VriFc1EBoQDjENLbAJv9OfQ +aCc9wiZhAoGBAP/8oEy48Zbb0P8Vdy4djf5tfBW8yXFLWzXewJ4l3itKS1r42nbX +9q3cJsgRTQm8uRcMIpWxsc3n6zG+lREvTkoTB3ViI7+uQPiqA+BtWyNy7jzufFke +ONKZfg7QxxmYRWZBRnoNGNbMpNeERuLmhvQuom9D1WbhzAYJbfs/O4WTAoGBAPds +2FNDU0gaesFDdkIUGq1nIJqRQDW485LXZm4pFqBFxdOpbdWRuYT2XZjd3fD0XY98 +Nhkpb7NTMCuK3BdKcqIptt+cK+quQgYid0hhhgZbpCQ5AL6c6KgyjgpYlh2enzU9 +Zo3yg8ej1zbbA11sBlhX+5iO2P1u5DG+JHLwUUbZAoGAUwaU102EzfEtsA4+QW7E +hyjrfgFlNKHES4yb3K9bh57pIfBkqvcQwwMMcQdrfSUAw0DkVrjzel0mI1Q09QXq +1ould6UFAz55RC2gZEITtUOpkYmoOx9aPrQZ9qQwb1S77ZZuTVfCHqjxLhVxCFbM +npYhiQTvShciHTMhwMOZgpECgYAVV5EtVXBYltgh1YTc3EkUzgF087R7LdHsx6Gx +POATwRD4WfP8aQ58lpeqOPEM+LcdSlSMRRO6fyF3kAm+BJDwxfJdRWZQXumZB94M +I0VhRQRaj4Qt7PDwmTPBVrTUJzuKZxpyggm17b8Bn1Ch/VBqzGQKW8AB1E/grosM +UwhfuQKBgQC2JO/iqTQScHClf0qlItCJsBuVukFmSAVCkpOD8YdbdlPdOOwSk1wQ +C0eAlsC3BCMvkpidKQmra6IqIrvTGI6EFgkrb3aknWdup2w8j2udYCNqyE3W+fVe +p8FdYQ1FkACQ+daO5VlClL/9l0sGjKXlNKbpmJ2H4ngZmXj5uGmxuQ== +-----END RSA PRIVATE KEY-----` + + // rsaPublicKey is a RSA Public Key in PEM encoded format + // openssl rsa -in rsa2048.pem -pubout -out rsa2048pub.pem + rsaPublicKey = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA92mVjhBKOFsdxFzb/Pjq ++7b5TJlODAdY5hK+WxLZTIrfhDPqFWrGKdjSNiHbXrdEtwJh9V+RqPZVSN3aWy12 +24RgkyNdMJsXhJKuCC24ZKY8SXtWxuTYmMRaMnCsv6QBGRTIbZ2EFbAObVM7lDyv +1VqY3amZIWFQMlZ9CNpxDSPa5yi43gopbXkne0oGNmey9X0qtpk7NMZIgAL6Zz4r +Z30bcfC2ag6RLOFI2E/c4n8c38R89MfXfLkj8/Cxo4JfI9NvRCpPOpFO8d/ZtWVU +uIrBQN+Y7tkN2T60Qq/TkKXUrhDefwlTlktZVJ/GztLYU41b2GcWsh/XO+PH831r +mwIDAQAB +-----END PUBLIC KEY-----` + + // certificate is an x509 certificate in PEM encoded format + // openssl req -new -key rsa2048.pem -sha256 -nodes -x509 -days 1826 -out x509certificate.pem -subj "/C=US/CN=not-valid" + certificate = `-----BEGIN CERTIFICATE----- +MIIDFTCCAf2gAwIBAgIJAN8B8NOwtiUCMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV +BAYTAlVTMRIwEAYDVQQDDAlub3QtdmFsaWQwHhcNMTcwMzIyMDI1NjM2WhcNMjIw +MzIyMDI1NjM2WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAwwJbm90LXZhbGlkMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA92mVjhBKOFsdxFzb/Pjq+7b5 +TJlODAdY5hK+WxLZTIrfhDPqFWrGKdjSNiHbXrdEtwJh9V+RqPZVSN3aWy1224Rg +kyNdMJsXhJKuCC24ZKY8SXtWxuTYmMRaMnCsv6QBGRTIbZ2EFbAObVM7lDyv1VqY +3amZIWFQMlZ9CNpxDSPa5yi43gopbXkne0oGNmey9X0qtpk7NMZIgAL6Zz4rZ30b +cfC2ag6RLOFI2E/c4n8c38R89MfXfLkj8/Cxo4JfI9NvRCpPOpFO8d/ZtWVUuIrB +QN+Y7tkN2T60Qq/TkKXUrhDefwlTlktZVJ/GztLYU41b2GcWsh/XO+PH831rmwID +AQABo1AwTjAdBgNVHQ4EFgQU1I5GfinLF7ta+dBJ6UWcrYaexLswHwYDVR0jBBgw +FoAU1I5GfinLF7ta+dBJ6UWcrYaexLswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAUl0wUD4y41juHFOVMYiziPYr1ShSpQXdwp8FfaHrzI5hsr8UMe8D +dzb9QzZ4bx3yZhiG3ahrSBh956thMTHrKTEwAfJIEXI4cuSVWQAaOJ4Em5SDFxQe +d0E6Ui2nGh1SFGF7oyuEXyzqgRMWFNDFw9HLUNgXaO18Zfouw8+K0BgbfEWEcSi1 +JLQbyhCjz088gltrliQGPWDFAg9cHBKtJhuTzZkvuqK1CLEmBhtzP1zFiGBfOJc8 +v+aKjAwrPUNX11cXOCPxBv2qXMetxaovBem6AI2hvypCInXaVQfP+yOLubzlTDjS +Y708SlY38hmS1uTwDpyLOn8AKkZ8jtx75g== +-----END CERTIFICATE-----` + + // ecdsaPrivateKeyWithParams is a ECDSA Private Key with included EC Parameters block + // openssl ecparam -name prime256v1 -genkey -out ecdsa256params.pem + ecdsaPrivateKeyWithParams = `-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIAwSOWQqlMTZNqNF7tgua812Jxib1DVOgb2pHHyIEyNNoAoGCCqGSM49 +AwEHoUQDQgAEyxYNrs6a6tsNCFNYn+l+JDUZ0PnUZbcsDgJn2O62D1se8M5iQ5rY +iIv6RpxE3VHvlHEIvYgCZkG0jHszTUopBg== +-----END EC PRIVATE KEY-----` + + // ecdsaPrivateKey is a ECDSA Private Key in ASN.1 format + // openssl ecparam -name prime256v1 -genkey -noout -out ecdsa256.pem + ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIP6Qw6dHDiLsSnLXUhQVTPE0fTQQrj3XSbiQAZPXnk5+oAoGCCqGSM49 +AwEHoUQDQgAEZZzi1u5f2/AEGFI/HYUhU+u6cTK1q2bbtE7r1JMK+/sQA5sNAp+7 +Vdc3psr1OaNzyTyuhTECyRdFKXm63cMnGg== +-----END EC PRIVATE KEY-----` + + // ecdsaPublicKey is a ECDSA Public Key in PEM encoded format + // openssl ec -in ecdsa256.pem -pubout -out ecdsa256pub.pem + ecdsaPublicKey = `-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZZzi1u5f2/AEGFI/HYUhU+u6cTK1 +q2bbtE7r1JMK+/sQA5sNAp+7Vdc3psr1OaNzyTyuhTECyRdFKXm63cMnGg== +-----END PUBLIC KEY-----` +) + +func TestReadPrivateKey(t *testing.T) { + f, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("error creating tmpfile: %v", err) + } + defer os.Remove(f.Name()) + + if _, err := PrivateKeyFromFile(f.Name()); err == nil { + t.Fatalf("Expected error reading key from empty file, got none") + } + + if err := ioutil.WriteFile(f.Name(), []byte(rsaPrivateKey), os.FileMode(0600)); err != nil { + t.Fatalf("error writing private key to tmpfile: %v", err) + } + if _, err := PrivateKeyFromFile(f.Name()); err != nil { + t.Fatalf("error reading private RSA key: %v", err) + } + + if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPrivateKey), os.FileMode(0600)); err != nil { + t.Fatalf("error writing private key to tmpfile: %v", err) + } + if _, err := PrivateKeyFromFile(f.Name()); err != nil { + t.Fatalf("error reading private ECDSA key: %v", err) + } + + if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPrivateKeyWithParams), os.FileMode(0600)); err != nil { + t.Fatalf("error writing private key to tmpfile: %v", err) + } + if _, err := PrivateKeyFromFile(f.Name()); err != nil { + t.Fatalf("error reading private ECDSA key with params: %v", err) + } +} + +func TestReadPublicKeys(t *testing.T) { + f, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("error creating tmpfile: %v", err) + } + defer os.Remove(f.Name()) + + if _, err := PublicKeysFromFile(f.Name()); err == nil { + t.Fatalf("Expected error reading keys from empty file, got none") + } + + if err := ioutil.WriteFile(f.Name(), []byte(rsaPublicKey), os.FileMode(0600)); err != nil { + t.Fatalf("error writing public key to tmpfile: %v", err) + } + if keys, err := PublicKeysFromFile(f.Name()); err != nil { + t.Fatalf("error reading RSA public key: %v", err) + } else if len(keys) != 1 { + t.Fatalf("expected 1 key, got %d", len(keys)) + } + + if err := ioutil.WriteFile(f.Name(), []byte(ecdsaPublicKey), os.FileMode(0600)); err != nil { + t.Fatalf("error writing public key to tmpfile: %v", err) + } + if keys, err := PublicKeysFromFile(f.Name()); err != nil { + t.Fatalf("error reading ECDSA public key: %v", err) + } else if len(keys) != 1 { + t.Fatalf("expected 1 key, got %d", len(keys)) + } + + if err := ioutil.WriteFile(f.Name(), []byte(rsaPublicKey+"\n"+ecdsaPublicKey), os.FileMode(0600)); err != nil { + t.Fatalf("error writing public key to tmpfile: %v", err) + } + if keys, err := PublicKeysFromFile(f.Name()); err != nil { + t.Fatalf("error reading combined RSA/ECDSA public key file: %v", err) + } else if len(keys) != 2 { + t.Fatalf("expected 2 keys, got %d", len(keys)) + } + + if err := ioutil.WriteFile(f.Name(), []byte(certificate), os.FileMode(0600)); err != nil { + t.Fatalf("error writing certificate to tmpfile: %v", err) + } + if keys, err := PublicKeysFromFile(f.Name()); err != nil { + t.Fatalf("error reading public key from certificate file: %v", err) + } else if len(keys) != 1 { + t.Fatalf("expected 1 keys, got %d", len(keys)) + } + +} diff --git a/vendor/k8s.io/client-go/util/connrotation/connrotation_test.go b/vendor/k8s.io/client-go/util/connrotation/connrotation_test.go new file mode 100644 index 000000000..a618f2961 --- /dev/null +++ b/vendor/k8s.io/client-go/util/connrotation/connrotation_test.go @@ -0,0 +1,61 @@ +/* +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. +*/ + +package connrotation + +import ( + "context" + "net" + "testing" + "time" +) + +func TestCloseAll(t *testing.T) { + closed := make(chan struct{}) + dialFn := func(ctx context.Context, network, address string) (net.Conn, error) { + return closeOnlyConn{onClose: func() { closed <- struct{}{} }}, nil + } + dialer := NewDialer(dialFn) + + const numConns = 10 + + // Outer loop to ensure Dialer is re-usable after CloseAll. + for i := 0; i < 5; i++ { + for j := 0; j < numConns; j++ { + if _, err := dialer.Dial("", ""); err != nil { + t.Fatal(err) + } + } + dialer.CloseAll() + for j := 0; j < numConns; j++ { + select { + case <-closed: + case <-time.After(time.Second): + t.Fatalf("iteration %d: 1s after CloseAll only %d/%d connections closed", i, j, numConns) + } + } + } +} + +type closeOnlyConn struct { + net.Conn + onClose func() +} + +func (c closeOnlyConn) Close() error { + go c.onClose() + return nil +} diff --git a/vendor/k8s.io/client-go/util/flowcontrol/backoff_test.go b/vendor/k8s.io/client-go/util/flowcontrol/backoff_test.go new file mode 100644 index 000000000..b14ab341b --- /dev/null +++ b/vendor/k8s.io/client-go/util/flowcontrol/backoff_test.go @@ -0,0 +1,195 @@ +/* +Copyright 2015 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 flowcontrol + +import ( + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/clock" +) + +func TestSlowBackoff(t *testing.T) { + id := "_idSlow" + tc := clock.NewFakeClock(time.Now()) + step := time.Second + maxDuration := 50 * step + + b := NewFakeBackOff(step, maxDuration, tc) + cases := []time.Duration{0, 1, 2, 4, 8, 16, 32, 50, 50, 50} + for ix, c := range cases { + tc.Step(step) + w := b.Get(id) + if w != c*step { + t.Errorf("input: '%d': expected %s, got %s", ix, c*step, w) + } + b.Next(id, tc.Now()) + } + + //Now confirm that the Reset cancels backoff. + b.Next(id, tc.Now()) + b.Reset(id) + if b.Get(id) != 0 { + t.Errorf("Reset didn't clear the backoff.") + } + +} + +func TestBackoffReset(t *testing.T) { + id := "_idReset" + tc := clock.NewFakeClock(time.Now()) + step := time.Second + maxDuration := step * 5 + b := NewFakeBackOff(step, maxDuration, tc) + startTime := tc.Now() + + // get to backoff = maxDuration + for i := 0; i <= int(maxDuration/step); i++ { + tc.Step(step) + b.Next(id, tc.Now()) + } + + // backoff should be capped at maxDuration + if !b.IsInBackOffSince(id, tc.Now()) { + t.Errorf("expected to be in Backoff got %s", b.Get(id)) + } + + lastUpdate := tc.Now() + tc.Step(2*maxDuration + step) // time += 11s, 11 > 2*maxDuration + if b.IsInBackOffSince(id, lastUpdate) { + t.Errorf("expected to not be in Backoff after reset (start=%s, now=%s, lastUpdate=%s), got %s", startTime, tc.Now(), lastUpdate, b.Get(id)) + } +} + +func TestBackoffHighWaterMark(t *testing.T) { + id := "_idHiWaterMark" + tc := clock.NewFakeClock(time.Now()) + step := time.Second + maxDuration := 5 * step + b := NewFakeBackOff(step, maxDuration, tc) + + // get to backoff = maxDuration + for i := 0; i <= int(maxDuration/step); i++ { + tc.Step(step) + b.Next(id, tc.Now()) + } + + // backoff high watermark expires after 2*maxDuration + tc.Step(maxDuration + step) + b.Next(id, tc.Now()) + + if b.Get(id) != maxDuration { + t.Errorf("expected Backoff to stay at high watermark %s got %s", maxDuration, b.Get(id)) + } +} + +func TestBackoffGC(t *testing.T) { + id := "_idGC" + tc := clock.NewFakeClock(time.Now()) + step := time.Second + maxDuration := 5 * step + + b := NewFakeBackOff(step, maxDuration, tc) + + for i := 0; i <= int(maxDuration/step); i++ { + tc.Step(step) + b.Next(id, tc.Now()) + } + lastUpdate := tc.Now() + tc.Step(maxDuration + step) + b.GC() + _, found := b.perItemBackoff[id] + if !found { + t.Errorf("expected GC to skip entry, elapsed time=%s maxDuration=%s", tc.Now().Sub(lastUpdate), maxDuration) + } + + tc.Step(maxDuration + step) + b.GC() + r, found := b.perItemBackoff[id] + if found { + t.Errorf("expected GC of entry after %s got entry %v", tc.Now().Sub(lastUpdate), r) + } +} + +func TestIsInBackOffSinceUpdate(t *testing.T) { + id := "_idIsInBackOffSinceUpdate" + tc := clock.NewFakeClock(time.Now()) + step := time.Second + maxDuration := 10 * step + b := NewFakeBackOff(step, maxDuration, tc) + startTime := tc.Now() + + cases := []struct { + tick time.Duration + inBackOff bool + value int + }{ + {tick: 0, inBackOff: false, value: 0}, + {tick: 1, inBackOff: false, value: 1}, + {tick: 2, inBackOff: true, value: 2}, + {tick: 3, inBackOff: false, value: 2}, + {tick: 4, inBackOff: true, value: 4}, + {tick: 5, inBackOff: true, value: 4}, + {tick: 6, inBackOff: true, value: 4}, + {tick: 7, inBackOff: false, value: 4}, + {tick: 8, inBackOff: true, value: 8}, + {tick: 9, inBackOff: true, value: 8}, + {tick: 10, inBackOff: true, value: 8}, + {tick: 11, inBackOff: true, value: 8}, + {tick: 12, inBackOff: true, value: 8}, + {tick: 13, inBackOff: true, value: 8}, + {tick: 14, inBackOff: true, value: 8}, + {tick: 15, inBackOff: false, value: 8}, + {tick: 16, inBackOff: true, value: 10}, + {tick: 17, inBackOff: true, value: 10}, + {tick: 18, inBackOff: true, value: 10}, + {tick: 19, inBackOff: true, value: 10}, + {tick: 20, inBackOff: true, value: 10}, + {tick: 21, inBackOff: true, value: 10}, + {tick: 22, inBackOff: true, value: 10}, + {tick: 23, inBackOff: true, value: 10}, + {tick: 24, inBackOff: true, value: 10}, + {tick: 25, inBackOff: false, value: 10}, + {tick: 26, inBackOff: true, value: 10}, + {tick: 27, inBackOff: true, value: 10}, + {tick: 28, inBackOff: true, value: 10}, + {tick: 29, inBackOff: true, value: 10}, + {tick: 30, inBackOff: true, value: 10}, + {tick: 31, inBackOff: true, value: 10}, + {tick: 32, inBackOff: true, value: 10}, + {tick: 33, inBackOff: true, value: 10}, + {tick: 34, inBackOff: true, value: 10}, + {tick: 35, inBackOff: false, value: 10}, + {tick: 56, inBackOff: false, value: 0}, + {tick: 57, inBackOff: false, value: 1}, + } + + for _, c := range cases { + tc.SetTime(startTime.Add(c.tick * step)) + if c.inBackOff != b.IsInBackOffSinceUpdate(id, tc.Now()) { + t.Errorf("expected IsInBackOffSinceUpdate %v got %v at tick %s", c.inBackOff, b.IsInBackOffSinceUpdate(id, tc.Now()), c.tick*step) + } + + if c.inBackOff && (time.Duration(c.value)*step != b.Get(id)) { + t.Errorf("expected backoff value=%s got %s at tick %s", time.Duration(c.value)*step, b.Get(id), c.tick*step) + } + + if !c.inBackOff { + b.Next(id, tc.Now()) + } + } +} diff --git a/vendor/k8s.io/client-go/util/flowcontrol/throttle_test.go b/vendor/k8s.io/client-go/util/flowcontrol/throttle_test.go new file mode 100644 index 000000000..99cf64d64 --- /dev/null +++ b/vendor/k8s.io/client-go/util/flowcontrol/throttle_test.go @@ -0,0 +1,153 @@ +/* +Copyright 2014 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 flowcontrol + +import ( + "sync" + "testing" + "time" +) + +func TestMultithreadedThrottling(t *testing.T) { + // Bucket with 100QPS and no burst + r := NewTokenBucketRateLimiter(100, 1) + + // channel to collect 100 tokens + taken := make(chan bool, 100) + + // Set up goroutines to hammer the throttler + startCh := make(chan bool) + endCh := make(chan bool) + for i := 0; i < 10; i++ { + go func() { + // wait for the starting signal + <-startCh + for { + // get a token + r.Accept() + select { + // try to add it to the taken channel + case taken <- true: + continue + // if taken is full, notify and return + default: + endCh <- true + return + } + } + }() + } + + // record wall time + startTime := time.Now() + // take the initial capacity so all tokens are the result of refill + r.Accept() + // start the thundering herd + close(startCh) + // wait for the first signal that we collected 100 tokens + <-endCh + // record wall time + endTime := time.Now() + + // tolerate a 1% clock change because these things happen + if duration := endTime.Sub(startTime); duration < (time.Second * 99 / 100) { + // We shouldn't be able to get 100 tokens out of the bucket in less than 1 second of wall clock time, no matter what + t.Errorf("Expected it to take at least 1 second to get 100 tokens, took %v", duration) + } else { + t.Logf("Took %v to get 100 tokens", duration) + } +} + +func TestBasicThrottle(t *testing.T) { + r := NewTokenBucketRateLimiter(1, 3) + for i := 0; i < 3; i++ { + if !r.TryAccept() { + t.Error("unexpected false accept") + } + } + if r.TryAccept() { + t.Error("unexpected true accept") + } +} + +func TestIncrementThrottle(t *testing.T) { + r := NewTokenBucketRateLimiter(1, 1) + if !r.TryAccept() { + t.Error("unexpected false accept") + } + if r.TryAccept() { + t.Error("unexpected true accept") + } + + // Allow to refill + time.Sleep(2 * time.Second) + + if !r.TryAccept() { + t.Error("unexpected false accept") + } +} + +func TestThrottle(t *testing.T) { + r := NewTokenBucketRateLimiter(10, 5) + + // Should consume 5 tokens immediately, then + // the remaining 11 should take at least 1 second (0.1s each) + expectedFinish := time.Now().Add(time.Second * 1) + for i := 0; i < 16; i++ { + r.Accept() + } + if time.Now().Before(expectedFinish) { + t.Error("rate limit was not respected, finished too early") + } +} + +func TestAlwaysFake(t *testing.T) { + rl := NewFakeAlwaysRateLimiter() + if !rl.TryAccept() { + t.Error("TryAccept in AlwaysFake should return true.") + } + // If this will block the test will timeout + rl.Accept() +} + +func TestNeverFake(t *testing.T) { + rl := NewFakeNeverRateLimiter() + if rl.TryAccept() { + t.Error("TryAccept in NeverFake should return false.") + } + + finished := false + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + rl.Accept() + finished = true + wg.Done() + }() + + // Wait some time to make sure it never finished. + time.Sleep(time.Second) + if finished { + t.Error("Accept should block forever in NeverFake.") + } + + rl.Stop() + wg.Wait() + if !finished { + t.Error("Stop should make Accept unblock in NeverFake.") + } +} diff --git a/vendor/k8s.io/client-go/util/integer/integer_test.go b/vendor/k8s.io/client-go/util/integer/integer_test.go new file mode 100644 index 000000000..e9f586888 --- /dev/null +++ b/vendor/k8s.io/client-go/util/integer/integer_test.go @@ -0,0 +1,244 @@ +/* +Copyright 2016 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 integer + +import "testing" + +func TestIntMax(t *testing.T) { + tests := []struct { + nums []int + expectedMax int + }{ + { + nums: []int{-1, 0}, + expectedMax: 0, + }, + { + nums: []int{-1, -2}, + expectedMax: -1, + }, + { + nums: []int{0, 1}, + expectedMax: 1, + }, + { + nums: []int{1, 2}, + expectedMax: 2, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if max := IntMax(test.nums[0], test.nums[1]); max != test.expectedMax { + t.Errorf("expected %v, got %v", test.expectedMax, max) + } + } +} + +func TestIntMin(t *testing.T) { + tests := []struct { + nums []int + expectedMin int + }{ + { + nums: []int{-1, 0}, + expectedMin: -1, + }, + { + nums: []int{-1, -2}, + expectedMin: -2, + }, + { + nums: []int{0, 1}, + expectedMin: 0, + }, + { + nums: []int{1, 2}, + expectedMin: 1, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if min := IntMin(test.nums[0], test.nums[1]); min != test.expectedMin { + t.Errorf("expected %v, got %v", test.expectedMin, min) + } + } +} + +func TestInt32Max(t *testing.T) { + tests := []struct { + nums []int32 + expectedMax int32 + }{ + { + nums: []int32{-1, 0}, + expectedMax: 0, + }, + { + nums: []int32{-1, -2}, + expectedMax: -1, + }, + { + nums: []int32{0, 1}, + expectedMax: 1, + }, + { + nums: []int32{1, 2}, + expectedMax: 2, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if max := Int32Max(test.nums[0], test.nums[1]); max != test.expectedMax { + t.Errorf("expected %v, got %v", test.expectedMax, max) + } + } +} + +func TestInt32Min(t *testing.T) { + tests := []struct { + nums []int32 + expectedMin int32 + }{ + { + nums: []int32{-1, 0}, + expectedMin: -1, + }, + { + nums: []int32{-1, -2}, + expectedMin: -2, + }, + { + nums: []int32{0, 1}, + expectedMin: 0, + }, + { + nums: []int32{1, 2}, + expectedMin: 1, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if min := Int32Min(test.nums[0], test.nums[1]); min != test.expectedMin { + t.Errorf("expected %v, got %v", test.expectedMin, min) + } + } +} + +func TestInt64Max(t *testing.T) { + tests := []struct { + nums []int64 + expectedMax int64 + }{ + { + nums: []int64{-1, 0}, + expectedMax: 0, + }, + { + nums: []int64{-1, -2}, + expectedMax: -1, + }, + { + nums: []int64{0, 1}, + expectedMax: 1, + }, + { + nums: []int64{1, 2}, + expectedMax: 2, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if max := Int64Max(test.nums[0], test.nums[1]); max != test.expectedMax { + t.Errorf("expected %v, got %v", test.expectedMax, max) + } + } +} + +func TestInt64Min(t *testing.T) { + tests := []struct { + nums []int64 + expectedMin int64 + }{ + { + nums: []int64{-1, 0}, + expectedMin: -1, + }, + { + nums: []int64{-1, -2}, + expectedMin: -2, + }, + { + nums: []int64{0, 1}, + expectedMin: 0, + }, + { + nums: []int64{1, 2}, + expectedMin: 1, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if min := Int64Min(test.nums[0], test.nums[1]); min != test.expectedMin { + t.Errorf("expected %v, got %v", test.expectedMin, min) + } + } +} + +func TestRoundToInt32(t *testing.T) { + tests := []struct { + num float64 + exp int32 + }{ + { + num: 5.5, + exp: 6, + }, + { + num: -3.7, + exp: -4, + }, + { + num: 3.49, + exp: 3, + }, + { + num: -7.9, + exp: -8, + }, + { + num: -4.499999, + exp: -4, + }, + { + num: 0, + exp: 0, + }, + } + + for i, test := range tests { + t.Logf("executing scenario %d", i) + if got := RoundToInt32(test.num); got != test.exp { + t.Errorf("expected %d, got %d", test.exp, got) + } + } +} diff --git a/vendor/k8s.io/client-go/util/retry/OWNERS b/vendor/k8s.io/client-go/util/retry/OWNERS new file mode 100755 index 000000000..a4c1c2d4f --- /dev/null +++ b/vendor/k8s.io/client-go/util/retry/OWNERS @@ -0,0 +1,2 @@ +reviewers: +- caesarxuchao diff --git a/vendor/k8s.io/client-go/util/retry/util_test.go b/vendor/k8s.io/client-go/util/retry/util_test.go new file mode 100644 index 000000000..dbb4374fe --- /dev/null +++ b/vendor/k8s.io/client-go/util/retry/util_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2016 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 retry + +import ( + "fmt" + "testing" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/wait" +) + +func TestRetryOnConflict(t *testing.T) { + opts := wait.Backoff{Factor: 1.0, Steps: 3} + conflictErr := errors.NewConflict(schema.GroupResource{Resource: "test"}, "other", nil) + + // never returns + err := RetryOnConflict(opts, func() error { + return conflictErr + }) + if err != conflictErr { + t.Errorf("unexpected error: %v", err) + } + + // returns immediately + i := 0 + err = RetryOnConflict(opts, func() error { + i++ + return nil + }) + if err != nil || i != 1 { + t.Errorf("unexpected error: %v", err) + } + + // returns immediately on error + testErr := fmt.Errorf("some other error") + err = RetryOnConflict(opts, func() error { + return testErr + }) + if err != testErr { + t.Errorf("unexpected error: %v", err) + } + + // keeps retrying + i = 0 + err = RetryOnConflict(opts, func() error { + if i < 2 { + i++ + return errors.NewConflict(schema.GroupResource{Resource: "test"}, "other", nil) + } + return nil + }) + if err != nil || i != 2 { + t.Errorf("unexpected error: %v", err) + } +} diff --git a/vendor/k8s.io/client-go/util/workqueue/default_rate_limiters_test.go b/vendor/k8s.io/client-go/util/workqueue/default_rate_limiters_test.go new file mode 100644 index 000000000..91d34a317 --- /dev/null +++ b/vendor/k8s.io/client-go/util/workqueue/default_rate_limiters_test.go @@ -0,0 +1,184 @@ +/* +Copyright 2016 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 workqueue + +import ( + "testing" + "time" +) + +func TestItemExponentialFailureRateLimiter(t *testing.T) { + limiter := NewItemExponentialFailureRateLimiter(1*time.Millisecond, 1*time.Second) + + if e, a := 1*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 2*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 4*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 8*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 16*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5, limiter.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + if e, a := 1*time.Millisecond, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 2*time.Millisecond, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 2, limiter.NumRequeues("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + limiter.Forget("one") + if e, a := 0, limiter.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 1*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + +} + +func TestItemExponentialFailureRateLimiterOverFlow(t *testing.T) { + limiter := NewItemExponentialFailureRateLimiter(1*time.Millisecond, 1000*time.Second) + for i := 0; i < 5; i++ { + limiter.When("one") + } + if e, a := 32*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + for i := 0; i < 1000; i++ { + limiter.When("overflow1") + } + if e, a := 1000*time.Second, limiter.When("overflow1"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + limiter = NewItemExponentialFailureRateLimiter(1*time.Minute, 1000*time.Hour) + for i := 0; i < 2; i++ { + limiter.When("two") + } + if e, a := 4*time.Minute, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + for i := 0; i < 1000; i++ { + limiter.When("overflow2") + } + if e, a := 1000*time.Hour, limiter.When("overflow2"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + +} + +func TestItemFastSlowRateLimiter(t *testing.T) { + limiter := NewItemFastSlowRateLimiter(5*time.Millisecond, 10*time.Second, 3) + + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 10*time.Second, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 10*time.Second, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5, limiter.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + if e, a := 5*time.Millisecond, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 2, limiter.NumRequeues("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + limiter.Forget("one") + if e, a := 0, limiter.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + +} + +func TestMaxOfRateLimiter(t *testing.T) { + limiter := NewMaxOfRateLimiter( + NewItemFastSlowRateLimiter(5*time.Millisecond, 3*time.Second, 3), + NewItemExponentialFailureRateLimiter(1*time.Millisecond, 1*time.Second), + ) + + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 3*time.Second, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 3*time.Second, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5, limiter.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + if e, a := 5*time.Millisecond, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 2, limiter.NumRequeues("two"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + limiter.Forget("one") + if e, a := 0, limiter.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 5*time.Millisecond, limiter.When("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + +} diff --git a/vendor/k8s.io/client-go/util/workqueue/delaying_queue_test.go b/vendor/k8s.io/client-go/util/workqueue/delaying_queue_test.go new file mode 100644 index 000000000..3c8ebf13a --- /dev/null +++ b/vendor/k8s.io/client-go/util/workqueue/delaying_queue_test.go @@ -0,0 +1,255 @@ +/* +Copyright 2016 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 workqueue + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/apimachinery/pkg/util/wait" +) + +func TestSimpleQueue(t *testing.T) { + fakeClock := clock.NewFakeClock(time.Now()) + q := newDelayingQueue(fakeClock, "") + + first := "foo" + + q.AddAfter(first, 50*time.Millisecond) + if err := waitForWaitingQueueToFill(q); err != nil { + t.Fatalf("unexpected err: %v", err) + } + + if q.Len() != 0 { + t.Errorf("should not have added") + } + + fakeClock.Step(60 * time.Millisecond) + + if err := waitForAdded(q, 1); err != nil { + t.Errorf("should have added") + } + item, _ := q.Get() + q.Done(item) + + // step past the next heartbeat + fakeClock.Step(10 * time.Second) + + err := wait.Poll(1*time.Millisecond, 30*time.Millisecond, func() (done bool, err error) { + if q.Len() > 0 { + return false, fmt.Errorf("added to queue") + } + + return false, nil + }) + if err != wait.ErrWaitTimeout { + t.Errorf("expected timeout, got: %v", err) + } + + if q.Len() != 0 { + t.Errorf("should not have added") + } +} + +func TestDeduping(t *testing.T) { + fakeClock := clock.NewFakeClock(time.Now()) + q := newDelayingQueue(fakeClock, "") + + first := "foo" + + q.AddAfter(first, 50*time.Millisecond) + if err := waitForWaitingQueueToFill(q); err != nil { + t.Fatalf("unexpected err: %v", err) + } + q.AddAfter(first, 70*time.Millisecond) + if err := waitForWaitingQueueToFill(q); err != nil { + t.Fatalf("unexpected err: %v", err) + } + if q.Len() != 0 { + t.Errorf("should not have added") + } + + // step past the first block, we should receive now + fakeClock.Step(60 * time.Millisecond) + if err := waitForAdded(q, 1); err != nil { + t.Errorf("should have added") + } + item, _ := q.Get() + q.Done(item) + + // step past the second add + fakeClock.Step(20 * time.Millisecond) + if q.Len() != 0 { + t.Errorf("should not have added") + } + + // test again, but this time the earlier should override + q.AddAfter(first, 50*time.Millisecond) + q.AddAfter(first, 30*time.Millisecond) + if err := waitForWaitingQueueToFill(q); err != nil { + t.Fatalf("unexpected err: %v", err) + } + if q.Len() != 0 { + t.Errorf("should not have added") + } + + fakeClock.Step(40 * time.Millisecond) + if err := waitForAdded(q, 1); err != nil { + t.Errorf("should have added") + } + item, _ = q.Get() + q.Done(item) + + // step past the second add + fakeClock.Step(20 * time.Millisecond) + if q.Len() != 0 { + t.Errorf("should not have added") + } + if q.Len() != 0 { + t.Errorf("should not have added") + } +} + +func TestAddTwoFireEarly(t *testing.T) { + fakeClock := clock.NewFakeClock(time.Now()) + q := newDelayingQueue(fakeClock, "") + + first := "foo" + second := "bar" + third := "baz" + + q.AddAfter(first, 1*time.Second) + q.AddAfter(second, 50*time.Millisecond) + if err := waitForWaitingQueueToFill(q); err != nil { + t.Fatalf("unexpected err: %v", err) + } + + if q.Len() != 0 { + t.Errorf("should not have added") + } + + fakeClock.Step(60 * time.Millisecond) + + if err := waitForAdded(q, 1); err != nil { + t.Fatalf("unexpected err: %v", err) + } + item, _ := q.Get() + if !reflect.DeepEqual(item, second) { + t.Errorf("expected %v, got %v", second, item) + } + + q.AddAfter(third, 2*time.Second) + + fakeClock.Step(1 * time.Second) + if err := waitForAdded(q, 1); err != nil { + t.Fatalf("unexpected err: %v", err) + } + item, _ = q.Get() + if !reflect.DeepEqual(item, first) { + t.Errorf("expected %v, got %v", first, item) + } + + fakeClock.Step(2 * time.Second) + if err := waitForAdded(q, 1); err != nil { + t.Fatalf("unexpected err: %v", err) + } + item, _ = q.Get() + if !reflect.DeepEqual(item, third) { + t.Errorf("expected %v, got %v", third, item) + } +} + +func TestCopyShifting(t *testing.T) { + fakeClock := clock.NewFakeClock(time.Now()) + q := newDelayingQueue(fakeClock, "") + + first := "foo" + second := "bar" + third := "baz" + + q.AddAfter(first, 1*time.Second) + q.AddAfter(second, 500*time.Millisecond) + q.AddAfter(third, 250*time.Millisecond) + if err := waitForWaitingQueueToFill(q); err != nil { + t.Fatalf("unexpected err: %v", err) + } + + if q.Len() != 0 { + t.Errorf("should not have added") + } + + fakeClock.Step(2 * time.Second) + + if err := waitForAdded(q, 3); err != nil { + t.Fatalf("unexpected err: %v", err) + } + actualFirst, _ := q.Get() + if !reflect.DeepEqual(actualFirst, third) { + t.Errorf("expected %v, got %v", third, actualFirst) + } + actualSecond, _ := q.Get() + if !reflect.DeepEqual(actualSecond, second) { + t.Errorf("expected %v, got %v", second, actualSecond) + } + actualThird, _ := q.Get() + if !reflect.DeepEqual(actualThird, first) { + t.Errorf("expected %v, got %v", first, actualThird) + } +} + +func BenchmarkDelayingQueue_AddAfter(b *testing.B) { + r := rand.New(rand.NewSource(time.Now().Unix())) + + fakeClock := clock.NewFakeClock(time.Now()) + q := newDelayingQueue(fakeClock, "") + + // Add items + for n := 0; n < b.N; n++ { + data := fmt.Sprintf("%d", n) + q.AddAfter(data, time.Duration(r.Int63n(int64(10*time.Minute)))) + } + + // Exercise item removal as well + fakeClock.Step(11 * time.Minute) + for n := 0; n < b.N; n++ { + _, _ = q.Get() + } +} + +func waitForAdded(q DelayingInterface, depth int) error { + return wait.Poll(1*time.Millisecond, 10*time.Second, func() (done bool, err error) { + if q.Len() == depth { + return true, nil + } + + return false, nil + }) +} + +func waitForWaitingQueueToFill(q DelayingInterface) error { + return wait.Poll(1*time.Millisecond, 10*time.Second, func() (done bool, err error) { + if len(q.(*delayingType).waitingForAddCh) == 0 { + return true, nil + } + + return false, nil + }) +} diff --git a/vendor/k8s.io/client-go/util/workqueue/queue_test.go b/vendor/k8s.io/client-go/util/workqueue/queue_test.go new file mode 100644 index 000000000..131f4a2a5 --- /dev/null +++ b/vendor/k8s.io/client-go/util/workqueue/queue_test.go @@ -0,0 +1,161 @@ +/* +Copyright 2015 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 workqueue_test + +import ( + "sync" + "testing" + "time" + + "k8s.io/client-go/util/workqueue" +) + +func TestBasic(t *testing.T) { + // If something is seriously wrong this test will never complete. + q := workqueue.New() + + // Start producers + const producers = 50 + producerWG := sync.WaitGroup{} + producerWG.Add(producers) + for i := 0; i < producers; i++ { + go func(i int) { + defer producerWG.Done() + for j := 0; j < 50; j++ { + q.Add(i) + time.Sleep(time.Millisecond) + } + }(i) + } + + // Start consumers + const consumers = 10 + consumerWG := sync.WaitGroup{} + consumerWG.Add(consumers) + for i := 0; i < consumers; i++ { + go func(i int) { + defer consumerWG.Done() + for { + item, quit := q.Get() + if item == "added after shutdown!" { + t.Errorf("Got an item added after shutdown.") + } + if quit { + return + } + t.Logf("Worker %v: begin processing %v", i, item) + time.Sleep(3 * time.Millisecond) + t.Logf("Worker %v: done processing %v", i, item) + q.Done(item) + } + }(i) + } + + producerWG.Wait() + q.ShutDown() + q.Add("added after shutdown!") + consumerWG.Wait() +} + +func TestAddWhileProcessing(t *testing.T) { + q := workqueue.New() + + // Start producers + const producers = 50 + producerWG := sync.WaitGroup{} + producerWG.Add(producers) + for i := 0; i < producers; i++ { + go func(i int) { + defer producerWG.Done() + q.Add(i) + }(i) + } + + // Start consumers + const consumers = 10 + consumerWG := sync.WaitGroup{} + consumerWG.Add(consumers) + for i := 0; i < consumers; i++ { + go func(i int) { + defer consumerWG.Done() + // Every worker will re-add every item up to two times. + // This tests the dirty-while-processing case. + counters := map[interface{}]int{} + for { + item, quit := q.Get() + if quit { + return + } + counters[item]++ + if counters[item] < 2 { + q.Add(item) + } + q.Done(item) + } + }(i) + } + + producerWG.Wait() + q.ShutDown() + consumerWG.Wait() +} + +func TestLen(t *testing.T) { + q := workqueue.New() + q.Add("foo") + if e, a := 1, q.Len(); e != a { + t.Errorf("Expected %v, got %v", e, a) + } + q.Add("bar") + if e, a := 2, q.Len(); e != a { + t.Errorf("Expected %v, got %v", e, a) + } + q.Add("foo") // should not increase the queue length. + if e, a := 2, q.Len(); e != a { + t.Errorf("Expected %v, got %v", e, a) + } +} + +func TestReinsert(t *testing.T) { + q := workqueue.New() + q.Add("foo") + + // Start processing + i, _ := q.Get() + if i != "foo" { + t.Errorf("Expected %v, got %v", "foo", i) + } + + // Add it back while processing + q.Add(i) + + // Finish it up + q.Done(i) + + // It should be back on the queue + i, _ = q.Get() + if i != "foo" { + t.Errorf("Expected %v, got %v", "foo", i) + } + + // Finish that one up + q.Done(i) + + if a := q.Len(); a != 0 { + t.Errorf("Expected queue to be empty. Has %v items", a) + } +} diff --git a/vendor/k8s.io/client-go/util/workqueue/rate_limitting_queue_test.go b/vendor/k8s.io/client-go/util/workqueue/rate_limitting_queue_test.go new file mode 100644 index 000000000..3fbe07d0d --- /dev/null +++ b/vendor/k8s.io/client-go/util/workqueue/rate_limitting_queue_test.go @@ -0,0 +1,75 @@ +/* +Copyright 2016 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 workqueue + +import ( + "testing" + "time" + + "k8s.io/apimachinery/pkg/util/clock" +) + +func TestRateLimitingQueue(t *testing.T) { + limiter := NewItemExponentialFailureRateLimiter(1*time.Millisecond, 1*time.Second) + queue := NewRateLimitingQueue(limiter).(*rateLimitingType) + fakeClock := clock.NewFakeClock(time.Now()) + delayingQueue := &delayingType{ + Interface: New(), + clock: fakeClock, + heartbeat: fakeClock.NewTicker(maxWait), + stopCh: make(chan struct{}), + waitingForAddCh: make(chan *waitFor, 1000), + metrics: newRetryMetrics(""), + } + queue.DelayingInterface = delayingQueue + + queue.AddRateLimited("one") + waitEntry := <-delayingQueue.waitingForAddCh + if e, a := 1*time.Millisecond, waitEntry.readyAt.Sub(fakeClock.Now()); e != a { + t.Errorf("expected %v, got %v", e, a) + } + queue.AddRateLimited("one") + waitEntry = <-delayingQueue.waitingForAddCh + if e, a := 2*time.Millisecond, waitEntry.readyAt.Sub(fakeClock.Now()); e != a { + t.Errorf("expected %v, got %v", e, a) + } + if e, a := 2, queue.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + queue.AddRateLimited("two") + waitEntry = <-delayingQueue.waitingForAddCh + if e, a := 1*time.Millisecond, waitEntry.readyAt.Sub(fakeClock.Now()); e != a { + t.Errorf("expected %v, got %v", e, a) + } + queue.AddRateLimited("two") + waitEntry = <-delayingQueue.waitingForAddCh + if e, a := 2*time.Millisecond, waitEntry.readyAt.Sub(fakeClock.Now()); e != a { + t.Errorf("expected %v, got %v", e, a) + } + + queue.Forget("one") + if e, a := 0, queue.NumRequeues("one"); e != a { + t.Errorf("expected %v, got %v", e, a) + } + queue.AddRateLimited("one") + waitEntry = <-delayingQueue.waitingForAddCh + if e, a := 1*time.Millisecond, waitEntry.readyAt.Sub(fakeClock.Now()); e != a { + t.Errorf("expected %v, got %v", e, a) + } + +} diff --git a/vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md b/vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index e559c074b..000000000 --- a/vendor/k8s.io/code-generator/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,2 +0,0 @@ -Sorry, we do not accept changes directly against this repository. Please see -CONTRIBUTING.md for information on where and how to contribute instead. diff --git a/vendor/k8s.io/code-generator/Godeps/Godeps.json b/vendor/k8s.io/code-generator/Godeps/Godeps.json deleted file mode 100644 index affc13ced..000000000 --- a/vendor/k8s.io/code-generator/Godeps/Godeps.json +++ /dev/null @@ -1,282 +0,0 @@ -{ - "ImportPath": "k8s.io/code-generator", - "GoVersion": "go1.10", - "GodepVersion": "v80", - "Packages": [ - "./..." - ], - "Deps": [ - { - "ImportPath": "github.com/PuerkitoBio/purell", - "Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4" - }, - { - "ImportPath": "github.com/PuerkitoBio/urlesc", - "Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e" - }, - { - "ImportPath": "github.com/emicklei/go-restful", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/emicklei/go-restful/log", - "Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46" - }, - { - "ImportPath": "github.com/go-openapi/jsonpointer", - "Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98" - }, - { - "ImportPath": "github.com/go-openapi/jsonreference", - "Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272" - }, - { - "ImportPath": "github.com/go-openapi/spec", - "Rev": "1de3e0542de65ad8d75452a595886fdd0befb363" - }, - { - "ImportPath": "github.com/go-openapi/swag", - "Rev": "f3f9494671f93fcff853e3c6e9e948b3eb71e590" - }, - { - "ImportPath": "github.com/gogo/protobuf/gogoproto", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/compare", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/defaultcheck", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/description", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/embedcheck", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/enumstringer", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/equal", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/face", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/gostring", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/marshalto", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/oneofcheck", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/populate", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/size", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/stringer", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/testgen", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/union", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/plugin/unmarshal", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/proto", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/descriptor", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/generator", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/grpc", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/protoc-gen-gogo/plugin", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/sortkeys", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/vanity", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/gogo/protobuf/vanity/command", - "Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7" - }, - { - "ImportPath": "github.com/golang/glog", - "Rev": "44145f04b68cf362d9c4df2182967c2275eaefed" - }, - { - "ImportPath": "github.com/mailru/easyjson/buffer", - "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" - }, - { - "ImportPath": "github.com/mailru/easyjson/jlexer", - "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" - }, - { - "ImportPath": "github.com/mailru/easyjson/jwriter", - "Rev": "2f5df55504ebc322e4d52d34df6a1f5b503bf26d" - }, - { - "ImportPath": "github.com/spf13/pflag", - "Rev": "583c0c0531f06d5278b7d917446061adc344b5cd" - }, - { - "ImportPath": "golang.org/x/net/idna", - "Rev": "1c05540f6879653db88113bc4a2b70aec4bd491f" - }, - { - "ImportPath": "golang.org/x/text/cases", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/internal", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/internal/tag", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/language", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/runes", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/secure/bidirule", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/secure/precis", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/transform", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/unicode/bidi", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/unicode/norm", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/text/width", - "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" - }, - { - "ImportPath": "golang.org/x/tools/go/ast/astutil", - "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" - }, - { - "ImportPath": "golang.org/x/tools/imports", - "Rev": "2382e3994d48b1d22acc2c86bcad0a2aff028e32" - }, - { - "ImportPath": "gopkg.in/yaml.v2", - "Rev": "670d4cfef0544295bc27a114dbac37980d83185a" - }, - { - "ImportPath": "k8s.io/gengo/args", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/examples/deepcopy-gen/generators", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/examples/defaulter-gen/generators", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/examples/import-boss/generators", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/examples/set-gen/generators", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/examples/set-gen/sets", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/generator", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/namer", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/parser", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/gengo/types", - "Rev": "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" - }, - { - "ImportPath": "k8s.io/kube-openapi/cmd/openapi-gen/args", - "Rev": "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" - }, - { - "ImportPath": "k8s.io/kube-openapi/pkg/common", - "Rev": "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" - }, - { - "ImportPath": "k8s.io/kube-openapi/pkg/generators", - "Rev": "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" - }, - { - "ImportPath": "k8s.io/kube-openapi/pkg/generators/rules", - "Rev": "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" - }, - { - "ImportPath": "k8s.io/kube-openapi/pkg/util/sets", - "Rev": "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" - } - ] -} diff --git a/vendor/k8s.io/code-generator/Godeps/OWNERS b/vendor/k8s.io/code-generator/Godeps/OWNERS deleted file mode 100644 index 3d49f3060..000000000 --- a/vendor/k8s.io/code-generator/Godeps/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -approvers: -- dep-approvers diff --git a/vendor/k8s.io/code-generator/Godeps/Readme b/vendor/k8s.io/code-generator/Godeps/Readme deleted file mode 100644 index 4cdaa53d5..000000000 --- a/vendor/k8s.io/code-generator/Godeps/Readme +++ /dev/null @@ -1,5 +0,0 @@ -This directory tree is generated automatically by godep. - -Please do not edit. - -See https://github.com/tools/godep for more information. diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go deleted file mode 100644 index d056c5b78..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/install/install.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2015 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 install installs the experimental API group, making it available as -// an option to all of the API encoding/decoding machinery. -package install - -import ( - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/code-generator/_examples/apiserver/apis/example" - "k8s.io/code-generator/_examples/apiserver/apis/example/v1" -) - -// Install registers the API group and adds types to a scheme -func Install(scheme *runtime.Scheme) { - utilruntime.Must(example.AddToScheme(scheme)) - utilruntime.Must(v1.AddToScheme(scheme)) - utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go deleted file mode 100644 index da397b524..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/register.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2015 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 example - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -var SchemeGroupVersion = schema.GroupVersion{Group: "example.api.code-generator.k8s.io", Version: runtime.APIVersionInternal} - -var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme -) - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &TestType{}, - &TestTypeList{}, - ) - - scheme.AddKnownTypes(SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go deleted file mode 100644 index b4fc97668..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/types.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2015 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 example - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestType is a top-level type. A client is created for it. -type TestType struct { - metav1.TypeMeta - metav1.ObjectMeta - Status TestTypeStatus -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestTypeList is a top-level list type. The client methods for lists are automatically created. -// You are not supposed to create a separated client for this one. -type TestTypeList struct { - metav1.TypeMeta - metav1.ListMeta - - Items []TestType -} - -type TestTypeStatus struct { - Blah string -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go deleted file mode 100644 index 5b6bd5b30..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2016 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. -*/ - -// +k8s:deepcopy-gen=package -// +k8s:defaulter-gen=TypeMeta -// +k8s:conversion-gen=k8s.io/code-generator/_examples/apiserver/apis/example -// +groupName=example.apiserver.code-generator.k8s.io -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go deleted file mode 100644 index c99619d7a..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/register.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2015 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 v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -var SchemeGroupVersion = schema.GroupVersion{Group: "example.apiserver.code-generator.k8s.io", Version: "v1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &TestType{}, - &TestTypeList{}, - ) - - scheme.AddKnownTypes(SchemeGroupVersion, - &metav1.Status{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go deleted file mode 100644 index 5c2ebc4d6..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/types.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2015 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 v1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestType is a top-level type. A client is created for it. -type TestType struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` - // +optional - Status TestTypeStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestTypeList is a top-level list type. The client methods for lists are automatically created. -// You are not supposed to create a separated client for this one. -type TestTypeList struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ListMeta `json:"metadata,omitempty"` - - Items []TestType `json:"items"` -} - -type TestTypeStatus struct { - Blah string -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go deleted file mode 100644 index ba47dbe2e..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.conversion.go +++ /dev/null @@ -1,137 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by conversion-gen. DO NOT EDIT. - -package v1 - -import ( - unsafe "unsafe" - - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" - example "k8s.io/code-generator/_examples/apiserver/apis/example" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_TestType_To_example_TestType(a.(*TestType), b.(*example.TestType), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*example.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_example_TestType_To_v1_TestType(a.(*example.TestType), b.(*TestType), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_TestTypeList_To_example_TestTypeList(a.(*TestTypeList), b.(*example.TestTypeList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*example.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_example_TestTypeList_To_v1_TestTypeList(a.(*example.TestTypeList), b.(*TestTypeList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_TestTypeStatus_To_example_TestTypeStatus(a.(*TestTypeStatus), b.(*example.TestTypeStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*example.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_example_TestTypeStatus_To_v1_TestTypeStatus(a.(*example.TestTypeStatus), b.(*TestTypeStatus), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1_TestType_To_example_TestType(in *TestType, out *example.TestType, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1_TestTypeStatus_To_example_TestTypeStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1_TestType_To_example_TestType is an autogenerated conversion function. -func Convert_v1_TestType_To_example_TestType(in *TestType, out *example.TestType, s conversion.Scope) error { - return autoConvert_v1_TestType_To_example_TestType(in, out, s) -} - -func autoConvert_example_TestType_To_v1_TestType(in *example.TestType, out *TestType, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_example_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_example_TestType_To_v1_TestType is an autogenerated conversion function. -func Convert_example_TestType_To_v1_TestType(in *example.TestType, out *TestType, s conversion.Scope) error { - return autoConvert_example_TestType_To_v1_TestType(in, out, s) -} - -func autoConvert_v1_TestTypeList_To_example_TestTypeList(in *TestTypeList, out *example.TestTypeList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]example.TestType)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1_TestTypeList_To_example_TestTypeList is an autogenerated conversion function. -func Convert_v1_TestTypeList_To_example_TestTypeList(in *TestTypeList, out *example.TestTypeList, s conversion.Scope) error { - return autoConvert_v1_TestTypeList_To_example_TestTypeList(in, out, s) -} - -func autoConvert_example_TestTypeList_To_v1_TestTypeList(in *example.TestTypeList, out *TestTypeList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_example_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. -func Convert_example_TestTypeList_To_v1_TestTypeList(in *example.TestTypeList, out *TestTypeList, s conversion.Scope) error { - return autoConvert_example_TestTypeList_To_v1_TestTypeList(in, out, s) -} - -func autoConvert_v1_TestTypeStatus_To_example_TestTypeStatus(in *TestTypeStatus, out *example.TestTypeStatus, s conversion.Scope) error { - out.Blah = in.Blah - return nil -} - -// Convert_v1_TestTypeStatus_To_example_TestTypeStatus is an autogenerated conversion function. -func Convert_v1_TestTypeStatus_To_example_TestTypeStatus(in *TestTypeStatus, out *example.TestTypeStatus, s conversion.Scope) error { - return autoConvert_v1_TestTypeStatus_To_example_TestTypeStatus(in, out, s) -} - -func autoConvert_example_TestTypeStatus_To_v1_TestTypeStatus(in *example.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { - out.Blah = in.Blah - return nil -} - -// Convert_example_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. -func Convert_example_TestTypeStatus_To_v1_TestTypeStatus(in *example.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { - return autoConvert_example_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go deleted file mode 100644 index dae52ff12..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/v1/zz_generated.deepcopy.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestType) DeepCopyInto(out *TestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. -func (in *TestType) DeepCopy() *TestType { - if in == nil { - return nil - } - out := new(TestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. -func (in *TestTypeList) DeepCopy() *TestTypeList { - if in == nil { - return nil - } - out := new(TestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. -func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { - if in == nil { - return nil - } - out := new(TestTypeStatus) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go deleted file mode 100644 index 980112fa8..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/zz_generated.deepcopy.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package example - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestType) DeepCopyInto(out *TestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. -func (in *TestType) DeepCopy() *TestType { - if in == nil { - return nil - } - out := new(TestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. -func (in *TestTypeList) DeepCopy() *TestTypeList { - if in == nil { - return nil - } - out := new(TestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. -func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { - if in == nil { - return nil - } - out := new(TestTypeStatus) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go deleted file mode 100644 index 386480375..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2015 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. -*/ - -// +k8s:deepcopy-gen=package -// +groupName=example.test.apiserver.code-generator.k8s.io -// +groupGoName=SecondExample -package example2 // import "k8s.io/code-generator/_examples/apiserver/apis/example2" diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go deleted file mode 100644 index 1e786f5c5..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/install/install.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright 2015 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 install installs the experimental API group, making it available as -// an option to all of the API encoding/decoding machinery. -package install - -import ( - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/code-generator/_examples/apiserver/apis/example2" - "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" -) - -// Install registers the API group and adds types to a scheme -func Install(scheme *runtime.Scheme) { - utilruntime.Must(example2.AddToScheme(scheme)) - utilruntime.Must(v1.AddToScheme(scheme)) - utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go deleted file mode 100644 index 508565af7..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/register.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2015 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 example2 - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.apiserver.code-generator.k8s.io", Version: runtime.APIVersionInternal} - -var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme -) - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &TestType{}, - &TestTypeList{}, - ) - - scheme.AddKnownTypes(SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go deleted file mode 100644 index 10219129b..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/types.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2015 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 example2 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestType is a top-level type. A client is created for it. -type TestType struct { - metav1.TypeMeta - metav1.ObjectMeta - Status TestTypeStatus -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestTypeList is a top-level list type. The client methods for lists are automatically created. -// You are not supposed to create a separated client for this one. -type TestTypeList struct { - metav1.TypeMeta - metav1.ListMeta - - Items []TestType -} - -type TestTypeStatus struct { - Blah string -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go deleted file mode 100644 index 19dd0c356..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/register.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2015 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 v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -// Adds the list of known types to api.Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &TestType{}, - &TestTypeList{}, - ) - - scheme.AddKnownTypes(SchemeGroupVersion, - &metav1.Status{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go deleted file mode 100644 index 5c2ebc4d6..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/types.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2015 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 v1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestType is a top-level type. A client is created for it. -type TestType struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` - // +optional - Status TestTypeStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestTypeList is a top-level list type. The client methods for lists are automatically created. -// You are not supposed to create a separated client for this one. -type TestTypeList struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ListMeta `json:"metadata,omitempty"` - - Items []TestType `json:"items"` -} - -type TestTypeStatus struct { - Blah string -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go deleted file mode 100644 index 5bf9a98e9..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.conversion.go +++ /dev/null @@ -1,137 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by conversion-gen. DO NOT EDIT. - -package v1 - -import ( - unsafe "unsafe" - - conversion "k8s.io/apimachinery/pkg/conversion" - runtime "k8s.io/apimachinery/pkg/runtime" - example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" -) - -func init() { - localSchemeBuilder.Register(RegisterConversions) -} - -// RegisterConversions adds conversion functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example2.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_TestType_To_example2_TestType(a.(*TestType), b.(*example2.TestType), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*example2.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_example2_TestType_To_v1_TestType(a.(*example2.TestType), b.(*TestType), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example2.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_TestTypeList_To_example2_TestTypeList(a.(*TestTypeList), b.(*example2.TestTypeList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*example2.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_example2_TestTypeList_To_v1_TestTypeList(a.(*example2.TestTypeList), b.(*TestTypeList), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example2.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(a.(*TestTypeStatus), b.(*example2.TestTypeStatus), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*example2.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(a.(*example2.TestTypeStatus), b.(*TestTypeStatus), scope) - }); err != nil { - return err - } - return nil -} - -func autoConvert_v1_TestType_To_example2_TestType(in *TestType, out *example2.TestType, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_v1_TestType_To_example2_TestType is an autogenerated conversion function. -func Convert_v1_TestType_To_example2_TestType(in *TestType, out *example2.TestType, s conversion.Scope) error { - return autoConvert_v1_TestType_To_example2_TestType(in, out, s) -} - -func autoConvert_example2_TestType_To_v1_TestType(in *example2.TestType, out *TestType, s conversion.Scope) error { - out.ObjectMeta = in.ObjectMeta - if err := Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { - return err - } - return nil -} - -// Convert_example2_TestType_To_v1_TestType is an autogenerated conversion function. -func Convert_example2_TestType_To_v1_TestType(in *example2.TestType, out *TestType, s conversion.Scope) error { - return autoConvert_example2_TestType_To_v1_TestType(in, out, s) -} - -func autoConvert_v1_TestTypeList_To_example2_TestTypeList(in *TestTypeList, out *example2.TestTypeList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]example2.TestType)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_v1_TestTypeList_To_example2_TestTypeList is an autogenerated conversion function. -func Convert_v1_TestTypeList_To_example2_TestTypeList(in *TestTypeList, out *example2.TestTypeList, s conversion.Scope) error { - return autoConvert_v1_TestTypeList_To_example2_TestTypeList(in, out, s) -} - -func autoConvert_example2_TestTypeList_To_v1_TestTypeList(in *example2.TestTypeList, out *TestTypeList, s conversion.Scope) error { - out.ListMeta = in.ListMeta - out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) - return nil -} - -// Convert_example2_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. -func Convert_example2_TestTypeList_To_v1_TestTypeList(in *example2.TestTypeList, out *TestTypeList, s conversion.Scope) error { - return autoConvert_example2_TestTypeList_To_v1_TestTypeList(in, out, s) -} - -func autoConvert_v1_TestTypeStatus_To_example2_TestTypeStatus(in *TestTypeStatus, out *example2.TestTypeStatus, s conversion.Scope) error { - out.Blah = in.Blah - return nil -} - -// Convert_v1_TestTypeStatus_To_example2_TestTypeStatus is an autogenerated conversion function. -func Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(in *TestTypeStatus, out *example2.TestTypeStatus, s conversion.Scope) error { - return autoConvert_v1_TestTypeStatus_To_example2_TestTypeStatus(in, out, s) -} - -func autoConvert_example2_TestTypeStatus_To_v1_TestTypeStatus(in *example2.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { - out.Blah = in.Blah - return nil -} - -// Convert_example2_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. -func Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(in *example2.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { - return autoConvert_example2_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go deleted file mode 100644 index dae52ff12..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestType) DeepCopyInto(out *TestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. -func (in *TestType) DeepCopy() *TestType { - if in == nil { - return nil - } - out := new(TestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. -func (in *TestTypeList) DeepCopy() *TestTypeList { - if in == nil { - return nil - } - out := new(TestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. -func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { - if in == nil { - return nil - } - out := new(TestTypeStatus) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go deleted file mode 100644 index cce2e603a..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/v1/zz_generated.defaults.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go deleted file mode 100644 index f9b317e57..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example2/zz_generated.deepcopy.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package example2 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestType) DeepCopyInto(out *TestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. -func (in *TestType) DeepCopy() *TestType { - if in == nil { - return nil - } - out := new(TestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. -func (in *TestTypeList) DeepCopy() *TestTypeList { - if in == nil { - return nil - } - out := new(TestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. -func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { - if in == nil { - return nil - } - out := new(TestTypeStatus) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go deleted file mode 100644 index ff88d121c..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/clientset.go +++ /dev/null @@ -1,104 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package internalversion - -import ( - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" - exampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion" - secondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - Example() exampleinternalversion.ExampleInterface - SecondExample() secondexampleinternalversion.SecondExampleInterface -} - -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. -type Clientset struct { - *discovery.DiscoveryClient - example *exampleinternalversion.ExampleClient - secondExample *secondexampleinternalversion.SecondExampleClient -} - -// Example retrieves the ExampleClient -func (c *Clientset) Example() exampleinternalversion.ExampleInterface { - return c.example -} - -// SecondExample retrieves the SecondExampleClient -func (c *Clientset) SecondExample() secondexampleinternalversion.SecondExampleInterface { - return c.secondExample -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - var cs Clientset - var err error - cs.example, err = exampleinternalversion.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - cs.secondExample, err = secondexampleinternalversion.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.example = exampleinternalversion.NewForConfigOrDie(c) - cs.secondExample = secondexampleinternalversion.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.example = exampleinternalversion.New(c) - cs.secondExample = secondexampleinternalversion.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go deleted file mode 100644 index 6c970b092..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package internalversion diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go deleted file mode 100644 index 37f1b724d..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/clientset_generated.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" - clientset "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" - exampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion" - fakeexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake" - secondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion" - fakesecondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -var _ clientset.Interface = &Clientset{} - -// Example retrieves the ExampleClient -func (c *Clientset) Example() exampleinternalversion.ExampleInterface { - return &fakeexampleinternalversion.FakeExample{Fake: &c.Fake} -} - -// SecondExample retrieves the SecondExampleClient -func (c *Clientset) SecondExample() secondexampleinternalversion.SecondExampleInterface { - return &fakesecondexampleinternalversion.FakeSecondExample{Fake: &c.Fake} -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go deleted file mode 100644 index 9b99e7167..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated fake clientset. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go deleted file mode 100644 index 5713015ce..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/fake/register.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - exampleinternalversion "k8s.io/code-generator/_examples/apiserver/apis/example" - secondexampleinternalversion "k8s.io/code-generator/_examples/apiserver/apis/example2" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) -var parameterCodec = runtime.NewParameterCodec(scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - exampleinternalversion.AddToScheme, - secondexampleinternalversion.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go deleted file mode 100644 index 7dc375616..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go deleted file mode 100644 index 97b03068e..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme/register.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package scheme - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - example "k8s.io/code-generator/_examples/apiserver/apis/example/install" - secondexample "k8s.io/code-generator/_examples/apiserver/apis/example2/install" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - Install(Scheme) -} - -// Install registers the API group and adds types to a scheme -func Install(scheme *runtime.Scheme) { - example.Install(scheme) - secondexample.Install(scheme) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go deleted file mode 100644 index 86602442b..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package internalversion diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go deleted file mode 100644 index 61d99cad0..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/example_client.go +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package internalversion - -import ( - rest "k8s.io/client-go/rest" - "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" -) - -type ExampleInterface interface { - RESTClient() rest.Interface - TestTypesGetter -} - -// ExampleClient is used to interact with features provided by the example.apiserver.code-generator.k8s.io group. -type ExampleClient struct { - restClient rest.Interface -} - -func (c *ExampleClient) TestTypes(namespace string) TestTypeInterface { - return newTestTypes(c, namespace) -} - -// NewForConfig creates a new ExampleClient for the given config. -func NewForConfig(c *rest.Config) (*ExampleClient, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &ExampleClient{client}, nil -} - -// NewForConfigOrDie creates a new ExampleClient for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *ExampleClient { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new ExampleClient for the given RESTClient. -func New(c rest.Interface) *ExampleClient { - return &ExampleClient{c} -} - -func setConfigDefaults(config *rest.Config) error { - config.APIPath = "/apis" - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - if config.GroupVersion == nil || config.GroupVersion.Group != scheme.Scheme.PrioritizedVersionsForGroup("example.apiserver.code-generator.k8s.io")[0].Group { - gv := scheme.Scheme.PrioritizedVersionsForGroup("example.apiserver.code-generator.k8s.io")[0] - config.GroupVersion = &gv - } - config.NegotiatedSerializer = scheme.Codecs - - if config.QPS == 0 { - config.QPS = 5 - } - if config.Burst == 0 { - config.Burst = 10 - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *ExampleClient) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go deleted file mode 100644 index 16f443990..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go deleted file mode 100644 index 90564e449..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_example_client.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion" -) - -type FakeExample struct { - *testing.Fake -} - -func (c *FakeExample) TestTypes(namespace string) internalversion.TestTypeInterface { - return &FakeTestTypes{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeExample) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go deleted file mode 100644 index 7b247ca95..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/fake/fake_testtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - example "k8s.io/code-generator/_examples/apiserver/apis/example" -) - -// FakeTestTypes implements TestTypeInterface -type FakeTestTypes struct { - Fake *FakeExample - ns string -} - -var testtypesResource = schema.GroupVersionResource{Group: "example.apiserver.code-generator.k8s.io", Version: "", Resource: "testtypes"} - -var testtypesKind = schema.GroupVersionKind{Group: "example.apiserver.code-generator.k8s.io", Version: "", Kind: "TestType"} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example.TestType), err -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &example.TestTypeList{ListMeta: obj.(*example.TestTypeList).ListMeta} - for _, item := range obj.(*example.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Create(testType *example.TestType) (result *example.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example.TestType), err -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Update(testType *example.TestType) (result *example.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example.TestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTestTypes) UpdateStatus(testType *example.TestType) (*example.TestType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example.TestType), err -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example.TestType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &example.TestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched testType. -func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, data, subresources...), &example.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example.TestType), err -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go deleted file mode 100644 index 50bdbd254..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/generated_expansion.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package internalversion - -type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go deleted file mode 100644 index d19392e85..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example/internalversion/testtype.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package internalversion - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - example "k8s.io/code-generator/_examples/apiserver/apis/example" - scheme "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" -) - -// TestTypesGetter has a method to return a TestTypeInterface. -// A group's client should implement this interface. -type TestTypesGetter interface { - TestTypes(namespace string) TestTypeInterface -} - -// TestTypeInterface has methods to work with TestType resources. -type TestTypeInterface interface { - Create(*example.TestType) (*example.TestType, error) - Update(*example.TestType) (*example.TestType, error) - UpdateStatus(*example.TestType) (*example.TestType, error) - Delete(name string, options *v1.DeleteOptions) error - DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error - Get(name string, options v1.GetOptions) (*example.TestType, error) - List(opts v1.ListOptions) (*example.TestTypeList, error) - Watch(opts v1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example.TestType, err error) - TestTypeExpansion -} - -// testTypes implements TestTypeInterface -type testTypes struct { - client rest.Interface - ns string -} - -// newTestTypes returns a TestTypes -func newTestTypes(c *ExampleClient, namespace string) *testTypes { - return &testTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options v1.GetOptions) (result *example.TestType, err error) { - result = &example.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts v1.ListOptions) (result *example.TestTypeList, err error) { - result = &example.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Create(testType *example.TestType) (result *example.TestType, err error) { - result = &example.TestType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("testtypes"). - Body(testType). - Do(). - Into(result) - return -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Update(testType *example.TestType) (result *example.TestType, err error) { - result = &example.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - Body(testType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *testTypes) UpdateStatus(testType *example.TestType) (result *example.TestType, err error) { - result = &example.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - SubResource("status"). - Body(testType). - Do(). - Into(result) - return -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *testTypes) Delete(name string, options *v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *testTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched testType. -func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example.TestType, err error) { - result = &example.TestType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("testtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go deleted file mode 100644 index 86602442b..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package internalversion diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go deleted file mode 100644 index 0fcc7baa4..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/example2_client.go +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package internalversion - -import ( - rest "k8s.io/client-go/rest" - "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" -) - -type SecondExampleInterface interface { - RESTClient() rest.Interface - TestTypesGetter -} - -// SecondExampleClient is used to interact with features provided by the example.test.apiserver.code-generator.k8s.io group. -type SecondExampleClient struct { - restClient rest.Interface -} - -func (c *SecondExampleClient) TestTypes(namespace string) TestTypeInterface { - return newTestTypes(c, namespace) -} - -// NewForConfig creates a new SecondExampleClient for the given config. -func NewForConfig(c *rest.Config) (*SecondExampleClient, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &SecondExampleClient{client}, nil -} - -// NewForConfigOrDie creates a new SecondExampleClient for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *SecondExampleClient { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new SecondExampleClient for the given RESTClient. -func New(c rest.Interface) *SecondExampleClient { - return &SecondExampleClient{c} -} - -func setConfigDefaults(config *rest.Config) error { - config.APIPath = "/apis" - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - if config.GroupVersion == nil || config.GroupVersion.Group != scheme.Scheme.PrioritizedVersionsForGroup("example.test.apiserver.code-generator.k8s.io")[0].Group { - gv := scheme.Scheme.PrioritizedVersionsForGroup("example.test.apiserver.code-generator.k8s.io")[0] - config.GroupVersion = &gv - } - config.NegotiatedSerializer = scheme.Codecs - - if config.QPS == 0 { - config.QPS = 5 - } - if config.Burst == 0 { - config.Burst = 10 - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *SecondExampleClient) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go deleted file mode 100644 index 16f443990..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go deleted file mode 100644 index 235305e9d..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_example2_client.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion" -) - -type FakeSecondExample struct { - *testing.Fake -} - -func (c *FakeSecondExample) TestTypes(namespace string) internalversion.TestTypeInterface { - return &FakeTestTypes{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeSecondExample) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go deleted file mode 100644 index 2890ff19d..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/fake/fake_testtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" -) - -// FakeTestTypes implements TestTypeInterface -type FakeTestTypes struct { - Fake *FakeSecondExample - ns string -} - -var testtypesResource = schema.GroupVersionResource{Group: "example.test.apiserver.code-generator.k8s.io", Version: "", Resource: "testtypes"} - -var testtypesKind = schema.GroupVersionKind{Group: "example.test.apiserver.code-generator.k8s.io", Version: "", Kind: "TestType"} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example2.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example2.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2.TestType), err -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example2.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example2.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &example2.TestTypeList{ListMeta: obj.(*example2.TestTypeList).ListMeta} - for _, item := range obj.(*example2.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Create(testType *example2.TestType) (result *example2.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example2.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2.TestType), err -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Update(testType *example2.TestType) (result *example2.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example2.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2.TestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTestTypes) UpdateStatus(testType *example2.TestType) (*example2.TestType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example2.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2.TestType), err -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example2.TestType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &example2.TestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched testType. -func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, data, subresources...), &example2.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2.TestType), err -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go deleted file mode 100644 index 1a2ca7891..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/internalversion/typed/example2/internalversion/testtype.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package internalversion - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" - scheme "k8s.io/code-generator/_examples/apiserver/clientset/internalversion/scheme" -) - -// TestTypesGetter has a method to return a TestTypeInterface. -// A group's client should implement this interface. -type TestTypesGetter interface { - TestTypes(namespace string) TestTypeInterface -} - -// TestTypeInterface has methods to work with TestType resources. -type TestTypeInterface interface { - Create(*example2.TestType) (*example2.TestType, error) - Update(*example2.TestType) (*example2.TestType, error) - UpdateStatus(*example2.TestType) (*example2.TestType, error) - Delete(name string, options *v1.DeleteOptions) error - DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error - Get(name string, options v1.GetOptions) (*example2.TestType, error) - List(opts v1.ListOptions) (*example2.TestTypeList, error) - Watch(opts v1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2.TestType, err error) - TestTypeExpansion -} - -// testTypes implements TestTypeInterface -type testTypes struct { - client rest.Interface - ns string -} - -// newTestTypes returns a TestTypes -func newTestTypes(c *SecondExampleClient, namespace string) *testTypes { - return &testTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options v1.GetOptions) (result *example2.TestType, err error) { - result = &example2.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts v1.ListOptions) (result *example2.TestTypeList, err error) { - result = &example2.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Create(testType *example2.TestType) (result *example2.TestType, err error) { - result = &example2.TestType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("testtypes"). - Body(testType). - Do(). - Into(result) - return -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Update(testType *example2.TestType) (result *example2.TestType, err error) { - result = &example2.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - Body(testType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *testTypes) UpdateStatus(testType *example2.TestType) (result *example2.TestType, err error) { - result = &example2.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - SubResource("status"). - Body(testType). - Do(). - Into(result) - return -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *testTypes) Delete(name string, options *v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *testTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched testType. -func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2.TestType, err error) { - result = &example2.TestType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("testtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go deleted file mode 100644 index 8ba9799f5..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/clientset.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package versioned - -import ( - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" - examplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1" - secondexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - ExampleV1() examplev1.ExampleV1Interface - // Deprecated: please explicitly pick a version if possible. - Example() examplev1.ExampleV1Interface - SecondExampleV1() secondexamplev1.SecondExampleV1Interface - // Deprecated: please explicitly pick a version if possible. - SecondExample() secondexamplev1.SecondExampleV1Interface -} - -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. -type Clientset struct { - *discovery.DiscoveryClient - exampleV1 *examplev1.ExampleV1Client - secondExampleV1 *secondexamplev1.SecondExampleV1Client -} - -// ExampleV1 retrieves the ExampleV1Client -func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { - return c.exampleV1 -} - -// Deprecated: Example retrieves the default version of ExampleClient. -// Please explicitly pick a version. -func (c *Clientset) Example() examplev1.ExampleV1Interface { - return c.exampleV1 -} - -// SecondExampleV1 retrieves the SecondExampleV1Client -func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { - return c.secondExampleV1 -} - -// Deprecated: SecondExample retrieves the default version of SecondExampleClient. -// Please explicitly pick a version. -func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { - return c.secondExampleV1 -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - var cs Clientset - var err error - cs.exampleV1, err = examplev1.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - cs.secondExampleV1, err = secondexamplev1.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.exampleV1 = examplev1.NewForConfigOrDie(c) - cs.secondExampleV1 = secondexamplev1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.exampleV1 = examplev1.New(c) - cs.secondExampleV1 = secondexamplev1.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go deleted file mode 100644 index 41721ca52..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go deleted file mode 100644 index 6dce4fed4..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/clientset_generated.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" - clientset "k8s.io/code-generator/_examples/apiserver/clientset/versioned" - examplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1" - fakeexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake" - secondexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1" - fakesecondexamplev1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -var _ clientset.Interface = &Clientset{} - -// ExampleV1 retrieves the ExampleV1Client -func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { - return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} -} - -// Example retrieves the ExampleV1Client -func (c *Clientset) Example() examplev1.ExampleV1Interface { - return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} -} - -// SecondExampleV1 retrieves the SecondExampleV1Client -func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { - return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} -} - -// SecondExample retrieves the SecondExampleV1Client -func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { - return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go deleted file mode 100644 index 9b99e7167..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated fake clientset. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go deleted file mode 100644 index 75282b82f..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/fake/register.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" - secondexamplev1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) -var parameterCodec = runtime.NewParameterCodec(scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - examplev1.AddToScheme, - secondexamplev1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go deleted file mode 100644 index 7dc375616..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go deleted file mode 100644 index e4c8dc102..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme/register.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package scheme - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" - secondexamplev1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - examplev1.AddToScheme, - secondexamplev1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(Scheme)) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go deleted file mode 100644 index 3af5d054f..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go deleted file mode 100644 index 743c8ded2..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/example_client.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" - "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" -) - -type ExampleV1Interface interface { - RESTClient() rest.Interface - TestTypesGetter -} - -// ExampleV1Client is used to interact with features provided by the example.apiserver.code-generator.k8s.io group. -type ExampleV1Client struct { - restClient rest.Interface -} - -func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { - return newTestTypes(c, namespace) -} - -// NewForConfig creates a new ExampleV1Client for the given config. -func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &ExampleV1Client{client}, nil -} - -// NewForConfigOrDie creates a new ExampleV1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new ExampleV1Client for the given RESTClient. -func New(c rest.Interface) *ExampleV1Client { - return &ExampleV1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *ExampleV1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go deleted file mode 100644 index 16f443990..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go deleted file mode 100644 index 509a5b427..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - v1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1" -) - -type FakeExampleV1 struct { - *testing.Fake -} - -func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { - return &FakeTestTypes{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeExampleV1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go deleted file mode 100644 index 6847f17d5..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" -) - -// FakeTestTypes implements TestTypeInterface -type FakeTestTypes struct { - Fake *FakeExampleV1 - ns string -} - -var testtypesResource = schema.GroupVersionResource{Group: "example.apiserver.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} - -var testtypesKind = schema.GroupVersionKind{Group: "example.apiserver.code-generator.k8s.io", Version: "v1", Kind: "TestType"} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *examplev1.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &examplev1.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &examplev1.TestTypeList{ListMeta: obj.(*examplev1.TestTypeList).ListMeta} - for _, item := range obj.(*examplev1.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Create(testType *examplev1.TestType) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Update(testType *examplev1.TestType) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTestTypes) UpdateStatus(testType *examplev1.TestType) (*examplev1.TestType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &examplev1.TestType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &examplev1.TestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched testType. -func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, data, subresources...), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go deleted file mode 100644 index d513810d0..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go deleted file mode 100644 index 2a0606512..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example/v1/testtype.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" - scheme "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" -) - -// TestTypesGetter has a method to return a TestTypeInterface. -// A group's client should implement this interface. -type TestTypesGetter interface { - TestTypes(namespace string) TestTypeInterface -} - -// TestTypeInterface has methods to work with TestType resources. -type TestTypeInterface interface { - Create(*v1.TestType) (*v1.TestType, error) - Update(*v1.TestType) (*v1.TestType, error) - UpdateStatus(*v1.TestType) (*v1.TestType, error) - Delete(name string, options *metav1.DeleteOptions) error - DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error - Get(name string, options metav1.GetOptions) (*v1.TestType, error) - List(opts metav1.ListOptions) (*v1.TestTypeList, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) - TestTypeExpansion -} - -// testTypes implements TestTypeInterface -type testTypes struct { - client rest.Interface - ns string -} - -// newTestTypes returns a TestTypes -func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { - return &testTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { - result = &v1.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("testtypes"). - Body(testType). - Do(). - Into(result) - return -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - Body(testType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - SubResource("status"). - Body(testType). - Do(). - Into(result) - return -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched testType. -func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("testtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go deleted file mode 100644 index 3af5d054f..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go deleted file mode 100644 index 1271c0f19..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" - "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" -) - -type SecondExampleV1Interface interface { - RESTClient() rest.Interface - TestTypesGetter -} - -// SecondExampleV1Client is used to interact with features provided by the example.test.apiserver.code-generator.k8s.io group. -type SecondExampleV1Client struct { - restClient rest.Interface -} - -func (c *SecondExampleV1Client) TestTypes(namespace string) TestTypeInterface { - return newTestTypes(c, namespace) -} - -// NewForConfig creates a new SecondExampleV1Client for the given config. -func NewForConfig(c *rest.Config) (*SecondExampleV1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &SecondExampleV1Client{client}, nil -} - -// NewForConfigOrDie creates a new SecondExampleV1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *SecondExampleV1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new SecondExampleV1Client for the given RESTClient. -func New(c rest.Interface) *SecondExampleV1Client { - return &SecondExampleV1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *SecondExampleV1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go deleted file mode 100644 index 16f443990..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go deleted file mode 100644 index 1820e182c..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - v1 "k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1" -) - -type FakeSecondExampleV1 struct { - *testing.Fake -} - -func (c *FakeSecondExampleV1) TestTypes(namespace string) v1.TestTypeInterface { - return &FakeTestTypes{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeSecondExampleV1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go deleted file mode 100644 index 51a3f3e7d..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - example2v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" -) - -// FakeTestTypes implements TestTypeInterface -type FakeTestTypes struct { - Fake *FakeSecondExampleV1 - ns string -} - -var testtypesResource = schema.GroupVersionResource{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} - -var testtypesKind = schema.GroupVersionKind{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1", Kind: "TestType"} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example2v1.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example2v1.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &example2v1.TestTypeList{ListMeta: obj.(*example2v1.TestTypeList).ListMeta} - for _, item := range obj.(*example2v1.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Create(testType *example2v1.TestType) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Update(testType *example2v1.TestType) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTestTypes) UpdateStatus(testType *example2v1.TestType) (*example2v1.TestType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example2v1.TestType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &example2v1.TestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched testType. -func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, data, subresources...), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go deleted file mode 100644 index d513810d0..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go deleted file mode 100644 index b29bd8118..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" - scheme "k8s.io/code-generator/_examples/apiserver/clientset/versioned/scheme" -) - -// TestTypesGetter has a method to return a TestTypeInterface. -// A group's client should implement this interface. -type TestTypesGetter interface { - TestTypes(namespace string) TestTypeInterface -} - -// TestTypeInterface has methods to work with TestType resources. -type TestTypeInterface interface { - Create(*v1.TestType) (*v1.TestType, error) - Update(*v1.TestType) (*v1.TestType, error) - UpdateStatus(*v1.TestType) (*v1.TestType, error) - Delete(name string, options *metav1.DeleteOptions) error - DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error - Get(name string, options metav1.GetOptions) (*v1.TestType, error) - List(opts metav1.ListOptions) (*v1.TestTypeList, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) - TestTypeExpansion -} - -// testTypes implements TestTypeInterface -type testTypes struct { - client rest.Interface - ns string -} - -// newTestTypes returns a TestTypes -func newTestTypes(c *SecondExampleV1Client, namespace string) *testTypes { - return &testTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { - result = &v1.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("testtypes"). - Body(testType). - Do(). - Into(result) - return -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - Body(testType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - SubResource("status"). - Body(testType). - Do(). - Into(result) - return -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched testType. -func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("testtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go deleted file mode 100644 index 9cc5d1b0a..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package example - -import ( - v1 "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1 provides access to shared informers for resources in V1. - V1() v1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1 returns a new v1.Interface. -func (g *group) V1() v1.Interface { - return v1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go deleted file mode 100644 index 1ccc8f3ca..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // TestTypes returns a TestTypeInformer. - TestTypes() TestTypeInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// TestTypes returns a TestTypeInformer. -func (v *version) TestTypes() TestTypeInformer { - return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go deleted file mode 100644 index 025113612..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example/v1/testtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - time "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - examplev1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" - versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" - v1 "k8s.io/code-generator/_examples/apiserver/listers/example/v1" -) - -// TestTypeInformer provides access to a shared informer and lister for -// TestTypes. -type TestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.TestTypeLister -} - -type testTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleV1().TestTypes(namespace).List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleV1().TestTypes(namespace).Watch(options) - }, - }, - &examplev1.TestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *testTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&examplev1.TestType{}, f.defaultInformer) -} - -func (f *testTypeInformer) Lister() v1.TestTypeLister { - return v1.NewTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go deleted file mode 100644 index 3a791dd0f..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package example - -import ( - v1 "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1 provides access to shared informers for resources in V1. - V1() v1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1 returns a new v1.Interface. -func (g *group) V1() v1.Interface { - return v1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go deleted file mode 100644 index 1ccc8f3ca..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // TestTypes returns a TestTypeInformer. - TestTypes() TestTypeInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// TestTypes returns a TestTypeInformer. -func (v *version) TestTypes() TestTypeInformer { - return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go deleted file mode 100644 index 979ee4d58..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2/v1/testtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - time "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - example2v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" - versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" - v1 "k8s.io/code-generator/_examples/apiserver/listers/example2/v1" -) - -// TestTypeInformer provides access to a shared informer and lister for -// TestTypes. -type TestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.TestTypeLister -} - -type testTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SecondExampleV1().TestTypes(namespace).List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SecondExampleV1().TestTypes(namespace).Watch(options) - }, - }, - &example2v1.TestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *testTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&example2v1.TestType{}, f.defaultInformer) -} - -func (f *testTypeInformer) Lister() v1.TestTypeLister { - return v1.NewTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go deleted file mode 100644 index fc4aa0d39..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/factory.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - reflect "reflect" - sync "sync" - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" - versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" - example "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example" - example2 "k8s.io/code-generator/_examples/apiserver/informers/externalversions/example2" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces" -) - -// SharedInformerOption defines the functional option type for SharedInformerFactory. -type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory - -type sharedInformerFactory struct { - client versioned.Interface - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc - lock sync.Mutex - defaultResync time.Duration - customResync map[reflect.Type]time.Duration - - informers map[reflect.Type]cache.SharedIndexInformer - // startedInformers is used for tracking which informers have been started. - // This allows Start() to be called multiple times safely. - startedInformers map[reflect.Type]bool -} - -// WithCustomResyncConfig sets a custom resync period for the specified informer types. -func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - for k, v := range resyncConfig { - factory.customResync[reflect.TypeOf(k)] = v - } - return factory - } -} - -// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. -func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.tweakListOptions = tweakListOptions - return factory - } -} - -// WithNamespace limits the SharedInformerFactory to the specified namespace. -func WithNamespace(namespace string) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.namespace = namespace - return factory - } -} - -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. -func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync) -} - -// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. -// Listers obtained via this SharedInformerFactory will be subject to the same filters -// as specified here. -// Deprecated: Please use NewSharedInformerFactoryWithOptions instead -func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) -} - -// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. -func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { - factory := &sharedInformerFactory{ - client: client, - namespace: v1.NamespaceAll, - defaultResync: defaultResync, - informers: make(map[reflect.Type]cache.SharedIndexInformer), - startedInformers: make(map[reflect.Type]bool), - customResync: make(map[reflect.Type]time.Duration), - } - - // Apply all options - for _, opt := range options { - factory = opt(factory) - } - - return factory -} - -// Start initializes all requested informers. -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - go informer.Run(stopCh) - f.startedInformers[informerType] = true - } - } -} - -// WaitForCacheSync waits for all started informers' cache were synced. -func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { - informers := func() map[reflect.Type]cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informers := map[reflect.Type]cache.SharedIndexInformer{} - for informerType, informer := range f.informers { - if f.startedInformers[informerType] { - informers[informerType] = informer - } - } - return informers - }() - - res := map[reflect.Type]bool{} - for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) - } - return res -} - -// InternalInformerFor returns the SharedIndexInformer for obj using an internal -// client. -func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informerType := reflect.TypeOf(obj) - informer, exists := f.informers[informerType] - if exists { - return informer - } - - resyncPeriod, exists := f.customResync[informerType] - if !exists { - resyncPeriod = f.defaultResync - } - - informer = newFunc(f.client, resyncPeriod) - f.informers[informerType] = informer - - return informer -} - -// SharedInformerFactory provides shared informers for resources in all known -// API group versions. -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - Example() example.Interface - SecondExample() example2.Interface -} - -func (f *sharedInformerFactory) Example() example.Interface { - return example.New(f, f.namespace, f.tweakListOptions) -} - -func (f *sharedInformerFactory) SecondExample() example2.Interface { - return example2.New(f, f.namespace, f.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go deleted file mode 100644 index feb7b2028..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/generic.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - "fmt" - - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" - example2v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" -) - -// GenericInformer is type of SharedIndexInformer which will locate and delegate to other -// sharedInformers based on type -type GenericInformer interface { - Informer() cache.SharedIndexInformer - Lister() cache.GenericLister -} - -type genericInformer struct { - informer cache.SharedIndexInformer - resource schema.GroupResource -} - -// Informer returns the SharedIndexInformer. -func (f *genericInformer) Informer() cache.SharedIndexInformer { - return f.informer -} - -// Lister returns the GenericLister. -func (f *genericInformer) Lister() cache.GenericLister { - return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) -} - -// ForResource gives generic access to a shared informer of the matching type -// TODO extend this to unknown resources with a client pool -func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { - switch resource { - // Group=example.apiserver.code-generator.k8s.io, Version=v1 - case v1.SchemeGroupVersion.WithResource("testtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil - - // Group=example.test.apiserver.code-generator.k8s.io, Version=v1 - case example2v1.SchemeGroupVersion.WithResource("testtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().V1().TestTypes().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go deleted file mode 100644 index 6318f5284..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalinterfaces - -import ( - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" - versioned "k8s.io/code-generator/_examples/apiserver/clientset/versioned" -) - -type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer - -// SharedInformerFactory a small interface to allow for adding an informer without an import cycle -type SharedInformerFactory interface { - Start(stopCh <-chan struct{}) - InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer -} - -type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go deleted file mode 100644 index d2a36b3c8..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package example - -import ( - internalversion "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // InternalVersion provides access to shared informers for resources in InternalVersion. - InternalVersion() internalversion.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// InternalVersion returns a new internalversion.Interface. -func (g *group) InternalVersion() internalversion.Interface { - return internalversion.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go deleted file mode 100644 index 0fd5f8c3b..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalversion - -import ( - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // TestTypes returns a TestTypeInformer. - TestTypes() TestTypeInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// TestTypes returns a TestTypeInformer. -func (v *version) TestTypes() TestTypeInformer { - return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go deleted file mode 100644 index 22d761056..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example/internalversion/testtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalversion - -import ( - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - example "k8s.io/code-generator/_examples/apiserver/apis/example" - clientsetinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" - internalversion "k8s.io/code-generator/_examples/apiserver/listers/example/internalversion" -) - -// TestTypeInformer provides access to a shared informer and lister for -// TestTypes. -type TestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() internalversion.TestTypeLister -} - -type testTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.Example().TestTypes(namespace).List(options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.Example().TestTypes(namespace).Watch(options) - }, - }, - &example.TestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *testTypeInformer) defaultInformer(client clientsetinternalversion.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *testTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&example.TestType{}, f.defaultInformer) -} - -func (f *testTypeInformer) Lister() internalversion.TestTypeLister { - return internalversion.NewTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go deleted file mode 100644 index 9a5b411a1..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package example - -import ( - internalversion "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // InternalVersion provides access to shared informers for resources in InternalVersion. - InternalVersion() internalversion.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// InternalVersion returns a new internalversion.Interface. -func (g *group) InternalVersion() internalversion.Interface { - return internalversion.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go deleted file mode 100644 index 0fd5f8c3b..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalversion - -import ( - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // TestTypes returns a TestTypeInformer. - TestTypes() TestTypeInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// TestTypes returns a TestTypeInformer. -func (v *version) TestTypes() TestTypeInformer { - return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go deleted file mode 100644 index dcac2ce84..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2/internalversion/testtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalversion - -import ( - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" - clientsetinternalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" - internalversion "k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion" -) - -// TestTypeInformer provides access to a shared informer and lister for -// TestTypes. -type TestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() internalversion.TestTypeLister -} - -type testTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredTestTypeInformer(client clientsetinternalversion.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SecondExample().TestTypes(namespace).List(options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SecondExample().TestTypes(namespace).Watch(options) - }, - }, - &example2.TestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *testTypeInformer) defaultInformer(client clientsetinternalversion.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *testTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&example2.TestType{}, f.defaultInformer) -} - -func (f *testTypeInformer) Lister() internalversion.TestTypeLister { - return internalversion.NewTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go deleted file mode 100644 index ca6d4defe..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/factory.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalversion - -import ( - reflect "reflect" - sync "sync" - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" - internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" - example "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example" - example2 "k8s.io/code-generator/_examples/apiserver/informers/internalversion/example2" - internalinterfaces "k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces" -) - -// SharedInformerOption defines the functional option type for SharedInformerFactory. -type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory - -type sharedInformerFactory struct { - client internalversion.Interface - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc - lock sync.Mutex - defaultResync time.Duration - customResync map[reflect.Type]time.Duration - - informers map[reflect.Type]cache.SharedIndexInformer - // startedInformers is used for tracking which informers have been started. - // This allows Start() to be called multiple times safely. - startedInformers map[reflect.Type]bool -} - -// WithCustomResyncConfig sets a custom resync period for the specified informer types. -func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - for k, v := range resyncConfig { - factory.customResync[reflect.TypeOf(k)] = v - } - return factory - } -} - -// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. -func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.tweakListOptions = tweakListOptions - return factory - } -} - -// WithNamespace limits the SharedInformerFactory to the specified namespace. -func WithNamespace(namespace string) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.namespace = namespace - return factory - } -} - -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. -func NewSharedInformerFactory(client internalversion.Interface, defaultResync time.Duration) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync) -} - -// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. -// Listers obtained via this SharedInformerFactory will be subject to the same filters -// as specified here. -// Deprecated: Please use NewSharedInformerFactoryWithOptions instead -func NewFilteredSharedInformerFactory(client internalversion.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) -} - -// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. -func NewSharedInformerFactoryWithOptions(client internalversion.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { - factory := &sharedInformerFactory{ - client: client, - namespace: v1.NamespaceAll, - defaultResync: defaultResync, - informers: make(map[reflect.Type]cache.SharedIndexInformer), - startedInformers: make(map[reflect.Type]bool), - customResync: make(map[reflect.Type]time.Duration), - } - - // Apply all options - for _, opt := range options { - factory = opt(factory) - } - - return factory -} - -// Start initializes all requested informers. -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - go informer.Run(stopCh) - f.startedInformers[informerType] = true - } - } -} - -// WaitForCacheSync waits for all started informers' cache were synced. -func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { - informers := func() map[reflect.Type]cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informers := map[reflect.Type]cache.SharedIndexInformer{} - for informerType, informer := range f.informers { - if f.startedInformers[informerType] { - informers[informerType] = informer - } - } - return informers - }() - - res := map[reflect.Type]bool{} - for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) - } - return res -} - -// InternalInformerFor returns the SharedIndexInformer for obj using an internal -// client. -func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informerType := reflect.TypeOf(obj) - informer, exists := f.informers[informerType] - if exists { - return informer - } - - resyncPeriod, exists := f.customResync[informerType] - if !exists { - resyncPeriod = f.defaultResync - } - - informer = newFunc(f.client, resyncPeriod) - f.informers[informerType] = informer - - return informer -} - -// SharedInformerFactory provides shared informers for resources in all known -// API group versions. -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - Example() example.Interface - SecondExample() example2.Interface -} - -func (f *sharedInformerFactory) Example() example.Interface { - return example.New(f, f.namespace, f.tweakListOptions) -} - -func (f *sharedInformerFactory) SecondExample() example2.Interface { - return example2.New(f, f.namespace, f.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go deleted file mode 100644 index 046ccac95..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/generic.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalversion - -import ( - "fmt" - - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" - example "k8s.io/code-generator/_examples/apiserver/apis/example" - example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" -) - -// GenericInformer is type of SharedIndexInformer which will locate and delegate to other -// sharedInformers based on type -type GenericInformer interface { - Informer() cache.SharedIndexInformer - Lister() cache.GenericLister -} - -type genericInformer struct { - informer cache.SharedIndexInformer - resource schema.GroupResource -} - -// Informer returns the SharedIndexInformer. -func (f *genericInformer) Informer() cache.SharedIndexInformer { - return f.informer -} - -// Lister returns the GenericLister. -func (f *genericInformer) Lister() cache.GenericLister { - return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) -} - -// ForResource gives generic access to a shared informer of the matching type -// TODO extend this to unknown resources with a client pool -func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { - switch resource { - // Group=example.apiserver.code-generator.k8s.io, Version=internalVersion - case example.SchemeGroupVersion.WithResource("testtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Example().InternalVersion().TestTypes().Informer()}, nil - - // Group=example.test.apiserver.code-generator.k8s.io, Version=internalVersion - case example2.SchemeGroupVersion.WithResource("testtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().InternalVersion().TestTypes().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go deleted file mode 100644 index 03c679244..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/informers/internalversion/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalinterfaces - -import ( - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" - internalversion "k8s.io/code-generator/_examples/apiserver/clientset/internalversion" -) - -type NewInformerFunc func(internalversion.Interface, time.Duration) cache.SharedIndexInformer - -// SharedInformerFactory a small interface to allow for adding an informer without an import cycle -type SharedInformerFactory interface { - Start(stopCh <-chan struct{}) - InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer -} - -type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go deleted file mode 100644 index 4bb87150c..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/expansion_generated.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package internalversion - -// TestTypeListerExpansion allows custom methods to be added to -// TestTypeLister. -type TestTypeListerExpansion interface{} - -// TestTypeNamespaceListerExpansion allows custom methods to be added to -// TestTypeNamespaceLister. -type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go deleted file mode 100644 index 9daa91bbc..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/internalversion/testtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package internalversion - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - example "k8s.io/code-generator/_examples/apiserver/apis/example" -) - -// TestTypeLister helps list TestTypes. -type TestTypeLister interface { - // List lists all TestTypes in the indexer. - List(selector labels.Selector) (ret []*example.TestType, err error) - // TestTypes returns an object that can list and get TestTypes. - TestTypes(namespace string) TestTypeNamespaceLister - TestTypeListerExpansion -} - -// testTypeLister implements the TestTypeLister interface. -type testTypeLister struct { - indexer cache.Indexer -} - -// NewTestTypeLister returns a new TestTypeLister. -func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { - return &testTypeLister{indexer: indexer} -} - -// List lists all TestTypes in the indexer. -func (s *testTypeLister) List(selector labels.Selector) (ret []*example.TestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*example.TestType)) - }) - return ret, err -} - -// TestTypes returns an object that can list and get TestTypes. -func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { - return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// TestTypeNamespaceLister helps list and get TestTypes. -type TestTypeNamespaceLister interface { - // List lists all TestTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*example.TestType, err error) - // Get retrieves the TestType from the indexer for a given namespace and name. - Get(name string) (*example.TestType, error) - TestTypeNamespaceListerExpansion -} - -// testTypeNamespaceLister implements the TestTypeNamespaceLister -// interface. -type testTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TestTypes in the indexer for a given namespace. -func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*example.TestType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*example.TestType)) - }) - return ret, err -} - -// Get retrieves the TestType from the indexer for a given namespace and name. -func (s testTypeNamespaceLister) Get(name string) (*example.TestType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(example.Resource("testtype"), name) - } - return obj.(*example.TestType), nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go deleted file mode 100644 index 0192e05f0..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/expansion_generated.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -// TestTypeListerExpansion allows custom methods to be added to -// TestTypeLister. -type TestTypeListerExpansion interface{} - -// TestTypeNamespaceListerExpansion allows custom methods to be added to -// TestTypeNamespaceLister. -type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go deleted file mode 100644 index a9b3d87c0..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example/v1/testtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example/v1" -) - -// TestTypeLister helps list TestTypes. -type TestTypeLister interface { - // List lists all TestTypes in the indexer. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // TestTypes returns an object that can list and get TestTypes. - TestTypes(namespace string) TestTypeNamespaceLister - TestTypeListerExpansion -} - -// testTypeLister implements the TestTypeLister interface. -type testTypeLister struct { - indexer cache.Indexer -} - -// NewTestTypeLister returns a new TestTypeLister. -func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { - return &testTypeLister{indexer: indexer} -} - -// List lists all TestTypes in the indexer. -func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// TestTypes returns an object that can list and get TestTypes. -func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { - return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// TestTypeNamespaceLister helps list and get TestTypes. -type TestTypeNamespaceLister interface { - // List lists all TestTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // Get retrieves the TestType from the indexer for a given namespace and name. - Get(name string) (*v1.TestType, error) - TestTypeNamespaceListerExpansion -} - -// testTypeNamespaceLister implements the TestTypeNamespaceLister -// interface. -type testTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TestTypes in the indexer for a given namespace. -func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// Get retrieves the TestType from the indexer for a given namespace and name. -func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("testtype"), name) - } - return obj.(*v1.TestType), nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go deleted file mode 100644 index 4bb87150c..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/expansion_generated.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package internalversion - -// TestTypeListerExpansion allows custom methods to be added to -// TestTypeLister. -type TestTypeListerExpansion interface{} - -// TestTypeNamespaceListerExpansion allows custom methods to be added to -// TestTypeNamespaceLister. -type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go deleted file mode 100644 index 724e63871..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/internalversion/testtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package internalversion - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - example2 "k8s.io/code-generator/_examples/apiserver/apis/example2" -) - -// TestTypeLister helps list TestTypes. -type TestTypeLister interface { - // List lists all TestTypes in the indexer. - List(selector labels.Selector) (ret []*example2.TestType, err error) - // TestTypes returns an object that can list and get TestTypes. - TestTypes(namespace string) TestTypeNamespaceLister - TestTypeListerExpansion -} - -// testTypeLister implements the TestTypeLister interface. -type testTypeLister struct { - indexer cache.Indexer -} - -// NewTestTypeLister returns a new TestTypeLister. -func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { - return &testTypeLister{indexer: indexer} -} - -// List lists all TestTypes in the indexer. -func (s *testTypeLister) List(selector labels.Selector) (ret []*example2.TestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*example2.TestType)) - }) - return ret, err -} - -// TestTypes returns an object that can list and get TestTypes. -func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { - return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// TestTypeNamespaceLister helps list and get TestTypes. -type TestTypeNamespaceLister interface { - // List lists all TestTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*example2.TestType, err error) - // Get retrieves the TestType from the indexer for a given namespace and name. - Get(name string) (*example2.TestType, error) - TestTypeNamespaceListerExpansion -} - -// testTypeNamespaceLister implements the TestTypeNamespaceLister -// interface. -type testTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TestTypes in the indexer for a given namespace. -func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*example2.TestType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*example2.TestType)) - }) - return ret, err -} - -// Get retrieves the TestType from the indexer for a given namespace and name. -func (s testTypeNamespaceLister) Get(name string) (*example2.TestType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(example2.Resource("testtype"), name) - } - return obj.(*example2.TestType), nil -} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go deleted file mode 100644 index 0192e05f0..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/expansion_generated.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -// TestTypeListerExpansion allows custom methods to be added to -// TestTypeLister. -type TestTypeListerExpansion interface{} - -// TestTypeNamespaceListerExpansion allows custom methods to be added to -// TestTypeNamespaceLister. -type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go deleted file mode 100644 index 8aa178af8..000000000 --- a/vendor/k8s.io/code-generator/_examples/apiserver/listers/example2/v1/testtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/apiserver/apis/example2/v1" -) - -// TestTypeLister helps list TestTypes. -type TestTypeLister interface { - // List lists all TestTypes in the indexer. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // TestTypes returns an object that can list and get TestTypes. - TestTypes(namespace string) TestTypeNamespaceLister - TestTypeListerExpansion -} - -// testTypeLister implements the TestTypeLister interface. -type testTypeLister struct { - indexer cache.Indexer -} - -// NewTestTypeLister returns a new TestTypeLister. -func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { - return &testTypeLister{indexer: indexer} -} - -// List lists all TestTypes in the indexer. -func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// TestTypes returns an object that can list and get TestTypes. -func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { - return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// TestTypeNamespaceLister helps list and get TestTypes. -type TestTypeNamespaceLister interface { - // List lists all TestTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // Get retrieves the TestType from the indexer for a given namespace and name. - Get(name string) (*v1.TestType, error) - TestTypeNamespaceListerExpansion -} - -// testTypeNamespaceLister implements the TestTypeNamespaceLister -// interface. -type testTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TestTypes in the indexer for a given namespace. -func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// Get retrieves the TestType from the indexer for a given namespace and name. -func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("testtype"), name) - } - return obj.(*v1.TestType), nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go deleted file mode 100644 index e6614c0da..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 2016 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. -*/ - -// +k8s:deepcopy-gen=package -// +k8s:defaulter-gen=TypeMeta -// +groupName=example.crd.code-generator.k8s.io -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go deleted file mode 100644 index 58371e0e9..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/register.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2015 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 v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -var SchemeGroupVersion = schema.GroupVersion{Group: "example.crd.code-generator.k8s.io", Version: "v1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -// Adds the list of known types to the given scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &TestType{}, - &TestTypeList{}, - ) - - scheme.AddKnownTypes(SchemeGroupVersion, - &metav1.Status{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go deleted file mode 100644 index d79ea38b7..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/types.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2015 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 v1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestType is a top-level type. A client is created for it. -type TestType struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` - // +optional - Status TestTypeStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestTypeList is a top-level list type. The client methods for lists are automatically created. -// You are not supposed to create a separated client for this one. -type TestTypeList struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ListMeta `json:"metadata,omitempty"` - - Items []TestType `json:"items"` -} - -type TestTypeStatus struct { - Blah string -} - -// +genclient:nonNamespaced -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type ClusterTestTypeList struct { - metav1.TypeMeta - metav1.ListMeta - Items []ClusterTestType -} - -// +genclient -// +genclient:nonNamespaced -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale -// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/autoscaling.Scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale - -type ClusterTestType struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` - // +optional - Status ClusterTestTypeStatus `json:"status,omitempty"` -} - -type ClusterTestTypeStatus struct { - Blah string -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go deleted file mode 100644 index a3b4bfa9c..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.deepcopy.go +++ /dev/null @@ -1,177 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. -func (in *ClusterTestType) DeepCopy() *ClusterTestType { - if in == nil { - return nil - } - out := new(ClusterTestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ClusterTestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]ClusterTestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. -func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { - if in == nil { - return nil - } - out := new(ClusterTestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. -func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { - if in == nil { - return nil - } - out := new(ClusterTestTypeStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestType) DeepCopyInto(out *TestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. -func (in *TestType) DeepCopy() *TestType { - if in == nil { - return nil - } - out := new(TestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. -func (in *TestTypeList) DeepCopy() *TestTypeList { - if in == nil { - return nil - } - out := new(TestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. -func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { - if in == nil { - return nil - } - out := new(TestTypeStatus) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go deleted file mode 100644 index cce2e603a..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example/v1/zz_generated.defaults.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go deleted file mode 100644 index 6521d83ff..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2016 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. -*/ - -// +k8s:deepcopy-gen=package -// +k8s:defaulter-gen=TypeMeta -// +groupName=example.test.crd.code-generator.k8s.io -// +groupGoName=SecondExample -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go deleted file mode 100644 index d0a852a31..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/register.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2015 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 v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.crd.code-generator.k8s.io", Version: "v1"} - -var ( - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - AddToScheme = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -// Adds the list of known types to api.Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &TestType{}, - &TestTypeList{}, - ) - - scheme.AddKnownTypes(SchemeGroupVersion, - &metav1.Status{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go deleted file mode 100644 index 5c2ebc4d6..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/types.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2015 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 v1 - -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestType is a top-level type. A client is created for it. -type TestType struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` - // +optional - Status TestTypeStatus `json:"status,omitempty"` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// TestTypeList is a top-level list type. The client methods for lists are automatically created. -// You are not supposed to create a separated client for this one. -type TestTypeList struct { - metav1.TypeMeta `json:",inline"` - // +optional - metav1.ListMeta `json:"metadata,omitempty"` - - Items []TestType `json:"items"` -} - -type TestTypeStatus struct { - Blah string -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go deleted file mode 100644 index dae52ff12..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.deepcopy.go +++ /dev/null @@ -1,101 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestType) DeepCopyInto(out *TestType) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Status = in.Status - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. -func (in *TestType) DeepCopy() *TestType { - if in == nil { - return nil - } - out := new(TestType) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestType) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]TestType, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. -func (in *TestTypeList) DeepCopy() *TestTypeList { - if in == nil { - return nil - } - out := new(TestTypeList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *TestTypeList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. -func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { - if in == nil { - return nil - } - out := new(TestTypeStatus) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go b/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go deleted file mode 100644 index cce2e603a..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/apis/example2/v1/zz_generated.defaults.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by defaulter-gen. DO NOT EDIT. - -package v1 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// RegisterDefaults adds defaulters functions to the given scheme. -// Public to allow building arbitrary schemes. -// All generated defaulters are covering - they call all nested defaulters. -func RegisterDefaults(scheme *runtime.Scheme) error { - return nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go deleted file mode 100644 index 034e06ad0..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/clientset.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package versioned - -import ( - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" - examplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1" - secondexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - ExampleV1() examplev1.ExampleV1Interface - // Deprecated: please explicitly pick a version if possible. - Example() examplev1.ExampleV1Interface - SecondExampleV1() secondexamplev1.SecondExampleV1Interface - // Deprecated: please explicitly pick a version if possible. - SecondExample() secondexamplev1.SecondExampleV1Interface -} - -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. -type Clientset struct { - *discovery.DiscoveryClient - exampleV1 *examplev1.ExampleV1Client - secondExampleV1 *secondexamplev1.SecondExampleV1Client -} - -// ExampleV1 retrieves the ExampleV1Client -func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { - return c.exampleV1 -} - -// Deprecated: Example retrieves the default version of ExampleClient. -// Please explicitly pick a version. -func (c *Clientset) Example() examplev1.ExampleV1Interface { - return c.exampleV1 -} - -// SecondExampleV1 retrieves the SecondExampleV1Client -func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { - return c.secondExampleV1 -} - -// Deprecated: SecondExample retrieves the default version of SecondExampleClient. -// Please explicitly pick a version. -func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { - return c.secondExampleV1 -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - var cs Clientset - var err error - cs.exampleV1, err = examplev1.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - cs.secondExampleV1, err = secondexamplev1.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.exampleV1 = examplev1.NewForConfigOrDie(c) - cs.secondExampleV1 = secondexamplev1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.exampleV1 = examplev1.New(c) - cs.secondExampleV1 = secondexamplev1.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go deleted file mode 100644 index 41721ca52..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go deleted file mode 100644 index 4ad8bba75..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/clientset_generated.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" - clientset "k8s.io/code-generator/_examples/crd/clientset/versioned" - examplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1" - fakeexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake" - secondexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1" - fakesecondexamplev1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -var _ clientset.Interface = &Clientset{} - -// ExampleV1 retrieves the ExampleV1Client -func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { - return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} -} - -// Example retrieves the ExampleV1Client -func (c *Clientset) Example() examplev1.ExampleV1Interface { - return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} -} - -// SecondExampleV1 retrieves the SecondExampleV1Client -func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { - return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} -} - -// SecondExample retrieves the SecondExampleV1Client -func (c *Clientset) SecondExample() secondexamplev1.SecondExampleV1Interface { - return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go deleted file mode 100644 index 9b99e7167..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated fake clientset. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go deleted file mode 100644 index f3fd49d0d..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/fake/register.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - secondexamplev1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) -var parameterCodec = runtime.NewParameterCodec(scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - examplev1.AddToScheme, - secondexamplev1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go deleted file mode 100644 index 7dc375616..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go deleted file mode 100644 index a98fc7ea7..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/scheme/register.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package scheme - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - secondexamplev1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - examplev1.AddToScheme, - secondexamplev1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(Scheme)) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go deleted file mode 100644 index 30e0e7498..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go +++ /dev/null @@ -1,193 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - scheme "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" - autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" -) - -// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. -// A group's client should implement this interface. -type ClusterTestTypesGetter interface { - ClusterTestTypes() ClusterTestTypeInterface -} - -// ClusterTestTypeInterface has methods to work with ClusterTestType resources. -type ClusterTestTypeInterface interface { - Create(*v1.ClusterTestType) (*v1.ClusterTestType, error) - Update(*v1.ClusterTestType) (*v1.ClusterTestType, error) - UpdateStatus(*v1.ClusterTestType) (*v1.ClusterTestType, error) - Delete(name string, options *metav1.DeleteOptions) error - DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error - Get(name string, options metav1.GetOptions) (*v1.ClusterTestType, error) - List(opts metav1.ListOptions) (*v1.ClusterTestTypeList, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterTestType, err error) - GetScale(clusterTestTypeName string, options metav1.GetOptions) (*autoscaling.Scale, error) - UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (*autoscaling.Scale, error) - - ClusterTestTypeExpansion -} - -// clusterTestTypes implements ClusterTestTypeInterface -type clusterTestTypes struct { - client rest.Interface -} - -// newClusterTestTypes returns a ClusterTestTypes -func newClusterTestTypes(c *ExampleV1Client) *clusterTestTypes { - return &clusterTestTypes{ - client: c.RESTClient(), - } -} - -// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. -func (c *clusterTestTypes) Get(name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { - result = &v1.ClusterTestType{} - err = c.client.Get(). - Resource("clustertesttypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. -func (c *clusterTestTypes) List(opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { - result = &v1.ClusterTestTypeList{} - err = c.client.Get(). - Resource("clustertesttypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested clusterTestTypes. -func (c *clusterTestTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Resource("clustertesttypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. -func (c *clusterTestTypes) Create(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { - result = &v1.ClusterTestType{} - err = c.client.Post(). - Resource("clustertesttypes"). - Body(clusterTestType). - Do(). - Into(result) - return -} - -// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. -func (c *clusterTestTypes) Update(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { - result = &v1.ClusterTestType{} - err = c.client.Put(). - Resource("clustertesttypes"). - Name(clusterTestType.Name). - Body(clusterTestType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *clusterTestTypes) UpdateStatus(clusterTestType *v1.ClusterTestType) (result *v1.ClusterTestType, err error) { - result = &v1.ClusterTestType{} - err = c.client.Put(). - Resource("clustertesttypes"). - Name(clusterTestType.Name). - SubResource("status"). - Body(clusterTestType). - Do(). - Into(result) - return -} - -// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. -func (c *clusterTestTypes) Delete(name string, options *metav1.DeleteOptions) error { - return c.client.Delete(). - Resource("clustertesttypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *clusterTestTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { - return c.client.Delete(). - Resource("clustertesttypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched clusterTestType. -func (c *clusterTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.ClusterTestType, err error) { - result = &v1.ClusterTestType{} - err = c.client.Patch(pt). - Resource("clustertesttypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} - -// GetScale takes name of the clusterTestType, and returns the corresponding autoscaling.Scale object, and an error if there is any. -func (c *clusterTestTypes) GetScale(clusterTestTypeName string, options metav1.GetOptions) (result *autoscaling.Scale, err error) { - result = &autoscaling.Scale{} - err = c.client.Get(). - Resource("clustertesttypes"). - Name(clusterTestTypeName). - SubResource("scale"). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. -func (c *clusterTestTypes) UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (result *autoscaling.Scale, err error) { - result = &autoscaling.Scale{} - err = c.client.Put(). - Resource("clustertesttypes"). - Name(clusterTestTypeName). - SubResource("scale"). - Body(scale). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go deleted file mode 100644 index 3af5d054f..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go deleted file mode 100644 index 25d80728c..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/example_client.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" -) - -type ExampleV1Interface interface { - RESTClient() rest.Interface - ClusterTestTypesGetter - TestTypesGetter -} - -// ExampleV1Client is used to interact with features provided by the example.crd.code-generator.k8s.io group. -type ExampleV1Client struct { - restClient rest.Interface -} - -func (c *ExampleV1Client) ClusterTestTypes() ClusterTestTypeInterface { - return newClusterTestTypes(c) -} - -func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { - return newTestTypes(c, namespace) -} - -// NewForConfig creates a new ExampleV1Client for the given config. -func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &ExampleV1Client{client}, nil -} - -// NewForConfigOrDie creates a new ExampleV1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new ExampleV1Client for the given RESTClient. -func New(c rest.Interface) *ExampleV1Client { - return &ExampleV1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *ExampleV1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go deleted file mode 100644 index 16f443990..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go deleted file mode 100644 index e0b0376b8..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go +++ /dev/null @@ -1,152 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" -) - -// FakeClusterTestTypes implements ClusterTestTypeInterface -type FakeClusterTestTypes struct { - Fake *FakeExampleV1 -} - -var clustertesttypesResource = schema.GroupVersionResource{Group: "example.crd.code-generator.k8s.io", Version: "v1", Resource: "clustertesttypes"} - -var clustertesttypesKind = schema.GroupVersionKind{Group: "example.crd.code-generator.k8s.io", Version: "v1", Kind: "ClusterTestType"} - -// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. -func (c *FakeClusterTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.ClusterTestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootGetAction(clustertesttypesResource, name), &examplev1.ClusterTestType{}) - if obj == nil { - return nil, err - } - return obj.(*examplev1.ClusterTestType), err -} - -// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. -func (c *FakeClusterTestTypes) List(opts v1.ListOptions) (result *examplev1.ClusterTestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootListAction(clustertesttypesResource, clustertesttypesKind, opts), &examplev1.ClusterTestTypeList{}) - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &examplev1.ClusterTestTypeList{ListMeta: obj.(*examplev1.ClusterTestTypeList).ListMeta} - for _, item := range obj.(*examplev1.ClusterTestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested clusterTestTypes. -func (c *FakeClusterTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewRootWatchAction(clustertesttypesResource, opts)) -} - -// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. -func (c *FakeClusterTestTypes) Create(clusterTestType *examplev1.ClusterTestType) (result *examplev1.ClusterTestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootCreateAction(clustertesttypesResource, clusterTestType), &examplev1.ClusterTestType{}) - if obj == nil { - return nil, err - } - return obj.(*examplev1.ClusterTestType), err -} - -// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. -func (c *FakeClusterTestTypes) Update(clusterTestType *examplev1.ClusterTestType) (result *examplev1.ClusterTestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootUpdateAction(clustertesttypesResource, clusterTestType), &examplev1.ClusterTestType{}) - if obj == nil { - return nil, err - } - return obj.(*examplev1.ClusterTestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeClusterTestTypes) UpdateStatus(clusterTestType *examplev1.ClusterTestType) (*examplev1.ClusterTestType, error) { - obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(clustertesttypesResource, "status", clusterTestType), &examplev1.ClusterTestType{}) - if obj == nil { - return nil, err - } - return obj.(*examplev1.ClusterTestType), err -} - -// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. -func (c *FakeClusterTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewRootDeleteAction(clustertesttypesResource, name), &examplev1.ClusterTestType{}) - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeClusterTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewRootDeleteCollectionAction(clustertesttypesResource, listOptions) - - _, err := c.Fake.Invokes(action, &examplev1.ClusterTestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched clusterTestType. -func (c *FakeClusterTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.ClusterTestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootPatchSubresourceAction(clustertesttypesResource, name, data, subresources...), &examplev1.ClusterTestType{}) - if obj == nil { - return nil, err - } - return obj.(*examplev1.ClusterTestType), err -} - -// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. -func (c *FakeClusterTestTypes) GetScale(clusterTestTypeName string, options v1.GetOptions) (result *autoscaling.Scale, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootGetSubresourceAction(clustertesttypesResource, clusterTestTypeName), &autoscaling.Scale{}) - if obj == nil { - return nil, err - } - return obj.(*autoscaling.Scale), err -} - -// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. -func (c *FakeClusterTestTypes) UpdateScale(clusterTestTypeName string, scale *autoscaling.Scale) (result *autoscaling.Scale, err error) { - obj, err := c.Fake. - Invokes(testing.NewRootUpdateSubresourceAction(clustertesttypesResource, "scale", scale), &autoscaling.Scale{}) - if obj == nil { - return nil, err - } - return obj.(*autoscaling.Scale), err -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go deleted file mode 100644 index e6aa99993..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - v1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1" -) - -type FakeExampleV1 struct { - *testing.Fake -} - -func (c *FakeExampleV1) ClusterTestTypes() v1.ClusterTestTypeInterface { - return &FakeClusterTestTypes{c} -} - -func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { - return &FakeTestTypes{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeExampleV1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go deleted file mode 100644 index b284a5797..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" -) - -// FakeTestTypes implements TestTypeInterface -type FakeTestTypes struct { - Fake *FakeExampleV1 - ns string -} - -var testtypesResource = schema.GroupVersionResource{Group: "example.crd.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} - -var testtypesKind = schema.GroupVersionKind{Group: "example.crd.code-generator.k8s.io", Version: "v1", Kind: "TestType"} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *examplev1.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &examplev1.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &examplev1.TestTypeList{ListMeta: obj.(*examplev1.TestTypeList).ListMeta} - for _, item := range obj.(*examplev1.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Create(testType *examplev1.TestType) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Update(testType *examplev1.TestType) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTestTypes) UpdateStatus(testType *examplev1.TestType) (*examplev1.TestType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &examplev1.TestType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &examplev1.TestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched testType. -func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *examplev1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, data, subresources...), &examplev1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*examplev1.TestType), err -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go deleted file mode 100644 index 6fafb1e1b..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example/v1/testtype.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - scheme "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" -) - -// TestTypesGetter has a method to return a TestTypeInterface. -// A group's client should implement this interface. -type TestTypesGetter interface { - TestTypes(namespace string) TestTypeInterface -} - -// TestTypeInterface has methods to work with TestType resources. -type TestTypeInterface interface { - Create(*v1.TestType) (*v1.TestType, error) - Update(*v1.TestType) (*v1.TestType, error) - UpdateStatus(*v1.TestType) (*v1.TestType, error) - Delete(name string, options *metav1.DeleteOptions) error - DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error - Get(name string, options metav1.GetOptions) (*v1.TestType, error) - List(opts metav1.ListOptions) (*v1.TestTypeList, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) - TestTypeExpansion -} - -// testTypes implements TestTypeInterface -type testTypes struct { - client rest.Interface - ns string -} - -// newTestTypes returns a TestTypes -func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { - return &testTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { - result = &v1.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("testtypes"). - Body(testType). - Do(). - Into(result) - return -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - Body(testType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - SubResource("status"). - Body(testType). - Do(). - Into(result) - return -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched testType. -func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("testtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go deleted file mode 100644 index 3af5d054f..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1 diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go deleted file mode 100644 index 210b6509f..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/example2_client.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" - "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" -) - -type SecondExampleV1Interface interface { - RESTClient() rest.Interface - TestTypesGetter -} - -// SecondExampleV1Client is used to interact with features provided by the example.test.crd.code-generator.k8s.io group. -type SecondExampleV1Client struct { - restClient rest.Interface -} - -func (c *SecondExampleV1Client) TestTypes(namespace string) TestTypeInterface { - return newTestTypes(c, namespace) -} - -// NewForConfig creates a new SecondExampleV1Client for the given config. -func NewForConfig(c *rest.Config) (*SecondExampleV1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &SecondExampleV1Client{client}, nil -} - -// NewForConfigOrDie creates a new SecondExampleV1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *SecondExampleV1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new SecondExampleV1Client for the given RESTClient. -func New(c rest.Interface) *SecondExampleV1Client { - return &SecondExampleV1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *SecondExampleV1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go deleted file mode 100644 index 16f443990..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go deleted file mode 100644 index 0d55a6b8e..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go +++ /dev/null @@ -1,40 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - v1 "k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1" -) - -type FakeSecondExampleV1 struct { - *testing.Fake -} - -func (c *FakeSecondExampleV1) TestTypes(namespace string) v1.TestTypeInterface { - return &FakeTestTypes{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeSecondExampleV1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go deleted file mode 100644 index 7c37bd816..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - example2v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" -) - -// FakeTestTypes implements TestTypeInterface -type FakeTestTypes struct { - Fake *FakeSecondExampleV1 - ns string -} - -var testtypesResource = schema.GroupVersionResource{Group: "example.test.crd.code-generator.k8s.io", Version: "v1", Resource: "testtypes"} - -var testtypesKind = schema.GroupVersionKind{Group: "example.test.crd.code-generator.k8s.io", Version: "v1", Kind: "TestType"} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *example2v1.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &example2v1.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &example2v1.TestTypeList{ListMeta: obj.(*example2v1.TestTypeList).ListMeta} - for _, item := range obj.(*example2v1.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Create(testType *example2v1.TestType) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *FakeTestTypes) Update(testType *example2v1.TestType) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(testtypesResource, c.ns, testType), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeTestTypes) UpdateStatus(testType *example2v1.TestType) (*example2v1.TestType, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(testtypesResource, "status", c.ns, testType), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *FakeTestTypes) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(testtypesResource, c.ns, name), &example2v1.TestType{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(testtypesResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &example2v1.TestTypeList{}) - return err -} - -// Patch applies the patch and returns the patched testType. -func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *example2v1.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(testtypesResource, c.ns, name, data, subresources...), &example2v1.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*example2v1.TestType), err -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go deleted file mode 100644 index d513810d0..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -type TestTypeExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go deleted file mode 100644 index 69b0e64c5..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/clientset/versioned/typed/example2/v1/testtype.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" - scheme "k8s.io/code-generator/_examples/crd/clientset/versioned/scheme" -) - -// TestTypesGetter has a method to return a TestTypeInterface. -// A group's client should implement this interface. -type TestTypesGetter interface { - TestTypes(namespace string) TestTypeInterface -} - -// TestTypeInterface has methods to work with TestType resources. -type TestTypeInterface interface { - Create(*v1.TestType) (*v1.TestType, error) - Update(*v1.TestType) (*v1.TestType, error) - UpdateStatus(*v1.TestType) (*v1.TestType, error) - Delete(name string, options *metav1.DeleteOptions) error - DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error - Get(name string, options metav1.GetOptions) (*v1.TestType, error) - List(opts metav1.ListOptions) (*v1.TestTypeList, error) - Watch(opts metav1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) - TestTypeExpansion -} - -// testTypes implements TestTypeInterface -type testTypes struct { - client rest.Interface - ns string -} - -// newTestTypes returns a TestTypes -func newTestTypes(c *SecondExampleV1Client, namespace string) *testTypes { - return &testTypes{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options metav1.GetOptions) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts metav1.ListOptions) (result *v1.TestTypeList, err error) { - result = &v1.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts metav1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Create(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Post(). - Namespace(c.ns). - Resource("testtypes"). - Body(testType). - Do(). - Into(result) - return -} - -// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. -func (c *testTypes) Update(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - Body(testType). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *testTypes) UpdateStatus(testType *v1.TestType) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Put(). - Namespace(c.ns). - Resource("testtypes"). - Name(testType.Name). - SubResource("status"). - Body(testType). - Do(). - Into(result) - return -} - -// Delete takes name of the testType and deletes it. Returns an error if one occurs. -func (c *testTypes) Delete(name string, options *metav1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *testTypes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched testType. -func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.TestType, err error) { - result = &v1.TestType{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("testtypes"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go deleted file mode 100644 index 10c18944c..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package example - -import ( - v1 "k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1" - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1 provides access to shared informers for resources in V1. - V1() v1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1 returns a new v1.Interface. -func (g *group) V1() v1.Interface { - return v1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go deleted file mode 100644 index 13c38e44f..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/clustertesttype.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - time "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" - v1 "k8s.io/code-generator/_examples/crd/listers/example/v1" -) - -// ClusterTestTypeInformer provides access to a shared informer and lister for -// ClusterTestTypes. -type ClusterTestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.ClusterTestTypeLister -} - -type clusterTestTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) -} - -// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleV1().ClusterTestTypes().List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleV1().ClusterTestTypes().Watch(options) - }, - }, - &examplev1.ClusterTestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&examplev1.ClusterTestType{}, f.defaultInformer) -} - -func (f *clusterTestTypeInformer) Lister() v1.ClusterTestTypeLister { - return v1.NewClusterTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go deleted file mode 100644 index 1e17b1325..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/interface.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // ClusterTestTypes returns a ClusterTestTypeInformer. - ClusterTestTypes() ClusterTestTypeInformer - // TestTypes returns a TestTypeInformer. - TestTypes() TestTypeInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// ClusterTestTypes returns a ClusterTestTypeInformer. -func (v *version) ClusterTestTypes() ClusterTestTypeInformer { - return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} -} - -// TestTypes returns a TestTypeInformer. -func (v *version) TestTypes() TestTypeInformer { - return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go deleted file mode 100644 index 47ca5b287..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example/v1/testtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - time "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - examplev1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" - v1 "k8s.io/code-generator/_examples/crd/listers/example/v1" -) - -// TestTypeInformer provides access to a shared informer and lister for -// TestTypes. -type TestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.TestTypeLister -} - -type testTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleV1().TestTypes(namespace).List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleV1().TestTypes(namespace).Watch(options) - }, - }, - &examplev1.TestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *testTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&examplev1.TestType{}, f.defaultInformer) -} - -func (f *testTypeInformer) Lister() v1.TestTypeLister { - return v1.NewTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go deleted file mode 100644 index 9e00c7b80..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/interface.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package example - -import ( - v1 "k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1" - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" -) - -// Interface provides access to each of this group's versions. -type Interface interface { - // V1 provides access to shared informers for resources in V1. - V1() v1.Interface -} - -type group struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// V1 returns a new v1.Interface. -func (g *group) V1() v1.Interface { - return v1.New(g.factory, g.namespace, g.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go deleted file mode 100644 index 024352284..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/interface.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" -) - -// Interface provides access to all the informers in this group version. -type Interface interface { - // TestTypes returns a TestTypeInformer. - TestTypes() TestTypeInformer -} - -type version struct { - factory internalinterfaces.SharedInformerFactory - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc -} - -// New returns a new Interface. -func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { - return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} -} - -// TestTypes returns a TestTypeInformer. -func (v *version) TestTypes() TestTypeInformer { - return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go deleted file mode 100644 index eb99c32d0..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/example2/v1/testtype.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1 - -import ( - time "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - example2v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" - versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" - v1 "k8s.io/code-generator/_examples/crd/listers/example2/v1" -) - -// TestTypeInformer provides access to a shared informer and lister for -// TestTypes. -type TestTypeInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1.TestTypeLister -} - -type testTypeInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredTestTypeInformer constructs a new informer for TestType type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SecondExampleV1().TestTypes(namespace).List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SecondExampleV1().TestTypes(namespace).Watch(options) - }, - }, - &example2v1.TestType{}, - resyncPeriod, - indexers, - ) -} - -func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *testTypeInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&example2v1.TestType{}, f.defaultInformer) -} - -func (f *testTypeInformer) Lister() v1.TestTypeLister { - return v1.NewTestTypeLister(f.Informer().GetIndexer()) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go deleted file mode 100644 index 7d6d1f934..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/factory.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - reflect "reflect" - sync "sync" - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" - versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" - example "k8s.io/code-generator/_examples/crd/informers/externalversions/example" - example2 "k8s.io/code-generator/_examples/crd/informers/externalversions/example2" - internalinterfaces "k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces" -) - -// SharedInformerOption defines the functional option type for SharedInformerFactory. -type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory - -type sharedInformerFactory struct { - client versioned.Interface - namespace string - tweakListOptions internalinterfaces.TweakListOptionsFunc - lock sync.Mutex - defaultResync time.Duration - customResync map[reflect.Type]time.Duration - - informers map[reflect.Type]cache.SharedIndexInformer - // startedInformers is used for tracking which informers have been started. - // This allows Start() to be called multiple times safely. - startedInformers map[reflect.Type]bool -} - -// WithCustomResyncConfig sets a custom resync period for the specified informer types. -func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - for k, v := range resyncConfig { - factory.customResync[reflect.TypeOf(k)] = v - } - return factory - } -} - -// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. -func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.tweakListOptions = tweakListOptions - return factory - } -} - -// WithNamespace limits the SharedInformerFactory to the specified namespace. -func WithNamespace(namespace string) SharedInformerOption { - return func(factory *sharedInformerFactory) *sharedInformerFactory { - factory.namespace = namespace - return factory - } -} - -// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. -func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync) -} - -// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. -// Listers obtained via this SharedInformerFactory will be subject to the same filters -// as specified here. -// Deprecated: Please use NewSharedInformerFactoryWithOptions instead -func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { - return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) -} - -// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. -func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { - factory := &sharedInformerFactory{ - client: client, - namespace: v1.NamespaceAll, - defaultResync: defaultResync, - informers: make(map[reflect.Type]cache.SharedIndexInformer), - startedInformers: make(map[reflect.Type]bool), - customResync: make(map[reflect.Type]time.Duration), - } - - // Apply all options - for _, opt := range options { - factory = opt(factory) - } - - return factory -} - -// Start initializes all requested informers. -func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { - f.lock.Lock() - defer f.lock.Unlock() - - for informerType, informer := range f.informers { - if !f.startedInformers[informerType] { - go informer.Run(stopCh) - f.startedInformers[informerType] = true - } - } -} - -// WaitForCacheSync waits for all started informers' cache were synced. -func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { - informers := func() map[reflect.Type]cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informers := map[reflect.Type]cache.SharedIndexInformer{} - for informerType, informer := range f.informers { - if f.startedInformers[informerType] { - informers[informerType] = informer - } - } - return informers - }() - - res := map[reflect.Type]bool{} - for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) - } - return res -} - -// InternalInformerFor returns the SharedIndexInformer for obj using an internal -// client. -func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { - f.lock.Lock() - defer f.lock.Unlock() - - informerType := reflect.TypeOf(obj) - informer, exists := f.informers[informerType] - if exists { - return informer - } - - resyncPeriod, exists := f.customResync[informerType] - if !exists { - resyncPeriod = f.defaultResync - } - - informer = newFunc(f.client, resyncPeriod) - f.informers[informerType] = informer - - return informer -} - -// SharedInformerFactory provides shared informers for resources in all known -// API group versions. -type SharedInformerFactory interface { - internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) - WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - - Example() example.Interface - SecondExample() example2.Interface -} - -func (f *sharedInformerFactory) Example() example.Interface { - return example.New(f, f.namespace, f.tweakListOptions) -} - -func (f *sharedInformerFactory) SecondExample() example2.Interface { - return example2.New(f, f.namespace, f.tweakListOptions) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go deleted file mode 100644 index f6b1174c6..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/generic.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package externalversions - -import ( - "fmt" - - schema "k8s.io/apimachinery/pkg/runtime/schema" - cache "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" - example2v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" -) - -// GenericInformer is type of SharedIndexInformer which will locate and delegate to other -// sharedInformers based on type -type GenericInformer interface { - Informer() cache.SharedIndexInformer - Lister() cache.GenericLister -} - -type genericInformer struct { - informer cache.SharedIndexInformer - resource schema.GroupResource -} - -// Informer returns the SharedIndexInformer. -func (f *genericInformer) Informer() cache.SharedIndexInformer { - return f.informer -} - -// Lister returns the GenericLister. -func (f *genericInformer) Lister() cache.GenericLister { - return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) -} - -// ForResource gives generic access to a shared informer of the matching type -// TODO extend this to unknown resources with a client pool -func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { - switch resource { - // Group=example.crd.code-generator.k8s.io, Version=v1 - case v1.SchemeGroupVersion.WithResource("clustertesttypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().ClusterTestTypes().Informer()}, nil - case v1.SchemeGroupVersion.WithResource("testtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil - - // Group=example.test.crd.code-generator.k8s.io, Version=v1 - case example2v1.SchemeGroupVersion.WithResource("testtypes"): - return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().V1().TestTypes().Informer()}, nil - - } - - return nil, fmt.Errorf("no informer found for %v", resource) -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go deleted file mode 100644 index 02e0d6ac3..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package internalinterfaces - -import ( - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - cache "k8s.io/client-go/tools/cache" - versioned "k8s.io/code-generator/_examples/crd/clientset/versioned" -) - -type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer - -// SharedInformerFactory a small interface to allow for adding an informer without an import cycle -type SharedInformerFactory interface { - Start(stopCh <-chan struct{}) - InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer -} - -type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go deleted file mode 100644 index 584b3b273..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/clustertesttype.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" -) - -// ClusterTestTypeLister helps list ClusterTestTypes. -type ClusterTestTypeLister interface { - // List lists all ClusterTestTypes in the indexer. - List(selector labels.Selector) (ret []*v1.ClusterTestType, err error) - // Get retrieves the ClusterTestType from the index for a given name. - Get(name string) (*v1.ClusterTestType, error) - ClusterTestTypeListerExpansion -} - -// clusterTestTypeLister implements the ClusterTestTypeLister interface. -type clusterTestTypeLister struct { - indexer cache.Indexer -} - -// NewClusterTestTypeLister returns a new ClusterTestTypeLister. -func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { - return &clusterTestTypeLister{indexer: indexer} -} - -// List lists all ClusterTestTypes in the indexer. -func (s *clusterTestTypeLister) List(selector labels.Selector) (ret []*v1.ClusterTestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.ClusterTestType)) - }) - return ret, err -} - -// Get retrieves the ClusterTestType from the index for a given name. -func (s *clusterTestTypeLister) Get(name string) (*v1.ClusterTestType, error) { - obj, exists, err := s.indexer.GetByKey(name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("clustertesttype"), name) - } - return obj.(*v1.ClusterTestType), nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go deleted file mode 100644 index 2681a29f4..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/expansion_generated.go +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -// ClusterTestTypeListerExpansion allows custom methods to be added to -// ClusterTestTypeLister. -type ClusterTestTypeListerExpansion interface{} - -// TestTypeListerExpansion allows custom methods to be added to -// TestTypeLister. -type TestTypeListerExpansion interface{} - -// TestTypeNamespaceListerExpansion allows custom methods to be added to -// TestTypeNamespaceLister. -type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go deleted file mode 100644 index 7055b6cc4..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/listers/example/v1/testtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/crd/apis/example/v1" -) - -// TestTypeLister helps list TestTypes. -type TestTypeLister interface { - // List lists all TestTypes in the indexer. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // TestTypes returns an object that can list and get TestTypes. - TestTypes(namespace string) TestTypeNamespaceLister - TestTypeListerExpansion -} - -// testTypeLister implements the TestTypeLister interface. -type testTypeLister struct { - indexer cache.Indexer -} - -// NewTestTypeLister returns a new TestTypeLister. -func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { - return &testTypeLister{indexer: indexer} -} - -// List lists all TestTypes in the indexer. -func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// TestTypes returns an object that can list and get TestTypes. -func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { - return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// TestTypeNamespaceLister helps list and get TestTypes. -type TestTypeNamespaceLister interface { - // List lists all TestTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // Get retrieves the TestType from the indexer for a given namespace and name. - Get(name string) (*v1.TestType, error) - TestTypeNamespaceListerExpansion -} - -// testTypeNamespaceLister implements the TestTypeNamespaceLister -// interface. -type testTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TestTypes in the indexer for a given namespace. -func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// Get retrieves the TestType from the indexer for a given namespace and name. -func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("testtype"), name) - } - return obj.(*v1.TestType), nil -} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go deleted file mode 100644 index 0192e05f0..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/expansion_generated.go +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -// TestTypeListerExpansion allows custom methods to be added to -// TestTypeLister. -type TestTypeListerExpansion interface{} - -// TestTypeNamespaceListerExpansion allows custom methods to be added to -// TestTypeNamespaceLister. -type TestTypeNamespaceListerExpansion interface{} diff --git a/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go b/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go deleted file mode 100644 index d3b15c0b9..000000000 --- a/vendor/k8s.io/code-generator/_examples/crd/listers/example2/v1/testtype.go +++ /dev/null @@ -1,94 +0,0 @@ -/* -Copyright 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1 - -import ( - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" - v1 "k8s.io/code-generator/_examples/crd/apis/example2/v1" -) - -// TestTypeLister helps list TestTypes. -type TestTypeLister interface { - // List lists all TestTypes in the indexer. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // TestTypes returns an object that can list and get TestTypes. - TestTypes(namespace string) TestTypeNamespaceLister - TestTypeListerExpansion -} - -// testTypeLister implements the TestTypeLister interface. -type testTypeLister struct { - indexer cache.Indexer -} - -// NewTestTypeLister returns a new TestTypeLister. -func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { - return &testTypeLister{indexer: indexer} -} - -// List lists all TestTypes in the indexer. -func (s *testTypeLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// TestTypes returns an object that can list and get TestTypes. -func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { - return testTypeNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// TestTypeNamespaceLister helps list and get TestTypes. -type TestTypeNamespaceLister interface { - // List lists all TestTypes in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1.TestType, err error) - // Get retrieves the TestType from the indexer for a given namespace and name. - Get(name string) (*v1.TestType, error) - TestTypeNamespaceListerExpansion -} - -// testTypeNamespaceLister implements the TestTypeNamespaceLister -// interface. -type testTypeNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all TestTypes in the indexer for a given namespace. -func (s testTypeNamespaceLister) List(selector labels.Selector) (ret []*v1.TestType, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1.TestType)) - }) - return ret, err -} - -// Get retrieves the TestType from the indexer for a given namespace and name. -func (s testTypeNamespaceLister) Get(name string) (*v1.TestType, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1.Resource("testtype"), name) - } - return obj.(*v1.TestType), nil -} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages_test.go b/vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages_test.go new file mode 100644 index 000000000..f8891bec8 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/args/gvpackages_test.go @@ -0,0 +1,116 @@ +/* +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 args + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "github.com/spf13/pflag" + + "k8s.io/code-generator/cmd/client-gen/types" +) + +func TestGVPackageFlag(t *testing.T) { + tests := []struct { + args []string + def []string + importBasePath string + expected map[types.GroupVersion]string + expectedGroups []types.GroupVersions + parseError string + }{ + { + args: []string{}, + expected: map[types.GroupVersion]string{}, + expectedGroups: []types.GroupVersions{}, + }, + { + args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"}, + expectedGroups: []types.GroupVersions{ + {PackageName: "bar", Group: types.Group("bar"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/bar/v1"}, + {Version: "v2", Package: "foo/bar/v2"}, + {Version: "", Package: "foo/bar"}, + }}, + {PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/v1"}, + }}, + }, + }, + { + args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"}, + def: []string{"foo/bar/v1alpha1", "foo/v1"}, + expectedGroups: []types.GroupVersions{ + {PackageName: "bar", Group: types.Group("bar"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/bar/v1"}, + {Version: "v2", Package: "foo/bar/v2"}, + {Version: "", Package: "foo/bar"}, + }}, + {PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/v1"}, + }}, + }, + }, + { + args: []string{"api/v1", "api"}, + expectedGroups: []types.GroupVersions{ + {PackageName: "core", Group: types.Group("api"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "core/v1"}, + {Version: "", Package: "core"}, + }}, + }, + }, + { + args: []string{"foo/v1"}, + importBasePath: "k8s.io/api", + expectedGroups: []types.GroupVersions{ + {PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "k8s.io/api/foo/v1"}, + }}, + }, + }, + } + for i, test := range tests { + fs := pflag.NewFlagSet("testGVPackage", pflag.ContinueOnError) + groups := []types.GroupVersions{} + builder := NewGroupVersionsBuilder(&groups) + fs.Var(NewGVPackagesValue(builder, test.def), "input", "usage") + fs.Var(NewInputBasePathValue(builder, test.importBasePath), "input-base-path", "usage") + + args := []string{} + for _, a := range test.args { + args = append(args, fmt.Sprintf("--input=%s", a)) + } + + err := fs.Parse(args) + if test.parseError != "" { + if err == nil { + t.Errorf("%d: expected error %q, got nil", i, test.parseError) + } else if !strings.Contains(err.Error(), test.parseError) { + t.Errorf("%d: expected error %q, got %q", i, test.parseError, err) + } + } else if err != nil { + t.Errorf("%d: expected nil error, got %v", i, err) + } + if !reflect.DeepEqual(groups, test.expectedGroups) { + t.Errorf("%d: expected groups %+v, got groups %+v", i, test.expectedGroups, groups) + } + } +} diff --git a/vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags_test.go b/vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags_test.go new file mode 100644 index 000000000..a5c938754 --- /dev/null +++ b/vendor/k8s.io/code-generator/cmd/client-gen/generators/util/tags_test.go @@ -0,0 +1,148 @@ +/* +Copyright 2016 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 util + +import ( + "reflect" + "testing" +) + +func TestParseTags(t *testing.T) { + testCases := map[string]struct { + lines []string + expectTags Tags + expectError bool + }{ + "genclient": { + lines: []string{`+genclient`}, + expectTags: Tags{GenerateClient: true}, + }, + "genclient=true": { + lines: []string{`+genclient=true`}, + expectError: true, + }, + "nonNamespaced=true": { + lines: []string{`+genclient=true`, `+nonNamespaced=true`}, + expectError: true, + }, + "readonly=true": { + lines: []string{`+genclient=true`, `+readonly=true`}, + expectError: true, + }, + "genclient:nonNamespaced": { + lines: []string{`+genclient`, `+genclient:nonNamespaced`}, + expectTags: Tags{GenerateClient: true, NonNamespaced: true}, + }, + "genclient:noVerbs": { + lines: []string{`+genclient`, `+genclient:noVerbs`}, + expectTags: Tags{GenerateClient: true, NoVerbs: true}, + }, + "genclient:noStatus": { + lines: []string{`+genclient`, `+genclient:noStatus`}, + expectTags: Tags{GenerateClient: true, NoStatus: true}, + }, + "genclient:onlyVerbs": { + lines: []string{`+genclient`, `+genclient:onlyVerbs=create,delete`}, + expectTags: Tags{GenerateClient: true, SkipVerbs: []string{"update", "updateStatus", "deleteCollection", "get", "list", "watch", "patch"}}, + }, + "genclient:readonly": { + lines: []string{`+genclient`, `+genclient:readonly`}, + expectTags: Tags{GenerateClient: true, SkipVerbs: []string{"create", "update", "updateStatus", "delete", "deleteCollection", "patch"}}, + }, + "genclient:conflict": { + lines: []string{`+genclient`, `+genclient:onlyVerbs=create`, `+genclient:skipVerbs=create`}, + expectError: true, + }, + "genclient:invalid": { + lines: []string{`+genclient`, `+genclient:invalid`}, + expectError: true, + }, + } + for key, c := range testCases { + result, err := ParseClientGenTags(c.lines) + if err != nil && !c.expectError { + t.Fatalf("unexpected error: %v", err) + } + if !c.expectError && !reflect.DeepEqual(result, c.expectTags) { + t.Errorf("[%s] expected %#v to be %#v", key, result, c.expectTags) + } + } +} + +func TestParseTagsExtension(t *testing.T) { + testCases := map[string]struct { + lines []string + expectedExtensions []extension + expectError bool + }{ + "simplest extension": { + lines: []string{`+genclient:method=Foo,verb=create`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}}, + }, + "multiple extensions": { + lines: []string{`+genclient:method=Foo,verb=create`, `+genclient:method=Bar,verb=get`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}, {VerbName: "Bar", VerbType: "get"}}, + }, + "extension without verb": { + lines: []string{`+genclient:method`}, + expectError: true, + }, + "extension without verb type": { + lines: []string{`+genclient:method=Foo`}, + expectError: true, + }, + "sub-resource extension": { + lines: []string{`+genclient:method=Foo,verb=create,subresource=bar`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create", SubResourcePath: "bar"}}, + }, + "output type extension": { + lines: []string{`+genclient:method=Foos,verb=list,result=Bars`}, + expectedExtensions: []extension{{VerbName: "Foos", VerbType: "list", ResultTypeOverride: "Bars"}}, + }, + "input type extension": { + lines: []string{`+genclient:method=Foo,verb=update,input=Bar`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "update", InputTypeOverride: "Bar"}}, + }, + "unknown verb type extension": { + lines: []string{`+genclient:method=Foo,verb=explode`}, + expectedExtensions: nil, + expectError: true, + }, + "invalid verb extension": { + lines: []string{`+genclient:method=Foo,unknown=bar`}, + expectedExtensions: nil, + expectError: true, + }, + "empty verb extension subresource": { + lines: []string{`+genclient:method=Foo,verb=get,subresource=`}, + expectedExtensions: nil, + expectError: true, + }, + } + for key, c := range testCases { + result, err := ParseClientGenTags(c.lines) + if err != nil && !c.expectError { + t.Fatalf("[%s] unexpected error: %v", key, err) + } + if err != nil && c.expectError { + t.Logf("[%s] got expected error: %+v", key, err) + } + if !c.expectError && !reflect.DeepEqual(result.Extensions, c.expectedExtensions) { + t.Errorf("[%s] expected %#+v to be %#+v", key, result.Extensions, c.expectedExtensions) + } + } +} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/tags.go b/vendor/k8s.io/code-generator/cmd/client-gen/types/helpers_test.go similarity index 59% rename from vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/tags.go rename to vendor/k8s.io/code-generator/cmd/client-gen/types/helpers_test.go index 2dff5b922..dec62dff2 100644 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/tags.go +++ b/vendor/k8s.io/code-generator/cmd/client-gen/types/helpers_test.go @@ -14,20 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -package protobuf +package types import ( - "github.com/golang/glog" - "k8s.io/gengo/types" + "reflect" + "sort" + "testing" ) -// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if -// it exists, the value is boolean. If the tag did not exist, it returns -// false. -func extractBoolTagOrDie(key string, lines []string) bool { - val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines) - if err != nil { - glog.Fatal(err) +func TestVersionSort(t *testing.T) { + unsortedVersions := []string{"v4beta1", "v2beta1", "v2alpha1", "v3", "v1"} + expected := []string{"v2alpha1", "v2beta1", "v4beta1", "v1", "v3"} + sort.Sort(sortableSliceOfVersions(unsortedVersions)) + if !reflect.DeepEqual(unsortedVersions, expected) { + t.Errorf("expected %#v\ngot %#v", expected, unsortedVersions) } - return val } diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore deleted file mode 100644 index 0e9aa466b..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/.gitignore +++ /dev/null @@ -1 +0,0 @@ -go-to-protobuf diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS deleted file mode 100644 index 05d4b2a65..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -approvers: -- smarterclayton -reviewers: -- smarterclayton diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go deleted file mode 100644 index 555073225..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/cmd.go +++ /dev/null @@ -1,349 +0,0 @@ -/* -Copyright 2015 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. -*/ - -// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any -// existing IDL tags on the Go struct. -package protobuf - -import ( - "bytes" - "fmt" - "log" - "os" - "os/exec" - "path/filepath" - "strings" - - "k8s.io/code-generator/pkg/util" - "k8s.io/gengo/args" - "k8s.io/gengo/generator" - "k8s.io/gengo/namer" - "k8s.io/gengo/parser" - "k8s.io/gengo/types" - - flag "github.com/spf13/pflag" -) - -type Generator struct { - Common args.GeneratorArgs - APIMachineryPackages string - Packages string - OutputBase string - VendorOutputBase string - ProtoImport []string - Conditional string - Clean bool - OnlyIDL bool - KeepGogoproto bool - SkipGeneratedRewrite bool - DropEmbeddedFields string -} - -func New() *Generator { - sourceTree := args.DefaultSourceTree() - common := args.GeneratorArgs{ - OutputBase: sourceTree, - GoHeaderFilePath: filepath.Join(sourceTree, util.BoilerplatePath()), - } - defaultProtoImport := filepath.Join(sourceTree, "k8s.io", "kubernetes", "vendor", "github.com", "gogo", "protobuf", "protobuf") - cwd, err := os.Getwd() - if err != nil { - log.Fatalf("Cannot get current directory.") - } - return &Generator{ - Common: common, - OutputBase: sourceTree, - VendorOutputBase: filepath.Join(cwd, "vendor"), - ProtoImport: []string{defaultProtoImport}, - APIMachineryPackages: strings.Join([]string{ - `+k8s.io/apimachinery/pkg/util/intstr`, - `+k8s.io/apimachinery/pkg/api/resource`, - `+k8s.io/apimachinery/pkg/runtime/schema`, - `+k8s.io/apimachinery/pkg/runtime`, - `k8s.io/apimachinery/pkg/apis/meta/v1`, - `k8s.io/apimachinery/pkg/apis/meta/v1beta1`, - `k8s.io/apimachinery/pkg/apis/testapigroup/v1`, - }, ","), - Packages: "", - DropEmbeddedFields: "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta", - } -} - -func (g *Generator) BindFlags(flag *flag.FlagSet) { - flag.StringVarP(&g.Common.GoHeaderFilePath, "go-header-file", "h", g.Common.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.") - flag.BoolVar(&g.Common.VerifyOnly, "verify-only", g.Common.VerifyOnly, "If true, only verify existing output, do not write anything.") - flag.StringVarP(&g.Packages, "packages", "p", g.Packages, "comma-separated list of directories to get input types from. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.") - flag.StringVar(&g.APIMachineryPackages, "apimachinery-packages", g.APIMachineryPackages, "comma-separated list of directories to get apimachinery input types from which are needed by any API. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.") - flag.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/") - flag.StringVar(&g.VendorOutputBase, "vendor-output-base", g.VendorOutputBase, "The vendor/ directory to look for packages in; defaults to $PWD/vendor/.") - flag.StringSliceVar(&g.ProtoImport, "proto-import", g.ProtoImport, "The search path for the core protobuf .protos, required; defaults $GOPATH/src/k8s.io/kubernetes/vendor/github.com/gogo/protobuf/protobuf.") - flag.StringVar(&g.Conditional, "conditional", g.Conditional, "An optional Golang build tag condition to add to the generated Go code") - flag.BoolVar(&g.Clean, "clean", g.Clean, "If true, remove all generated files for the specified Packages.") - flag.BoolVar(&g.OnlyIDL, "only-idl", g.OnlyIDL, "If true, only generate the IDL for each package.") - flag.BoolVar(&g.KeepGogoproto, "keep-gogoproto", g.KeepGogoproto, "If true, the generated IDL will contain gogoprotobuf extensions which are normally removed") - flag.BoolVar(&g.SkipGeneratedRewrite, "skip-generated-rewrite", g.SkipGeneratedRewrite, "If true, skip fixing up the generated.pb.go file (debugging only).") - flag.StringVar(&g.DropEmbeddedFields, "drop-embedded-fields", g.DropEmbeddedFields, "Comma-delimited list of embedded Go types to omit from generated protobufs") -} - -func Run(g *Generator) { - if g.Common.VerifyOnly { - g.OnlyIDL = true - g.Clean = false - } - - b := parser.New() - b.AddBuildTags("proto") - - omitTypes := map[types.Name]struct{}{} - for _, t := range strings.Split(g.DropEmbeddedFields, ",") { - name := types.Name{} - if i := strings.LastIndex(t, "."); i != -1 { - name.Package, name.Name = t[:i], t[i+1:] - } else { - name.Name = t - } - if len(name.Name) == 0 { - log.Fatalf("--drop-embedded-types requires names in the form of [GOPACKAGE.]TYPENAME: %v", t) - } - omitTypes[name] = struct{}{} - } - - boilerplate, err := g.Common.LoadGoBoilerplate() - if err != nil { - log.Fatalf("Failed loading boilerplate (consider using the go-header-file flag): %v", err) - } - - protobufNames := NewProtobufNamer() - outputPackages := generator.Packages{} - nonOutputPackages := map[string]struct{}{} - - var packages []string - if len(g.APIMachineryPackages) != 0 { - packages = append(packages, strings.Split(g.APIMachineryPackages, ",")...) - } - if len(g.Packages) != 0 { - packages = append(packages, strings.Split(g.Packages, ",")...) - } - if len(packages) == 0 { - log.Fatalf("Both apimachinery-packages and packages are empty. At least one package must be specified.") - } - - for _, d := range packages { - generateAllTypes, outputPackage := true, true - switch { - case strings.HasPrefix(d, "+"): - d = d[1:] - generateAllTypes = false - case strings.HasPrefix(d, "-"): - d = d[1:] - outputPackage = false - } - name := protoSafePackage(d) - parts := strings.SplitN(d, "=", 2) - if len(parts) > 1 { - d = parts[0] - name = parts[1] - } - p := newProtobufPackage(d, name, generateAllTypes, omitTypes) - header := append([]byte{}, boilerplate...) - header = append(header, p.HeaderText...) - p.HeaderText = header - protobufNames.Add(p) - if outputPackage { - outputPackages = append(outputPackages, p) - } else { - nonOutputPackages[name] = struct{}{} - } - } - - if !g.Common.VerifyOnly { - for _, p := range outputPackages { - if err := p.(*protobufPackage).Clean(g.OutputBase); err != nil { - log.Fatalf("Unable to clean package %s: %v", p.Name(), err) - } - } - } - - if g.Clean { - return - } - - for _, p := range protobufNames.List() { - if err := b.AddDir(p.Path()); err != nil { - log.Fatalf("Unable to add directory %q: %v", p.Path(), err) - } - } - - c, err := generator.NewContext( - b, - namer.NameSystems{ - "public": namer.NewPublicNamer(3), - "proto": protobufNames, - }, - "public", - ) - if err != nil { - log.Fatalf("Failed making a context: %v", err) - } - - c.Verify = g.Common.VerifyOnly - c.FileTypes["protoidl"] = NewProtoFile() - - var vendoredOutputPackages, localOutputPackages generator.Packages - for _, p := range protobufNames.packages { - if _, ok := nonOutputPackages[p.Name()]; ok { - // if we're not outputting the package, don't include it in either package list - continue - } - p.Vendored = strings.Contains(c.Universe[p.PackagePath].SourcePath, "/vendor/") - if p.Vendored { - vendoredOutputPackages = append(vendoredOutputPackages, p) - } else { - localOutputPackages = append(localOutputPackages, p) - } - } - - if err := protobufNames.AssignTypesToPackages(c); err != nil { - log.Fatalf("Failed to identify Common types: %v", err) - } - - if err := c.ExecutePackages(g.VendorOutputBase, vendoredOutputPackages); err != nil { - log.Fatalf("Failed executing vendor generator: %v", err) - } - if err := c.ExecutePackages(g.OutputBase, localOutputPackages); err != nil { - log.Fatalf("Failed executing local generator: %v", err) - } - - if g.OnlyIDL { - return - } - - if _, err := exec.LookPath("protoc"); err != nil { - log.Fatalf("Unable to find 'protoc': %v", err) - } - - searchArgs := []string{"-I", ".", "-I", g.OutputBase} - if len(g.ProtoImport) != 0 { - for _, s := range g.ProtoImport { - searchArgs = append(searchArgs, "-I", s) - } - } - args := append(searchArgs, fmt.Sprintf("--gogo_out=%s", g.OutputBase)) - - buf := &bytes.Buffer{} - if len(g.Conditional) > 0 { - fmt.Fprintf(buf, "// +build %s\n\n", g.Conditional) - } - buf.Write(boilerplate) - - for _, outputPackage := range outputPackages { - p := outputPackage.(*protobufPackage) - - path := filepath.Join(g.OutputBase, p.ImportPath()) - outputPath := filepath.Join(g.OutputBase, p.OutputPath()) - if p.Vendored { - path = filepath.Join(g.VendorOutputBase, p.ImportPath()) - outputPath = filepath.Join(g.VendorOutputBase, p.OutputPath()) - } - - // generate the gogoprotobuf protoc - cmd := exec.Command("protoc", append(args, path)...) - out, err := cmd.CombinedOutput() - if len(out) > 0 { - log.Printf(string(out)) - } - if err != nil { - log.Println(strings.Join(cmd.Args, " ")) - log.Fatalf("Unable to generate protoc on %s: %v", p.PackageName, err) - } - - if g.SkipGeneratedRewrite { - continue - } - - // alter the generated protobuf file to remove the generated types (but leave the serializers) and rewrite the - // package statement to match the desired package name - if err := RewriteGeneratedGogoProtobufFile(outputPath, p.ExtractGeneratedType, p.OptionalTypeName, buf.Bytes()); err != nil { - log.Fatalf("Unable to rewrite generated %s: %v", outputPath, err) - } - - // sort imports - cmd = exec.Command("goimports", "-w", outputPath) - out, err = cmd.CombinedOutput() - if len(out) > 0 { - log.Printf(string(out)) - } - if err != nil { - log.Println(strings.Join(cmd.Args, " ")) - log.Fatalf("Unable to rewrite imports for %s: %v", p.PackageName, err) - } - - // format and simplify the generated file - cmd = exec.Command("gofmt", "-s", "-w", outputPath) - out, err = cmd.CombinedOutput() - if len(out) > 0 { - log.Printf(string(out)) - } - if err != nil { - log.Println(strings.Join(cmd.Args, " ")) - log.Fatalf("Unable to apply gofmt for %s: %v", p.PackageName, err) - } - } - - if g.SkipGeneratedRewrite { - return - } - - if !g.KeepGogoproto { - // generate, but do so without gogoprotobuf extensions - for _, outputPackage := range outputPackages { - p := outputPackage.(*protobufPackage) - p.OmitGogo = true - } - if err := c.ExecutePackages(g.VendorOutputBase, vendoredOutputPackages); err != nil { - log.Fatalf("Failed executing vendor generator: %v", err) - } - if err := c.ExecutePackages(g.OutputBase, localOutputPackages); err != nil { - log.Fatalf("Failed executing local generator: %v", err) - } - } - - for _, outputPackage := range outputPackages { - p := outputPackage.(*protobufPackage) - - if len(p.StructTags) == 0 { - continue - } - - pattern := filepath.Join(g.OutputBase, p.PackagePath, "*.go") - if p.Vendored { - pattern = filepath.Join(g.VendorOutputBase, p.PackagePath, "*.go") - } - files, err := filepath.Glob(pattern) - if err != nil { - log.Fatalf("Can't glob pattern %q: %v", pattern, err) - } - - for _, s := range files { - if strings.HasSuffix(s, "_test.go") { - continue - } - if err := RewriteTypesWithProtobufStructTags(s, p.StructTags); err != nil { - log.Fatalf("Unable to rewrite with struct tags %s: %v", s, err) - } - } - } -} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go deleted file mode 100644 index 0e7a7d8ec..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/generator.go +++ /dev/null @@ -1,769 +0,0 @@ -/* -Copyright 2015 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 protobuf - -import ( - "fmt" - "io" - "log" - "reflect" - "sort" - "strconv" - "strings" - - "github.com/golang/glog" - - "k8s.io/gengo/generator" - "k8s.io/gengo/namer" - "k8s.io/gengo/types" -) - -// genProtoIDL produces a .proto IDL. -type genProtoIDL struct { - generator.DefaultGen - localPackage types.Name - localGoPackage types.Name - imports namer.ImportTracker - - generateAll bool - omitGogo bool - omitFieldTypes map[types.Name]struct{} -} - -func (g *genProtoIDL) PackageVars(c *generator.Context) []string { - if g.omitGogo { - return []string{ - fmt.Sprintf("option go_package = %q;", g.localGoPackage.Name), - } - } - return []string{ - "option (gogoproto.marshaler_all) = true;", - "option (gogoproto.stable_marshaler_all) = true;", - "option (gogoproto.sizer_all) = true;", - "option (gogoproto.goproto_stringer_all) = false;", - "option (gogoproto.stringer_all) = true;", - "option (gogoproto.unmarshaler_all) = true;", - "option (gogoproto.goproto_unrecognized_all) = false;", - "option (gogoproto.goproto_enum_prefix_all) = false;", - "option (gogoproto.goproto_getters_all) = false;", - fmt.Sprintf("option go_package = %q;", g.localGoPackage.Name), - } -} -func (g *genProtoIDL) Filename() string { return g.OptionalName + ".proto" } -func (g *genProtoIDL) FileType() string { return "protoidl" } -func (g *genProtoIDL) Namers(c *generator.Context) namer.NameSystems { - return namer.NameSystems{ - // The local namer returns the correct protobuf name for a proto type - // in the context of a package - "local": localNamer{g.localPackage}, - } -} - -// Filter ignores types that are identified as not exportable. -func (g *genProtoIDL) Filter(c *generator.Context, t *types.Type) bool { - tagVals := types.ExtractCommentTags("+", t.CommentLines)["protobuf"] - if tagVals != nil { - if tagVals[0] == "false" { - // Type specified "false". - return false - } - if tagVals[0] == "true" { - // Type specified "true". - return true - } - glog.Fatalf(`Comment tag "protobuf" must be true or false, found: %q`, tagVals[0]) - } - if !g.generateAll { - // We're not generating everything. - return false - } - seen := map[*types.Type]bool{} - ok := isProtoable(seen, t) - return ok -} - -func isProtoable(seen map[*types.Type]bool, t *types.Type) bool { - if seen[t] { - // be optimistic in the case of type cycles. - return true - } - seen[t] = true - switch t.Kind { - case types.Builtin: - return true - case types.Alias: - return isProtoable(seen, t.Underlying) - case types.Slice, types.Pointer: - return isProtoable(seen, t.Elem) - case types.Map: - return isProtoable(seen, t.Key) && isProtoable(seen, t.Elem) - case types.Struct: - if len(t.Members) == 0 { - return true - } - for _, m := range t.Members { - if isProtoable(seen, m.Type) { - return true - } - } - return false - case types.Func, types.Chan: - return false - case types.DeclarationOf, types.Unknown, types.Unsupported: - return false - case types.Interface: - return false - default: - log.Printf("WARNING: type %q is not portable: %s", t.Kind, t.Name) - return false - } -} - -// isOptionalAlias should return true if the specified type has an underlying type -// (is an alias) of a map or slice and has the comment tag protobuf.nullable=true, -// indicating that the type should be nullable in protobuf. -func isOptionalAlias(t *types.Type) bool { - if t.Underlying == nil || (t.Underlying.Kind != types.Map && t.Underlying.Kind != types.Slice) { - return false - } - if extractBoolTagOrDie("protobuf.nullable", t.CommentLines) == false { - return false - } - return true -} - -func (g *genProtoIDL) Imports(c *generator.Context) (imports []string) { - lines := []string{} - // TODO: this could be expressed more cleanly - for _, line := range g.imports.ImportLines() { - if g.omitGogo && line == "github.com/gogo/protobuf/gogoproto/gogo.proto" { - continue - } - lines = append(lines, line) - } - return lines -} - -// GenerateType makes the body of a file implementing a set for type t. -func (g *genProtoIDL) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { - sw := generator.NewSnippetWriter(w, c, "$", "$") - b := bodyGen{ - locator: &protobufLocator{ - namer: c.Namers["proto"].(ProtobufFromGoNamer), - tracker: g.imports, - universe: c.Universe, - - localGoPackage: g.localGoPackage.Package, - }, - localPackage: g.localPackage, - - omitGogo: g.omitGogo, - omitFieldTypes: g.omitFieldTypes, - - t: t, - } - switch t.Kind { - case types.Alias: - return b.doAlias(sw) - case types.Struct: - return b.doStruct(sw) - default: - return b.unknown(sw) - } -} - -// ProtobufFromGoNamer finds the protobuf name of a type (and its package, and -// the package path) from its Go name. -type ProtobufFromGoNamer interface { - GoNameToProtoName(name types.Name) types.Name -} - -type ProtobufLocator interface { - ProtoTypeFor(t *types.Type) (*types.Type, error) - GoTypeForName(name types.Name) *types.Type - CastTypeName(name types.Name) string -} - -type protobufLocator struct { - namer ProtobufFromGoNamer - tracker namer.ImportTracker - universe types.Universe - - localGoPackage string -} - -// CastTypeName returns the cast type name of a Go type -// TODO: delegate to a new localgo namer? -func (p protobufLocator) CastTypeName(name types.Name) string { - if name.Package == p.localGoPackage { - return name.Name - } - return name.String() -} - -func (p protobufLocator) GoTypeForName(name types.Name) *types.Type { - if len(name.Package) == 0 { - name.Package = p.localGoPackage - } - return p.universe.Type(name) -} - -// ProtoTypeFor locates a Protobuf type for the provided Go type (if possible). -func (p protobufLocator) ProtoTypeFor(t *types.Type) (*types.Type, error) { - switch { - // we've already converted the type, or it's a map - case t.Kind == types.Protobuf || t.Kind == types.Map: - p.tracker.AddType(t) - return t, nil - } - // it's a fundamental type - if t, ok := isFundamentalProtoType(t); ok { - p.tracker.AddType(t) - return t, nil - } - // it's a message - if t.Kind == types.Struct || isOptionalAlias(t) { - t := &types.Type{ - Name: p.namer.GoNameToProtoName(t.Name), - Kind: types.Protobuf, - - CommentLines: t.CommentLines, - } - p.tracker.AddType(t) - return t, nil - } - return nil, errUnrecognizedType -} - -type bodyGen struct { - locator ProtobufLocator - localPackage types.Name - omitGogo bool - omitFieldTypes map[types.Name]struct{} - - t *types.Type -} - -func (b bodyGen) unknown(sw *generator.SnippetWriter) error { - return fmt.Errorf("not sure how to generate: %#v", b.t) -} - -func (b bodyGen) doAlias(sw *generator.SnippetWriter) error { - if !isOptionalAlias(b.t) { - return nil - } - - var kind string - switch b.t.Underlying.Kind { - case types.Map: - kind = "map" - default: - kind = "slice" - } - optional := &types.Type{ - Name: b.t.Name, - Kind: types.Struct, - - CommentLines: b.t.CommentLines, - SecondClosestCommentLines: b.t.SecondClosestCommentLines, - Members: []types.Member{ - { - Name: "Items", - CommentLines: []string{fmt.Sprintf("items, if empty, will result in an empty %s\n", kind)}, - Type: b.t.Underlying, - }, - }, - } - nested := b - nested.t = optional - return nested.doStruct(sw) -} - -func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { - if len(b.t.Name.Name) == 0 { - return nil - } - if namer.IsPrivateGoName(b.t.Name.Name) { - return nil - } - - var alias *types.Type - var fields []protoField - options := []string{} - allOptions := types.ExtractCommentTags("+", b.t.CommentLines) - for k, v := range allOptions { - switch { - case strings.HasPrefix(k, "protobuf.options."): - key := strings.TrimPrefix(k, "protobuf.options.") - switch key { - case "marshal": - if v[0] == "false" { - if !b.omitGogo { - options = append(options, - "(gogoproto.marshaler) = false", - "(gogoproto.unmarshaler) = false", - "(gogoproto.sizer) = false", - ) - } - } - default: - if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") { - if key == "(gogoproto.goproto_stringer)" && v[0] == "false" { - options = append(options, "(gogoproto.stringer) = false") - } - options = append(options, fmt.Sprintf("%s = %s", key, v[0])) - } - } - // protobuf.as allows a type to have the same message contents as another Go type - case k == "protobuf.as": - fields = nil - if alias = b.locator.GoTypeForName(types.Name{Name: v[0]}); alias == nil { - return fmt.Errorf("type %v references alias %q which does not exist", b.t, v[0]) - } - // protobuf.embed instructs the generator to use the named type in this package - // as an embedded message. - case k == "protobuf.embed": - fields = []protoField{ - { - Tag: 1, - Name: v[0], - Type: &types.Type{ - Name: types.Name{ - Name: v[0], - Package: b.localPackage.Package, - Path: b.localPackage.Path, - }, - }, - }, - } - } - } - if alias == nil { - alias = b.t - } - - // If we don't explicitly embed anything, generate fields by traversing fields. - if fields == nil { - memberFields, err := membersToFields(b.locator, alias, b.localPackage, b.omitFieldTypes) - if err != nil { - return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err) - } - fields = memberFields - } - - out := sw.Out() - genComment(out, b.t.CommentLines, "") - sw.Do(`message $.Name.Name$ { -`, b.t) - - if len(options) > 0 { - sort.Sort(sort.StringSlice(options)) - for _, s := range options { - fmt.Fprintf(out, " option %s;\n", s) - } - fmt.Fprintln(out) - } - - for i, field := range fields { - genComment(out, field.CommentLines, " ") - fmt.Fprintf(out, " ") - switch { - case field.Map: - case field.Repeated: - fmt.Fprintf(out, "repeated ") - case field.Required: - fmt.Fprintf(out, "required ") - default: - fmt.Fprintf(out, "optional ") - } - sw.Do(`$.Type|local$ $.Name$ = $.Tag$`, field) - if len(field.Extras) > 0 { - extras := []string{} - for k, v := range field.Extras { - if b.omitGogo && strings.HasPrefix(k, "(gogoproto.") { - continue - } - extras = append(extras, fmt.Sprintf("%s = %s", k, v)) - } - sort.Sort(sort.StringSlice(extras)) - if len(extras) > 0 { - fmt.Fprintf(out, " [") - fmt.Fprint(out, strings.Join(extras, ", ")) - fmt.Fprintf(out, "]") - } - } - fmt.Fprintf(out, ";\n") - if i != len(fields)-1 { - fmt.Fprintf(out, "\n") - } - } - fmt.Fprintf(out, "}\n\n") - return nil -} - -type protoField struct { - LocalPackage types.Name - - Tag int - Name string - Type *types.Type - Map bool - Repeated bool - Optional bool - Required bool - Nullable bool - Extras map[string]string - - CommentLines []string -} - -var ( - errUnrecognizedType = fmt.Errorf("did not recognize the provided type") -) - -func isFundamentalProtoType(t *types.Type) (*types.Type, bool) { - // TODO: when we enable proto3, also include other fundamental types in the google.protobuf package - // switch { - // case t.Kind == types.Struct && t.Name == types.Name{Package: "time", Name: "Time"}: - // return &types.Type{ - // Kind: types.Protobuf, - // Name: types.Name{Path: "google/protobuf/timestamp.proto", Package: "google.protobuf", Name: "Timestamp"}, - // }, true - // } - switch t.Kind { - case types.Slice: - if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 { - return &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf}, true - } - case types.Builtin: - switch t.Name.Name { - case "string", "uint32", "int32", "uint64", "int64", "bool": - return &types.Type{Name: types.Name{Name: t.Name.Name}, Kind: types.Protobuf}, true - case "int": - return &types.Type{Name: types.Name{Name: "int64"}, Kind: types.Protobuf}, true - case "uint": - return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true - case "float64", "float": - return &types.Type{Name: types.Name{Name: "double"}, Kind: types.Protobuf}, true - case "float32": - return &types.Type{Name: types.Name{Name: "float"}, Kind: types.Protobuf}, true - case "uintptr": - return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true - } - // TODO: complex? - } - return t, false -} - -func memberTypeToProtobufField(locator ProtobufLocator, field *protoField, t *types.Type) error { - var err error - switch t.Kind { - case types.Protobuf: - field.Type, err = locator.ProtoTypeFor(t) - case types.Builtin: - field.Type, err = locator.ProtoTypeFor(t) - case types.Map: - valueField := &protoField{} - if err := memberTypeToProtobufField(locator, valueField, t.Elem); err != nil { - return err - } - keyField := &protoField{} - if err := memberTypeToProtobufField(locator, keyField, t.Key); err != nil { - return err - } - // All other protobuf types have kind types.Protobuf, so setting types.Map - // here would be very misleading. - field.Type = &types.Type{ - Kind: types.Protobuf, - Key: keyField.Type, - Elem: valueField.Type, - } - if !strings.HasPrefix(t.Name.Name, "map[") { - field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name)) - } - if k, ok := keyField.Extras["(gogoproto.casttype)"]; ok { - field.Extras["(gogoproto.castkey)"] = k - } - if v, ok := valueField.Extras["(gogoproto.casttype)"]; ok { - field.Extras["(gogoproto.castvalue)"] = v - } - field.Map = true - case types.Pointer: - if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil { - return err - } - field.Nullable = true - case types.Alias: - if isOptionalAlias(t) { - field.Type, err = locator.ProtoTypeFor(t) - field.Nullable = true - } else { - if err := memberTypeToProtobufField(locator, field, t.Underlying); err != nil { - log.Printf("failed to alias: %s %s: err %v", t.Name, t.Underlying.Name, err) - return err - } - // If this is not an alias to a slice, cast to the alias - if !field.Repeated { - if field.Extras == nil { - field.Extras = make(map[string]string) - } - field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name)) - } - } - case types.Slice: - if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 { - field.Type = &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf} - return nil - } - if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil { - return err - } - field.Repeated = true - case types.Struct: - if len(t.Name.Name) == 0 { - return errUnrecognizedType - } - field.Type, err = locator.ProtoTypeFor(t) - field.Nullable = false - default: - return errUnrecognizedType - } - return err -} - -// protobufTagToField extracts information from an existing protobuf tag -func protobufTagToField(tag string, field *protoField, m types.Member, t *types.Type, localPackage types.Name) error { - if len(tag) == 0 || tag == "-" { - return nil - } - - // protobuf:"bytes,3,opt,name=Id,customtype=github.com/gogo/protobuf/test.Uuid" - parts := strings.Split(tag, ",") - if len(parts) < 3 { - return fmt.Errorf("member %q of %q malformed 'protobuf' tag, not enough segments\n", m.Name, t.Name) - } - protoTag, err := strconv.Atoi(parts[1]) - if err != nil { - return fmt.Errorf("member %q of %q malformed 'protobuf' tag, field ID is %q which is not an integer: %v\n", m.Name, t.Name, parts[1], err) - } - field.Tag = protoTag - - // In general there is doesn't make sense to parse the protobuf tags to get the type, - // as all auto-generated once will have wire type "bytes", "varint" or "fixed64". - // However, sometimes we explicitly set them to have a custom serialization, e.g.: - // type Time struct { - // time.Time `protobuf:"Timestamp,1,req,name=time"` - // } - // to force the generator to use a given type (that we manually wrote serialization & - // deserialization methods for). - switch parts[0] { - case "varint", "fixed32", "fixed64", "bytes", "group": - default: - name := types.Name{} - if last := strings.LastIndex(parts[0], "."); last != -1 { - prefix := parts[0][:last] - name = types.Name{ - Name: parts[0][last+1:], - Package: prefix, - Path: strings.Replace(prefix, ".", "/", -1), - } - } else { - name = types.Name{ - Name: parts[0], - Package: localPackage.Package, - Path: localPackage.Path, - } - } - field.Type = &types.Type{ - Name: name, - Kind: types.Protobuf, - } - } - - protoExtra := make(map[string]string) - for i, extra := range parts[3:] { - parts := strings.SplitN(extra, "=", 2) - if len(parts) != 2 { - return fmt.Errorf("member %q of %q malformed 'protobuf' tag, tag %d should be key=value, got %q\n", m.Name, t.Name, i+4, extra) - } - switch parts[0] { - case "name": - protoExtra[parts[0]] = parts[1] - case "casttype", "castkey", "castvalue": - parts[0] = fmt.Sprintf("(gogoproto.%s)", parts[0]) - protoExtra[parts[0]] = strconv.Quote(parts[1]) - } - } - - field.Extras = protoExtra - if name, ok := protoExtra["name"]; ok { - field.Name = name - delete(protoExtra, "name") - } - - return nil -} - -func membersToFields(locator ProtobufLocator, t *types.Type, localPackage types.Name, omitFieldTypes map[types.Name]struct{}) ([]protoField, error) { - fields := []protoField{} - - for _, m := range t.Members { - if namer.IsPrivateGoName(m.Name) { - // skip private fields - continue - } - if _, ok := omitFieldTypes[types.Name{Name: m.Type.Name.Name, Package: m.Type.Name.Package}]; ok { - continue - } - tags := reflect.StructTag(m.Tags) - field := protoField{ - LocalPackage: localPackage, - - Tag: -1, - Extras: make(map[string]string), - } - - protobufTag := tags.Get("protobuf") - if protobufTag == "-" { - continue - } - - if err := protobufTagToField(protobufTag, &field, m, t, localPackage); err != nil { - return nil, err - } - - // extract information from JSON field tag - if tag := tags.Get("json"); len(tag) > 0 { - parts := strings.Split(tag, ",") - if len(field.Name) == 0 && len(parts[0]) != 0 { - field.Name = parts[0] - } - if field.Tag == -1 && field.Name == "-" { - continue - } - } - - if field.Type == nil { - if err := memberTypeToProtobufField(locator, &field, m.Type); err != nil { - return nil, fmt.Errorf("unable to embed type %q as field %q in %q: %v", m.Type, field.Name, t.Name, err) - } - } - if len(field.Name) == 0 { - field.Name = namer.IL(m.Name) - } - - if field.Map && field.Repeated { - // maps cannot be repeated - field.Repeated = false - field.Nullable = true - } - - if !field.Nullable { - field.Extras["(gogoproto.nullable)"] = "false" - } - if (field.Type.Name.Name == "bytes" && field.Type.Name.Package == "") || (field.Repeated && field.Type.Name.Package == "" && namer.IsPrivateGoName(field.Type.Name.Name)) { - delete(field.Extras, "(gogoproto.nullable)") - } - if field.Name != m.Name { - field.Extras["(gogoproto.customname)"] = strconv.Quote(m.Name) - } - field.CommentLines = m.CommentLines - fields = append(fields, field) - } - - // assign tags - highest := 0 - byTag := make(map[int]*protoField) - // fields are in Go struct order, which we preserve - for i := range fields { - field := &fields[i] - tag := field.Tag - if tag != -1 { - if existing, ok := byTag[tag]; ok { - return nil, fmt.Errorf("field %q and %q both have tag %d", field.Name, existing.Name, tag) - } - byTag[tag] = field - } - if tag > highest { - highest = tag - } - } - // starting from the highest observed tag, assign new field tags - for i := range fields { - field := &fields[i] - if field.Tag != -1 { - continue - } - highest++ - field.Tag = highest - byTag[field.Tag] = field - } - return fields, nil -} - -func genComment(out io.Writer, lines []string, indent string) { - for { - l := len(lines) - if l == 0 || len(lines[l-1]) != 0 { - break - } - lines = lines[:l-1] - } - for _, c := range lines { - fmt.Fprintf(out, "%s// %s\n", indent, c) - } -} - -func formatProtoFile(source []byte) ([]byte, error) { - // TODO; Is there any protobuf formatter? - return source, nil -} - -func assembleProtoFile(w io.Writer, f *generator.File) { - w.Write(f.Header) - - fmt.Fprint(w, "syntax = 'proto2';\n\n") - - if len(f.PackageName) > 0 { - fmt.Fprintf(w, "package %s;\n\n", f.PackageName) - } - - if len(f.Imports) > 0 { - imports := []string{} - for i := range f.Imports { - imports = append(imports, i) - } - sort.Strings(imports) - for _, s := range imports { - fmt.Fprintf(w, "import %q;\n", s) - } - fmt.Fprint(w, "\n") - } - - if f.Vars.Len() > 0 { - fmt.Fprintf(w, "%s\n", f.Vars.String()) - } - - w.Write(f.Body.Bytes()) -} - -func NewProtoFile() *generator.DefaultFileType { - return &generator.DefaultFileType{ - Format: formatProtoFile, - Assemble: assembleProtoFile, - } -} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go deleted file mode 100644 index 08a991b15..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2015 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 protobuf - -import ( - "k8s.io/gengo/namer" - "k8s.io/gengo/types" -) - -type ImportTracker struct { - namer.DefaultImportTracker -} - -func NewImportTracker(local types.Name, typesToAdd ...*types.Type) *ImportTracker { - tracker := namer.NewDefaultImportTracker(local) - tracker.IsInvalidType = func(t *types.Type) bool { return t.Kind != types.Protobuf } - tracker.LocalName = func(name types.Name) string { return name.Package } - tracker.PrintImport = func(path, name string) string { return path } - - tracker.AddTypes(typesToAdd...) - return &ImportTracker{ - DefaultImportTracker: tracker, - } -} - -// AddNullable ensures that support for the nullable Gogo-protobuf extension is added. -func (tracker *ImportTracker) AddNullable() { - tracker.AddType(&types.Type{ - Kind: types.Protobuf, - Name: types.Name{ - Name: "nullable", - Package: "gogoproto", - Path: "github.com/gogo/protobuf/gogoproto/gogo.proto", - }, - }) -} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go deleted file mode 100644 index e3b21c670..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/namer.go +++ /dev/null @@ -1,208 +0,0 @@ -/* -Copyright 2015 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 protobuf - -import ( - "fmt" - "reflect" - "strings" - - "k8s.io/gengo/generator" - "k8s.io/gengo/namer" - "k8s.io/gengo/types" -) - -type localNamer struct { - localPackage types.Name -} - -func (n localNamer) Name(t *types.Type) string { - if t.Key != nil && t.Elem != nil { - return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem)) - } - if len(n.localPackage.Package) != 0 && n.localPackage.Package == t.Name.Package { - return t.Name.Name - } - return t.Name.String() -} - -type protobufNamer struct { - packages []*protobufPackage - packagesByPath map[string]*protobufPackage -} - -func NewProtobufNamer() *protobufNamer { - return &protobufNamer{ - packagesByPath: make(map[string]*protobufPackage), - } -} - -func (n *protobufNamer) Name(t *types.Type) string { - if t.Kind == types.Map { - return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem)) - } - return t.Name.String() -} - -func (n *protobufNamer) List() []generator.Package { - packages := make([]generator.Package, 0, len(n.packages)) - for i := range n.packages { - packages = append(packages, n.packages[i]) - } - return packages -} - -func (n *protobufNamer) Add(p *protobufPackage) { - if _, ok := n.packagesByPath[p.PackagePath]; !ok { - n.packagesByPath[p.PackagePath] = p - n.packages = append(n.packages, p) - } -} - -func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name { - if p, ok := n.packagesByPath[name.Package]; ok { - return types.Name{ - Name: name.Name, - Package: p.PackageName, - Path: p.ImportPath(), - } - } - for _, p := range n.packages { - if _, ok := p.FilterTypes[name]; ok { - return types.Name{ - Name: name.Name, - Package: p.PackageName, - Path: p.ImportPath(), - } - } - } - return types.Name{Name: name.Name} -} - -func protoSafePackage(name string) string { - pkg := strings.Replace(name, "/", ".", -1) - return strings.Replace(pkg, "-", "_", -1) -} - -type typeNameSet map[types.Name]*protobufPackage - -// assignGoTypeToProtoPackage looks for Go and Protobuf types that are referenced by a type in -// a package. It will not recurse into protobuf types. -func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global typeNameSet, optional map[types.Name]struct{}) { - newT, isProto := isFundamentalProtoType(t) - if isProto { - t = newT - } - if otherP, ok := global[t.Name]; ok { - if _, ok := local[t.Name]; !ok { - p.Imports.AddType(&types.Type{ - Kind: types.Protobuf, - Name: otherP.ProtoTypeName(), - }) - } - return - } - if t.Name.Package == p.PackagePath { - // Associate types only to their own package - global[t.Name] = p - } - if _, ok := local[t.Name]; ok { - return - } - // don't recurse into existing proto types - if isProto { - p.Imports.AddType(t) - return - } - - local[t.Name] = p - for _, m := range t.Members { - if namer.IsPrivateGoName(m.Name) { - continue - } - field := &protoField{} - tag := reflect.StructTag(m.Tags).Get("protobuf") - if tag == "-" { - continue - } - if err := protobufTagToField(tag, field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil { - assignGoTypeToProtoPackage(p, field.Type, local, global, optional) - continue - } - assignGoTypeToProtoPackage(p, m.Type, local, global, optional) - } - // TODO: should methods be walked? - if t.Elem != nil { - assignGoTypeToProtoPackage(p, t.Elem, local, global, optional) - } - if t.Key != nil { - assignGoTypeToProtoPackage(p, t.Key, local, global, optional) - } - if t.Underlying != nil { - if t.Kind == types.Alias && isOptionalAlias(t) { - optional[t.Name] = struct{}{} - } - assignGoTypeToProtoPackage(p, t.Underlying, local, global, optional) - } -} - -// isTypeApplicableToProtobuf checks to see if a type is relevant for protobuf processing. -// Currently, it filters out functions and private types. -func isTypeApplicableToProtobuf(t *types.Type) bool { - // skip functions -- we don't care about them for protobuf - if t.Kind == types.Func || (t.Kind == types.DeclarationOf && t.Underlying.Kind == types.Func) { - return false - } - // skip private types - if namer.IsPrivateGoName(t.Name.Name) { - return false - } - - return true -} - -func (n *protobufNamer) AssignTypesToPackages(c *generator.Context) error { - global := make(typeNameSet) - for _, p := range n.packages { - local := make(typeNameSet) - optional := make(map[types.Name]struct{}) - p.Imports = NewImportTracker(p.ProtoTypeName()) - for _, t := range c.Order { - if t.Name.Package != p.PackagePath { - continue - } - if !isTypeApplicableToProtobuf(t) { - // skip types that we don't care about, like functions - continue - } - assignGoTypeToProtoPackage(p, t, local, global, optional) - } - p.FilterTypes = make(map[types.Name]struct{}) - p.LocalNames = make(map[string]struct{}) - p.OptionalTypeNames = make(map[string]struct{}) - for k, v := range local { - if v == p { - p.FilterTypes[k] = struct{}{} - p.LocalNames[k.Name] = struct{}{} - if _, ok := optional[k]; ok { - p.OptionalTypeNames[k.Name] = struct{}{} - } - } - } - } - return nil -} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go deleted file mode 100644 index bed4c3e30..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/package.go +++ /dev/null @@ -1,215 +0,0 @@ -/* -Copyright 2015 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 protobuf - -import ( - "fmt" - "go/ast" - "log" - "os" - "path/filepath" - "reflect" - "strings" - - "k8s.io/gengo/generator" - "k8s.io/gengo/types" -) - -func newProtobufPackage(packagePath, packageName string, generateAll bool, omitFieldTypes map[types.Name]struct{}) *protobufPackage { - pkg := &protobufPackage{ - DefaultPackage: generator.DefaultPackage{ - // The protobuf package name (foo.bar.baz) - PackageName: packageName, - // A path segment relative to the GOPATH root (foo/bar/baz) - PackagePath: packagePath, - HeaderText: []byte( - ` -// This file was autogenerated by go-to-protobuf. Do not edit it manually! - -`), - PackageDocumentation: []byte(fmt.Sprintf( - `// Package %s is an autogenerated protobuf IDL. -`, packageName)), - }, - GenerateAll: generateAll, - OmitFieldTypes: omitFieldTypes, - } - pkg.FilterFunc = pkg.filterFunc - pkg.GeneratorFunc = pkg.generatorFunc - return pkg -} - -// protobufPackage contains the protobuf implementation of Package. -type protobufPackage struct { - generator.DefaultPackage - - // If true, this package has been vendored into our source tree and thus can - // only be generated by changing the vendor tree. - Vendored bool - - // If true, generate protobuf serializations for all public types. - // If false, only generate protobuf serializations for structs that - // request serialization. - GenerateAll bool - - // A list of types to filter to; if not specified all types will be included. - FilterTypes map[types.Name]struct{} - - // If true, omit any gogoprotobuf extensions not defined as types. - OmitGogo bool - - // A list of field types that will be excluded from the output struct - OmitFieldTypes map[types.Name]struct{} - - // A list of names that this package exports - LocalNames map[string]struct{} - - // A list of type names in this package that will need marshaller rewriting - // to remove synthetic protobuf fields. - OptionalTypeNames map[string]struct{} - - // A list of struct tags to generate onto named struct fields - StructTags map[string]map[string]string - - // An import tracker for this package - Imports *ImportTracker -} - -func (p *protobufPackage) Clean(outputBase string) error { - for _, s := range []string{p.ImportPath(), p.OutputPath()} { - if err := os.Remove(filepath.Join(outputBase, s)); err != nil && !os.IsNotExist(err) { - return err - } - } - return nil -} - -func (p *protobufPackage) ProtoTypeName() types.Name { - return types.Name{ - Name: p.Path(), // the go path "foo/bar/baz" - Package: p.Name(), // the protobuf package "foo.bar.baz" - Path: p.ImportPath(), // the path of the import to get the proto - } -} - -func (p *protobufPackage) filterFunc(c *generator.Context, t *types.Type) bool { - switch t.Kind { - case types.Func, types.Chan: - return false - case types.Struct: - if t.Name.Name == "struct{}" { - return false - } - case types.Builtin: - return false - case types.Alias: - if !isOptionalAlias(t) { - return false - } - case types.Slice, types.Array, types.Map: - return false - case types.Pointer: - return false - } - if _, ok := isFundamentalProtoType(t); ok { - return false - } - _, ok := p.FilterTypes[t.Name] - return ok -} - -func (p *protobufPackage) HasGoType(name string) bool { - _, ok := p.LocalNames[name] - return ok -} - -func (p *protobufPackage) OptionalTypeName(name string) bool { - _, ok := p.OptionalTypeNames[name] - return ok -} - -func (p *protobufPackage) ExtractGeneratedType(t *ast.TypeSpec) bool { - if !p.HasGoType(t.Name.Name) { - return false - } - - switch s := t.Type.(type) { - case *ast.StructType: - for i, f := range s.Fields.List { - if len(f.Tag.Value) == 0 { - continue - } - tag := strings.Trim(f.Tag.Value, "`") - protobufTag := reflect.StructTag(tag).Get("protobuf") - if len(protobufTag) == 0 { - continue - } - if len(f.Names) > 1 { - log.Printf("WARNING: struct %s field %d %s: defined multiple names but single protobuf tag", t.Name.Name, i, f.Names[0].Name) - // TODO hard error? - } - if p.StructTags == nil { - p.StructTags = make(map[string]map[string]string) - } - m := p.StructTags[t.Name.Name] - if m == nil { - m = make(map[string]string) - p.StructTags[t.Name.Name] = m - } - m[f.Names[0].Name] = tag - } - default: - log.Printf("WARNING: unexpected Go AST type definition: %#v", t) - } - - return true -} - -func (p *protobufPackage) generatorFunc(c *generator.Context) []generator.Generator { - generators := []generator.Generator{} - - p.Imports.AddNullable() - - generators = append(generators, &genProtoIDL{ - DefaultGen: generator.DefaultGen{ - OptionalName: "generated", - }, - localPackage: types.Name{Package: p.PackageName, Path: p.PackagePath}, - localGoPackage: types.Name{Package: p.PackagePath, Name: p.GoPackageName()}, - imports: p.Imports, - generateAll: p.GenerateAll, - omitGogo: p.OmitGogo, - omitFieldTypes: p.OmitFieldTypes, - }) - return generators -} - -func (p *protobufPackage) GoPackageName() string { - return filepath.Base(p.PackagePath) -} - -func (p *protobufPackage) ImportPath() string { - return filepath.Join(p.PackagePath, "generated.proto") -} - -func (p *protobufPackage) OutputPath() string { - return filepath.Join(p.PackagePath, "generated.pb.go") -} - -var ( - _ = generator.Package(&protobufPackage{}) -) diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go deleted file mode 100644 index 305b718ed..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protobuf/parser.go +++ /dev/null @@ -1,452 +0,0 @@ -/* -Copyright 2015 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 protobuf - -import ( - "bytes" - "errors" - "fmt" - "go/ast" - "go/format" - "go/parser" - "go/printer" - "go/token" - "io/ioutil" - "os" - "reflect" - "strings" - - customreflect "k8s.io/code-generator/third_party/forked/golang/reflect" -) - -func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error { - fset := token.NewFileSet() - src, err := ioutil.ReadFile(name) - if err != nil { - return err - } - file, err := parser.ParseFile(fset, name, src, parser.DeclarationErrors|parser.ParseComments) - if err != nil { - return err - } - - if err := rewriteFn(fset, file); err != nil { - return err - } - - b := &bytes.Buffer{} - b.Write(header) - if err := printer.Fprint(b, fset, file); err != nil { - return err - } - - body, err := format.Source(b.Bytes()) - if err != nil { - return err - } - - f, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC, 0644) - if err != nil { - return err - } - defer f.Close() - if _, err := f.Write(body); err != nil { - return err - } - return f.Close() -} - -// ExtractFunc extracts information from the provided TypeSpec and returns true if the type should be -// removed from the destination file. -type ExtractFunc func(*ast.TypeSpec) bool - -// OptionalFunc returns true if the provided local name is a type that has protobuf.nullable=true -// and should have its marshal functions adjusted to remove the 'Items' accessor. -type OptionalFunc func(name string) bool - -func RewriteGeneratedGogoProtobufFile(name string, extractFn ExtractFunc, optionalFn OptionalFunc, header []byte) error { - return rewriteFile(name, header, func(fset *token.FileSet, file *ast.File) error { - cmap := ast.NewCommentMap(fset, file, file.Comments) - - // transform methods that point to optional maps or slices - for _, d := range file.Decls { - rewriteOptionalMethods(d, optionalFn) - } - - // remove types that are already declared - decls := []ast.Decl{} - for _, d := range file.Decls { - if dropExistingTypeDeclarations(d, extractFn) { - continue - } - if dropEmptyImportDeclarations(d) { - continue - } - decls = append(decls, d) - } - file.Decls = decls - - // remove unmapped comments - file.Comments = cmap.Filter(file).Comments() - return nil - }) -} - -// rewriteOptionalMethods makes specific mutations to marshaller methods that belong to types identified -// as being "optional" (they may be nil on the wire). This allows protobuf to serialize a map or slice and -// properly discriminate between empty and nil (which is not possible in protobuf). -// TODO: move into upstream gogo-protobuf once https://github.com/gogo/protobuf/issues/181 -// has agreement -func rewriteOptionalMethods(decl ast.Decl, isOptional OptionalFunc) { - switch t := decl.(type) { - case *ast.FuncDecl: - ident, ptr, ok := receiver(t) - if !ok { - return - } - - // correct initialization of the form `m.Field = &OptionalType{}` to - // `m.Field = OptionalType{}` - if t.Name.Name == "Unmarshal" { - ast.Walk(optionalAssignmentVisitor{fn: isOptional}, t.Body) - } - - if !isOptional(ident.Name) { - return - } - - switch t.Name.Name { - case "Unmarshal": - ast.Walk(&optionalItemsVisitor{}, t.Body) - case "MarshalTo", "Size", "String": - ast.Walk(&optionalItemsVisitor{}, t.Body) - fallthrough - case "Marshal": - // if the method has a pointer receiver, set it back to a normal receiver - if ptr { - t.Recv.List[0].Type = ident - } - } - } -} - -type optionalAssignmentVisitor struct { - fn OptionalFunc -} - -// Visit walks the provided node, transforming field initializations of the form -// m.Field = &OptionalType{} -> m.Field = OptionalType{} -func (v optionalAssignmentVisitor) Visit(n ast.Node) ast.Visitor { - switch t := n.(type) { - case *ast.AssignStmt: - if len(t.Lhs) == 1 && len(t.Rhs) == 1 { - if !isFieldSelector(t.Lhs[0], "m", "") { - return nil - } - unary, ok := t.Rhs[0].(*ast.UnaryExpr) - if !ok || unary.Op != token.AND { - return nil - } - composite, ok := unary.X.(*ast.CompositeLit) - if !ok || composite.Type == nil || len(composite.Elts) != 0 { - return nil - } - if ident, ok := composite.Type.(*ast.Ident); ok && v.fn(ident.Name) { - t.Rhs[0] = composite - } - } - return nil - } - return v -} - -type optionalItemsVisitor struct{} - -// Visit walks the provided node, looking for specific patterns to transform that match -// the effective outcome of turning struct{ map[x]y || []x } into map[x]y or []x. -func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor { - switch t := n.(type) { - case *ast.RangeStmt: - if isFieldSelector(t.X, "m", "Items") { - t.X = &ast.Ident{Name: "m"} - } - case *ast.AssignStmt: - if len(t.Lhs) == 1 && len(t.Rhs) == 1 { - switch lhs := t.Lhs[0].(type) { - case *ast.IndexExpr: - if isFieldSelector(lhs.X, "m", "Items") { - lhs.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} - } - default: - if isFieldSelector(t.Lhs[0], "m", "Items") { - t.Lhs[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} - } - } - switch rhs := t.Rhs[0].(type) { - case *ast.CallExpr: - if ident, ok := rhs.Fun.(*ast.Ident); ok && ident.Name == "append" { - ast.Walk(v, rhs) - if len(rhs.Args) > 0 { - switch arg := rhs.Args[0].(type) { - case *ast.Ident: - if arg.Name == "m" { - rhs.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} - } - } - } - return nil - } - } - } - case *ast.IfStmt: - switch cond := t.Cond.(type) { - case *ast.BinaryExpr: - if cond.Op == token.EQL { - if isFieldSelector(cond.X, "m", "Items") && isIdent(cond.Y, "nil") { - cond.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} - } - } - } - if t.Init != nil { - // Find form: - // if err := m[len(m.Items)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { - // return err - // } - switch s := t.Init.(type) { - case *ast.AssignStmt: - if call, ok := s.Rhs[0].(*ast.CallExpr); ok { - if sel, ok := call.Fun.(*ast.SelectorExpr); ok { - if x, ok := sel.X.(*ast.IndexExpr); ok { - // m[] -> (*m)[] - if sel2, ok := x.X.(*ast.SelectorExpr); ok { - if ident, ok := sel2.X.(*ast.Ident); ok && ident.Name == "m" { - x.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} - } - } - // len(m.Items) -> len(*m) - if bin, ok := x.Index.(*ast.BinaryExpr); ok { - if call2, ok := bin.X.(*ast.CallExpr); ok && len(call2.Args) == 1 { - if isFieldSelector(call2.Args[0], "m", "Items") { - call2.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} - } - } - } - } - } - } - } - } - case *ast.IndexExpr: - if isFieldSelector(t.X, "m", "Items") { - t.X = &ast.Ident{Name: "m"} - return nil - } - case *ast.CallExpr: - changed := false - for i := range t.Args { - if isFieldSelector(t.Args[i], "m", "Items") { - t.Args[i] = &ast.Ident{Name: "m"} - changed = true - } - } - if changed { - return nil - } - } - return v -} - -func isFieldSelector(n ast.Expr, name, field string) bool { - s, ok := n.(*ast.SelectorExpr) - if !ok || s.Sel == nil || (field != "" && s.Sel.Name != field) { - return false - } - return isIdent(s.X, name) -} - -func isIdent(n ast.Expr, value string) bool { - ident, ok := n.(*ast.Ident) - return ok && ident.Name == value -} - -func receiver(f *ast.FuncDecl) (ident *ast.Ident, pointer bool, ok bool) { - if f.Recv == nil || len(f.Recv.List) != 1 { - return nil, false, false - } - switch t := f.Recv.List[0].Type.(type) { - case *ast.StarExpr: - identity, ok := t.X.(*ast.Ident) - if !ok { - return nil, false, false - } - return identity, true, true - case *ast.Ident: - return t, false, true - } - return nil, false, false -} - -// dropExistingTypeDeclarations removes any type declaration for which extractFn returns true. The function -// returns true if the entire declaration should be dropped. -func dropExistingTypeDeclarations(decl ast.Decl, extractFn ExtractFunc) bool { - switch t := decl.(type) { - case *ast.GenDecl: - if t.Tok != token.TYPE { - return false - } - specs := []ast.Spec{} - for _, s := range t.Specs { - switch spec := s.(type) { - case *ast.TypeSpec: - if extractFn(spec) { - continue - } - specs = append(specs, spec) - } - } - if len(specs) == 0 { - return true - } - t.Specs = specs - } - return false -} - -// dropEmptyImportDeclarations strips any generated but no-op imports from the generated code -// to prevent generation from being able to define side-effects. The function returns true -// if the entire declaration should be dropped. -func dropEmptyImportDeclarations(decl ast.Decl) bool { - switch t := decl.(type) { - case *ast.GenDecl: - if t.Tok != token.IMPORT { - return false - } - specs := []ast.Spec{} - for _, s := range t.Specs { - switch spec := s.(type) { - case *ast.ImportSpec: - if spec.Name != nil && spec.Name.Name == "_" { - continue - } - specs = append(specs, spec) - } - } - if len(specs) == 0 { - return true - } - t.Specs = specs - } - return false -} - -func RewriteTypesWithProtobufStructTags(name string, structTags map[string]map[string]string) error { - return rewriteFile(name, []byte{}, func(fset *token.FileSet, file *ast.File) error { - allErrs := []error{} - - // set any new struct tags - for _, d := range file.Decls { - if errs := updateStructTags(d, structTags, []string{"protobuf"}); len(errs) > 0 { - allErrs = append(allErrs, errs...) - } - } - - if len(allErrs) > 0 { - var s string - for _, err := range allErrs { - s += err.Error() + "\n" - } - return errors.New(s) - } - return nil - }) -} - -func updateStructTags(decl ast.Decl, structTags map[string]map[string]string, toCopy []string) []error { - var errs []error - t, ok := decl.(*ast.GenDecl) - if !ok { - return nil - } - if t.Tok != token.TYPE { - return nil - } - - for _, s := range t.Specs { - spec, ok := s.(*ast.TypeSpec) - if !ok { - continue - } - typeName := spec.Name.Name - fieldTags, ok := structTags[typeName] - if !ok { - continue - } - st, ok := spec.Type.(*ast.StructType) - if !ok { - continue - } - - for i := range st.Fields.List { - f := st.Fields.List[i] - var name string - if len(f.Names) == 0 { - switch t := f.Type.(type) { - case *ast.Ident: - name = t.Name - case *ast.SelectorExpr: - name = t.Sel.Name - default: - errs = append(errs, fmt.Errorf("unable to get name for tag from struct %q, field %#v", spec.Name.Name, t)) - continue - } - } else { - name = f.Names[0].Name - } - value, ok := fieldTags[name] - if !ok { - continue - } - var tags customreflect.StructTags - if f.Tag != nil { - oldTags, err := customreflect.ParseStructTags(strings.Trim(f.Tag.Value, "`")) - if err != nil { - errs = append(errs, fmt.Errorf("unable to read struct tag from struct %q, field %q: %v", spec.Name.Name, name, err)) - continue - } - tags = oldTags - } - for _, name := range toCopy { - // don't overwrite existing tags - if tags.Has(name) { - continue - } - // append new tags - if v := reflect.StructTag(value).Get(name); len(v) > 0 { - tags = append(tags, customreflect.StructTag{Name: name, Value: v}) - } - } - if len(tags) == 0 { - continue - } - if f.Tag == nil { - f.Tag = &ast.BasicLit{} - } - f.Tag.Value = tags.String() - } - } - return errs -} diff --git a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go b/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go deleted file mode 100644 index 6e5051dce..000000000 --- a/vendor/k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2015 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 main defines the protoc-gen-gogo binary we use to generate our proto go files, -// as well as takes dependencies on the correct gogo/protobuf packages for godeps. -package main - -import ( - "github.com/gogo/protobuf/vanity/command" - - // dependencies that are required for our packages - _ "github.com/gogo/protobuf/gogoproto" - _ "github.com/gogo/protobuf/proto" - _ "github.com/gogo/protobuf/sortkeys" -) - -func main() { - command.Write(command.Generate(command.Read())) -} diff --git a/vendor/k8s.io/code-generator/cmd/import-boss/.gitignore b/vendor/k8s.io/code-generator/cmd/import-boss/.gitignore deleted file mode 100644 index a5c47b66f..000000000 --- a/vendor/k8s.io/code-generator/cmd/import-boss/.gitignore +++ /dev/null @@ -1 +0,0 @@ -import-boss diff --git a/vendor/k8s.io/code-generator/cmd/import-boss/main.go b/vendor/k8s.io/code-generator/cmd/import-boss/main.go deleted file mode 100644 index d99899441..000000000 --- a/vendor/k8s.io/code-generator/cmd/import-boss/main.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright 2016 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. -*/ - -// import-boss enforces import restrictions in a given repository. -// -// When a directory is verified, import-boss looks for a file called -// ".import-restrictions". If this file is not found, parent directories will be -// recursively searched. -// -// If an ".import-restrictions" file is found, then all imports of the package -// are checked against each "rule" in the file. A rule consists of three parts: -// * A SelectorRegexp, to select the import paths that the rule applies to. -// * A list of AllowedPrefixes -// * A list of ForbiddenPrefixes -// An import is allowed if it matches at least one allowed prefix and does not -// match any forbidden prefix. An example file looks like this: -// -// { -// "Rules": [ -// { -// "SelectorRegexp": "k8s[.]io", -// "AllowedPrefixes": [ -// "k8s.io/gengo/examples", -// "k8s.io/kubernetes/third_party" -// ], -// "ForbiddenPrefixes": [ -// "k8s.io/kubernetes/pkg/third_party/deprecated" -// ] -// }, -// { -// "SelectorRegexp": "^unsafe$", -// "AllowedPrefixes": [ -// ], -// "ForbiddenPrefixes": [ -// "" -// ] -// } -// ] -// } -// -// Note the second block explicitly matches the unsafe package, and forbids it -// ("" is a prefix of everything). -package main - -import ( - "os" - "path/filepath" - - "k8s.io/code-generator/pkg/util" - "k8s.io/gengo/args" - "k8s.io/gengo/examples/import-boss/generators" - - "github.com/golang/glog" -) - -func main() { - arguments := args.Default() - - // Override defaults. - arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) - arguments.InputDirs = []string{ - "k8s.io/kubernetes/pkg/...", - "k8s.io/kubernetes/cmd/...", - "k8s.io/kubernetes/plugin/...", - } - - if err := arguments.Execute( - generators.NameSystems(), - generators.DefaultNameSystem(), - generators.Packages, - ); err != nil { - glog.Errorf("Error: %v", err) - os.Exit(1) - } - glog.V(2).Info("Completed successfully.") -} diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/args/args.go b/vendor/k8s.io/code-generator/cmd/register-gen/args/args.go deleted file mode 100644 index 2e3ab084e..000000000 --- a/vendor/k8s.io/code-generator/cmd/register-gen/args/args.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -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. -*/ - -package args - -import ( - "fmt" - - "k8s.io/gengo/args" -) - -// NewDefaults returns default arguments for the generator. -func NewDefaults() *args.GeneratorArgs { - genericArgs := args.Default().WithoutDefaultFlagParsing() - genericArgs.OutputFileBaseName = "zz_generated.register" - return genericArgs -} - -// Validate checks the given arguments. -func Validate(genericArgs *args.GeneratorArgs) error { - if len(genericArgs.OutputFileBaseName) == 0 { - return fmt.Errorf("output file base name cannot be empty") - } - - return nil -} diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go b/vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go deleted file mode 100644 index ca13ca857..000000000 --- a/vendor/k8s.io/code-generator/cmd/register-gen/generators/packages.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -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. -*/ - -package generators - -import ( - "fmt" - "os" - "path" - "strings" - - "github.com/golang/glog" - - clientgentypes "k8s.io/code-generator/cmd/client-gen/types" - "k8s.io/gengo/args" - "k8s.io/gengo/generator" - "k8s.io/gengo/namer" - "k8s.io/gengo/types" -) - -// NameSystems returns the name system used by the generators in this package. -func NameSystems() namer.NameSystems { - return namer.NameSystems{} -} - -// DefaultNameSystem returns the default name system for ordering the types to be -// processed by the generators in this package. -func DefaultNameSystem() string { - return "public" -} - -// Packages makes packages to generate. -func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { - boilerplate, err := arguments.LoadGoBoilerplate() - if err != nil { - glog.Fatalf("Failed loading boilerplate: %v", err) - } - - packages := generator.Packages{} - for _, inputDir := range arguments.InputDirs { - pkg := context.Universe.Package(inputDir) - internal, err := isInternal(pkg) - if err != nil { - glog.V(5).Infof("skipping the generation of %s file, due to err %v", arguments.OutputFileBaseName, err) - continue - } - if internal { - glog.V(5).Infof("skipping the generation of %s file because %s package contains internal types, note that internal types don't have \"json\" tags", arguments.OutputFileBaseName, pkg.Name) - continue - } - registerFileName := "register.go" - searchPath := path.Join(args.DefaultSourceTree(), inputDir, registerFileName) - if _, err := os.Stat(path.Join(searchPath)); err == nil { - glog.V(5).Infof("skipping the generation of %s file because %s already exists in the path %s", arguments.OutputFileBaseName, registerFileName, searchPath) - continue - } else if err != nil && !os.IsNotExist(err) { - glog.Fatalf("an error %v has occurred while checking if %s exists", err, registerFileName) - } - - gv := clientgentypes.GroupVersion{} - { - pathParts := strings.Split(pkg.Path, "/") - if len(pathParts) < 2 { - glog.Errorf("the path of the package must contain the group name and the version, path = %s", pkg.Path) - continue - } - gv.Group = clientgentypes.Group(pathParts[len(pathParts)-2]) - gv.Version = clientgentypes.Version(pathParts[len(pathParts)-1]) - - // if there is a comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", - // extract the fully qualified API group name from it and overwrite the group inferred from the package path - if override := types.ExtractCommentTags("+", pkg.DocComments)["groupName"]; override != nil { - groupName := override[0] - glog.V(5).Infof("overriding the group name with = %s", groupName) - gv.Group = clientgentypes.Group(groupName) - } - } - - typesToRegister := []*types.Type{} - for _, t := range pkg.Types { - glog.V(5).Infof("considering type = %s", t.Name.String()) - for _, typeMember := range t.Members { - if typeMember.Name == "TypeMeta" && typeMember.Embedded == true { - typesToRegister = append(typesToRegister, t) - } - } - } - - packages = append(packages, - &generator.DefaultPackage{ - PackageName: pkg.Name, - PackagePath: pkg.Path, - HeaderText: boilerplate, - GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { - return []generator.Generator{ - &registerExternalGenerator{ - DefaultGen: generator.DefaultGen{ - OptionalName: arguments.OutputFileBaseName, - }, - gv: gv, - typesToGenerate: typesToRegister, - outputPackage: pkg.Path, - imports: generator.NewImportTracker(), - }, - } - }, - }) - } - - return packages -} - -// isInternal determines whether the given package -// contains the internal types or not -func isInternal(p *types.Package) (bool, error) { - for _, t := range p.Types { - for _, member := range t.Members { - if member.Name == "TypeMeta" { - return !strings.Contains(member.Tags, "json"), nil - } - } - } - return false, fmt.Errorf("unable to find TypeMeta for any types in package %s", p.Path) -} diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go b/vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go deleted file mode 100644 index c831c575d..000000000 --- a/vendor/k8s.io/code-generator/cmd/register-gen/generators/register_external.go +++ /dev/null @@ -1,117 +0,0 @@ -/* -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. -*/ - -package generators - -import ( - "io" - "sort" - - clientgentypes "k8s.io/code-generator/cmd/client-gen/types" - "k8s.io/gengo/generator" - "k8s.io/gengo/namer" - "k8s.io/gengo/types" -) - -type registerExternalGenerator struct { - generator.DefaultGen - outputPackage string - gv clientgentypes.GroupVersion - typesToGenerate []*types.Type - imports namer.ImportTracker -} - -var _ generator.Generator = &registerExternalGenerator{} - -func (g *registerExternalGenerator) Filter(_ *generator.Context, _ *types.Type) bool { - return false -} - -func (g *registerExternalGenerator) Imports(c *generator.Context) (imports []string) { - return g.imports.ImportLines() -} - -func (g *registerExternalGenerator) Namers(_ *generator.Context) namer.NameSystems { - return namer.NameSystems{ - "raw": namer.NewRawNamer(g.outputPackage, g.imports), - } -} - -func (g *registerExternalGenerator) Finalize(context *generator.Context, w io.Writer) error { - typesToGenerateOnlyNames := make([]string, len(g.typesToGenerate)) - for index, typeToGenerate := range g.typesToGenerate { - typesToGenerateOnlyNames[index] = typeToGenerate.Name.Name - } - - // sort the list of types to register, so that the generator produces stable output - sort.Strings(typesToGenerateOnlyNames) - - sw := generator.NewSnippetWriter(w, context, "$", "$") - m := map[string]interface{}{ - "groupName": g.gv.Group, - "version": g.gv.Version, - "types": typesToGenerateOnlyNames, - "addToGroupVersion": context.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}), - "groupVersion": context.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GroupVersion"}), - } - sw.Do(registerExternalTypesTemplate, m) - return sw.Error() -} - -var registerExternalTypesTemplate = ` -// GroupName specifies the group name used to register the objects. -const GroupName = "$.groupName$" - -// GroupVersion specifies the group and the version used to register the objects. -var GroupVersion = $.groupVersion|raw${Group: GroupName, Version: "$.version$"} - -// SchemeGroupVersion is group version used to register these objects -// Deprecated: use GroupVersion instead. -var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "$.version$"} - -// Resource takes an unqualified resource and returns a Group qualified GroupResource -func Resource(resource string) schema.GroupResource { - return SchemeGroupVersion.WithResource(resource).GroupResource() -} - -var ( - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. - SchemeBuilder runtime.SchemeBuilder - localSchemeBuilder = &SchemeBuilder - // Depreciated: use Install instead - AddToScheme = localSchemeBuilder.AddToScheme - Install = localSchemeBuilder.AddToScheme -) - -func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. - localSchemeBuilder.Register(addKnownTypes) -} - -// Adds the list of known types to Scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - $range .types -$ - &$.${}, - $end$ - ) - // AddToGroupVersion allows the serialization of client types like ListOptions. - $.addToGroupVersion|raw$(scheme, SchemeGroupVersion) - return nil -} -` diff --git a/vendor/k8s.io/code-generator/cmd/register-gen/main.go b/vendor/k8s.io/code-generator/cmd/register-gen/main.go deleted file mode 100644 index db02a4af4..000000000 --- a/vendor/k8s.io/code-generator/cmd/register-gen/main.go +++ /dev/null @@ -1,52 +0,0 @@ -/* -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. -*/ - -package main - -import ( - "flag" - "path/filepath" - - "github.com/golang/glog" - "github.com/spf13/pflag" - - generatorargs "k8s.io/code-generator/cmd/register-gen/args" - "k8s.io/code-generator/cmd/register-gen/generators" - "k8s.io/code-generator/pkg/util" - "k8s.io/gengo/args" -) - -func main() { - genericArgs := generatorargs.NewDefaults() - genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) - genericArgs.AddFlags(pflag.CommandLine) - flag.Set("logtostderr", "true") - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - - pflag.Parse() - if err := generatorargs.Validate(genericArgs); err != nil { - glog.Fatalf("Error: %v", err) - } - - if err := genericArgs.Execute( - generators.NameSystems(), - generators.DefaultNameSystem(), - generators.Packages, - ); err != nil { - glog.Fatalf("Error: %v", err) - } - glog.V(2).Info("Completed successfully.") -} diff --git a/vendor/k8s.io/code-generator/hack/boilerplate.go.txt b/vendor/k8s.io/code-generator/hack/boilerplate.go.txt deleted file mode 100644 index b7c650da4..000000000 --- a/vendor/k8s.io/code-generator/hack/boilerplate.go.txt +++ /dev/null @@ -1,16 +0,0 @@ -/* -Copyright 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. -*/ - diff --git a/vendor/k8s.io/code-generator/hack/update-codegen.sh b/vendor/k8s.io/code-generator/hack/update-codegen.sh deleted file mode 100755 index 767c2ab36..000000000 --- a/vendor/k8s.io/code-generator/hack/update-codegen.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -set -o errexit -set -o nounset -set -o pipefail - -# generate the code with: -# - --output-base because this script should also be able to run inside the vendor dir of -# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir -# instead of the $GOPATH directly. For normal projects this can be dropped. -$(dirname ${BASH_SOURCE})/../generate-internal-groups.sh all \ - k8s.io/code-generator/_examples/apiserver k8s.io/code-generator/_examples/apiserver/apis k8s.io/code-generator/_examples/apiserver/apis \ - "example:v1 example2:v1" \ - --output-base "$(dirname ${BASH_SOURCE})/../../.." -$(dirname ${BASH_SOURCE})/../generate-groups.sh all \ - k8s.io/code-generator/_examples/crd k8s.io/code-generator/_examples/crd/apis \ - "example:v1 example2:v1" \ - --output-base "$(dirname ${BASH_SOURCE})/../../.." diff --git a/vendor/k8s.io/code-generator/hack/verify-codegen.sh b/vendor/k8s.io/code-generator/hack/verify-codegen.sh deleted file mode 100755 index 25302228d..000000000 --- a/vendor/k8s.io/code-generator/hack/verify-codegen.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -# 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. - -set -o errexit -set -o nounset -set -o pipefail - -SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/.. -SCRIPT_BASE=${SCRIPT_ROOT}/../.. - -DIFFROOT="${SCRIPT_ROOT}/_examples" -TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/_examples" -_tmp="${SCRIPT_ROOT}/_tmp" - -cleanup() { - rm -rf "${_tmp}" -} -trap "cleanup" EXIT SIGINT - -cleanup - -mkdir -p "${TMP_DIFFROOT}" -cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" - -"${SCRIPT_ROOT}/hack/update-codegen.sh" -echo "diffing ${DIFFROOT} against freshly generated codegen" -ret=0 -diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? -cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}" -if [[ $ret -eq 0 ]] -then - echo "${DIFFROOT} up to date." -else - echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh" - exit 1 -fi - -# smoke test -echo "Smoke testing _example by compiling..." -go build ${SCRIPT_ROOT}/_example/... \ No newline at end of file diff --git a/vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go b/vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go deleted file mode 100644 index 67957ee33..000000000 --- a/vendor/k8s.io/code-generator/third_party/forked/golang/reflect/type.go +++ /dev/null @@ -1,91 +0,0 @@ -//This package is copied from Go library reflect/type.go. -//The struct tag library provides no way to extract the list of struct tags, only -//a specific tag -package reflect - -import ( - "fmt" - - "strconv" - "strings" -) - -type StructTag struct { - Name string - Value string -} - -func (t StructTag) String() string { - return fmt.Sprintf("%s:%q", t.Name, t.Value) -} - -type StructTags []StructTag - -func (tags StructTags) String() string { - s := make([]string, 0, len(tags)) - for _, tag := range tags { - s = append(s, tag.String()) - } - return "`" + strings.Join(s, " ") + "`" -} - -func (tags StructTags) Has(name string) bool { - for i := range tags { - if tags[i].Name == name { - return true - } - } - return false -} - -// ParseStructTags returns the full set of fields in a struct tag in the order they appear in -// the struct tag. -func ParseStructTags(tag string) (StructTags, error) { - tags := StructTags{} - for tag != "" { - // Skip leading space. - i := 0 - for i < len(tag) && tag[i] == ' ' { - i++ - } - tag = tag[i:] - if tag == "" { - break - } - - // Scan to colon. A space, a quote or a control character is a syntax error. - // Strictly speaking, control chars include the range [0x7f, 0x9f], not just - // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters - // as it is simpler to inspect the tag's bytes than the tag's runes. - i = 0 - for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { - i++ - } - if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { - break - } - name := string(tag[:i]) - tag = tag[i+1:] - - // Scan quoted string to find value. - i = 1 - for i < len(tag) && tag[i] != '"' { - if tag[i] == '\\' { - i++ - } - i++ - } - if i >= len(tag) { - break - } - qvalue := string(tag[:i+1]) - tag = tag[i+1:] - - value, err := strconv.Unquote(qvalue) - if err != nil { - return nil, err - } - tags = append(tags, StructTag{Name: name, Value: value}) - } - return tags, nil -} diff --git a/vendor/k8s.io/gengo/.import-restrictions b/vendor/k8s.io/gengo/.import-restrictions new file mode 100644 index 000000000..fd05377f0 --- /dev/null +++ b/vendor/k8s.io/gengo/.import-restrictions @@ -0,0 +1,10 @@ +{ + "Rules": [ + { + "SelectorRegexp": "k8s[.]io", + "AllowedPrefixes": [ + "k8s.io/gengo" + ] + } + ] +} diff --git a/vendor/k8s.io/gengo/.travis.yml b/vendor/k8s.io/gengo/.travis.yml new file mode 100644 index 000000000..f89579ed2 --- /dev/null +++ b/vendor/k8s.io/gengo/.travis.yml @@ -0,0 +1,16 @@ +language: go +go: + - 1.8 + - tip + +go_import_path: k8s.io/gengo + +jobs: + include: + - stage: Run tests + script: + - find . -name vendor -prune -o -name Makefile -execdir make test \; + - go test -v ./... + - stage: Verify examples + script: + - go run ./examples/import-boss/main.go -i k8s.io/gengo/... --verify-only diff --git a/vendor/k8s.io/gengo/OWNERS b/vendor/k8s.io/gengo/OWNERS new file mode 100644 index 000000000..756e9b6df --- /dev/null +++ b/vendor/k8s.io/gengo/OWNERS @@ -0,0 +1,4 @@ +approvers: + - lavalamp + - wojtek-t + - sttts diff --git a/vendor/k8s.io/gengo/README.md b/vendor/k8s.io/gengo/README.md new file mode 100644 index 000000000..8b7f6cc10 --- /dev/null +++ b/vendor/k8s.io/gengo/README.md @@ -0,0 +1,53 @@ +# gengo + +[![Travis Widget]][Travis] [![GoDoc Widget]][GoDoc] [![GoReport]][GoReportStatus] + +[Travis]: https://travis-ci.org/kubernetes/gengo +[Travis Widget]: https://travis-ci.org/kubernetes/gengo.svg?branch=master +[GoDoc]: https://godoc.org/k8s.io/gengo +[GoDoc Widget]: https://godoc.org/k8s.io/gengo?status.svg +[GoReport]: https://goreportcard.com/badge/github.com/kubernetes/gengo +[GoReportStatus]: https://goreportcard.com/report/github.com/kubernetes/gengo + +A package for generating things based on go files. This mechanism was first used +in Kubernetes and is split out here for ease of reuse and maintainability. + +`go get k8s.io/gengo` + +## Examples + +A set generator, deep-copy generator, defaulter generator and go-to-protobuf +generator are included here. Also, import-boss will enforce arbitrary rules about +import trees. + +## args/ + +Package args defines common arguments for a generator binary. + +## generator/ + +Package generator defines interfaces for code generators to implement, and +machinery that will execute those code generators. + +## types/ + +Package types contains the type system definition. It is modeled after Go's type +system, but it's intended that you could produce these types by parsing +something else, if you want to write the parser/converter. + +We don't directly use the go types in the go typecheck library because they are +based on implementing differing interfaces. A struct-based format is more +convenient input for template driven output. + +## parser/ + +Package parser parses go source files. + +## namer/ + +Package namer defines a naming system, for: +* helping you reference go objects in a syntactically correct way +* keeping track of what you reference, for importing the right packages +* and defining parallel tracks of names, for making public interfaces and + private implementations. + diff --git a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/doc.go b/vendor/k8s.io/gengo/args/args_test.go similarity index 61% rename from vendor/k8s.io/code-generator/_examples/apiserver/apis/example/doc.go rename to vendor/k8s.io/gengo/args/args_test.go index b221d7eb4..3e85447f8 100644 --- a/vendor/k8s.io/code-generator/_examples/apiserver/apis/example/doc.go +++ b/vendor/k8s.io/gengo/args/args_test.go @@ -14,6 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -// +k8s:deepcopy-gen=package -// +groupName=example.apiserver.code-generator.k8s.io -package example // import "k8s.io/code-generator/_examples/apiserver/apis/example" +package args + +import ( + "testing" + + "k8s.io/gengo/types" +) + +func TestInputIncludes(t *testing.T) { + a := &GeneratorArgs{ + InputDirs: []string{"a/b/..."}, + } + if !a.InputIncludes(&types.Package{Path: "a/b/c"}) { + t.Errorf("Expected /... syntax to work") + } + if a.InputIncludes(&types.Package{Path: "a/c/b"}) { + t.Errorf("Expected correctness") + } +} diff --git a/vendor/k8s.io/gengo/code-of-conduct.md b/vendor/k8s.io/gengo/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/gengo/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/k8s.io/gengo/examples/deepcopy-gen/.gitignore b/vendor/k8s.io/gengo/examples/deepcopy-gen/.gitignore new file mode 100644 index 000000000..eab8184d4 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/deepcopy-gen/.gitignore @@ -0,0 +1 @@ +deepcopy-gen diff --git a/vendor/k8s.io/gengo/examples/deepcopy-gen/Makefile b/vendor/k8s.io/gengo/examples/deepcopy-gen/Makefile new file mode 100644 index 000000000..66af5608e --- /dev/null +++ b/vendor/k8s.io/gengo/examples/deepcopy-gen/Makefile @@ -0,0 +1,16 @@ +TOOL=deepcopy-gen + +test: + @if ! git diff --quiet HEAD; then \ + echo "FAIL: git client is not clean"; \ + false; \ + fi + @go build -o /tmp/$(TOOL) + @PKGS=$$(go list ./output_tests/... | paste -sd' ' -); \ + /tmp/$(TOOL) --logtostderr --v=4 -i $$(echo $$PKGS | sed 's/ /,/g') -O zz_generated + @if ! git diff --quiet HEAD; then \ + echo "FAIL: output files changed"; \ + git diff; \ + false; \ + fi + diff --git a/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy_test.go b/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy_test.go new file mode 100644 index 000000000..8b9bad413 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy_test.go @@ -0,0 +1,713 @@ +/* +Copyright 2016 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 generators + +import ( + "reflect" + "testing" + + "k8s.io/gengo/types" +) + +func Test_isRootedUnder(t *testing.T) { + testCases := []struct { + path string + roots []string + expect bool + }{ + { + path: "/foo/bar", + roots: nil, + expect: false, + }, + { + path: "/foo/bar", + roots: []string{}, + expect: false, + }, + { + path: "/foo/bar", + roots: []string{ + "/bad", + }, + expect: false, + }, + { + path: "/foo/bar", + roots: []string{ + "/foo", + }, + expect: true, + }, + { + path: "/foo/bar", + roots: []string{ + "/bad", + "/foo", + }, + expect: true, + }, + { + path: "/foo/bar/qux/zorb", + roots: []string{ + "/foo/bar/qux", + }, + expect: true, + }, + { + path: "/foo/bar", + roots: []string{ + "/foo/bar", + }, + expect: true, + }, + { + path: "/foo/barn", + roots: []string{ + "/foo/bar", + }, + expect: false, + }, + { + path: "/foo/bar", + roots: []string{ + "/foo/barn", + }, + expect: false, + }, + { + path: "/foo/bar", + roots: []string{ + "", + }, + expect: true, + }, + } + + for i, tc := range testCases { + r := isRootedUnder(tc.path, tc.roots) + if r != tc.expect { + t.Errorf("case[%d]: expected %t, got %t for %q in %q", i, tc.expect, r, tc.path, tc.roots) + } + } +} + +func Test_deepCopyMethod(t *testing.T) { + testCases := []struct { + typ types.Type + expect bool + error bool + }{ + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + // No DeepCopy method. + Methods: map[string]*types.Type{}, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // No DeepCopy method. + "method": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (no result). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (wrong result). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() int"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature with pointer receiver, but non-pointer result. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature with non-pointer receiver, but pointer result. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with non-pointer receiver. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with pointer receiver. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (has params). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func(int) pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (extra results). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() (pkgname.typename, int)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + } + + for i, tc := range testCases { + r, err := deepCopyMethod(&tc.typ) + if tc.error && err == nil { + t.Errorf("case[%d]: expected an error, got none", i) + } else if !tc.error && err != nil { + t.Errorf("case[%d]: expected no error, got: %v", i, err) + } else if !tc.error && (r != nil) != tc.expect { + t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) + } + } +} + +func Test_deepCopyIntoMethod(t *testing.T) { + testCases := []struct { + typ types.Type + expect bool + error bool + }{ + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + // No DeepCopyInto method. + Methods: map[string]*types.Type{}, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // No DeepCopyInto method. + "method": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (no parameter). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (unexpected result). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename) int"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.Type{ + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (non-pointer parameter, pointer receiver). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + {Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (non-pointer parameter, non-pointer receiver). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{ + {Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with non-pointer receiver. + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with pointer receiver. + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: true, + }, + } + + for i, tc := range testCases { + r, err := deepCopyIntoMethod(&tc.typ) + if tc.error && err == nil { + t.Errorf("case[%d]: expected an error, got none", i) + } else if !tc.error && err != nil { + t.Errorf("case[%d]: expected no error, got: %v", i, err) + } else if !tc.error && (r != nil) != tc.expect { + t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) + } + } +} + +func Test_extractTagParams(t *testing.T) { + testCases := []struct { + comments []string + expect *tagValue + }{ + { + comments: []string{ + "Human comment", + }, + expect: nil, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen", + }, + expect: &tagValue{ + value: "", + register: false, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package", + }, + expect: &tagValue{ + value: "package", + register: false, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register", + }, + expect: &tagValue{ + value: "package", + register: true, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register=true", + }, + expect: &tagValue{ + value: "package", + register: true, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register=false", + }, + expect: &tagValue{ + value: "package", + register: false, + }, + }, + } + + for i, tc := range testCases { + r := extractTag(tc.comments) + if r == nil && tc.expect != nil { + t.Errorf("case[%d]: expected non-nil", i) + } + if r != nil && tc.expect == nil { + t.Errorf("case[%d]: expected nil, got %v", i, *r) + } + if r != nil && *r != *tc.expect { + t.Errorf("case[%d]: expected %v, got %v", i, *tc.expect, *r) + } + } +} + +func Test_extractInterfacesTag(t *testing.T) { + testCases := []struct { + comments []string + expect []string + }{ + { + comments: []string{}, + expect: nil, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.List", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.Object", + }, + }, + } + + for i, tc := range testCases { + r := extractInterfacesTag(tc.comments) + if r == nil && tc.expect != nil { + t.Errorf("case[%d]: expected non-nil", i) + } + if r != nil && tc.expect == nil { + t.Errorf("case[%d]: expected nil, got %v", i, r) + } + if r != nil && !reflect.DeepEqual(r, tc.expect) { + t.Errorf("case[%d]: expected %v, got %v", i, tc.expect, r) + } + } +} diff --git a/vendor/k8s.io/gengo/examples/deepcopy-gen/main.go b/vendor/k8s.io/gengo/examples/deepcopy-gen/main.go new file mode 100644 index 000000000..53d1ee36d --- /dev/null +++ b/vendor/k8s.io/gengo/examples/deepcopy-gen/main.go @@ -0,0 +1,88 @@ +/* +Copyright 2015 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. +*/ + +// deepcopy-gen is a tool for auto-generating DeepCopy functions. +// +// Given a list of input directories, it will generate DeepCopy and DeepCopyInto +// methods that efficiently perform a full deep-copy of each type. If these +// already exist (are predefined by the developer), they are used instead of +// generating new ones. +// +// If interfaces are referenced in types, it is expected that corresponding +// DeepCopyInterfaceName methods exist, e.g. DeepCopyObject for runtime.Object. +// These can be predefined by the developer or generated through tags, see below. +// They must be added to the interfaces themselves manually, e.g. +// type Object interface { +// ... +// DeepCopyObject() Object +// } +// +// All generation is governed by comment tags in the source. Any package may +// request DeepCopy generation by including a comment in the file-comments of +// one file, of the form: +// // +k8s:deepcopy-gen=package +// +// DeepCopy functions can be generated for individual types, rather than the +// entire package by specifying a comment on the type definion of the form: +// // +k8s:deepcopy-gen=true +// +// When generating for a whole package, individual types may opt out of +// DeepCopy generation by specifying a comment on the type definition of the form: +// // +k8s:deepcopy-gen=false +// +// Additional DeepCopyInterfaceName methods can be generated by sepcifying a +// comment on the type definition of the form: +// // +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object,k8s.io/kubernetes/runtime.List +// This leads to the generation of DeepCopyObject and DeepCopyList with the given +// interfaces as return types. We say that the tagged type implements deepcopy for the +// interfaces. +// +// The deepcopy funcs for interfaces using "+k8s:deepcopy-gen:interfaces" use the pointer +// of the type as receiver. For those special cases where the non-pointer object should +// implement the interface, this can be done with: +// // +k8s:deepcopy-gen:nonpointer-interfaces=true +package main + +import ( + "k8s.io/gengo/args" + "k8s.io/gengo/examples/deepcopy-gen/generators" + + "github.com/golang/glog" + "github.com/spf13/pflag" +) + +func main() { + arguments := args.Default() + + // Override defaults. + arguments.OutputFileBaseName = "deepcopy_generated" + + // Custom args. + customArgs := &generators.CustomArgs{} + pflag.CommandLine.StringSliceVar(&customArgs.BoundingDirs, "bounding-dirs", customArgs.BoundingDirs, + "Comma-separated list of import paths which bound the types for which deep-copies will be generated.") + arguments.CustomArgs = customArgs + + // Run it. + if err := arguments.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + glog.Fatalf("Error: %v", err) + } + glog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/.gitignore b/vendor/k8s.io/gengo/examples/defaulter-gen/.gitignore new file mode 100644 index 000000000..dbb164e0f --- /dev/null +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/.gitignore @@ -0,0 +1 @@ +defaulter-gen diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/.import-restrictions b/vendor/k8s.io/gengo/examples/defaulter-gen/.import-restrictions new file mode 100644 index 000000000..7e69de1f8 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/.import-restrictions @@ -0,0 +1,12 @@ +{ + "Rules": [ + { + "SelectorRegexp": "k8s[.]io", + "AllowedPrefixes": [ + "k8s.io/gengo", + "k8s.io/kubernetes/third_party/forked/golang", + "k8s.io/apimachinery/pkg/runtime" + ] + } + ] +} diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/Makefile b/vendor/k8s.io/gengo/examples/defaulter-gen/Makefile new file mode 100644 index 000000000..380442ce5 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/Makefile @@ -0,0 +1,15 @@ +TOOL=defaulter-gen + +test: + @if ! git diff --quiet HEAD; then \ + echo "FAIL: git client is not clean"; \ + false; \ + fi + @go build -o /tmp/$(TOOL) + @PKGS=$$(cd _output_tests; go list ./... | paste -sd' ' -); \ + /tmp/$(TOOL) --logtostderr --v=4 -i $$(echo $$PKGS | sed 's/ /,/g') -O zz_generated + @if ! git diff --quiet HEAD; then \ + echo "FAIL: output files changed"; \ + git diff; \ + false; \ + fi diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/OWNERS b/vendor/k8s.io/gengo/examples/defaulter-gen/OWNERS new file mode 100644 index 000000000..cefd99c34 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/OWNERS @@ -0,0 +1,2 @@ +approvers: + - smarterclayton diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/main.go b/vendor/k8s.io/gengo/examples/defaulter-gen/main.go new file mode 100644 index 000000000..822ec4c5b --- /dev/null +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/main.go @@ -0,0 +1,75 @@ +/* +Copyright 2016 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. +*/ + +// defaulter-gen is a tool for auto-generating Defaulter functions. +// +// Given a list of input directories, it will scan for top level types +// and generate efficient defaulters for an entire object from the sum +// of the SetDefault_* methods contained in the object tree. +// +// Generation is governed by comment tags in the source. Any package may +// request defaulter generation by including one or more comment tags at +// the package comment level: +// +// // +k8s:defaulter-gen=<field-name-to-flag> +// +// which will create defaulters for any type that contains the provided +// field name (if the type has defaulters). Any type may request explicit +// defaulting by providing the comment tag: +// +// // +k8s:defaulter-gen=true|false +// +// An existing defaulter method (`SetDefaults_TYPE`) can provide the +// comment tag: +// +// // +k8s:defaulter-gen=covers +// +// to indicate that the defaulter does not or should not call any nested +// defaulters. +package main + +import ( + "k8s.io/gengo/args" + "k8s.io/gengo/examples/defaulter-gen/generators" + + "github.com/golang/glog" + "github.com/spf13/pflag" +) + +func main() { + arguments := args.Default() + + // Override defaults. + arguments.OutputFileBaseName = "defaulter_generated" + + // Custom args. + customArgs := &generators.CustomArgs{ + ExtraPeerDirs: []string{}, + } + pflag.CommandLine.StringSliceVar(&customArgs.ExtraPeerDirs, "extra-peer-dirs", customArgs.ExtraPeerDirs, + "Comma-separated list of import paths which are considered, after tag-specified peers, for conversions.") + arguments.CustomArgs = customArgs + + // Run it. + if err := arguments.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + glog.Fatalf("Error: %v", err) + } + glog.V(2).Info("Completed successfully.") +} diff --git a/vendor/k8s.io/code-generator/cmd/set-gen/.gitignore b/vendor/k8s.io/gengo/examples/set-gen/.gitignore similarity index 100% rename from vendor/k8s.io/code-generator/cmd/set-gen/.gitignore rename to vendor/k8s.io/gengo/examples/set-gen/.gitignore diff --git a/vendor/k8s.io/gengo/examples/set-gen/Makefile b/vendor/k8s.io/gengo/examples/set-gen/Makefile new file mode 100644 index 000000000..0e73130ae --- /dev/null +++ b/vendor/k8s.io/gengo/examples/set-gen/Makefile @@ -0,0 +1,15 @@ +TOOL=set-gen + +test: + @if ! git diff --quiet HEAD; then \ + echo "FAIL: git client is not clean"; \ + false; \ + fi + @go build -o /tmp/$(TOOL) + @PKGS=$$(go list ./sets/types | paste -sd' ' -); \ + /tmp/$(TOOL) --logtostderr --v=4 -i $$(echo $$PKGS | sed 's/ /,/g') -O zz_generated -o ./sets + @if ! git diff --quiet HEAD; then \ + echo "FAIL: output files changed"; \ + git diff; \ + false; \ + fi diff --git a/vendor/k8s.io/code-generator/cmd/set-gen/main.go b/vendor/k8s.io/gengo/examples/set-gen/main.go similarity index 77% rename from vendor/k8s.io/code-generator/cmd/set-gen/main.go rename to vendor/k8s.io/gengo/examples/set-gen/main.go index cf8f01d89..7efc8e6ae 100644 --- a/vendor/k8s.io/code-generator/cmd/set-gen/main.go +++ b/vendor/k8s.io/gengo/examples/set-gen/main.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// set-gen is an example usage of gengo. +// set-gen is an example usage of go2idl. // // Structs in the input directories with the below line in their comments will // have sets generated for them. @@ -26,9 +26,7 @@ package main import ( "os" - "path/filepath" - "k8s.io/code-generator/pkg/util" "k8s.io/gengo/args" "k8s.io/gengo/examples/set-gen/generators" @@ -37,12 +35,6 @@ import ( func main() { arguments := args.Default() - - // Override defaults. - arguments.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) - arguments.InputDirs = []string{"k8s.io/kubernetes/pkg/util/sets/types"} - arguments.OutputPackagePath = "k8s.io/apimachinery/pkg/util/sets" - if err := arguments.Execute( generators.NameSystems(), generators.DefaultNameSystem(), diff --git a/vendor/k8s.io/gengo/examples/set-gen/sets/set_test.go b/vendor/k8s.io/gengo/examples/set-gen/sets/set_test.go new file mode 100644 index 000000000..df722ec27 --- /dev/null +++ b/vendor/k8s.io/gengo/examples/set-gen/sets/set_test.go @@ -0,0 +1,270 @@ +/* +Copyright 2014 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 sets + +import ( + "reflect" + "testing" +) + +func TestStringSet(t *testing.T) { + s := String{} + s2 := String{} + if len(s) != 0 { + t.Errorf("Expected len=0: %d", len(s)) + } + s.Insert("a", "b") + if len(s) != 2 { + t.Errorf("Expected len=2: %d", len(s)) + } + s.Insert("c") + if s.Has("d") { + t.Errorf("Unexpected contents: %#v", s) + } + if !s.Has("a") { + t.Errorf("Missing contents: %#v", s) + } + s.Delete("a") + if s.Has("a") { + t.Errorf("Unexpected contents: %#v", s) + } + s.Insert("a") + if s.HasAll("a", "b", "d") { + t.Errorf("Unexpected contents: %#v", s) + } + if !s.HasAll("a", "b") { + t.Errorf("Missing contents: %#v", s) + } + s2.Insert("a", "b", "d") + if s.IsSuperset(s2) { + t.Errorf("Unexpected contents: %#v", s) + } + s2.Delete("d") + if !s.IsSuperset(s2) { + t.Errorf("Missing contents: %#v", s) + } +} + +func TestStringSetDeleteMultiples(t *testing.T) { + s := String{} + s.Insert("a", "b", "c") + if len(s) != 3 { + t.Errorf("Expected len=3: %d", len(s)) + } + + s.Delete("a", "c") + if len(s) != 1 { + t.Errorf("Expected len=1: %d", len(s)) + } + if s.Has("a") { + t.Errorf("Unexpected contents: %#v", s) + } + if s.Has("c") { + t.Errorf("Unexpected contents: %#v", s) + } + if !s.Has("b") { + t.Errorf("Missing contents: %#v", s) + } + +} + +func TestNewStringSet(t *testing.T) { + s := NewString("a", "b", "c") + if len(s) != 3 { + t.Errorf("Expected len=3: %d", len(s)) + } + if !s.Has("a") || !s.Has("b") || !s.Has("c") { + t.Errorf("Unexpected contents: %#v", s) + } +} + +func TestStringSetList(t *testing.T) { + s := NewString("z", "y", "x", "a") + if !reflect.DeepEqual(s.List(), []string{"a", "x", "y", "z"}) { + t.Errorf("List gave unexpected result: %#v", s.List()) + } +} + +func TestStringSetDifference(t *testing.T) { + a := NewString("1", "2", "3") + b := NewString("1", "2", "4", "5") + c := a.Difference(b) + d := b.Difference(a) + if len(c) != 1 { + t.Errorf("Expected len=1: %d", len(c)) + } + if !c.Has("3") { + t.Errorf("Unexpected contents: %#v", c.List()) + } + if len(d) != 2 { + t.Errorf("Expected len=2: %d", len(d)) + } + if !d.Has("4") || !d.Has("5") { + t.Errorf("Unexpected contents: %#v", d.List()) + } +} + +func TestStringSetHasAny(t *testing.T) { + a := NewString("1", "2", "3") + + if !a.HasAny("1", "4") { + t.Errorf("expected true, got false") + } + + if a.HasAny("0", "4") { + t.Errorf("expected false, got true") + } +} + +func TestStringSetEquals(t *testing.T) { + // Simple case (order doesn't matter) + a := NewString("1", "2") + b := NewString("2", "1") + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + // It is a set; duplicates are ignored + b = NewString("2", "2", "1") + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + // Edge cases around empty sets / empty strings + a = NewString() + b = NewString() + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + b = NewString("1", "2", "3") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + b = NewString("1", "2", "") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + // Check for equality after mutation + a = NewString() + a.Insert("1") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + a.Insert("2") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } + + a.Insert("") + if !a.Equal(b) { + t.Errorf("Expected to be equal: %v vs %v", a, b) + } + + a.Delete("") + if a.Equal(b) { + t.Errorf("Expected to be not-equal: %v vs %v", a, b) + } +} + +func TestStringUnion(t *testing.T) { + tests := []struct { + s1 String + s2 String + expected String + }{ + { + NewString("1", "2", "3", "4"), + NewString("3", "4", "5", "6"), + NewString("1", "2", "3", "4", "5", "6"), + }, + { + NewString("1", "2", "3", "4"), + NewString(), + NewString("1", "2", "3", "4"), + }, + { + NewString(), + NewString("1", "2", "3", "4"), + NewString("1", "2", "3", "4"), + }, + { + NewString(), + NewString(), + NewString(), + }, + } + + for _, test := range tests { + union := test.s1.Union(test.s2) + if union.Len() != test.expected.Len() { + t.Errorf("Expected union.Len()=%d but got %d", test.expected.Len(), union.Len()) + } + + if !union.Equal(test.expected) { + t.Errorf("Expected union.Equal(expected) but not true. union:%v expected:%v", union.List(), test.expected.List()) + } + } +} + +func TestStringIntersection(t *testing.T) { + tests := []struct { + s1 String + s2 String + expected String + }{ + { + NewString("1", "2", "3", "4"), + NewString("3", "4", "5", "6"), + NewString("3", "4"), + }, + { + NewString("1", "2", "3", "4"), + NewString("1", "2", "3", "4"), + NewString("1", "2", "3", "4"), + }, + { + NewString("1", "2", "3", "4"), + NewString(), + NewString(), + }, + { + NewString(), + NewString("1", "2", "3", "4"), + NewString(), + }, + { + NewString(), + NewString(), + NewString(), + }, + } + + for _, test := range tests { + intersection := test.s1.Intersection(test.s2) + if intersection.Len() != test.expected.Len() { + t.Errorf("Expected intersection.Len()=%d but got %d", test.expected.Len(), intersection.Len()) + } + + if !intersection.Equal(test.expected) { + t.Errorf("Expected intersection.Equal(expected) but not true. intersection:%v expected:%v", intersection.List(), test.expected.List()) + } + } +} diff --git a/vendor/k8s.io/gengo/generator/snippet_writer_test.go b/vendor/k8s.io/gengo/generator/snippet_writer_test.go new file mode 100644 index 000000000..046494145 --- /dev/null +++ b/vendor/k8s.io/gengo/generator/snippet_writer_test.go @@ -0,0 +1,88 @@ +/* +Copyright 2015 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 generator_test + +import ( + "bytes" + "strings" + "testing" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/parser" +) + +func construct(t *testing.T, files map[string]string) *generator.Context { + b := parser.New() + for name, src := range files { + if err := b.AddFileForTest("/tmp/"+name, name, []byte(src)); err != nil { + t.Fatal(err) + } + } + c, err := generator.NewContext(b, namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + }, "public") + if err != nil { + t.Fatal(err) + } + return c +} + +func TestSnippetWriter(t *testing.T) { + var structTest = map[string]string{ + "base/foo/proto/foo.go": ` +package foo + +// Blah is a test. +// A test, I tell you. +type Blah struct { + // A is the first field. + A int64 ` + "`" + `json:"a"` + "`" + ` + + // B is the second field. + // Multiline comments work. + B string ` + "`" + `json:"b"` + "`" + ` +} +`, + } + + c := construct(t, structTest) + b := &bytes.Buffer{} + err := generator.NewSnippetWriter(b, c, "$", "$"). + Do("$.|public$$.|private$", c.Order[0]). + Error() + if err != nil { + t.Errorf("Unexpected error %v", err) + } + if e, a := "Blahblah", b.String(); e != a { + t.Errorf("Expected %q, got %q", e, a) + } + + err = generator.NewSnippetWriter(b, c, "$", "$"). + Do("$.|public", c.Order[0]). + Error() + if err == nil { + t.Errorf("expected error on invalid template") + } else { + // Dear reader, I apologize for making the worst change + // detection test in the history of ever. + if e, a := "snippet_writer_test.go", err.Error(); !strings.Contains(a, e) { + t.Errorf("Expected %q but didn't find it in %q", e, a) + } + } +} diff --git a/vendor/k8s.io/gengo/namer/namer_test.go b/vendor/k8s.io/gengo/namer/namer_test.go new file mode 100644 index 000000000..fd5ca6362 --- /dev/null +++ b/vendor/k8s.io/gengo/namer/namer_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2015 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 namer + +import ( + "reflect" + "testing" + + "k8s.io/gengo/types" +) + +func TestNameStrategy(t *testing.T) { + u := types.Universe{} + + // Add some types. + base := u.Type(types.Name{Package: "foo/bar", Name: "Baz"}) + base.Kind = types.Struct + + tmp := u.Type(types.Name{Package: "", Name: "[]bar.Baz"}) + tmp.Kind = types.Slice + tmp.Elem = base + + tmp = u.Type(types.Name{Package: "", Name: "map[string]bar.Baz"}) + tmp.Kind = types.Map + tmp.Key = types.String + tmp.Elem = base + + tmp = u.Type(types.Name{Package: "foo/other", Name: "Baz"}) + tmp.Kind = types.Struct + tmp.Members = []types.Member{{ + Embedded: true, + Type: base, + }} + + tmp = u.Type(types.Name{Package: "", Name: "chan Baz"}) + tmp.Kind = types.Chan + tmp.Elem = base + + u.Type(types.Name{Package: "", Name: "string"}) + + o := Orderer{NewPublicNamer(0)} + order := o.OrderUniverse(u) + orderedNames := make([]string, len(order)) + for i, t := range order { + orderedNames[i] = o.Name(t) + } + expect := []string{"Baz", "Baz", "ChanBaz", "MapStringToBaz", "SliceBaz", "String"} + if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { + t.Errorf("Wanted %#v, got %#v", e, a) + } + + o = Orderer{NewRawNamer("my/package", nil)} + order = o.OrderUniverse(u) + orderedNames = make([]string, len(order)) + for i, t := range order { + orderedNames[i] = o.Name(t) + } + + expect = []string{"[]bar.Baz", "bar.Baz", "chan bar.Baz", "map[string]bar.Baz", "other.Baz", "string"} + if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { + t.Errorf("Wanted %#v, got %#v", e, a) + } + + o = Orderer{NewRawNamer("foo/bar", nil)} + order = o.OrderUniverse(u) + orderedNames = make([]string, len(order)) + for i, t := range order { + orderedNames[i] = o.Name(t) + } + + expect = []string{"Baz", "[]Baz", "chan Baz", "map[string]Baz", "other.Baz", "string"} + if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { + t.Errorf("Wanted %#v, got %#v", e, a) + } + + o = Orderer{NewPublicNamer(1)} + order = o.OrderUniverse(u) + orderedNames = make([]string, len(order)) + for i, t := range order { + orderedNames[i] = o.Name(t) + } + expect = []string{"BarBaz", "ChanBarBaz", "MapStringToBarBaz", "OtherBaz", "SliceBarBaz", "String"} + if e, a := expect, orderedNames; !reflect.DeepEqual(e, a) { + t.Errorf("Wanted %#v, got %#v", e, a) + } +} diff --git a/vendor/k8s.io/gengo/namer/plural_namer_test.go b/vendor/k8s.io/gengo/namer/plural_namer_test.go new file mode 100644 index 000000000..c10d3b71f --- /dev/null +++ b/vendor/k8s.io/gengo/namer/plural_namer_test.go @@ -0,0 +1,118 @@ +/* +Copyright 2015 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 namer + +import ( + "testing" + + "k8s.io/gengo/types" +) + +func TestPluralNamer(t *testing.T) { + exceptions := map[string]string{ + // The type name is already in the plural form + "Endpoints": "endpoints", + } + public := NewPublicPluralNamer(exceptions) + private := NewPrivatePluralNamer(exceptions) + + cases := []struct { + typeName string + expectedPrivate string + expectedPublic string + }{ + { + "Pod", + "pods", + "Pods", + }, + { + "Entry", + "entries", + "Entries", + }, + { + "Endpoints", + "endpoints", + "Endpoints", + }, + { + "Bus", + "buses", + "Buses", + }, + { + "Fizz", + "fizzes", + "Fizzes", + }, + { + "Search", + "searches", + "Searches", + }, + { + "Autograph", + "autographs", + "Autographs", + }, + { + "Dispatch", + "dispatches", + "Dispatches", + }, + { + "Earth", + "earths", + "Earths", + }, + { + "City", + "cities", + "Cities", + }, + { + "Ray", + "rays", + "Rays", + }, + { + "Fountain", + "fountains", + "Fountains", + }, + { + "Life", + "lives", + "Lives", + }, + { + "Leaf", + "leaves", + "Leaves", + }, + } + for _, c := range cases { + testType := &types.Type{Name: types.Name{Name: c.typeName}} + if e, a := c.expectedPrivate, private.Name(testType); e != a { + t.Errorf("Unexpected result from private plural namer. Expected: %s, Got: %s", e, a) + } + if e, a := c.expectedPublic, public.Name(testType); e != a { + t.Errorf("Unexpected result from public plural namer. Expected: %s, Got: %s", e, a) + } + } +} diff --git a/vendor/k8s.io/gengo/parser/local_parse_test.go b/vendor/k8s.io/gengo/parser/local_parse_test.go new file mode 100644 index 000000000..851fc7da3 --- /dev/null +++ b/vendor/k8s.io/gengo/parser/local_parse_test.go @@ -0,0 +1,68 @@ +/* +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 parser + +import ( + "testing" +) + +func TestImportBuildPackage(t *testing.T) { + b := New() + if _, err := b.importBuildPackage("fake/dep"); err != nil { + t.Fatal(err) + } + if _, ok := b.buildPackages["fake/dep"]; !ok { + t.Errorf("missing expected, but got %v", b.buildPackages) + } + + if len(b.buildPackages) > 1 { + // this would happen if the canonicalization failed to normalize the path + // you'd get a k8s.io/gengo/vendor/fake/dep key too + t.Errorf("missing one, but got %v", b.buildPackages) + } +} + +func TestCanonicalizeImportPath(t *testing.T) { + tcs := []struct { + name string + input string + output string + }{ + { + name: "passthrough", + input: "github.com/foo/bar", + output: "github.com/foo/bar", + }, + { + name: "simple", + input: "github.com/foo/vendor/k8s.io/kubernetes/pkg/api", + output: "k8s.io/kubernetes/pkg/api", + }, + { + name: "deeper", + input: "github.com/foo/bar/vendor/k8s.io/kubernetes/pkg/api", + output: "k8s.io/kubernetes/pkg/api", + }, + } + + for _, tc := range tcs { + actual := canonicalizeImportPath(tc.input) + if string(actual) != tc.output { + t.Errorf("%v: expected %q got %q", tc.name, tc.output, actual) + } + } +} diff --git a/vendor/k8s.io/gengo/parser/parse_test.go b/vendor/k8s.io/gengo/parser/parse_test.go new file mode 100644 index 000000000..6212682c3 --- /dev/null +++ b/vendor/k8s.io/gengo/parser/parse_test.go @@ -0,0 +1,458 @@ +/* +Copyright 2015 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 parser_test + +import ( + "bytes" + "path/filepath" + "reflect" + "testing" + "text/template" + + "k8s.io/gengo/args" + "k8s.io/gengo/namer" + "k8s.io/gengo/parser" + "k8s.io/gengo/types" +) + +func TestRecursive(t *testing.T) { + d := args.Default() + d.InputDirs = []string{"k8s.io/gengo/testdata/a/..."} + b, err := d.NewBuilder() + if err != nil { + t.Fatalf("Fail making builder: %v", err) + } + _, err = b.FindTypes() + if err != nil { + t.Fatalf("Fail finding types: %v", err) + } + foundB := false + for _, p := range b.FindPackages() { + t.Logf("Package: %v", p) + if p == "k8s.io/gengo/testdata/a/b" { + foundB = true + } + } + if !foundB { + t.Errorf("Expected to find packages a and b") + } +} + +type file struct { + path string + contents string +} + +// Pass files in topological order - deps first! +func construct(t *testing.T, files []file, testNamer namer.Namer) (*parser.Builder, types.Universe, []*types.Type) { + b := parser.New() + for _, f := range files { + if err := b.AddFileForTest(filepath.Dir(f.path), f.path, []byte(f.contents)); err != nil { + t.Fatal(err) + } + } + u, err := b.FindTypes() + if err != nil { + t.Fatal(err) + } + orderer := namer.Orderer{Namer: testNamer} + o := orderer.OrderUniverse(u) + return b, u, o +} + +func TestBuilder(t *testing.T) { + var testFiles = []file{ + { + path: "base/common/proto/common.go", contents: ` + package common + + type Object struct { + ID int64 + } + `, + }, { + path: "base/foo/proto/foo.go", contents: ` + package foo + + import ( + "base/common/proto" + ) + + type Blah struct { + common.Object + Count int64 + Frobbers map[string]*Frobber + Baz []Object + Nickname *string + NumberIsAFavorite map[int]bool + } + + type Frobber struct { + Name string + Amount int64 + } + + type Object struct { + common.Object + } + + func AFunc(obj1 common.Object, obj2 Object) Frobber { + } + + var AVar Frobber + + var ( + AnotherVar = Frobber{} + ) + `, + }, + } + + var tmplText = ` +package o +{{define "Struct"}}type {{Name .}} interface { {{range $m := .Members}}{{$n := Name $m.Type}} + {{if $m.Embedded}}{{$n}}{{else}}{{$m.Name}}() {{$n}}{{if $m.Type.Elem}}{{else}} + Set{{$m.Name}}({{$n}}){{end}}{{end}}{{end}} +} + +{{end}} +{{define "Func"}}{{$s := .Underlying.Signature}}var {{Name .}} func({{range $index,$elem := $s.Parameters}}{{if $index}}, {{end}}{{Raw $elem}}{{end}}) {{if $s.Results|len |gt 1}}({{end}}{{range $index,$elem := $s.Results}}{{if $index}}, {{end}}{{Raw .}}{{end}}{{if $s.Results|len |gt 1}}){{end}} = {{Raw .}} + +{{end}} +{{define "Var"}}{{$t := .Underlying}}var {{Name .}} {{Raw $t}} = {{Raw .}} + +{{end}} +{{range $t := .}}{{if eq $t.Kind "Struct"}}{{template "Struct" $t}}{{end}}{{end}} +{{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if eq $t.Underlying.Kind "Func"}}{{template "Func" $t}}{{end}}{{end}}{{end}} +{{range $t := .}}{{if eq $t.Kind "DeclarationOf"}}{{if ne $t.Underlying.Kind "Func"}}{{template "Var" $t}}{{end}}{{end}}{{end}}` + + var expect = ` +package o + + + +type CommonObject interface { + ID() Int64 + SetID(Int64) +} + +type FooBlah interface { + CommonObject + Count() Int64 + SetCount(Int64) + Frobbers() MapStringToPointerFooFrobber + Baz() SliceFooObject + Nickname() PointerString + NumberIsAFavorite() MapIntToBool +} + +type FooFrobber interface { + Name() String + SetName(String) + Amount() Int64 + SetAmount(Int64) +} + +type FooObject interface { + CommonObject +} + + +var FooAFunc func(proto.Object, proto.Object) proto.Frobber = proto.AFunc + + +var FooAVar proto.Frobber = proto.AVar + +var FooAnotherVar proto.Frobber = proto.AnotherVar + +` + testNamer := namer.NewPublicNamer(1, "proto") + rawNamer := namer.NewRawNamer("o", nil) + _, u, o := construct(t, testFiles, testNamer) + t.Logf("\n%v\n\n", o) + args := map[string]interface{}{ + "Name": testNamer.Name, + "Raw": rawNamer.Name, + } + tmpl := template.Must( + template.New(""). + Funcs(args). + Parse(tmplText), + ) + buf := &bytes.Buffer{} + tmpl.Execute(buf, o) + if e, a := expect, buf.String(); e != a { + t.Errorf("Wanted, got:\n%v\n-----\n%v\n", e, a) + } + if p := u.Package("base/foo/proto"); !p.HasImport("base/common/proto") { + t.Errorf("Unexpected lack of import line: %s", p.Imports) + } +} + +func TestStructParse(t *testing.T) { + var structTest = file{ + path: "base/foo/proto/foo.go", + contents: ` + package foo + + // Blah is a test. + // A test, I tell you. + type Blah struct { + // A is the first field. + A int64 ` + "`" + `json:"a"` + "`" + ` + + // B is the second field. + // Multiline comments work. + B string ` + "`" + `json:"b"` + "`" + ` + } + `, + } + + _, u, o := construct(t, []file{structTest}, namer.NewPublicNamer(0)) + t.Logf("%#v", o) + blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"}) + if blahT == nil { + t.Fatal("type not found") + } + if e, a := types.Struct, blahT.Kind; e != a { + t.Errorf("struct kind wrong, wanted %v, got %v", e, a) + } + if e, a := []string{"Blah is a test.", "A test, I tell you."}, blahT.CommentLines; !reflect.DeepEqual(e, a) { + t.Errorf("struct comment wrong, wanted %q, got %q", e, a) + } + m := types.Member{ + Name: "B", + Embedded: false, + CommentLines: []string{"B is the second field.", "Multiline comments work."}, + Tags: `json:"b"`, + Type: types.String, + } + if e, a := m, blahT.Members[1]; !reflect.DeepEqual(e, a) { + t.Errorf("wanted, got:\n%#v\n%#v", e, a) + } +} + +func TestParseSecondClosestCommentLines(t *testing.T) { + const fileName = "base/foo/proto/foo.go" + testCases := []struct { + testFile file + expected []string + }{ + { + testFile: file{ + path: fileName, contents: ` + package foo + // Blah's SecondClosestCommentLines. + // Another line. + + // Blah is a test. + // A test, I tell you. + type Blah struct { + a int + } + `}, + expected: []string{"Blah's SecondClosestCommentLines.", "Another line."}, + }, + { + testFile: file{ + path: fileName, contents: ` + package foo + // Blah's SecondClosestCommentLines. + // Another line. + + type Blah struct { + a int + } + `}, + expected: []string{"Blah's SecondClosestCommentLines.", "Another line."}, + }, + } + for _, test := range testCases { + _, u, o := construct(t, []file{test.testFile}, namer.NewPublicNamer(0)) + t.Logf("%#v", o) + blahT := u.Type(types.Name{Package: "base/foo/proto", Name: "Blah"}) + if e, a := test.expected, blahT.SecondClosestCommentLines; !reflect.DeepEqual(e, a) { + t.Errorf("struct second closest comment wrong, wanted %q, got %q", e, a) + } + } +} + +func TestTypeKindParse(t *testing.T) { + var testFiles = []file{ + {path: "a/foo.go", contents: "package a\ntype Test string\n"}, + {path: "b/foo.go", contents: "package b\ntype Test map[int]string\n"}, + {path: "c/foo.go", contents: "package c\ntype Test []string\n"}, + {path: "d/foo.go", contents: "package d\ntype Test struct{a int; b struct{a int}; c map[int]string; d *string}\n"}, + {path: "e/foo.go", contents: "package e\ntype Test *string\n"}, + {path: "f/foo.go", contents: ` + package f + import ( + "a" + "b" + ) + type Test []a.Test + type Test2 *a.Test + type Test3 map[a.Test]b.Test + type Test4 struct { + a struct {a a.Test; b b.Test} + b map[a.Test]b.Test + c *a.Test + d []a.Test + e []string + } + `}, + {path: "g/foo.go", contents: ` + package g + type Test func(a, b string) (c, d string) + func (t Test) Method(a, b string) (c, d string) { return t(a, b) } + type Interface interface{Method(a, b string) (c, d string)} + `}, + } + + // Check that the right types are found, and the namers give the expected names. + + assertions := []struct { + Package, Name string + k types.Kind + names []string + }{ + { + Package: "a", Name: "Test", k: types.Alias, + names: []string{"Test", "ATest", "test", "aTest", "a.Test"}, + }, + { + Package: "b", Name: "Test", k: types.Map, + names: []string{"Test", "BTest", "test", "bTest", "b.Test"}, + }, + { + Package: "c", Name: "Test", k: types.Slice, + names: []string{"Test", "CTest", "test", "cTest", "c.Test"}, + }, + { + Package: "d", Name: "Test", k: types.Struct, + names: []string{"Test", "DTest", "test", "dTest", "d.Test"}, + }, + { + Package: "e", Name: "Test", k: types.Pointer, + names: []string{"Test", "ETest", "test", "eTest", "e.Test"}, + }, + { + Package: "f", Name: "Test", k: types.Slice, + names: []string{"Test", "FTest", "test", "fTest", "f.Test"}, + }, + { + Package: "g", Name: "Test", k: types.Func, + names: []string{"Test", "GTest", "test", "gTest", "g.Test"}, + }, + { + Package: "g", Name: "Interface", k: types.Interface, + names: []string{"Interface", "GInterface", "interface", "gInterface", "g.Interface"}, + }, + { + Package: "", Name: "string", k: types.Builtin, + names: []string{"String", "String", "string", "string", "string"}, + }, + { + Package: "", Name: "int", k: types.Builtin, + names: []string{"Int", "Int", "int", "int", "int"}, + }, + { + Package: "", Name: "struct{a int}", k: types.Struct, + names: []string{"StructInt", "StructInt", "structInt", "structInt", "struct{a int}"}, + }, + { + Package: "", Name: "struct{a a.Test; b b.Test}", k: types.Struct, + names: []string{"StructTestTest", "StructATestBTest", "structTestTest", "structATestBTest", "struct{a a.Test; b b.Test}"}, + }, + { + Package: "", Name: "map[int]string", k: types.Map, + names: []string{"MapIntToString", "MapIntToString", "mapIntToString", "mapIntToString", "map[int]string"}, + }, + { + Package: "", Name: "map[a.Test]b.Test", k: types.Map, + names: []string{"MapTestToTest", "MapATestToBTest", "mapTestToTest", "mapATestToBTest", "map[a.Test]b.Test"}, + }, + { + Package: "", Name: "[]string", k: types.Slice, + names: []string{"SliceString", "SliceString", "sliceString", "sliceString", "[]string"}, + }, + { + Package: "", Name: "[]a.Test", k: types.Slice, + names: []string{"SliceTest", "SliceATest", "sliceTest", "sliceATest", "[]a.Test"}, + }, + { + Package: "", Name: "*string", k: types.Pointer, + names: []string{"PointerString", "PointerString", "pointerString", "pointerString", "*string"}, + }, + { + Package: "", Name: "*a.Test", k: types.Pointer, + names: []string{"PointerTest", "PointerATest", "pointerTest", "pointerATest", "*a.Test"}, + }, + } + + namers := []namer.Namer{ + namer.NewPublicNamer(0), + namer.NewPublicNamer(1), + namer.NewPrivateNamer(0), + namer.NewPrivateNamer(1), + namer.NewRawNamer("", nil), + } + + for nameIndex, namer := range namers { + _, u, _ := construct(t, testFiles, namer) + t.Logf("Found types:\n") + for pkgName, pkg := range u { + for typeName, cur := range pkg.Types { + t.Logf("%q-%q: %s %s", pkgName, typeName, cur.Name, cur.Kind) + } + } + t.Logf("\n\n") + + for _, item := range assertions { + n := types.Name{Package: item.Package, Name: item.Name} + thisType := u.Type(n) + if thisType == nil { + t.Errorf("type %s not found", n) + continue + } + underlyingType := thisType + if item.k != types.Alias && thisType.Kind == types.Alias { + underlyingType = thisType.Underlying + if underlyingType == nil { + t.Errorf("underlying type %s not found", n) + continue + } + } + if e, a := item.k, underlyingType.Kind; e != a { + t.Errorf("%v-%s: type kind wrong, wanted %v, got %v (%#v)", nameIndex, n, e, a, underlyingType) + } + if e, a := item.names[nameIndex], namer.Name(thisType); e != a { + t.Errorf("%v-%s: Expected %q, got %q", nameIndex, n, e, a) + } + } + + // Also do some one-off checks + gtest := u.Type(types.Name{Package: "g", Name: "Test"}) + if e, a := 1, len(gtest.Methods); e != a { + t.Errorf("expected %v but found %v methods: %#v", e, a, gtest) + } + iface := u.Type(types.Name{Package: "g", Name: "Interface"}) + if e, a := 1, len(iface.Methods); e != a { + t.Errorf("expected %v but found %v methods: %#v", e, a, iface) + } + } +} diff --git a/vendor/k8s.io/gengo/types/comments_test.go b/vendor/k8s.io/gengo/types/comments_test.go new file mode 100644 index 000000000..161f4a6e9 --- /dev/null +++ b/vendor/k8s.io/gengo/types/comments_test.go @@ -0,0 +1,86 @@ +/* +Copyright 2015 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 types + +import ( + "reflect" + "strings" + "testing" +) + +func TestExtractCommentTags(t *testing.T) { + commentLines := []string{ + "Human comment that is ignored.", + "+foo=value1", + "+bar", + "+foo=value2", + "+baz=qux,zrb=true", + } + + a := ExtractCommentTags("+", commentLines) + e := map[string][]string{ + "foo": {"value1", "value2"}, + "bar": {""}, + "baz": {"qux,zrb=true"}, + } + if !reflect.DeepEqual(e, a) { + t.Errorf("Wanted %q, got %q", e, a) + } +} + +func TestExtractSingleBoolCommentTag(t *testing.T) { + commentLines := []string{ + "Human comment that is ignored.", + "+TRUE=true", + "+FALSE=false", + "+MULTI=true", + "+MULTI=false", + "+MULTI=multi", + "+NOTBOOL=blue", + "+EMPTY", + } + + testCases := []struct { + key string + def bool + exp bool + err string // if set, ignore exp. + }{ + {"TRUE", false, true, ""}, + {"FALSE", true, false, ""}, + {"MULTI", false, true, ""}, + {"NOTBOOL", false, true, "is not boolean"}, + {"EMPTY", false, true, "is not boolean"}, + {"ABSENT", true, true, ""}, + {"ABSENT", false, false, ""}, + } + + for i, tc := range testCases { + v, err := ExtractSingleBoolCommentTag("+", tc.key, tc.def, commentLines) + if err != nil && tc.err == "" { + t.Errorf("[%d]: unexpected failure: %v", i, err) + } else if err == nil && tc.err != "" { + t.Errorf("[%d]: expected failure: %v", i, tc.err) + } else if err != nil { + if !strings.Contains(err.Error(), tc.err) { + t.Errorf("[%d]: unexpected error: expected %q, got %q", i, tc.err, err) + } + } else if v != tc.exp { + t.Errorf("[%d]: unexpected value: expected %t, got %t", i, tc.exp, v) + } + } +} diff --git a/vendor/k8s.io/gengo/types/flatten_test.go b/vendor/k8s.io/gengo/types/flatten_test.go new file mode 100644 index 000000000..9da34e561 --- /dev/null +++ b/vendor/k8s.io/gengo/types/flatten_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2015 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 types + +import ( + "reflect" + "testing" +) + +func TestFlatten(t *testing.T) { + mapType := &Type{ + Name: Name{Package: "", Name: "map[string]string"}, + Kind: Map, + Key: String, + Elem: String, + } + m := []Member{ + { + Name: "Baz", + Embedded: true, + Type: &Type{ + Name: Name{Package: "pkg", Name: "Baz"}, + Kind: Struct, + Members: []Member{ + {Name: "Foo", Type: String}, + { + Name: "Qux", + Embedded: true, + Type: &Type{ + Name: Name{Package: "pkg", Name: "Qux"}, + Kind: Struct, + Members: []Member{{Name: "Zot", Type: String}}, + }, + }, + }, + }, + }, + {Name: "Bar", Type: String}, + { + Name: "NotSureIfLegal", + Embedded: true, + Type: mapType, + }, + } + e := []Member{ + {Name: "Bar", Type: String}, + {Name: "NotSureIfLegal", Type: mapType, Embedded: true}, + {Name: "Foo", Type: String}, + {Name: "Zot", Type: String}, + } + if a := FlattenMembers(m); !reflect.DeepEqual(e, a) { + t.Errorf("Expected \n%#v\n, got \n%#v\n", e, a) + } +} diff --git a/vendor/k8s.io/gengo/types/types_test.go b/vendor/k8s.io/gengo/types/types_test.go new file mode 100644 index 000000000..35cc4d61d --- /dev/null +++ b/vendor/k8s.io/gengo/types/types_test.go @@ -0,0 +1,210 @@ +/* +Copyright 2015 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 types + +import ( + "testing" +) + +func TestGetBuiltin(t *testing.T) { + u := Universe{} + if builtinPkg := u.Package(""); builtinPkg.Has("string") { + t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) + } + s := u.Type(Name{Package: "", Name: "string"}) + if s != String { + t.Errorf("Expected canonical string type.") + } + if builtinPkg := u.Package(""); !builtinPkg.Has("string") { + t.Errorf("Expected builtin package to exist and have builtins by default. %#v", builtinPkg) + } + if builtinPkg := u.Package(""); len(builtinPkg.Types) != 1 { + t.Errorf("Expected builtin package to not have builtins until they're asked for explicitly. %#v", builtinPkg) + } +} + +func TestGetMarker(t *testing.T) { + u := Universe{} + n := Name{Package: "path/to/package", Name: "Foo"} + f := u.Type(n) + if f == nil || f.Name != n { + t.Errorf("Expected marker type.") + } +} + +func Test_Type_IsPrimitive(t *testing.T) { + testCases := []struct { + typ Type + expect bool + }{ + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Builtin, + }, + expect: true, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Alias, + Underlying: &Type{ + Name: Name{Package: "pkgname", Name: "underlying"}, + Kind: Builtin, + }, + }, + expect: true, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Pointer, + Elem: &Type{ + Name: Name{Package: "pkgname", Name: "pointee"}, + Kind: Builtin, + }, + }, + expect: false, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Struct, + }, + expect: false, + }, + } + + for i, tc := range testCases { + r := tc.typ.IsPrimitive() + if r != tc.expect { + t.Errorf("case[%d]: expected %t, got %t", i, tc.expect, r) + } + } +} + +func Test_Type_IsAssignable(t *testing.T) { + testCases := []struct { + typ Type + expect bool + }{ + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Builtin, + }, + expect: true, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Alias, + Underlying: &Type{ + Name: Name{Package: "pkgname", Name: "underlying"}, + Kind: Builtin, + }, + }, + expect: true, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Pointer, + Elem: &Type{ + Name: Name{Package: "pkgname", Name: "pointee"}, + Kind: Builtin, + }, + }, + expect: false, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Struct, // Empty struct + }, + expect: true, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Struct, + Members: []Member{ + { + Name: "m1", + Type: &Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Builtin, + }, + }, + { + Name: "m2", + Type: &Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Alias, + Underlying: &Type{ + Name: Name{Package: "pkgname", Name: "underlying"}, + Kind: Builtin, + }, + }, + }, + { + Name: "m3", + Type: &Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Struct, // Empty struct + }, + }, + }, + }, + expect: true, + }, + { + typ: Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Struct, + Members: []Member{ + { + Name: "m1", + Type: &Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Builtin, + }, + }, + { + Name: "m2", + Type: &Type{ + Name: Name{Package: "pkgname", Name: "typename"}, + Kind: Pointer, + Elem: &Type{ + Name: Name{Package: "pkgname", Name: "pointee"}, + Kind: Builtin, + }, + }, + }, + }, + }, + expect: false, + }, + } + + for i, tc := range testCases { + r := tc.typ.IsAssignable() + if r != tc.expect { + t.Errorf("case[%d]: expected %t, got %t", i, tc.expect, r) + } + } +} diff --git a/vendor/k8s.io/kube-openapi/.gitignore b/vendor/k8s.io/kube-openapi/.gitignore new file mode 100644 index 000000000..e36047774 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/.gitignore @@ -0,0 +1,20 @@ +# 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 + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +# Intellij IDEA files +.idea/ +*.iml +.vscode + diff --git a/vendor/k8s.io/kube-openapi/.travis.yml b/vendor/k8s.io/kube-openapi/.travis.yml new file mode 100644 index 000000000..996a4df0e --- /dev/null +++ b/vendor/k8s.io/kube-openapi/.travis.yml @@ -0,0 +1,4 @@ +language: go +go_import_path: k8s.io/kube-openapi +script: go test ./pkg/... + diff --git a/vendor/k8s.io/kube-openapi/OWNERS b/vendor/k8s.io/kube-openapi/OWNERS new file mode 100755 index 000000000..7c8ad60c5 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/OWNERS @@ -0,0 +1,7 @@ +reviewers: +- yujuhong +- gmarek +- mbohlool +- philips +approvers: +- mbohlool diff --git a/vendor/k8s.io/kube-openapi/README.md b/vendor/k8s.io/kube-openapi/README.md new file mode 100644 index 000000000..babadde1f --- /dev/null +++ b/vendor/k8s.io/kube-openapi/README.md @@ -0,0 +1,14 @@ +# Kube OpenAPI + +This repo is the home for Kubernetes OpenAPI discovery spec generation. The goal +is to support a subset of OpenAPI features to satisfy kubernetes use-cases but +implement that subset with little to no assumption about the structure of the +code or routes. Thus, there should be no kubernetes specific code in this repo. + + +There are two main parts: + - A model generator that goes through .go files, find and generate model +definitions. + - The spec generator that is responsible for dynamically generate +the final OpenAPI spec using web service routes or combining other +OpenAPI/Json specs. diff --git a/vendor/k8s.io/kube-openapi/code-of-conduct.md b/vendor/k8s.io/kube-openapi/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/vendor/k8s.io/kube-openapi/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/k8s.io/kube-openapi/pkg/generators/README b/vendor/k8s.io/kube-openapi/pkg/generators/README new file mode 100644 index 000000000..feb19b401 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/generators/README @@ -0,0 +1,46 @@ +# Generate OpenAPI definitions + +- To generate definition for a specific type or package add "+k8s:openapi-gen=true" tag to the type/package comment lines. +- To exclude a type or a member from a tagged package/type, add "+k8s:openapi-gen=false" tag to the comment lines. + +# OpenAPI Extensions +OpenAPI spec can have extensions on types. To define one or more extensions on a type or its member +add `+k8s:openapi-gen=x-kubernetes-$NAME:`$VALUE`` to the comment lines before type/member. A type/member can +have multiple extensions. The rest of the line in the comment will be used as $VALUE so there is no need to +escape or quote the value string. Extensions can be used to pass more information to client generators or +documentation generators. For example a type might have a friendly name to be displayed in documentation or +being used in a client's fluent interface. + +# Custom OpenAPI type definitions + +Custom types which otherwise don't map directly to OpenAPI can override their +OpenAPI definition by implementing a function named "OpenAPIDefinition" with +the following signature: + + import openapi "k8s.io/kube-openapi/pkg/common" + + // ... + + type Time struct { + time.Time + } + + func (_ Time) OpenAPIDefinition() openapi.OpenAPIDefinition { + return openapi.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "date-time", + }, + }, + } + } + +Alternatively, the type can avoid the "openapi" import by defining the following +methods. The following example produces the same OpenAPI definition as the +example above: + + func (_ Time) OpenAPISchemaType() []string { return []string{"string"} } + func (_ Time) OpenAPISchemaFormat() string { return "date-time" } + +TODO(mehdy): Make k8s:openapi-gen a parameter to the generator now that OpenAPI has its own repo. diff --git a/vendor/k8s.io/kube-openapi/pkg/generators/openapi_test.go b/vendor/k8s.io/kube-openapi/pkg/generators/openapi_test.go new file mode 100644 index 000000000..c6128d02a --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/generators/openapi_test.go @@ -0,0 +1,482 @@ +/* +Copyright 2016 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 generators + +import ( + "bytes" + "fmt" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/parser" + "k8s.io/gengo/types" +) + +func construct(t *testing.T, files map[string]string, testNamer namer.Namer) (*parser.Builder, types.Universe, []*types.Type) { + b := parser.New() + for name, src := range files { + if err := b.AddFileForTest(filepath.Dir(name), name, []byte(src)); err != nil { + t.Fatal(err) + } + } + u, err := b.FindTypes() + if err != nil { + t.Fatal(err) + } + orderer := namer.Orderer{Namer: testNamer} + o := orderer.OrderUniverse(u) + return b, u, o +} + +func testOpenAPITypeWritter(t *testing.T, code string) (error, *assert.Assertions, *bytes.Buffer) { + assert := assert.New(t) + var testFiles = map[string]string{ + "base/foo/bar.go": code, + } + rawNamer := namer.NewRawNamer("o", nil) + namers := namer.NameSystems{ + "raw": namer.NewRawNamer("", nil), + } + builder, universe, _ := construct(t, testFiles, rawNamer) + context, err := generator.NewContext(builder, namers, "raw") + if err != nil { + t.Fatal(err) + } + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + blahT := universe.Type(types.Name{Package: "base/foo", Name: "Blah"}) + return newOpenAPITypeWriter(sw).generate(blahT), assert, buffer +} + +func TestSimple(t *testing.T) { + err, assert, buffer := testOpenAPITypeWritter(t, ` +package foo + +// Blah is a test. +// +k8s:openapi-gen=true +// +k8s:openapi-gen=x-kubernetes-type-tag:type_test +type Blah struct { + // A simple string + String string + // A simple int + Int int `+"`"+`json:",omitempty"`+"`"+` + // An int considered string simple int + IntString int `+"`"+`json:",string"`+"`"+` + // A simple int64 + Int64 int64 + // A simple int32 + Int32 int32 + // A simple int16 + Int16 int16 + // A simple int8 + Int8 int8 + // A simple int + Uint uint + // A simple int64 + Uint64 uint64 + // A simple int32 + Uint32 uint32 + // A simple int16 + Uint16 uint16 + // A simple int8 + Uint8 uint8 + // A simple byte + Byte byte + // A simple boolean + Bool bool + // A simple float64 + Float64 float64 + // A simple float32 + Float32 float32 + // a base64 encoded characters + ByteArray []byte + // a member with an extension + // +k8s:openapi-gen=x-kubernetes-member-tag:member_test + WithExtension string + // a member with struct tag as extension + // +patchStrategy=ps + // +patchMergeKey=pmk + WithStructTagExtension string `+"`"+`patchStrategy:"ps" patchMergeKey:"pmk"`+"`"+` +} + `) + if err != nil { + t.Fatal(err) + } + assert.Equal(`"base/foo.Blah": { +Schema: spec.Schema{ +SchemaProps: spec.SchemaProps{ +Description: "Blah is a test.", +Properties: map[string]spec.Schema{ +"String": { +SchemaProps: spec.SchemaProps{ +Description: "A simple string", +Type: []string{"string"}, +Format: "", +}, +}, +"Int64": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int64", +Type: []string{"integer"}, +Format: "int64", +}, +}, +"Int32": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int32", +Type: []string{"integer"}, +Format: "int32", +}, +}, +"Int16": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int16", +Type: []string{"integer"}, +Format: "int32", +}, +}, +"Int8": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int8", +Type: []string{"integer"}, +Format: "byte", +}, +}, +"Uint": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int", +Type: []string{"integer"}, +Format: "int32", +}, +}, +"Uint64": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int64", +Type: []string{"integer"}, +Format: "int64", +}, +}, +"Uint32": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int32", +Type: []string{"integer"}, +Format: "int64", +}, +}, +"Uint16": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int16", +Type: []string{"integer"}, +Format: "int32", +}, +}, +"Uint8": { +SchemaProps: spec.SchemaProps{ +Description: "A simple int8", +Type: []string{"integer"}, +Format: "byte", +}, +}, +"Byte": { +SchemaProps: spec.SchemaProps{ +Description: "A simple byte", +Type: []string{"integer"}, +Format: "byte", +}, +}, +"Bool": { +SchemaProps: spec.SchemaProps{ +Description: "A simple boolean", +Type: []string{"boolean"}, +Format: "", +}, +}, +"Float64": { +SchemaProps: spec.SchemaProps{ +Description: "A simple float64", +Type: []string{"number"}, +Format: "double", +}, +}, +"Float32": { +SchemaProps: spec.SchemaProps{ +Description: "A simple float32", +Type: []string{"number"}, +Format: "float", +}, +}, +"ByteArray": { +SchemaProps: spec.SchemaProps{ +Description: "a base64 encoded characters", +Type: []string{"string"}, +Format: "byte", +}, +}, +"WithExtension": { +VendorExtensible: spec.VendorExtensible{ +Extensions: spec.Extensions{ +"x-kubernetes-member-tag": "member_test", +}, +}, +SchemaProps: spec.SchemaProps{ +Description: "a member with an extension", +Type: []string{"string"}, +Format: "", +}, +}, +"WithStructTagExtension": { +VendorExtensible: spec.VendorExtensible{ +Extensions: spec.Extensions{ +"x-kubernetes-patch-merge-key": "pmk", +"x-kubernetes-patch-strategy": "ps", +}, +}, +SchemaProps: spec.SchemaProps{ +Description: "a member with struct tag as extension", +Type: []string{"string"}, +Format: "", +}, +}, +}, +Required: []string{"String","Int64","Int32","Int16","Int8","Uint","Uint64","Uint32","Uint16","Uint8","Byte","Bool","Float64","Float32","ByteArray","WithExtension","WithStructTagExtension"}, +}, +VendorExtensible: spec.VendorExtensible{ +Extensions: spec.Extensions{ +"x-kubernetes-type-tag": "type_test", +}, +}, +}, +Dependencies: []string{ +}, +}, +`, buffer.String()) +} + +func TestFailingSample1(t *testing.T) { + err, assert, _ := testOpenAPITypeWritter(t, ` +package foo + +// Map sample tests openAPIGen.generateMapProperty method. +type Blah struct { + // A sample String to String map + StringToArray map[string]map[string]string +} + `) + if assert.Error(err, "An error was expected") { + assert.Equal(err, fmt.Errorf("map Element kind Map is not supported in map[string]map[string]string")) + } +} + +func TestFailingSample2(t *testing.T) { + err, assert, _ := testOpenAPITypeWritter(t, ` +package foo + +// Map sample tests openAPIGen.generateMapProperty method. +type Blah struct { + // A sample String to String map + StringToArray map[int]string +} `) + if assert.Error(err, "An error was expected") { + assert.Equal(err, fmt.Errorf("map with non-string keys are not supported by OpenAPI in map[int]string")) + } +} + +func TestCustomDef(t *testing.T) { + err, assert, buffer := testOpenAPITypeWritter(t, ` +package foo + +import openapi "k8s.io/kube-openapi/pkg/common" + +type Blah struct { +} + +func (_ Blah) OpenAPIDefinition() openapi.OpenAPIDefinition { + return openapi.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "date-time", + }, + }, + } +} +`) + if err != nil { + t.Fatal(err) + } + assert.Equal(`"base/foo.Blah": foo.Blah{}.OpenAPIDefinition(), +`, buffer.String()) +} + +func TestCustomDefs(t *testing.T) { + err, assert, buffer := testOpenAPITypeWritter(t, ` +package foo + +type Blah struct { +} + +func (_ Blah) OpenAPISchemaType() []string { return []string{"string"} } +func (_ Blah) OpenAPISchemaFormat() string { return "date-time" } +`) + if err != nil { + t.Fatal(err) + } + assert.Equal(`"base/foo.Blah": { +Schema: spec.Schema{ +SchemaProps: spec.SchemaProps{ +Type:foo.Blah{}.OpenAPISchemaType(), +Format:foo.Blah{}.OpenAPISchemaFormat(), +}, +}, +}, +`, buffer.String()) +} + +func TestPointer(t *testing.T) { + err, assert, buffer := testOpenAPITypeWritter(t, ` +package foo + +// PointerSample demonstrate pointer's properties +type Blah struct { + // A string pointer + StringPointer *string + // A struct pointer + StructPointer *Blah + // A slice pointer + SlicePointer *[]string + // A map pointer + MapPointer *map[string]string +} + `) + if err != nil { + t.Fatal(err) + } + assert.Equal(`"base/foo.Blah": { +Schema: spec.Schema{ +SchemaProps: spec.SchemaProps{ +Description: "PointerSample demonstrate pointer's properties", +Properties: map[string]spec.Schema{ +"StringPointer": { +SchemaProps: spec.SchemaProps{ +Description: "A string pointer", +Type: []string{"string"}, +Format: "", +}, +}, +"StructPointer": { +SchemaProps: spec.SchemaProps{ +Description: "A struct pointer", +Ref: ref("base/foo.Blah"), +}, +}, +"SlicePointer": { +SchemaProps: spec.SchemaProps{ +Description: "A slice pointer", +Type: []string{"array"}, +Items: &spec.SchemaOrArray{ +Schema: &spec.Schema{ +SchemaProps: spec.SchemaProps{ +Type: []string{"string"}, +Format: "", +}, +}, +}, +}, +}, +"MapPointer": { +SchemaProps: spec.SchemaProps{ +Description: "A map pointer", +Type: []string{"object"}, +AdditionalProperties: &spec.SchemaOrBool{ +Schema: &spec.Schema{ +SchemaProps: spec.SchemaProps{ +Type: []string{"string"}, +Format: "", +}, +}, +}, +}, +}, +}, +Required: []string{"StringPointer","StructPointer","SlicePointer","MapPointer"}, +}, +}, +Dependencies: []string{ +"base/foo.Blah",}, +}, +`, buffer.String()) +} + +func TestNestedLists(t *testing.T) { + err, assert, buffer := testOpenAPITypeWritter(t, ` +package foo + +// Blah is a test. +// +k8s:openapi-gen=true +// +k8s:openapi-gen=x-kubernetes-type-tag:type_test +type Blah struct { + // Nested list + NestedList [][]int64 +} +`) + if err != nil { + t.Fatal(err) + } + assert.Equal(`"base/foo.Blah": { +Schema: spec.Schema{ +SchemaProps: spec.SchemaProps{ +Description: "Blah is a test.", +Properties: map[string]spec.Schema{ +"NestedList": { +SchemaProps: spec.SchemaProps{ +Description: "Nested list", +Type: []string{"array"}, +Items: &spec.SchemaOrArray{ +Schema: &spec.Schema{ +SchemaProps: spec.SchemaProps{ +Type: []string{"array"}, +Items: &spec.SchemaOrArray{ +Schema: &spec.Schema{ +SchemaProps: spec.SchemaProps{ +Type: []string{"integer"}, +Format: "int64", +}, +}, +}, +}, +}, +}, +}, +}, +}, +Required: []string{"NestedList"}, +}, +VendorExtensible: spec.VendorExtensible{ +Extensions: spec.Extensions{ +"x-kubernetes-type-tag": "type_test", +}, +}, +}, +Dependencies: []string{ +}, +}, +`, buffer.String()) +} diff --git a/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_suite_test.go b/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_suite_test.go new file mode 100644 index 000000000..24b5168e4 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_suite_test.go @@ -0,0 +1,49 @@ +/* +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 proto_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/config" + . "github.com/onsi/ginkgo/types" + . "github.com/onsi/gomega" + + "fmt" + "testing" +) + +func TestOpenapi(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecsWithDefaultAndCustomReporters(t, "Openapi Suite", []Reporter{newlineReporter{}}) +} + +// Print a newline after the default newlineReporter due to issue +// https://github.com/jstemmer/go-junit-report/issues/31 +type newlineReporter struct{} + +func (newlineReporter) SpecSuiteWillBegin(config GinkgoConfigType, summary *SuiteSummary) {} + +func (newlineReporter) BeforeSuiteDidRun(setupSummary *SetupSummary) {} + +func (newlineReporter) AfterSuiteDidRun(setupSummary *SetupSummary) {} + +func (newlineReporter) SpecWillRun(specSummary *SpecSummary) {} + +func (newlineReporter) SpecDidComplete(specSummary *SpecSummary) {} + +// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:" +func (newlineReporter) SpecSuiteDidEnd(summary *SuiteSummary) { fmt.Printf("\n") } diff --git a/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_test.go b/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_test.go new file mode 100644 index 000000000..916abe0c0 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_test.go @@ -0,0 +1,207 @@ +/* +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 proto_test + +import ( + "path/filepath" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "k8s.io/kube-openapi/pkg/util/proto" + "k8s.io/kube-openapi/pkg/util/proto/testing" +) + +var fakeSchema = testing.Fake{Path: filepath.Join("testing", "swagger.json")} + +var _ = Describe("Reading apps/v1beta1/Deployment from openAPIData", func() { + var models proto.Models + BeforeEach(func() { + s, err := fakeSchema.OpenAPISchema() + Expect(err).To(BeNil()) + models, err = proto.NewOpenAPIData(s) + Expect(err).To(BeNil()) + }) + + model := "io.k8s.api.apps.v1beta1.Deployment" + var schema proto.Schema + It("should lookup the Schema by its model name", func() { + schema = models.LookupModel(model) + Expect(schema).ToNot(BeNil()) + }) + + var deployment *proto.Kind + It("should be a Kind", func() { + deployment = schema.(*proto.Kind) + Expect(deployment).ToNot(BeNil()) + }) + + It("should have a path", func() { + Expect(deployment.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment"})) + }) + + It("should have a kind key of type string", func() { + Expect(deployment.Fields).To(HaveKey("kind")) + key := deployment.Fields["kind"].(*proto.Primitive) + Expect(key).ToNot(BeNil()) + Expect(key.Type).To(Equal("string")) + Expect(key.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment", ".kind"})) + }) + + It("should have a apiVersion key of type string", func() { + Expect(deployment.Fields).To(HaveKey("apiVersion")) + key := deployment.Fields["apiVersion"].(*proto.Primitive) + Expect(key).ToNot(BeNil()) + Expect(key.Type).To(Equal("string")) + Expect(key.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment", ".apiVersion"})) + }) + + It("should have a metadata key of type Reference", func() { + Expect(deployment.Fields).To(HaveKey("metadata")) + key := deployment.Fields["metadata"].(proto.Reference) + Expect(key).ToNot(BeNil()) + Expect(key.Reference()).To(Equal("io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta")) + subSchema := key.SubSchema().(*proto.Kind) + Expect(subSchema).ToNot(BeNil()) + }) + + var status *proto.Kind + It("should have a status key of type Reference", func() { + Expect(deployment.Fields).To(HaveKey("status")) + key := deployment.Fields["status"].(proto.Reference) + Expect(key).ToNot(BeNil()) + Expect(key.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentStatus")) + status = key.SubSchema().(*proto.Kind) + Expect(status).ToNot(BeNil()) + }) + + It("should have a valid DeploymentStatus", func() { + By("having availableReplicas key") + Expect(status.Fields).To(HaveKey("availableReplicas")) + replicas := status.Fields["availableReplicas"].(*proto.Primitive) + Expect(replicas).ToNot(BeNil()) + Expect(replicas.Type).To(Equal("integer")) + + By("having conditions key") + Expect(status.Fields).To(HaveKey("conditions")) + conditions := status.Fields["conditions"].(*proto.Array) + Expect(conditions).ToNot(BeNil()) + Expect(conditions.GetName()).To(Equal(`Array of Reference to "io.k8s.api.apps.v1beta1.DeploymentCondition"`)) + Expect(conditions.GetExtensions()).To(Equal(map[string]interface{}{ + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + })) + condition := conditions.SubType.(proto.Reference) + Expect(condition.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentCondition")) + }) + + var spec *proto.Kind + It("should have a spec key of type Reference", func() { + Expect(deployment.Fields).To(HaveKey("spec")) + key := deployment.Fields["spec"].(proto.Reference) + Expect(key).ToNot(BeNil()) + Expect(key.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentSpec")) + spec = key.SubSchema().(*proto.Kind) + Expect(spec).ToNot(BeNil()) + }) + + It("should have a spec with no gvk", func() { + _, found := spec.GetExtensions()["x-kubernetes-group-version-kind"] + Expect(found).To(BeFalse()) + }) + + It("should have a spec with a PodTemplateSpec sub-field", func() { + Expect(spec.Fields).To(HaveKey("template")) + key := spec.Fields["template"].(proto.Reference) + Expect(key).ToNot(BeNil()) + Expect(key.Reference()).To(Equal("io.k8s.api.core.v1.PodTemplateSpec")) + }) +}) + +var _ = Describe("Reading authorization.k8s.io/v1/SubjectAccessReview from openAPIData", func() { + var models proto.Models + BeforeEach(func() { + s, err := fakeSchema.OpenAPISchema() + Expect(err).To(BeNil()) + models, err = proto.NewOpenAPIData(s) + Expect(err).To(BeNil()) + }) + + model := "io.k8s.api.authorization.v1.LocalSubjectAccessReview" + var schema proto.Schema + It("should lookup the Schema by its model", func() { + schema = models.LookupModel(model) + Expect(schema).ToNot(BeNil()) + }) + + var sarspec *proto.Kind + It("should be a Kind and have a spec", func() { + sar := schema.(*proto.Kind) + Expect(sar).ToNot(BeNil()) + Expect(sar.Fields).To(HaveKey("spec")) + specRef := sar.Fields["spec"].(proto.Reference) + Expect(specRef).ToNot(BeNil()) + Expect(specRef.Reference()).To(Equal("io.k8s.api.authorization.v1.SubjectAccessReviewSpec")) + sarspec = specRef.SubSchema().(*proto.Kind) + Expect(sarspec).ToNot(BeNil()) + }) + + It("should have a valid SubjectAccessReviewSpec", func() { + Expect(sarspec.Fields).To(HaveKey("extra")) + extra := sarspec.Fields["extra"].(*proto.Map) + Expect(extra).ToNot(BeNil()) + Expect(extra.GetName()).To(Equal("Map of Array of string")) + Expect(extra.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"})) + array := extra.SubType.(*proto.Array) + Expect(array).ToNot(BeNil()) + Expect(array.GetName()).To(Equal("Array of string")) + Expect(array.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"})) + str := array.SubType.(*proto.Primitive) + Expect(str).ToNot(BeNil()) + Expect(str.Type).To(Equal("string")) + Expect(str.GetName()).To(Equal("string")) + Expect(str.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"})) + }) +}) + +var _ = Describe("Path", func() { + It("can be created by NewPath", func() { + path := proto.NewPath("key") + Expect(path.String()).To(Equal("key")) + }) + It("can create and print complex paths", func() { + key := proto.NewPath("key") + array := key.ArrayPath(12) + field := array.FieldPath("subKey") + + Expect(field.String()).To(Equal("key[12].subKey")) + }) + It("has a length", func() { + key := proto.NewPath("key") + array := key.ArrayPath(12) + field := array.FieldPath("subKey") + + Expect(field.Len()).To(Equal(3)) + }) + It("can look like an array", func() { + key := proto.NewPath("key") + array := key.ArrayPath(12) + field := array.FieldPath("subKey") + + Expect(field.Get()).To(Equal([]string{"key", "[12]", ".subKey"})) + }) +}) diff --git a/vendor/k8s.io/kube-openapi/pkg/util/trie.go b/vendor/k8s.io/kube-openapi/pkg/util/trie.go new file mode 100644 index 000000000..a9a76c179 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/util/trie.go @@ -0,0 +1,79 @@ +/* +Copyright 2016 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 util + +// A simple trie implementation with Add and HasPrefix methods only. +type Trie struct { + children map[byte]*Trie + wordTail bool + word string +} + +// NewTrie creates a Trie and add all strings in the provided list to it. +func NewTrie(list []string) Trie { + ret := Trie{ + children: make(map[byte]*Trie), + wordTail: false, + } + for _, v := range list { + ret.Add(v) + } + return ret +} + +// Add adds a word to this trie +func (t *Trie) Add(v string) { + root := t + for _, b := range []byte(v) { + child, exists := root.children[b] + if !exists { + child = &Trie{ + children: make(map[byte]*Trie), + wordTail: false, + } + root.children[b] = child + } + root = child + } + root.wordTail = true + root.word = v +} + +// HasPrefix returns true of v has any of the prefixes stored in this trie. +func (t *Trie) HasPrefix(v string) bool { + _, has := t.GetPrefix(v) + return has +} + +// GetPrefix is like HasPrefix but return the prefix in case of match or empty string otherwise. +func (t *Trie) GetPrefix(v string) (string, bool) { + root := t + if root.wordTail { + return root.word, true + } + for _, b := range []byte(v) { + child, exists := root.children[b] + if !exists { + return "", false + } + if child.wordTail { + return child.word, true + } + root = child + } + return "", false +} diff --git a/vendor/k8s.io/kube-openapi/pkg/util/util.go b/vendor/k8s.io/kube-openapi/pkg/util/util.go new file mode 100644 index 000000000..bcc0c4d4b --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/util/util.go @@ -0,0 +1,39 @@ +/* +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 util + +import "strings" + +// ToCanonicalName converts Golang package/type name into canonical OpenAPI name. +// Examples: +// Input: k8s.io/api/core/v1.Pod +// Output: io.k8s.api.core.v1.Pod +// +// Input: k8s.io/api/core/v1 +// Output: io.k8s.api.core.v1 +func ToCanonicalName(name string) string { + nameParts := strings.Split(name, "/") + // Reverse first part. e.g., io.k8s... instead of k8s.io... + if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") { + parts := strings.Split(nameParts[0], ".") + for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 { + parts[i], parts[j] = parts[j], parts[i] + } + nameParts[0] = strings.Join(parts, ".") + } + return strings.Join(nameParts, ".") +}